diff options
| author | Michael Gielda <mgielda@antmicro.com> | 2014-04-03 14:53:04 +0200 |
|---|---|---|
| committer | Michael Gielda <mgielda@antmicro.com> | 2014-04-03 14:53:04 +0200 |
| commit | ae1e4e08a1005a0c487f03ba189d7536e7fdcba6 (patch) | |
| tree | f1c296f8a966a9a39876b0e98e16d9c5da1776dd /ecos/packages/io/can | |
| parent | f157da5337118d3c5cd464266796de4262ac9dbd (diff) | |
Added the OS files
Diffstat (limited to 'ecos/packages/io/can')
| -rw-r--r-- | ecos/packages/io/can/current/ChangeLog | 199 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/cdl/io_can.cdl | 368 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/doc/can.sgml | 2276 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/doc/can_driver_doc.html | 495 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/include/can.h | 240 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/include/canio.h | 489 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/src/can.c | 834 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/tests/can_filter.c | 306 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/tests/can_hdi.c | 234 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/tests/can_load.c | 307 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/tests/can_remote.c | 311 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/tests/can_test_aux.inl | 147 | ||||
| -rw-r--r-- | ecos/packages/io/can/current/tests/can_tx.c | 229 |
13 files changed, 6435 insertions, 0 deletions
diff --git a/ecos/packages/io/can/current/ChangeLog b/ecos/packages/io/can/current/ChangeLog new file mode 100644 index 0000000..71d40b1 --- /dev/null +++ b/ecos/packages/io/can/current/ChangeLog @@ -0,0 +1,199 @@ +2013-06-24 Uwe Kindler <uwe_kindler@web.de> + + * include/canio.h: Added structure cyg_can_err_count_info for reading + CAN hardware error counter values from CAN hardware. + * doc/can.sgml: Documented new CAN config key + CYG_IO_GET_CONFIG_ERR_COUNTERS. + +2013-05-06 Uwe Kindler <uwe_kindler@web.de> + + * doc/can.sgml: Documented return code -ENOSPC for cyg_io_set_config() + for config keys CYG_IO_SET_CONFIG_CAN_RANGE_FILTER and + CYG_IO_SET_CONFIG_CAN_MASK_FILTER + +2012-01-22 Bernard Fouché <bernard.fouche@kuantic.com> + + * cdl/io_can.cdl: support for add/remove compiler flags + * doc/can.sgml, doc/can_driver_doc.html: updated doc reflecting API + changes (range/mask filtering, listen-only mode, return values for + xmt_msg/rcv_event, new flags). + * include/can.h: given in a match the types of function pointers for + can_callbacks_t according to the changes made in can.c. + * include/canio.h: flags field in event enlarged to 32 bits to fit + new events 'CYGNUM_CAN_EVENT_ERR_ACTIVE' and + 'CYGNUM_CAN_EVENT_OVERRUN_RX_HW'. Made a 'flag' typedef. + cyg_can_event fields reordered so flags size change keeps events the + same size. Defined new filtering capabilities (range/mask). New + convenience macro CYGNUM_CAN_EVENT_ALL. New listen-only mode. + * src/can.c: can_rcv_event() and can_xmt_msg() now returns cyg_bool + (were 'void'). flags using cyg_can_event_flags_t type. + [ Bugzilla 1001453 ] + +2010-01-13 Sergei Gavrikov <sergei.gavrikov@gmail.com> + + * include/can.h: EOF footer: s/SERIAL/CAN/. + * src/can.c: can_set_config(): Fixed key's name to drain output: + s{CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN + }{CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN}. + +2007-08-23 Alexey Shusharin <mrfinch@mail.ru> + + * doc/can.sgml: Callback on event documentation. + * src/can.c: Change one wakeup to callback in a comment. + * include/canio.h: changed cyg_addrword_t to CYG_ADDRWORD so + can will compile without the kernel. + +2007-08-06 Alexey Shusharin <mrfinch@mail.ru> + Andrew Lunn <andrew.lunn@ascom.ch> + + * cdl/io_can.cdl: Added option CYGOPT_IO_CAN_SUPPORT_CALLBACK + + * include/canio.h: Added struct cyg_can_callback_cfg for setting + callback configurations. + + * include/can.h: Added declaration and initialization of callback + configuration in struct can_channel. + + * src/can.c: Added callback configuration changing and + application function call. + +2007-07-02 Uwe Kindler <uwe_kindler@web.de> + + * cdl/io_can.cdl: Added interface CYGINT_IO_CAN_CHANNELS for + counting available CAN channels + + * include/canio.h: Changed type cyg_can_msgbuf_info. The two + fields are 16 bit now because device drivers may support more + than 256 message buffers (i.e. the LPC2xxx CAN driver) + +2007-06-20 Uwe Kindler <uwe_kindler@web.de> + + * test/can_filter: Changed filter loop counter from cyg_uint8 to + cyg_uint16 because LPC2xxx CAN driver supports more than 256 + message buffers. + +2007-03-23 Uwe Kindler <uwe_kindler@web.de> + + * cdl/io_can.cdl: Added several interfaces for implementation by + device drivers. + Moved several configuration options from device drivers to the + generic CAN driver. With this design a device driver does not + need to provide all configuration options in its CDL file - it + simply needs to implement the provided interfaces. The drawback + of this decicsion is, that it is not possible to control these + options independently for several CAN devices. (But most platforms + will have only 1 channel) + Added configuration option CYGBLD_IO_CAN_EXTRA_TESTS. This option + enables the build of the interactive CAN tests. + + * test/can_filter: Added interactive message filtering test + + * test/can_hdi: Added interactive hardware description interface + test + + * test/can_load: Added interactive message handling (reception, + transmission) test. + + * test/can_remote: Added interactive remote response buffer test + + * test/can_tx: Added interactive basic TX test. All tests are not + part of the eCos test framework because they are interactive. That + means, they require interaction with another user controlled + CAN node. + + * include/can.h: Added identifier masks for standard and extended + identifiers. + Added the line #include CYGDAT_IO_CAN_DEVICE_INL. This enables a + device driver to provide an own device inline file. In this inline + file the driver may define own data types for CAN messages (for + internal storage of CAN messages (see AT91SAM7 CAN driver)) + + * include/canio.h: Added baudrate CYGNUM_CAN_KBAUD_AUTO - support of + automatic baudrate detection if a driver supports such a feature. + Added state CYGNUM_CAN_STATE_CONFIG and mode CYGNUM_CAN_MODE_CONFIG. + The application may use these identifiers to set the CAN device into + a state where it is safe to add/remove/configure message buffers. + Added union data type cyg_can_msg_data. With this data type a 4 byte + alignment of message data is guaranteed, an byte, word and dword + access to the data is possible and an assignment of two CAN datas are + possible now. + cyg_can_message now uses cyg_can_msg_data union for CAN data. + Replaced SW-Filt flag by autobaud flag in HDI. + Added CAN message access macros for read/write acces of CAN message + structures. These macros hide implementation of CAN message from + application. + + * src/can.c: Added support for device driver defined CAN message + data types + +2006-12-19 Sergei Gavrikov <sg@sgs.gomel.by> + + * doc/can.sgml: Correctly close para tag. + +2006-12-13 Uwe Kindler <uwe_kindler@web.de> + + * doc/can.sgml: CAN driver SGML documentation added. + +2006-08-25 Gary Thomas <gary@mlbassoc.com> + + * cdl/io_can.cdl: Set parent for more intuitive ConfigTool layout. + +2006-03-27 Uwe Kindler <uwe_kindler@web.de> + + * src/can.c can_rcv_event() Clear the flag field in new event before + calling into low level hardware driver. + +2006-02-15 Uwe Kindler <uwe_kindler@web.de> + + * include/can_io.h Added message buffer configuration identifier: + CYGNUM_CAN_MSGBUF_RESET_ALL, CYGNUM_CAN_MSGBUF_RX_FILTER_ALL ... + Added cfg_id field to cyg_can_msgbuf_cfg data structure. + +2005-09-11 Uwe Kindler <uwe_kindler@web.de> + + * 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 <uwe_kindler@web.de> + + * Generic CAN driver package created + +//=========================================================================== +// ####GPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2003, 2004 Free Software Foundation, Inc. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, +// Fifth Floor, Boston, MA 02110-1301, USA. +// ------------------------------------------- +// ####GPLCOPYRIGHTEND#### +//=========================================================================== diff --git a/ecos/packages/io/can/current/cdl/io_can.cdl b/ecos/packages/io/can/current/cdl/io_can.cdl new file mode 100644 index 0000000..2efacb2 --- /dev/null +++ b/ecos/packages/io/can/current/cdl/io_can.cdl @@ -0,0 +1,368 @@ +# ==================================================================== +# +# io_can.cdl +# +# eCos IO configuration data +# +# ==================================================================== +## ####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later +## version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License +## along with eCos; if not, write to the Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +## +## As a special exception, if other files instantiate templates or use +## macros or inline functions from this file, or you compile this file +## and link it with other works to produce a work based on this file, +## this file does not by itself cause the resulting work to be covered by +## the GNU General Public License. However the source code for this file +## must still be made available in accordance with section (3) of the GNU +## General Public License v2. +## +## This exception does not invalidate any other reasons why a work based +## on this file might be covered by the GNU General Public License. +## ------------------------------------------- +## ####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): Uwe Kindler +# Original data: gthomas +# Contributors: +# Date: 2005-05-17 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_IO_CAN { + display "CAN device drivers" + parent CYGPKG_IO + active_if CYGPKG_IO + requires CYGPKG_ERROR + include_dir cyg/io + description " + This option enables drivers for basic I/O services on + CAN devices." + doc ref/io.html + + compile -library=libextras.a can.c + + define_proc { + puts $::cdl_header "/***** proc output start *****/" + puts $::cdl_header "#include <pkgconf/system.h>" + puts $::cdl_header "#ifdef CYGDAT_IO_CAN_DEVICE_HEADER" + puts $::cdl_header "# include CYGDAT_IO_CAN_DEVICE_HEADER" + puts $::cdl_header "#endif " + puts $::cdl_header "/****** proc output end ******/" + } + + #----------------------------------------------------------------- + # Interfaces + # A hardware device driver should implement each interface it + # supports + # + cdl_interface CYGINT_IO_CAN_TIMESTAMP { + display "CAN driver supports timestamps" + } + + cdl_interface CYGINT_IO_CAN_STD_CAN_ID { + display "11 Bit standard CAN ID support" + } + + cdl_interface CYGINT_IO_CAN_EXT_CAN_ID { + display "29 Bit extended CAN ID support" + } + + cdl_interface CYGINT_IO_CAN_RUNTIME_MBOX_CFG { + display "CAN driver supports message box runtime configuration" + } + + cdl_interface CYGINT_IO_CAN_REMOTE_BUF { + display "CAN driver supports remote response buffers" + } + + cdl_interface CYGINT_IO_CAN_AUTOBAUD { + display "CAN driver supports automatic baudrate detection" + } + + cdl_interface CYGINT_IO_CAN_TX_EVENTS { + display "CAN driver supports TX events" + } + + #----------------------------------------------------------------- + # Each single channel of a CAN chip or on chip CAN module should + # implement this interface. It counts the number of available + # CAN channels + # + cdl_interface CYGINT_IO_CAN_CHANNELS { + display "Number of CAN channels" + } + + + #----------------------------------------------------------------- + # Generic CAN driver configuration + # + cdl_component CYGPKG_IO_CAN_DEVICES { + display "Hardware CAN device drivers" + flavor bool + default_value 1 + description " + This option enables the hardware device drivers + for the current platform." + } + + cdl_option CYGOPT_IO_CAN_SUPPORT_TIMESTAMP { + display "Support CAN event timestamps" + requires { CYGINT_IO_CAN_TIMESTAMP > 0 } + active_if { CYGINT_IO_CAN_TIMESTAMP > 0 } + default_value 0 + description " + If the CAN hardware driver supports some kind of timestamps + then this option enables propagation of timestamps to higher layers. + This may add some extra code to hardware drivers." + } + + cdl_option CYGOPT_IO_CAN_TX_EVENT_SUPPORT { + display "Support TX events" + requires { CYGINT_IO_CAN_TX_EVENTS > 0 } + active_if { CYGINT_IO_CAN_TX_EVENTS > 0 } + default_value 0 + description " + This option enables support for TX events. If a CAN message is + transmitted successfully a TX event will be inserted into the + receive event queue and propagated to higher layers. If this + option is enabled the RX event queue will be filled faster." + } + + cdl_option CYGOPT_IO_CAN_STD_CAN_ID { + display "11 Bit standard CAN ID support" + requires { CYGINT_IO_CAN_STD_CAN_ID > 0 } + active_if { CYGINT_IO_CAN_STD_CAN_ID > 0 } + default_value { CYGINT_IO_CAN_STD_CAN_ID > 0 ? 1 : 0 } + description " + This option enables support for 11 Bit standard CAN identifiers. + If the application deals only with 29 Bit extended CAN messages + then disabling this option may reduce codesize or increase + performance." + } + + cdl_option CYGOPT_IO_CAN_EXT_CAN_ID { + display "29 Bit extended CAN ID support" + requires { CYGINT_IO_CAN_EXT_CAN_ID > 0 } + active_if { CYGINT_IO_CAN_EXT_CAN_ID > 0 } + default_value { CYGINT_IO_CAN_EXT_CAN_ID > 0 ? 1 : 0 } + description " + This option enables support for 29 Bit extended CAN identifiers. + If the application deals only with 11 Bit standard CAN messages + then disabling this option may reduce codesize or increase + performance." + } + + cdl_option CYGOPT_IO_CAN_AUTOBAUD { + display "Support automatic baudrate detection." + requires { CYGINT_IO_CAN_AUTOBAUD > 0 } + active_if { CYGINT_IO_CAN_AUTOBAUD > 0 } + default_value 0 + description " + If the CAN hardware device driver supports any kind of automatic + baudrate detection then this option enables support for this feature. + If automatic baudrate detection is not required, then disabling this + option may reduce codesize." + } + + cdl_option CYGOPT_IO_CAN_RUNTIME_MBOX_CFG { + display "Message box runtime configuration support" + requires { CYGINT_IO_CAN_RUNTIME_MBOX_CFG > 0 } + active_if { CYGINT_IO_CAN_RUNTIME_MBOX_CFG > 0 } + default_value 1 + description " + Message box runtime configuration is required for for hardware message + filtering and for hardware remote response buffers. If no hardware + filtering is required and if the application does not need remote + response buffers this option can be disabled to decrease codesize." + } + + cdl_option CYGOPT_IO_CAN_REMOTE_BUF { + display "Remote response buffer support" + requires { CYGOPT_IO_CAN_RUNTIME_MBOX_CFG } + requires { CYGINT_IO_CAN_REMOTE_BUF > 0} + active_if { CYGINT_IO_CAN_REMOTE_BUF > 0 } + default_value 1 + description " + If the driver should handle remote requests automatically then remote + response buffers are required. Disabling this option may save some + bytes of ROM memory." + } + + cdl_option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING { + display "Support non-blocking read and write calls" + default_value 0 + description " + This option enables extra code in the generic CAN driver + which allows clients to switch read() and write() call + semantics from blocking to non-blocking." + } + + cdl_option CYGOPT_IO_CAN_SUPPORT_CALLBACK { + display "Support callback on events" + default_value 0 + description " + This option enables extra code in the generic CAN driver + which allows application to register a callback for + events. The callback function is called from DSR + context so you should be careful to only call API + functions that are safe in DSR context." + } + + cdl_component CYGOPT_IO_CAN_SUPPORT_TIMEOUTS { + display "Support read/write timeouts" + flavor bool + default_value 0 + active_if CYGPKG_KERNEL + requires CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT + requires CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + description " + Read and write operations are blocking calls. If no CAN message + arrives for a long time the calling thread remains blocked. If + nonblocking calls are enabled but the call should return after + a certain amount of time then this option should be enabled." + + cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ { + display "Default read timeout." + flavor data + default_value 100 + description " + The initial timeout value in clock ticks for cyg_io_read() calls." + } + + cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE { + display "Default write timeout." + flavor data + default_value 100 + description " + The initial timeout value in clock ticks for cyg_io_write() calls." + } + } + + cdl_component CYGPKG_IO_CAN_OPTIONS { + display "CAN device driver build options" + flavor none + description " + Package specific build options including control over + compiler flags used only in building this package, + and details of which tests are built." + + + cdl_option CYGPKG_IO_CAN_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the CAN device drivers. These flags are used + in addition to the set of global flags." + } + + cdl_option CYGPKG_IO_CAN_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the CAN device drivers. These flags are + removed from the set of global flags if present." + } + + } + + cdl_option CYGBLD_IO_CAN_EXTRA_TESTS { + display "Build extra CAN tests" + default_value 0 + no_define + description " + This option enables the building of some extra tests which + can be used when testing / debugging CAN drivers. These + are not built by default since they do not use the dedicated + testing infrastructure. All tests require a properly configured + CAN network with a second CAN node that can send and receive + CAN messages." + + make -priority 320 { + <PREFIX>/bin/can_load : <PACKAGE>/tests/can_load.c + @sh -c "mkdir -p tests $(dir $@)" + $(CC) -c $(INCLUDE_PATH) -Wp,-MD,deps.tmp -I$(dir $<) $(CFLAGS) -o tests/can_load.o $< + @echo $@ ": \\" > $(notdir $@).deps + @echo $(wildcard $(PREFIX)/lib/*) " \\" >> $(notdir $@).deps + @tail -n +2 deps.tmp >> $(notdir $@).deps + @echo >> $(notdir $@).deps + @rm deps.tmp + $(CC) $(LDFLAGS) -L$(PREFIX)/lib -Ttarget.ld -o $@ tests/can_load.o + } + + make -priority 320 { + <PREFIX>/bin/can_remote : <PACKAGE>/tests/can_remote.c + @sh -c "mkdir -p tests $(dir $@)" + $(CC) -c $(INCLUDE_PATH) -Wp,-MD,deps.tmp -I$(dir $<) $(CFLAGS) -o tests/can_remote.o $< + @echo $@ ": \\" > $(notdir $@).deps + @echo $(wildcard $(PREFIX)/lib/*) " \\" >> $(notdir $@).deps + @tail -n +2 deps.tmp >> $(notdir $@).deps + @echo >> $(notdir $@).deps + @rm deps.tmp + $(CC) $(LDFLAGS) -L$(PREFIX)/lib -Ttarget.ld -o $@ tests/can_remote.o + } + + make -priority 320 { + <PREFIX>/bin/can_tx : <PACKAGE>/tests/can_tx.c + @sh -c "mkdir -p tests $(dir $@)" + $(CC) -c $(INCLUDE_PATH) -Wp,-MD,deps.tmp -I$(dir $<) $(CFLAGS) -o tests/can_tx.o $< + @echo $@ ": \\" > $(notdir $@).deps + @echo $(wildcard $(PREFIX)/lib/*) " \\" >> $(notdir $@).deps + @tail -n +2 deps.tmp >> $(notdir $@).deps + @echo >> $(notdir $@).deps + @rm deps.tmp + $(CC) $(LDFLAGS) -L$(PREFIX)/lib -Ttarget.ld -o $@ tests/can_tx.o + } + + make -priority 320 { + <PREFIX>/bin/can_filter : <PACKAGE>/tests/can_filter.c + @sh -c "mkdir -p tests $(dir $@)" + $(CC) -c $(INCLUDE_PATH) -Wp,-MD,deps.tmp -I$(dir $<) $(CFLAGS) -o tests/can_filter.o $< + @echo $@ ": \\" > $(notdir $@).deps + @echo $(wildcard $(PREFIX)/lib/*) " \\" >> $(notdir $@).deps + @tail -n +2 deps.tmp >> $(notdir $@).deps + @echo >> $(notdir $@).deps + @rm deps.tmp + $(CC) $(LDFLAGS) -L$(PREFIX)/lib -Ttarget.ld -o $@ tests/can_filter.o + } + + make -priority 320 { + <PREFIX>/bin/can_hdi : <PACKAGE>/tests/can_hdi.c + @sh -c "mkdir -p tests $(dir $@)" + $(CC) -c $(INCLUDE_PATH) -Wp,-MD,deps.tmp -I$(dir $<) $(CFLAGS) -o tests/can_hdi.o $< + @echo $@ ": \\" > $(notdir $@).deps + @echo $(wildcard $(PREFIX)/lib/*) " \\" >> $(notdir $@).deps + @tail -n +2 deps.tmp >> $(notdir $@).deps + @echo >> $(notdir $@).deps + @rm deps.tmp + $(CC) $(LDFLAGS) -L$(PREFIX)/lib -Ttarget.ld -o $@ tests/can_hdi.o + } + } +} + +# EOF io_can.cdl diff --git a/ecos/packages/io/can/current/doc/can.sgml b/ecos/packages/io/can/current/doc/can.sgml new file mode 100644 index 0000000..6fd8066 --- /dev/null +++ b/ecos/packages/io/can/current/doc/can.sgml @@ -0,0 +1,2276 @@ +<!-- {{{ Banner --> + +<!-- =============================================================== --> +<!-- --> +<!-- can.sgml --> +<!-- --> +<!-- Generic CAN documentation. --> +<!-- --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTBEGIN#### --> +<!-- =============================================================== --> +<!-- Copyright (C) 2004 Free Software Foundation, Inc. --> +<!-- This material may be distributed only subject to the terms --> +<!-- and conditions set forth in the Open Publication License, v1.0 --> +<!-- or later (the latest version is presently available at --> +<!-- http://www.opencontent.org/openpub/) --> +<!-- Distribution of the work or derivative of the work in any --> +<!-- standard (paper) book form is prohibited unless prior --> +<!-- permission obtained from the copyright holder --> +<!-- =============================================================== --> +<!-- ####ECOSDOCCOPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####DESCRIPTIONBEGIN#### --> +<!-- --> +<!-- Author(s): Uwe Kindler --> +<!-- Date: 2006/12/04 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<!-- }}} --> + +<PART id="io-can"><title>CAN Support</title> + +<CHAPTER id="io-can-overview"> +<TITLE>Overview</TITLE> + +<SECTION id="io-can-overview-descr"> +<TITLE>Description</TITLE> + +<PARA> +The Controller Area Network, CAN, is a multicast shared, differential +serial bus standard especially suited for networking "intelligent" +devices as well as sensors and actuators within a system or sub-system. +The protocol was originally developed in the 1980s by Robert Bosch GmbH +aiming at automotive applications. Nowadays CAN has gained widespread use +and is used in industrial automation as well as in automotive, mobile +machines and in many embedded control applications. +</PARA> + +<PARA> +The CAN protocol is defined by the ISO 11898-1 standard. The physical layer +uses differential transmission on a twisted pair wire. CAN uses a +non-destructive bit-wise arbitration to control access to the bus. +</PARA> + +<PARA> +There is no explicit address in the messages because in CAN networks there +is no addressing of subscribers or stations, but instead, each message carries +a prioritized identifier. A transmitter sends a message to all CAN nodes +(broadcasting). The identifier may serve as an identification of the contents +of the message and also determines the priority that the message enjoys in +competition for bus access. A node decides on the basis of this identifier +received whether it should process the message or not. +</PARA> + +<PARA> +The CAN messages are small (at most eight data bytes) and are protected +by a checksum. Each CAN message consists of an 11 bit message ID, up to 8 +bytes of data and, a CRC checksum and a number of control bits. These +short messages ensure a robust transfer of data in electromagnetically +noisy environments. An extended version of the CAN frame supports 29 bit +message identifiers. +</PARA> + +<PARA> +Basically there are two different operational modes for CAN receivers - +FullCAN and BasicCAN. The difference between these two modes is the +Object Storage function. The BasicCAN architecture is quite similar to a +simple UART. A BasicCAN device has typically one transmit buffer and two +receive buffers. The CAN chip handles only the transmitting and receiving +of the data (and the error handling) and so most of the manipulation of the +data has to be done by the CPU. The CPU has to request the transmitting or +acknowledge the receiving of the data through the interrupt flags. This will +burden the CPU and take up much of the CPU time. +</PARA> + +<PARA> +The FullCAN architecture is more suitable for high-speed performance. It +has its own storage area on chip and works with a number of message buffers +or message boxes. The CAN controller has its own Acceptance Filtering Mask +on chip. It can thus determine which frames are to be received by examining +the identifiers. The CPU in this case will only receive the valid (wanted) +frames and hence improve the performance of the CPU. +</PARA> + +<PARA> +You can find more information at the +<ulink url="http://www.can-cia.org/">CAN in Automation</ulink> website. +</PARA> + +</SECTION> <!-- "io-can-description" --> + +<SECTION id="io-can-ecos-support"> +<TITLE>eCos Support for CAN</TITLE> + +<PARA> +The eCos CAN subsystem supports the BasicCAN and FullCAN mode. The architecture +and the interface of the eCos CAN driver is quite similar to the eCos serial +driver and supports the same interface. +</PARA> + +<PARA> +The eCos CAN support for any given platform is spread over a number of different +packages: +</PARA> + +<itemizedlist> + <listitem> + <para> + +This package, <varname>CYGPKG_IO_CAN</varname>, exports a generic +device independent CAN I/O API for accessing devices attached to a CAN +network. This API handles issues such as locking between threads. The +package does not contain any hardware-specific code. Instead it will +call into a CAN device driver to handle the hardware device +access. This package also defines the interface that such hardware +drivers should provide. + </para> + </listitem> + <listitem> + <para> +Each CAN device will have its own device driver, which is implemented +as a separate package, for example +<varname>CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN</varname>. For devices that may +be attached to a variety of different boards the device driver will be +generic and a second platform specific package will be used to customize +it to each platform. For devices that are associated with a specific +chipset, only a single package may be present. + </para> + </listitem> +</itemizedlist> + +<PARA> +Typically all appropriate packages will be loaded automatically when +you configure eCos for a given platform. If the application does not use +any of the CAN I/O facilities, directly or indirectly, then linker garbage +collection should eliminate all unnecessary code and data. All necessary +initialization should happen automatically. However the exact details may +depend on the platform, so the platform HAL documentation should be +checked for further details. +</PARA> + +<PARA> +There is an important exception to this: if the CAN devices are attached +to an expansion connector, such as PCI, then the platform HAL will not +know about these devices. Instead the necessary packages will need to be +added explicitly during configuration. +</PARA> +</SECTION> +</CHAPTER> + +<CHAPTER id="io-can-api"> +<TITLE>User API</TITLE> + +<PARA> +The CAN driver uses the standard eCos I/O API functions. All functions +except <function>cyg_io_lookup()</function> require an I/O "handle". +</PARA> + +<PARA> +All functions return a value of the type <type>Cyg_ErrNo</type>. +If an error condition is detected, this value will be negative and the +absolute value indicates the actual error, as specified in +<filename>cyg/error/codes.h</filename>. The only other legal return values +will be <varname>ENOERR</varname>, <varname>-EINTR</varname>, +<varname>-EINVAL</varname> and <varname>-EAGAIN</varname>. 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 <parameter>len</parameter> 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. +</PARA> + +<PROGRAMLISTING> +// Lookup a CAN device and return its handle +Cyg_ErrNo <FUNCTION><!-- <index></index> -->cyg_io_lookup</function>( + const char <parameter>*name</parameter>, + cyg_io_handle_t <parameter>*handle</parameter> ) +</PROGRAMLISTING> + +<PARA> +This function maps a CAN device name onto an appropriate handle. If the +named device is not in the system, then the error +<varname>-ENOENT</varname> is returned. If the device is found, then +the handle for the device is returned by way of the handle pointer +<parameter>*handle</parameter>. +</PARA> + +<PROGRAMLISTING> +// Send a CAN message +Cyg_ErrNo <FUNCTION><!-- <index></index> -->cyg_io_write</function>( + cyg_io_handle_t <parameter>handle</parameter>, + const void <parameter>*buf</parameter>, + cyg_uint32 <parameter>*len</parameter> ) +</PROGRAMLISTING> + +<PARA> +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 +<parameter>*len</parameter> and the actual size sent will be returned in +the same place. +</PARA> + +<PROGRAMLISTING> +// Read one CAN event from device +Cyg_ErrNo <!-- <index></index> --><function>cyg_io_read</function>( + cyg_io_handle_t <parameter>handle</parameter>, + void <parameter>*buf</parameter>, + cyg_uint32 <parameter>*len</parameter> ) +</PROGRAMLISTING> + +<PARA> +This function receives one single CAN event from a device. The desired size +of data to receive is contained in <parameter>*len</parameter> and the +actual size obtained will be returned in the same place. +</PARA> + +<PARA> +You may notice that the data sent (messages) is different from the +data received (events). An event includes flags that describe the +event, and eventually a received message and a timestamp. +</PARA> + +<PROGRAMLISTING> +// Read configuration of a CAN device +Cyg_ErrNo <FUNCTION><!-- <index></index> -->cyg_io_get_config</FUNCTION>( + cyg_io_handle_t <parameter>handle</parameter>, + cyg_uint32 <parameter>key</parameter>, + void *<parameter>buf</parameter>, + cyg_uint32 *<parameter>len</parameter> ) +</PROGRAMLISTING> + +<PARA> +This function is used to obtain run-time configuration about a +device. The type of information retrieved is specified by the +<parameter>key</parameter>. The data will be returned in the given +buffer. The value of <parameter>*len</parameter> 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 <parameter>*len</parameter>. The appropriate key values +are all listed in the file <filename><cyg/io/config_keys.h></filename>. +</PARA> + +<PROGRAMLISTING> +// Change configuration of a CAN device +Cyg_ErrNo <!-- <index></index> --><function>cyg_io_set_config</function>( + cyg_io_handle_t <parameter>handle</parameter>, + cyg_uint32 <parameter>key</parameter>, + const void <parameter>*buf</parameter>, + cyg_uint32 <parameter>*len</parameter> ) +</PROGRAMLISTING> + +<PARA> +This function is used to manipulate or change the run-time +configuration of a device. The type of information is specified by the +<parameter>key</parameter>. The data will be obtained from the given +buffer. The value of <parameter>*len</parameter> 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 +<filename><cyg/io/config_keys.h></filename>. +</PARA> +</CHAPTER> + +<CHAPTER id="io-can-driver-details"> +<TITLE>CAN driver details</TITLE> + +<PARA> +Allow applications and other packages to access CAN devices. +</PARA> + +<SECTION id="io-can-driver-description"> +<TITLE>Description</TITLE> + +<PARA> +A raw CAN driver is is provided as a standard part of the eCos system. +</PARA> + +<PARA> +Use the include file <filename><cyg/io/canio.h></filename> for this driver. +</PARA> + +<PARA> +The CAN driver is capable of sending single CAN messages to a device and +receiving single CAN events from a CAN device. Controls are provided to +configure the actual hardware, but there is no manipulation of the data by +this driver. +</PARA> + +<PARA> +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. +</PARA> +</SECTION> + +<SECTION id="io-can-api-details"> +<TITLE>API Details</TITLE> + +<SECTION> +<TITLE>cyg_io_write</TITLE> + +<PROGRAMLISTING> +cyg_io_write(handle, buf, len) +</PROGRAMLISTING> + +<PARA> +To transmit a message an application must fill a <type>cyg_can_message</type> +buffer and call <function>cyg_io_write()</function>. +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 <parameter>*len</parameter> +and the actual size sent will be returned in the same place. A pointer to a +<type>cyg_can_message</type> is contained in <parameter>*buf</parameter>. +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, <parameter>*len</parameter> +contains the amount of characters actually consumed - that means +<parameter>*len</parameter> always contains +<function>sizeof(cyg_can_message)</function>. +</PARA> + +<PARA> +It is possible to configure the write call to be blocking (default) or +non-blocking. Non-blocking mode requires both the configuration option +<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> to be enabled, and +the specific device to be set to non-blocking mode for writes +(see <function>cyg_io_set_config()</function>). 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, <varname>-EAGAIN</varname> is +returned and the caller must try again. +</PARA> + +<PARA> +It is possible to configure the write call to be non-blocking with timeout. +None-blocking mode with timeout requires the configuration option +<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> and +<varname>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</varname> 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 <function>cyg_io_set_config() +</function>). +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, <varname>-EINTR</varname> is returned and +the caller must try again. +</PARA> + +<PARA> +If a message was successfully sent, the function returns <varname>ENOERR</varname>. +</PARA> +</SECTION> + +<SECTION> +<TITLE>CAN Messages</TITLE> + +<PARA> +The CAN driver uses <structname>cyg_can_message</structname> structures to +pass messages between the application and the CAN driver. The type +cyg_can_message provides a device independent type of CAN message. +Before calling the write function this message should be setup properly. +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<PARA> +The structure contains the following fields: +</PARA> + +<variablelist> + <varlistentry> + <term><type>cyg_uint32</type> <varname>id</varname></term> + <listitem><para> +Message ID. This is the ID to be transmitted with the message, or the +ID received. If the <structfield>ext</structfield> field is set, then +this will contain a 29 bit ID, otherwise it will contain an 11 bit ID. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>data</varname></term> + <listitem><para> +Message data. Only the first <structfield>dlc</structfield> bytes of +data are valid. If the <structfield>rtr</structfield> field is set, +then the contents of this field are ignored. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_id_type</type> <varname>ext</varname></term> + <listitem><para> +Extended ID. If this field is <varname>CYGNUM_CAN_ID_EXT</varname> then the +<structname>id</structname> field contains a 29 bit extended ID. If it +contains <varname>CYGNUM_CAN_ID_STD</varname> then the ID is 11 bits. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_frame_type</type> <varname>rtr</varname></term> + <listitem><para> +Remote Transmission Request. If this field contains +<varname>CYGNUM_CAN_FRAME_RTR</varname> then the RTR bit on the message +will be set and the <structfield>data</structfield> field will be ignored. +If the field contains <varname>CYGNUM_CAN_FRAME_DATA</varname> then a +normal data frame will be send. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint8</type> <varname>dlc</varname></term> + <listitem><para> +The length of the data carried in the message. This can range from +zero to 8. In a message with the <structfield>rtr</structfield> field set, +this indicates the size of data being requested. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +Example code for sending one single CAN message: +</PARA> + +<PROGRAMLISTING> +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); +</PROGRAMLISTING> +</SECTION><!-- can-cyg_can_message --> + +<SECTION> +<TITLE>cyg_io_read</TITLE> + +<PROGRAMLISTING> +cyg_io_read(handle, buf, len) +</PROGRAMLISTING> + +<PARA> +To receive a message the application calls <function>cyg_io_read()</function>. +This function receives one single event from a device. The desired size +of data to receive is contained in <parameter>*len</parameter> and the +actual size obtained will be returned in the same place. A pointer to +a <type>cyg_can_event</type> is contained in <parameter>*buf</parameter>. +No manipulation of the data is performed before being transferred. +Again, this buffering is completely configurable. On return, +<parameter>*len</parameter> contains <function>sizeof(cyg_can_event)</function>. +</PARA> + +<PARA> +It is possible to configure the read call to be blocking (default) or +non-blocking. Non-blocking mode requires both the configuration option +<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> to be enabled, +and the specific device to be set to non-blocking mode for reads +(see <function>cyg_io_set_config()</function>). 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 <varname>-EAGAIN</varname> and the caller must +try again. +</PARA> + +<PARA> +It is possible to configure the read call to be non-blocking with timeout. +None-blocking mode with timeout requires the configuration option +<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> and +<varname>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</varname> 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 +<function>cyg_io_set_config()</function>). In non-blocking mode with timeouts, +if there is no CAN event in receive buffer, the driver waits a certain amount +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, <varname>-EINTR</varname> +is returned and the caller must try again. +</PARA> + +<PARA> +If an event was successfully received, the function returns <varname>ENOERR</varname>. +</PARA> +</SECTION><!-- cyg_io_read --> + + +<SECTION> +<TITLE>CAN Events</TITLE> + +<PARA> +The CAN driver uses <structname>cyg_can_event</structname> structures to +pass events from hardware device driver to the generic CAN driver. +A <structname>cyg_can_event</structname> provides a generic device +independent type for handling CAN events that may occur. +</PARA> + +<PROGRAMLISTING> +typedef struct cyg_can_event_st +{ + cyg_uint32 timestamp; + cyg_can_event_flags_t flags; + cyg_can_message msg; +} cyg_can_event; +</PROGRAMLISTING> + +<PARA> +The structure contains the following fields: +</PARA> + +<variablelist> + <varlistentry> + <term><type>cyg_uint32</type> <varname>timestamp</varname></term> + <listitem><para> +If the hardware CAN device driver supports timestamps then this field may +contain a timestamp value for an event that occured. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_event_flags_t</type> <varname>flags</varname></term> + <listitem><para> +Event flags. The <varname>flags</varname> field contains bits that +indicate which kind of events occured. More than one flag can be raised +in a single event. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_message</type> <varname>msg</varname></term> + <listitem><para> +CAN message. The msg field contains a CAN message if an RX or TX event +occured. If another type of event occured, +the <structfield>data</structfield> field of +the <structfield>msg</structfield> may contain additional event +specific data. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +The following events are supported and after receiving an event the +application should check the <varname>flags</varname> field against these values: +</PARA> + +<PROGRAMLISTING> +CYGNUM_CAN_EVENT_RX 0x00000001 // message received +CYGNUM_CAN_EVENT_TX 0x00000002 // mesage transmitted +CYGNUM_CAN_EVENT_WARNING_RX 0x00000004 // tx error counter (TEC) reached warning level (>96) +CYGNUM_CAN_EVENT_WARNING_TX 0x00000008 // rx error counter (REC) reached warning level (>96) +CYGNUM_CAN_EVENT_ERR_PASSIVE 0x00000010 // CAN "error passive" occured +CYGNUM_CAN_EVENT_BUS_OFF 0x00000020 // CAN "bus off" error occured +CYGNUM_CAN_EVENT_OVERRUN_RX 0x00000040 // overrun in RX queue occured +CYGNUM_CAN_EVENT_OVERRUN_TX 0x00000080 // overrun in TX queue occured +CYGNUM_CAN_EVENT_CAN_ERR 0x00000100 // a CAN bit or frame error occured +CYGNUM_CAN_EVENT_LEAVING_STANDBY 0x00000200 // CAN hardware leaves standby / power down mode or is waked up +CYGNUM_CAN_EVENT_ENTERING_STANDBY 0x00000400 // CAN hardware enters standby / power down mode +CYGNUM_CAN_EVENT_ARBITRATION_LOST 0x00000800 // arbitration lost +CYGNUM_CAN_EVENT_FILTER_ERR 0x00001000 // CAN message filter / acceptance filter error +CYGNUM_CAN_EVENT_PHY_FAULT 0x00002000 // General failure of physical layer detected +CYGNUM_CAN_EVENT_PHY_H 0x00004000 // Fault on CAN-H detected (Low Speed CAN) +CYGNUM_CAN_EVENT_PHY_L 0x00008000 // Fault on CAN-L detected (Low Speed CAN) +CYGNUM_CAN_EVENT_ERR_ACTIVE 0x00010000 // CAN controller now "error active" +CYGNUM_CAN_EVENT_OVERRUN_RX_HW 0x00020000 // CAN controller reports a RX overrun +</PROGRAMLISTING> + +<PARA> +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. Most of the flags are independent +from each other and the receiver has to handle each of them separately. +</PARA> + +<PARA> +The internal receive buffers of the CAN device driver are 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 the receive buffer. If this +happens the +<varname>CYGNUM_CAN_EVENT_OVERRUN_RX</varname> flag will be set for +this new message that caused overwriting of the old one. However if an +overrun occurs in the hardware message buffers of the CAN controller, +the flag <varname>CYGNUM_CAN_EVENT_OVERRUN_RX_HW</varname> is raised +instead. +</PARA> + +<PARA> +Example code for receiving one single CAN event: +</PARA> + +<PROGRAMLISTING> +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 +} +</PROGRAMLISTING> +</SECTION><!-- can-cyg_can_event --> + + +<SECTION> +<TITLE>cyg_io_get_config</TITLE> + +<PROGRAMLISTING> +cyg_io_get_config(handle, key, buf, len) +</PROGRAMLISTING> + +<PARA> +This function is used to obtain run-time configuration about a device. +The type of information retrieved is specified by the <parameter>key</parameter>. +The data will be returned in the given buffer. The value of +<parameter>*len</parameter> should contain the amount of data requested, +which must be at least as large as the size appropriate to the selected +<parameter>key</parameter>. The actual size of data retrieved is placed +in <parameter>*len</parameter>. The appropriate key values are all listed +in the file <filename><cyg/io/config_keys.h></filename>. +</PARA> + +<PARA> +The following config keys are currently supported: +</PARA> + +<PROGRAMLISTING> +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 +CYG_IO_GET_CONFIG_CAN_ERR_COUNTERS +</PROGRAMLISTING> +</SECTION><!-- can-cyg-io-get-config --> + +<SECTION> +<TITLE>cyg_io_set_config</TITLE> + +<PROGRAMLISTING> +cyg_io_set_config(handle, key, buf, len) +</PROGRAMLISTING> + +<PARA> +This function is used to manipulate or change the run-time configuration +of a device. The type of information is specified by the <parameter>key</parameter>. +The data will be obtained from the given buffer. The value of +<parameter>*len</parameter> should contain the amount of data provided, +which must match the size appropriate to the selected <parameter>key</parameter>. +The appropriate key values are all listed in the file +<filename><cyg/io/config_keys.h></filename>. +</PARA> + +<PARA> +The following config keys are currently supported: +</PARA> + +<PROGRAMLISTING> +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_MSGBUF +CYG_IO_SET_CONFIG_CAN_MODE +CYG_IO_SET_CONFIG_CAN_ABORT +CYG_IO_SET_CONFIG_CAN_CALLBACK +CYG_IO_SET_CONFIG_CAN_RANGE_FILTER +CYG_IO_SET_CONFIG_CAN_MASK_FILTER +</PROGRAMLISTING> +</SECTION><!-- can-cyg-io-set-config --> +</SECTION><!-- io-can-api-details --> + +<SECTION id="io-can-runtime-cfg"> +<TITLE>Runtime Configuration</TITLE> + +<PARA> +Runtime configuration is achieved by exchanging data structures with the +driver via the <function>cyg_io_set_config()</function> and +<function>cyg_io_get_config()</function> functions. +</PARA> + +<SECTION> +<TITLE>Device configuration</TITLE> + +<PROGRAMLISTING> +typedef struct cyg_can_info_st { + cyg_can_baud_rate_t baud; +} cyg_can_info_t; +</PROGRAMLISTING> + +<PARA> +Device configuration is achieved by by exchanging +<structname>cyg_can_info_t</structname> data structures with the driver +via the <function>cyg_io_set_config()</function> and +<function>cyg_io_get_config()</function> functions using the config keys +<varname>CYG_IO_GET_CONFIG_CAN_INFO</varname> and +<varname>CYG_IO_SET_CONFIG_CAN_INFO</varname>. +The field <structfield>baud</structfield> contains a baud rate selection. +This must be one of the following values: +</PARA> + +<PROGRAMLISTING> +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 +</PROGRAMLISTING> +</SECTION><!-- can-cyg-io-set-config --> + +<SECTION> +<TITLE>Timeout configuration</TITLE> + +<PROGRAMLISTING> +typedef struct cyg_can_timeout_info_st +{ + cyg_uint32 rx_timeout; + cyg_uint32 tx_timeout; +} cyg_can_timeout_info_t; +</PROGRAMLISTING> + +<PARA> +Timeout configuration is achieved by by exchanging +<structname>cyg_can_timeout_info_t</structname> data structures with the +driver via the <function>cyg_io_set_config()</function> and +<function>cyg_io_get_config()</function> functions using the config keys +<varname>CYG_IO_SET_CONFIG_CAN_TIMEOUT</varname> and +<varname>CYG_IO_SET_CONFIG_CAN_TIMEOUT</varname>. +</PARA> + +<variablelist> + <varlistentry> + <term><type>cyg_uint32</type> <varname>rx_timeout</varname></term> + <listitem><para> +Timeout for <function>cyg_io_read</function> calls. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>tx_timeout</varname></term> + <listitem><para> +Timeout for <function>cyg_io_write</function> calls. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +Timeout runtime configuration is supported if the configuration options +<varname>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</varname> +and <varname>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</varname> are enabled. +</PARA> +</SECTION><!-- can-timeout-config --> + +<SECTION> +<TITLE>Reading buffer configuration</TITLE> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<PARA> +<varname>CYG_IO_GET_CONFIG_CAN_BUFFER_INFO</varname> - 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 +<type>cyg_can_message</type> objects in buffer and the current number of +<type>cyg_can_message</type> objects occupied in the buffer. +For the receive buffer it returns the total number of +<type>cyg_can_event</type> objects in receive buffer and the current +number of <type>cyg_can_event</type> 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. +</PARA> + +<variablelist> + <varlistentry> + <term><type>cyg_uint32</type> <varname>rx_bufsize</varname></term> + <listitem><para> +Total number of <type>cyg_can_event</type> buffers in receive queue. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>rx_count</varname></term> + <listitem><para> +Current number of <type>cyg_can_event</type> buffers occupied in receive queue. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>tx_bufsize</varname></term> + <listitem><para> +Total number of <type>cyg_can_message</type> buffers in transmit queue. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>rtx_count</varname></term> + <listitem><para> +Current number of <type>cyg_can_message</type> buffers occupied in transmit queue. + </para></listitem> + </varlistentry> +</variablelist> +</SECTION> <!-- can-read-buffer-config --> + + +<SECTION> +<TITLE>Reading hardware description information</TITLE> + +<PROGRAMLISTING> +typedef struct cyg_can_hdi_st +{ + cyg_uint8 support_flags; + cyg_uint8 controller_type; +} cyg_can_hdi; +</PROGRAMLISTING> + +<PARA> +<varname>CYG_IO_GET_CONFIG_CAN_HDI</varname> - 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 +<structname>cyg_can_hdi</structname> is defined. +</PARA> + +<variablelist> + <varlistentry> + <term><type>cyg_uint8</type> <varname>support_flags</varname></term> + <listitem><para> +Contains information about the capabilities of the used CAN hardware. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint8</type> <varname>controller_type</varname></term> + <listitem><para> +A number that identifies the CAN controller type. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +The following flags are available in the field <structfield>support_flags</structfield>: +</PARA> + +<PROGRAMLISTING> +| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ++-------+-------+-------+-------+--------+-------+-------+-------+ +|ListenO|Mask F |Range F|timest.|autobaud|FullCAN| Frametype | +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><parameter>Frametype</parameter></term> + <listitem><para> +Bit 0 and Bit 1 of the structure describe the possibilities of the CAN +controller. The following values are defined: + <PROGRAMLISTING> +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 + </PROGRAMLISTING> + </para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>FullCAN</parameter></term> + <listitem><para> +If the Bit 2 - <varname>CYGNUM_CAN_HDI_FULLCAN </varname> - is set to one, +the CAN controller supports more than one message buffer. + </para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>autobaud</parameter></term> + <listitem><para> +If Bit 3 - <varname>CYGNUM_CAN_HDI_AUTBAUD</varname> - is set to one then +the CAN driver supports an autobaud feature. + </para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>Timestamp</parameter></term> + <listitem><para> +If Bit 4 - <varname>CYGNUM_CAN_HDI_TIMESTAMP</varname> - is set to one then +the CAN hardware supports timestamps for CAN messages. + </para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>Identifier Range filtering</parameter></term> + <listitem><para> +If Bit 5 - <varname>CYGNUM_CAN_HDI_RANGE_FILTERING</varname> - is set to one +then the CAN hardware supports message filtering based on identifier ranges. + </para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>Identifier Mask filtering</parameter></term> + <listitem><para> +If Bit 6 - <varname>CYGNUM_CAN_HDI_MASK_FILTERING</varname> - is set to one +then the CAN hardware supports message filtering based on identifier masks. + </para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>Listen Only mode</parameter></term> + <listitem><para> +If Bit 7 - <varname>CYGNUM_CAN_HDI_LISTEN_ONLY</varname> - is set to one +then the CAN hardware supports a 'listen-only' mode. + </para></listitem> + </varlistentry> +</variablelist> +</SECTION> <!-- can-read-buffer-config --> + +<SECTION> +<TITLE>Reading hardware message buffer configuration</TITLE> +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<PARA> +<varname>CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO</varname> - If the CAN hardware supports +more than one message buffer for reception of CAN messages (flag +<varname>CYGNUM_CAN_HDI_FULLCAN</varname> is set while reading hardware description +interface with <varname>CYG_IO_GET_CONFIG_CAN_HDI</varname>) then this function +reads the number of message buffers the CAN hardware supports and the number of +free message buffers. +</PARA> + +<variablelist> + <varlistentry> + <term><type>cyg_uint16</type> <varname>count</varname></term> + <listitem><para> +Counts the number of message buffers supported by the device. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint16</type> <varname>free</varname></term> + <listitem><para> +Contains the number of free message buffers. The free message buffers are +available for setting up remote buffers (<varname>CYG_IO_SET_CONFIG_CAN_REMOTE_BUF</varname>) +and message filters (<varname>CYG_IO_SET_CONFIG_CAN_FILTER_MSG</varname>). + </para></listitem> + </varlistentry> +</variablelist> +</SECTION> <!-- can-read-buffer-config --> + +<SECTION> +<TITLE>Reading state of CAN hardware</TITLE> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<PARA> +<varname>CYG_IO_GET_CONFIG_CAN_STATE</varname> - This function retrieves the +present state of the CAN controller. Possible values are defined in the +<type>cyg_can_state</type> enumeration. +</PARA> +</SECTION> <!-- can-read-hw-state --> + +<SECTION> +<TITLE>Reading CAN hardware error counters</TITLE> + +<PROGRAMLISTING> +typedef struct cyg_can_err_count_info_st +{ + cyg_uint8 rx_err_count; + cyg_uint8 tx_err_count; +} cyg_can_err_count_info; +</PROGRAMLISTING> + +<PARA> +Each CAN node maintains two error counters: the Transmit Error Counter (TEC) +and the Receive Error Counter (REC). There are several rules governing how +these counters are incremented and/or decremented. +<varname>CYG_IO_GET_CONFIG_CAN_ERR_COUNTERS</varname> retrieves the present +value of both error counters (TEC and REC). +</PARA> +</SECTION> <!-- can-read-err-counters --> + + +<SECTION> +<TITLE>Changing mode of CAN hardware</TITLE> + +<PARA> +<varname>CYG_IO_SET_CONFIG_CAN_MODE</varname> - This function changes +the operating mode of the CAN controller. The identifiers for the different +operating modes are defined in the <type>cyg_can_mode</type> enumeration. +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><type>CYGNUM_CAN_MODE_STOP</type></term> + <listitem><para> +Set controller into stop mode + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MODE_START</type></term> + <listitem><para> +Set controller into operational mode + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MODE_STANDBY</type></term> + <listitem><para> +Set controller into standby / sleep mode. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MODE_CONFIG</type></term> + <listitem><para> +Set controller into a mode allowing modifying message buffers. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MODE_LISTEN_ONLY_ENTER</type></term> + <listitem><para> 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. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MODE_LISTEN_ONLY_EXIT</type></term> + <listitem><para> Make controller exit of listen-only +mode. The controller will acknowledge all messages it sees on the bus. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +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 <varname>CYGNUM_CAN_EVENT_LEAVING_STANDBY</varname> event will be +inserted into receive message buffer or +the <varname>CYGNUM_CAN_EVENT_LEAVING_STANDBY</varname> flag will be +set for the message that caused wake up of CAN hardware. +</PARA> + +<PARA> +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. +</PARA> +</SECTION> <!-- can-mode-cfg --> + +<SECTION> +<TITLE>Flush or drain buffers</TITLE> + +<PARA> +<varname>CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN</varname> - 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. +</PARA> + +<PARA> +<varname>CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH</varname> - This function +discards any buffered output for the device. +</PARA> + +<PARA> +<varname>CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH</varname> - This function +discards any buffered input for the device. +</PARA> +</SECTION> + +<SECTION> +<TITLE>Configuring blocking/non-blocking calls</TITLE> +<PARA> +By default all calls to <function>cyg_io_read()</function> +and <function>cyg_io_write()</function> are blocking calls. The config +keys +</PARA> + +<PROGRAMLISTING> +CYG_IO_SET_CONFIG_READ_BLOCKING +CYG_IO_SET_CONFIG_WRITE_BLOCKING +</PROGRAMLISTING> + +<PARA> +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 <varname>-EAGAIN</varname>. +</PARA> + +<PARA> +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 <varname>-EINTR</varname>. If +the read/write operation succeeds during the timed wait then the +functions return succesfully with +<varname>ENOERR</varname>. +</PARA> + +<PARA> +To query if <function>cyg_io_read()</function> +and <function>cyg_io_write()</function> are blocking or non-blocking +you can use the config keys +</PARA> + +<PROGRAMLISTING> +CYG_IO_GET_CONFIG_READ_BLOCKING +CYG_IO_GET_CONFIG_WRITE_BLOCKING +</PROGRAMLISTING> +</SECTION> <!-- can-cfg-unblock --> + +<SECTION> +<TITLE>Message buffer management</TITLE> + +<PARA> +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. +</PARA> + +<PARA> +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 <function>cyg_io_set_config()</function> with the config key +</PARA> + +<PROGRAMLISTING> +CYG_IO_SET_CONFIG_CAN_MSGBUF +</PROGRAMLISTING> + +<PARA> +and by exchanging <type>cyg_can_msgbuf_cfg</type> data structures. +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> +<variablelist> + <varlistentry> + <term><type>cyg_can_msgbuf_cfg_id</type> <varname>cfg_id</varname></term> + <listitem><para> The <varname>cfg_id</varname> field +contains the configuration ID that tells the driver what to do with a +message buffer. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_msgbuf_handle</type> <varname>handle</varname></term> + <listitem><para> +Contains a reference to a certain message buffer. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_message</type> <varname>msg</varname></term> + <listitem><para> +Required for configuration of message buffer parameters. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +The following configuration identifiers are supported: +</PARA> + +<PROGRAMLISTING> +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 +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><type>CYGNUM_CAN_MSGBUF_RESET_ALL</type></term> + <listitem><para> +Clears all message buffers - no message will be received and all remote buffers are deleted. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MSGBUF_RX_FILTER_ALL</type></term> + <listitem><para> +Configure driver for reception of all can messages + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MSGBUF_RX_FILTER_ADD</type></term> + <listitem><para> +Add single message filter. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD</type></term> + <listitem><para> +Add new remote response buffer. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE</type></term> + <listitem><para> +Stores data into existing remote buffer (remote buffer handle required). + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +Example code for resetting all message buffers: +</PARA> + +<PROGRAMLISTING> +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 +} +</PROGRAMLISTING> +</SECTION> <!-- can-msgbuf-cfg --> + + +<SECTION> +<TITLE>Remote frame response buffer configuration</TITLE> + +<PARA> +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. +</PARA> + +<PARA> +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. +</PARA> + +<PARA> +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. +</PARA> + +<PARA> +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 <type>cyg_can_remote_buf</type> data structures with the +driver via the <function>cyg_io_set_config()</function> function using +the config key <varname>CYG_IO_SET_CONFIG_CAN_MSGBUF</varname>. Once +the buffer is initialized, the CAN data can be changed at any time by +the application. +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> +<variablelist> + <varlistentry> + <term><type>cyg_can_msgbuf_cfg_id</type> <varname>cfg_id</varname></term> + <listitem><para> +The <varname>cfg_id</varname> field contains the configuration ID that tells the driver what to do with +a message buffer (<varname>CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD</varname> or +<varname>CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE</varname>). + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_msgbuf_handle</type> <varname>handle</varname></term> + <listitem><para> +If there is no buffer initialized for this data, the value of the handle field need to be set to +<varname>CYGNUM_CAN_MSGBUF_INIT</varname>. After the call to <function>cyg_io_set_config()</function> +the handle field contains a valid remote buffer handle ( >= 0) or the value +<varname>CYGNUM_CAN_MSGBUF_NA</varname> ( < 0) if no free buffer is available. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_message</type> <varname>msg</varname></term> + <listitem><para> +The CAN frame that should be transmitted in response to a remote frame. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +Example code for setting up a remote response buffer: +</PARA> + +<PROGRAMLISTING> +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 +} +</PROGRAMLISTING> +</SECTION> <!-- can-rtrbuf-cfg --> + + +<SECTION> +<TITLE>Message filter configuration</TITLE> + +<PARA> +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. +</PARA> + +<PARA> +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. +</PARA> + +<PARA> +In order to add a message filter, a message buffer need to be +initialized. This is achieved by +exchanging <type>cyg_can_filter</type> data structures with the driver +via the <function>cyg_io_set_config()</function> function using the +config key <varname>CYG_IO_SET_CONFIG_CAN_MSGBUF</varname>. Once the +buffer is initialized, the CAN hardware can receive messages with the +identifier of the filter. +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><type>cyg_can_msgbuf_cfg_id</type> <varname>cfg_id</varname></term> + <listitem><para> +The <varname>cfg_id</varname> field contains the configuration ID that tells the driver what to do with +a message buffer. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_msgbuf_handle</type> <varname>handle</varname></term> + <listitem><para> +After the call to <function>cyg_io_set_config()</function> the handle field contains a valid value +( >= 0) or the value <varname>CYGNUM_CAN_MSGBUF_NA</varname> ( < 0) if no free buffer is available. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_message</type> <varname>msg</varname></term> + <listitem><para> +The fields <structfield>id</structfield> and <structfield>ext</structfield> of the <structfield>msg</structfield> +configure the type of message to receive by a certain message filter. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +Before adding message filters the device should be stopped and after +configuration it should be set into operational mode again. +</PARA> + +<PARA> +Example code for setting up a message filter: +</PARA> + +<PROGRAMLISTING> +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 +} +</PROGRAMLISTING> +</SECTION> <!-- can-msgfilt-cfg --> + + +<SECTION id="can-msgfilt-deact"> +<TITLE>Message filter deactivation</TITLE> + +<PARA> +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: +</PARA> + +<PROGRAMLISTING> +CYGNUM_CAN_MSGBUF_RX_FILTER_ALL +</PROGRAMLISTING> + +<PARA> +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. +</PARA> + +<PARA> +Example code for deactivation of message filtering: +</PARA> + +<PROGRAMLISTING> +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"); +} +</PROGRAMLISTING> +</SECTION> <!-- can-msgfilt-deact --> + +<SECTION id="can-id-range-filter"> +<TITLE>Message filtering using identifier ranges</TITLE> + +<PARA> +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. +</PARA> + +<PARA> +To add such a filter, use this configuration ID: +</PARA> + +<PROGRAMLISTING> +CYG_IO_SET_CONFIG_CAN_RANGE_FILTER +</PROGRAMLISTING> + +<PARA> +The buffer argument given to <function>cyg_io_set_config()</function> +must point to an area holding the following structure: +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><type>cyg_can_id_type</type> <varname>ext</varname></term> + <listitem><para> Extended ID. If this field +is <varname>CYGNUM_CAN_ID_EXT</varname> then the next two fields contains +29 bit extended ID. If <varname>ext</varname> +contains <varname>CYGNUM_CAN_ID_STD</varname> then the next two fields +represent 11 bits identifiers. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>lower_id_bound</varname></term> + <listitem><para> +Combined with <varname>upper_id_bound</varname> an identifier range is +defined. All messages having an identifier of the type defined by +<varname>ext</varname> and included in the range <varname>lower_id_bound</varname> +to <varname>upper_id_bound</varname> will pass the filter. The identifiers +<varname>lower_id_bound</varname> and <varname>upper_id_bound</varname> are +included in the defined range. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>upper_id_bound</varname></term> + <listitem><para> +Upper identifier value of the defined range. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +If no free buffers or filters are available, <varname>-ENOSPC</varname> is +returned. +</PARA> + +</SECTION> <!-- can-id-range-filter --> + +<SECTION id="can-id-mask-filter"> +<TITLE>Message filtering using identifier masks</TITLE> + +<PARA> +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. +</PARA> + +<PARA> +To add such a filter, use this configuration ID: +</PARA> + +<PROGRAMLISTING> +CYG_IO_SET_CONFIG_CAN_MASK_FILTER +</PROGRAMLISTING> + +<PARA> +The buffer argument given to <function>cyg_io_set_config()</function> +must point to an area holding the following structure: +</PARA> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><type>cyg_can_id_type</type> <varname>ext</varname></term> + <listitem><para> +Extended ID. If this field is <varname>CYGNUM_CAN_ID_EXT</varname> then the +<structname>id</structname> field contains a 29 bit extended ID. If it +contains <varname>CYGNUM_CAN_ID_STD</varname> then the ID is 11 bits. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>id</varname></term> + <listitem><para> +Message ID. This is the ID to be matched with an incoming message, after +having considered the <varname>mask</varname> field. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_uint32</type> <varname>mask</varname></term> + <listitem><para> +Mask value. A message will pass the filter if, for each bit set in +<varname>mask</varname>, the received message ID has its corresponding +bit equals to the corresponding bit in the <varname>id</varname> field. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +For instance let's suppose that the <varname>id</varname> field is +0x05 (bits 0 and 2 are set) and the <varname>mask</varname> 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 <varname>id</varname> field have a similar +value for bit 0. The message ID has its bit 1 set to 0, as +the <varname>id</varname> 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 <varname>id</varname> +field, hence this example message does not pass the filter. +</PARA> + +<PARA> +If no free buffers or filters are available, <varname>-ENOSPC</varname> is +returned. +</PARA> + +</SECTION> <!-- can-id-mask-filter --> + +<SECTION id="can-event-callback"> +<TITLE>Configuring a callback on events</TITLE> + +<PARA> +By default application cannot get information about an event arriving +in the RX buffer until it calls +the <function>cyg_io_read()</function>. Usually this leads applications +to use accessory threads to wait for new CAN events. +</PARA> + +<PARA> +The CDL option <varname>CYGOPT_IO_CAN_SUPPORT_CALLBACK</varname> +allows application to use a callback on event arrival. It is +configured by passing a <structname>cyg_can_callback_cfg</structname> +data structure to the driver via +the <function>cyg_io_set_config()</function> function using the config +key +<varname>CYG_IO_SET_CONFIG_CAN_CALLBACK</varname>. +</PARA> + +<PROGRAMLISTING> +CYG_IO_SET_CONFIG_CAN_CALLBACK +</PROGRAMLISTING> + +<PROGRAMLISTING> +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; +</PROGRAMLISTING> + +<variablelist> + <varlistentry> + <term><type>cyg_can_event_cb_t</type> <varname>callback_func</varname></term> + <listitem><para> +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. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>CYG_ADDRWORD</type> <varname>data</varname></term> + <listitem><para> +Additional user data that will be passed to callback function as a second parameter. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cyg_can_event_flags_t</type> <varname>flag_mask</varname></term> + <listitem><para> +Should be set with a combination +of <varname>CYGNUM_CAN_EVENT_*</varname> 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 <varname>flag_mask</varname> to 0. To +set all possible flags use the <varname>CYGNUM_CAN_EVENT_ALL</varname> macro. + </para></listitem> + </varlistentry> +</variablelist> + +<PARA> +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. +</PARA> + +<PARA> +If you plan to have the callback function to perform read operations, +be aware that <function>cyg_io_read()</function> retrieves events of +all kinds while the callback function is triggered only on events it +is expecting, as defined by the <varname>flag_mask</varname> +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 <function>cyg_io_read()</function>. +</PARA> + +<PARA> +For instance, let's suppose the callback function is expecting +only <varname>CYGNUM_CAN_EVENT_RX</varname> events while the bus +activity triggers other kind of events, like +the <varname>CYGNUM_CAN_EVENT_WARNING_RX</varname> event. It is +possible to have in the receive queue a first event of +type <varname>CYGNUM_CAN_EVENT_WARNING_RX</varname> followed by a +second event of type <varname>CYGNUM_CAN_EVENT_RX</varname>. In that +case, the callback function is triggered and have its first parameter +set to <varname>CYGNUM_CAN_EVENT_RX</varname> exactly +when <varname>CYGNUM_CAN_EVENT_RX</varname> occurs, but if the +callback function reads the event queue, it will first get +the <varname>CYGNUM_CAN_EVENT_WARNING_RX</varname> event. +</PARA> + +<PARA> +If the callback function is set to process all kind of events and +always call <function>cyg_io_read()</function> to get each event, it +is possible to have a receive queue size of one event. +</PARA> + +<PARA> +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 <function>cyg_current_time()</function> may not be accurate enough, +according to the clock resolution and your needs of accuracy. +</PARA> + +</SECTION> <!-- can-event-callback --> + +</SECTION> +</CHAPTER> + +<CHAPTER id="io-can-configuration"> +<TITLE>Configuration</TITLE> + +<PARA> +The CAN subsystem has a number of configuration options. +</PARA> + +<variablelist> + <varlistentry> + <term><type>cdl_interface CYGINT_IO_CAN_TIMESTAMP</type></term> + <listitem><para> +A hardware device driver that supports timestamps should implement this interface. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cdl_option CYGOPT_IO_CAN_SUPPORT_TIMESTAMP</type></term> + <listitem><para> +If the CAN hardware driver supports some kind of timestamps then this option enables +propagation of timestamps to higher layers. This may add some extra code to hardware +drivers. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cdl_option CYGOPT_IO_CAN_TX_EVENT_SUPPORT</type></term> + <listitem> +<para> This option enables support for TX +events. If a CAN message is transmitted successfully a TX event will +be inserted into the receive event queue and propagated to higher +layers. If this option is enabled the RX event queue will be filled +faster. +</para></listitem> + </varlistentry> + <varlistentry> + <term><type>cdl_option CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</type></term> + <listitem> +<para> +This option enables extra code in the generic CAN driver which allows +clients to switch read() and write() call semantics from blocking to +non-blocking. +</para></listitem> + </varlistentry> + <varlistentry> + <term><type>cdl_option CYGOPT_IO_CAN_SUPPORT_CALLBACK</type></term> + <listitem> +<para> +This option enables extra code in the generic CAN driver which allows +an application to register a callback for events. The callback function +is called from DSR context so you should be careful to only call API +functions that are safe in DSR context. +</para></listitem> + </varlistentry> + <varlistentry> + <term><type>cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ</type></term> + <listitem><para> +The initial timeout value in clock ticks for <FUNCTION>cyg_io_read()</FUNCTION> calls. + </para></listitem> + </varlistentry> + <varlistentry> + <term><type>cdl_option CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE</type></term> + <listitem><para> The initial timeout value in clock ticks +for <FUNCTION>cyg_io_write()</FUNCTION> calls. + </para></listitem> + </varlistentry> +</variablelist> +</CHAPTER> + + +<CHAPTER id="io-can-device-drivers"> +<TITLE>Writing a CAN hardware device driver</TITLE> + +<PARA> +A CAN driver is nothing more than a named entity that supports the +basic I/O functions - read, write, get config, and set config. The +device driver uses and manages interrupts from the device. While the +interface is generic and device driver independent, the actual driver +implementation is completely up to the device driver designer. +</PARA> + +<PARA> +That said, the reason for using a device driver is to provide access +to a CAN device from application code in as general purpose a fashion +as reasonable. Most driver writers are also concerned with making this +access as simple as possible while being as efficient as possible. +</PARA> + +<PARA> +Like other device drivers the CAN device driver is concerned with the +movement of information - the CAN messages. In order to make the most +efficient use of system resources, interrupts are used. This will +allow other application processing to take place while the data +transfers are under way, with interrupts used to indicate when various +events have occurred. For example, a CAN device typically generates an +interrupt after a CAN message has been sent or a CAN message has been +received by a CAN hardware message buffer. It makes sense to allow +further application processing while the data is being sent since this +can take quite a long time. The interrupt can be used to allow the +driver to send a CAN message as soon as the current one is complete, +without any active participation by the application code. +</PARA> + +<PARA> +The main building blocks for CAN device drivers are found in the +include files +<filename><cyg/io/devtab.h></filename> and <filename><cyg/io/can.h></filename> +</PARA> + +<PARA> +Like many other device drivers in eCos, CAN device drivers are described by a device +table entry, using the <type>cyg_devtab_entry_t</type> type. The entry should be created using +the <varname>DEVTAB_ENTRY()</varname> macro. +</PARA> + + +<SECTION id="io-can-how-to-write-interface-driver"> +<TITLE>How to Write a CAN Hardware Interface Driver</TITLE> + +<PARA> +The standard CAN driver supplied with eCos is structured as a hardware +independent portion and a hardware dependent interface module. To add +support for a new CAN device, the user should be able to use the +existing hardware independent portion and just add their own interface +driver which handles the details of the actual device. The user should +have no need to change the hardware independent portion. +</PARA> + +<PARA> +The interfaces used by the CAN driver and CAN implementation modules +are contained in the file <filename><cyg/io/can.h></filename>. +</PARA> + +<SECTION> +<title>DevTab Entry</TITLE> + +<PARA> +The interface module contains the devtab entry (or entries if a single +module supports more than one interface). This entry should have the +form: +</PARA> + +<PROGRAMLISTING> +DEVTAB_ENTRY(<<module_name>>, + <<device_name>>, + 0, + &can_devio, + <<module_init>>, + <<module_lookup>>, + &<<can_channel>> + ); +</PROGRAMLISTING> + +<variablelist> +<title>Arguments</title> + <varlistentry> + <term><parameter>module_name</parameter></term> + <listitem><para>The "C" label for this devtab entry</para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>device_name</parameter></term> + <listitem><para>The "C" string for the + device. E.g. <filename>/dev/can0</filename>.</para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>can_devio</parameter></term> + <listitem><para>The table of I/O functions. This set is defined in + the hardware independent CAN driver and should be used.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>module_init</parameter></term> + <listitem><para>The hardware module initialization function.</para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>module_lookup</parameter></term> + <listitem><para>The device lookup function. This function + typically sets up the CAN device for actual use, turning on + interrupts, configuring the message buffers, etc.</para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>can_channel</parameter></term> + <listitem><para>This table (defined below) contains the interface + between the interface module and the CAN driver proper.</para></listitem> + </varlistentry> +</variablelist> + +<PARA> +Example devtab entry for Motorola FlexCAN device driver: +</PARA> + +<PROGRAMLISTING> +DEVTAB_ENTRY(flexcan_devtab, + CYGDAT_DEVS_CAN_MCF52xx_FLEXCAN0_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_can_devio, + flexcan_init, + flexcan_lookup, // CAN driver may need initializing + &flexcan_can0_chan + ); +</PROGRAMLISTING> +</SECTION> + + +<SECTION> +<title>CAN Channel Structure</TITLE> + +<PARA> +Each CAN device must have a “CAN channel”. +This is a set of data which describes all operations on the device. +It also contains buffers, etc. The CAN channel is created by the macro: +</PARA> + +<PROGRAMLISTING> +CAN_CHANNEL_USING_INTERRUPTS(l, funs, dev_priv, baud, + out_buf, out_buflen, + in_buf, in_buflen) +</PROGRAMLISTING> + +<variablelist> + <title>Arguments</title> + <varlistentry> + <term><parameter>l</parameter></term> + <listitem><para>The "C" label for this structure.</para></listitem> + </varlistentry> + <varlistentry> + <term><parameter>funs</parameter></term> + <listitem><para>The set of interface functions (see below).</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>dev_priv</structfield></term> + <listitem><para>A placeholder for any device specific data for + this channel.</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>baud</structfield></term> + <listitem><para>The initial baud rate value + (<type>cyg_can_baud_rate_t</type>).</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>out_buf</structfield></term> + <listitem><para>Pointer to the output buffer</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>out_buflen</structfield></term> + <listitem><para>The length of the output buffer.</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>in_buf</structfield></term> + <listitem><para>pointer to the input buffer.</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>in_buflen</structfield></term> + <listitem><para>The length of the input buffer.</PARA></listitem> + </varlistentry> +</variablelist> + +<PARA> +Example CAN channel implementation for Motorola FlexCAN device driver: +</PARA> + +<PROGRAMLISTING> +CAN_CHANNEL_USING_INTERRUPTS( + flexcan_can0_chan, + flexcan_lowlevel_funs, + flexcan_can0_info, + CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_KBAUD), + flexcan_can0_txbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_TX, + flexcan_can0_rxbuf, CYGNUM_DEVS_CAN_MCF52xx_FLEXCAN0_QUEUESIZE_RX +); +</PROGRAMLISTING> + +<PARA> +The interface from the hardware independent driver into the hardware +interface module is contained in the <structfield>funs</structfield> +table. This is defined by the macro: +</PARA> +</SECTION> + +<SECTION> +<TITLE>CAN Lowlevel Functions Structure</TITLE> + +<PROGRAMLISTING> +CAN_LOWLEVEL_FUNS(l, putmsg, getevent, get_config, set_config, start_xmit, stop_xmit) +</PROGRAMLISTING> + +<variablelist> + <title>Arguments</title> + <varlistentry> + <term><structfield>l</structfield></term> + <listitem><para>The "C" label for this structure.</para></listitem> + </varlistentry> + <varlistentry> + <term><structfield>putmsg</structfield></term> + <listitem> + <para><literal> + bool (*putmsg)(can_channel *priv, cyg_can_message *pmsg, void *pdata) + </literal></para> + <para> + This function sends one CAN message to the interface. It should + return <literal>true</literal> if the message is actually + consumed. It should return <literal>false</literal> if there is + no space in the interface + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><structfield>getevent</structfield></term> + <listitem> + <para><literal> + bool (*getevent)(can_channel *priv, cyg_can_event *pevent, void *pdata) + </literal></para> + <para> + This function fetches one event from the interface. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><structfield>get_config</structfield></term> + <listitem> + <para><literal> + Cyg_ErrNo (*get_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len) + </literal></para> + <para> + This function is used to query the configuration of a CAN channel. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><structfield>set_config</structfield></term> + <listitem> + <para><literal> + Cyg_ErrNo (*set_config)(can_channel *priv, cyg_uint32 key, const void *xbuf, cyg_uint32 *len) + </literal></para> + <para> + This function is used to change configuration of a CAN channel. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>start_xmit</parameter></term> + <listitem><para><literal>void (*start_xmit)(can_channel *priv)</literal></para> + <para> + Enable the transmit channel and turn on transmit interrupts. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>stop_xmit</parameter></term> + <listitem> + <para><literal>void (*stop_xmit)(can_channel *priv)</literal></para> + <para>Disable the transmit channel and turn transmit interrupts off.</PARA> + </listitem> + </varlistentry> +</variablelist> + +<PARA> +Example implementation of low level function structure for Motorola FlexCAN +device driver: +</PARA> + +<PROGRAMLISTING> +CAN_LOWLEVEL_FUNS(flexcan_lowlevel_funs, + flexcan_putmsg, + flexcan_getevent, + flexcan_get_config, + flexcan_set_config, + flexcan_start_xmit, + flexcan_stop_xmit + ); +</PROGRAMLISTING> +</SECTION> + +<SECTION> +<TITLE>Callbacks</TITLE> + +<PARA> +The device interface module can execute functions in the +hardware independent driver via <literal>chan->callbacks</literal>. +These functions are available: +</PARA> + +<PROGRAMLISTING> +void (*can_init)(can_channel *chan) +</PROGRAMLISTING> + +<PARA>This function is used to initialize the CAN channel.</PARA> + +<PROGRAMLISTING> +cyg_bool (*xmt_msg)(can_channel *chan, void *pdata) +</PROGRAMLISTING> + +<PARA> +This function would be called from an interrupt handler after a +transmit interrupt indicating that additional messages may be +sent. The upper driver will call the <function>putmsg</function> +function as appropriate to send more data to the +device. <function>xmt_msg()</function> returns <literal>true</literal> +if a message has been provided to the low level +driver, <literal>false</literal> otherwise. +</PARA> + +<PROGRAMLISTING> +cyg_bool (*rcv_event)(can_channel *chan, void *pdata) +</PROGRAMLISTING> + +<PARA> +This function is used to tell the driver that a message has arrived at +the interface or that an event has occurred. This function is +typically called from the interrupt +handler. <function>rcv_event()</function> +returns <literal>true</literal> if an event has been provided by the +low level driver, <literal>false</literal> otherwise. +</PARA> +</SECTION><!-- Callbacks --> + +</SECTION><!-- id="io-can-how-to-write-interface-driver" --> +</CHAPTER> + +</PART> diff --git a/ecos/packages/io/can/current/doc/can_driver_doc.html b/ecos/packages/io/can/current/doc/can_driver_doc.html new file mode 100644 index 0000000..405721d --- /dev/null +++ b/ecos/packages/io/can/current/doc/can_driver_doc.html @@ -0,0 +1,495 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<html> + + <head> + <meta http-equiv="content-type" content="text/html;charset=iso-8859-1"> + <title>IO/CAN Doc</title> + </head> + + <body bgcolor="#ffffff"> + <h2>CAN driver details</h2> + <p>A raw CAN driver is is provided as a standard part of the eCos system. Use the include file <code><cyg/io/canio.h></code> 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.</p> + <h3>User API</h3> + <p>The CAN driver uses the standard eCos I/O API functions. All functions except <code>cyg_io_lookup()</code> require an I/O "handle".</p> + <p>All functions return a value of the type <code>Cyg_ErrNo</code>. If an error condition is detected, this value will be negative and the absolute value indicates the actual error, as specified in <code>cyg/error/codes.h</code>. The only other legal return value will be <code>ENOERR</code> , <code>-EINTR </code>and<code> -EAGAIN</code>. 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 <i>len </i>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.</p> + <h4>Lookup a CAN device</h4> + <p><code>Cyg_ErrNo cyg_io_lookup(<br> const char *name,<br> cyg_io_handle_t *handle )</code></p> + <p>This function maps a device name onto an appropriate handle. If the named device is not in the system, then the error -<code>ENOENT</code> is returned. If the device is found, then the handle for the device is returned by way of the handle pointer <i>*handle</i>.</p> + <h4>Send a CAN message</h4> + <p><code>Cyg_ErrNo cyg_io_write(<br> + cyg_io_handle_t handle,<br> + const void *buf,<br> + cyg_uint32 *len )<br> + </code></p> + <p>This function sends <b>one single</b> CAN message (not a buffer of CAN messages) to a device. The size of data to send is contained in <i>*len</i> and the actual size sent will be returned in the same place. A pointer to a <code>cyg_can_message</code> is contained in <i>*buf</i> . 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,<i> *len</i> contains the amount of characters actually consumed - that means <i>*len</i> always contains <code>sizeof(cyg_can_message)</code>.</p> + <p>It is possible to configure the write call to be blocking (default) or non-blocking. Non-blocking mode requires both the configuration option <code>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</code> to be enabled, and the specific device to be set to non-blocking mode for writes (see <code>cyg_io_set_config()</code>). 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, <code>-EAGAIN</code> is returned and the caller must try again.</p> + <p>It is possible to configure the write call to be non-blocking with timeout. None-blocking mode with timeout requires the configuration option <code>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING </code>and<code> CYGOPT_IO_CAN_SUPPORT_TIMEOUTS </code>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 <code>cyg_io_set_config()</code>). 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, <code> -EINTR</code> is returned and the caller must try again.</p> + <p>If a message was sucessfully sent, the function returns <code>ENOERR</code>. </p> + <p><code>typedef struct can_message<br> + + {<br> + + + cyg_uint32 id;<br> + + + cyg_uint8 data[8];<br> + + + cyg_can_id_type ext;<br> + + + cyg_can_frame_type rtr;<br> + + + cyg_uint8 dlc;<br> + + } cyg_can_message;</code></p> + <p>The type <code>cyg_can_message</code> provides a device independent type of CAN message. Before calling the write function this message should be setup properly. The<i> id</i> field contains the 11 Bit or 29 bit CAN message identifier depending on the value of the <i>ext</i> field. The <i>data</i> field contains the 8 data bytes of one CAN message. The <i>ext</i> field configures the type of CAN message identifier (<code>CYGNUM_CAN_ID_STD</code> = standard 11 Bit id,<i> </i><code>CYGNUM_CAN_ID_EXT</code> = extended 29 Bit id). The <i>rtr</i> field contains the frame type. (<code>CYGNUM_CAN_FRAME_DATA</code> = data frame, <code>CYGNUM_CAN_FRAME_RTR</code> = remote transmission request). The <i>dlc</i> field (data length code) contains the number of valid data bytes (0 - 8) in the <i>data</i> field.</p> + <p>Example code for sending one single CAN message:</p> + <p><code>cyg_can_message tx_msg;<br>cyg_uint32 len;<br> + Cyg_ErrNo ret;<br> + <br> + + + tx_msg.id = 0x100;<br> + + + tx_msg.ext = CYGNUM_CAN_ID_EXT;<br> + + tx_msg.rtr = CYGNUM_CAN_FRAME_DATA;<br> + + tx_msg.dlc = 1;<br> + + tx_msg.data[0] = 0xF1;<br> + <br> + + len = sizeof(tx_msg);<br> + ret = cyg_io_write(hDrvCAN, &tx_msg, &len);</code></p> + <h4>Read a CAN event</h4> + <p><code>Cyg_ErrNo cyg_io_read(<br> + cyg_io_handle_t handle,<br> + + void *buf,<br> + + cyg_uint32 *len )<br> + </code></p> + <p>This function receives one single event from a device. The desired size of data to receive is contained in <i>*len</i> and the actual size obtained will be returned in the same place. A pointer to a<code> cyg_can_event</code> is contained in <i>*buf</i>. No manipulation of the data is performed before being transferred. Again, this buffering is completely configurable. On return, <i>*len</i> contains <code>sizeof(cyg_can_event)</code><br> + </p> + <p>It is possible to configure the read call to be blocking (default) or non-blocking. Non-blocking mode requires both the configuration option <code>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING</code> to be enabled, and the specific device to be set to non-blocking mode for reads (<code>see cyg_io_set_config()</code>). In blocking mode, the call will not return until one single CAN event has been read. In<i> </i>non-blocking mode, if there is no CAN event in buffer, the call returns immediately with <code>-EAGAIN</code> and the caller must try again.</p> + <p>It is possible to configure the write call to be non-blocking with timeout. None-blocking mode with timeout requires the configuration option <code>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING </code>and<code> CYGOPT_IO_CAN_SUPPORT_TIMEOUTS </code>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 <code>cyg_io_set_config()</code>). 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, <code> -EINTR</code> is returned and the caller must try again.</p> + <p>If an event was sucessfully received, the function returns <code>ENOERR</code>.</p> + <p><code>typedef struct cyg_can_event_st<br> + {<br> + cyg_uint32 timestamp;<br> + + cyg_can_message msg;<br> + + cyg_uint16 flags;<br> + } cyg_can_event;<br> + </code></p> + <p>A <code>cyg_can_event</code> provides a generic device independent type for handling CAN events that may occur. If the driver supports timestamps then the <i>timestamp</i> field my contain a timestamp value for an event that occured. The <i>msg</i> field contains a CAN message if an RX or TX event occured. The <i>flags</i> 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:</p> + <p><code>typedef enum <br> + {<br> + + CYGNUM_CAN_EVENT_RX = 0x0001, // message received<br> + + CYGNUM_CAN_EVENT_TX = 0x0002, // mesage transmitted<br> + + CYGNUM_CAN_EVENT_WARNING_RX = 0x0004, // tx error counter (TEC) reached warning level (>96)<br> + + CYGNUM_CAN_EVENT_WARNING_TX = 0x0008, // rx error counter (REC) reached warning level (>96)<br> + + CYGNUM_CAN_EVENT_ERR_PASSIVE = 0x0010, // CAN "error passive" occured<br> + + CYGNUM_CAN_EVENT_BUS_OFF = 0x0020, // CAN "bus off" error occured<br> + + CYGNUM_CAN_EVENT_OVERRUN_RX = 0x0040, // overrun in RX queue or hardware occured<br> + + CYGNUM_CAN_EVENT_OVERRUN_TX = 0x0080, // overrun in TX queue occured<br> + + CYGNUM_CAN_EVENT_CAN_ERR = 0x0100, // a CAN bit or frame error occured<br> + + CYGNUM_CAN_EVENT_LEAVING_STANDBY = 0x0200, // CAN hardware leaves standby / power don mode or is waked up<br> + + CYGNUM_CAN_EVENT_ENTERING_STANDBY = 0x0400, // CAN hardware enters standby / power down mode<br> + + CYGNUM_CAN_EVENT_ARBITRATION_LOST = 0x0800, // arbitration lost<br> + CYGNUM_CAN_EVENT_DEVICE_CHANGED = 0x1000, // device changed event<br> + </code><code>CYGNUM_CAN_EVENT_PHY_FAULT = 0x2000, // General failure of physical layer detected (if supported by hardware)<br> + </code><code>CYGNUM_CAN_EVENT_PHY_H = 0x4000, // Fault on CAN-H detected (Low Speed CAN)<br> + </code><code>CYGNUM_CAN_EVENT_PHY_L = 0x8000, // Fault on CAN-L detected (Low Speed CAN)<br> + } cyg_can_event_flags;</code></p> + <p>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 <code>CYGNUM_CAN_EVENT_RX </code>is set then also the <code>CYGNUM_CAN_EVENT_OVERRUN_RX </code>may be set if the received message caused an RX overrun.</p> + <p>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 <code>CYGNUM_CAN_EVENT_OVERRUN_RX </code>flag will be set for this new message that caused overwriting of the old one. The <code>CYGNUM_CAN_EVENT_OVERRUN_RX </code>flag will be set also if a overrun occures in hardware message buffers of the CAN device.</p> + <p>Example code for receiving one single CAN event:</p> + <p><code>cyg_can_event rx_event;<br> + cyg_uint32 len;<br> + Cyg_ErrNo ret;<br> + <br> + + len = sizeof(rx_event);<br> + + ret = cyg_io_read(hDrvCAN, &rx_event, &len);<br> + <br> + + if (ENOERR == ret)<br> + + {<br> + + if (rx_event.flags & CYGNUM_CAN_EVENT_RX)<br> + + {<br> + + // handle RX event<br> + + }<br> + + <br> + + if (rx_event.flags & ~CYGNUM_CAN_EVENT_RX)<br> + + {<br> + + // handle other events<br> + + }<br> + + }<br> + + else if (-EINTR == ret)<br> + + {<br> + + // handle timeout<br> + + }<br> + </code></p> + <h4>Read configuration of a CAN device</h4> + <p><code>Cyg_ErrNo cyg_io_get_config(<br> + cyg_io_handle_t handle,<br> + cyg_uint32 key,<br> + void *buf,<br> + cyg_uint32 *len )<br> + </code></p> + <p>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 <i>*len</i> 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 <i>*len</i>. The appropriate key values are all listed in the file<code> <cyg/io/config_keys.h></code>.</p> + <p>The following config keys are currently supported:</p> + <p><code>CYG_IO_GET_CONFIG_READ_BLOCKING<br> + CYG_IO_GET_CONFIG_WRITE_BLOCKING<br> + CYG_IO_GET_CONFIG_CAN_INFO<br> + CYG_IO_GET_CONFIG_CAN_BUFFER_INFO<br>CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO<br> + + CYG_IO_GET_CONFIG_CAN_TIMEOUT<br> + CYG_IO_GET_CONFIG_CAN_HDI<br> + CYG_IO_GET_CONFIG_CAN_STATE<br> + </code></p> + <h4>Change configuration of a CAN device</h4> + <p><code>Cyg_ErrNo cyg_io_set_config(<br> + cyg_io_handle_t handle,<br> + + cyg_uint32 key,<br> + + const void *buf,<br> + + cyg_uint32 *len)<br> + </code></p> + <p>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 <i>*len</i> 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 <code><cyg/io/config_keys.h></code>.</p> + <p>The following config keys are currently supported:</p> + <p><code>CYG_IO_SET_CONFIG_READ_BLOCKING<br> + CYG_IO_SET_CONFIG_WRITE_BLOCKING<br> + CYG_IO_SET_CONFIG_CAN_INFO<br> + CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN<br> + CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH<br> + CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH<br> + + + CYG_IO_SET_CONFIG_CAN_TIMEOUT<br>CYG_IO_SET_CONFIG_CAN_MSGBUF<br> + </code><code>CYG_IO_SET_CONFIG_CAN_MODE<br> + <br> + </code></p> + <h3>Runtime Configuration</h3> + <p>Runtime configuration is achieved by exchanging data structures with the driver via the <code>cyg_io_set_config()</code> and <code>cyg_io_get_config()</code> functions.</p> + <h4>Device configuration</h4> + <p><code>typedef struct cyg_can_info_st {<br> + cyg_can_baud_rate_t baud;<br> + } cyg_can_info_t;</code></p> + <p>Device configuration is achieved by by exchanging <code>cyg_can_info_t </code>data structures with the driver via the <code>cyg_io_set_config()</code> and <code>cyg_io_get_config()</code> functions using the config keys <code>CYG_IO_GET_CONFIG_CAN_INFO </code>and<code> CYG_IO_SET_CONFIG_CAN_INFO</code>. The field <i>baud</i> contains a baud rate selection. This must be one of the follwing values:</p> + <p><code>CYGNUM_CAN_KBAUD_10<br> + CYGNUM_CAN_KBAUD_20<br> + CYGNUM_CAN_KBAUD_50<br> + CYGNUM_CAN_KBAUD_100<br> + CYGNUM_CAN_KBAUD_125<br> + CYGNUM_CAN_KBAUD_250<br> + CYGNUM_CAN_KBAUD_500<br> + CYGNUM_CAN_KBAUD_800<br> + CYGNUM_CAN_KBAUD_1000<br> + </code></p> + <h4>Timeout configuration</h4> + <p><code>typedef struct cyg_can_timeout_info_st<br> + {<br> + + cyg_uint32 rx_timeout; <br> + + cyg_uint32 tx_timeout;<br> + } cyg_can_timeout_info_t;<br> + </code></p> + <p>Timeout configuration is achieved by by exchanging <code>cyg_can_timeout_info_t </code>data structures with the driver via the <code>cyg_io_set_config()</code> and <code>cyg_io_get_config()</code> functions using the config keys <code>CYG_IO_SET_CONFIG_CAN_TIMEOUT </code>and<code> CYG_IO_SET_CONFIG_CAN_TIMEOUT</code>. The field <i>rx_timeout</i> contains the timeout value for <code>cyg_io_read </code>calls and <i>tx_timeout</i> contains the timeout value for <code>cyg_io_write </code>calls. This call is only available if the configuration options <code>CYGOPT_IO_CAN_SUPPORT_NONBLOCKING </code>and <code>CYGOPT_IO_CAN_SUPPORT_TIMEOUTS</code> are enabled.</p> + <h4>Reading buffer configuration</h4> + <p><code>typedef struct cyg_can_buf_info_st<br> + { <br> + cyg_int32 rx_bufsize; <br> + cyg_int32 rx_count;<br> + cyg_int32 tx_bufsize;<br> + cyg_int32 tx_count;<br> + } cyg_can_buf_info_t;<br> + </code></p> + <p><code>CYG_IO_GET_CONFIG_CAN_BUFFER_INFO - </code>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 <code>cyg_can_message </code>objects in buffer and the current number of <code>cyg_can_message </code>objects occupied in the buffer. For the recieve buffer it returns the total number of <code>cyg_can_event </code>objects in receive buffer and the current number of <code>cyg_can_event </code>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.</p> + <h4>Reading hardware description information</h4> + <p><code>typedef struct cyg_can_hdi_st<br> + {<br> + cyg_uint8 support_flags;<br> + cyg_uint8 controller_type;<br> + } cyg_can_hdi;</code></p> + <p><code>CYG_IO_GET_CONFIG_CAN_HDI - </code>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 <code>cyg_can_hdi </code>is defined. The field support_flags contains information about the capabilities of the used CAN hardware. The following flags are available:</p> + <table width="600" border="0" cellspacing="2" cellpadding="0"> + <tr> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">7</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">6</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">5</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">4</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">3</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">2</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">1</td> + <td align="center" valign="middle" bgcolor="#c6c6c6" width="70">0</td> + </tr> + <tr> + <td align="center" valign="middle" width="70">res</td> + <td align="center" valign="middle" width="70">res</td> + <td align="center" valign="middle" width="70">res</td> + <td align="center" valign="middle" width="70">timest.</td> + <td align="center" valign="middle" width="70">SW-Filt</td> + <td align="center" valign="middle" width="70">FullCAN</td> + <td colspan="2" align="center" valign="middle" width="142">Frametype</td> + </tr> + </table> + <p><i>Frametype:<br> + </i>Bit 0 and Bit 1 of the structure describe the<i> </i>possibilities of the CAN controller. The following values are defined:</p> + <p><code>CYGNUM_CAN_HDI_FRAMETYPE_STD // receives only standard frame<br> + CYGNUM_CAN_HDI_FRAMETYPE_EXT_PASSIVE // can recieve but not send extended frames<br> + CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE // can send and receive extended frames<br> + </code></p> + <p><i>FullCAN:<br> + </i>If the Bit 2 is set to one, the CAN controller supports more than one message buffer.</p> + <p><code>CYGNUM_CAN_HDI_FULLCAN // supports more than one message buffer<br> + </code></p> + <p><i>SW-Filter:<br> + </i>If Bit3 is set to one then the CAN driver supports some kind of software message filtering.</p> + <p><code>CYGNUM_CAN_HDI_FILT_SW // software message filtering supported<br> + </code></p> + <p><i>Timestamp:<br> + </i>If Bit 4 is set to one then the CAN hardware supports timestamps for CAN messages</p> + <p><code>CYGNUM_CAN_HDI_TIMESTAMP // CAN hardware supports timestamps<br> + </code></p> + <h4>Reading message buffer configuration</h4> + <p><code>typedef struct cyg_can_msgbox_info_st<br> + </code><code>{<br> + c</code><code>yg_uint8 count; // number of message buffers available for this device<br> + </code><code>cyg_uint8 free; // number of free message buffers<br> + </code><code>} cyg_can_msgbuf_info;</code></p> + <p><code>CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO</code> - If the CAN hardware supports more than one message buffer for reception of CAN message (flag <code>CYGNUM_CAN_HDI_FULLCAN </code>is set after reading hardware description interface with <code>CYG_IO_GET_CONFIG_CAN_HDI</code>) then this function reads the number of message buffers the CAN hardware supports and the number of free message buffers. The field<i> count</i> contains the number of message buffers supported by device and the field <i>free</i> contains the number of free message buffers. The free message buffers are available for setting up remote buffers (<code>CYG_IO_SET_CONFIG_CAN_REMOTE_BUF)</code> and message filters (<code>CYG_IO_SET_CONFIG_CAN_FILTER_MSG</code>).</p> + <h4>Reading state of CAN hardware</h4> + <p><code>typedef enum<br> + {<br> CYGNUM_CAN_STATE_ACTIVE, // CAN controller is active, no errors<br> + </code><code>CYGNUM_CAN_STATE_STOPPED, // CAN controller is in stopped mode<br> + </code><code>CYGNUM_CAN_STATE_STANDBY, // CAN controller is in Sleep mode<br> + </code><code>CYGNUM_CAN_STATE_BUS_WARN, // CAN controller is active, warning level is reached<br> + </code><code>CYGNUM_CAN_STATE_ERR_PASSIVE, // CAN controller went into error passive mode<br> + </code><code>CYGNUM_CAN_STATE_BUS_OFF, // CAN controller went into bus off mode<br> + </code><code>CYGNUM_CAN_STATE_PHY_FAULT, // General failure of physical layer detected (if supported by hardware)<br> + </code><code>CYGNUM_CAN_STATE_PHY_H, // Fault on CAN-H detected (Low Speed CAN)<br> + </code><code>CYGNUM_CAN_STATE_PHY_L, // Fault on CAN-L detected (Low Speed CAN)<br> + </code><code>} cyg_can_state;</code></p> + <p><code>CYG_IO_GET_CONFIG_CAN_STATE</code> - This function retrieves the present state of the CAN controller. Possible values are defined in the <code>cyg_can_state</code> enumeration.</p> + <h4>Drain output buffers</h4> + <p><code>CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN</code> - 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.</p> + <h4>Flush output buffers</h4> + <p><code>CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH</code> - This function discards any buffered output for the device.</p> + <h4>Flush input buffers</h4> + <p><code>CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH</code> - This function discards any buffered input for the device.</p> + <h4>Configuring blocking/nonblocking calls</h4> + + + + + By default all calls to <code>cyg_io_read()</code> and<code> cyg_io_write()</code> are blocking calls. The config keys<br> + <br> + <code>CYG_IO_GET_CONFIG_READ_BLOCKING<br> + CYG_IO_GET_CONFIG_WRITE_BLOCKING<br> + <br> + </code>and<br> + <br> + <code>CYG_IO_GET_CONFIG_READ_BLOCKING<br> + CYG_IO_GET_CONFIG_WRITE_BLOCKING<br> + <br> + </code>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 nonblocking calls are enabled and there is no space in TX buffer or RX buffer is empty then the function returns immediatelly with <code>-EAGAIN</code>. 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 <code>-EINTR</code>. If the read/write operation succeeds during the timed wait then the functions return succesfully with<code> ENOERR</code>. + + <h4>Message buffer configuration</h4> + <p><code>typedef struct cyg_can_msgbox_cfg_st<br> + </code><code>{<br> + </code><code>cyg_can_msgbuf_cfg_id cfg_id; // configuration id - cfg. what to do with message buffer<br> + </code><code>cyg_can_msgbuf_handle handle; // handle to message buffer<br> + </code><code>cyg_can_message msg; // CAN message - for configuration of buffer<br> + </code><code>} cyg_can_msgbuf_cfg;</code></p> + <p>Full CAN controllers often support more the one message buffer. These message buffers are often configurable for transmission or reception of certain CAN messages or as a remote buffer. 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 <code>cyg_io_set_config() </code>with the config key:</p> + <p><code>CYG_IO_SET_CONFIG_CAN_MSGBUF<br> + </code></p> + <p>and exchanging <code>cyg_can_msgbuf_cfg </code>data structures. The <i>cfg_id</i> field contains the configuration ID that tells the driver what to do with a message buffer, the <i>handle</i> field contains a reference to a certain message buffer and the <i>msg</i> field is necessary for configuration of message buffer parameters. The following configuration identifiers are supported:</p> + <p><code>CYGNUM_CAN_MSGBUF_RESET_ALL // clears all message buffers, no message will be received, all remote buffers deleted<br> + </code><code>CYGNUM_CAN_MSGBUF_RX_FILTER_ALL // cfg driver for reception of all can messges<br> + </code><code>CYGNUM_CAN_MSGBUF_RX_FILTER_ADD // add single message filter<br> + </code><code>CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD // add new remote response buffer<br> + </code><code>CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE // stores data into existing remote buffer (remote buf handle required)</code></p> + <p>Example code for resetting all message buffers:</p> + <p><code>cyg_can_msgbuf_cfg msgbox_cfg;</code></p> + <p><code>msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;<br> + </code><code>len = sizeof(msgbox_cfg);<br> + </code><code>if (ENOERR != cyg_io_set_config(hDrvFlexCAN, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&msgbox_cfg, &len))<br> + </code><code>{<br> + </code><code>// handle configuration error<br> + </code><code>} </code></p> + <h4>Remote frame response buffer configuration</h4> + <p>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.</p> + <p>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 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.</p> + <p>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.</p> + <p>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 <code>cyg_can_remote_buf </code>data structures with the driver via the <code>cyg_io_set_config()</code> function using the config key <code>CYG_IO_SET_CONFIG_CAN_MSGBUF</code>. Once the buffer is initialized, the CAN data can be changed at any time by the application.</p> + <p><code>typedef struct cyg_can_msgbuf_cfg_st<br> + </code><code>{<br> cyg_can_msgbuf_cfg_id cfg_id; // configuration id - cfg. what to do with message buffer<br> + </code><code>cyg_can_msgbuf_handle handle; // handle to message buffer<br> + </code><code>cyg_can_message msg; // CAN message - for configuration of buffer<br> + } cyg_can_remote_buf;<br> + </code></p> + <p>The CAN frame that should be transmitted in response to a remote frame is stored in the<i> msg</i> field of the <code>cyg_can_remote_buf </code>data structure. If there is no buffer initialized for this data, the value of the <i>handle</i> field need to be set to <code>CYGNUM_CAN_MSGBUF_INIT</code>. After the call to <code>cyg_io_set_config()</code> the <i>handle</i> field contains a valid value ( >= 0) or the value <code>CYGNUM_CAN_MSGBUF_NA</code> ( < 0) if no free buffer is available. With the valid handle value the CAN data can be changed later by calling <code>cyg_io_set_config(). </code>Before adding remote buffers the device should be stopped and after configuration it should be set into operational mode again</p> + <p>Example code for setting up a remote response buffer:</p> + <p><code>cyg_can_remote_buf rtr_buf;<br> + <br> + // prepare the remote response buffer<br>rtr_buf.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD;<br> + </code><code>rtr_buf.handle = CYGNUM_CAN_MSGBUF_INIT;<br> + </code><code>rtr_buf.msg.id = 0x7FF;<br> + </code><code>rtr_buf.msg.ext = CYGNUM_CAN_ID_STD;<br> + </code><code>rtr_buf.msg.rtr = CYGNUM_CAN_FRAME_DATA;<br> + </code><code>rtr_buf.msg.dlc = 1;<br> + </code><code>rtr_buf.msg.data[0] = 0xAB;<br> + <br> + + len = sizeof(rtr_buf);<br> + </code><code>if (ENOERR != cyg_io_set_config(hDrvFlexCAN, <br> + CYG_IO_SET_CONFIG_CAN_MSGBUF,<br> + + + &rtr_buf, &len))<br> + </code><code>{<br> + + + // handle configuration error<br> + </code><code>} <br> + </code><code><br> + </code><code>if (rtr_buf.handle == CYGNUM_CAN_MSGBUF_NA)<br> + </code><code>{<br> + + + // no free message buffer available - handle this problem here<br> + </code><code>}<br> + <br> + <br> + + // change CAN data for a buffer that is already initialized<br> + </code><code>rtr_buf.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE;<br> + + + rtr_buf.msg.data[0] = 0x11;<br> + <br> + + + len = sizeof(rtr_buf);<br> + </code><code>if (ENOERR != cyg_io_set_config(hDrvFlexCAN, <br> + + CYG_IO_SET_CONFIG_CAN_MSGBUF,<br> + + + + &rtr_buf, &len))<br> + </code><code>{<br> + + + + // handle configuration error<br> + </code><code>} <br> + </code></p> + <h4>Message filter configuration</h4> + <p> 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.</p> + <p>Adding message filters is only possible if driver is not configured for reception of all available CAN messages. If driver is configured for recption of all CAN messages then message buffers neet to be reset before adding single message filters.</p> + <p>In order to add a message filter, a message buffer need to be initialized. This is achieved by by exchanging <code>cyg_can_filter </code>data structures with the driver via the <code>cyg_io_set_config()</code> function using the config key <code>CYG_IO_SET_CONFIG_CAN_MSGBUF</code>. Once the buffer is initialized, the CAN hardware can recive messages with the identifier of the filter.</p> + <p><code>typedef struct cyg_can_msgbox_cfg_st<br> + </code><code>{<br> + cyg_can_msgbuf_cfg_id cfg_id;<br> + </code><code>cyg_can_msgbuf_handle handle;<br> + + </code><code>cyg_can_message msg;<br> + </code><code>} cyg_can_filter;</code></p> + <p>After the call to <code>cyg_io_set_config()</code> the <i>handle</i> field contains a valid value ( >= 0) or the value <code>CYGNUM_CAN_MSGBUF_NA</code> ( < 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</p> + <p>Example code for setting up a message filter:</p> + <p><code>cyg_can_msgbuf_cfg msgbox_cfg;<br> + cyg_can_filter rx_filter;<br> + <br> + // reset all message buffers</code><br> + <code>msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL;<br> + </code><code>len = sizeof(msgbox_cfg);<br> + </code><code>if (ENOERR != cyg_io_set_config(hDrvFlexCAN, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&msgbox_cfg, &len))<br> + </code><code>{<br> + </code><code>// handle configuration error<br> + </code><code>} <br> + <br> + </code><code>// prepare the message filter<br> + rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD<br> + </code><code>rx_filter.msg.id = 0x800;<br> + rx_filter.msg.ext = CYGNUM_CAN_ID_EXT;<br> + <br> + len = sizeof(rx_filter);<br> + if (ENOERR != cyg_io_set_config(hDrvFlexCAN,<br> + CYG_IO_SET_CONFIG_CAN_MSGBUF,<br> + &rx_filter, &len))<br> + </code><code>{<br> + </code><code>// handle configuration error;<br> + </code><code>}<br> + </code><code>else if (CYGNUM_CAN_MSGBUF_NA == rx_filter.handle)<br> + </code><code>{<br> + // no free message buffer available - handle this problem here<br> + }</code></p> + <h4>Receive all CAN messages</h4>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: <p><code>CYGNUM_CAN_MSGBUF_RX_FILTER_ALL</code> </p> + <p>A call to this function will clear all message filters and remote buffers and prepares the CAN hardware for recption of any kind of CAN standard and extended frames. It is not neccesary to reset the message buffer configuration before this configuration is setup because this should be done by device driver.</p> + <p>Example code for setup of a receive all CAN frames configuration:</p> + <p><code>cyg_can_filter rx_filter;<br> + <br> + // now setup a RX all configuration<br> + </code><code>rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ALL;<br> + </code><code>len = sizeof(rx_filter);<br> + </code><code>if (ENOERR != cyg_io_set_config(hDrvFlexCAN, CYG_IO_SET_CONFIG_CAN_MSGBUF , &rx_filter, &len))<br> + </code><code>{<br> + </code><code>CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0");<br> + </code><code>}</code></p> + <h4>Set mode of CAN hardware</h4> + <p><code>typedef enum <br> + </code><code>{<br> + CYGNUM_CAN_MODE_STOP, // set controller into stop mode<br> + </code><code>CYGNUM_CAN_MODE_START, // set controller into operational mode<br> + </code><code>CYGNUM_CAN_MODE_STANDBY // set controller into standby / sleep mode<br> + } cyg_can_mode;</code></p> + <p><code>CYG_IO_SET_CONFIG_CAN_MODE</code> - This function changes the operating mode of the CAN controller. Possible values for mode are defined in the <code>cyg_can_mode</code> 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 <code>CYGNUM_CAN_EVENT_LEAVING_STANDBY</code> event will be inserted into receive message buffer or the <code>CYGNUM_CAN_EVENT_LEAVING_STANDBY </code>flag will be set for the message that caused wake up of CAN hardware.</p> + <h2>FlexCAN device driver</h2> + <p>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.</p> + <p>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.</p> + <p>The message buffer 16 of the FlexCAN modul is reserved for transmission of CAN messages. Message buffers 1 - 15 are available for configuration of remote buffers and message filters. If the FlexCAN modul is configured for reception of all CAN frames, then the user can select the number of buffers used for reception of CAN frames. The interrupt priority of each message box is configurable.</p> + </body> + +</html> diff --git a/ecos/packages/io/can/current/include/can.h b/ecos/packages/io/can/current/include/can.h new file mode 100644 index 0000000..7b8e2fa --- /dev/null +++ b/ecos/packages/io/can/current/include/can.h @@ -0,0 +1,240 @@ +#ifndef CYGONCE_CAN_H +#define CYGONCE_CAN_H +// ==================================================================== +// +// can.h +// +// Device I/O +// +// ==================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +// ==================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: gthomas +// Date: 2005-12-05 +// Purpose: Internal interfaces for CAN I/O drivers +// Description: +// +//####DESCRIPTIONEND#### +// +// ==================================================================== + + +//========================================================================== +// INCLUDES +//========================================================================== +#include <pkgconf/system.h> +#include <pkgconf/io_can.h> + +#include <cyg/infra/cyg_type.h> +#include <cyg/io/io.h> +#include <cyg/io/canio.h> +#include <cyg/io/devtab.h> +#include <cyg/hal/drv_api.h> + + +// define standard and extended id masks +#define CYG_CAN_STD_ID_MASK 0x7FF +#define CYG_CAN_EXT_ID_MASK 0x1FFFFFFF + +// +// include device header +// a device can define its own types of CAN messages and CAN events. It does this +// in the device header CYGDAT_IO_CAN_DEVICE_INL. Because this header is included +// here, the device header file can use all definitions in the files included +// in the include section above +// +#ifdef CYGDAT_IO_CAN_DEVICE_INL +#include CYGDAT_IO_CAN_DEVICE_INL // include device header +#endif + +// +// If the device did not define its own type of CAN message and CAN event, then +// we define standard types here and use the types cyg_can_message and cyg_can_event +// from CAN I/O layer +// +#ifndef CYG_CAN_MSG_T +#define CYG_CAN_MSG_T cyg_can_message +#define CYG_CAN_EVENT_T cyg_can_event +#define CYG_CAN_WRITE_MSG(_devmsg_ptr_, _iomsg_ptr_) (*(_devmsg_ptr_) = *(_iomsg_ptr_)) +#define CYG_CAN_READ_EVENT(_ioevent_ptr_, _devevent_ptr_) (*(_ioevent_ptr_) = *(_devevent_ptr_)) +#endif + + +//=========================================================================== +// FORWARD DECLARATIONS +//=========================================================================== +typedef struct can_channel can_channel; +typedef struct can_lowlevel_funs can_lowlevel_funs; + + +//=========================================================================== +// DATA TYPES +//=========================================================================== + +//--------------------------------------------------------------------------- +// Pointers into uper-level driver which ISRs and DSRs need +// +typedef struct +{ + void (*can_init)(can_channel *chan); // Initialize the CAN channel + cyg_bool (*xmt_msg)(can_channel *chan, void *pdata); // transmit one single message + cyg_bool (*rcv_event)(can_channel *chan, void *pdata); // indicate CAN event occurance +} can_callbacks_t; + + +#define CAN_CALLBACKS(_l,_init,_xmt_msg,_rcv_event) \ +can_callbacks_t _l = { \ + _init, \ + _xmt_msg, \ + _rcv_event \ +}; + +extern can_callbacks_t cyg_io_can_callbacks; + + +//--------------------------------------------------------------------------- +// Data buffer for receive and transmit FIFOs +// +typedef struct can_cbuf_st +{ + void *pdata; // points to data buffer + volatile int put; + volatile int get; + int len; + volatile int data_cnt; // count of events or messages currently in buffer + cyg_drv_cond_t wait; + cyg_drv_mutex_t lock; + bool waiting; +#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) + bool blocking; // true - timeouts will bes used, false - call blocks until data arrives +#endif + volatile bool abort; // Set by an outsider to kill processing + volatile cyg_int32 pending; // This many bytes waiting to be sent +#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + cyg_uint32 timeout; // timeout value for reading data from buffer +#endif +} can_cbuf_t; + + +#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS +#define _TX_TIMEOUT CYGNUM_IO_CAN_DEFAULT_TIMEOUT_WRITE +#define _RX_TIMEOUT CYGNUM_IO_CAN_DEFAULT_TIMEOUT_READ +#define CBUF_INIT(_data, _len, _timeout) \ + {_data, 0, 0, _len, timeout : _timeout} +#else +#define _TX_TIMEOUT 0 +#define _RX_TIMEOUT 0 +#define CBUF_INIT(_data, _len, _timeout) \ + {_data, 0, 0, _len, } +#endif // #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS + + +//--------------------------------------------------------------------------- +// Private data which describes this channel + initialisation macro +// +struct can_channel +{ + can_lowlevel_funs *funs; + can_callbacks_t *callbacks; + void *dev_priv; // Whatever is needed by actual device routines + cyg_can_info_t config; // Current configuration + bool init; // true if driver is already initialized + can_cbuf_t out_cbuf; // buffer for transmit can messages + can_cbuf_t in_cbuf; // buffer with received can events +#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK + cyg_can_callback_cfg callback_cfg; // Callback configuration +#endif +}; + +#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK +#define CYG_CAN_CALLBACK_INIT , {(cyg_can_event_cb_t) 0, 0, 0} +#else +#define CYG_CAN_CALLBACK_INIT +#endif + + +#define CAN_CHANNEL_USING_INTERRUPTS(_l, \ + _funs, \ + _dev_priv, \ + _baud, \ + _out_buf, _out_buflen, \ + _in_buf, _in_buflen) \ +can_channel _l = { \ + &_funs, \ + &cyg_io_can_callbacks, \ + &(_dev_priv), \ + CYG_CAN_INFO_INIT(_baud), \ + false, \ + CBUF_INIT(_out_buf, _out_buflen, _TX_TIMEOUT), \ + CBUF_INIT(_in_buf, _in_buflen, _RX_TIMEOUT) \ + CYG_CAN_CALLBACK_INIT \ +}; + + + +//--------------------------------------------------------------------------- +// Low level interface functions - these functions are required by the generic +// CAN driver in order to access the low level hardware +// +struct can_lowlevel_funs +{ + bool (*putmsg)(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata); // send one can message - return true if consumed + bool (*getevent)(can_channel *priv, CYG_CAN_EVENT_T *pevent, void *pdata); // fetch one CAN event from device + 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); + void (*start_xmit)(can_channel *priv); // Enable the transmit channel and turn on transmit interrupts + void (*stop_xmit)(can_channel *priv); // Disable the transmit channel and turn transmit interrupts off +}; + +#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; +//------------------------------------------------------------------------- +#endif // CYGONCE_CAN_H diff --git a/ecos/packages/io/can/current/include/canio.h b/ecos/packages/io/can/current/include/canio.h new file mode 100644 index 0000000..5ce3516 --- /dev/null +++ b/ecos/packages/io/can/current/include/canio.h @@ -0,0 +1,489 @@ +#ifndef CYGONCE_CANIO_H +#define CYGONCE_CANIO_H +// ==================================================================== +// +// canio.h +// +// Device I/O +// +// ==================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +// ==================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: gthomas +// Date: 2005-05-12 +// Purpose: Special support for CAN I/O devices +// Description: +// +//####DESCRIPTIONEND#### +// +// ==================================================================== + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include <pkgconf/system.h> +#include <pkgconf/io_can.h> +#include <pkgconf/hal.h> +#include <cyg/infra/cyg_type.h> +#include <cyg/io/config_keys.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +//=========================================================================== +// DATA TYPES +//=========================================================================== + +// +// Supported baud rates +// +typedef enum { + CYGNUM_CAN_KBAUD_10 = 1, + 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, + CYGNUM_CAN_KBAUD_AUTO, // automatic detection of baudrate (if supported by hardware) +} cyg_can_baud_rate_t; +#define CYGNUM_CAN_KBAUD_MIN CYGNUM_CAN_KBAUD_10 +#define CYGNUM_CAN_KBAUD_MAX CYGNUM_CAN_KBAUD_1000 + + +// Note: two levels of macro are required to get proper expansion. +#define _CYG_CAN_BAUD_RATE(n) CYGNUM_CAN_KBAUD_##n +#define CYG_CAN_BAUD_RATE(n) _CYG_CAN_BAUD_RATE(n) + +// +// Event types for received events. Not all event types are supported by each CAN +// hardware but normally these events should cover the most common CAN events +// that may occur. A combination of the event type values is allowed. +// +#define CYGNUM_CAN_EVENT_RX 0x00000001 // message received +#define CYGNUM_CAN_EVENT_TX 0x00000002 // mesage transmitted +#define CYGNUM_CAN_EVENT_WARNING_RX 0x00000004 // tx error counter (TEC) reached warning level (>96) +#define CYGNUM_CAN_EVENT_WARNING_TX 0x00000008 // rx error counter (REC) reached warning level (>96) +#define CYGNUM_CAN_EVENT_ERR_PASSIVE 0x00000010 // CAN "error passive" occured +#define CYGNUM_CAN_EVENT_BUS_OFF 0x00000020 // CAN "bus off" error occured +#define CYGNUM_CAN_EVENT_OVERRUN_RX 0x00000040 // overrun in RX queue occured +#define CYGNUM_CAN_EVENT_OVERRUN_TX 0x00000080 // overrun in TX queue occured +#define CYGNUM_CAN_EVENT_CAN_ERR 0x00000100 // a CAN bit or frame error occured +#define CYGNUM_CAN_EVENT_LEAVING_STANDBY 0x00000200 // CAN hardware leaves standby/power down mode or is waked up +#define CYGNUM_CAN_EVENT_ENTERING_STANDBY 0x00000400 // CAN hardware enters standby/power down mode +#define CYGNUM_CAN_EVENT_ARBITRATION_LOST 0x00000800 // arbitration lost +#define CYGNUM_CAN_EVENT_FILTER_ERR 0x00001000 // CAN message filter / acceptance filter error +#define CYGNUM_CAN_EVENT_PHY_FAULT 0x00002000 // General failure of physical layer detected (if supported by hardware) +#define CYGNUM_CAN_EVENT_PHY_H 0x00004000 // Fault on CAN-H detected (Low Speed CAN) +#define CYGNUM_CAN_EVENT_PHY_L 0x00008000 // Fault on CAN-L detected (Low Speed CAN) +#define CYGNUM_CAN_EVENT_ERR_ACTIVE 0x00010000 // CAN controller now "error active" +#define CYGNUM_CAN_EVENT_OVERRUN_RX_HW 0x00020000 // CAN controller reports a RX overrun + +typedef cyg_int32 cyg_can_event_flags_t; + +#define CYGNUM_CAN_EVENT_ALL \ + CYGNUM_CAN_EVENT_RX \ + |CYGNUM_CAN_EVENT_TX \ + |CYGNUM_CAN_EVENT_WARNING_RX \ + |CYGNUM_CAN_EVENT_WARNING_TX \ + |CYGNUM_CAN_EVENT_ERR_PASSIVE \ + |CYGNUM_CAN_EVENT_BUS_OFF \ + |CYGNUM_CAN_EVENT_OVERRUN_RX \ + |CYGNUM_CAN_EVENT_OVERRUN_TX \ + |CYGNUM_CAN_EVENT_CAN_ERR \ + |CYGNUM_CAN_EVENT_LEAVING_STANDBY \ + |CYGNUM_CAN_EVENT_ENTERING_STANDBY \ + |CYGNUM_CAN_EVENT_ARBITRATION_LOST \ + |CYGNUM_CAN_EVENT_FILTER_ERR \ + |CYGNUM_CAN_EVENT_PHY_FAULT \ + |CYGNUM_CAN_EVENT_PHY_H \ + |CYGNUM_CAN_EVENT_PHY_L \ + |CYGNUM_CAN_EVENT_ERR_ACTIVE \ + |CYGNUM_CAN_EVENT_OVERRUN_RX_HW + +// +// State of CAN controller +// +typedef enum e_cyg_can_state +{ + 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) + CYGNUM_CAN_STATE_CONFIG, // CAN controller is in configuration state +} cyg_can_state; + +// +// Identifiers for operating mode of the CAN controller. +// +typedef enum e_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, // 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; + +// +// Type of CAN identifier. +// +typedef enum e_cyg_can_id_type +{ + CYGNUM_CAN_ID_STD = 0x00, // standard ID 11 Bit + CYGNUM_CAN_ID_EXT = 0x01 // extended ID 29 Bit +} cyg_can_id_type; + +// +// Type of CAN frame +// +typedef enum e_cyg_can_frame_type +{ + CYGNUM_CAN_FRAME_DATA = 0x00, // CAN data frame + CYGNUM_CAN_FRAME_RTR = 0x01 // CAN remote transmission request +} cyg_can_frame_type; + +// +// Message buffer configuration identifier - we do not use an enum here so that +// a specific device driver can add its own configuration identifier +// +typedef cyg_uint8 cyg_can_msgbuf_cfg_id; +#define CYGNUM_CAN_MSGBUF_RESET_ALL 0 // no message will be received, all remote buffers deleted +#define CYGNUM_CAN_MSGBUF_RX_FILTER_ALL 1 // cfg driver for reception of all can messges +#define CYGNUM_CAN_MSGBUF_RX_FILTER_ADD 2 // add single message filter +#define CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD 3 // add new remote response buffer +#define CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE 4 // store data into existing remote buffer (remote buf handle required) + + +// +// CAN message data - this union is a container for the 8 data bytes of a can +// message and the union is alway part of a can message - no matter if this type +// is defined by generic CAN layer or by CAN hardware device driver +// +typedef union u_cyg_can_msg_data +{ + cyg_uint8 bytes[8]; // byte access (array of 8 bytes) + cyg_uint16 words[4]; // word access (array of 4 words) + cyg_uint32 dwords[2]; // double word access (array of 2 dwords) +} cyg_can_msg_data; + +// +// CAN message type for transport or transmit of CAN messages +// The message data is a union. This enables byte, word and dword access and +// also ensures a 4 byte alignment of the message data +// +typedef struct st_cyg_can_message +{ + cyg_uint32 id; // 11 Bit or 29 Bit CAN identifier - cyg_can_id_type + cyg_can_msg_data data; // CAN data (8 data bytes) + cyg_can_id_type ext; // CYGNUM_CAN_ID_STD = 11 Bit CAN id, CYGNUM_CAN_ID_EXT = 29 Bit CAN id + cyg_can_frame_type rtr; // CYGNUM_CAN_FRAME_DATA = data frame, CYGNUM_CAN_FRAME_RTR = remote transmission request + cyg_uint8 dlc; // data length code (number of bytes (0 - 8) containing valid data +} cyg_can_message; + +// +// CAN event type for reception of CAN events from driver. CAN events may be +// a received CAN message or any other status information like tx msg or +// arbitration lost +// +typedef struct cyg_can_event_st +{ + cyg_uint32 timestamp; + cyg_can_event_flags_t flags; + cyg_can_message msg; +} cyg_can_event; + +// +// CAN configuration - at the moment there is only one data member but we are +// prepared for future enhancements +// +typedef struct cyg_can_info_st { + 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_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_uint16 count; // number of message buffers available for this device + cyg_uint16 free; // number of free message buffers +} cyg_can_msgbuf_info; + + +// +// Timeout configuration +// +typedef struct cyg_can_timeout_info_st +{ + cyg_uint32 rx_timeout; + cyg_uint32 tx_timeout; +} cyg_can_timeout_info_t; + + +// +// For reading error counter values from CAN controller +// +typedef struct cyg_can_err_count_info_st +{ + cyg_uint8 rx_err_count; + cyg_uint8 tx_err_count; +} cyg_can_err_count_info; + + +// +// this data type defines a handle to a message buffer or message box +// of the CAN hardware device +// +typedef cyg_int32 cyg_can_msgbuf_handle; + + +// +// structure for configuration of message buffers +// +typedef struct cyg_can_msgbox_cfg_st +{ + cyg_can_msgbuf_cfg_id cfg_id; // configuration id - cfg. what to do with message buffer + cyg_can_msgbuf_handle handle; // handle to message buffer + cyg_can_message msg; // CAN message - for configuration of buffer +} cyg_can_msgbuf_cfg; + +// +// structure for configuration of identifier range filtering +// +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; + +// +// structure for configuration of identifier/mask filtering +// +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; + +// +// 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, cyg_can_filter and +// cyg_can_msgbuf_cfg data structure +// +#define CYGNUM_CAN_MSGBUF_NA -0x01 // no free message buffer available + + +// +// 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 | +// +-------+-------+-------+-------+--------+-------+-------+--------+ +// |ListenO|Mask F |Range F|timest.|autobaud|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 +#define CYGNUM_CAN_HDI_FULLCAN 0x04 // controller supports more than one receive and transmit buffer +#define CYGNUM_CAN_HDI_AUTBAUD 0x08 // driver supports automatic baudrate detection +#define CYGNUM_CAN_HDI_TIMESTAMP 0x10 // driver supports timestamps +#define CYGNUM_CAN_HDI_RANGE_FILTERING 0x20 // driver supports identifier range filtering +#define CYGNUM_CAN_HDI_MASK_FILTERING 0x40 // driver supports identifier mask filtering +#define CYGNUM_CAN_HDI_LISTEN_ONLY 0x80 // driver supports 'listen-only' mode. + +// +// Callback configuration structure. +// + +typedef void (*cyg_can_event_cb_t)(cyg_uint16, CYG_ADDRWORD); +// +// 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. +// +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; + + +//=========================================================================== +// CAN MESSAGE ACCESS MACROS +// +// An application should not access a cyg_can_message directly instead it +// should use these macros for all manipulations to a CAN message. +//=========================================================================== + +//--------------------------------------------------------------------------- +// Frame type macros +// +#define CYG_CAN_MSG_SET_FRAME_TYPE(_msg_, _type_) ((_msg_).rtr = (_type_)) +#define CYG_CAN_MSG_GET_FRAME_TYPE(_msg_) ((_msg_).rtr) +#define CYG_CAN_MSG_SET_RTR(_msg_) ((_msg_).rtr = CYGNUM_CAN_FRAME_RTR) +#define CYG_CAN_MSG_IS_REMOTE(_msg_) ((_msg_).rtr == CYGNUM_CAN_FRAME_RTR) + + +//--------------------------------------------------------------------------- +// ID type macros +// +#define CYG_CAN_MSG_SET_ID_TYPE(_msg_, _type_) ((_msg_).ext = (_type_)) +#define CYG_CAN_MSG_GET_ID_TYPE(_msg_) ((_msg_).ext) +#define CYG_CAN_MSG_SET_EXT(_msg_) ((_msg_).ext = CYGNUM_CAN_ID_EXT) +#define CYG_CAN_MSG_SET_STD(_msg_) ((_msg_).ext = CYGNUM_CAN_ID_STD) +#define CYG_CAN_MSG_IS_EXT(_msg_) ((_msg_).ext == CYGNUM_CAN_ID_EXT) + + +//--------------------------------------------------------------------------- +// Identifier access macros +// +#define CYG_CAN_MSG_GET_ID(_msg_) ((_msg_).id) +#define CYG_CAN_MSG_SET_ID(_msg_, _id_) ((_msg_).id = (_id_)) +#define CYG_CAN_MSG_SET_STD_ID(_msg_, _id_) \ +CYG_MACRO_START \ + CYG_CAN_MSG_SET_ID(_msg_, _id_); \ + CYG_CAN_MSG_SET_STD(_msg_); \ +CYG_MACRO_END + +#define CYG_CAN_MSG_SET_EXT_ID(_msg_, _id_) \ +CYG_MACRO_START \ + CYG_CAN_MSG_SET_ID(_msg_, _id_); \ + CYG_CAN_MSG_SET_EXT(_msg_); \ +CYG_MACRO_END + + +//--------------------------------------------------------------------------- +// DLC (data length code) access macros +// +#define CYG_CAN_MSG_GET_DATA_LEN(_msg_) ((_msg_).dlc) +#define CYG_CAN_MSG_SET_DATA_LEN(_msg_, _len_) ((_msg_).dlc = (_len_)) + + +//--------------------------------------------------------------------------- +// CAN message data access +// This macro returns a pointer to a cyg_can_msg_data union +// +#define CYG_CAN_MSG_DATA_PTR(_msg_) (&(_msg_).data) +#define CYG_CAN_MSG_GET_DATA(_msg_, _pos_) ((_msg_).data.bytes[_pos_]) +#define CYG_CAN_MSG_SET_DATA(_msg_, _pos_, _val_) ((_msg_).data.bytes[_pos_] = (_val_)) + + +//--------------------------------------------------------------------------- +// Access multiple parameters +// +#define CYG_CAN_MSG_SET_PARAM(_msg_, _id_, _ext_, _dlc_, _rtr_) \ +CYG_MACRO_START \ + CYG_CAN_MSG_SET_ID(_msg_, _id_); \ + CYG_CAN_MSG_SET_ID_TYPE(_msg_, _ext_); \ + CYG_CAN_MSG_SET_DATA_LEN(_msg_, _dlc_); \ + CYG_CAN_MSG_SET_FRAME_TYPE(_msg_, _rtr_); \ +CYG_MACRO_END + +#define CYG_CAN_MSG_INIT(_clabel_, _id_, _ext_, _dlc_, _rtr_) \ +cyg_can_message _clabel_ = \ +{ \ + id : _id_, \ + ext : _ext_, \ + rtr : _rtr_, \ + dlc : _dlc_, \ +} + + + +#ifdef __cplusplus +} +#endif + +//--------------------------------------------------------------------------- +#endif // CYGONCE_CANIO_H diff --git a/ecos/packages/io/can/current/src/can.c b/ecos/packages/io/can/current/src/can.c new file mode 100644 index 0000000..f0d0117 --- /dev/null +++ b/ecos/packages/io/can/current/src/can.c @@ -0,0 +1,834 @@ +//========================================================================== +// +// io/can/common/can.c +// +// High level CAN driver +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2005-05-12 +// Purpose: Top level CAN driver +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +//========================================================================== +// INCLUDES +//========================================================================== +#include <pkgconf/io.h> +#include <pkgconf/io_can.h> + +#include <cyg/io/io.h> +#include <cyg/io/devtab.h> +#include <cyg/io/can.h> +#include <cyg/infra/cyg_ass.h> // assertion support +#include <cyg/infra/diag.h> // diagnostic output + + +//========================================================================== +// MACROS +//========================================================================== +#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS +#define CYG_DRV_COND_WAIT(_cond, _time) cyg_cond_timed_wait(_cond, cyg_current_time() + (_time)) +#else +#define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond) +#endif + + +//========================================================================== +// LOCAL FUNCTIONS +//========================================================================== +// +// Device I/O functions +// +static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len); +static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len); +static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info); +static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len); +static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len); + +// +// Callback functions into upper layer driver +// +static void can_init(can_channel *chan); +static cyg_bool can_rcv_event(can_channel *chan, void *pdata); +static cyg_bool can_xmt_msg(can_channel *chan, void *pdata); + +// +// Device I/O table +// +DEVIO_TABLE(cyg_io_can_devio, + can_write, + can_read, + can_select, + can_get_config, + can_set_config + ); + + +// +// Callbacks into upper layer driver +// +CAN_CALLBACKS(cyg_io_can_callbacks, + can_init, + can_xmt_msg, + can_rcv_event); + + +//=========================================================================== +// Initialize CAN driver +//=========================================================================== +static void can_init(can_channel *chan) +{ + can_cbuf_t *cbuf; + + if (chan->init) + { + return; + } + + cbuf = &chan->in_cbuf; + cbuf->waiting = false; + cbuf->abort = false; +#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + cbuf->blocking = true; +#endif + cyg_drv_mutex_init(&cbuf->lock); + cyg_drv_cond_init(&cbuf->wait, &cbuf->lock); + + cbuf = &chan->out_cbuf; + cbuf->waiting = false; + cbuf->abort = false; +#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + cbuf->blocking = true; +#endif + cyg_drv_mutex_init(&cbuf->lock); + cyg_drv_cond_init(&cbuf->wait, &cbuf->lock); + + chan->init = true; +} + + +//=========================================================================== +// Write exactly one CAN message to CAN bus +//=========================================================================== +static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len) +{ + cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; + can_channel *chan = (can_channel *)t->priv; + can_lowlevel_funs *funs = chan->funs; + Cyg_ErrNo res = ENOERR; + can_cbuf_t *cbuf = &chan->out_cbuf; + cyg_uint32 size = *len; + + // + // the user need to provide a can message buffer + // + if (*len != sizeof(cyg_can_message)) + { + return -EINVAL; + } + + cyg_drv_mutex_lock(&cbuf->lock); + cbuf->abort = false; + cyg_drv_dsr_lock(); // avoid race condition while testing pointers + + while (size > 0) + { + if (cbuf->data_cnt == cbuf->len) + { + cbuf->waiting = true; // Buffer full - wait for space + funs->start_xmit(chan); // Make sure xmit is running + // + // Check flag: 'start_xmit' may have obviated the need + // to wait + // + if (cbuf->waiting) + { + cbuf->pending += size; // Have this much more to send [eventually] +#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) +#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + // + // If timeouts are enabled and we use nonblocking calls then we + // can use the timeout values + // + if (!cbuf->blocking) + { + if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout)) + { + cbuf->abort = true; + } + } // if (!cbuf->blocking)# + else +#else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + // + // if this is a nonblocking call then we return immediatelly + // + if (!cbuf->blocking) + { + *len = 0; + res = -EAGAIN; + break; + } + else +#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) +#endif //defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) + { + if(!cyg_drv_cond_wait(&cbuf->wait)) + { + cbuf->abort = true; + } + } + cbuf->pending -= size; + if (cbuf->abort) + { + // Give up! + *len -= size; // number of characters actually sent + cbuf->abort = false; + cbuf->waiting = false; + res = -EINTR; + break; + } // if (cbuf->abort) + } // if (cbuf->waiting) + } // if (cbuf->data_cnt == cbuf->len) + else + { + // + // there is enougth space left so we can store additional data + // + CYG_CAN_MSG_T *ptxbuf = (CYG_CAN_MSG_T *)cbuf->pdata; + CYG_CAN_MSG_T *pbuf_message = &ptxbuf[cbuf->put]; + cyg_can_message *pmessage = (cyg_can_message *)_buf; + + CYG_CAN_WRITE_MSG(pbuf_message, pmessage); // copy message + + cbuf->put = (cbuf->put + 1) % cbuf->len; + cbuf->data_cnt++; + size -= sizeof(cyg_can_message); + } + } // while (size > 0) + + (funs->start_xmit)(chan); // Start output as necessary + cyg_drv_dsr_unlock(); + cyg_drv_mutex_unlock(&cbuf->lock); + return res; +} + + +//=========================================================================== +// Read one single CAN event from hw +//=========================================================================== +static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len) +{ + cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; + can_channel *chan = (can_channel *)t->priv; + can_cbuf_t *cbuf = &chan->in_cbuf; + cyg_uint32 size = 0; + Cyg_ErrNo res = ENOERR; + + // + // the user need to provide a can event buffer + // + if (*len != sizeof(cyg_can_event)) + { + return -EINVAL; + } + + cyg_drv_mutex_lock(&cbuf->lock); + cbuf->abort = false; + + cyg_drv_dsr_lock(); // avoid race conditions + while (size < *len) + { + // + // if message buffer contains at least one message then read the + // oldest message from buffer and return + // + if (cbuf->data_cnt > 0) + { + CYG_CAN_EVENT_T *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata; + CYG_CAN_EVENT_T *pbuf_event = &prxbuf[cbuf->get]; + cyg_can_event *pevent = (cyg_can_event *)_buf; + + CYG_CAN_READ_EVENT(pevent, pbuf_event); // copy event + + cbuf->get = (cbuf->get + 1) % cbuf->len; + cbuf->data_cnt--; + size += sizeof(cyg_can_event); + } + else + { + // + // if messaeg buffer does not contain any message, then wait until + // a message arrives or return immediatelly if nonblocking calls are + // supported + // + cbuf->waiting = true; +#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) +#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + // + // If timeouts are enabled and we use nonblocking calls then we + // can use the timeout values + // + if (!cbuf->blocking) + { + if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout)) + { + cbuf->abort = true; + } + } // if (!cbuf->blocking)# + else +#else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + // + // if this is a nonblocking call then we return immediatelly + // + if (!cbuf->blocking) + { + *len = 0; + res = -EAGAIN; + break; + } + else +#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) +#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) + { + if(!cyg_drv_cond_wait(&cbuf->wait)) + { + cbuf->abort = true; + } + } + + if (cbuf->abort) + { + *len = size; + cbuf->abort = false; + cbuf->waiting = false; + res = -EINTR; + break; + } + } + } // while (size < *len) + cyg_drv_dsr_unlock(); + + cyg_drv_mutex_unlock(&cbuf->lock); + + return res; +} + + +//=========================================================================== +// Query CAN channel configuration data +//=========================================================================== +static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, + cyg_uint32 key, + void *xbuf, + cyg_uint32 *len) +{ + cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; + can_channel *chan = (can_channel *)t->priv; + Cyg_ErrNo res = ENOERR; + 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)) + { + return -EINVAL; + } + *pcan_info = chan->config; + *len = sizeof(chan->config); + break; + // + // return rx/tx buffer sizes and counts + // + case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO : + { + cyg_can_buf_info_t *pbuf_info; + if (*len < sizeof(cyg_can_buf_info_t)) + { + return -EINVAL; + } + + *len = sizeof(cyg_can_buf_info_t); + pbuf_info = (cyg_can_buf_info_t *)xbuf; + pbuf_info->rx_bufsize = in_cbuf->len; + if (pbuf_info->rx_bufsize) + { + pbuf_info->rx_count = in_cbuf->data_cnt ; + } + else + { + pbuf_info->rx_count = 0; + } + pbuf_info->tx_bufsize = out_cbuf->len; + if (pbuf_info->tx_bufsize) + { + pbuf_info->tx_count = out_cbuf->data_cnt; + } + else + { + pbuf_info->tx_count = 0; + } + } + break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO + +#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS + // + // return current timeouts + // + case CYG_IO_GET_CONFIG_CAN_TIMEOUT : + { + cyg_can_timeout_info_t *ptimeout_info; + if (*len < sizeof(cyg_can_timeout_info_t)) + { + return -EINVAL; + } + + *len = sizeof(cyg_can_timeout_info_t); + ptimeout_info = (cyg_can_timeout_info_t *)xbuf; + + ptimeout_info->rx_timeout = in_cbuf->timeout; + ptimeout_info->tx_timeout = out_cbuf->timeout; + } + break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO +#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)) + { + return -EINVAL; + } + *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0; + } + break; + + // + // check if nonblocking calls are enabled + // + case CYG_IO_GET_CONFIG_WRITE_BLOCKING: + { + if (*len < sizeof(cyg_uint32)) + { + return -EINVAL; + } + *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0; + } + 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 = (funs->get_config)(chan, key, xbuf, len); + } // switch (key) + + return res; +} + + +//=========================================================================== +// Set CAN channel configuration +//=========================================================================== +static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, + cyg_uint32 key, + const void *xbuf, + cyg_uint32 *len) +{ + cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; + can_channel *chan = (can_channel *)t->priv; + Cyg_ErrNo res = ENOERR; + can_lowlevel_funs *funs = chan->funs; + can_cbuf_t *out_cbuf = &chan->out_cbuf; + can_cbuf_t *in_cbuf = &chan->in_cbuf; + + 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) + { + return -EINVAL; + } + 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) + { + return -EINVAL; + } + out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false; + } + break; +#endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING + +#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS + // + // return current timeouts + // + case CYG_IO_SET_CONFIG_CAN_TIMEOUT : + { + cyg_can_timeout_info_t *ptimeout_info; + if (*len < sizeof(cyg_can_timeout_info_t)) + { + return -EINVAL; + } + + *len = sizeof(cyg_can_timeout_info_t); + ptimeout_info = (cyg_can_timeout_info_t *)xbuf; + + in_cbuf->timeout = ptimeout_info->rx_timeout; + out_cbuf->timeout = ptimeout_info->tx_timeout; + } + 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_SET_CONFIG_CAN_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_SET_CONFIG_CAN_OUTPUT_DRAIN: + + // + // Abort any outstanding I/O, including blocked reads + // Caution - assumed to be called from 'timeout' (i.e. DSR) code + // + case CYG_IO_SET_CONFIG_CAN_ABORT : + { + in_cbuf->abort = true; + cyg_drv_cond_broadcast(&in_cbuf->wait); + + out_cbuf->abort = true; + cyg_drv_cond_broadcast(&out_cbuf->wait); + } + break; + + +#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK + // + // Set callback configuration + // To disable callback set flag_mask = 0 + // + case CYG_IO_SET_CONFIG_CAN_CALLBACK: + { + if (*len != sizeof(cyg_can_callback_cfg)) + { + return -EINVAL; + } + + // Copy data under DSR locking + cyg_drv_dsr_lock(); + chan->callback_cfg = *((cyg_can_callback_cfg*) xbuf); + cyg_drv_dsr_unlock(); + } + break; +#endif //CYGOPT_IO_CAN_SUPPORT_CALLBACK + + default: + // + // pass down to lower layers + // + res = (funs->set_config)(chan, key, xbuf, len); + } // switch (key) + + return res; +} + + +//=========================================================================== +// Select support for CAN channel +//=========================================================================== +static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info) +{ + // + // do nothing here because we currently do not support select + // + return true; +} + + +//=========================================================================== +// Callback for received events +//=========================================================================== +static cyg_bool can_rcv_event(can_channel *chan, void *pdata) +{ + can_cbuf_t *cbuf = &chan->in_cbuf; + CYG_CAN_EVENT_T *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata; +#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK + cyg_can_event_flags_t flags; +#endif + cyg_bool res = false; + + // + // 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. 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(); + prxbuf[cbuf->put].flags = 0; // clear flags because it is a new event + if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata)) + { + res = true; + if (cbuf->data_cnt < cbuf->len) + { + cbuf->data_cnt++; + } + else + { + // + // the buffer is full but a new message arrived. We store this new + // message and overwrite the oldest one, but at least we tell the user + // that there is an overrun in RX queue + // + prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX; + cbuf->get = (cbuf->get + 1) % cbuf->len; + } + +#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK + flags = prxbuf[cbuf->put].flags; +#endif + + cbuf->put = (cbuf->put + 1) % cbuf->len; + + if (cbuf->waiting) + { + cbuf->waiting = false; + cyg_drv_cond_broadcast(&cbuf->wait); + } +#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK + // Call application callback function, if any of the flag events + // are unmasked. + if((flags & chan->callback_cfg.flag_mask) && + (chan->callback_cfg.callback_func)) + { + chan->callback_cfg.callback_func(flags, + chan->callback_cfg.data); + } +#endif + } + + cyg_drv_dsr_unlock(); + + return res; +} + + +//=========================================================================== +// Callback function for transmit events +//=========================================================================== +static cyg_bool can_xmt_msg(can_channel *chan, void *pdata) +{ + can_cbuf_t *cbuf = &chan->out_cbuf; + can_lowlevel_funs *funs = chan->funs; + CYG_CAN_MSG_T *ptxbuf = (CYG_CAN_MSG_T *)cbuf->pdata; + CYG_CAN_MSG_T *pbuf_txmsg; + cyg_bool res = false; + + // + // transmit messages as long as there are messages in the buffer + // + while (cbuf->data_cnt > 0) + { + pbuf_txmsg = &ptxbuf[cbuf->get]; + + if (funs->putmsg(chan, pbuf_txmsg, pdata)) + { + cbuf->get = (cbuf->get + 1) % cbuf->len; + cbuf->data_cnt--; + res = true; + } + else + { + // + // we are here because the hardware is busy at the moment and + // we can't send another message - now we check if there is already + // some space in buffer so we can wakeup the writer + // + if ((cbuf->len - cbuf->data_cnt) > 0) + { + if (cbuf->waiting) + { + cbuf->waiting = false; + cyg_drv_cond_broadcast(&cbuf->wait); + } + } + return res; + } + } // while (cbuf->data_cnt > 0) + funs->stop_xmit(chan); // Done with transmit + + if (cbuf->waiting) + { + cbuf->waiting = false; + cyg_drv_cond_broadcast(&cbuf->wait); + } + + return res; +} + + +//--------------------------------------------------------------------------- +// end of can.c diff --git a/ecos/packages/io/can/current/tests/can_filter.c b/ecos/packages/io/can/current/tests/can_filter.c new file mode 100644 index 0000000..cc1fddc --- /dev/null +++ b/ecos/packages/io/can/current/tests/can_filter.c @@ -0,0 +1,306 @@ +//========================================================================== +// +// can_filter.c +// +// CAN message filter test +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-03-21 +// Description: CAN hardware filter test +//####DESCRIPTIONEND#### + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include <pkgconf/system.h> + +#include <cyg/infra/testcase.h> // test macros +#include <cyg/infra/cyg_ass.h> // assertion macros +#include <cyg/infra/diag.h> + +// Package requirements +#if defined(CYGPKG_IO_CAN) && defined(CYGPKG_KERNEL) + +#include <pkgconf/kernel.h> +#include <cyg/io/io.h> +#include <cyg/io/canio.h> + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + +// Package option requirements +#if defined (CYGOPT_IO_CAN_STD_CAN_ID) + + +//=========================================================================== +// DATA TYPES +//=========================================================================== +typedef struct st_thread_data +{ + cyg_thread obj; + long stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; + cyg_handle_t hdl; +} thread_data_t; + + +//=========================================================================== +// LOCAL DATA +//=========================================================================== +cyg_thread_entry_t can0_thread; +thread_data_t can0_thread_data; + + +cyg_io_handle_t hCAN0; + + +//=========================================================================== +// LOCAL FUNCTIONS +//=========================================================================== +#include "can_test_aux.inl" // include CAN test auxiliary functions + + +//=========================================================================== +// Main thread +//=========================================================================== +void can0_thread(cyg_addrword_t data) +{ + cyg_uint32 len; + cyg_can_event rx_event; + cyg_uint16 i; + cyg_can_hdi hdi; + cyg_can_msgbuf_info msgbox_info; + cyg_can_msgbuf_cfg msgbox_cfg; + + + len = sizeof(hdi); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_HDI ,&hdi, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0"); + } + + // + // Normally the CAN modul should support message filters. So the + // FULLCAN flag should be set - if it is not, we treat this as an error + // + if (!(hdi.support_flags & CYGNUM_CAN_HDI_FULLCAN)) + { + CYG_TEST_FAIL_FINISH("/dev/can0 does not support message buffers"); + } + + + // + // Now reset message buffer configuration - this is mandatory bevore starting + // message buffer runtime configuration + // + msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL; + len = sizeof(msgbox_cfg); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&msgbox_cfg, &len)) + { + CYG_TEST_FAIL_FINISH("Error resetting message buffer configuration of /dev/can0"); + } + + // + // Now query number of available and free message boxes + // + len = sizeof(msgbox_info); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO ,&msgbox_info, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0"); + } + + // + // if there are no free message boxes available then this is a failure + // + if (!msgbox_info.free) + { + CYG_TEST_FAIL_FINISH("No free message boxes available for /dev/can0"); + } + + // + // We setup as many standard CAN message filters as there are free + // message buffers available. + // + for (i = 0; i < msgbox_info.free; ++i) + { + cyg_can_filter rx_filter; + + rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD; + rx_filter.msg.id = i; + rx_filter.msg.ext = CYGNUM_CAN_ID_STD; + + len = sizeof(rx_filter); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&rx_filter, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0"); + } + else if (CYGNUM_CAN_MSGBUF_NA == rx_filter.handle) + { + CYG_TEST_FAIL_FINISH("Error setting up message filter for /dev/can0"); + } + } + + + diag_printf("\n\nNow try to send CAN messages. The device should only\n" + "receive messages identifiers in the range of 0x00 to 0x%X.\n" + "As soon as a standard message with ID 0x000 arrives, all\n" + "message filters will be cleared\n\n", (msgbox_info.free - 1)); + + // + // Now receive messages until a message arrives with largest ID of all + // available message filters + // + rx_event.msg.id = 1; + while(rx_event.msg.id != 0) + { + len = sizeof(rx_event); + + if (ENOERR != cyg_io_read(hCAN0, &rx_event, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading from /dev/can0"); + } + else if (rx_event.flags & CYGNUM_CAN_EVENT_RX) + { + print_can_msg(&rx_event.msg, ""); + } // if (ENOERR != cyg_io_read(hCAN0, &rx_event, &len)) + else + { + print_can_flags(rx_event.flags, ""); + rx_event.msg.id = 1; + } + } // while(1) + + + // + // Now enable reception of all available CAN messages + // + cyg_can_filter rx_filter; + rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ALL; + len = sizeof(rx_filter); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF , &rx_filter, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0"); + } + + + diag_printf("\n\nAll message filters have been cleared an now the device\n" + "will receive any available CAN message identifiers.\n" + "Send a CAN message with ID 0x100 to stop this test.\n\n"); + + // + // Now receive messages until a message arrives with largest ID of all + // available message filters + // + rx_event.msg.id = 1; + while(rx_event.msg.id != 0x100) + { + len = sizeof(rx_event); + + if (ENOERR != cyg_io_read(hCAN0, &rx_event, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading from /dev/can0"); + } + else if (rx_event.flags & CYGNUM_CAN_EVENT_RX) + { + print_can_msg(&rx_event.msg, ""); + } // if (ENOERR != cyg_io_read(hCAN0, &rx_event, &len)) + } // while(1) + + CYG_TEST_PASS_FINISH("can_filter test OK"); +} + + +void +cyg_start(void) +{ + CYG_TEST_INIT(); + + // + // open CAN device driver + // + if (ENOERR != cyg_io_lookup("/dev/can0", &hCAN0)) + { + CYG_TEST_FAIL_FINISH("Error opening /dev/can0"); + } + + + // + // create the two threads which access the CAN device driver + // a reader thread with a higher priority and a writer thread + // with a lower priority + // + cyg_thread_create(4, can0_thread, + (cyg_addrword_t) 0, + "can0_thread", + (void *) can0_thread_data.stack, + 1024 * sizeof(long), + &can0_thread_data.hdl, + &can0_thread_data.obj); + + cyg_thread_resume(can0_thread_data.hdl); + + cyg_scheduler_start(); +} + +#else // CYGOPT_IO_CAN_STD_CAN_ID +#define N_A_MSG "Needs support for standard CAN identifiers" +#endif + +#else // CYGFUN_KERNEL_API_C +#define N_A_MSG "Needs kernel C API" +#endif + +#else // CYGPKG_IO_CAN && CYGPKG_KERNEL +#define N_A_MSG "Needs IO/CAN and Kernel" +#endif + +#ifdef N_A_MSG +void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA( N_A_MSG); +} +#endif // N_A_MSG + +//--------------------------------------------------------------------------- +// EOF can_filter.c diff --git a/ecos/packages/io/can/current/tests/can_hdi.c b/ecos/packages/io/can/current/tests/can_hdi.c new file mode 100644 index 0000000..6756f75 --- /dev/null +++ b/ecos/packages/io/can/current/tests/can_hdi.c @@ -0,0 +1,234 @@ +//========================================================================== +// +// can_hdi.c +// +// CAN hardware description information test +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-03-22 +// Description: CAN hardware desciption information test +//####DESCRIPTIONEND#### + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include <pkgconf/system.h> + +#include <cyg/infra/testcase.h> // test macros +#include <cyg/infra/cyg_ass.h> // assertion macros +#include <cyg/infra/diag.h> + +// Package requirements +#if defined(CYGPKG_IO_CAN) && defined(CYGPKG_KERNEL) + +#include <pkgconf/kernel.h> +#include <cyg/io/io.h> +#include <cyg/io/canio.h> + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + + +//=========================================================================== +// DATA TYPES +//=========================================================================== +typedef struct st_thread_data +{ + cyg_thread obj; + long stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; + cyg_handle_t hdl; +} thread_data_t; + + +//=========================================================================== +// LOCAL DATA +//=========================================================================== +cyg_thread_entry_t can0_thread; +thread_data_t can0_thread_data; + + +cyg_io_handle_t hCAN0; + + +//=========================================================================== +// LOCAL FUNCTIONS +//=========================================================================== +#include "can_test_aux.inl" // include CAN test auxiliary functions + + +//=========================================================================== +// Main thread +//=========================================================================== +void can0_thread(cyg_addrword_t data) +{ + cyg_uint32 len; + cyg_can_hdi hdi; + cyg_can_msgbuf_info msgbox_info; + + + // + // Query information about hardware of CAN controller + // + len = sizeof(hdi); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_HDI ,&hdi, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0"); + } + + // + // Check type of CAN controller - type of supported CAN frames + // + diag_printf("\n\nSupported message formats:\n"); + if (hdi.support_flags & CYGNUM_CAN_HDI_FRAMETYPE_STD) + { + diag_printf(" Standard CAN (2.0A): yes\n"); + diag_printf(" Extended CAN (2.0B): no\n"); + } + else if (hdi.support_flags & CYGNUM_CAN_HDI_FRAMETYPE_EXT_PASSIVE) + { + diag_printf(" Standard CAN (2.0A): yes\n"); + diag_printf(" Extended CAN (2.0B): passive\n"); + } + else if (hdi.support_flags & CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE) + { + diag_printf(" Standard CAN (2.0A): yes\n"); + diag_printf(" Extended CAN (2.0B): yes\n"); + } + + // + // Check if this is a FullCAN controller + // + diag_printf("\nController type: "); + if (hdi.support_flags & CYGNUM_CAN_HDI_FULLCAN) + { + diag_printf("FullCAN\n"); + // + // FullCAN means the controller supports a number of message buffers. + // Now query number of available and free message buffers + // + len = sizeof(msgbox_info); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO ,&msgbox_info, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0"); + } + + diag_printf(" Message buffers: %d\n", msgbox_info.count); + diag_printf(" Message buffers free: %d\n", msgbox_info.free); + } + else + { + diag_printf("BasicCAN\n"); + } + + // + // Check if automatic baudrate detection is supported + // + if (hdi.support_flags & CYGNUM_CAN_HDI_AUTBAUD) + { + diag_printf("\nAutomatic baudrate detection: supported\n"); + } + + // + // Check if driver supports timestamps + // + if (hdi.support_flags & CYGNUM_CAN_HDI_TIMESTAMP) + { + diag_printf("Timestamps: supported\n"); + } + + diag_printf("\n\n"); + CYG_TEST_PASS_FINISH("can_hdi test OK"); +} + + +void +cyg_start(void) +{ + CYG_TEST_INIT(); + + // + // open CAN device driver + // + if (ENOERR != cyg_io_lookup("/dev/can0", &hCAN0)) + { + CYG_TEST_FAIL_FINISH("Error opening /dev/can0"); + } + + + // + // create the two threads which access the CAN device driver + // a reader thread with a higher priority and a writer thread + // with a lower priority + // + cyg_thread_create(4, can0_thread, + (cyg_addrword_t) 0, + "can0_thread", + (void *) can0_thread_data.stack, + 1024 * sizeof(long), + &can0_thread_data.hdl, + &can0_thread_data.obj); + + cyg_thread_resume(can0_thread_data.hdl); + + cyg_scheduler_start(); +} + +#else // CYGFUN_KERNEL_API_C +#define N_A_MSG "Needs kernel C API" +#endif + +#else // CYGPKG_IO_CAN && CYGPKG_KERNEL +#define N_A_MSG "Needs IO/CAN and Kernel" +#endif + +#ifdef N_A_MSG +void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA( N_A_MSG); +} +#endif // N_A_MSG + +//--------------------------------------------------------------------------- +// EOF can_hdi.c diff --git a/ecos/packages/io/can/current/tests/can_load.c b/ecos/packages/io/can/current/tests/can_load.c new file mode 100644 index 0000000..15cdb28 --- /dev/null +++ b/ecos/packages/io/can/current/tests/can_load.c @@ -0,0 +1,307 @@ +//========================================================================== +// +// can_load.c +// +// CAN load test +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2005-08-14 +// Description: CAN load test +//####DESCRIPTIONEND#### + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include <pkgconf/system.h> + +#include <cyg/infra/testcase.h> // test macros +#include <cyg/infra/cyg_ass.h> // assertion macros +#include <cyg/infra/diag.h> + +// Package requirements +#if defined(CYGPKG_IO_CAN) && defined(CYGPKG_KERNEL) + +#include <pkgconf/kernel.h> +#include <cyg/io/io.h> +#include <cyg/io/canio.h> + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + +// Package option requirements +#if defined(CYGOPT_IO_CAN_STD_CAN_ID) && defined(CYGOPT_IO_CAN_EXT_CAN_ID) + + +//=========================================================================== +// DATA TYPES +//=========================================================================== +typedef struct st_thread_data +{ + cyg_thread obj; + long stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; + cyg_handle_t hdl; +} thread_data_t; + + +//=========================================================================== +// LOCAL DATA +//=========================================================================== +cyg_thread_entry_t can0_thread; +thread_data_t can0_thread_data; + +cyg_thread_entry_t can1_thread; +thread_data_t can1_thread_data; + +cyg_io_handle_t hCAN0; + + +//=========================================================================== +// LOCAL FUNCTIONS +//=========================================================================== +#include "can_test_aux.inl" // include CAN test auxiliary functions + + +//=========================================================================== +// Main thread +//=========================================================================== +void can0_thread(cyg_addrword_t data) +{ + cyg_uint32 len; + cyg_can_event rx_event; + cyg_can_timeout_info_t timeouts; + +#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + // + // setup large timeout values because we do not need timeouts here + // + timeouts.rx_timeout = 100000; + timeouts.tx_timeout = 100000; + + len = sizeof(timeouts); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_TIMEOUT ,&timeouts, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0"); + } +#endif // defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) + + // + // This thread simply receives all CAN events and prints the event flags and the + // CAN message if it was a TX or RX event. You can use this test in order to check + // when a RX overrun occurs + // + while (1) + { + len = sizeof(rx_event); + + if (ENOERR != cyg_io_read(hCAN0, &rx_event, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading from /dev/can0"); + } + else + { + print_can_flags(rx_event.flags, ""); + + if ((rx_event.flags & CYGNUM_CAN_EVENT_RX) || (rx_event.flags & CYGNUM_CAN_EVENT_TX)) + { + print_can_msg(&rx_event.msg, ""); + } + } + } +} + + +//=========================================================================== +// WRITER THREAD +//=========================================================================== +void can1_thread(cyg_addrword_t data) +{ + cyg_uint16 i = 0; + cyg_uint32 len; + cyg_can_message tx_msg = + { + 0x000, // CAN identifier + data : + { + {0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 } // 8 data bytes + }, + CYGNUM_CAN_ID_STD, // standard frame + CYGNUM_CAN_FRAME_DATA, // data frame + 8, // data length code + }; + + // + // This thread simply sends CAN messages. It increments the ID for each new CAN messsage + // and sends a remote frame after seven data frames. In the first byte of each data frame + // the number (0 - 7) of the data frame is stored and the length of the data frame grows + // from 1 - 8 data bytes. + // + // The received pattern should look like this way: + // ID Length Data + // ---------------------------------------------- + // 000 1 00 + // 001 2 01 F1 + // 002 3 02 F1 F2 + // 003 4 03 F1 F2 F3 + // 004 5 04 F1 F2 F3 F4 + // 005 6 05 F1 F2 F3 F4 F5 + // 006 7 06 F1 F2 F3 F4 F5 F6 + // 007 8 Remote Request + // 008 1 00 + // 009 2 01 F1 + // 00A 3 02 F1 F2 + // ... + // + while (1) + { + tx_msg.id = i; + tx_msg.dlc = (i % 8) + 1; + tx_msg.data.bytes[0] = (i % 8); + i = (i + 1) % 0x7FF; + + // + // the 6th frame is a remote frame + // + if ((i % 8) == 6) + { + tx_msg.rtr = CYGNUM_CAN_FRAME_RTR; + tx_msg.ext = CYGNUM_CAN_ID_STD; + } + // + // the 7th frame is a extended frame + // + else if ((i % 8) == 7) + { + tx_msg.ext = CYGNUM_CAN_ID_EXT; + tx_msg.rtr = CYGNUM_CAN_FRAME_DATA; + } + // + // the 8th frame is a extended remote frame + // + else if (!(i % 8)) + { + tx_msg.ext = CYGNUM_CAN_ID_EXT; + tx_msg.rtr = CYGNUM_CAN_FRAME_RTR; + } + // + // all other frames are standard data frames + // + else + { + tx_msg.ext = CYGNUM_CAN_ID_STD; + tx_msg.rtr = CYGNUM_CAN_FRAME_DATA; + } + + len = sizeof(tx_msg); + if (ENOERR != cyg_io_write(hCAN0, &tx_msg, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing to /dev/can0"); + } + + cyg_thread_delay(50); + } // while (1) +} + + + +void +cyg_start(void) +{ + CYG_TEST_INIT(); + + // + // open CAN device driver + // + if (ENOERR != cyg_io_lookup("/dev/can0", &hCAN0)) + { + CYG_TEST_FAIL_FINISH("Error opening /dev/can0"); + } + + // + // create the two threads which access the CAN device driver + // a reader thread with a higher priority and a writer thread + // with a lower priority + // + cyg_thread_create(4, can0_thread, + (cyg_addrword_t) 0, + "can0_thread", + (void *) can0_thread_data.stack, + 1024 * sizeof(long), + &can0_thread_data.hdl, + &can0_thread_data.obj); + + cyg_thread_create(5, can1_thread, + (cyg_addrword_t) can0_thread_data.hdl, + "can1_thread", + (void *) can1_thread_data.stack, + 1024 * sizeof(long), + &can1_thread_data.hdl, + &can1_thread_data.obj); + + cyg_thread_resume(can0_thread_data.hdl); + cyg_thread_resume(can1_thread_data.hdl); + + cyg_scheduler_start(); +} + +#else // defined(CYGOPT_IO_CAN_STD_CAN_ID) && defined(CYGOPT_IO_CAN_EXT_CAN_ID) +#define N_A_MSG "Needs support for standard and extended CAN identifiers" +#endif + +#else // CYGFUN_KERNEL_API_C +#define N_A_MSG "Needs kernel C API" +#endif + +#else // CYGPKG_IO_CAN && CYGPKG_KERNEL +#define N_A_MSG "Needs IO/CAN and Kernel" +#endif + +#ifdef N_A_MSG +void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA( N_A_MSG); +} +#endif // N_A_MSG + +// EOF can_load.c diff --git a/ecos/packages/io/can/current/tests/can_remote.c b/ecos/packages/io/can/current/tests/can_remote.c new file mode 100644 index 0000000..81ed981 --- /dev/null +++ b/ecos/packages/io/can/current/tests/can_remote.c @@ -0,0 +1,311 @@ +//========================================================================== +// +// can_remote.c +// +// CAN remote response buffer test +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2005-08-14 +// Description: CAN load test +//####DESCRIPTIONEND#### + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include <pkgconf/system.h> + +#include <cyg/infra/testcase.h> // test macros +#include <cyg/infra/cyg_ass.h> // assertion macros +#include <cyg/infra/diag.h> + +// Package requirements +#if defined(CYGPKG_IO_CAN) && defined(CYGPKG_KERNEL) + +#include <pkgconf/kernel.h> +#include <cyg/io/io.h> +#include <cyg/io/canio.h> + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + +// Package option requirements +#if defined(CYGOPT_IO_CAN_RUNTIME_MBOX_CFG) + +// Package option requirements +#if defined(CYGOPT_IO_CAN_REMOTE_BUF) + + +//=========================================================================== +// DATA TYPES +//=========================================================================== +typedef struct st_thread_data +{ + cyg_thread obj; + long stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; + cyg_handle_t hdl; +} thread_data_t; + + +//=========================================================================== +// LOCAL DATA +//=========================================================================== +cyg_thread_entry_t can0_thread; +thread_data_t can0_thread_data; +cyg_io_handle_t hCAN0; + + +//=========================================================================== +// LOCAL FUNCTIONS +//=========================================================================== +#include "can_test_aux.inl" // include CAN test auxiliary functions + + +//=========================================================================== +// Main thread +//=========================================================================== +void can0_thread(cyg_addrword_t data) +{ + cyg_uint32 len; + cyg_can_event rx_event; + cyg_can_remote_buf rtr_buf; + cyg_can_filter rx_filter; + cyg_can_msgbuf_info msgbox_info; + cyg_can_msgbuf_cfg msgbox_cfg; + + // + // We would like to setup 2 remote buffers - check if we have enough + // free message buffers + // + len = sizeof(msgbox_info); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO ,&msgbox_info, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0"); + } + else + { + diag_printf("\n\n\nMessage boxes available: %d free: %d\n", + msgbox_info.count, msgbox_info.free); + } + + // + // We have not enougth free message buffers, so we clear all message buffers now + // and try again + // + if (msgbox_info.free < 2) + { + msgbox_cfg.cfg_id = CYGNUM_CAN_MSGBUF_RESET_ALL; + len = sizeof(msgbox_cfg); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF, &msgbox_cfg, &len)) + { + CYG_TEST_FAIL_FINISH("Error clearing message buffers of /dev/can0"); + } + + // + // Now query number of free message boxes again. We need 3 free message boxes. + // 2 message boxes for setup of remote response buffers and 1 message box for + // setup of receive message box for CAN identifier 0x100 + // + len = sizeof(msgbox_info); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO ,&msgbox_info, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading config of /dev/can0"); + } + else + { + diag_printf("Message boxes available: %d free: %d\n", + msgbox_info.count, msgbox_info.free); + } + + if (msgbox_info.free < 3) + { + CYG_TEST_FAIL_FINISH("Not enough free message buffers available for /dev/can0"); + } + else + { + rx_filter.cfg_id = CYGNUM_CAN_MSGBUF_RX_FILTER_ADD; + CYG_CAN_MSG_SET_STD_ID(rx_filter.msg, 0x100); + + len = sizeof(rx_filter); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&rx_filter, &len)) + { + CYG_TEST_FAIL_FINISH("Error adding rx filter for CAN ID 0x100 for /dev/can0"); + } + } // if (msgbox_info.free < 3) + } // if (msgbox_info.free < 2) +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + // + // Setup the first remote response buffer for resception of standard + // remote frames + // + rtr_buf.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD; + CYG_CAN_MSG_SET_PARAM(rtr_buf.msg, 0x7FF, CYGNUM_CAN_ID_STD, 1, CYGNUM_CAN_FRAME_DATA); + CYG_CAN_MSG_SET_DATA(rtr_buf.msg, 0, 0xAB); + + len = sizeof(rtr_buf); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&rtr_buf, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0"); + } +#endif + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + cyg_can_remote_buf rtr_buf2; + // + // setup the second remote response buffer for reception of extended + // remote frames + // + rtr_buf2.cfg_id = CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD; + CYG_CAN_MSG_SET_PARAM(rtr_buf2.msg, 0x800, CYGNUM_CAN_ID_EXT, 4, CYGNUM_CAN_FRAME_DATA); + CYG_CAN_MSG_SET_DATA(rtr_buf2.msg, 0, 0xCD); + + len = sizeof(rtr_buf2); + if (ENOERR != cyg_io_set_config(hCAN0, CYG_IO_SET_CONFIG_CAN_MSGBUF ,&rtr_buf2, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0"); + } + + if (rtr_buf.handle == CYGNUM_CAN_MSGBUF_NA) + { + CYG_TEST_FAIL_FINISH("No free message buffer available for /dev/can0"); + } +#endif + + diag_printf("\nTest of CAN remote response buffer configuration\n" + "If a CAN node sends a remote request with ID 0x7FF (std. ID)\n" + "or 0x800 (ext. ID) then the CAN driver should respond with\n" + "data frames.\n\n"); + diag_printf("!!! This test can be stopped by sending a data frame\n" + "with ID 0x100 !!!\n\n"); + + len = sizeof(msgbox_info); + if (ENOERR != cyg_io_get_config(hCAN0, CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO ,&msgbox_info, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing config of /dev/can0"); + } + else + { + diag_printf("Message boxes available: %d free: %d\n", + msgbox_info.count, msgbox_info.free); + } + + while (1) + { + len = sizeof(rx_event); + + if (ENOERR != cyg_io_read(hCAN0, &rx_event, &len)) + { + CYG_TEST_FAIL_FINISH("Error reading from /dev/can0"); + } + + if (0x100 == rx_event.msg.id) + { + CYG_TEST_PASS_FINISH("can_remote test OK"); + } + else + { + print_can_flags(rx_event.flags, ""); + + if (rx_event.flags & CYGNUM_CAN_EVENT_RX) + { + print_can_msg(&rx_event.msg, ""); + } + } + } +} + + +void +cyg_start(void) +{ + CYG_TEST_INIT(); + + // + // open CAN device driver + // + if (ENOERR != cyg_io_lookup("/dev/can0", &hCAN0)) + { + CYG_TEST_FAIL_FINISH("Error opening /dev/can0"); + } + + // + // create the thread that accesses the CAN device driver + // + cyg_thread_create(4, can0_thread, + (cyg_addrword_t) 0, + "can0_thread", + (void *) can0_thread_data.stack, + 1024 * sizeof(long), + &can0_thread_data.hdl, + &can0_thread_data.obj); + + cyg_thread_resume(can0_thread_data.hdl); + + cyg_scheduler_start(); +} + +#else // CYGOPT_IO_CAN_REMOTE_BUF +#define N_A_MSG "Needs support for CAN remote response buffers" +#endif + +#else // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +#define N_A_MSG "Needs support for CAN message buffer runtime configuration" +#endif + +#else // CYGFUN_KERNEL_API_C +#define N_A_MSG "Needs kernel C API" +#endif + +#else // CYGPKG_IO_CAN && CYGPKG_KERNEL +#define N_A_MSG "Needs IO/CAN and Kernel" +#endif + +#ifdef N_A_MSG +void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA( N_A_MSG); +} +#endif // N_A_MSG + +// EOF can_remote.c diff --git a/ecos/packages/io/can/current/tests/can_test_aux.inl b/ecos/packages/io/can/current/tests/can_test_aux.inl new file mode 100644 index 0000000..2bb2e07 --- /dev/null +++ b/ecos/packages/io/can/current/tests/can_test_aux.inl @@ -0,0 +1,147 @@ +//========================================================================== +// +// can_test_aux.inl +// +// CAN test auxiliary functions +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2005-08-07 +// Description: Auxiliary functions for CAN driver tests +//####DESCRIPTIONEND#### + + +//=========================================================================== +// PRINT CAN EVENT +//=========================================================================== +void print_can_msg(cyg_can_message *pmsg, char *pMsg) +{ + char *pmsg_str; + static char* msg_tbl[] = + { + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X %02X]\n" + }; + + if (pmsg->rtr) + { + diag_printf("%s [ID:%03X] [RTR:%d] [EXT:%d] [DLC:%d]\n", + pMsg, + pmsg->id, + pmsg->rtr, + pmsg->ext, + pmsg->dlc); + + return; + } + + if (pmsg->dlc > 8) + { + pmsg_str = msg_tbl[8]; + } + else + { + pmsg_str = msg_tbl[pmsg->dlc]; + } + + diag_printf(pmsg_str, + pMsg, + pmsg->id, + pmsg->rtr, + pmsg->ext, + pmsg->data.bytes[0], + pmsg->data.bytes[1], + pmsg->data.bytes[2], + pmsg->data.bytes[3], + pmsg->data.bytes[4], + pmsg->data.bytes[5], + pmsg->data.bytes[6], + pmsg->data.bytes[7]); +} + + +//=========================================================================== +// PRINT CAN EVENT FLAGS +//=========================================================================== +void print_can_flags(cyg_uint16 flags, char *pMsg) +{ + char *pmsg_str; + cyg_uint8 i ; + static char* msg_tbl[] = + { + "RX ", + "TX ", + "WRX ", + "WTX ", + "ERRP ", + "BOFF ", + "OVRX ", + "OVTX ", + "CERR ", + "LSTY ", + "ESTY ", + "ALOS ", + "DEVC ", + "PHYF ", + "PHYH ", + "PHYL " + }; + i = 0; + while (flags && (i < 16)) + { + if (flags & 0x0001) + { + pmsg_str = msg_tbl[i]; + diag_printf(pmsg_str); + } + flags >>=1; + i++; + } + + diag_printf("\n"); +} + +//--------------------------------------------------------------------------- +// end of can_test_aux.inl diff --git a/ecos/packages/io/can/current/tests/can_tx.c b/ecos/packages/io/can/current/tests/can_tx.c new file mode 100644 index 0000000..0b38bf3 --- /dev/null +++ b/ecos/packages/io/can/current/tests/can_tx.c @@ -0,0 +1,229 @@ +//========================================================================== +// +// can_tx.c +// +// Simple CAN TX test +// +//========================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-01-08 +// Description: Simple write test of CAN driver +//####DESCRIPTIONEND#### + + +//=========================================================================== +// INCLUDES +//=========================================================================== +#include <pkgconf/system.h> + +#include <cyg/infra/testcase.h> // test macros +#include <cyg/infra/cyg_ass.h> // assertion macros +#include <cyg/infra/diag.h> +#include <cyg/hal/hal_diag.h> + +// Package requirements +#if defined(CYGPKG_IO_CAN) && defined(CYGPKG_KERNEL) + +#include <pkgconf/kernel.h> +#include <cyg/io/io.h> +#include <cyg/io/canio.h> + +// Package option requirements +#if defined(CYGFUN_KERNEL_API_C) + +#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL +#include <cyg/kernel/kapi.h> + + +//=========================================================================== +// DATA TYPES +//=========================================================================== +typedef struct st_thread_data +{ + cyg_thread obj; + long stack[CYGNUM_HAL_STACK_SIZE_TYPICAL]; + cyg_handle_t hdl; +} thread_data_t; + + +//=========================================================================== +// LOCAL DATA +//=========================================================================== +cyg_thread_entry_t can0_thread; +thread_data_t can0_thread_data; + + +//=========================================================================== +// LOCAL FUNCTIONS +//=========================================================================== +#include "can_test_aux.inl" // include CAN test auxiliary functions + + +//=========================================================================== +// WRITER THREAD +//=========================================================================== +void can0_thread(cyg_addrword_t data) +{ + cyg_io_handle_t hCAN0; + cyg_uint32 i; + cyg_uint32 len; + CYG_CAN_MSG_INIT(tx_msg, 0x001, CYGNUM_CAN_ID_STD, 1, CYGNUM_CAN_FRAME_DATA); + + // + // Open device and check return value + // + if (ENOERR != cyg_io_lookup("/dev/can0", &hCAN0)) + { + CYG_TEST_FAIL_FINISH("Error opening /dev/can0"); + } + +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + // + // Now send 1000 messages with standard identifier. + // Each message contains the message number in its identifier + // and in the first data byte + // + for (i = 0; i < 1000; ++i) + { + CYG_CAN_MSG_SET_STD_ID(tx_msg, i); + CYG_CAN_MSG_SET_DATA(tx_msg, 0, i); + len = sizeof(tx_msg); + + // + // Each message with an odd identifier should be a remote request message + // + if (i % 2) + { + CYG_CAN_MSG_SET_FRAME_TYPE(tx_msg, CYGNUM_CAN_FRAME_RTR); + } + else + { + CYG_CAN_MSG_SET_FRAME_TYPE(tx_msg, CYGNUM_CAN_FRAME_DATA); + } + + // + // Sending CAN messages is blocking so the thread waits until there is + // space in the tx queue + // + if (ENOERR != cyg_io_write(hCAN0, &tx_msg, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing to /dev/can0"); + } + } +#endif + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + // + // Now send 1000 messages with extended identifier. + // Each message contains the message number in its identifier + // and in the first data byte + // + for (i = 0; i < 1000; ++i) + { + CYG_CAN_MSG_SET_EXT_ID(tx_msg, i + 0x800); + CYG_CAN_MSG_SET_DATA(tx_msg, 0, i); + CYG_CAN_MSG_SET_DATA_LEN(tx_msg, 8); + len = sizeof(tx_msg); + + // + // Each message with an odd identifier should be a remote request message + // + if (i % 2) + { + CYG_CAN_MSG_SET_FRAME_TYPE(tx_msg, CYGNUM_CAN_FRAME_RTR); + } + else + { + CYG_CAN_MSG_SET_FRAME_TYPE(tx_msg, CYGNUM_CAN_FRAME_DATA); + } + + // + // Sending CAN messages is blocking so the thread waits until there is + // space in the tx queue + // + if (ENOERR != cyg_io_write(hCAN0, &tx_msg, &len)) + { + CYG_TEST_FAIL_FINISH("Error writing to /dev/can0"); + } + } +#endif + + + CYG_TEST_PASS_FINISH("CAN TX test OK"); +} + + +void +cyg_start(void) +{ + CYG_TEST_INIT(); + + // + // create the threads that access the CAN device driver + // + cyg_thread_create(4, can0_thread, + (cyg_addrword_t) 0, + "can0_thread", + (void *) can0_thread_data.stack, + 1024 * sizeof(long), + &can0_thread_data.hdl, + &can0_thread_data.obj); + + cyg_thread_resume(can0_thread_data.hdl); + + cyg_scheduler_start(); +} + +#else // CYGFUN_KERNEL_API_C +#define N_A_MSG "Needs kernel C API" +#endif + +#else // CYGPKG_IO_CAN && CYGPKG_KERNEL +#define N_A_MSG "Needs IO/CAN and Kernel" +#endif + +#ifdef N_A_MSG +void +cyg_start( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_NA( N_A_MSG); +} +#endif // N_A_MSG + +// EOF can_tx.c |
