README
¶
canbuskit
canbuskit 是一个面向 Go 的 CAN / CAN FD 诊断工具库,提供了:
- 多种底层 CAN 驱动封装
- ISO-TP 传输层实现
- UDS 客户端
- 常见 UDS 服务封装
- 面向刷写场景的 HEX / SREC 分块辅助能力
项目适合做 ECU 诊断、刷写、自动化测试,以及把不同 CAN 硬件接入统一的 Go 接口。
当前硬件驱动统一支持标准 11 位 ID 的 CAN / CAN FD 数据帧;29 位扩展帧不在驱动层支持范围内。
模块结构
仓库主要分成四层:
driver:底层 CAN 驱动统一接口,屏蔽不同厂商设备差异tp_layer:ISO-15765-2 传输层,实现单帧、多帧、流控、超时管理uds_client:基于driver + ISO-TP的 UDS 客户端,负责请求、超时、负响应和重试逻辑services:对常见 UDS 服务做了更高层封装
如果现成服务不够用,也可以直接调用 UDSClient.Request(...) 发送任意 SID。
已支持的驱动
本地硬件驱动
driver.NewToomoss(...)- Windows
- macOS(
darwin && cgo)
driver.NewTSMaster(...)- Windows
driver.NewPCAN(...)- Windows
driver.NewVector(...)- Windows
driver.NewAutoDriver(...)- Windows
- 按
Toomoss -> TSMaster -> PCAN -> Vector顺序自动选择第一个可用设备
安装
go get github.com/LoveWonYoung/canbuskit
快速开始
下面示例演示一个典型链路:
CAN Driver -> Adapter -> ISO-TP -> UDS Client -> UDS Service
package main
import (
"fmt"
"log"
"github.com/LoveWonYoung/canbuskit/driver"
"github.com/LoveWonYoung/canbuskit/services"
isotp "github.com/LoveWonYoung/canbuskit/tp_layer"
"github.com/LoveWonYoung/canbuskit/uds_client"
)
func main() {
dev := driver.NewToomoss(driver.CANFD, driver.CHANNEL1)
addr, err := isotp.NewAddress(
isotp.Normal11Bit,
isotp.WithTxID(0x7C6),
isotp.WithRxID(0x7C7),
)
if err != nil {
log.Fatal(err)
}
client, err := uds_client.NewUDSClient(dev, addr, isotp.DefaultConfig())
if err != nil {
log.Fatal(err)
}
defer client.Close()
client.SetFDMode(true)
rdbi := services.NewReadDataByIdentifier(client)
resp, err := rdbi.ReadDataByIdentifier(0xF190)
if err != nil {
log.Fatal(err)
}
fmt.Printf("VIN: %X\n", resp.Values[0xF190])
}
如果你在 Windows 下希望自动挑选本机可用设备,可以把驱动替换成:
dev := driver.NewAutoDriver(driver.CANFD)
驱动配置
旧构造函数默认使用通道 1、500 kbit/s 仲裁速率、2 Mbit/s 数据速率。需要自定义时,可以使用统一的 driver.Config:
cfg := driver.DefaultConfig(driver.CANFD, driver.CHANNEL2)
cfg.NominalBitrate = 500_000
cfg.DataBitrate = 4_000_000
cfg.RxBufferSize = 4096
cfg.PollingInterval = 500 * time.Microsecond
dev := driver.NewToomossWithConfig(cfg)
Windows 下的其他驱动对应使用:
pcan := driver.NewPCANWithConfig(cfg)
tsmaster := driver.NewTSMasterWithConfig(cfg, driver.TC1016)
vector := driver.NewVectorWithConfig(cfg, driver.CANOEVN1640)
auto := driver.NewAutoDriverWithConfig(cfg)
对 TSMaster 而言,cfg.Channel 表示物理硬件通道。默认会把应用逻辑通道 CAN1 映射到设备索引 0 的该物理通道。例如只连接一个设备但使用物理 CAN4:
cfg := driver.DefaultConfig(driver.CANFD, driver.CHANNEL4)
tsmaster := driver.NewTSMasterWithConfig(cfg, driver.TC1016)
// 映射结果:应用 CAN1 -> 设备 0 / 物理 CAN4
需要指定其他应用通道或第 N 个设备时,可以显式配置映射:
mapping := driver.TSMasterMapping{
ApplicationChannel: driver.CHANNEL2,
HardwareIndex: 1,
HardwareChannel: driver.CHANNEL4,
}
tsmaster := driver.NewTSMasterWithMapping(cfg, driver.TC1016, mapping)
IncludeTxEcho 默认为 false。抓包程序如果需要同时观察发送帧,可以显式开启;ISO-TP Adapter 始终只接收 RX 帧。
AutoDriver 会按默认顺序探测设备,清理初始化失败或模式不匹配的候选。也可以通过 AutoCandidate 传入自定义顺序和设备构造参数。
寻址与 ISO-TP 配置
tp_layer 支持多种寻址模式:
Normal11BitNormal29BitNormalFixed29BitExtended11BitExtended29BitMixed11BitMixed29Bit
基础配置来自:
cfg := isotp.DefaultConfig()
你可以按需覆盖:
PaddingByteTimeoutN_As / N_Bs / N_CsTimeoutN_Ar / N_Br / N_CrBlockSizeStMin
UDS 客户端能力
uds_client.UDSClient 负责:
- 请求发送与响应接收
- 超时管理
0x7F负响应解析0x78 Response Pending自动继续等待- 可重试负响应的有限重试
- 物理地址 / 功能地址切换
- CAN / CAN FD 切换
常用方法:
Request(payload []byte)RequestWithTimeout(payload, timeout)RequestWithContext(ctx, payload, opts)SendAndRecv(payload, timeout)SetFDMode(isFD bool)SetFunctionalAddress(addr)UseFunctionalAddress()UsePhysicalAddress()
例如,直接发送一个未封装的 UDS 请求:
resp, err := client.Request([]byte{0x10, 0x03})
已封装的 UDS 服务
services 目录目前包含:
ReadDataByIdentifier(0x22)RoutineControl(0x31)RequestDownload(0x34)TransferData(0x36)RequestTransferExit(0x37)SecurityAccess(0x27)
示例:读取多个 DID
rdbi := services.NewReadDataByIdentifier(client)
resp, err := rdbi.ReadDataByIdentifierWithLengths(
map[uint16]int{
0xF187: 16,
0xF190: 17,
},
0xF187,
0xF190,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("DID F187: %X\n", resp.Values[0xF187])
fmt.Printf("DID F190: %X\n", resp.Values[0xF190])
刷写流程示例
仓库已经提供了刷写链路里最常见的几个步骤封装:
RequestDownloadTransferDataRequestTransferExit
同时支持把 HEX / SREC 文件解析成分段和分块。
reqDownload := services.NewRequestDownload(client)
transfer := services.NewTransferData(client)
exit := services.NewRequestTransferExit(client)
downloadResp, err := reqDownload.RequestDownload(0x00100000, 0x00002000, 4, 4)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ECU max block len: %d\n", downloadResp.MaxLength)
_, nextSeq, err := transfer.TransferHexFile("./app.hex", 256, 1)
if err != nil {
log.Fatal(err)
}
fmt.Printf("next sequence: 0x%02X\n", nextSeq)
_, err = exit.RequestTransferExit(nil)
if err != nil {
log.Fatal(err)
}
如果你只想解析文件,不立刻发送,也可以直接使用:
ParseHexSegmentsMyHexParserMyHexParserWithLengths
支持按扩展名或内容自动识别:
- Intel HEX
- SREC / S19 / S28 / S37
SecurityAccess 说明
services.SecurityAccess 在不同平台行为不同:
- Windows:通过
SecKey.dll加载SecKeyCmac计算 key - 非 Windows:提供 stub,实现会返回不支持错误
如果你的项目依赖 SecurityAccess,需要自行准备匹配 ECU 算法的 SecKey.dll。
注意事项
driver层只提供统一的Write(id, fd, data)能力,通过fd标志在同一函数里发送 CAN / CAN-FD。- 驱动层只接受
0x000-0x7FF的标准 11 位 CAN ID。 services只封装了部分常见 UDS 服务;其他服务建议直接用UDSClient.Request(...)。UDSClient.Close()会同时关闭后台 goroutine 和底层设备连接,使用结束后应主动调用。
测试
go test ./...
当前仓库已经包含 tp_layer、uds_client 的测试。
License
[MIT]