找回密码
 立即注册
首页 业界区 业界 10分钟,创建你的第一个点线面低代码串口调试应用 ...

10分钟,创建你的第一个点线面低代码串口调试应用

即息极 前天 19:16
1. 效果预览
这个例子包括,串口的打开和发送,包括字符串的发送和hex 的发送。最终效果如图。
1.png

点线面低代码应用下载
GitHub 下载地址 https://github.com/dotLinePlane-com/dotlineplane/releases
通过百度网盘分享的文件:dotLinePlaneV2.1.0.7z 链接:https://pan.baidu.com/s/1XUl32fFD3ssZoPMqC4NmQw?pwd=qn0d 提取码:qn0d
 
2. 具体步骤
创建一个应用主要有四个步骤,包括:拖拽组件、设置组件属性、编写js脚本和设置组件事件与脚本关联。
2.1 拖拽组件
界面的右边选择拖拽到画布中。
使用的组件有 dropdown (端口和波特率)、按钮(打开和发送)、复选框(Hex 发送)、文本输入框(发送区)和 多行文本输入框(接收区和log)
 
 
2.2 添加 js 脚本
2.png

 
***添加 init 脚本时,注意需要在Settings 中打开 在应用程序加载时运行此查询
init 脚本
  1. //init 脚本
  2. // 获取串口列表
  3. const ports = await serialAPI.getSerialPorts();
  4. console.log("v port :", ports);
  5. // 格式化串口数据
  6. let formattedPorts = ports.map(port => ({
  7.   disable: false,
  8.   visible: true,
  9.   value: port.path,
  10.   label: port.friendlyName || port.path,
  11. }));
  12. console.log("port:", formattedPorts);
  13. // 获取 defaultPortsValue, portsLabel 和 portsValue
  14. const defaultPortsValue = formattedPorts.length > 0 ? formattedPorts[0].value : null;
  15. const portsLabel = formattedPorts.map(port => port.label);
  16. const portsValue = formattedPorts.map(port => port.value);
  17. const portsSelect = {
  18.   defaultPortsValue,
  19.   portsLabel,
  20.   portsValue,
  21. };
  22. const baudsValue = [9600, 115200];
  23. const baudsLabel = ["9600", "115200"];
  24. const defaultBaudsValue = baudsValue[0];
  25. const baudsSelect = {
  26.   defaultBaudsValue,
  27.   baudsValue,
  28.   baudsLabel,
  29. };
  30. // 更新 formattedPorts 对象结构
  31. const formattedPortsObject = {
  32.   portsSelect,
  33.   baudsSelect,
  34. };
  35. console.log("formattedPortsObject:", formattedPortsObject);
  36. // 设置页面变量
  37. await actions.setPageVariable('ports', formattedPortsObject);
  38. await actions.setPageVariable('serialRx', '');
  39. await actions.setPageVariable('isOpen', false);
  40. // 定义处理串口数据的函数
  41. const handleSerialData = async (path, data) => {
  42.   if (path === page.variables.usedPort) {
  43.     const receiveTime = Date.now();
  44.     console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data);
  45.     await actions.setPageVariable('serialRx', data);
  46.   }
  47. };
  48. // 初始化串口连接
  49. const initializeSerialConnection = async () => {
  50.   if (page.variables.isOpen) {
  51.     // 设置使用的串口
  52.     await actions.setPageVariable('usedPort', components.dropdownPort.value);
  53.     serialAPI.onSerialData(components.dropdownPort.value, handleSerialData);
  54.   } else {
  55.     await actions.setPageVariable('usedPort', '');
  56.     // serialAPI.offSerialData(portRef.current, handleSerialData);
  57.   }
  58. };
  59. // 在页面加载时执行初始化
  60. await initializeSerialConnection();
  61. // 返回格式化后的串口对象
  62. return formattedPortsObject;
复制代码
 
openPort 脚本
  1. //openPort
  2. function mergeUint8Arrays(arrays) {
  3.   console.log(`Received data:`, arrays);
  4.   if (arrays instanceof Uint8Array) {
  5.     arrays = [arrays];
  6.   }
  7.     if (!Array.isArray(arrays)) {
  8.         console.error("Input is not an array.");
  9.         return null;
  10.     }
  11.     // 确保数组中的每个元素都是 Uint8Array
  12.     for (let i = 0; i < arrays.length; i++) {
  13.         if (!(arrays[i] instanceof Uint8Array)) {
  14.             console.error(`Element at index ${i} is not a Uint8Array.`);
  15.             return null;
  16.         }
  17.     }
  18.     // 计算总长度
  19.     const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
  20.     // 创建新的 Uint8Array
  21.     const mergedArray = new Uint8Array(totalLength);
  22.     // 复制数据
  23.     let offset = 0;
  24.     arrays.forEach(arr => {
  25.         mergedArray.set(arr, offset);
  26.         offset += arr.length;
  27.     });
  28.     return mergedArray;
  29. }
  30. const handleSerialData = async (path, data) => {
  31.   if (path === page.variables.usedPort) {
  32.     const receiveTime = Date.now();
  33.     console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data);
  34.     const mergeData = mergeUint8Arrays(data);
  35.     const decoder = new TextDecoder('utf-8');
  36.     const stringData = decoder.decode(mergeData);
  37.     console.log("serialRx:",stringData);
  38.     await actions.setPageVariable('serialRx', stringData);
  39.   }
  40. };
  41. if (!page.variables.isOpen) {
  42.       // Open the serial port
  43.       const config = {
  44.         path:components.dropdownPort.value,
  45.         baudRate: parseInt(components.dropdownBaud.value, 10),
  46.         dataBits:8,
  47.         parity:'none',
  48.         stopBits:1,
  49.         // dataBits: parseInt(components.dropdownBits.value, 10),
  50.         // parity: components.dropdownCrc.value === 'NONE' ? 'none' : components.dropdownCrc.value.toLowerCase(),
  51.         // stopBits: parseInt(components.dropdownStop.value, 10),
  52.       };
  53.       try {
  54.         const result = await serialAPI.openSerialPort(config);
  55.         console.log(result);
  56.         await actions.setPageVariable('usedPort', components.dropdownPort.value);
  57.         serialAPI.onSerialData(components.dropdownPort.value, handleSerialData);
  58.         await actions.setPageVariable('isOpen', true);
  59.         components.openButton.setText("关闭");
  60.       } catch (error) {
  61.         console.error('Failed to open serial port:', error);
  62.       }
  63.     } else {
  64.       // Close the serial port
  65.       try {
  66.         await serialAPI.closeSerialPort(page.variables.usedPort);
  67.         serialAPI.offSerialData(page.variables.usedPort, handleSerialData);
  68.         await actions.setPageVariable('isOpen', false);
  69.         components.openButton.setText("打开");
  70.       } catch (error) {
  71.         console.error('Failed to close serial port:', error);
  72.         await actions.setPageVariable('isOpen', false);
  73.         components.openButton.setText("打开");
  74.         if(page.variables.usedPort){
  75.           serialAPI.offSerialData(page.variables.usedPort, handleSerialData);
  76.         }
  77.       }
  78.     }
  79. return 0;
复制代码
 
sendData 脚本
  1. //sendData
  2. function hexStringToUint8Array(hexString) {
  3.     // 确保字符串长度为偶数
  4.     if (hexString.length % 2 !== 0) {
  5.       return null;
  6.     }
  7.     // 创建一个 Uint8Array,长度为字符串长度的一半
  8.     const length = hexString.length / 2;
  9.     const uint8Array = new Uint8Array(length);
  10.     // 遍历字符串,每两个字符解析为一个字节
  11.     for (let i = 0; i < length; i++) {
  12.         const byteHex = hexString.substr(i * 2, 2); // 提取两个字符
  13.         uint8Array[i] = parseInt(byteHex, 16); // 将 16 进制字符串解析为数字
  14.     }
  15.     return uint8Array;
  16. }
  17. if(page.variables.isOpen){
  18.   if(!components.HexSendCheckbox.value){
  19.     serialAPI.writeSerialPort(page.variables.usedPort,components.sendData.value);
  20.   }else{
  21.     const hexSend = hexStringToUint8Array(components.sendData.value);
  22.     if(hexSend){
  23.       serialAPI.writeSerialPort(page.variables.usedPort,hexSend);
  24.       // actions.showAlert("info:"+ "发送成功"); // 使用 ToolJet 的 toast 组件
  25.       actions.setVariable("infoMessage", "发送成功");
  26.       // queries.log.run()
  27.       await actions.runQuery('log',{message: "发送成功"});
  28.     }
  29.   }
  30. }
复制代码
 
log 脚本
  1. //log
  2. // 更新 log 内容
  3. components.log.setText(components.log.value + variables.infoMessage + "\r\n");
  4. // 获取 TextArea 元素
  5. // 获取外层 div 元素
  6. const textareaWrapper = document.getElementById(components.log.id);
  7. // 从外层 div 中找到 textarea 元素
  8. const textareaElement = textareaWrapper ? textareaWrapper.querySelector("textarea") : null;
  9. // 检查是否成功获取 textarea
  10. if (textareaElement) {
  11.     // 滚动到 textarea 的底部
  12.     textareaElement.scrollTop = textareaElement.scrollHeight;
  13. }
复制代码
 
2.3 设置组件属性
这里主要设置组件的名称属性,其他的有程序设置。
3.png

端口组件: 
    名称:dropdownPort
    默认值:queries.init.data.portsSelect.defaultPortsValue
    选项值:queries.init.data.portsSelect.portsValue
    选项标签:queries.init.data.portsSelect.portsLabel
 
波特率组件:
    名称:dropdownBaud
    默认值:queries.init.data.baudsSelect.defaultBaudsValue
    选项值:queries.init.data.baudsSelect.baudsValue
    选项标签:queries.init.data.baudsSelect.baudsLabel
 
打开按钮组件
    名称:openButton
 
Hex 发送组件
    名称:HexSendCheckbox
 
发送区组件
    名称:sendData
 
接收区组件
    名称:recivedData
    默认值:page.variables.serialRx     *注意:需要使用{{}},符号包裹起来
 
log 组件
    名称:log
 
2.4 组件事件与js脚本进行关联
4.png

 
打开和发送组件,都需要添加关联事件
3. 结束
更多的细节需要你自己的探索,那就开始你的点线面低代码的探索之旅吧!
有问题可以私信我,也可以在应用程序中找到联系方式,单独交流。
 
 
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册