ChibiOS/RT Architecture - Reference Manual - Guides |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. 00003 00004 This file is part of ChibiOS/RT. 00005 00006 ChibiOS/RT is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 ChibiOS/RT is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 --- 00020 00021 A special exception to the GPL can be applied should you wish to distribute 00022 a combined work that includes ChibiOS/RT, without being obliged to provide 00023 the source code for any proprietary components. See the file exception.txt 00024 for full details of how and when the exception can be applied. 00025 */ 00026 00027 /** 00028 * @file can.c 00029 * @brief CAN Driver code. 00030 * 00031 * @addtogroup CAN 00032 * @{ 00033 */ 00034 00035 #include "ch.h" 00036 #include "hal.h" 00037 00038 #if CH_HAL_USE_CAN || defined(__DOXYGEN__) 00039 00040 /*===========================================================================*/ 00041 /* Driver exported variables. */ 00042 /*===========================================================================*/ 00043 00044 /*===========================================================================*/ 00045 /* Driver local variables. */ 00046 /*===========================================================================*/ 00047 00048 /*===========================================================================*/ 00049 /* Driver local functions. */ 00050 /*===========================================================================*/ 00051 00052 /*===========================================================================*/ 00053 /* Driver exported functions. */ 00054 /*===========================================================================*/ 00055 00056 /** 00057 * @brief CAN Driver initialization. 00058 */ 00059 void canInit(void) { 00060 00061 can_lld_init(); 00062 } 00063 00064 /** 00065 * @brief Initializes the standard part of a @p CANDriver structure. 00066 * 00067 * @param[in] canp pointer to the @p CANDriver object 00068 */ 00069 void canObjectInit(CANDriver *canp) { 00070 00071 canp->cd_state = CAN_STOP; 00072 canp->cd_config = NULL; 00073 chSemInit(&canp->cd_txsem, 0); 00074 chSemInit(&canp->cd_rxsem, 0); 00075 chEvtInit(&canp->cd_rxfull_event); 00076 chEvtInit(&canp->cd_txempty_event); 00077 chEvtInit(&canp->cd_error_event); 00078 canp->cd_status = 0; 00079 #if CAN_USE_SLEEP_MODE 00080 chEvtInit(&canp->cd_sleep_event); 00081 chEvtInit(&canp->cd_wakeup_event); 00082 #endif /* CAN_USE_SLEEP_MODE */ 00083 } 00084 00085 /** 00086 * @brief Configures and activates the CAN peripheral. 00087 * 00088 * @param[in] canp pointer to the @p CANDriver object 00089 * @param[in] config pointer to the @p CANConfig object 00090 */ 00091 void canStart(CANDriver *canp, const CANConfig *config) { 00092 00093 chDbgCheck((canp != NULL) && (config != NULL), "canStart"); 00094 00095 chSysLock(); 00096 chDbgAssert((canp->cd_state == CAN_STOP) || 00097 (canp->cd_state == CAN_STARTING) || 00098 (canp->cd_state == CAN_READY), 00099 "canStart(), #1", 00100 "invalid state"); 00101 while (canp->cd_state == CAN_STARTING) 00102 chThdSleepS(1); 00103 if (canp->cd_state == CAN_STOP) { 00104 canp->cd_config = config; 00105 can_lld_start(canp); 00106 canp->cd_state = CAN_READY; 00107 } 00108 chSysUnlock(); 00109 } 00110 00111 /** 00112 * @brief Deactivates the CAN peripheral. 00113 * 00114 * @param[in] canp pointer to the @p CANDriver object 00115 */ 00116 void canStop(CANDriver *canp) { 00117 00118 chDbgCheck(canp != NULL, "canStop"); 00119 00120 chSysLock(); 00121 chDbgAssert((canp->cd_state == CAN_STOP) || (canp->cd_state == CAN_READY), 00122 "canStop(), #1", 00123 "invalid state"); 00124 can_lld_stop(canp); 00125 chSemResetI(&canp->cd_rxsem, 0); 00126 chSemResetI(&canp->cd_txsem, 0); 00127 chSchRescheduleS(); 00128 canp->cd_state = CAN_STOP; 00129 canp->cd_status = 0; 00130 chSysUnlock(); 00131 } 00132 00133 /** 00134 * @brief Can frame transmission. 00135 * @details The specified frame is queued for transmission, if the hardware 00136 * queue is full then the invoking thread is queued. 00137 * @note Trying to transmit while in sleep mode simply enqueues the thread. 00138 * 00139 * @param[in] canp pointer to the @p CANDriver object 00140 * @param[in] ctfp pointer to the CAN frame to be transmitted 00141 * @param[in] timeout the number of ticks before the operation timeouts, 00142 * the following special values are allowed: 00143 * - @a TIME_IMMEDIATE immediate timeout. 00144 * - @a TIME_INFINITE no timeout. 00145 * . 00146 * @return The operation result. 00147 * @retval RDY_OK the frame has been queued for transmission. 00148 * @retval RDY_TIMEOUT operation not finished within the specified time. 00149 * @retval RDY_RESET driver stopped while waiting. 00150 */ 00151 msg_t canTransmit(CANDriver *canp, const CANTxFrame *ctfp, systime_t timeout) { 00152 00153 chDbgCheck((canp != NULL) && (ctfp != NULL), "canTransmit"); 00154 00155 chSysLock(); 00156 chDbgAssert((canp->cd_state == CAN_READY) || (canp->cd_state == CAN_SLEEP), 00157 "canTransmit(), #1", 00158 "invalid state"); 00159 while ((canp->cd_state == CAN_SLEEP) || !can_lld_can_transmit(canp)) { 00160 msg_t msg = chSemWaitTimeoutS(&canp->cd_txsem, timeout); 00161 if (msg != RDY_OK) { 00162 chSysUnlock(); 00163 return msg; 00164 } 00165 } 00166 can_lld_transmit(canp, ctfp); 00167 chSysUnlock(); 00168 return RDY_OK; 00169 } 00170 00171 /** 00172 * @brief Can frame receive. 00173 * @details The function waits until a frame is received. 00174 * @note Trying to receive while in sleep mode simply enqueues the thread. 00175 * 00176 * @param[in] canp pointer to the @p CANDriver object 00177 * @param[out] crfp pointer to the buffer where the CAN frame is copied 00178 * @param[in] timeout the number of ticks before the operation timeouts, 00179 * the following special values are allowed: 00180 * - @a TIME_IMMEDIATE immediate timeout (useful in an 00181 * event driven scenario where a thread never blocks 00182 * for I/O). 00183 * - @a TIME_INFINITE no timeout. 00184 * . 00185 * @return The operation result. 00186 * @retval RDY_OK a frame has been received and placed in the buffer. 00187 * @retval RDY_TIMEOUT operation not finished within the specified time or 00188 * frame not immediately available if invoked using 00189 * @p TIME_IMMEDIATE. 00190 * @retval RDY_RESET driver stopped while waiting. 00191 */ 00192 msg_t canReceive(CANDriver *canp, CANRxFrame *crfp, systime_t timeout) { 00193 00194 chDbgCheck((canp != NULL) && (crfp != NULL), "canReceive"); 00195 00196 chSysLock(); 00197 chDbgAssert((canp->cd_state == CAN_READY) || (canp->cd_state == CAN_SLEEP), 00198 "canReceive(), #1", 00199 "invalid state"); 00200 while ((canp->cd_state == CAN_SLEEP) || !can_lld_can_receive(canp)) { 00201 msg_t msg = chSemWaitTimeoutS(&canp->cd_rxsem, timeout); 00202 if (msg != RDY_OK) { 00203 chSysUnlock(); 00204 return msg; 00205 } 00206 } 00207 can_lld_receive(canp, crfp); 00208 chSysUnlock(); 00209 return RDY_OK; 00210 } 00211 00212 /** 00213 * @brief Returns the current status mask and clears it. 00214 * 00215 * @param[in] canp pointer to the @p CANDriver object 00216 * @return The status flags mask. 00217 */ 00218 canstatus_t canGetAndClearFlags(CANDriver *canp) { 00219 canstatus_t status; 00220 00221 chSysLock(); 00222 status = canp->cd_status; 00223 canp->cd_status = 0; 00224 chSysUnlock(); 00225 return status; 00226 } 00227 00228 #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) 00229 /** 00230 * @brief Enters the sleep mode. 00231 * 00232 * @param[in] canp pointer to the @p CANDriver object 00233 */ 00234 void canSleep(CANDriver *canp) { 00235 00236 chDbgCheck(canp != NULL, "canSleep"); 00237 00238 chSysLock(); 00239 chDbgAssert((canp->cd_state == CAN_READY) || (canp->cd_state == CAN_SLEEP), 00240 "canSleep(), #1", 00241 "invalid state"); 00242 if (canp->cd_state == CAN_READY) { 00243 can_lld_sleep(canp); 00244 canp->cd_state = CAN_SLEEP; 00245 chEvtBroadcastI(&canp->cd_sleep_event); 00246 chSchRescheduleS(); 00247 } 00248 chSysUnlock(); 00249 } 00250 00251 /** 00252 * @brief Enforces leaving the sleep mode. 00253 * @note The sleep mode is supposed to be usually exited automatically by 00254 * an hardware event. 00255 * 00256 * @param[in] canp pointer to the @p CANDriver object 00257 */ 00258 void canWakeup(CANDriver *canp) { 00259 00260 chDbgCheck(canp != NULL, "canWakeup"); 00261 00262 chSysLock(); 00263 chDbgAssert((canp->cd_state == CAN_READY) || (canp->cd_state == CAN_SLEEP), 00264 "canWakeup(), #1", 00265 "invalid state"); 00266 if (canp->cd_state == CAN_SLEEP) { 00267 can_lld_wakeup(canp); 00268 canp->cd_state = CAN_READY; 00269 chEvtBroadcastI(&canp->cd_wakeup_event); 00270 chSchRescheduleS(); 00271 } 00272 chSysUnlock(); 00273 } 00274 #endif /* CAN_USE_SLEEP_MODE */ 00275 00276 #endif /* CH_HAL_USE_CAN */ 00277 00278 /** @} */