slcan 协议 脚本 测试

slcan 协议

slcan, 基于文本 ASCII 的协议, 也是 LAWICEL 硬件设备的协议, CAN Tools by LAWICEL 有两种硬件设备:

  • CANUSB: 目前是 2011 年的 Version 1.0D
  • CAN232: 目前是 2023 年的 Version 3.0B

协议有细微差别, 整体不大, 以 CANUSB 为例:

  • 所有命令 \r 结尾, 大小写敏感, 设备一般会返回 信息 或者 状态 ( \r 表示 OK, 或者 \b 表示 ERROR)
  • Sn\r, 设置 Setup 标准 CAN 的位速率, 其中 n 取 0~8, 对应 10,20,50,100,125,250,500,800,1000Kbit/s, 如想设置 500Kbit/s, 只需要通过串口给 slcan 设备发 S6\r 即可, 设备会返回 \r 表示 OK, 或者 \b 表示 ERROR
  • O\r, 打开 Open CAN 通道, 返回值同上
  • C\r, 关闭 Close CAN 通道, 返回值同上
  • tiiildd...\r, 发送标准帧, 如 t0A70\r 表示发送 id 为 0x0A7, 长度为 0 的标准帧, 又比如 t7FF81122334455667788\r 表示发送 id 为 0x7FF, 长度为8, 数据为 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 的标准帧. 注: CAN接收再通过串口发出来的数据也一样. 返回 z\r 表示 OK, \b表示 ERROR
  • Tiiiiiiiildd..\r, 发送扩展帧, 如 T0C34567F20102\r 表示发送 id 为 0x0C34567F, 长度为2, 数据为 0x01,0x02 的扩展帧返回 Z\r 表示 OK, \b表示 ERROR
  • riiil\r, 发送标准远程帧, 如 r1000\r 表示 发送 0x100 的远程帧, 返回 z\r 表示 OK, \b表示 ERROR
  • Riiiiiiiil\r, 发送扩展远程帧, 如 r1234567F2 表示发送 0x1234567F 且 DLC=2 的 远程帧
  • F\r, 读状态标志 Flags, 返回 Fxx\r 表示 OK, 其中 xx 是2字节, 也就是8个bit, 分别代表 0-接收FIFO满, 1-发送FIFO满, 2-Error Warning, 3-Data Overrun, 4-Not used, 5-Error Passive, 6-Arbitration Lost, 7-Bus Error, 如果 can 通道没有打开, 返回 \b
  • V\r, 查询版本 Version 号, 返回值为 Vxxyy\r, 如 返回 V1013\r 表示硬件版本号1.0, 软件或固件版本号1.3
  • N\r, 查询Serial编号, 如保存在 EEPROM 中的编号, 可用于程序中区分多个slcan设备, 返回值 Nxxxx\r, 如 NA123\r
  • Zn\r, 设置4字节毫秒时间戳, Z0\r为默认值, 关闭时间戳, Z1\r打开时间戳. 如 关闭时间戳为 t10021133\r, 打开时间戳为 t10021133A902\r, 0xA902=43266, 即 时间戳为 43.266s, 为 mcu 打的时间戳
  • 其它命令可参考 CANUSBCAN232 中的手册

slcan 协议的优点是比较直观, 缺点也很明显, ascii 协议 相比 hex协议 太浪费带宽了, 如本来8bit的数据 0x12 需要用两个ascii字符 12 表示, 直接导致了协议膨胀, 但 slcan 在 linux 中支持较早, 也比较完善, 有参考学习和使用的价值

slcan 的代码实现 github 上有一堆, 如latonita/arduino-canbus-monitor, slcanuino/slcan.ino, conroy-cheers/rusty-can, 也有各种MCU的移植实现如 CANable. 此处略.

kernel slcan

slcan 在 Linux 内核源码中的目录为 drivers/net/can/slcan.c, 一般的 Ubuntu 发行版默认已经有了, 像 WSL 这种可以下载 WSL 内核源码后 make menuconfig 手动开启

在这里插入图片描述

slcan 的加载

sudo modprobe can
sudo modprobe can_raw
sudo modprobe slcan

可以管理员运行 powershell, 用 usbipd 把设备连到 WSL 系统

# 查看wsl发行版名称
wsl -l
# 查看设备的BUSID
usbipd list
# 把设备从windows系统连到wsl的发行版, 如
usbipd wsl attach -d Ubuntu --busid 1-14
# 断开设备连接, 重连到windows
usbipd wsl detach --busid 1-14

can-utils slcanpty

linux-can/can-utils 这个用户空间应用直接提供了 slcan_attach, slcand, slcanpty 这几个应用, 这里先介绍 slcanpty, 可以创建一个遵循 slcan 协议的 pty, 把 ascii 数据转给 can 网络接口, 给手头没有 slcan 设备的体验下 slcan 协议. 用法: slcanpty <pty> <can interface> 这里 pty 可以是默认都有的 /dev/ptmx

#!/bin/bash
sudo modprobe can
sudo modprobe can_raw
sudo modprobe vcan
sudo modprobe slcan

sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
sudo slcanpty /dev/ptmx vcan0

运行完最后一行后会打印 open: /dev/ptmx: slave pseudo-terminal is /dev/pts/19 且不退出. 接下来可以用 minicom 来测试一下

sudo minicom -D /dev/pts/19
# 可以 Ctrl+A,Z, 然后E, 打开输入回显 local Echo
# Ctrl+A,Z, 然后A, 打开行反馈 linefeed

测试结果如图

在这里插入图片描述

时间戳的测试

在这里插入图片描述

can-utils slcand

假设有 slcan 的真家伙, 就可以直接当 socketcan 来使

#!/bin/bash
sudo modprobe can
sudo modprobe can_raw
sudo modprobe slcan

sudo slcand -c -s6 -o -f -S2000000 /dev/ttyACM1 can0
sudo ip link set up can0

下面是 slcand 命令的使用方法

$ slcand
slcand - userspace daemon for serial line CAN interface driver SLCAN.

Usage: slcand [options] <tty> [canif-name]

Options:
         -o          (send open command 'O\r')
         -c          (send close command 'C\r')
         -f          (read status flags with 'F\r' to reset error states)
         -l          (send listen only command 'L\r', overrides -o)
         -s <speed>  (set CAN speed 0..8)
         -S <speed>  (set UART speed in baud)
         -t <type>   (set UART flow control type 'hw' or 'sw')
         -b <btr>    (set bit time register value)
         -F          (stay in foreground; no daemonize)
         -h          (show this help page)

Examples:
slcand -o -c -f -s6 ttyUSB0

slcand -o -c -f -s6 ttyUSB0 can0

slcand -o -c -f -s6 /dev/ttyUSB0

接下来解释下 sudo slcand -c -s6 -o -f -S2000000 /dev/ttyACM1 can0:

  • -c, close, 首先关闭can通道
  • -s6, 设置 can 位速率 500 kbit/s, 注: 0~8, 对应 10,20,50,100,125,250,500,800,1000Kbit/s
  • -o, open, 打开can通道
  • -f, 读取状态
  • -S2000000, 串口波特率2Mbps, 因为是通过串口通信, 所以需要知道底层的串口波特率, 一般为 115200bps, 961200bps或2Mbps, slcand的最新源码里支持到 4Mbps
  • /dev/ttyACM1, 串口和虚拟串口设备
  • can0, 在 ip linkifconfig 中对应的名字
  • 事实上这条命令会让串口发出 C\rS6\rF\rO\r

运行完上面的脚本后, 就可以进行 candump cansend 收发了, 把 slcan 设备 接上 can 分析仪测试, 注意挂上至少 120Ω 终端电阻.

在这里插入图片描述

slcand 也可以用 socat 生成虚拟串口对来测试通信协议 sudo socat -d -d pty,link=/dev/ttyS10,raw,echo=0 pty,link=/dev/ttyS11,raw,echo=0

can-utils slcan_attach

slcan_attach 起到和 slcand 类似的效果, 只是不能指示波特率, 是不是弃用了?

sudo slcan_attach -s6 -o /dev/ttyACM13 -n can0
# 实际发出 `C\rS6\rO\r`, 为 9600bps
sudo ip link set up can0

slcan_attach 帮助文档为

$ slcan_attach
slcan_attach - userspace tool for serial line CAN interface driver SLCAN.

Usage: slcan_attach [options] tty

Options:
         -o          (send open command 'O\r')
         -l          (send listen only command 'L\r', overrides -o)
         -c          (send close command 'C\r')
         -f          (read status flags with 'F\r' to reset error states)
         -s <speed>  (set CAN speed 0..8)
         -b <btr>    (set bit time register value)
         -d          (only detach line discipline)
         -w          (attach - wait for keypress - detach)
         -n <name>   (assign created netdevice name)

    <speed>          Bitrate
          0            10 Kbit/s
          1            20 Kbit/s
          2            50 Kbit/s
          3           100 Kbit/s
          4           125 Kbit/s
          5           250 Kbit/s
          6           500 Kbit/s
          7           800 Kbit/s
          8          1000 Kbit/s


Examples:
slcan_attach -w -o -f -s6 -c /dev/ttyS1

slcan_attach /dev/ttyS1

slcan_attach -d /dev/ttyS1

slcan_attach -w -n can15 /dev/ttyS1

python slcan

linux 中可以直接使用 soketcan 来操作 slcan, 但是 windows 中没有 socketcan, 怎么操作 slcan 设备? 因为协议并不复杂, 完全可以手搓 串口通信 来收发 can 报文, 也有很多现成的封装好的, 如 CAN over Serial / SLCAN — python-can, 安装 python3 -m pip install python-can

windows 上 python 使用 slcan 发送 can 报文的示例代码

import can

# slcan
bus = can.interface.Bus(bustype='slcan', channel='COM3', ttyBaudrate=2000000, bitrate=500000)

# send msg
msg = can.Message(arbitration_id=0xc0ffee, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=True)
bus.send(msg)
msg = can.Message(arbitration_id=0x123, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=False)
bus.send(msg)

# receive msg
while True:
    msg = bus.recv()
    print(msg)
    if(msg.arbitration_id == 0x0120ffee):
        print("This is a message with id 0x0120ffee")
    elif(msg.arbitration_id == 0x456):
        print("This is a message with id 0x456")
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值