Skip to main content

CANFD Functions

dev.io.canfd - wire path i\c - generated from fwMenuCANFD.

enable_canfd_stream

Stream CAN(FD). Streams received CAN frames and errors to the host.

Requires power zone 15 (CAN). See Errors.

Stream CAN(FD)

Enables or disables streaming of received CAN/CAN-FD frames and bus errors from the selected channel to the host.

Arguments
  • channel — CAN controller index
    • 0 — CAN channel 0 (obCANFD1)
    • 1 — CAN channel 1 (obCANFD2)
  • enabled — stream state
    • 0 — disable streaming
    • 1 — enable streaming
Returns
  • success1 if both arguments parsed correctly, 0 otherwise.
Example
o 0 1 # enable streaming on channel 0
o 1 0 # disable streaming on channel 1
Notes
  • Each channel streams independently; toggling one channel does not affect the other.
  • If only channel parses successfully but enabled does not, streaming on that channel is forced off as a safety fallback.
  • All frames will be received unless a receive filter is configured (see Setup Filter) so the controller actually accepts the frames you want to observe.
  • FreeWili2 only has one CAN channel (channel 2 is reserved for future orcas)

Wire command: i\c\o

ArgWire type
channeldecS32
enableddecS32

Returns: none (Ok/Err only)

dev.io.canfd.enable_canfd_stream(channel: int, enabled: int) -> Result
ow_status ow_io_canfd_enable_canfd_stream(ow_device* dev, int32_t channel, int32_t enabled);
dev.io().canfd().enable_canfd_stream(channel: i32, enabled: i32) -> Result<(), OwError>

The C and Rust signatures above are also the WASM guest signatures - the device API surface is identical; only the transport differs (ow_open_wasm(&dev) in C, OneWili::open() in Rust).

dev.io.canfd.enable_canfd_stream(channel, enabled) # check dev.ok

write_canfd

Transmit CAN(FD). Transmits a CAN(FD) frame.

Requires power zone 15 (CAN). See Errors.

Transmit CAN(FD)

Transmits a single CAN 2.0 or CAN-FD frame on the selected channel. The frame is queued to the controller's transmit FIFO and sent as soon as the bus permits.

Arguments
  • channel — CAN controller index
    • 0 — CAN channel 0 (obCANFD1)
    • 1 — CAN channel 1 (obCANFD2)
    • Note: FreeWili2 only has one CAN channel; channel 1 is reserved for future Orcas.
  • arbId — arbitration ID (hex)
    • 11-bit value (0x0000x7FF) when xtdId = 0
    • 29-bit value (0x000000000x1FFFFFFF) when xtdId = 1
  • canFd — frame format
    • 0 — classic CAN 2.0 frame
    • 1 — CAN-FD frame (allows >8 data bytes and bit-rate switching as configured on the controller)
  • xtdId — identifier length
    • 0 — standard 11-bit ID
    • 1 — extended 29-bit ID
  • dataIn — payload bytes in hex, space-separated (e.g. DE AD BE EF). May be empty for a zero-length frame.
Valid payload lengths (DLC)
  • Classic CAN (canFd = 0): 08 bytes.
  • CAN-FD (canFd = 1): 08, 12, 16, 20, 24, 32, 48, or 64 bytes.

Any other byte count is rejected and the command reports Invalid.

Returns
  • success1 if the frame was accepted by the controller for transmission, 0 otherwise.
Examples
#### Classic CAN, standard ID 0x123, 4 data bytes
w 0 0x123 0 0 DE AD BE EF

#### Classic CAN, extended ID 0x1ABCDEF, no data (remote/empty frame)
w 0 0x01ABCDEF 0 1

#### CAN-FD, standard ID 0x200, 16-byte payload
w 0 0x200 1 0 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
Notes
  • The frame is queued to the transmit FIFO; if the FIFO is full or the bus is unavailable the frame may be delayed.
  • Make sure the controller's bit timing (and FD data-phase timing) is configured before transmitting — see the Neptune/Orca setup commands.
  • For periodic / repeated transmission use Transmit CAN(FD) Periodic instead.

Wire command: i\c\w

ArgWire type
channeldecS32
arb_idhexU32
can_fddecS32
xtd_iddecS32
data_inbyteArray

Returns: none (Ok/Err only)

dev.io.canfd.write_canfd(channel: int, arb_id: int, can_fd: int, xtd_id: int, data_in: bytes | bytearray) -> Result
ow_status ow_io_canfd_write_canfd(ow_device* dev, int32_t channel, uint32_t arb_id, int32_t can_fd, int32_t xtd_id, const uint8_t* data_in, size_t data_in_len);
dev.io().canfd().write_canfd(channel: i32, arb_id: u32, can_fd: i32, xtd_id: i32, data_in: &[u8]) -> Result<(), OwError>

The C and Rust signatures above are also the WASM guest signatures - the device API surface is identical; only the transport differs (ow_open_wasm(&dev) in C, OneWili::open() in Rust).

dev.io.canfd.write_canfd(channel, arb_id, can_fd, xtd_id, data_in) # check dev.ok

write_canfd_periodic

Transmit CAN(FD) Periodic. Transmits a CAN(FD) frame periodically (period in us; 0 = as fast as possible).

Requires power zone 15 (CAN). See Errors.

Transmit CAN(FD) Periodic

Configures one of the controller's periodic-transmit slots. Each slot holds a CAN/CAN-FD frame that is re-sent automatically at a fixed interval (or as fast as the bus permits) until it is disabled.

Arguments
  • index — periodic slot, 0RPCANFD_NUM_PERIODICS-1. Each channel has its own independent set of slots.
  • enable — slot state
    • 1 — enable the slot (and load it with the frame defined below)
    • 0 — disable the slot
  • period — transmit interval in microseconds
    • 0 — send as fast as possible (whenever the TX FIFO has room)
    • >0 — send one frame every period µs
  • channel — CAN controller index
    • 0 — CAN channel 0 (obCANFD1)
    • 1 — CAN channel 1 (obCANFD2)
    • Note: FreeWili2 only has one CAN channel; channel 1 is reserved for future Orcas.
  • arbId — arbitration ID (hex)
    • 11-bit (0x0000x7FF) when xtdId = 0
    • 29-bit (0x000000000x1FFFFFFF) when xtdId = 1
  • canFd — frame format
    • 0 — classic CAN 2.0
    • 1 — CAN-FD
  • xtdId — identifier length
    • 0 — standard 11-bit ID
    • 1 — extended 29-bit ID
  • dataIn — payload bytes in hex, space-separated (e.g. DE AD BE EF). May be empty for a zero-length frame.
Valid payload lengths (DLC)
  • Classic CAN (canFd = 0): 08 bytes.
  • CAN-FD (canFd = 1): 08, 12, 16, 20, 24, 32, 48, or 64 bytes.

Any other byte count is rejected and the command reports Invalid.

Short form (toggle only)

If only the first arguments parse — index, enable, and channel — the previously configured frame in that slot is simply enabled or disabled without being re-loaded:

p <index> <enable> <period_ignored> <channel>

In practice, to just turn a configured slot off, the simplest form is:

p 0 0 0 0 # disable slot 0 on channel 0
Returns
  • success1 if the slot was updated, 0 otherwise.
Examples
#### Slot 0 on channel 0: send classic standard-ID 0x123 with 4 data bytes every 10 ms
p 0 1 10000 0 0x123 0 0 DE AD BE EF

#### Slot 1 on channel 0: send CAN-FD standard-ID 0x200, 16-byte payload, as fast as possible
p 1 1 0 0 0x200 1 0 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF

#### Slot 2 on channel 0: extended-ID 0x1ABCDEF, no data, every 1 s
p 2 1 1000000 0 0x01ABCDEF 0 1

#### Disable slot 0 on channel 0
p 0 0 0 0
Notes
  • Frames are queued to the transmit FIFO; if the FIFO is full or the bus is unavailable the frame is delayed until room becomes available.
  • period = 0 ("as fast as possible") fills any free TX FIFO slots every service tick and can saturate the bus — use with care.
  • Make sure the controller's bit timing (and FD data-phase timing) is configured before transmitting — see the Neptune/Orca setup commands.
  • Periodic slots are independent per channel; slot 0 on channel 0 is unrelated to slot 0 on channel 1.
  • To send a single, one-shot frame instead of a periodic stream, use Transmit CAN(FD).

Wire command: i\c\p

ArgWire type
indexdecS32
enabledecS32
perioddecS32
channeldecS32
arb_idhexU32
can_fddecS32
xtd_iddecS32
data_inbyteArray

Returns: none (Ok/Err only)

dev.io.canfd.write_canfd_periodic(index: int, enable: int, period: int, channel: int, arb_id: int, can_fd: int, xtd_id: int, data_in: bytes | bytearray) -> Result
ow_status ow_io_canfd_write_canfd_periodic(ow_device* dev, int32_t index, int32_t enable, int32_t period, int32_t channel, uint32_t arb_id, int32_t can_fd, int32_t xtd_id, const uint8_t* data_in, size_t data_in_len);
dev.io().canfd().write_canfd_periodic(index: i32, enable: i32, period: i32, channel: i32, arb_id: u32, can_fd: i32, xtd_id: i32, data_in: &[u8]) -> Result<(), OwError>

The C and Rust signatures above are also the WASM guest signatures - the device API surface is identical; only the transport differs (ow_open_wasm(&dev) in C, OneWili::open() in Rust).

dev.io.canfd.write_canfd_periodic(index, enable, period, channel, arb_id, can_fd, xtd_id, data_in) # check dev.ok

setup_filter

Setup Filter. Sets up a hardware receive filter (the byte-filter args are optional).

Requires power zone 15 (CAN). See Errors.

Setup Filter

Configures one of the CAN controller's hardware receive filters. Frames that do not match an enabled filter are dropped before reaching the stream / FIFO. If there are no filters configure Stream CAN(FD) shows all messages.

Arguments

Arguments are space-separated. The four byte-filter arguments at the end are optional.

  • channel — CAN controller index
    • 0 — CAN channel 0 (obCANFD1)
    • 1 — CAN channel 1 (obCANFD2)
    • Note: FreeWili2 only has one CAN channel; channel 1 is reserved for future Orcas.
  • index — hardware filter slot, 0RPCANFD_FILTERS_COUNT-1 (up to 32).
  • enable1 to enable the filter, 0 to disable it.
  • xtdId0 = standard 11-bit ID, 1 = extended 29-bit ID.
  • mask — ID mask (hex). A 1 bit means "this bit must match"; a 0 bit is don't-care.
  • accept — ID value to match after the mask is applied (hex).
  • maskb0, acceptB0 (optional) — mask/accept for data byte 0 (hex, 8-bit). Standard IDs only.
  • maskb1, acceptB1 (optional) — mask/accept for data byte 1 (hex, 8-bit). Standard IDs only.

A frame is accepted when:

(rxId & mask) == accept
(rxByte0 & maskb0) == acceptB0 # if byte filters provided
(rxByte1 & maskb1) == acceptB1 # if byte filters provided
Returns
  • success1 if the filter was updated, 0 otherwise.
Examples
#### Enable filter 0 on channel 0, standard ID, accept only ID 0x123
f 0 0 1 0 0x7FF 0x123

#### Accept any standard ID 0x100–0x10F (mask off low 4 bits)
f 0 1 1 0 0x7F0 0x100

#### Same as above, but only frames whose first data byte is 0xA5
f 0 1 1 0 0x7F0 0x100 0xFF 0xA5 0x00 0x00

#### Disable filter 2 on channel 0 (only the first three args are needed)
f 0 2 0
Notes
  • Omitting mask/accept is only valid when enable is 0; otherwise parsing fails and the command reports Invalid.
  • If the byte-filter arguments are omitted, all four byte mask/accept values are cleared to 0 (i.e., no byte filtering).
  • Byte filtering applies to standard IDs only; do not rely on maskb0/maskb1 when xtdId = 1.
  • Filters are re-applied to the controller immediately (setupFilters(false)) after a successful update.
  • if no filters are configured all frames will be received.

Wire command: i\c\f

ArgWire type
channeldecS32
indexdecS32
enabledecS32
xtd_iddecS32
maskhexU32
accepthexU32
maskb0hexU32
accept_b0hexU32
maskb1hexU32
accept_b1hexU32

Returns: none (Ok/Err only)

dev.io.canfd.setup_filter(channel: int, index: int, enable: int, xtd_id: int, mask: int, accept: int, maskb0: int, accept_b0: int, maskb1: int, accept_b1: int) -> Result
ow_status ow_io_canfd_setup_filter(ow_device* dev, int32_t channel, int32_t index, int32_t enable, int32_t xtd_id, uint32_t mask, uint32_t accept, uint32_t maskb0, uint32_t accept_b0, uint32_t maskb1, uint32_t accept_b1);
dev.io().canfd().setup_filter(channel: i32, index: i32, enable: i32, xtd_id: i32, mask: u32, accept: u32, maskb0: u32, accept_b0: u32, maskb1: u32, accept_b1: u32) -> Result<(), OwError>

The C and Rust signatures above are also the WASM guest signatures - the device API surface is identical; only the transport differs (ow_open_wasm(&dev) in C, OneWili::open() in Rust).

dev.io.canfd.setup_filter(channel, index, enable, xtd_id, mask, accept, maskb0, accept_b0, maskb1, accept_b1) # check dev.ok

read_can_registers

Read CAN Register(s). Reads 32-bit words from CAN controller SFR registers.

Requires power zone 15 (CAN). See Errors.

Read CAN Register(s)

Reads one or more consecutive 32-bit Special Function Registers (SFRs) from the selected CAN controller and returns them to the host as name/value pairs.

Arguments
  • channel — CAN controller index
    • 0 — CAN channel 0 (obCANFD1)
    • 1 — CAN channel 1 (obCANFD2)
    • Note: FreeWili2 only has one CAN channel; channel 1 is reserved for future Orcas.
  • startAddress — SFR start address (hex). Aligned to the controller's 32-bit register map (e.g. MCP25xxFD-style SFRs on the on-board controller).
  • wordCount — number of consecutive 32-bit words to read, starting at startAddress.
Returns
  • registers — a list of name=value pairs, one per 32-bit word, with each value formatted as a 32-bit hex number.
Example
#### Read 4 words starting at SFR address 0x000 on channel 0
r 0 0x000 4
Notes
  • The command operates directly on the CAN controller's SFR space — be careful when reading registers that have read-side-effects (e.g. interrupt/error status clears).
  • Use Set CAN Register (s) to write a register, and the Neptune/Orca setup commands for normal bit-timing and configuration changes.
  • Returns Invalid if channel is out of range or any argument fails to parse.
  • FreeWili GUI decodes these values for helpful debugging

Wire command: i\c\r

ArgWire type
channeldecS32
start_addresshexU32
word_countdecS32

Returns: registers (namevaluepairH32)

dev.io.canfd.read_can_registers(channel: int, start_address: int, word_count: int) -> Result
ow_status ow_io_canfd_read_can_registers(ow_device* dev, int32_t channel, uint32_t start_address, int32_t word_count, char* registers, size_t registers_cap);
dev.io().canfd().read_can_registers(channel: i32, start_address: u32, word_count: i32) -> Result<String, OwError>

The C and Rust signatures above are also the WASM guest signatures - the device API surface is identical; only the transport differs (ow_open_wasm(&dev) in C, OneWili::open() in Rust).

dev.io.canfd.read_can_registers(channel, start_address, word_count) # returns value; check dev.ok

set_can_register

Set CAN Register. Sets a CAN controller register.

Requires power zone 15 (CAN). See Errors.

Set CAN Register

Writes a single 32-bit (or 8-bit) Special Function Register (SFR) on the selected CAN controller. This is a direct register write — bypassing the normal setup commands — and should be used only when you know exactly what the controller expects.

Arguments
  • channel — CAN controller index
    • 0 — CAN channel 0 (obCANFD1)
    • 1 — CAN channel 1 (obCANFD2)
    • Note: FreeWili2 only has one CAN channel; channel 1 is reserved for future Orcas.
  • startAddress — SFR address (hex). Aligned to the controller's 32-bit register map (e.g. MCP25xxFD-style SFRs on the on-board controller).
  • byteCount — write width
    • 1 — write the low 8 bits of wordToWrite to startAddress
    • 4 — write the full 32-bit wordToWrite to startAddress
  • wordToWrite — value to write (hex). Only the low byteCount bytes are used.
Returns
  • success1 if the write was accepted, 0 otherwise.
Examples
#### Write the 32-bit value 0x00000004 to SFR 0x000 on channel 0
s 0 0x000 4 0x00000004

#### Write the single byte 0xA5 to SFR 0x010 on channel 0
s 0 0x010 1 0xA5
Notes
  • This is a raw register write — be careful with registers that have write-side-effects (mode changes, FIFO control, interrupt clears, etc.).
  • For normal bit-timing and configuration changes, prefer the Neptune/Orca setup commands instead of writing SFRs directly.
  • Use Read CAN Register(s) (r) to verify the value after writing.
  • Returns Invalid if channel is out of range or any argument fails to parse.

Wire command: i\c\s

ArgWire type
channeldecS32
start_addresshexU32
byte_countdecS32
word_to_writehexU32

Returns: none (Ok/Err only)

dev.io.canfd.set_can_register(channel: int, start_address: int, byte_count: int, word_to_write: int) -> Result
ow_status ow_io_canfd_set_can_register(ow_device* dev, int32_t channel, uint32_t start_address, int32_t byte_count, uint32_t word_to_write);
dev.io().canfd().set_can_register(channel: i32, start_address: u32, byte_count: i32, word_to_write: u32) -> Result<(), OwError>

The C and Rust signatures above are also the WASM guest signatures - the device API surface is identical; only the transport differs (ow_open_wasm(&dev) in C, OneWili::open() in Rust).

dev.io.canfd.set_can_register(channel, start_address, byte_count, word_to_write) # check dev.ok

Events

Spontaneous frames this menu emits (not command responses). Text events arrive as [*<id> ...] frames (Python: Transport.events; C: ow_poll_text_event; Rust: poll_event -> Event::Text); binary events use the binary API below. The on-device rthon binding does not receive event streams in v1.

can0 (text)

CAN RX frame on channel 0 (hex arb id, 'x' suffix = extended, then hex data)

Payload fieldWire type
arb_idstring
data_byteshexbytes

can1 (text)

CAN RX frame on channel 1 (hex arb id, 'x' suffix = extended, then hex data)

Payload fieldWire type
arb_idstring
data_byteshexbytes

canTx0 (text)

CAN TX echo on channel 0 (hex arb id, 'x' suffix = extended, then hex data)

Payload fieldWire type
arb_idstring
data_byteshexbytes

canTx1 (text)

CAN TX echo on channel 1 (hex arb id, 'x' suffix = extended, then hex data)

Payload fieldWire type
arb_idstring
data_byteshexbytes

canRxReport (binary)

CAN RX frame report (binary API, MCP2518 memory-map layout)

Header type: 1 - payload struct apiFrame_canRxReport (84 bytes):

FieldC typeOffset
ui64TimeStampNsuint64_t0
uiGpioBitfielduint32_t8
uiR0_CANIDuint32_t12
uiR1_Filter_HeaderBitsuint32_t16
uiDataWordsuint32_t[16]20

Receive it:

evt = dev.binary_events.get() # CanRxReportEvent
ow_event ev;
if (ow_binary_poll(&bdev, &ev) == 1 && ev.kind == OW_EV_CAN_RX_REPORT)
{ /* ev.u.can_rx_report.<field> */ }
if let Some(onewili::Event::CanRxReport(e)) = dev.poll_event()? { /* e.<field> */ }