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 设置组件属性

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

端口----》dropdownPort

波特率----dropdownBaud

复选框----HexSendCheckbox

发送区----》send

接收区----recivedData

log----》log

 

2.3 添加 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[0].value : null;
const portsLabel = formattedPorts.map(port => port.label);
const portsValue = formattedPorts.map(port => port.value);
const portsSelect = {
  defaultPortsValue,
  portsLabel,
  portsValue,
};

const baudsValue = [9600, 115200];
const baudsLabel = ["9600", "115200"];
const defaultBaudsValue = baudsValue[0];
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 = [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[i] 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[i] = 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.4 组件事件与js脚本进行关联

 

3. 结束

更多的细节需要你自己的探索,那就开始你的点线面低代码的探索之旅吧!

有问题可以私信我,也可以在应用程序中找到联系方式,单独交流。

 

 

 

相关博文:
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目

随笔 - 1, 文章 - 0, 评论 - 1, 阅读 - 5

Copyright © 2025 点线面低代码调试助手
Powered by .NET 9.0 on Kubernetes

点击右上角即可分享
微信分享提示