pcanbasic

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 22, 2026 License: MIT Imports: 8 Imported by: 0

README

pcanbasic_go

PEAK-System PCANBasic.dll 的 Go 语言封装库(Windows 专用)。

Go Reference

pcanbasic_go 在 Windows 平台用纯 Go(syscall 调用,无 CGO)封装 PEAK-System 的 PCANBasic.dll,让 Go 程序能直接收发 CAN / CAN FD 报文,无须再依赖 Python 或 C++ 中间层。

⚠️ 当前为预发布阶段v0.x),API 仍可能调整。本仓库目前处于初始化阶段, 完整设计见 docs/superpowers/specs/2026-05-22-pcanbasic-go-design.md


为什么做这个

  • Linux 端可以用 socketcan 等成熟 Go 库直连 CAN
  • Windows 端 PEAK 官方仅提供 C/C++、C#、Java、Python 等绑定,没有 Go 封装
  • 现有的 Python 桥接(can-bridge-win)需要打包 PyInstaller、引入 python-can 依赖, 在嵌入到机器人控制等纯 Go 项目时既笨重又难以追踪问题

pcanbasic_go 旨在补上这块空缺,作为未来跨平台 CAN 抽象层(Linux 走 socketcan、 Windows 走 PCANBasic)的 Windows 后端。


特性(v0.1 计划)

  • ✅ Classical CAN 与 CAN FD 双标准支持
  • ✅ 高层 Bus API:Send / SendMany / Receive / ReadOne / TryRead / Status / Reset / SetFilter
  • ✅ 三种接收模式:ModeAuto / ModePolling / ModeEvent(Windows Event 驱动)
  • ✅ 子包 raw:与 PCANBasic C API 1:1 对应的低层绑定
  • ✅ 错误处理:位掩码语义 + errors.Is 哨兵
  • ✅ 非 Windows 平台编译桩,便于 Linux/macOS 上做 lint / vet / 单元测试
  • ✅ 完整的中文文档与 10 个示例

详细范围见 设计文档


快速开始(计划交付时)

package main

import (
    "context"
    "log"

    "github.com/Crush251/pcanbasic_go"
)

func main() {
    bus, err := pcanbasic.Open(
        pcanbasic.USBBus1,
        pcanbasic.WithBitrate(pcanbasic.Baud1M),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer bus.Close()

    frame, _ := pcanbasic.NewFrame(0x123, []byte{0x01, 0x02, 0x03, 0x04})
    if err := bus.Send(context.Background(), frame); err != nil {
        log.Fatal(err)
    }
}

系统要求

  • Windows(v0.1 真机仅支持 Windows;非 Windows 平台仅可编译,无法实际通信)
  • Go 1.22+
  • 已安装 PEAK PCAN 驱动(官方下载
  • PCANBasic.dll 与 Go 程序架构匹配(amd64 → 64 位 DLL;386 → 32 位 DLL)

路线图

版本 主要内容
v0.1.0 Classical + FD 收发、Bus 完整高层、raw 子包基础 API、文档与示例
v0.2.0 LookUpChannel、设备信息查询、Trace;Linux libpcanbasic.so 适配
v0.3.0 CAN XL(视需求)
v1.0.0 API 冻结,进入严格兼容承诺

许可证

MIT

Documentation

Overview

Package pcanbasic 是 PEAK-System PCANBasic.dll 的 Go 封装库(Windows 专用)。

顶层包提供 idiomatic Go 高层 API(Bus / Frame / Option / Error), 大多数应用直接使用本包即可。需要 PCAN 特殊功能或希望进一步定制时, 可使用子包 github.com/Crush251/pcanbasic_go/raw。

快速开始

bus, err := pcanbasic.Open(pcanbasic.USBBus1, pcanbasic.WithBitrate(pcanbasic.Baud1M))
if err != nil { log.Fatal(err) }
defer bus.Close()

f, _ := pcanbasic.NewFrame(0x123, []byte{1, 2, 3})
_ = bus.Send(context.Background(), f)

详见 README 与 docs/quickstart.md。

平台

v0.1 真机仅支持 Windows;Linux/macOS 上代码可编译、单元测试可运行, 但 Open/OpenFD 会返回 ErrIllOperation(底层 PCAN_ERROR_ILLOPERATION)。

并发

Bus 内部使用单 reader goroutine 独占底层 Read, 调用方可在多个 goroutine 中并发 Send / Status / Reset / Receive; Close 是幂等的。

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrIDOutOfRange 表示 CAN ID 超出范围(标准 11 位 / 扩展 29 位)。
	ErrIDOutOfRange = errors.New("pcanbasic: CAN ID out of range")
	// ErrDataTooLong 表示数据长度超过该帧类型允许的最大长度。
	ErrDataTooLong = errors.New("pcanbasic: data length exceeds capacity")
	// ErrInvalidFDLength 表示 FD 帧 data 长度不在 {0..8, 12, 16, 20, 24, 32, 48, 64} 中。
	ErrInvalidFDLength = errors.New("pcanbasic: invalid CAN FD data length")
	// ErrRemoteOnFD 表示在 FD 帧上指定了 Remote 标志(FD 协议无 RTR)。
	ErrRemoteOnFD = errors.New("pcanbasic: remote frame not allowed on CAN FD")
	// ErrBusClosed 表示 Bus 已被关闭,后续操作非法。
	ErrBusClosed = errors.New("pcanbasic: bus is closed")
	// ErrNotSupported 表示当前平台不支持此操作(如非 Windows 试图打开真实通道)。
	ErrNotSupported = errors.New("pcanbasic: operation not supported on this platform")
	// ErrDLLNotFound 表示 PCANBasic.dll 加载失败。
	ErrDLLNotFound = errors.New("pcanbasic: PCANBasic.dll not found or failed to load")
	// ErrFDNotSupportedOnBus 表示在非 FD Bus 上尝试发送 FD 帧。
	ErrFDNotSupportedOnBus = errors.New("pcanbasic: FD frame requires a bus opened with OpenFD")
)

库内部错误(参数校验、状态等)。

View Source
var (
	// ErrQueueEmpty 表示接收队列暂时为空(TryRead 用)。
	ErrQueueEmpty = errors.New("pcanbasic: receive queue empty")
	// ErrQueueOverrun 表示接收队列被覆盖(应用读取过慢)。
	ErrQueueOverrun = errors.New("pcanbasic: receive queue overrun")
	// ErrQueueXmtFull 表示发送队列已满。
	ErrQueueXmtFull = errors.New("pcanbasic: transmit queue full")
)

队列状态相关错误。

View Source
var (
	ErrBusLight   = errors.New("pcanbasic: bus light")
	ErrBusHeavy   = errors.New("pcanbasic: bus heavy")
	ErrBusPassive = errors.New("pcanbasic: bus passive")
	ErrBusOff     = errors.New("pcanbasic: bus off")
)

总线状态相关错误(位掩码语义,多个可同时为真)。

View Source
var (
	// ErrNotInitialized 对应 PCAN_ERROR_INITIALIZE:通道未被初始化。
	ErrNotInitialized = errors.New("pcanbasic: channel not initialized")
	// ErrIllHandle 对应 PCAN_ERROR_ILLHANDLE:非法通道句柄。
	ErrIllHandle = errors.New("pcanbasic: invalid channel handle")
	// ErrIllParamType 对应 PCAN_ERROR_ILLPARAMTYPE。
	ErrIllParamType = errors.New("pcanbasic: invalid parameter type")
	// ErrIllParamValue 对应 PCAN_ERROR_ILLPARAMVAL。
	ErrIllParamValue = errors.New("pcanbasic: invalid parameter value")
	// ErrIllOperation 对应 PCAN_ERROR_ILLOPERATION:非法操作(如平台不支持)。
	ErrIllOperation = errors.New("pcanbasic: illegal operation")
	// ErrNoDriver 对应 PCAN_ERROR_NODRIVER:驱动未加载。
	ErrNoDriver = errors.New("pcanbasic: driver not loaded")
	// ErrUnknown 对应 PCAN_ERROR_UNKNOWN。
	ErrUnknown = errors.New("pcanbasic: unknown error")
)

API / 驱动层错误。

Functions

func StatusHas

func StatusHas(status, bit Status) bool

StatusHas 判断 status 中是否包含指定的位。

特别处理 StatusOK (0):仅当 status 也是 0 时才算"包含", 否则按位掩码 AND 判断。

Types

type Bitrate

type Bitrate = raw.TPCANBaudrate

Bitrate 是 Classical CAN 波特率的别名。

常用 Classical CAN 波特率。

type Bus

type Bus struct {
	// contains filtered or unexported fields
}

Bus 表示一个已初始化的 CAN/CAN FD 通道。

必须使用 Close 释放资源。Close 是幂等的,可以从多个 goroutine 安全调用。

func Open

func Open(ch Channel, opts ...Option) (*Bus, error)

Open 打开一个 Classical CAN 通道。

ch 是通道句柄(USBBus1..USBBus16 等); opts 用于配置波特率、接收模式、buffer 大小、Logger 等。

func OpenFD

func OpenFD(ch Channel, fdBitrate string, opts ...Option) (*Bus, error)

OpenFD 打开一个 CAN FD 通道。

fdBitrate 是 PCAN 官方格式的字符串,详见 docs/can-fd.md。 WithBitrate 对 OpenFD 无效(FD 波特率完全由 fdBitrate 决定)。

func (*Bus) Close

func (b *Bus) Close() error

Close 释放底层通道。幂等:多次调用安全。

流程:标记 closed → 关闭 closing → 触发 abort event 唤醒 reader → 等 reader 关闭 rxCh → 释放 event 句柄 → Uninitialize → 关闭 errCh。

func (*Bus) Errors

func (b *Bus) Errors() <-chan error

Errors 返回接收侧的异步错误流。Bus 关闭时 channel 也关闭。 QRCVEMPTY(队列空)不会出现在这里 —— 它是正常状态,不算错误。

func (*Bus) ReadOne

func (b *Bus) ReadOne(ctx context.Context) (Frame, error)

ReadOne 阻塞从接收队列取一帧,直到 ctx 取消或 Bus 关闭。

Bus 关闭时返回 ErrBusClosed。 ctx 被取消时返回 ctx.Err()。

func (*Bus) Receive

func (b *Bus) Receive() <-chan Frame

Receive 返回流式接收 channel。Bus 关闭时 channel 也关闭。

推荐用法:在专门的 goroutine 里 `for f := range bus.Receive()`。

func (*Bus) Reset

func (b *Bus) Reset() error

Reset 复位通道,清空 PCAN 内部的收发队列。 通常用于 BUSOFF 恢复。

func (*Bus) ResetFilter

func (b *Bus) ResetFilter() error

ResetFilter 恢复"接收全部"。 实现方式:通过 SetValue(PCAN_MESSAGE_FILTER, PCAN_FILTER_OPEN) 打开滤波器。

func (*Bus) Send

func (b *Bus) Send(ctx context.Context, f Frame) error

Send 同步发送一帧。Close 后调用返回 ErrBusClosed。

ctx 在 Send 入口被一次性检查(Send 自身是同步调用,不会阻塞太久), 真正长时阻塞应通过 SendMany 或上层超时机制控制。

func (*Bus) SendMany

func (b *Bus) SendMany(ctx context.Context, frames []Frame) error

SendMany 顺序逐帧发送,任意一帧失败立即返回 *SendManyError。

已成功发送的帧不会回滚 —— CAN 总线无事务概念。 ctx 在每帧前检查一次,便于及时取消大批量发送。

func (*Bus) SetFilter

func (b *Bus) SetFilter(idMin, idMax uint32, mode FilterMode) error

SetFilter 设置消息过滤范围(PCAN 默认是开放的,本方法用于收窄)。

idMin/idMax 是要接受的 ID 闭区间;mode 区分 11 位 / 29 位 ID。 多次调用会累加:要恢复"接收全部"应调用 ResetFilter。

func (*Bus) Status

func (b *Bus) Status() (Status, error)

Status 查询通道当前状态。

返回的 Status 是位掩码,使用 StatusHas 判断具体位。

func (*Bus) TryRead

func (b *Bus) TryRead() (Frame, error)

TryRead 非阻塞读一帧。队列空时返回 ErrQueueEmpty;Bus 已关闭返回 ErrBusClosed。

type Channel

type Channel = raw.TPCANHandle

Channel 是 PCAN 通道句柄的别名,方便 Open 调用。

PCAN-USB 通道常量。重新导出 raw 包的对应值,避免使用者引入 raw 包。

type Error

type Error struct {
	Code raw.TPCANStatus // 原始 PCAN 错误位掩码
	Op   string          // 触发错误的操作,如 "CAN_Initialize"
	Msg  string          // 通过 CAN_GetErrorText 取到的可读描述(可能为空)
}

Error 是一次 PCAN API 调用产生的错误。

Code 保留原始的 PCAN 错误位掩码(可能是多个 bit 的 OR 组合), 用 errors.Is(err, ErrXxx) 可精确判断"是否包含某种错误"。

func (*Error) Error

func (e *Error) Error() string

Error 实现 error。

func (*Error) Has

func (e *Error) Has(code raw.TPCANStatus) bool

Has 判断错误码中是否包含某个具体错误位。

特别处理 PCAN_ERROR_OK (0):仅当 e.Code 也是 0 时才算"包含"。 否则按位掩码 AND 判断。

func (*Error) Is

func (e *Error) Is(target error) bool

Is 让一个 *Error 可以同时匹配多个哨兵错误(位掩码语义)。

因为 PCAN 错误码本质是位掩码,单次 API 调用可能同时报告 BUSOFF|QOVERRUN, 此时 errors.Is(err, ErrBusOff) 和 errors.Is(err, ErrQueueOverrun) 都应为 true。

type FilterMode

type FilterMode uint8

FilterMode 用于 SetFilter。

const (
	FilterStandard FilterMode = 0 // 接收 11 位 ID
	FilterExtended FilterMode = 1 // 接收 29 位 ID
)

过滤器模式:区分 11 位 / 29 位 ID。

type Frame

type Frame struct {
	ID    uint32     // CAN 标识符(11 位 / 29 位由 FlagExtended 决定)
	Data  []byte     // 数据载荷
	Flags FrameFlags // 帧类型标志位

	TimestampMicros uint64    // PCAN 提供的微秒时间戳(接收帧才有效)
	ReceivedAt      time.Time // Go 进程接收到该帧的时刻(接收帧才有效)
}

Frame 代表一帧 CAN 报文,统一承载 Classical / Extended / Remote / FD。

通过 Flags 区分帧类型;Data 长度 + Flags 决定底层映射到 TPCANMsg 还是 TPCANMsgFD。 接收到的帧会填充 TimestampMicros(PCAN 自带)和 ReceivedAt(Go 端时刻)。

func NewExtendedFrame

func NewExtendedFrame(id uint32, data []byte) (Frame, error)

NewExtendedFrame 构造一帧扩展 Classical CAN 报文(29 位 ID)。

ID 必须 ≤ 0x1FFFFFFF;data 长度必须 ≤ 8。

func NewFDFrame

func NewFDFrame(id uint32, data []byte, brs, extended bool) (Frame, error)

NewFDFrame 构造一帧 CAN FD 报文。

data 长度必须属于 {0..8, 12, 16, 20, 24, 32, 48, 64}。 brs 控制是否启用加速段;extended 控制是否使用 29 位扩展 ID。 FD 协议无 RTR,因此不允许 Remote 标志。

func NewFrame

func NewFrame(id uint32, data []byte) (Frame, error)

NewFrame 构造一帧标准 Classical CAN 报文(11 位 ID)。

ID 必须 ≤ 0x7FF;data 长度必须 ≤ 8。 data 会被深拷贝,调用者后续修改原切片不影响已构造的 Frame。

func NewRemoteFrame

func NewRemoteFrame(id uint32, dlc uint8, extended bool) (Frame, error)

NewRemoteFrame 构造一帧远程请求帧(Classical CAN 专用)。

dlc 表示请求长度(≤ 8);extended 控制是否使用 29 位扩展 ID。 远程帧没有真实数据,Data 字段会被填充 dlc 个零字节用于标记长度。

func (Frame) Has

func (f Frame) Has(flag FrameFlags) bool

Has 判断 Flags 中是否包含指定位。

type FrameFlags

type FrameFlags uint16

FrameFlags 是 Frame 类型/属性位的组合。

const (
	FlagExtended FrameFlags = 1 << iota // 29 位扩展 ID
	FlagRemote                          // 远程帧(仅 Classical CAN)
	FlagFD                              // CAN FD 帧
	FlagBRS                             // FD 加速段(仅 FD 帧有意义)
	FlagESI                             // FD 错误状态指示(仅 FD 帧有意义)
)

Frame 标志位常量。

type Logger

type Logger interface {
	Debugf(format string, args ...any)
	Infof(format string, args ...any)
	Warnf(format string, args ...any)
}

Logger 是本库内部使用的极简日志接口。

默认使用 noopLogger(什么都不打印)。如需接入 slog/zap/logrus, 实现下面三个方法并通过 WithLogger 注入即可。

接口故意保持最小:库本身只在少数地方打 Debug/Info/Warn 日志, 不输出 Error 级(错误通过 *Error/Errors() 返回给调用方)。

type Option

type Option func(*config)

Option 用于配置 Open / OpenFD。

func WithBitrate

func WithBitrate(b Bitrate) Option

WithBitrate 设置 Classical CAN 波特率,默认 Baud1M。

OpenFD 时此选项被忽略 —— FD 波特率由 OpenFD 的 fdBitrate 字符串决定。

func WithErrBufferSize

func WithErrBufferSize(n int) Option

WithErrBufferSize 设置错误 channel 容量,默认 16。 非正值会被忽略并保留默认。

func WithLogger

func WithLogger(l Logger) Option

WithLogger 注入日志接口。默认 noopLogger 不打印任何东西。 传入 nil 会被忽略。

func WithPollInterval

func WithPollInterval(d time.Duration) Option

WithPollInterval 设置 Polling 模式下的轮询间隔,默认 1ms。

非正值(≤0)会被忽略并保留默认。 仅 ModePolling(或 ModeAuto 降级到 Polling)时生效。

func WithReceiveMode

func WithReceiveMode(m ReceiveMode) Option

WithReceiveMode 设置接收模式,默认 ModeAuto。

func WithRxBufferSize

func WithRxBufferSize(n int) Option

WithRxBufferSize 设置接收 channel 容量,默认 1024。 非正值会被忽略并保留默认。

type ReceiveMode

type ReceiveMode int

ReceiveMode 控制 Bus 内部 reader goroutine 的等待策略。

const (
	// ModeAuto:Windows + 驱动支持事件 → Event;否则退回 Polling。
	// 库的默认模式:兼顾延迟与可移植性。
	ModeAuto ReceiveMode = iota
	// ModePolling:以 WithPollInterval 设定的间隔轮询底层。
	ModePolling
	// ModeEvent:Windows Event Handle 阻塞等待,CPU 占用最低。
	ModeEvent
)

接收模式常量。

type SendManyError

type SendManyError struct {
	Index int   // 失败的帧下标
	Frame Frame // 失败的帧本身(深拷贝)
	Err   error // 底层错误
}

SendManyError 标识 SendMany 中第 Index 帧(0-based)发送失败。

Frame 是失败帧的深拷贝,调用方可安全持有以供日志或重试使用。 已成功发送的帧不会回滚(CAN 总线无事务概念)。

func (*SendManyError) Error

func (e *SendManyError) Error() string

Error 实现 error。

func (*SendManyError) Unwrap

func (e *SendManyError) Unwrap() error

Unwrap 让 errors.Is/errors.As 可以穿透到内部错误。

type Status

type Status = raw.TPCANStatus

Status 是 PCAN 通道当前状态的位掩码值。

直接 alias raw.TPCANStatus 以保证与官方常量值一致; 与 *Error.Code 是同一底层类型,便于互操作。

const (
	StatusOK           Status = raw.PCAN_ERROR_OK
	StatusBusLight     Status = raw.PCAN_ERROR_BUSLIGHT
	StatusBusHeavy     Status = raw.PCAN_ERROR_BUSHEAVY
	StatusBusPassive   Status = raw.PCAN_ERROR_BUSPASSIVE
	StatusBusOff       Status = raw.PCAN_ERROR_BUSOFF
	StatusQueueOverrun Status = raw.PCAN_ERROR_QOVERRUN
)

通道状态常量。注意这些是位掩码,可以多个同时置位(如 BUSOFF|QOVERRUN)。

Directories

Path Synopsis
examples
04_send_fd command
05_receive_fd command
07_filter command
09_with_logger command
10_using_raw command
Package raw 提供 PCANBasic.dll C API 的零开销 Go 绑定。
Package raw 提供 PCANBasic.dll C API 的零开销 Go 绑定。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL