Runtime Configuration

Runtime configuration is achieved by exchanging data structures with the driver via the cyg_io_set_config() and cyg_io_get_config() functions.

Device configuration

typedef struct cyg_can_info_st {
    cyg_can_baud_rate_t baud;
} cyg_can_info_t;

Device configuration is achieved by by exchanging cyg_can_info_t data structures with the driver via the cyg_io_set_config() and cyg_io_get_config() functions using the config keys CYG_IO_GET_CONFIG_CAN_INFO and CYG_IO_SET_CONFIG_CAN_INFO. The field baud contains a baud rate selection. This must be one of the following values:

CYGNUM_CAN_KBAUD_10
CYGNUM_CAN_KBAUD_20
CYGNUM_CAN_KBAUD_50
CYGNUM_CAN_KBAUD_100
CYGNUM_CAN_KBAUD_125
CYGNUM_CAN_KBAUD_250
CYGNUM_CAN_KBAUD_500
CYGNUM_CAN_KBAUD_800
CYGNUM_CAN_KBAUD_1000

Timeout configuration

typedef struct cyg_can_timeout_info_st
{
    cyg_uint32 rx_timeout;
    cyg_uint32 tx_timeout;
} cyg_can_timeout_info_t;

Timeout configuration is achieved by by exchanging cyg_can_timeout_info_t data structures with the driver via the cyg_io_set_config() and cyg_io_get_config() functions using the config keys CYG_IO_SET_CONFIG_CAN_TIMEOUT and CYG_IO_SET_CONFIG_CAN_TIMEOUT.

cyg_uint32 rx_timeout

Timeout for cyg_io_read calls.

cyg_uint32 tx_timeout

Timeout for cyg_io_write calls.

Timeout runtime configuration is supported if the configuration options CYGOPT_IO_CAN_SUPPORT_NONBLOCKING and CYGOPT_IO_CAN_SUPPORT_TIMEOUTS are enabled.

Reading buffer configuration

    
typedef struct cyg_can_buf_info_st
{
    cyg_int32 rx_bufsize;
    cyg_int32 rx_count;
    cyg_int32 tx_bufsize;
    cyg_int32 tx_count;
} cyg_can_buf_info_t;

CYG_IO_GET_CONFIG_CAN_BUFFER_INFO - This function retrieves the current state of the software buffers in the CAN drivers. For the transmit buffer it returns the the total number of cyg_can_message objects in buffer and the current number of cyg_can_message objects occupied in the buffer. For the receive buffer it returns the total number of cyg_can_event objects in receive buffer and the current number of cyg_can_event objects occupied in the buffer. It does not take into account any buffering such as FIFOs or holding registers that the CAN hardware device itself may have.

cyg_uint32 rx_bufsize

Total number of cyg_can_event buffers in receive queue.

cyg_uint32 rx_count

Current number of cyg_can_event buffers occupied in receive queue.

cyg_uint32 tx_bufsize

Total number of cyg_can_message buffers in transmit queue.

cyg_uint32 rtx_count

Current number of cyg_can_message buffers occupied in transmit queue.

Reading hardware description information

    
typedef struct cyg_can_hdi_st
{
    cyg_uint8 support_flags;
    cyg_uint8 controller_type;
} cyg_can_hdi;

CYG_IO_GET_CONFIG_CAN_HDI - This function retrieves information about the used hardware. The Hardware Description Interface provides a method to gather information about the CAN hardware and the functionality of the driver. For this purpose the structure cyg_can_hdi is defined.

cyg_uint8 support_flags

Contains information about the capabilities of the used CAN hardware.

cyg_uint8 controller_type

A number that identifies the CAN controller type.

The following flags are available in the field support_flags:

    
|   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
+-------+-------+-------+-------+--------+-------+-------+-------+
|ListenO|Mask F |Range F|timest.|autobaud|FullCAN|   Frametype   |

Frametype

Bit 0 and Bit 1 of the structure describe the possibilities of the CAN controller. The following values are defined:

    
CYGNUM_CAN_HDI_FRAMETYPE_STD          // receives only standard frame
CYGNUM_CAN_HDI_FRAMETYPE_EXT_PASSIVE  // can receive but not send extended frames
CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE   // can send and receive extended frames
    

FullCAN

If the Bit 2 - CYGNUM_CAN_HDI_FULLCAN - is set to one, the CAN controller supports more than one message buffer.

autobaud

If Bit 3 - CYGNUM_CAN_HDI_AUTBAUD - is set to one then the CAN driver supports an autobaud feature.

Timestamp

If Bit 4 - CYGNUM_CAN_HDI_TIMESTAMP - is set to one then the CAN hardware supports timestamps for CAN messages.

Identifier Range filtering

If Bit 5 - CYGNUM_CAN_HDI_RANGE_FILTERING - is set to one then the CAN hardware supports message filtering based on identifier ranges.

Identifier Mask filtering

If Bit 6 - CYGNUM_CAN_HDI_MASK_FILTERING - is set to one then the CAN hardware supports message filtering based on identifier masks.

Listen Only mode

If Bit 7 - CYGNUM_CAN_HDI_LISTEN_ONLY - is set to one then the CAN hardware supports a 'listen-only' mode.

Reading hardware message buffer configuration

    
typedef struct cyg_can_msgbox_info_st
{
    cyg_uint16 count; // number of message buffers available for this device
    cyg_uint16 free;  // number of free message buffers
} cyg_can_msgbuf_info;

CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO - If the CAN hardware supports more than one message buffer for reception of CAN messages (flag CYGNUM_CAN_HDI_FULLCAN is set while reading hardware description interface with CYG_IO_GET_CONFIG_CAN_HDI) then this function reads the number of message buffers the CAN hardware supports and the number of free message buffers.

cyg_uint16 count

Counts the number of message buffers supported by the device.

cyg_uint16 free

Contains the number of free message buffers. The free message buffers are available for setting up remote buffers (CYG_IO_SET_CONFIG_CAN_REMOTE_BUF) and message filters (CYG_IO_SET_CONFIG_CAN_FILTER_MSG).

Reading state of CAN hardware

    
typedef enum
{
  CYGNUM_CAN_STATE_ACTIVE,      // CAN controller active, no errors
  CYGNUM_CAN_STATE_STOPPED,     // CAN controller in stopped mode
  CYGNUM_CAN_STATE_STANDBY,     // CAN controller in Sleep mode
  CYGNUM_CAN_STATE_BUS_WARN,    // CAN controller active, warning level is reached
  CYGNUM_CAN_STATE_ERR_PASSIVE, // CAN controller went into error passive mode
  CYGNUM_CAN_STATE_BUS_OFF,     // CAN controller went into bus off mode
  CYGNUM_CAN_STATE_PHY_FAULT,   // General failure of physical layer 
  CYGNUM_CAN_STATE_PHY_H,       // Fault on CAN-H detected (Low Speed CAN)
  CYGNUM_CAN_STATE_PHY_L,       // Fault on CAN-L detected (Low Speed CAN)
} cyg_can_state;

CYG_IO_GET_CONFIG_CAN_STATE - This function retrieves the present state of the CAN controller. Possible values are defined in the cyg_can_state enumeration.

Changing mode of CAN hardware

CYG_IO_SET_CONFIG_CAN_MODE - This function changes the operating mode of the CAN controller. The identifiers for the different operating modes are defined in the cyg_can_mode enumeration.

 
typedef enum
{
  CYGNUM_CAN_MODE_STOP,   // set controller into stop mode
  CYGNUM_CAN_MODE_START,  // set controller into operational mode
  CYGNUM_CAN_MODE_STANDBY,// set controller into standby / sleep mode
  CYGNUM_CAN_MODE_CONFIG, // safe mode to add/delete message buffers
  CYGNUM_CAN_MODE_LISTEN_ONLY_ENTER, // set controller into listen only mode.
  CYGNUM_CAN_MODE_LISTEN_ONLY_EXIT   // set controller out of listen only mode.
} cyg_can_mode;

CYGNUM_CAN_MODE_STOP

Set controller into stop mode

CYGNUM_CAN_MODE_START

Set controller into operational mode

CYGNUM_CAN_MODE_STANDBY

Set controller into standby / sleep mode.

CYGNUM_CAN_MODE_CONFIG

Set controller into a mode allowing modifying message buffers.

CYGNUM_CAN_MODE_LISTEN_ONLY_ENTER

Make controller enter listen-only mode (if supported by hardware). In such a mode the CAN controller won't acknowledge the messages it sees on the bus. This mode can help to perform autobaud at application level if the underlying hardware does not support it directly. Depending on your CAN transceiver, such a mode may also be implemented by the transceiver.

CYGNUM_CAN_MODE_LISTEN_ONLY_EXIT

Make controller exit of listen-only mode. The controller will acknowledge all messages it sees on the bus.

Before the hardware configuration of the device is changed, that means if baud rate is changed or the message buffer and filter configuration is changed, the CAN hardware should be set into stop or config mode and if configuration is finished, then device should be set back into operational mode. Before the device is set into standby mode, the output buffers should be flushed or drained because transmission of a CAN message may wake up the CAN hardware. If a received message wakes up the CAN hardware from standby mode then a CYGNUM_CAN_EVENT_LEAVING_STANDBY event will be inserted into receive message buffer or the CYGNUM_CAN_EVENT_LEAVING_STANDBY flag will be set for the message that caused wake up of CAN hardware.

You must also check with the CAN controller data sheet if an incoming message waking up the controller is fully received and processed by the controller, or if such a wake up message is lost.

Flush or drain buffers

CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN - This function waits for any buffered output to complete. This function only completes when there is no more data remaining to be sent to the device.

CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH - This function discards any buffered output for the device.

CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH - This function discards any buffered input for the device.

Configuring blocking/non-blocking calls

By default all calls to cyg_io_read() and cyg_io_write() are blocking calls. The config keys

CYG_IO_SET_CONFIG_READ_BLOCKING
CYG_IO_SET_CONFIG_WRITE_BLOCKING

enable switching between blocking and nonblocking calls separatly for read and write calls. If blocking calls are configured then the read/write functions return only if a message was stored into TX buffer or an event was received from RX buffer. If non-blocking calls are enabled and there is no space in TX buffer or RX buffer is empty then the function returns immediately with -EAGAIN.

If non-blocking calls are enabled and additionally timeouts are supported by driver, then the read/write functions wait until timeout value is expired and then return with -EINTR. If the read/write operation succeeds during the timed wait then the functions return succesfully with ENOERR.

To query if cyg_io_read() and cyg_io_write() are blocking or non-blocking you can use the config keys

CYG_IO_GET_CONFIG_READ_BLOCKING
CYG_IO_GET_CONFIG_WRITE_BLOCKING

Message buffer management

Full CAN controllers often support more than one message buffer. These message buffers are often configurable for transmission or reception of certain CAN messages or as a remote buffers. If a CAN hardware supports more than one message buffer then it is possible to configure the CAN hardware to receive only CAN messages with certain identifiers or to configure hardware support for remote buffers. If message filtering is done by hardware, the number of received CAN messages decreases and so also the time for processing received CAN messages and the memory required for buffering received messages decreases. This saves valuable memory and processing time.

The eCos CAN driver supports a generic way of adding message filters or remote buffers. By default the CAN driver is configured for reception of any kind of CAN standard and extended frames. Configuration of message buffers is done by calling cyg_io_set_config() with the config key

CYG_IO_SET_CONFIG_CAN_MSGBUF

and by exchanging cyg_can_msgbuf_cfg data structures.

typedef struct cyg_can_msgbox_cfg_st
{
    cyg_can_msgbuf_cfg_id cfg_id; // configuration id
    cyg_can_msgbuf_handle handle; // handle to message buffer
    cyg_can_message msg;          // CAN message - for configuration of buffer
} cyg_can_msgbuf_cfg;

cyg_can_msgbuf_cfg_id cfg_id

The cfg_id field contains the configuration ID that tells the driver what to do with a message buffer.

cyg_can_msgbuf_handle handle

Contains a reference to a certain message buffer.

cyg_can_message msg

Required for configuration of message buffer parameters.

The following configuration identifiers are supported:

CYGNUM_CAN_MSGBUF_RESET_ALL        // clears alle message buffers
CYGNUM_CAN_MSGBUF_RX_FILTER_ALL    // cfg driver for reception of all can messages
CYGNUM_CAN_MSGBUF_RX_FILTER_ADD    // add single message filter
CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD   // add new remote response buffer
CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE // stores data into existing remote buffer 

CYGNUM_CAN_MSGBUF_RESET_ALL

Clears all message buffers - no message will be received and all remote buffers are deleted.

CYGNUM_CAN_MSGBUF_RX_FILTER_ALL

Configure driver for reception of all can messages

CYGNUM_CAN_MSGBUF_RX_FILTER_ADD

Add single message filter.

CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD

Add new remote response buffer.

CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE

Stores data into existing remote buffer (remote buffer handle required).

Example code for resetting all message buffers:

cyg_can_msgbuf_cfg msgbox_cfg;

msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;
len = sizeof(msgbox_cfg);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
                                CYG_IO_SET_CONFIG_CAN_MSGBUF,
                                &msgbox_cfg, &len))
{
    // handle configuration error
}

Remote frame response buffer configuration

The remote frame is a message frame which is transmitted to request a data frame. Some CAN hardware generates receive interrupts when a remote transmission request arrives. Other CAN hardware, i.e. the Motorola FlexCAN module, does not generate any receive interrupt. These CAN hardware chips like the FlexCAN module can be configured to transmit a data frame automatically in response to a remote frame. In order to support any kind of CAN hardware the eCos CAN driver provides a generic handling of remote transmission requests.

The transmission of the data frame in response to a remote frame is completely handled by the CAN driver. If the hardware driver, like the driver for the FlexCAN module, supports hardware message buffers, then the response frame is automatically transmitted if a remote transmission request with a matching ID arrives. If a CAN hardware does not provide hardware support for sending data frames in response to a remote frame, then this need to be implemented in software by the hardware device driver.

It is always possible to add remote response buffers. It does not matter if the driver is configured for reception of all CAN messages or if message filtering is used. As long as there are free message buffers available, it is possible to add remote response buffers.

In order to respond to a remote frame, a remote frame response buffer need to be initialized before a data frame can be sent in response to a remote frame. This is achieved by by exchanging cyg_can_remote_buf data structures with the driver via the cyg_io_set_config() function using the config key CYG_IO_SET_CONFIG_CAN_MSGBUF. Once the buffer is initialized, the CAN data can be changed at any time by the application.

typedef struct cyg_can_msgbuf_cfg_st
{
    cyg_can_msgbuf_cfg_id cfg_id; // configuration id 
    cyg_can_msgbuf_handle handle; // handle to message buffer
    cyg_can_message msg;          // CAN message - for configuration of buffer
} cyg_can_remote_buf;

cyg_can_msgbuf_cfg_id cfg_id

The cfg_id field contains the configuration ID that tells the driver what to do with a message buffer (CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD or CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE).

cyg_can_msgbuf_handle handle

If there is no buffer initialized for this data, the value of the handle field need to be set to CYGNUM_CAN_MSGBUF_INIT. After the call to cyg_io_set_config() the handle field contains a valid remote buffer handle ( >= 0) or the value CYGNUM_CAN_MSGBUF_NA ( < 0) if no free buffer is available.

cyg_can_message msg

The CAN frame that should be transmitted in response to a remote frame.

Example code for setting up a remote response buffer:

cyg_can_remote_buf rtr_buf;

// prepare the remote response buffer
rtr_buf.cfg_id  = CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD;
rtr_buf.handle  = CYGNUM_CAN_MSGBUF_INIT;
rtr_buf.msg.id  = 0x7FF;
rtr_buf.msg.ext = CYGNUM_CAN_ID_STD;
rtr_buf.msg.rtr = CYGNUM_CAN_FRAME_DATA;
rtr_buf.msg.dlc = 1;
rtr_buf.msg.data[0] = 0xAB;

len = sizeof(rtr_buf);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
                                CYG_IO_SET_CONFIG_CAN_MSGBUF,
                                &rtr_buf, &len))
{
    // handle configuration error
}

if (rtr_buf.handle == CYGNUM_CAN_MSGBUF_NA)
{
    // no free message buffer available - handle this problem here
}


// change CAN data for a buffer that is already initialized
rtr_buf.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE;
rtr_buf.msg.data[0] = 0x11;

len = sizeof(rtr_buf);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
                                CYG_IO_SET_CONFIG_CAN_MSGBUF,
                                &rtr_buf, &len))
{
    // handle configuration error
} 

Message filter configuration

If message filtering is done by hardware the number of received CAN messages decreases and so also the time for processing received CAN messages and the memory required for buffering received messages decreases. This saves valuable memory and processing time. The eCos CAN driver supports a generic way of adding message filters. By default the CAN driver is configured for reception of any kind of CAN standard and extended frames. As soon as a message filter is added, the CAN driver will only receive the CAN frames with the identifier of the CAN filter. By adding a number of message filters it is possible for the CAN hardware to receive an number of different CAN messages.

Adding message filters is only possible if driver is not configured for reception of all available CAN messages. If the driver is configured for reception of all CAN messages then message buffers need to be reset before adding single message filters.

In order to add a message filter, a message buffer need to be initialized. This is achieved by exchanging cyg_can_filter data structures with the driver via the cyg_io_set_config() function using the config key CYG_IO_SET_CONFIG_CAN_MSGBUF. Once the buffer is initialized, the CAN hardware can receive messages with the identifier of the filter.

 
typedef struct cyg_can_msgbox_cfg_st
{
    cyg_can_msgbuf_cfg_id cfg_id;
    cyg_can_msgbuf_handle handle;
    cyg_can_message       msg;
} cyg_can_filter;

cyg_can_msgbuf_cfg_id cfg_id

The cfg_id field contains the configuration ID that tells the driver what to do with a message buffer.

cyg_can_msgbuf_handle handle

After the call to cyg_io_set_config() the handle field contains a valid value ( >= 0) or the value CYGNUM_CAN_MSGBUF_NA ( < 0) if no free buffer is available.

cyg_can_message msg

The fields id and ext of the msg configure the type of message to receive by a certain message filter.

Before adding message filters the device should be stopped and after configuration it should be set into operational mode again.

Example code for setting up a message filter:

 
cyg_can_msgbuf_cfg msgbox_cfg;
cyg_can_filter rx_filter;

// reset all message buffers
msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;
len = sizeof(msgbox_cfg);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN, 
                                CYG_IO_SET_CONFIG_CAN_MSGBUF,
                                &msgbox_cfg, &len))
{
    // handle configuration error
}

// prepare the message filter
rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD;
rx_filter.msg.id  = 0x800;
rx_filter.msg.ext = CYGNUM_CAN_ID_EXT;

len = sizeof(rx_filter);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
                                CYG_IO_SET_CONFIG_CAN_MSGBUF,
                                &rx_filter, &len))
{
    // handle configuration error;
}
else if (CYGNUM_CAN_MSGBUF_NA == rx_filter.handle)
{
    // no free message buffer available - handle this problem here
}

Message filter deactivation

After startup of your device the CAN driver is configured for reception of all available CAN messages. If you change this configuration by adding single message filters then you can reset this default state with the configuration ID:

 
CYGNUM_CAN_MSGBUF_RX_FILTER_ALL

This message buffer configuration id will clear all message filters and remote buffers and prepares the CAN hardware for reception of any kind of CAN standard and extended frames. It is not necessary to reset the message buffer configuration before this configuration step is executed because this should be done by device driver.

Example code for deactivation of message filtering:

 
cyg_can_filter rx_filter;

// now setup a RX all configuration
rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ALL;
len = sizeof(rx_filter);
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
                                CYG_IO_SET_CONFIG_CAN_MSGBUF,
                                &rx_filter, &len))
{
    CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0");
}

Message filtering using identifier ranges

If the low level driver supports it, you can filter messages using identifier ranges. Such filtering is interesting if it is directly supported by the CAN controller hardware. Instead of waiting for a particular message identifier, the application can define one or more ranges of identifiers. If a received message has an identifier value (and type) matching a defined identifier range, then the message passes the filter and is made available to the application.

To add such a filter, use this configuration ID:

CYG_IO_SET_CONFIG_CAN_RANGE_FILTER

The buffer argument given to cyg_io_set_config() must point to an area holding the following structure:

typedef struct cyg_can_filter_range_cfg_st
{
    cyg_can_id_type        ext;            // type of identifier concerned
    cyg_uint32             lower_id_bound; // lower bound identifier (included)
    cyg_uint32             upper_id_bound; // upper bound identifier (included)
} cyg_can_filter_range_cfg;

cyg_can_id_type ext

Extended ID. If this field is CYGNUM_CAN_ID_EXT then the next two fields contains 29 bit extended ID. If ext contains CYGNUM_CAN_ID_STD then the next two fields represent 11 bits identifiers.

cyg_uint32 lower_id_bound

Combined with upper_id_bound an identifier range is defined. All messages having an identifier of the type defined by ext and included in the range lower_id_bound to upper_id_bound will pass the filter. The identifiers lower_id_bound and upper_id_bound are included in the defined range.

cyg_uint32 upper_id_bound

Upper identifier value of the defined range.

Message filtering using identifier masks

If the low level driver supports it, you can filter messages using identifier masks. Such filtering is interesting if it is directly supported by the CAN controller hardware. Instead of waiting for a particular message identifier, the application can define one or more pair of identifier and mask. If a received message has an identifier value (and type) that, for each bit set of the mask, matches the corresponding bit in the provided identifier, then the message passes the filter and is made available to the application.

To add such a filter, use this configuration ID:

CYG_IO_SET_CONFIG_CAN_MASK_FILTER

The buffer argument given to cyg_io_set_config() must point to an area holding the following structure:

typedef struct cyg_can_filter_mask_cfg_st
{
    cyg_can_id_type        ext;            // type of identifier concerned
    cyg_uint32             id;             // identifier to use for filtering
    cyg_uint32             mask;           // mask to apply for filtering
} cyg_can_filter_mask_cfg;

cyg_can_id_type ext

Extended ID. If this field is CYGNUM_CAN_ID_EXT then the id field contains a 29 bit extended ID. If it contains CYGNUM_CAN_ID_STD then the ID is 11 bits.

cyg_uint32 id

Message ID. This is the ID to be matched with an incoming message, after having considered the mask field.

cyg_uint32 mask

Mask value. A message will pass the filter if, for each bit set in mask, the received message ID has its corresponding bit equals to the corresponding bit in the id field.

For instance let's suppose that the id field is 0x05 (bits 0 and 2 are set) and the mask field is 0x07 (bits 0, 1 and 2 are set). If an incoming message has an ID of 0x01: bit 0 matches since bit 0 is set in the mask and both the incoming message and the id field have a similar value for bit 0. The message ID has its bit 1 set to 0, as the id field and the mask tells the controller to check this bit: it passes too. However the message ID has its bit 2 unset, while bit 2 of the mask tells the controller to check bit 2. Bit 2 of the identifier isn't set in the id field, hence this example message does not pass the filter.

Configuring a callback on events

By default application cannot get information about an event arriving in the RX buffer until it calls the cyg_io_read(). Usually this leads applications to use accessory threads to wait for new CAN events.

The CDL option CYGOPT_IO_CAN_SUPPORT_CALLBACK allows application to use a callback on event arrival. It is configured by passing a cyg_can_callback_cfg data structure to the driver via the cyg_io_set_config() function using the config key CYG_IO_SET_CONFIG_CAN_CALLBACK.

CYG_IO_SET_CONFIG_CAN_CALLBACK
typedef void (*cyg_can_event_cb_t)(cyg_uint16, CYG_ADDRWORD);

typedef struct cyg_can_callback_cfg_st
{
    cyg_can_event_cb_t callback_func;   // callback function
    cyg_can_event_flags_t flag_mask;  // flags mask
    CYG_ADDRWORD data;                  // data passed to callback
} cyg_can_callback_cfg;

cyg_can_event_cb_t callback_func

Pointer to the callback function. The function will be called from DSR context so you should be careful to only call API functions that are safe in DSR context. The first parameter is a combination of event flags for events that have occurred. Second parameter is a user defined data pointer or value.

CYG_ADDRWORD data

Additional user data that will be passed to callback function as a second parameter.

cyg_can_event_flags_t flag_mask

Should be set with a combination of CYGNUM_CAN_EVENT_* flags. If one of these events happens, the callback function will be called, with the actually event flags passed as a parameter. To disable the callback function from being called set flag_mask to 0. To set all possible flags use the CYGNUM_CAN_EVENT_ALL macro.

Instead of using a thread dedicated to reading CAN events, it is possible, if the CAN controller I/O handle was set in non-blocking mode for read operations, to have the callback function to read each event it is waiting for. However the callback function runs in DSR mode, so it must be carefully written to avoid any blocking call.

If you plan to have the callback function to perform read operations, be aware that cyg_io_read() retrieves events of all kinds while the callback function is triggered only on events it is expecting, as defined by the flag_mask field. The side effect is that the callback function, if it is not waiting for all events, may see its first parameter (the flag(s) describing why the callback function is called) different from an event it get from cyg_io_read().

For instance, let's suppose the callback function is expecting only CYGNUM_CAN_EVENT_RX events while the bus activity triggers other kind of events, like the CYGNUM_CAN_EVENT_WARNING_RX event. It is possible to have in the receive queue a first event of type CYGNUM_CAN_EVENT_WARNING_RX followed by a second event of type CYGNUM_CAN_EVENT_RX. In that case, the callback function is triggered and have its first parameter set to CYGNUM_CAN_EVENT_RX exactly when CYGNUM_CAN_EVENT_RX occurs, but if the callback function reads the event queue, it will first get the CYGNUM_CAN_EVENT_WARNING_RX event.

If the callback function is set to process all kind of events and always call cyg_io_read() to get each event, it is possible to have a receive queue size of one event.

If the CAN controller does not provide message timestamps of its own, or if the provided timestamps do not match your needs, the callback function mechanism can be helpful since it is called from the DSR processing the hardware related events. The callback function can manage timestamps in the way that suits you the best however there is a slight delay between an event related to the CAN bus activity occurs and the time the callback function runs. If you implement your own timestamps this way, pay also attention to what gives you the current time. For instance the granularity of cyg_current_time() may not be accurate enough, according to the clock resolution and your needs of accuracy.