slcan 协议 脚本 测试
slcan 协议
slcan, 基于文本 ASCII 的协议, 也是 LAWICEL 硬件设备的协议, CAN Tools by LAWICEL 有两种硬件设备:
协议有细微差别, 整体不大, 以 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
表示 ERRORO\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
表示 ERRORTiiiiiiiildd..\r
, 发送扩展帧, 如T0C34567F20102\r
表示发送 id 为 0x0C34567F, 长度为2, 数据为 0x01,0x02 的扩展帧返回Z\r
表示 OK,\b
表示 ERRORriiil\r
, 发送标准远程帧, 如r1000\r
表示 发送 0x100 的远程帧, 返回z\r
表示 OK,\b
表示 ERRORRiiiiiiiil\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.3N\r
, 查询Serial编号, 如保存在 EEPROM 中的编号, 可用于程序中区分多个slcan设备, 返回值Nxxxx\r
, 如NA123\r
Zn\r
, 设置4字节毫秒时间戳,Z0\r
为默认值, 关闭时间戳,Z1\r
打开时间戳. 如 关闭时间戳为t10021133\r
, 打开时间戳为t10021133A902\r
, 0xA902=43266, 即 时间戳为 43.266s, 为 mcu 打的时间戳- 其它命令可参考 CANUSB 和 CAN232 中的手册
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 link
或ifconfig
中对应的名字- 事实上这条命令会让串口发出
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")