即息极 发表于 前天 19:16

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

1. 效果预览
这个例子包括,串口的打开和发送,包括字符串的发送和hex 的发送。最终效果如图。

点线面低代码应用下载
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 脚本

 
***添加 init 脚本时,注意需要在Settings 中打开 在应用程序加载时运行此查询
init 脚本
//init 脚本
// 获取串口列表
const ports = await serialAPI.getSerialPorts();
console.log("v port :", ports);

// 格式化串口数据
let formattedPorts = ports.map(port => ({
disable: false,
visible: true,
value: port.path,
label: port.friendlyName || port.path,
}));
console.log("port:", formattedPorts);

// 获取 defaultPortsValue, portsLabel 和 portsValue
const defaultPortsValue = formattedPorts.length > 0 ? formattedPorts.value : null;
const portsLabel = formattedPorts.map(port => port.label);
const portsValue = formattedPorts.map(port => port.value);
const portsSelect = {
defaultPortsValue,
portsLabel,
portsValue,
};

const baudsValue = ;
const baudsLabel = ["9600", "115200"];
const defaultBaudsValue = baudsValue;
const baudsSelect = {
defaultBaudsValue,
baudsValue,
baudsLabel,
};

// 更新 formattedPorts 对象结构
const formattedPortsObject = {
portsSelect,
baudsSelect,
};

console.log("formattedPortsObject:", formattedPortsObject);

// 设置页面变量
await actions.setPageVariable('ports', formattedPortsObject);
await actions.setPageVariable('serialRx', '');
await actions.setPageVariable('isOpen', false);

// 定义处理串口数据的函数
const handleSerialData = async (path, data) => {
if (path === page.variables.usedPort) {
    const receiveTime = Date.now();
    console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data);
    await actions.setPageVariable('serialRx', data);
}
};

// 初始化串口连接
const initializeSerialConnection = async () => {
if (page.variables.isOpen) {
    // 设置使用的串口
    await actions.setPageVariable('usedPort', components.dropdownPort.value);
    serialAPI.onSerialData(components.dropdownPort.value, handleSerialData);
} else {
    await actions.setPageVariable('usedPort', '');
    // serialAPI.offSerialData(portRef.current, handleSerialData);
}
};


// 在页面加载时执行初始化
await initializeSerialConnection();

// 返回格式化后的串口对象
return formattedPortsObject; 
openPort 脚本
//openPort
function mergeUint8Arrays(arrays) {
console.log(`Received data:`, arrays);

if (arrays instanceof Uint8Array) {
    arrays = ;
}
    if (!Array.isArray(arrays)) {
      console.error("Input is not an array.");
      return null;
    }

    // 确保数组中的每个元素都是 Uint8Array
    for (let i = 0; i < arrays.length; i++) {
      if (!(arrays instanceof Uint8Array)) {
            console.error(`Element at index ${i} is not a Uint8Array.`);
            return null;
      }
    }

    // 计算总长度
    const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);

    // 创建新的 Uint8Array
    const mergedArray = new Uint8Array(totalLength);

    // 复制数据
    let offset = 0;
    arrays.forEach(arr => {
      mergedArray.set(arr, offset);
      offset += arr.length;
    });

    return mergedArray;
}

const handleSerialData = async (path, data) => {
if (path === page.variables.usedPort) {
    const receiveTime = Date.now();
    console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data);

    const mergeData = mergeUint8Arrays(data);
    const decoder = new TextDecoder('utf-8');
    const stringData = decoder.decode(mergeData);
    console.log("serialRx:",stringData);
    await actions.setPageVariable('serialRx', stringData);
}
};


if (!page.variables.isOpen) {
      // Open the serial port
      const config = {
      path:components.dropdownPort.value,
      baudRate: parseInt(components.dropdownBaud.value, 10),
      dataBits:8,
      parity:'none',
      stopBits:1,
      // dataBits: parseInt(components.dropdownBits.value, 10),
      // parity: components.dropdownCrc.value === 'NONE' ? 'none' : components.dropdownCrc.value.toLowerCase(),
      // stopBits: parseInt(components.dropdownStop.value, 10),
      };
      try {
      const result = await serialAPI.openSerialPort(config);
      console.log(result);

      await actions.setPageVariable('usedPort', components.dropdownPort.value);
      serialAPI.onSerialData(components.dropdownPort.value, handleSerialData);

      await actions.setPageVariable('isOpen', true);
      components.openButton.setText("关闭");
      } catch (error) {
      console.error('Failed to open serial port:', error);
      }
    } else {
      // Close the serial port
      try {
      await serialAPI.closeSerialPort(page.variables.usedPort);
      serialAPI.offSerialData(page.variables.usedPort, handleSerialData);

      await actions.setPageVariable('isOpen', false);
      components.openButton.setText("打开");
      } catch (error) {
      console.error('Failed to close serial port:', error);
      await actions.setPageVariable('isOpen', false);
      components.openButton.setText("打开");
      if(page.variables.usedPort){
          serialAPI.offSerialData(page.variables.usedPort, handleSerialData);
      }

      }
    }
return 0; 
sendData 脚本
//sendData
function hexStringToUint8Array(hexString) {
    // 确保字符串长度为偶数
    if (hexString.length % 2 !== 0) {
      return null;
    }

    // 创建一个 Uint8Array,长度为字符串长度的一半
    const length = hexString.length / 2;
    const uint8Array = new Uint8Array(length);

    // 遍历字符串,每两个字符解析为一个字节
    for (let i = 0; i < length; i++) {
      const byteHex = hexString.substr(i * 2, 2); // 提取两个字符
      uint8Array = parseInt(byteHex, 16); // 将 16 进制字符串解析为数字
    }

    return uint8Array;
}


if(page.variables.isOpen){
if(!components.HexSendCheckbox.value){
    serialAPI.writeSerialPort(page.variables.usedPort,components.sendData.value);
}else{
    const hexSend = hexStringToUint8Array(components.sendData.value);
    if(hexSend){
      serialAPI.writeSerialPort(page.variables.usedPort,hexSend);
      // actions.showAlert("info:"+ "发送成功"); // 使用 ToolJet 的 toast 组件
      actions.setVariable("infoMessage", "发送成功");
      // queries.log.run()
      await actions.runQuery('log',{message: "发送成功"});
    }
}


log 脚本
//log

// 更新 log 内容
components.log.setText(components.log.value + variables.infoMessage + "\r\n");

// 获取 TextArea 元素
// 获取外层 div 元素
const textareaWrapper = document.getElementById(components.log.id);

// 从外层 div 中找到 textarea 元素
const textareaElement = textareaWrapper ? textareaWrapper.querySelector("textarea") : null;

// 检查是否成功获取 textarea
if (textareaElement) {
    // 滚动到 textarea 的底部
    textareaElement.scrollTop = textareaElement.scrollHeight;

2.3 设置组件属性
这里主要设置组件的名称属性,其他的有程序设置。

端口组件: 
    名称: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脚本进行关联

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

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 10分钟,创建你的第一个点线面低代码串口调试应用