Skip to content

Inconsistent CAN interfaces #5442

@kenbell

Description

@kenbell

I'm implementing CAN for ESP32. I've found the interfaces are inconsistent, so I'm proposing that like I2C and SPI a strict minimum interface is enforced for sending / receiving CAN messages.

First, a quick audit/comparison:

Fn drivers/mcp2515 atsame5x STM32G0 Notes
Configure Configure(cfg Configuration) Configure(config CANConfig) error Configure(config FDCANConfig) error
Start Begin(speed byte, clock byte) error - Start() error Inconsistent with other drivers? Why have a Start/Begin?
Stop - - Stop() error Inconsistent with other drivers? Optional?
Available Received() bool RxFifoIsEmpty() bool RxFifoIsEmpty() bool
Tx Full - TxFifoIsFull() bool TxFifoIsFull() bool
Rx Rx() (*CANMsg, error) Rx() (id uint32, dlc byte, data []byte, isFd, isExtendedID bool) Rx() (id uint32, dlc byte, data []byte, isFD, isExtendedID bool, err error) Basic Rx does mandatory allocation, errors are inconsistent
Raw Rx - RxRaw(e *CANRxBufferElement) RxRaw(e *FDCANRxBufferElement) error is mcp2515 Rx really Raw Rx?
Tx Tx(canid uint32, dlc uint8, data []byte) error Tx(id uint32, data []byte, isFD, isExtendedID bool) Tx(id uint32, data []byte, isFD, isExtendedID bool) error Inconsistent error handling
Raw Tx - TxRaw(e *CANTxBufferElement) TxRaw(e *FDCANTxBufferElement) error
Reset Reset() error - - Is this really Stop?

Proposal

Implement a can.go in src/machine that demands a consistent interface for CAN:

//go:build XXXXX

package machine

var (
    ErrCANTxFifoFull  = errors.New("can: tx fifo full")
	ErrCANRxFifoEmpty = errors.New("can: rx fifo empty")
)

// If you are getting a compile error on this line please check to see you've
// correctly implemented the methods on the CAN type. They must match the
// interface method signatures type to type perfectly. If not implementing
// the CAN type please remove your target from the build tags at the top of
// this file.
var _ interface {
    // False if there is at least one frame to read
    RxFifoIsEmpty() bool

    // True if Tx would overflow transmission fifo
    TxFifoIsFull() bool

    // Rx returns a frame (if one available), or error
    Rx() (id uint32, data []byte, isFD bool, isExtendedID bool, err error)

    // RxTo returns a frame (if one available), or error
    RxTo(data []byte) (id uint32, len uint32, isFD bool, isExtendedID bool, err error)

    // Tx transmits a from (if space), or error
    Tx(id uint32, data []byte, isFD bool, isExtendedID bool) error
} = (*CAN)(nil)

Notes:

  • Use consistent existing RxFifoIsEmpty / TxFifoIsFull to indicate suitability to Rx or Tx
  • Make error return consistent
  • Provide RxTo to enable allocation-free semantics for Rx (especially 'classic CAN' with 8-byte limit)
  • I've left out Configuration / Start since it's quite varied right now and the biggest value is being able to pass a running 'CAN' device to higher-level protocol logic, rather than initialization.
  • STM32G0 has the type FDCAN rather than CAN. Suggest adding a type alias (type CAN = FDCAN) to ensure FDCAN remains to avoid breaking existing code.

Make these device-specific / optional:

  • Configure
  • Start / Begin
  • Stop / Reset
  • RawRx / RawTx
  • Fifo Sizing

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions