ChibiOS/RT 2.6.9 CAN Driver
Detailed Description
Generic CAN Driver.
This module implements a generic CAN (Controller Area Network) driver allowing the exchange of information at frame level.
- Precondition:
- In order to use the CAN driver the
HAL_USE_CAN
option must be enabled inhalconf.h
.
Driver State Machine
The driver implements a state machine internally, not all the driver functionalities can be used in any moment,
any transition not explicitly shown in the following diagram has to be considered an error and shall be captured by an assertion (if enabled).
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio 00003 00004 Licensed under the Apache License, Version 2.0 (the "License"); 00005 you may not use this file except in compliance with the License. 00006 You may obtain a copy of the License at 00007 00008 http://www.apache.org/licenses/LICENSE-2.0 00009 00010 Unless required by applicable law or agreed to in writing, software 00011 distributed under the License is distributed on an "AS IS" BASIS, 00012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 See the License for the specific language governing permissions and 00014 limitations under the License. 00015 */ 00016 00017 /** 00018 * @file templates/can_lld.h 00019 * @brief CAN Driver subsystem low level driver header template. 00020 * 00021 * @addtogroup CAN 00022 * @{ 00023 */ 00024 00025 #ifndef _CAN_LLD_H_ 00026 #define _CAN_LLD_H_ 00027 00028 #if HAL_USE_CAN || defined(__DOXYGEN__) 00029 00030 /*===========================================================================*/ 00031 /* Driver constants. */ 00032 /*===========================================================================*/ 00033 00034 /** 00035 * @brief This switch defines whether the driver implementation supports 00036 * a low power switch mode with automatic an wakeup feature. 00037 */ 00038 #define CAN_SUPPORTS_SLEEP TRUE 00039 00040 /** 00041 * @brief This implementation supports three transmit mailboxes. 00042 */ 00043 #define CAN_TX_MAILBOXES 3 00044 00045 /** 00046 * @brief This implementation supports two receive mailboxes. 00047 */ 00048 #define CAN_RX_MAILBOXES 2 00049 00050 /*===========================================================================*/ 00051 /* Driver pre-compile time settings. */ 00052 /*===========================================================================*/ 00053 00054 /** 00055 * @name Configuration options 00056 * @{ 00057 */ 00058 /** 00059 * @brief CAN1 driver enable switch. 00060 * @details If set to @p TRUE the support for CAN1 is included. 00061 */ 00062 #if !defined(PLATFORM_CAN_USE_CAN1) || defined(__DOXYGEN__) 00063 #define PLATFORM_CAN_USE_CAN1 FALSE 00064 #endif 00065 /** @} */ 00066 00067 /*===========================================================================*/ 00068 /* Derived constants and error checks. */ 00069 /*===========================================================================*/ 00070 00071 #if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP 00072 #error "CAN sleep mode not supported in this architecture" 00073 #endif 00074 00075 /*===========================================================================*/ 00076 /* Driver data structures and types. */ 00077 /*===========================================================================*/ 00078 00079 /** 00080 * @brief Type of a transmission mailbox index. 00081 */ 00082 typedef uint32_t canmbx_t; 00083 00084 /** 00085 * @brief CAN transmission frame. 00086 * @note Accessing the frame data as word16 or word32 is not portable because 00087 * machine data endianness, it can be still useful for a quick filling. 00088 */ 00089 typedef struct { 00090 struct { 00091 uint8_t DLC:4; /**< @brief Data length. */ 00092 uint8_t RTR:1; /**< @brief Frame type. */ 00093 uint8_t IDE:1; /**< @brief Identifier type. */ 00094 }; 00095 union { 00096 struct { 00097 uint32_t SID:11; /**< @brief Standard identifier.*/ 00098 }; 00099 struct { 00100 uint32_t EID:29; /**< @brief Extended identifier.*/ 00101 }; 00102 }; 00103 union { 00104 uint8_t data8[8]; /**< @brief Frame data. */ 00105 uint16_t data16[4]; /**< @brief Frame data. */ 00106 uint32_t data32[2]; /**< @brief Frame data. */ 00107 }; 00108 } CANTxFrame; 00109 00110 /** 00111 * @brief CAN received frame. 00112 * @note Accessing the frame data as word16 or word32 is not portable because 00113 * machine data endianness, it can be still useful for a quick filling. 00114 */ 00115 typedef struct { 00116 struct { 00117 uint8_t DLC:4; /**< @brief Data length. */ 00118 uint8_t RTR:1; /**< @brief Frame type. */ 00119 uint8_t IDE:1; /**< @brief Identifier type. */ 00120 }; 00121 union { 00122 struct { 00123 uint32_t SID:11; /**< @brief Standard identifier.*/ 00124 }; 00125 struct { 00126 uint32_t EID:29; /**< @brief Extended identifier.*/ 00127 }; 00128 }; 00129 union { 00130 uint8_t data8[8]; /**< @brief Frame data. */ 00131 uint16_t data16[4]; /**< @brief Frame data. */ 00132 uint32_t data32[2]; /**< @brief Frame data. */ 00133 }; 00134 } CANRxFrame; 00135 00136 /** 00137 * @brief CAN filter. 00138 * @note Implementations may extend this structure to contain more, 00139 * architecture dependent, fields. 00140 * @note It could not be present on some architectures. 00141 */ 00142 typedef struct { 00143 uint32_t dummy; 00144 } CANFilter; 00145 00146 /** 00147 * @brief Driver configuration structure. 00148 * @note Implementations may extend this structure to contain more, 00149 * architecture dependent, fields. 00150 * @note It could be empty on some architectures. 00151 */ 00152 typedef struct { 00153 uint32_t dummy; 00154 } CANConfig; 00155 00156 /** 00157 * @brief Structure representing an CAN driver. 00158 */ 00159 typedef struct { 00160 /** 00161 * @brief Driver state. 00162 */ 00163 canstate_t state; 00164 /** 00165 * @brief Current configuration data. 00166 */ 00167 const CANConfig *config; 00168 /** 00169 * @brief Transmission queue semaphore. 00170 */ 00171 Semaphore txsem; 00172 /** 00173 * @brief Receive queue semaphore. 00174 */ 00175 Semaphore rxsem; 00176 /** 00177 * @brief One or more frames become available. 00178 * @note After broadcasting this event it will not be broadcasted again 00179 * until the received frames queue has been completely emptied. It 00180 * is <b>not</b> broadcasted for each received frame. It is 00181 * responsibility of the application to empty the queue by 00182 * repeatedly invoking @p chReceive() when listening to this event. 00183 * This behavior minimizes the interrupt served by the system 00184 * because CAN traffic. 00185 * @note The flags associated to the listeners will indicate which 00186 * receive mailboxes become non-empty. 00187 */ 00188 EventSource rxfull_event; 00189 /** 00190 * @brief One or more transmission mailbox become available. 00191 * @note The flags associated to the listeners will indicate which 00192 * transmit mailboxes become empty. 00193 * 00194 */ 00195 EventSource txempty_event; 00196 /** 00197 * @brief A CAN bus error happened. 00198 * @note The flags associated to the listeners will indicate the 00199 * error(s) that have occurred. 00200 */ 00201 EventSource error_event; 00202 #if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) 00203 /** 00204 * @brief Entering sleep state event. 00205 */ 00206 EventSource sleep_event; 00207 /** 00208 * @brief Exiting sleep state event. 00209 */ 00210 EventSource wakeup_event; 00211 #endif /* CAN_USE_SLEEP_MODE */ 00212 /* End of the mandatory fields.*/ 00213 } CANDriver; 00214 00215 /*===========================================================================*/ 00216 /* Driver macros. */ 00217 /*===========================================================================*/ 00218 00219 /*===========================================================================*/ 00220 /* External declarations. */ 00221 /*===========================================================================*/ 00222 00223 #if PLATFORM_CAN_USE_CAN1 && !defined(__DOXYGEN__) 00224 extern CANDriver CAND1; 00225 #endif 00226 00227 #ifdef __cplusplus 00228 extern "C" { 00229 #endif 00230 void can_lld_init(void); 00231 void can_lld_start(CANDriver *canp); 00232 void can_lld_stop(CANDriver *canp); 00233 bool_t can_lld_is_tx_empty(CANDriver *canp, 00234 canmbx_t mailbox); 00235 void can_lld_transmit(CANDriver *canp, 00236 canmbx_t mailbox, 00237 const CANTxFrame *crfp); 00238 bool_t can_lld_is_rx_nonempty(CANDriver *canp, 00239 canmbx_t mailbox); 00240 void can_lld_receive(CANDriver *canp, 00241 canmbx_t mailbox, 00242 CANRxFrame *ctfp); 00243 #if CAN_USE_SLEEP_MODE 00244 void can_lld_sleep(CANDriver *canp); 00245 void can_lld_wakeup(CANDriver *canp); 00246 #endif /* CAN_USE_SLEEP_MODE */ 00247 #ifdef __cplusplus 00248 } 00249 #endif 00250 00251 #endif /* HAL_USE_CAN */ 00252 00253 #endif /* _CAN_LLD_H_ */ 00254 00255 /** @} */
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio 00003 00004 Licensed under the Apache License, Version 2.0 (the "License"); 00005 you may not use this file except in compliance with the License. 00006 You may obtain a copy of the License at 00007 00008 http://www.apache.org/licenses/LICENSE-2.0 00009 00010 Unless required by applicable law or agreed to in writing, software 00011 distributed under the License is distributed on an "AS IS" BASIS, 00012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 See the License for the specific language governing permissions and 00014 limitations under the License. 00015 */ 00016 00017 /** 00018 * @file templates/can_lld.c 00019 * @brief CAN Driver subsystem low level driver source template. 00020 * 00021 * @addtogroup CAN 00022 * @{ 00023 */ 00024 00025 #include "ch.h" 00026 #include "hal.h" 00027 00028 #if HAL_USE_CAN || defined(__DOXYGEN__) 00029 00030 /*===========================================================================*/ 00031 /* Driver local definitions. */ 00032 /*===========================================================================*/ 00033 00034 /*===========================================================================*/ 00035 /* Driver exported variables. */ 00036 /*===========================================================================*/ 00037 00038 /** 00039 * @brief CAN1 driver identifier. 00040 */ 00041 #if PLATFORM_CAN_USE_CAN1 || defined(__DOXYGEN__) 00042 CANDriver CAND1; 00043 #endif 00044 00045 /*===========================================================================*/ 00046 /* Driver local variables and types. */ 00047 /*===========================================================================*/ 00048 00049 /*===========================================================================*/ 00050 /* Driver local functions. */ 00051 /*===========================================================================*/ 00052 00053 /*===========================================================================*/ 00054 /* Driver interrupt handlers. */ 00055 /*===========================================================================*/ 00056 00057 /*===========================================================================*/ 00058 /* Driver exported functions. */ 00059 /*===========================================================================*/ 00060 00061 /** 00062 * @brief Low level CAN driver initialization. 00063 * 00064 * @notapi 00065 */ 00066 void can_lld_init(void) { 00067 00068 #if PLATFORM_CAN_USE_CAN1 00069 /* Driver initialization.*/ 00070 canObjectInit(&CAND1); 00071 #endif /* PLATFORM_CAN_USE_CAN1 */ 00072 } 00073 00074 /** 00075 * @brief Configures and activates the CAN peripheral. 00076 * 00077 * @param[in] canp pointer to the @p CANDriver object 00078 * 00079 * @notapi 00080 */ 00081 void can_lld_start(CANDriver *canp) { 00082 00083 if (canp->state == CAN_STOP) { 00084 /* Enables the peripheral.*/ 00085 #if PLATFORM_CAN_USE_CAN1 00086 if (&CAND1 == canp) { 00087 00088 } 00089 #endif /* PLATFORM_CAN_USE_CAN1 */ 00090 } 00091 /* Configures the peripheral.*/ 00092 00093 } 00094 00095 /** 00096 * @brief Deactivates the CAN peripheral. 00097 * 00098 * @param[in] canp pointer to the @p CANDriver object 00099 * 00100 * @notapi 00101 */ 00102 void can_lld_stop(CANDriver *canp) { 00103 00104 if (canp->state == CAN_READY) { 00105 /* Resets the peripheral.*/ 00106 00107 /* Disables the peripheral.*/ 00108 #if PLATFORM_CAN_USE_CAN1 00109 if (&CAND1 == canp) { 00110 00111 } 00112 #endif /* PLATFORM_CAN_USE_CAN1 */ 00113 } 00114 } 00115 00116 /** 00117 * @brief Determines whether a frame can be transmitted. 00118 * 00119 * @param[in] canp pointer to the @p CANDriver object 00120 * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox 00121 * 00122 * @return The queue space availability. 00123 * @retval FALSE no space in the transmit queue. 00124 * @retval TRUE transmit slot available. 00125 * 00126 * @notapi 00127 */ 00128 bool_t can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { 00129 00130 (void)canp; 00131 00132 switch (mailbox) { 00133 case CAN_ANY_MAILBOX: 00134 return FALSE; 00135 case 1: 00136 return FALSE; 00137 case 2: 00138 return FALSE; 00139 case 3: 00140 return FALSE; 00141 default: 00142 return FALSE; 00143 } 00144 } 00145 00146 /** 00147 * @brief Inserts a frame into the transmit queue. 00148 * 00149 * @param[in] canp pointer to the @p CANDriver object 00150 * @param[in] ctfp pointer to the CAN frame to be transmitted 00151 * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox 00152 * 00153 * @notapi 00154 */ 00155 void can_lld_transmit(CANDriver *canp, 00156 canmbx_t mailbox, 00157 const CANTxFrame *ctfp) { 00158 00159 (void)canp; 00160 (void)mailbox; 00161 (void)ctfp; 00162 00163 } 00164 00165 /** 00166 * @brief Determines whether a frame has been received. 00167 * 00168 * @param[in] canp pointer to the @p CANDriver object 00169 * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox 00170 * 00171 * @return The queue space availability. 00172 * @retval FALSE no space in the transmit queue. 00173 * @retval TRUE transmit slot available. 00174 * 00175 * @notapi 00176 */ 00177 bool_t can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { 00178 00179 (void)canp; 00180 (void)mailbox; 00181 00182 switch (mailbox) { 00183 case CAN_ANY_MAILBOX: 00184 return FALSE; 00185 case 1: 00186 return FALSE; 00187 case 2: 00188 return FALSE; 00189 default: 00190 return FALSE; 00191 } 00192 } 00193 00194 /** 00195 * @brief Receives a frame from the input queue. 00196 * 00197 * @param[in] canp pointer to the @p CANDriver object 00198 * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox 00199 * @param[out] crfp pointer to the buffer where the CAN frame is copied 00200 * 00201 * @notapi 00202 */ 00203 void can_lld_receive(CANDriver *canp, 00204 canmbx_t mailbox, 00205 CANRxFrame *crfp) { 00206 00207 (void)canp; 00208 (void)mailbox; 00209 (void)crfp; 00210 00211 } 00212 00213 #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) 00214 /** 00215 * @brief Enters the sleep mode. 00216 * 00217 * @param[in] canp pointer to the @p CANDriver object 00218 * 00219 * @notapi 00220 */ 00221 void can_lld_sleep(CANDriver *canp) { 00222 00223 (void)canp; 00224 00225 } 00226 00227 /** 00228 * @brief Enforces leaving the sleep mode. 00229 * 00230 * @param[in] canp pointer to the @p CANDriver object 00231 * 00232 * @notapi 00233 */ 00234 void can_lld_wakeup(CANDriver *canp) { 00235 00236 (void)canp; 00237 00238 } 00239 #endif /* CAN_USE_SLEEP_MODE */ 00240 00241 #endif /* HAL_USE_CAN */ 00242 00243 /** @} */
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012,2013 Giovanni Di Sirio. 00004 00005 This file is part of ChibiOS/RT. 00006 00007 ChibiOS/RT is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 ChibiOS/RT is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 00020 --- 00021 00022 A special exception to the GPL can be applied should you wish to distribute 00023 a combined work that includes ChibiOS/RT, without being obliged to provide 00024 the source code for any proprietary components. See the file exception.txt 00025 for full details of how and when the exception can be applied. 00026 */ 00027 00028 /** 00029 * @file can.h 00030 * @brief CAN Driver macros and structures. 00031 * 00032 * @addtogroup CAN 00033 * @{ 00034 */ 00035 00036 #ifndef _CAN_H_ 00037 #define _CAN_H_ 00038 00039 #if HAL_USE_CAN || defined(__DOXYGEN__) 00040 00041 /*===========================================================================*/ 00042 /* Driver constants. */ 00043 /*===========================================================================*/ 00044 00045 /** 00046 * @name CAN status flags 00047 * @{ 00048 */ 00049 /** 00050 * @brief Errors rate warning. 00051 */ 00052 #define CAN_LIMIT_WARNING 1 00053 /** 00054 * @brief Errors rate error. 00055 */ 00056 #define CAN_LIMIT_ERROR 2 00057 /** 00058 * @brief Bus off condition reached. 00059 */ 00060 #define CAN_BUS_OFF_ERROR 4 00061 /** 00062 * @brief Framing error of some kind on the CAN bus. 00063 */ 00064 #define CAN_FRAMING_ERROR 8 00065 /** 00066 * @brief Overflow in receive queue. 00067 */ 00068 #define CAN_OVERFLOW_ERROR 16 00069 /** @} */ 00070 00071 /** 00072 * @brief Special mailbox identifier. 00073 */ 00074 #define CAN_ANY_MAILBOX 0 00075 00076 /*===========================================================================*/ 00077 /* Driver pre-compile time settings. */ 00078 /*===========================================================================*/ 00079 00080 /** 00081 * @name CAN configuration options 00082 * @{ 00083 */ 00084 /** 00085 * @brief Sleep mode related APIs inclusion switch. 00086 * @details This option can only be enabled if the CAN implementation supports 00087 * the sleep mode, see the macro @p CAN_SUPPORTS_SLEEP exported by 00088 * the underlying implementation. 00089 */ 00090 #if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) 00091 #define CAN_USE_SLEEP_MODE TRUE 00092 #endif 00093 /** @} */ 00094 00095 /*===========================================================================*/ 00096 /* Derived constants and error checks. */ 00097 /*===========================================================================*/ 00098 00099 #if !CH_USE_SEMAPHORES || !CH_USE_EVENTS 00100 #error "CAN driver requires CH_USE_SEMAPHORES and CH_USE_EVENTS" 00101 #endif 00102 00103 /*===========================================================================*/ 00104 /* Driver data structures and types. */ 00105 /*===========================================================================*/ 00106 00107 /** 00108 * @brief Driver state machine possible states. 00109 */ 00110 typedef enum { 00111 CAN_UNINIT = 0, /**< Not initialized. */ 00112 CAN_STOP = 1, /**< Stopped. */ 00113 CAN_STARTING = 2, /**< Starting. */ 00114 CAN_READY = 3, /**< Ready. */ 00115 CAN_SLEEP = 4 /**< Sleep state. */ 00116 } canstate_t; 00117 00118 #include "can_lld.h" 00119 00120 /*===========================================================================*/ 00121 /* Driver macros. */ 00122 /*===========================================================================*/ 00123 00124 /** 00125 * @name Macro Functions 00126 * @{ 00127 */ 00128 /** 00129 * @brief Converts a mailbox index to a bit mask. 00130 */ 00131 #define CAN_MAILBOX_TO_MASK(mbx) (1 << ((mbx) - 1)) 00132 /** @} */ 00133 00134 /*===========================================================================*/ 00135 /* External declarations. */ 00136 /*===========================================================================*/ 00137 00138 #ifdef __cplusplus 00139 extern "C" { 00140 #endif 00141 void canInit(void); 00142 void canObjectInit(CANDriver *canp); 00143 void canStart(CANDriver *canp, const CANConfig *config); 00144 void canStop(CANDriver *canp); 00145 msg_t canTransmit(CANDriver *canp, 00146 canmbx_t mailbox, 00147 const CANTxFrame *ctfp, 00148 systime_t timeout); 00149 msg_t canReceive(CANDriver *canp, 00150 canmbx_t mailbox, 00151 CANRxFrame *crfp, 00152 systime_t timeout); 00153 #if CAN_USE_SLEEP_MODE 00154 void canSleep(CANDriver *canp); 00155 void canWakeup(CANDriver *canp); 00156 #endif /* CAN_USE_SLEEP_MODE */ 00157 #ifdef __cplusplus 00158 } 00159 #endif 00160 00161 #endif /* HAL_USE_CAN */ 00162 00163 #endif /* _CAN_H_ */ 00164 00165 /** @} */
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012,2013 Giovanni Di Sirio. 00004 00005 This file is part of ChibiOS/RT. 00006 00007 ChibiOS/RT is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 ChibiOS/RT is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 00020 --- 00021 00022 A special exception to the GPL can be applied should you wish to distribute 00023 a combined work that includes ChibiOS/RT, without being obliged to provide 00024 the source code for any proprietary components. See the file exception.txt 00025 for full details of how and when the exception can be applied. 00026 */ 00027 00028 /** 00029 * @file can.c 00030 * @brief CAN Driver code. 00031 * 00032 * @addtogroup CAN 00033 * @{ 00034 */ 00035 00036 #include "ch.h" 00037 #include "hal.h" 00038 00039 #if HAL_USE_CAN || defined(__DOXYGEN__) 00040 00041 /*===========================================================================*/ 00042 /* Driver local definitions. */ 00043 /*===========================================================================*/ 00044 00045 /*===========================================================================*/ 00046 /* Driver exported variables. */ 00047 /*===========================================================================*/ 00048 00049 /*===========================================================================*/ 00050 /* Driver local variables and types. */ 00051 /*===========================================================================*/ 00052 00053 /*===========================================================================*/ 00054 /* Driver local functions. */ 00055 /*===========================================================================*/ 00056 00057 /*===========================================================================*/ 00058 /* Driver exported functions. */ 00059 /*===========================================================================*/ 00060 00061 /** 00062 * @brief CAN Driver initialization. 00063 * @note This function is implicitly invoked by @p halInit(), there is 00064 * no need to explicitly initialize the driver. 00065 * 00066 * @init 00067 */ 00068 void canInit(void) { 00069 00070 can_lld_init(); 00071 } 00072 00073 /** 00074 * @brief Initializes the standard part of a @p CANDriver structure. 00075 * 00076 * @param[out] canp pointer to the @p CANDriver object 00077 * 00078 * @init 00079 */ 00080 void canObjectInit(CANDriver *canp) { 00081 00082 canp->state = CAN_STOP; 00083 canp->config = NULL; 00084 chSemInit(&canp->txsem, 0); 00085 chSemInit(&canp->rxsem, 0); 00086 chEvtInit(&canp->rxfull_event); 00087 chEvtInit(&canp->txempty_event); 00088 chEvtInit(&canp->error_event); 00089 #if CAN_USE_SLEEP_MODE 00090 chEvtInit(&canp->sleep_event); 00091 chEvtInit(&canp->wakeup_event); 00092 #endif /* CAN_USE_SLEEP_MODE */ 00093 } 00094 00095 /** 00096 * @brief Configures and activates the CAN peripheral. 00097 * @note Activating the CAN bus can be a slow operation this this function 00098 * is not atomic, it waits internally for the initialization to 00099 * complete. 00100 * 00101 * @param[in] canp pointer to the @p CANDriver object 00102 * @param[in] config pointer to the @p CANConfig object. Depending on 00103 * the implementation the value can be @p NULL. 00104 * 00105 * @api 00106 */ 00107 void canStart(CANDriver *canp, const CANConfig *config) { 00108 00109 chDbgCheck(canp != NULL, "canStart"); 00110 00111 chSysLock(); 00112 chDbgAssert((canp->state == CAN_STOP) || 00113 (canp->state == CAN_STARTING) || 00114 (canp->state == CAN_READY), 00115 "canStart(), #1", "invalid state"); 00116 while (canp->state == CAN_STARTING) 00117 chThdSleepS(1); 00118 if (canp->state == CAN_STOP) { 00119 canp->config = config; 00120 can_lld_start(canp); 00121 canp->state = CAN_READY; 00122 } 00123 chSysUnlock(); 00124 } 00125 00126 /** 00127 * @brief Deactivates the CAN peripheral. 00128 * 00129 * @param[in] canp pointer to the @p CANDriver object 00130 * 00131 * @api 00132 */ 00133 void canStop(CANDriver *canp) { 00134 00135 chDbgCheck(canp != NULL, "canStop"); 00136 00137 chSysLock(); 00138 chDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY), 00139 "canStop(), #1", "invalid state"); 00140 can_lld_stop(canp); 00141 canp->state = CAN_STOP; 00142 chSemResetI(&canp->rxsem, 0); 00143 chSemResetI(&canp->txsem, 0); 00144 chSchRescheduleS(); 00145 chSysUnlock(); 00146 } 00147 00148 /** 00149 * @brief Can frame transmission. 00150 * @details The specified frame is queued for transmission, if the hardware 00151 * queue is full then the invoking thread is queued. 00152 * @note Trying to transmit while in sleep mode simply enqueues the thread. 00153 * 00154 * @param[in] canp pointer to the @p CANDriver object 00155 * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox 00156 * @param[in] ctfp pointer to the CAN frame to be transmitted 00157 * @param[in] timeout the number of ticks before the operation timeouts, 00158 * the following special values are allowed: 00159 * - @a TIME_IMMEDIATE immediate timeout. 00160 * - @a TIME_INFINITE no timeout. 00161 * . 00162 * @return The operation result. 00163 * @retval RDY_OK the frame has been queued for transmission. 00164 * @retval RDY_TIMEOUT The operation has timed out. 00165 * @retval RDY_RESET The driver has been stopped while waiting. 00166 * 00167 * @api 00168 */ 00169 msg_t canTransmit(CANDriver *canp, 00170 canmbx_t mailbox, 00171 const CANTxFrame *ctfp, 00172 systime_t timeout) { 00173 00174 chDbgCheck((canp != NULL) && (ctfp != NULL) && (mailbox <= CAN_TX_MAILBOXES), 00175 "canTransmit"); 00176 00177 chSysLock(); 00178 chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), 00179 "canTransmit(), #1", "invalid state"); 00180 while ((canp->state == CAN_SLEEP) || !can_lld_is_tx_empty(canp, mailbox)) { 00181 msg_t msg = chSemWaitTimeoutS(&canp->txsem, timeout); 00182 if (msg != RDY_OK) { 00183 chSysUnlock(); 00184 return msg; 00185 } 00186 } 00187 can_lld_transmit(canp, mailbox, ctfp); 00188 chSysUnlock(); 00189 return RDY_OK; 00190 } 00191 00192 /** 00193 * @brief Can frame receive. 00194 * @details The function waits until a frame is received. 00195 * @note Trying to receive while in sleep mode simply enqueues the thread. 00196 * 00197 * @param[in] canp pointer to the @p CANDriver object 00198 * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox 00199 * @param[out] crfp pointer to the buffer where the CAN frame is copied 00200 * @param[in] timeout the number of ticks before the operation timeouts, 00201 * the following special values are allowed: 00202 * - @a TIME_IMMEDIATE immediate timeout (useful in an 00203 * event driven scenario where a thread never blocks 00204 * for I/O). 00205 * - @a TIME_INFINITE no timeout. 00206 * . 00207 * @return The operation result. 00208 * @retval RDY_OK a frame has been received and placed in the buffer. 00209 * @retval RDY_TIMEOUT The operation has timed out. 00210 * @retval RDY_RESET The driver has been stopped while waiting. 00211 * 00212 * @api 00213 */ 00214 msg_t canReceive(CANDriver *canp, 00215 canmbx_t mailbox, 00216 CANRxFrame *crfp, 00217 systime_t timeout) { 00218 00219 chDbgCheck((canp != NULL) && (crfp != NULL) && (mailbox <= CAN_RX_MAILBOXES), 00220 "canReceive"); 00221 00222 chSysLock(); 00223 chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), 00224 "canReceive(), #1", "invalid state"); 00225 while ((canp->state == CAN_SLEEP) || !can_lld_is_rx_nonempty(canp, mailbox)) { 00226 msg_t msg = chSemWaitTimeoutS(&canp->rxsem, timeout); 00227 if (msg != RDY_OK) { 00228 chSysUnlock(); 00229 return msg; 00230 } 00231 } 00232 can_lld_receive(canp, mailbox, crfp); 00233 chSysUnlock(); 00234 return RDY_OK; 00235 } 00236 00237 #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) 00238 /** 00239 * @brief Enters the sleep mode. 00240 * @details This function puts the CAN driver in sleep mode and broadcasts 00241 * the @p sleep_event event source. 00242 * @pre In order to use this function the option @p CAN_USE_SLEEP_MODE must 00243 * be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported 00244 * by the low level driver. 00245 * 00246 * @param[in] canp pointer to the @p CANDriver object 00247 * 00248 * @api 00249 */ 00250 void canSleep(CANDriver *canp) { 00251 00252 chDbgCheck(canp != NULL, "canSleep"); 00253 00254 chSysLock(); 00255 chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), 00256 "canSleep(), #1", "invalid state"); 00257 if (canp->state == CAN_READY) { 00258 can_lld_sleep(canp); 00259 canp->state = CAN_SLEEP; 00260 chEvtBroadcastI(&canp->sleep_event); 00261 chSchRescheduleS(); 00262 } 00263 chSysUnlock(); 00264 } 00265 00266 /** 00267 * @brief Enforces leaving the sleep mode. 00268 * @note The sleep mode is supposed to be usually exited automatically by 00269 * an hardware event. 00270 * 00271 * @param[in] canp pointer to the @p CANDriver object 00272 */ 00273 void canWakeup(CANDriver *canp) { 00274 00275 chDbgCheck(canp != NULL, "canWakeup"); 00276 00277 chSysLock(); 00278 chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), 00279 "canWakeup(), #1", "invalid state"); 00280 if (canp->state == CAN_SLEEP) { 00281 can_lld_wakeup(canp); 00282 canp->state = CAN_READY; 00283 chEvtBroadcastI(&canp->wakeup_event); 00284 chSchRescheduleS(); 00285 } 00286 chSysUnlock(); 00287 } 00288 #endif /* CAN_USE_SLEEP_MODE */ 00289 00290 #endif /* HAL_USE_CAN */ 00291 00292 /** @} */
void canInit(void )
CAN Driver initialization.
- Note:
- This function is implicitly invoked by
halInit()
, there is no need to explicitly initialize the driver.
- Function Class:
- Initializer, this function just initializes an object and can be invoked before the kernel is initialized.
Here is the call graph for this function:
void canObjectInit ( CANDriver * canp )
Initializes the standard part of a CANDriver
structure.
- Function Class:
- Initializer, this function just initializes an object and can be invoked before the kernel is initialized.
Configures and activates the CAN peripheral.
- Note:
- Activating the CAN bus can be a slow operation this this function is not atomic, it waits internally for the initialization to complete.
Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.
void canStop ( CANDriver * canp )
Deactivates the CAN peripheral.
Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.
msg_t canTransmit ( CANDriver * canp, canmbx_t mailbox, const CANTxFrame * ctfp, systime_t timeout )
Can frame transmission.
The specified frame is queued for transmission, if the hardware queue is full then the invoking thread is queued.
- Note:
- Trying to transmit while in sleep mode simply enqueues the thread.
Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.
msg_t canReceive ( CANDriver * canp, canmbx_t mailbox, CANRxFrame * crfp, systime_t timeout )
Can frame receive.
The function waits until a frame is received.
- Note:
- Trying to receive while in sleep mode simply enqueues the thread.
Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.
void canSleep ( CANDriver * canp )
Enters the sleep mode.
This function puts the CAN driver in sleep mode and broadcasts the sleep_event
event source.
- Precondition:
- In order to use this function the option
CAN_USE_SLEEP_MODE
must be enabled - and the
CAN_SUPPORTS_SLEEP
mode must be supported by the low level driver.
Function Class:Normal API, this function can be invoked by regular system threads but not from within a lock zone.
void canWakeup ( CANDriver * canp )
Enforces leaving the sleep mode.
- Note:
- The sleep mode is supposed to be usually exited automatically by an hardware event.
/** * This switch defines whether the driver implementation supports * a low power switch mode with automatic an wakeup feature. */ #define CAN_SUPPORTS_SLEEP TRUE /** * This implementation supports three transmit mailboxes. */ #define CAN_TX_MAILBOXES 3 /** * This implementation supports two receive mailboxes. */ #define CAN_RX_MAILBOXES 2 /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ /** * @name Configuration options * @{ */ /** * CAN1 driver enable switch. * @details If set to @p TRUE the support for CAN1 is included. */ #if !defined(PLATFORM_CAN_USE_CAN1) || defined(__DOXYGEN__) #define PLATFORM_CAN_USE_CAN1 FALSE #endif /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ #if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP #error "CAN sleep mode not supported in this architecture" #endif /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ /** * Type of a transmission mailbox index. */ typedef uint32_t canmbx_t; /** * CAN transmission frame. * @note Accessing the frame data as word16 or word32 is not portable because * machine data endianness, it can be still useful for a quick filling. */ typedef struct { struct { uint8_t DLC :4; /**< @brief Data length. */ uint8_t RTR :1; /**< @brief Frame type. */ uint8_t IDE :1; /**< @brief Identifier type. */ }; union { struct { uint32_t SID :11; /**< @brief Standard identifier.*/ }; struct { uint32_t EID :29; /**< @brief Extended identifier.*/ }; }; union { uint8_t data8[ 8 ]; /**< @brief Frame data. */ uint16_t data16[ 4 ]; /**< @brief Frame data. */ uint32_t data32[ 2 ]; /**< @brief Frame data. */ }; } CANTxFrame; /** * CAN received frame. * @note Accessing the frame data as word16 or word32 is not portable because * machine data endianness, it can be still useful for a quick filling. */ typedef struct { struct { uint8_t DLC :4; /**< @brief Data length. */ uint8_t RTR :1; /**< @brief Frame type. */ uint8_t IDE :1; /**< @brief Identifier type. */ }; union { struct { uint32_t SID :11; /**< @brief Standard identifier.*/ }; struct { uint32_t EID :29; /**< @brief Extended identifier.*/ }; }; union { uint8_t data8[ 8 ]; /**< @brief Frame data. */ uint16_t data16[ 4 ]; /**< @brief Frame data. */ uint32_t data32[ 2 ]; /**< @brief Frame data. */ }; } CANRxFrame; /** * CAN filter. * @note Implementations may extend this structure to contain more, * architecture dependent, fields. * @note It could not be present on some architectures. */ typedef struct { uint32_t dummy; } CANFilter; /** * Driver configuration structure. * @note Implementations may extend this structure to contain more, * architecture dependent, fields. * @note It could be empty on some architectures. */ typedef struct { uint32_t dummy; } CANConfig; /** * Structure representing an CAN driver. */ typedef struct { /** * Driver state. */ canstate_t state; /** * Current configuration data. */ const CANConfig *config; /** * Transmission queue semaphore. */ Semaphore txsem; /** * Receive queue semaphore. */ Semaphore rxsem; /** * One or more frames become available. * @note After broadcasting this event it will not be broadcasted again * until the received frames queue has been completely emptied. It * is <b>not</b> broadcasted for each received frame. It is * responsibility of the application to empty the queue by * repeatedly invoking @p chReceive() when listening to this event. * This behavior minimizes the interrupt served by the system * because CAN traffic. * @note The flags associated to the listeners will indicate which * receive mailboxes become non-empty. */ EventSource rxfull_event; /** * One or more transmission mailbox become available. * @note The flags associated to the listeners will indicate which * transmit mailboxes become empty. * */ EventSource txempty_event; /** * A CAN bus error happened. * @note The flags associated to the listeners will indicate the * error(s) that have occurred. */ EventSource error_event; /** * Entering sleep state event. */ EventSource sleep_event; /** * Exiting sleep state event. */ EventSource wakeup_event; /* End of the mandatory fields.*/ } CANDriver; extern CANDriver CAND1; void can_lld_init( void ); void can_lld_start( CANDriver *canp ); void can_lld_stop( CANDriver *canp ); uiknt32_t can_lld_is_tx_empty( CANDriver *canp, canmbx_t mailbox ); void can_lld_transmit( CANDriver *canp, canmbx_t mailbox, const CANTxFrame *crfp ); uiknt32_t can_lld_is_rx_nonempty( CANDriver *canp, canmbx_t mailbox ); void can_lld_receive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *ctfp ); void can_lld_sleep( CANDriver *canp ); void can_lld_wakeup( CANDriver *canp ); /** * @file templates/can_lld.c * CAN Driver subsystem low level driver source template. * * @addtogroup CAN * @{ */ /** * CAN1 driver identifier. */ CANDriver CAND1; /** * Low level CAN driver initialization. * * @notapi */ void can_lld_init( void ) { /* Driver initialization.*/ canObjectInit( &CAND1 ); } /** * Configures and activates the CAN peripheral. * * @param[in] canp pointer to the @p CANDriver object * * @notapi */ void can_lld_start( CANDriver *canp ) { if ( canp->state == CAN_STOP ) { /* Enables the peripheral.*/ if ( &CAND1 == canp ) { } } /* Configures the peripheral.*/ } /** * Deactivates the CAN peripheral. * * @param[in] canp pointer to the @p CANDriver object * * @notapi */ void can_lld_stop( CANDriver *canp ) { if ( canp->state == CAN_READY ) { /* Resets the peripheral.*/ /* Disables the peripheral.*/ if ( &CAND1 == canp ) { } } } /** * Determines whether a frame can be transmitted. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * * @return The queue space availability. * @retval FALSE no space in the transmit queue. * @retval TRUE transmit slot available. * * @notapi */ uiknt32_t can_lld_is_tx_empty( CANDriver *canp, canmbx_t mailbox ) { (void) canp; switch ( mailbox ) { case CAN_ANY_MAILBOX: return FALSE; case 1: return FALSE; case 2: return FALSE; case 3: return FALSE; default: return FALSE; } } /** * Inserts a frame into the transmit queue. * * @param[in] canp pointer to the @p CANDriver object * @param[in] ctfp pointer to the CAN frame to be transmitted * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * * @notapi */ void can_lld_transmit( CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp ) { (void) canp; (void) mailbox; (void) ctfp; } /** * Determines whether a frame has been received. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * * @return The queue space availability. * @retval FALSE no space in the transmit queue. * @retval TRUE transmit slot available. * * @notapi */ uiknt32_t can_lld_is_rx_nonempty( CANDriver *canp, canmbx_t mailbox ) { (void) canp; (void) mailbox; switch ( mailbox ) { case CAN_ANY_MAILBOX: return FALSE; case 1: return FALSE; case 2: return FALSE; default: return FALSE; } } /** * Receives a frame from the input queue. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * @param[out] crfp pointer to the buffer where the CAN frame is copied * * @notapi */ void can_lld_receive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp ) { (void) canp; (void) mailbox; (void) crfp; } /** * Enters the sleep mode. * * @param[in] canp pointer to the @p CANDriver object * * @notapi */ void can_lld_sleep( CANDriver *canp ) { (void) canp; } /** * Enforces leaving the sleep mode. * * @param[in] canp pointer to the @p CANDriver object * * @notapi */ void can_lld_wakeup( CANDriver *canp ) { (void) canp; } /** * @name CAN status flags * @{ */ /** * Errors rate warning. */ #define CAN_LIMIT_WARNING 1 /** * Errors rate error. */ #define CAN_LIMIT_ERROR 2 /** * Bus off condition reached. */ #define CAN_BUS_OFF_ERROR 4 /** * Framing error of some kind on the CAN bus. */ #define CAN_FRAMING_ERROR 8 /** * Overflow in receive queue. */ #define CAN_OVERFLOW_ERROR 16 /** * Special mailbox identifier. */ #define CAN_ANY_MAILBOX 0 /** * @name CAN configuration options * @{ */ /** * Sleep mode related APIs inclusion switch. * @details This option can only be enabled if the CAN implementation supports * the sleep mode, see the macro @p CAN_SUPPORTS_SLEEP exported by * the underlying implementation. */ #define CAN_USE_SLEEP_MODE TRUE /** * Driver state machine possible states. */ typedef enum { CAN_UNINIT = 0, /**< Not initialized. */ CAN_STOP = 1, /**< Stopped. */ CAN_STARTING = 2, /**< Starting. */ CAN_READY = 3, /**< Ready. */ CAN_SLEEP = 4 /**< Sleep state. */ } canstate_t; #include "can_lld.h" /** * Converts a mailbox index to a bit mask. */ #define CAN_MAILBOX_TO_MASK(mbx) (1 << ((mbx) - 1)) void canInit( void ); void canObjectInit( CANDriver *canp ); void canStart( CANDriver *canp, const CANConfig *config ); void canStop( CANDriver *canp ); msg_t canTransmit( CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp, systime_t timeout ); msg_t canReceive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp, systime_t timeout ); void canSleep( CANDriver *canp ); void canWakeup( CANDriver *canp ); #include "ch.h" #include "hal.h" /** * CAN Driver initialization. * @note This function is implicitly invoked by @p halInit(), there is * no need to explicitly initialize the driver. * * @init */ void canInit( void ) { can_lld_init( ); } /** * Initializes the standard part of a @p CANDriver structure. * * @param[out] canp pointer to the @p CANDriver object * * @init */ void canObjectInit( CANDriver *canp ) { canp->state = CAN_STOP; canp->config = NULL; chSemInit( &canp->txsem, 0 ); chSemInit( &canp->rxsem, 0 ); chEvtInit( &canp->rxfull_event ); chEvtInit( &canp->txempty_event ); chEvtInit( &canp->error_event ); chEvtInit( &canp->sleep_event ); chEvtInit( &canp->wakeup_event ); } /** * Configures and activates the CAN peripheral. * @note Activating the CAN bus can be a slow operation this this function * is not atomic, it waits internally for the initialization to * complete. * * @param[in] canp pointer to the @p CANDriver object * @param[in] config pointer to the @p CANConfig object. Depending on * the implementation the value can be @p NULL. * * @api */ void canStart( CANDriver *canp, const CANConfig *config ) { chDbgCheck( canp != NULL, "canStart" ); chSysLock( ); chDbgAssert( ( canp->state == CAN_STOP ) || ( canp->state == CAN_STARTING ) || ( canp->state == CAN_READY ), "canStart(), #1", "invalid state" ); while ( canp->state == CAN_STARTING ) chThdSleepS( 1 ); if ( canp->state == CAN_STOP ) { canp->config = config; can_lld_start( canp ); canp->state = CAN_READY; } chSysUnlock( ); } /** * Deactivates the CAN peripheral. * * @param[in] canp pointer to the @p CANDriver object * * @api */ void canStop( CANDriver *canp ) { chDbgCheck( canp != NULL, "canStop" ); chSysLock( ); chDbgAssert( ( canp->state == CAN_STOP ) || ( canp->state == CAN_READY ), "canStop(), #1", "invalid state" ); can_lld_stop( canp ); canp->state = CAN_STOP; chSemResetI( &canp->rxsem, 0 ); chSemResetI( &canp->txsem, 0 ); chSchRescheduleS( ); chSysUnlock( ); } /** * Can frame transmission. * @details The specified frame is queued for transmission, if the hardware * queue is full then the invoking thread is queued. * @note Trying to transmit while in sleep mode simply enqueues the thread. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * @param[in] ctfp pointer to the CAN frame to be transmitted * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout. * - @a TIME_INFINITE no timeout. * . * @return The operation result. * @retval RDY_OK the frame has been queued for transmission. * @retval RDY_TIMEOUT The operation has timed out. * @retval RDY_RESET The driver has been stopped while waiting. * * @api */ msg_t canTransmit( CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp, systime_t timeout ) { chDbgCheck( ( canp != NULL ) && ( ctfp != NULL ) && ( mailbox <= CAN_TX_MAILBOXES ), "canTransmit" ); chSysLock( ); chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ), "canTransmit(), #1", "invalid state" ); while ( ( canp->state == CAN_SLEEP ) || !can_lld_is_tx_empty( canp, mailbox ) ) { msg_t msg = chSemWaitTimeoutS( &canp->txsem, timeout ); if ( msg != RDY_OK ) { chSysUnlock( ); return msg; } } can_lld_transmit( canp, mailbox, ctfp ); chSysUnlock( ); return RDY_OK; } /** * Can frame receive. * @details The function waits until a frame is received. * @note Trying to receive while in sleep mode simply enqueues the thread. * * @param[in] canp pointer to the @p CANDriver object * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox * @param[out] crfp pointer to the buffer where the CAN frame is copied * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_IMMEDIATE immediate timeout (useful in an * event driven scenario where a thread never blocks * for I/O). * - @a TIME_INFINITE no timeout. * . * @return The operation result. * @retval RDY_OK a frame has been received and placed in the buffer. * @retval RDY_TIMEOUT The operation has timed out. * @retval RDY_RESET The driver has been stopped while waiting. * * @api */ msg_t canReceive( CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp, systime_t timeout ) { chDbgCheck( ( canp != NULL ) && ( crfp != NULL ) && ( mailbox <= CAN_RX_MAILBOXES ), "canReceive" ); chSysLock( ); chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ), "canReceive(), #1", "invalid state" ); while ( ( canp->state == CAN_SLEEP ) || !can_lld_is_rx_nonempty( canp, mailbox ) ) { msg_t msg = chSemWaitTimeoutS( &canp->rxsem, timeout ); if ( msg != RDY_OK ) { chSysUnlock( ); return msg; } } can_lld_receive( canp, mailbox, crfp ); chSysUnlock( ); return RDY_OK; } /** * Enters the sleep mode. * @details This function puts the CAN driver in sleep mode and broadcasts * the @p sleep_event event source. * @pre In order to use this function the option @p CAN_USE_SLEEP_MODE must * be enabled and the @p CAN_SUPPORTS_SLEEP mode must be supported * by the low level driver. * * @param[in] canp pointer to the @p CANDriver object * * @api */ void canSleep( CANDriver *canp ) { chDbgCheck( canp != NULL, "canSleep" ); chSysLock( ); chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ), "canSleep(), #1", "invalid state" ); if ( canp->state == CAN_READY ) { can_lld_sleep( canp ); canp->state = CAN_SLEEP; chEvtBroadcastI( &canp->sleep_event ); chSchRescheduleS( ); } chSysUnlock( ); } /** * Enforces leaving the sleep mode. * @note The sleep mode is supposed to be usually exited automatically by * an hardware event. * * @param[in] canp pointer to the @p CANDriver object */ void canWakeup( CANDriver *canp ) { chDbgCheck( canp != NULL, "canWakeup" ); chSysLock( ); chDbgAssert( ( canp->state == CAN_READY ) || ( canp->state == CAN_SLEEP ), "canWakeup(), #1", "invalid state" ); if ( canp->state == CAN_SLEEP ) { can_lld_wakeup( canp ); canp->state = CAN_READY; chEvtBroadcastI( &canp->wakeup_event ); chSchRescheduleS( ); } chSysUnlock( ); }