Please enable JavaScript to view this site.

MaxxECU Documentation

can.filter(id, ...) - Registers CAN IDs that the ECU should route to this script's receive queue.

Without filters, no frames are delivered to your script.

Parameters: (variadic, function accepts a variable number of arguments).

Each argument can be either an integer CAN ID or a table (array) of integer CAN IDs. Any number of arguments in any order.

Returns: Nothing.

Lua code:

-- Single ID

can.filter(0x7E0)

 

-- Multiple IDs

can.filter(0x7E0, 0x7E8)

 

-- Table of IDs

can.filter({0x100, 0x101, 0x102})

 

-- Mixed

can.filter(0x123, {0x200, 0x201}, 0x7E0)

 

Call can.filter() once at the start of your script (before the main loop).

 

can.clear() - Removes all CAN ID filters for this script slot.

After calling this, no frames will be delivered until new filters are added.

Lua code:

can.clear()

 

 

can.count() - Returns the number of CAN frames waiting in this script's receive queue.

Returns: integer - pending frame count.

Lua code:

while can.count() > 0 do

   local frame = can.recv()

   -- process frame

end

 

can.recv() - Pops the next pending frame from this script's receive queue.

Returns: A CAN frame object, or "nil" if the queue is empty.

The returned frame object has the following fields:

".id" (integer): CAN ID (standard or extended).

".bus" (integer): CAN bus number (1 or 2).

".dlc" (integer): Data length code (0–8).

".data" (data object): Byte array, 0-indexed: data[0] through data[dlc-1].

Lua code:

local frame = can.recv()

if frame then

   print(string.format("ID=0x%X bus=%d dlc=%d", frame.id, frame.bus, frame.dlc))

   print("Byte 0 = " .. frame.data[0])

end

 

Data access notes:

"frame.data" is 0-indexed to match CAN byte positions directly.

"#frame.data" returns the DLC (number of bytes).

"tostring(frame)" prints a human-readable representation for debugging.

"tostring(frame.data)" prints the data bytes in hex.

 

can.frame(id, bus [, data_table [, dlc]]) - Creates a new CAN frame object without sending it.

Useful when you want to build a frame incrementally or reuse it.

Parameters:

"id" (integer): CAN ID (0x000 - 0x1FFFFFFF).

"bus" (integer): CAN bus number (1 or 2).

"data_table" (table): (Optional) array of byte values {0x00, ..., 0xFF}.

"dlc" (integer): (Optional) explicit DLC override. Defaults to the length of "data_table", or 0 if no data provided.

Returns: A CAN frame object.

Lua code:

-- Empty 8-byte frame

local tx = can.frame(0x600, 1, {0,0,0,0,0,0,0,0})

 

-- Modify bytes

tx.data[0] = 0xAB

tx.data[1] = 0xCD

 

-- Frame with preset data

local status = can.frame(0x321, 1, {0x01, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00})

 

Legacy form: can.frame(id, bus, dlc) with a plain integer as the third argument creates a zero-filled frame with that DLC.

 

can.send(frame) or can.send(id, bus, data_table [, dlc])  - Transmits a CAN frame onto the bus.

Accepts either a pre-built frame object or inline arguments. Use a frame object when you need to reuse and modify the same frame across iterations. Use inline arguments for one-off transmissions.

Returns: boolean - true if the frame was queued for transmission, false if the TX buffer is full.

 

Parameters (style 1 - frame object):

"frame" (CAN frame): A frame previously created by can.frame() or received by can.recv().

 

Parameters (style 2 - inline):

"id" (integer): CAN ID (0x000 - 0x1FFFFFFF).

"bus" (integer): CAN bus number (1 or 2).

"data_table" (table): Array of byte values {0x00, ..., 0xFF}.

"dlc" (integer): (Optional) explicit DLC override. Defaults to the length of "data_table".

 

Lua code:

-- Style 1: build once with can.frame(), modify and send repeatedly

local tx = can.frame(0x600, 1, {0,0,0,0,0,0,0,0})

while true do

tx.data[0] = ecu.get(RTDATA.RPM) >> 8

tx.data[1] = ecu.get(RTDATA.RPM) & 0xFF

can.send(tx)

time.delay(50)

end

 

-- Style 2: send inline without creating a frame object

can.send(0x600, 1, {0x01, 0x02, 0x03})

-- Check if transmission was accepted

if not can.send(0x600, 1, {0xFF}) then

print("TX buffer full!")

end

 

Note: Use can.frame() when you want to pre-build a frame once and reuse it in a loop, modifying individual bytes between sends.

 

 

CAN Frame Object Reference

CAN frame objects (returned by can.recv() or created by can.frame()) have readable and writable fields:

 

Field

Read

Write

Type

Range/notes

.id

YES

YES

integer

0 - 0x1FFFFFFF

.bus

YES

YES

integer

1-2

.dlc

YES

YES

integer

0-8

.data

YES

NO*

object

0-indexed byte access

*The `.data` field itself cannot be reassigned, but individual bytes can be read and written.

 

Lua code:

frame.data[0] = 0xFF    - write byte 0

local b = frame.data[3]  - read byte 3

 

#frame.data returns the DLC.

tostring(frame) gives a debug representation like: CAN(bus=1 id=0x321 dlc=8 data=[0x01 0x02 ...]).

Lua code:

-- Print frame length (DLC)

local frame = can.frame(0x321, 1, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08})

print(#frame.data) -- 8

 

-- Print full debug representation

print(tostring(frame))  -- CAN(bus=1 id=0x321 dlc=8 data=[0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08])

 

-- Useful for debugging incoming frames

while can.count() > 0 do

local rx = can.recv()

print(tostring(rx))

end

 

 

For more information about the MaxxECU user scripts, see User Scripts (LUA), or directly reference the LUA api reference and LUA examples. For more all available LUA settings and options, see Script Code, Script Input Control, Output Functions and Script RT values.