diff -urN ecos_web_cvs/ecos/packages/io/can/current/ChangeLog ecos/ecos/packages/io/can/current/ChangeLog --- ecos_web_cvs/ecos/packages/io/can/current/ChangeLog 2005-08-25 15:40:35.000000000 +0200 +++ ecos/ecos/packages/io/can/current/ChangeLog 2005-09-11 19:24:49.000000000 +0200 @@ -1,3 +1,24 @@ +2005-09-11 Uwe Kindler + + * include/can_io.h Added support for get_config to CAN_LOWLEVEL_FUNS + structure. + Added additional CAN events. + Added support for can state (cyg_can_state) and CAN mode (cyg_can_mode). + Changed data type of cyg_can_buf_info_t data structure from cyg_int32 + to cyg_uint32. + Added support for message box configuration (cyg_can_msgbuf_info). + Added support for message filtering (cyg_cn_filter). + Renamed cyg_can_rtr_buf to cyg_can_remote_buf. + Renamed CYGNUM_CAN_RTR_BUF_NA and CYGNUM_CAN_RTR_BUF_INIT to + CYGNUM_CAN_MSGBUF_NA and CYGNUM_CAN_MSGBUF_INIT because they are + also used for message filtering. + Added support for hardware description interface. + Added support for CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH, + CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH and CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN. + + * doc/can_driver_doc.html Additional configuration options + documented. + 2005-05-24 Uwe Kindler * Generic CAN driver package created diff -urN ecos_web_cvs/ecos/packages/io/can/current/doc/can_driver_doc.html ecos/ecos/packages/io/can/current/doc/can_driver_doc.html --- ecos_web_cvs/ecos/packages/io/can/current/doc/can_driver_doc.html 2005-08-25 15:40:36.000000000 +0200 +++ ecos/ecos/packages/io/can/current/doc/can_driver_doc.html 2005-09-11 19:25:22.000000000 +0200 @@ -1,296 +1,431 @@ - - - - - - - - IO/CAN Doc - - - -

CAN driver details

-

A raw CAN driver is is provided as a standard part of the eCos system. Use the include file <cyg/io/canio.h> for this driver. The CAN driver is capable of sending single CAN messages and receiving single CAN events to a CAN device. Controls are provided to configure the actual hardware, but there is no manipulation of the data by this driver. There may be many instances of this driver in a given system, one for each CAN channel. Each channel corresponds to a physical device and there will typically be a device module created for this purpose. The device modules themselves are configurable, allowing specification of the actual hardware details.

-

User API

-

The CAN driver uses the standard eCos I/O API functions. All functions except cyg_io_lookup() require an I/O "handle".

-

All functions return a value of the type Cyg_ErrNo. If an error condition is detected, this value will be negative and the absolute value indicates the actual error, as specified in cyg/error/codes.h. The only other legal return value will be ENOERR , -EINTR and -EAGAIN. All other function arguments are pointers (references). This allows the drivers to pass information efficiently, both into and out of the driver. The most striking example of this is the len value passed to the read and write functions. This parameter contains the desired length of data on input to the function and the actual transferred length on return.

-

Lookup a CAN device

-

Cyg_ErrNo cyg_io_lookup(
    const char      *name,
    cyg_io_handle_t *handle )

-

This function maps a device name onto an appropriate handle. If the named device is not in the system, then the error -ENOENT is returned. If the device is found, then the handle for the device is returned by way of the handle pointer *handle.

-

Send a CAN message

-

Cyg_ErrNo cyg_io_write(
-     cyg_io_handle_t  handle,
-     const void      *buf,
-     cyg_uint32      *len )
-

-

This function sends one single CAN message (not a buffer of CAN messages) to a device. The size of data to send is contained in *len and the actual size sent will be returned in the same place. A pointer to a cyg_can_message is contained in *buf . If a message was sucessfully sent, the function returns ENOERR. If nonblocking calls are supported and the TX buffer is full then the function returns immediatelly with -EAGAIN. If the driver supports timeouts and nonblocking calls are enabled then this function may also return -EINTR after the timout expired and the TX buffer is still full. This is important for applications where i.e. a watchdog need to be toggled by each task. Because it may happen that no CAN message will arrive for a long time the receiving thread remains blocked if the driver does not support timeouts and the watchdog will never be toggled.

-

typedef struct can_message
- {
- -     cyg_uint32         id;
- -     cyg_uint8          data[8];
- -     cyg_can_id_type    ext;
- -     cyg_can_frame_type rtr;
- -     cyg_uint8          dlc;
- } cyg_can_message;

-

The type cyg_can_message provides a device independent type of CAN message. Before calling the write function this message should be setup properly. The id field contains the 11 Bit or 29 bit CAN message identifier depending on the value of the ext field. The data field contains the 8 data bytes of one CAN message. The ext field configures the type of CAN message identifier (CYGNUM_CAN_ID_STD = standard 11 Bit id, CYGNUM_CAN_ID_EXT = extended 29 Bit id). The rtr field contains the frame type. (CYGNUM_CAN_FRAME_DATA = data frame, CYGNUM_CAN_FRAME_RTR = remote transmission request). The dlc field (data length code) contains the number of valid data bytes (0 - 8) in the data field.

-

Example code for sending one single CAN message:

-

cyg_can_message tx_msg;
cyg_uint32      len;
- Cyg_ErrNo       ret;
-
- - - tx_msg.id  = 0x100;
- - - tx_msg.ext = CYGNUM_CAN_ID_EXT;
- - tx_msg.rtr = CYGNUM_CAN_FRAME_DATA;
- - tx_msg.dlc = 1;
- - tx_msg.data[0] = 0xF1;
-
- - len = sizeof(tx_msg);
- ret = cyg_io_write(hDrvCAN, &tx_msg, &len);

-

Read a CAN event

-

Cyg_ErrNo cyg_io_read(
-     cyg_io_handle_t  handle,
- -     void            *buf,
- -     cyg_uint32      *len )
-

-

This function receives one single event from a device. The desired size of data to receive is contained in *len and the actual size obtained will be returned in the same place. A pointer to a cyg_can_event is contained in *buf. If a message was sucessfully sent, the function returns ENOERR. If nonblocking calls are supported the driver returns -EAGAIN if the RX buffer is empty. If the driver supports timeouts and nonblocking calls are enabled then this function may also return -EINTR if the timout value expired and the RX buffer is still empty.

-

typedef struct cyg_can_event_st
- {
-     cyg_uint32      timestamp;
- -     cyg_can_message msg;
- -     cyg_uint16      flags;
- } cyg_can_event;
-

-

A cyg_can_event provides a generic device independent type for handling CAN events that may occur. If the driver supports timestamps then the timestamp field my contain a timestamp value for an event that occured. The msg field contains a CAN message if an RX or TX event occured. The flags field contains 16 bits that indicate which kind of events occured. The following events are supported and after receiving an event the flag field should be checked against these values:

-

typedef enum
- {
- -   CYGNUM_CAN_EVENT_RX               = 0x0001, // message received
- -   CYGNUM_CAN_EVENT_TX               = 0x0002, // mesage transmitted
- -   CYGNUM_CAN_EVENT_WARNING_RX       = 0x0004, // tx error counter (TEC) reached warning level (>96)
- -   CYGNUM_CAN_EVENT_WARNING_TX       = 0x0008, // rx error counter (REC) reached warning level (>96)
- -   CYGNUM_CAN_EVENT_ERR_PASSIVE      = 0x0010, // CAN "error passive" occured
- -   CYGNUM_CAN_EVENT_BUS_OFF          = 0x0020, // CAN "bus off" error occured
- -   CYGNUM_CAN_EVENT_OVERRUN_RX       = 0x0040, // overrun in RX queue or hardware occured
- -   CYGNUM_CAN_EVENT_OVERRUN_TX       = 0x0080, // overrun in TX queue occured
- -   CYGNUM_CAN_EVENT_CAN_ERR          = 0x0100, // a CAN bit or frame error occured
- -   CYGNUM_CAN_EVENT_LEAVING_STANDBY  = 0x0200, // CAN hardware leaves standby / power don mode or is waked up
- -   CYGNUM_CAN_EVENT_ENTERING_STANDBY = 0x0400, // CAN hardware enters standby / power down mode
- -   CYGNUM_CAN_EVENT_ARBITRATION_LOST = 0x0800, // arbitration lost
- -   CYGNUM_CAN_EVENT_DEVICE_CHANGED   = 0x1000, // device changed event
- } cyg_can_event_flags;

-

Often the flags field will contain only one single set flag. But it is possible that a number of flags is set and so the flag field should always be checked by a receiver. I.e. if the CYGNUM_CAN_EVENT_RX is set then also the CYGNUM_CAN_EVENT_OVERRUN_RX may be set if the received message caused an RX overrun.

-

The internal receive buffers of the CAN device driver a circular buffers. That means that even if the buffers are completely filled new messages will be received. In this case the newest message will always overwrite the oldes message in receive buffer. If this happens the CYGNUM_CAN_EVENT_OVERRUN_RX flag will be set for this new message that caused overwriting of the old one.

-

Example code for receiving one single CAN event:

-

cyg_can_event rx_event;
- cyg_uint32    len;
- Cyg_ErrNo     ret;
-
- - len = sizeof(rx_event);
- - ret = cyg_io_read(hDrvCAN, &rx_event, &len);
-
- - if (ENOERR == ret)
- - {
- -     if (rx_event.flags & CYGNUM_CAN_EVENT_RX)
- -     {
- -         // handle RX event
- -     }
- -     
- -     if (rx_event.flags & ~CYGNUM_CAN_EVENT_RX)
- -     {
- -         // handle other events
- -     }
- - }
- - else if (-EINTR == ret)
- - {
- -     // handle timeout
- - }
-

-

Read configuration of a CAN device

-

Cyg_ErrNo cyg_io_get_config(
-     cyg_io_handle_t handle,
-     cyg_uint32      key,
-     void           *buf,
-     cyg_uint32     *len )
-

-

This function is used to obtain run-time configuration about a device. The type of information retrieved is specified by the key. The data will be returned in the given buffer. The value of *len should contain the amount of data requested, which must be at least as large as the size appropriate to the selected key. The actual size of data retrieved is placed in *len. The appropriate key values are all listed in the file <cyg/io/config_keys.h>.

-

The following config keys are currently supported:

-

CYG_IO_GET_CONFIG_READ_BLOCKING
- CYG_IO_GET_CONFIG_WRITE_BLOCKING
- CYG_IO_GET_CONFIG_CAN_INFO
- CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
- CYG_IO_GET_CONFIG_CAN_TIMEOUT
-

-

Change configuration of a CAN device

-

Cyg_ErrNo cyg_io_set_config(
-     cyg_io_handle_t  handle,
- -     cyg_uint32       key,
- -     const void      *buf,
- -     cyg_uint32      *len)
-

-

This function is used to manipulate or change the run-time configuration of a device. The type of information is specified by the key. The data will be obtained from the given buffer. The value of *len should contain the amount of data provided, which must match the size appropriate to the selected key. The appropriate key values are all listed in the file <cyg/io/config_keys.h>.

-

The following config keys are currently supported:

-

CYG_IO_SET_CONFIG_READ_BLOCKING
- CYG_IO_SET_CONFIG_WRITE_BLOCKING
- CYG_IO_SET_CONFIG_CAN_INFO
- - CYG_IO_SET_CONFIG_CAN_TIMEOUT
- CYG_IO_SET_CONFIG_CAN_RTR_BUF
-

-

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 follwing 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. The field rx_timeout contains the timeout value for cyg_io_read calls and tx_timeout contains the timeout value for cyg_io_write calls. This call is only available 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 serial 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 recieve 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.

-

Configuring blocking/nonblocking calls

- By default all calls to cyg_io_read() and cyg_io_write() are blocking calls. The config keys
-
- CYG_IO_GET_CONFIG_READ_BLOCKING
- CYG_IO_GET_CONFIG_WRITE_BLOCKING
-
-
and
-
- CYG_IO_GET_CONFIG_READ_BLOCKING
- CYG_IO_GET_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 a event was received from RX buffer. If nonblocking calls are enabled and there is no space in TX buffer or RX buffer is empty then the function returns immediatelly with -EAGAIN. If nonblocking calls are enabled and additionally timeouts are supported by driver, then the read/write functions wait until timeout value is expired and then return witn -EINTR. If the read/write operation succeeds during the timed wait then the functions return succesfully with ENOERR. - -

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 FlexCAN module, does not generate any receive interrupt. These CAN hardware chips, i.e. the FlexCAN module, can be configured to transmit a data frame automatically in response to a remote frame. In oder 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 of the remote frame is completely handled by the CAN driver. If the hardware driver, like the driver for the FlexCAN modul, supports harware message buffers, then the response frame is automatically transmitted if a remote transmission request with a matching ID arrives. If a CAN hardware does provide hardware support for sending the data frames in response to a remote frame, then this need to be implemented in software by the hardware device driver.

-

In order to respond to a remote frame, a remote frame reponse 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_rtr_buf_t data structures with the driver via the cyg_io_set_config() function using the config key CYG_IO_SET_CONFIG_CAN_RTR_BUF. Once the buffer is initialized, the CAN data can be changed at any time by the application.

-

typedef struct cyg_can_rtr_buf_st
-
{
-     cyg_int8 handle;
-     cyg_can_message msg;
-
} cyg_can_rtr_buf_t;
-

-

The CAN frame that should be transmitted in response to a remote frame is stored in the msg field of the cyg_can_rtr_buf_t data structure. If there is no buffer initialized for this data, the value of the handle field need to be set to CYGNUM_CAN_RTR_BUF_INIT. After the call to cyg_io_set_config() the handle field contains a valid value ( >= 0) or the value CYGNUM_CAN_RTR_BUF_NA ( < 0) if no free buffer is available. With the valid handle value the CAN data can be changed later by calling cyg_io_set_config().

-

Example code for setting up a remote response buffer:

-

cyg_can_rtr_buf_t rtr_buf;
-
- // prepare the remote response buffer
-
rtr_buf.handle  = CYGNUM_CAN_RTR_BUF_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_RTR_BUF ,
- -                                 &rtr_buf, &len))
-
{
- -     // handle configuration error
-
}
-

-
if (rtr_buf.handle == CYGNUM_CAN_RTR_BUF_NA)
-
{
- -     // no free message buffer available - handle this problem here
-
}
-
// change CAN data for a buffer that is already initialized
- rtr_buf.msg.data[0] = 0x11;
-
- len = sizeof(rtr_buf);
-
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
- -                                 CYG_IO_SET_CONFIG_CAN_RTR_BUF ,
- -                                 &rtr_buf, &len))
-
{
- -     // handle configuration error
-
}
-

-

FlexCAN device driver

-

The FlexCAN module is a communication controller implementing the controller area network (CAN) protocol, an asynchronous communications protocol used in automotive and industrial control systems. It is a high speed (1 Mbit/sec), short distance, priority based protocol which can communicate using a variety of mediums (for example, fiber optic cable or an unshielded twisted pair of wires). The FlexCAN supports both the standard and extended identifier (ID) message formats specified in the CAN protocol specification, revision 2.0, part B.

-

It supports up to 16 flexible flexible message buffers of 0–8 bytes data length, each configurable as Rx or Tx, all supporting standard and extended messages.

-

The FlexCAN device driver currently supports two message buffers for sending and receiving CAN messages - message buffer 14 for receiving CAN messages and message buffer 15 for transmitting CAN messages. The receive mask of message buffer 14 is configured in a way that it is possible to receive any kind of CAN message. Message buffers 0 - 13 can be used for setting up remote frame response buffers.

- - + + + + + + + IO/CAN Doc + + + +

CAN driver details

+

A raw CAN driver is is provided as a standard part of the eCos system. Use the include file <cyg/io/canio.h> for this driver. The CAN driver is capable of sending single CAN messages and receiving single CAN events to a CAN device. Controls are provided to configure the actual hardware, but there is no manipulation of the data by this driver. There may be many instances of this driver in a given system, one for each CAN channel. Each channel corresponds to a physical device and there will typically be a device module created for this purpose. The device modules themselves are configurable, allowing specification of the actual hardware details.

+

User API

+

The CAN driver uses the standard eCos I/O API functions. All functions except cyg_io_lookup() require an I/O "handle".

+

All functions return a value of the type Cyg_ErrNo. If an error condition is detected, this value will be negative and the absolute value indicates the actual error, as specified in cyg/error/codes.h. The only other legal return value will be ENOERR , -EINTR and -EAGAIN. All other function arguments are pointers (references). This allows the drivers to pass information efficiently, both into and out of the driver. The most striking example of this is the len value passed to the read and write functions. This parameter contains the desired length of data on input to the function and the actual transferred length on return.

+

Lookup a CAN device

+

Cyg_ErrNo cyg_io_lookup(
    const char      *name,
    cyg_io_handle_t *handle )

+

This function maps a device name onto an appropriate handle. If the named device is not in the system, then the error -ENOENT is returned. If the device is found, then the handle for the device is returned by way of the handle pointer *handle.

+

Send a CAN message

+

Cyg_ErrNo cyg_io_write(
+     cyg_io_handle_t  handle,
+     const void      *buf,
+     cyg_uint32      *len )
+

+

This function sends one single CAN message (not a buffer of CAN messages) to a device. The size of data to send is contained in *len and the actual size sent will be returned in the same place. A pointer to a cyg_can_message is contained in *buf . The driver maintains a buffer to hold the data. The size of the intermediate buffer is configurable within the interface module. The data is not modified at all while it is being buffered. On return, *len contains the amount of characters actually consumed - that means *len always contains sizeof(cyg_can_message).

+

It is possible to configure the write call to be blocking (default) or non-blocking. Non-blocking mode requires both the configuration option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING to be enabled, and the specific device to be set to non-blocking mode for writes (see cyg_io_set_config()). In blocking mode, the call will not return until there is space in the buffer and the content of the CAN message has been consumed. In non-blocking mode, if there is no space in buffer for the CAN message, -EAGAIN is returned and the caller must try again.

+

It is possible to configure the write call to be non-blocking with timeout. None-blocking mode with timeout requires the configuration option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING and CYGOPT_IO_CAN_SUPPORT_TIMEOUTS to be enabled, requires the eCos kernel package to be included and the specific device to be set to non-blocking mode for writes (see cyg_io_set_config()). In non-blocking mode with timeouts, if there is no space in buffer for the CAN message, the driver waits a certain amount of time (the timeout time) for space in the buffer. If there is still no space in buffer after expiration of the timeout time, -EINTR is returned and the caller must try again.

+

If a message was sucessfully sent, the function returns ENOERR.

+

typedef struct can_message
+ + {
+ + +     cyg_uint32         id;
+ + +     cyg_uint8          data[8];
+ + +     cyg_can_id_type    ext;
+ + +     cyg_can_frame_type rtr;
+ + +     cyg_uint8          dlc;
+ + } cyg_can_message;

+

The type cyg_can_message provides a device independent type of CAN message. Before calling the write function this message should be setup properly. The id field contains the 11 Bit or 29 bit CAN message identifier depending on the value of the ext field. The data field contains the 8 data bytes of one CAN message. The ext field configures the type of CAN message identifier (CYGNUM_CAN_ID_STD = standard 11 Bit id, CYGNUM_CAN_ID_EXT = extended 29 Bit id). The rtr field contains the frame type. (CYGNUM_CAN_FRAME_DATA = data frame, CYGNUM_CAN_FRAME_RTR = remote transmission request). The dlc field (data length code) contains the number of valid data bytes (0 - 8) in the data field.

+

Example code for sending one single CAN message:

+

cyg_can_message tx_msg;
cyg_uint32      len;
+ Cyg_ErrNo       ret;
+
+ + + tx_msg.id  = 0x100;
+ + + tx_msg.ext = CYGNUM_CAN_ID_EXT;
+ + tx_msg.rtr = CYGNUM_CAN_FRAME_DATA;
+ + tx_msg.dlc = 1;
+ + tx_msg.data[0] = 0xF1;
+
+ + len = sizeof(tx_msg);
+ ret = cyg_io_write(hDrvCAN, &tx_msg, &len);

+

Read a CAN event

+

Cyg_ErrNo cyg_io_read(
+     cyg_io_handle_t  handle,
+ +     void            *buf,
+ +     cyg_uint32      *len )
+

+

This function receives one single event from a device. The desired size of data to receive is contained in *len and the actual size obtained will be returned in the same place. A pointer to a cyg_can_event is contained in *buf. No manipulation of the data is performed before being transferred. Again, this buffering is completely configurable. On return, *len contains sizeof(cyg_can_event)
+

+

It is possible to configure the read call to be blocking (default) or non-blocking. Non-blocking mode requires both the configuration option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING to be enabled, and the specific device to be set to non-blocking mode for reads (see cyg_io_set_config()). In blocking mode, the call will not return until one single CAN event has been read. In non-blocking mode, if there is no CAN event in buffer, the call returns immediately with -EAGAIN and the caller must try again.

+

It is possible to configure the write call to be non-blocking with timeout. None-blocking mode with timeout requires the configuration option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING and CYGOPT_IO_CAN_SUPPORT_TIMEOUTS to be enabled, requires the eCos kernel package to be included and the specific device to be set to non-blocking mode for reads (see cyg_io_set_config()). In non-blocking mode with timeouts, if there is no CAN event in receive buffer, the driver waits a certain amound of time (the timeout time) for a CAN event to arrive. If there is still no CAN event in buffer after expiration of the timeout time, -EINTR is returned and the caller must try again.

+

If a event was sucessfully received, the function returns ENOERR.

+

typedef struct cyg_can_event_st
+ {
+     cyg_uint32      timestamp;
+ +     cyg_can_message msg;
+ +     cyg_uint16      flags;
+ } cyg_can_event;
+

+

A cyg_can_event provides a generic device independent type for handling CAN events that may occur. If the driver supports timestamps then the timestamp field my contain a timestamp value for an event that occured. The msg field contains a CAN message if an RX or TX event occured. The flags field contains 16 bits that indicate which kind of events occured. The following events are supported and after receiving an event the flag field should be checked against these values:

+

typedef enum
+ {
+ +   CYGNUM_CAN_EVENT_RX               = 0x0001, // message received
+ +   CYGNUM_CAN_EVENT_TX               = 0x0002, // mesage transmitted
+ +   CYGNUM_CAN_EVENT_WARNING_RX       = 0x0004, // tx error counter (TEC) reached warning level (>96)
+ +   CYGNUM_CAN_EVENT_WARNING_TX       = 0x0008, // rx error counter (REC) reached warning level (>96)
+ +   CYGNUM_CAN_EVENT_ERR_PASSIVE      = 0x0010, // CAN "error passive" occured
+ +   CYGNUM_CAN_EVENT_BUS_OFF          = 0x0020, // CAN "bus off" error occured
+ +   CYGNUM_CAN_EVENT_OVERRUN_RX       = 0x0040, // overrun in RX queue or hardware occured
+ +   CYGNUM_CAN_EVENT_OVERRUN_TX       = 0x0080, // overrun in TX queue occured
+ +   CYGNUM_CAN_EVENT_CAN_ERR          = 0x0100, // a CAN bit or frame error occured
+ +   CYGNUM_CAN_EVENT_LEAVING_STANDBY  = 0x0200, // CAN hardware leaves standby / power don mode or is waked up
+ +   CYGNUM_CAN_EVENT_ENTERING_STANDBY = 0x0400, // CAN hardware enters standby / power down mode
+ +   CYGNUM_CAN_EVENT_ARBITRATION_LOST = 0x0800, // arbitration lost
+   CYGNUM_CAN_EVENT_DEVICE_CHANGED   = 0x1000, // device changed event
+   
CYGNUM_CAN_EVENT_PHY_FAULT        = 0x2000, // General failure of physical layer detected (if supported by hardware)
+   
CYGNUM_CAN_EVENT_PHY_H            = 0x4000, // Fault on CAN-H detected (Low Speed CAN)
+   
CYGNUM_CAN_EVENT_PHY_L            = 0x8000, // Fault on CAN-L detected (Low Speed CAN)
+ } cyg_can_event_flags;

+

Often the flags field will contain only one single set flag. But it is possible that a number of flags is set and so the flag field should always be checked by a receiver. I.e. if the CYGNUM_CAN_EVENT_RX is set then also the CYGNUM_CAN_EVENT_OVERRUN_RX may be set if the received message caused an RX overrun.

+

The internal receive buffers of the CAN device driver a circular buffers. That means that even if the buffers are completely filled new messages will be received. In this case the newest message will always overwrite the oldest message in receive buffer. If this happens the CYGNUM_CAN_EVENT_OVERRUN_RX flag will be set for this new message that caused overwriting of the old one. The CYGNUM_CAN_EVENT_OVERRUN_RX flag will be set also if a overrun occures in hardware message buffers of the CAN device.

+

Example code for receiving one single CAN event:

+

cyg_can_event rx_event;
+ cyg_uint32    len;
+ Cyg_ErrNo     ret;
+
+ + len = sizeof(rx_event);
+ + ret = cyg_io_read(hDrvCAN, &rx_event, &len);
+
+ + if (ENOERR == ret)
+ + {
+ +     if (rx_event.flags & CYGNUM_CAN_EVENT_RX)
+ +     {
+ +         // handle RX event
+ +     }
+ +     
+ +     if (rx_event.flags & ~CYGNUM_CAN_EVENT_RX)
+ +     {
+ +         // handle other events
+ +     }
+ + }
+ + else if (-EINTR == ret)
+ + {
+ +     // handle timeout
+ + }
+

+

Read configuration of a CAN device

+

Cyg_ErrNo cyg_io_get_config(
+     cyg_io_handle_t handle,
+     cyg_uint32      key,
+     void           *buf,
+     cyg_uint32     *len )
+

+

This function is used to obtain run-time configuration about a device. The type of information retrieved is specified by the key. The data will be returned in the given buffer. The value of *len should contain the amount of data requested, which must be at least as large as the size appropriate to the selected key. The actual size of data retrieved is placed in *len. The appropriate key values are all listed in the file <cyg/io/config_keys.h>.

+

The following config keys are currently supported:

+

CYG_IO_GET_CONFIG_READ_BLOCKING
+ CYG_IO_GET_CONFIG_WRITE_BLOCKING
+ CYG_IO_GET_CONFIG_CAN_INFO
+ CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO
+ + CYG_IO_GET_CONFIG_CAN_TIMEOUT
+ CYG_IO_GET_CONFIG_CAN_HDI
+ CYG_IO_GET_CONFIG_CAN_STATE
+

+

Change configuration of a CAN device

+

Cyg_ErrNo cyg_io_set_config(
+     cyg_io_handle_t  handle,
+ +     cyg_uint32       key,
+ +     const void      *buf,
+ +     cyg_uint32      *len)
+

+

This function is used to manipulate or change the run-time configuration of a device. The type of information is specified by the key. The data will be obtained from the given buffer. The value of *len should contain the amount of data provided, which must match the size appropriate to the selected key. The appropriate key values are all listed in the file <cyg/io/config_keys.h>.

+

The following config keys are currently supported:

+

CYG_IO_SET_CONFIG_READ_BLOCKING
+ CYG_IO_SET_CONFIG_WRITE_BLOCKING
+ CYG_IO_SET_CONFIG_CAN_INFO
+ CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN
+ CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH
+ CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH
+ + + CYG_IO_SET_CONFIG_CAN_TIMEOUT
+ CYG_IO_SET_CONFIG_CAN_REMOTE_BUF
+
CYG_IO_SET_CONFIG_CAN_MODE
+ CYG_IO_SET_CONFIG_CAN_FILTER_ALL
+ CYG_IO_SET_CONFIG_CAN_FILTER_MSG
+
+

+

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 follwing 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. The field rx_timeout contains the timeout value for cyg_io_read calls and tx_timeout contains the timeout value for cyg_io_write calls. This call is only available 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 serial 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 recieve 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.

+

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. The field support_flags contains information about the capabilities of the used CAN hardware. The following flags are available:

+ + + + + + + + + + + + + + + + + + + + +
76543210
resresrestimest.SW-FiltFullCANFrametype
+

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 recieve but not send extended frames
+ CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE   // can send and receive extended frames
+

+

FullCAN:
+
If the Bit 2 is set to one, the CAN controller supports more than one message buffer.

+

CYGNUM_CAN_HDI_FULLCAN    // supports more than one message buffer
+

+

SW-Filter:
+
If Bit3 is set to one then the CAN driver supports some kind of software message filtering.

+

CYGNUM_CAN_HDI_FILT_SW    // software message filtering supported
+

+

Timestamp:
+
If Bit 4 is set to one then the CAN hardware supports timestamps for CAN messages

+

CYGNUM_CAN_HDI_TIMESTAMP    // CAN hardware supports timestamps
+

+

Reading message buffer configuration

+

typedef struct cyg_can_msgbox_info_st
+
{
+     c
yg_uint8 count; // number of message buffers available for this device
+     
cyg_uint8 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 message (flag CYGNUM_CAN_HDI_FULLCAN is set after 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. The field count contains the number of message buffers supported by device and the field 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 is active, no errors
+   
CYGNUM_CAN_STATE_STOPPED,     // CAN controller is in stopped mode
+   
CYGNUM_CAN_STATE_STANDBY,     // CAN controller is in Sleep mode
+   
CYGNUM_CAN_STATE_BUS_WARN,    // CAN controller is 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 detected (if supported by hardware)
+   
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.

+

Drain output 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.

+

Flush output buffers

+

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

+

Flush input buffers

+

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

+

Configuring blocking/nonblocking calls

+ + + + + By default all calls to cyg_io_read() and cyg_io_write() are blocking calls. The config keys
+
+ CYG_IO_GET_CONFIG_READ_BLOCKING
+ CYG_IO_GET_CONFIG_WRITE_BLOCKING
+
+
and
+
+ CYG_IO_GET_CONFIG_READ_BLOCKING
+ CYG_IO_GET_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 a event was received from RX buffer. If nonblocking calls are enabled and there is no space in TX buffer or RX buffer is empty then the function returns immediatelly with -EAGAIN. If nonblocking calls are enabled and additionally timeouts are supported by driver, then the read/write functions wait until timeout value is expired and then return witn -EINTR. If the read/write operation succeeds during the timed wait then the functions return succesfully with ENOERR. + +

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 FlexCAN module, does not generate any receive interrupt. These CAN hardware chips, i.e. the FlexCAN module, can be configured to transmit a data frame automatically in response to a remote frame. In oder 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 modul, supports harware message buffers, then the response frame is automatically transmitted if a remote transmission request with a matching ID arrives. If a CAN hardware does provide hardware support for sending the data frames in response to a remote frame, then this need to be implemented in software by the hardware device driver.

+

In order to respond to a remote frame, a remote frame reponse 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_REMOTE_BUF. 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_int8 handle;
+     cyg_can_message msg;
+
} cyg_can_remote_buf;
+

+

The CAN frame that should be transmitted in response to a remote frame is stored in the msg field of the cyg_can_remote_buf data structure. 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 value ( >= 0) or the value CYGNUM_CAN_MSGBUF_NA ( < 0) if no free buffer is available. With the valid handle value the CAN data can be changed later by calling cyg_io_set_config(). Before adding remote buffers the device should be stopped and after configuration it should be set into operational mode again

+

Example code for setting up a remote response buffer:

+

cyg_can_remote_buf rtr_buf;
+
+ // prepare the remote response buffer
+
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_REMOTE_BUF ,
+ +                                 &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.msg.data[0] = 0x11;
+
+ len = sizeof(rtr_buf);
+
if (ENOERR != cyg_io_set_config(hDrvFlexCAN,
                                CYG_IO_SET_CONFIG_CAN_REMOTE_BUF ,
+ +                                 &rtr_buf, &len))
+
{
+ +     // handle configuration error
+
}
+

+

Set mode of CAN hardware

+

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
+ } cyg_can_mode;

+

CYG_IO_SET_CONFIG_CAN_MODE - This function changes the operating mode of the CAN controller. Possible values for mode are defined in the cyg_can_mode enumeration. Befor the hardware configuration of the device is changed, that means if baudrate is changed or the message buffer and filter configuration is changed, the CAN hardware should be set into stop 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.

+

Message filter configuration

+

CYG_IO_SET_CONFIG_CAN_FILTER_MSG - Full CAN controlles often support more the one message buffer for reception of CAN messages. If a CAN hardware supports more then one message buffer it is possible to configure the CAN hardware to receive only CAN messages with certain identifiers. 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 messagews 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.

+

In order to add a message filter, a message buffer need to be initialized. This is achieved by 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_FILTER_MSG. Once the buffer is initialized, the CAN hardware can recive messages with the identifier of the filter.

+

typedef struct cyg_can_msgbox_cfg_st
+
{
+     
cyg_can_msgbuf_handle handle;
+     
cyg_can_message       msg;
+
} cyg_can_filter;

+

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. 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_filter rx_filter;
+
+ // prepare the message filter
+ 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_FILTER_MSG,
+                                 &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 reset

+

CYG_IO_SET_CONFIG_CAN_FILTER_ALL - A call to this function will clear all message filters (the remote buffers are not affected by this call) and prepares the CAN hardware for recption of any kind of CAN standard and extended frames.

+

FlexCAN device driver

+

The FlexCAN module is a communication controller implementing the controller area network (CAN) protocol, an asynchronous communications protocol used in automotive and industrial control systems. It is a high speed (1 Mbit/sec), short distance, priority based protocol which can communicate using a variety of mediums (for example, fiber optic cable or an unshielded twisted pair of wires). The FlexCAN supports both the standard and extended identifier (ID) message formats specified in the CAN protocol specification, revision 2.0, part B.

+

It supports up to 16 flexible flexible message buffers of 0-8 bytes data length, each configurable as Rx or Tx, all supporting standard and extended messages.

+

The message buffer 13 of the FlexCAN modul is reserved for transmission of CAN messages. Message buffer 14 is reserved for reception of any kind of standard frames and message buffer 15 is reserved for reception of any kind of extended frames. Message buffers 0 - 12 are available for configuration of remote buffers and message filters.

+ + \ No newline at end of file diff -urN ecos_web_cvs/ecos/packages/io/can/current/include/can.h ecos/ecos/packages/io/can/current/include/can.h --- ecos_web_cvs/ecos/packages/io/can/current/include/can.h 2005-08-25 15:40:36.000000000 +0200 +++ ecos/ecos/packages/io/can/current/include/can.h 2005-08-25 22:10:08.000000000 +0200 @@ -177,7 +177,11 @@ { bool (*putmsg)(can_channel *priv, cyg_can_message *pmsg, void *pdata); // send one can message - return true if consumed bool (*getevent)(can_channel *priv, cyg_can_event *pevent, void *pdata); // fetch one CAN event from device - Cyg_ErrNo (*set_config)(can_channel *priv, // Change hardware configuration (baud rate, etc) + Cyg_ErrNo (*get_config)(can_channel *priv, // query hardware configuration (baud rate, etc) + cyg_uint32 key, + const void *xbuf, + cyg_uint32 *len); + Cyg_ErrNo (*set_config)(can_channel *priv, // Change hardware configuration (baud rate, etc) cyg_uint32 key, const void *xbuf, cyg_uint32 *len); @@ -185,13 +189,14 @@ void (*stop_xmit)(can_channel *priv); // Disable the transmit channel and turn transmit interrupts off }; -#define CAN_LOWLEVEL_FUNS(_l,_putmsg,_getevent,_set_config,_start_xmit,_stop_xmit) \ -can_lowlevel_funs _l = { \ - _putmsg, \ - _getevent, \ - _set_config, \ - _start_xmit, \ - _stop_xmit \ +#define CAN_LOWLEVEL_FUNS(_l,_putmsg,_getevent,_get_config,_set_config,_start_xmit,_stop_xmit) \ +can_lowlevel_funs _l = { \ + _putmsg, \ + _getevent, \ + _get_config, \ + _set_config, \ + _start_xmit, \ + _stop_xmit \ }; extern cyg_devio_table_t cyg_io_can_devio; diff -urN ecos_web_cvs/ecos/packages/io/can/current/include/canio.h ecos/ecos/packages/io/can/current/include/canio.h --- ecos_web_cvs/ecos/packages/io/can/current/include/canio.h 2005-08-25 15:40:36.000000000 +0200 +++ ecos/ecos/packages/io/can/current/include/canio.h 2005-09-12 00:28:32.000000000 +0200 @@ -114,9 +114,38 @@ CYGNUM_CAN_EVENT_ENTERING_STANDBY = 0x0400, // CAN hardware enters standby / power down mode CYGNUM_CAN_EVENT_ARBITRATION_LOST = 0x0800, // arbitration lost CYGNUM_CAN_EVENT_DEVICE_CHANGED = 0x1000, // device changed event + CYGNUM_CAN_EVENT_PHY_FAULT = 0x2000, // General failure of physical layer detected (if supported by hardware) + CYGNUM_CAN_EVENT_PHY_H = 0x4000, // Fault on CAN-H detected (Low Speed CAN) + CYGNUM_CAN_EVENT_PHY_L = 0x8000, // Fault on CAN-L detected (Low Speed CAN) } cyg_can_event_flags; // +// State of CAN controller +// +typedef enum +{ + CYGNUM_CAN_STATE_ACTIVE, // CAN controller is active, no errors + CYGNUM_CAN_STATE_STOPPED, // CAN controller is in stopped mode + CYGNUM_CAN_STATE_STANDBY, // CAN controller is in Sleep mode + CYGNUM_CAN_STATE_BUS_WARN, // CAN controller is 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 detected (if supported by hardware) + 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; + +// +// Identifiers for operating mode of the CAN controller. +// +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 +} cyg_can_mode; + +// // Type of CAN identifier. // typedef enum @@ -167,19 +196,33 @@ cyg_can_baud_rate_t baud; } cyg_can_info_t; + +#define CYG_CAN_INFO_INIT(_baud) \ + { _baud} + // // buffer configuration - bufsize and count for tx are the number of messages // and for rx the number of events // typedef struct cyg_can_buf_info_st { - cyg_int32 rx_bufsize; - cyg_int32 rx_count; - cyg_int32 tx_bufsize; - cyg_int32 tx_count; + cyg_uint32 rx_bufsize; + cyg_uint32 rx_count; + cyg_uint32 tx_bufsize; + cyg_uint32 tx_count; } cyg_can_buf_info_t; // +// Message box configuration +// +typedef struct cyg_can_msgbox_info_st +{ + cyg_uint8 count; // number of message buffers available for this device + cyg_uint8 free; // number of free message buffers +} cyg_can_msgbuf_info; + + +// // Timeout configuration // typedef struct cyg_can_timeout_info_st @@ -188,24 +231,82 @@ cyg_uint32 tx_timeout; } cyg_can_timeout_info_t; + // -// this data type defines a remote transmission request buffer +// this data type defines a handle to a message buffer or message box +// of the CAN hardware device // -typedef struct cyg_can_rtr_buf_st +typedef cyg_int8 cyg_can_msgbuf_handle; + + +// +// structure for configuration of message buffers +// +typedef struct cyg_can_msgbox_cfg_st { - cyg_int8 handle; - cyg_can_message msg; -} cyg_can_rtr_buf_t; + cyg_can_msgbuf_handle handle; + cyg_can_message msg; +} cyg_can_msgbuf_cfg; + +// +// this data type defines a CAN message filter. It consits +// of a handle to a message box or message buffer and a CAN message. +// For the filtering only the id and the ext field of the CAN message are +// important. The values of the other fields doesn't matter +// +typedef cyg_can_msgbuf_cfg cyg_can_filter; + +// +// this data type defines a remote buffer. It consits +// of a handle to a message box or message buffer and the message data +// to send on reception of a remote request +// +typedef cyg_can_msgbuf_cfg cyg_can_remote_buf; // // Values for the handle field of the cyg_can_rtr_buf_t data structure // -#define CYGNUM_CAN_RTR_BUF_NA -0x01 // no free message buffer available -#define CYGNUM_CAN_RTR_BUF_INIT -0x02 // initialize the remote message buffer +#define CYGNUM_CAN_MSGBUF_NA -0x01 // no free message buffer available +#define CYGNUM_CAN_MSGBUF_INIT -0x02 // initialize the remote message buffer -#define CYG_CAN_INFO_INIT(_baud) \ - { _baud} +// +// The Hardware Description Interface provides a method to gather information +// about the CAN hardware and the functionality of the driver. For +// this purpose the following structure is defined: +// +// Support flags: +// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +// +-------+-------+-------+-------+-------+-------+-------+--------+ +// | res | res | res |timest.|SW-Filt|FullCAN| Frametype | +// +typedef struct cyg_can_hdi_st +{ + cyg_uint8 support_flags; + cyg_uint8 controller_type; +} cyg_can_hdi; + +// +// Bit 0 and Bit 1 of the structure member support_flags describe the +// possibities of the CAN controller. The following values are defined: +// +#define CYGNUM_CAN_HDI_FRAMETYPE_STD 0x00 // standard frame (11-bit identifier), 2.0A +#define CYGNUM_CAN_HDI_FRAMETYPE_EXT_PASSIVE 0x01 // extended frame (29-bit identifier), 2.0B passive +#define CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE 0x02 // extended frame (29-bit identifier), 2.0B active + +// +// If the flag "FullCAN" is set to "1", the CAN controller has more than one +// receive buffer and one transmit buffer. +// +#define CYGNUM_CAN_HDI_FULLCAN 0x04 + +// +// If the flag "Software ID-Filter" is set to "1", the driver has implemented +// the software ID filter for standard frames. If the member is set to "0", the +// software filter is not available. +// +#define CYGNUM_CAN_HDI_FILT_SW 0x08 +#define CYGNUM_CAN_HDI_TIMESTAMP 0x10 #ifdef __cplusplus } diff -urN ecos_web_cvs/ecos/packages/io/can/current/src/can.c ecos/ecos/packages/io/can/current/src/can.c --- ecos_web_cvs/ecos/packages/io/can/current/src/can.c 2005-08-25 15:40:36.000000000 +0200 +++ ecos/ecos/packages/io/can/current/src/can.c 2005-09-09 00:19:52.000000000 +0200 @@ -370,9 +370,13 @@ cyg_can_info_t *pcan_info = (cyg_can_info_t *)xbuf; can_cbuf_t *out_cbuf = &chan->out_cbuf; can_cbuf_t *in_cbuf = &chan->in_cbuf; + can_lowlevel_funs *funs = chan->funs; switch (key) { + // + // query about CAN configuration like baud rate + // case CYG_IO_GET_CONFIG_CAN_INFO : if (*len < sizeof(cyg_can_info_t)) { @@ -437,6 +441,9 @@ #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + // + // check if blocking calls are enabled + // case CYG_IO_GET_CONFIG_READ_BLOCKING: { if (*len < sizeof(cyg_uint32)) @@ -447,6 +454,9 @@ } break; + // + // check if nonblocking calls are enabled + // case CYG_IO_GET_CONFIG_WRITE_BLOCKING: { if (*len < sizeof(cyg_uint32)) @@ -458,8 +468,28 @@ break; #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + // + // return hardware description interface + // + case CYG_IO_GET_CONFIG_CAN_HDI : + { + cyg_can_hdi *hdi = (cyg_can_hdi *)xbuf; + if (*len != sizeof(cyg_can_hdi)) + { + return -EINVAL; + } + hdi = hdi; // avoid compiler warnings + *len = sizeof(cyg_can_hdi); + // + // pass down to low level to gather more information about + // CAN hardware + // + res = (funs->get_config)(chan, key, xbuf, len); + } + break; + default: - res = -EINVAL; + res = (funs->get_config)(chan, key, xbuf, len); } // switch (key) return res; @@ -484,6 +514,9 @@ switch (key) { #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + // + // Set calls to read function to blocking / nonblocking mode + // case CYG_IO_SET_CONFIG_READ_BLOCKING: { if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) @@ -493,7 +526,10 @@ in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false; } break; - + + // + // set calls to write functions to blocking / nonblocking mode + // case CYG_IO_SET_CONFIG_WRITE_BLOCKING: { if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) @@ -525,6 +561,95 @@ } break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS + + case CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH: + { + // + // Flush any buffered input + // + if (in_cbuf->len == 0) + { + break; // Nothing to do if not buffered + } + cyg_drv_mutex_lock(&in_cbuf->lock); // Stop any further input processing + cyg_drv_dsr_lock(); + if (in_cbuf->waiting) + { + in_cbuf->abort = true; + cyg_drv_cond_broadcast(&in_cbuf->wait); + in_cbuf->waiting = false; + } + in_cbuf->get = in_cbuf->put = in_cbuf->data_cnt = 0; // Flush buffered input + + // + // Pass to the hardware driver in case it wants to flush FIFOs etc. + // + (funs->set_config)(chan, + CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH, + NULL, NULL); + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&in_cbuf->lock); + } // CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH: + + // + // flush any buffered output + // + case CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH: + { + // Throw away any pending output + if (out_cbuf->len == 0) + { + break; // Nothing to do if not buffered + } + cyg_drv_mutex_lock(&out_cbuf->lock); // Stop any further output processing + cyg_drv_dsr_lock(); + if (out_cbuf->data_cnt > 0) + { + out_cbuf->get = out_cbuf->put = out_cbuf->data_cnt = 0; // Empties queue! + (funs->stop_xmit)(chan); // Done with transmit + } + + // + // Pass to the hardware driver in case it wants to flush FIFOs etc. + // + (funs->set_config)(chan, + CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH, + NULL, NULL); + if (out_cbuf->waiting) + { + out_cbuf->abort = true; + cyg_drv_cond_broadcast(&out_cbuf->wait); + out_cbuf->waiting = false; + }// if (out_cbuf->waiting) + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&out_cbuf->lock); + } + break; // CYG_IO_GET_CONFIG_CAN_OUTPUT_FLUSH: + + // + // wait until all messages in outbut buffer are sent + // + case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN: + { + // Wait for any pending output to complete + if (out_cbuf->len == 0) + { + break; // Nothing to do if not buffered + } + cyg_drv_mutex_lock(&out_cbuf->lock); // Stop any further output processing + cyg_drv_dsr_lock(); + while (out_cbuf->pending || (out_cbuf->data_cnt > 0)) + { + out_cbuf->waiting = true; + if(!cyg_drv_cond_wait(&out_cbuf->wait)) + { + res = -EINTR; + } + } + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&out_cbuf->lock); + } + break;// CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN: default: // @@ -561,8 +686,11 @@ // cbuf is a ring buffer - if the buffer is full, then we overwrite the // oldest message in buffer so the user will always get the actual and // last state of the external hardware that is connected to the - // CAN bus. + // CAN bus. We need to call cyg_drv_dsr_lock() here because this function + // may be called from different message box interrupts and so we have to + // protect data access here // + cyg_drv_dsr_lock(); if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata)) { if (cbuf->data_cnt < cbuf->len) @@ -588,6 +716,8 @@ cyg_drv_cond_broadcast(&cbuf->wait); } } + + cyg_drv_dsr_unlock(); }