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 serial.c 00029 * @brief Serial Driver code. 00030 * 00031 * @addtogroup SERIAL 00032 * @{ 00033 */ 00034 00035 #include "ch.h" 00036 #include "hal.h" 00037 00038 #if CH_HAL_USE_SERIAL || 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 * Interface implementation, the following functions just invoke the equivalent 00054 * queue-level function or macro. 00055 */ 00056 00057 static size_t writes(void *ip, const uint8_t *bp, size_t n) { 00058 00059 return chOQWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, 00060 n, TIME_INFINITE); 00061 } 00062 00063 static size_t reads(void *ip, uint8_t *bp, size_t n) { 00064 00065 return chIQReadTimeout(&((SerialDriver *)ip)->iqueue, bp, 00066 n, TIME_INFINITE); 00067 } 00068 00069 static bool_t putwouldblock(void *ip) { 00070 00071 return chOQIsFull(&((SerialDriver *)ip)->oqueue); 00072 } 00073 00074 static bool_t getwouldblock(void *ip) { 00075 00076 return chIQIsEmpty(&((SerialDriver *)ip)->iqueue); 00077 } 00078 00079 static msg_t putt(void *ip, uint8_t b, systime_t timeout) { 00080 00081 return chOQPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout); 00082 } 00083 00084 static msg_t gett(void *ip, systime_t timeout) { 00085 00086 return chIQGetTimeout(&((SerialDriver *)ip)->iqueue, timeout); 00087 } 00088 00089 static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t time) { 00090 00091 return chOQWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, n, time); 00092 } 00093 00094 static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t time) { 00095 00096 return chIQReadTimeout(&((SerialDriver *)ip)->iqueue, bp, n, time); 00097 } 00098 00099 static const struct SerialDriverVMT vmt = { 00100 writes, reads, putwouldblock, getwouldblock, putt, gett, writet, readt 00101 }; 00102 00103 /*===========================================================================*/ 00104 /* Driver exported functions. */ 00105 /*===========================================================================*/ 00106 00107 /** 00108 * @brief Serial Driver initialization. 00109 */ 00110 void sdInit(void) { 00111 00112 sd_lld_init(); 00113 } 00114 00115 /** 00116 * @brief Initializes a generic full duplex driver object. 00117 * @details The HW dependent part of the initialization has to be performed 00118 * outside, usually in the hardware initialization code. 00119 * 00120 * @param[out] sdp pointer to a @p SerialDriver structure 00121 * @param[in] inotify pointer to a callback function that is invoked when 00122 * some data is read from the Queue. The value can be 00123 * @p NULL. 00124 * @param[in] onotify pointer to a callback function that is invoked when 00125 * some data is written in the Queue. The value can be 00126 * @p NULL. 00127 */ 00128 void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) { 00129 00130 sdp->vmt = &vmt; 00131 chEvtInit(&sdp->ievent); 00132 chEvtInit(&sdp->oevent); 00133 chEvtInit(&sdp->sevent); 00134 sdp->state = SD_STOP; 00135 sdp->flags = SD_NO_ERROR; 00136 chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify); 00137 chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify); 00138 } 00139 00140 /** 00141 * @brief Configures and starts the driver. 00142 * 00143 * @param[in] sdp pointer to a @p SerialDriver object 00144 * @param[in] config the architecture-dependent serial driver configuration. 00145 * If this parameter is set to @p NULL then a default 00146 * configuration is used. 00147 */ 00148 void sdStart(SerialDriver *sdp, const SerialConfig *config) { 00149 00150 chDbgCheck(sdp != NULL, "sdStart"); 00151 00152 chSysLock(); 00153 chDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), 00154 "sdStart(), #1", 00155 "invalid state"); 00156 sd_lld_start(sdp, config); 00157 sdp->state = SD_READY; 00158 chSysUnlock(); 00159 } 00160 00161 /** 00162 * @brief Stops the driver. 00163 * @details Any thread waiting on the driver's queues will be awakened with 00164 * the message @p Q_RESET. 00165 * 00166 * @param[in] sdp pointer to a @p SerialDrive object 00167 */ 00168 void sdStop(SerialDriver *sdp) { 00169 00170 chDbgCheck(sdp != NULL, "sdStop"); 00171 00172 chSysLock(); 00173 chDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), 00174 "sdStop(), #1", 00175 "invalid state"); 00176 sd_lld_stop(sdp); 00177 sdp->state = SD_STOP; 00178 chOQResetI(&sdp->oqueue); 00179 chIQResetI(&sdp->iqueue); 00180 chSchRescheduleS(); 00181 chSysUnlock(); 00182 } 00183 00184 /** 00185 * @brief Handles incoming data. 00186 * @details This function must be called from the input interrupt service 00187 * routine in order to enqueue incoming data and generate the 00188 * related events. 00189 * @note The incoming data event is only generated when the input queue 00190 * becomes non-empty. 00191 * @note In order to gain some performance it is suggested to not use 00192 * this function directly but copy this code directly into the 00193 * interrupt service routine. 00194 * 00195 * @param[in] sdp pointer to a @p SerialDriver structure 00196 * @param[in] b the byte to be written in the driver's Input Queue 00197 */ 00198 void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { 00199 00200 chDbgCheck(sdp != NULL, "sdIncomingDataI"); 00201 00202 if (chIQIsEmpty(&sdp->iqueue)) 00203 chEvtBroadcastI(&sdp->ievent); 00204 if (chIQPutI(&sdp->iqueue, b) < Q_OK) 00205 sdAddFlagsI(sdp, SD_OVERRUN_ERROR); 00206 } 00207 00208 /** 00209 * @brief Handles outgoing data. 00210 * @details Must be called from the output interrupt service routine in order 00211 * to get the next byte to be transmitted. 00212 * @note In order to gain some performance it is suggested to not use 00213 * this function directly but copy this code directly into the 00214 * interrupt service routine. 00215 * 00216 * @param[in] sdp pointer to a @p SerialDriver structure 00217 * @return The byte value read from the driver's output queue. 00218 * @retval Q_EMPTY if the queue is empty (the lower driver usually 00219 * disables the interrupt source when this happens). 00220 */ 00221 msg_t sdRequestDataI(SerialDriver *sdp) { 00222 msg_t b; 00223 00224 chDbgCheck(sdp != NULL, "sdRequestDataI"); 00225 00226 b = chOQGetI(&sdp->oqueue); 00227 if (b < Q_OK) 00228 chEvtBroadcastI(&sdp->oevent); 00229 return b; 00230 } 00231 00232 /** 00233 * @brief Handles communication events/errors. 00234 * @details Must be called from the I/O interrupt service routine in order to 00235 * notify I/O conditions as errors, signals change etc. 00236 * 00237 * @param[in] sdp pointer to a @p SerialDriver structure 00238 * @param[in] mask condition flags to be added to the mask 00239 */ 00240 void sdAddFlagsI(SerialDriver *sdp, sdflags_t mask) { 00241 00242 chDbgCheck(sdp != NULL, "sdAddFlagsI"); 00243 00244 sdp->flags |= mask; 00245 chEvtBroadcastI(&sdp->sevent); 00246 } 00247 00248 /** 00249 * @brief Returns and clears the errors mask associated to the driver. 00250 * 00251 * @param[in] sdp pointer to a @p SerialDriver structure 00252 * @return The condition flags modified since last time this 00253 * function was invoked. 00254 */ 00255 sdflags_t sdGetAndClearFlags(SerialDriver *sdp) { 00256 sdflags_t mask; 00257 00258 chDbgCheck(sdp != NULL, "sdGetAndClearFlags"); 00259 00260 chSysLock(); 00261 mask = sdp->flags; 00262 sdp->flags = SD_NO_ERROR; 00263 chSysUnlock(); 00264 return mask; 00265 } 00266 00267 #endif /* CH_HAL_USE_SERIAL */ 00268 00269 /** @} */