|
ChibiOS/RT
2.5.1 |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012 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 * @file serial.c 00023 * @brief Serial Driver code. 00024 * 00025 * @addtogroup SERIAL 00026 * @{ 00027 */ 00028 00029 #include "ch.h" 00030 #include "hal.h" 00031 00032 #if HAL_USE_SERIAL || defined(__DOXYGEN__) 00033 00034 /*===========================================================================*/ 00035 /* Driver local definitions. */ 00036 /*===========================================================================*/ 00037 00038 /*===========================================================================*/ 00039 /* Driver exported variables. */ 00040 /*===========================================================================*/ 00041 00042 /*===========================================================================*/ 00043 /* Driver local variables. */ 00044 /*===========================================================================*/ 00045 00046 /*===========================================================================*/ 00047 /* Driver local functions. */ 00048 /*===========================================================================*/ 00049 00050 /* 00051 * Interface implementation, the following functions just invoke the equivalent 00052 * queue-level function or macro. 00053 */ 00054 00055 static size_t write(void *ip, const uint8_t *bp, size_t n) { 00056 00057 return chOQWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, 00058 n, TIME_INFINITE); 00059 } 00060 00061 static size_t read(void *ip, uint8_t *bp, size_t n) { 00062 00063 return chIQReadTimeout(&((SerialDriver *)ip)->iqueue, bp, 00064 n, TIME_INFINITE); 00065 } 00066 00067 static msg_t put(void *ip, uint8_t b) { 00068 00069 return chOQPutTimeout(&((SerialDriver *)ip)->oqueue, b, TIME_INFINITE); 00070 } 00071 00072 static msg_t get(void *ip) { 00073 00074 return chIQGetTimeout(&((SerialDriver *)ip)->iqueue, TIME_INFINITE); 00075 } 00076 00077 static msg_t putt(void *ip, uint8_t b, systime_t timeout) { 00078 00079 return chOQPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout); 00080 } 00081 00082 static msg_t gett(void *ip, systime_t timeout) { 00083 00084 return chIQGetTimeout(&((SerialDriver *)ip)->iqueue, timeout); 00085 } 00086 00087 static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t time) { 00088 00089 return chOQWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, n, time); 00090 } 00091 00092 static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t time) { 00093 00094 return chIQReadTimeout(&((SerialDriver *)ip)->iqueue, bp, n, time); 00095 } 00096 00097 static const struct SerialDriverVMT vmt = { 00098 write, read, put, get, 00099 putt, gett, writet, readt 00100 }; 00101 00102 /*===========================================================================*/ 00103 /* Driver exported functions. */ 00104 /*===========================================================================*/ 00105 00106 /** 00107 * @brief Serial Driver initialization. 00108 * @note This function is implicitly invoked by @p halInit(), there is 00109 * no need to explicitly initialize the driver. 00110 * 00111 * @init 00112 */ 00113 void sdInit(void) { 00114 00115 sd_lld_init(); 00116 } 00117 00118 /** 00119 * @brief Initializes a generic full duplex driver object. 00120 * @details The HW dependent part of the initialization has to be performed 00121 * outside, usually in the hardware initialization code. 00122 * 00123 * @param[out] sdp pointer to a @p SerialDriver structure 00124 * @param[in] inotify pointer to a callback function that is invoked when 00125 * some data is read from the Queue. The value can be 00126 * @p NULL. 00127 * @param[in] onotify pointer to a callback function that is invoked when 00128 * some data is written in the Queue. The value can be 00129 * @p NULL. 00130 * 00131 * @init 00132 */ 00133 void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) { 00134 00135 sdp->vmt = &vmt; 00136 chEvtInit(&sdp->event); 00137 sdp->state = SD_STOP; 00138 chIQInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp); 00139 chOQInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp); 00140 } 00141 00142 /** 00143 * @brief Configures and starts the driver. 00144 * 00145 * @param[in] sdp pointer to a @p SerialDriver object 00146 * @param[in] config the architecture-dependent serial driver configuration. 00147 * If this parameter is set to @p NULL then a default 00148 * configuration is used. 00149 * 00150 * @api 00151 */ 00152 void sdStart(SerialDriver *sdp, const SerialConfig *config) { 00153 00154 chDbgCheck(sdp != NULL, "sdStart"); 00155 00156 chSysLock(); 00157 chDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), 00158 "sdStart(), #1", 00159 "invalid state"); 00160 sd_lld_start(sdp, config); 00161 sdp->state = SD_READY; 00162 chSysUnlock(); 00163 } 00164 00165 /** 00166 * @brief Stops the driver. 00167 * @details Any thread waiting on the driver's queues will be awakened with 00168 * the message @p Q_RESET. 00169 * 00170 * @param[in] sdp pointer to a @p SerialDriver object 00171 * 00172 * @api 00173 */ 00174 void sdStop(SerialDriver *sdp) { 00175 00176 chDbgCheck(sdp != NULL, "sdStop"); 00177 00178 chSysLock(); 00179 chDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY), 00180 "sdStop(), #1", 00181 "invalid state"); 00182 sd_lld_stop(sdp); 00183 sdp->state = SD_STOP; 00184 chOQResetI(&sdp->oqueue); 00185 chIQResetI(&sdp->iqueue); 00186 chSchRescheduleS(); 00187 chSysUnlock(); 00188 } 00189 00190 /** 00191 * @brief Handles incoming data. 00192 * @details This function must be called from the input interrupt service 00193 * routine in order to enqueue incoming data and generate the 00194 * related events. 00195 * @note The incoming data event is only generated when the input queue 00196 * becomes non-empty. 00197 * @note In order to gain some performance it is suggested to not use 00198 * this function directly but copy this code directly into the 00199 * interrupt service routine. 00200 * 00201 * @param[in] sdp pointer to a @p SerialDriver structure 00202 * @param[in] b the byte to be written in the driver's Input Queue 00203 * 00204 * @iclass 00205 */ 00206 void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { 00207 00208 chDbgCheckClassI(); 00209 chDbgCheck(sdp != NULL, "sdIncomingDataI"); 00210 00211 if (chIQIsEmptyI(&sdp->iqueue)) 00212 chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); 00213 if (chIQPutI(&sdp->iqueue, b) < Q_OK) 00214 chnAddFlagsI(sdp, SD_OVERRUN_ERROR); 00215 } 00216 00217 /** 00218 * @brief Handles outgoing data. 00219 * @details Must be called from the output interrupt service routine in order 00220 * to get the next byte to be transmitted. 00221 * @note In order to gain some performance it is suggested to not use 00222 * this function directly but copy this code directly into the 00223 * interrupt service routine. 00224 * 00225 * @param[in] sdp pointer to a @p SerialDriver structure 00226 * @return The byte value read from the driver's output queue. 00227 * @retval Q_EMPTY if the queue is empty (the lower driver usually 00228 * disables the interrupt source when this happens). 00229 * 00230 * @iclass 00231 */ 00232 msg_t sdRequestDataI(SerialDriver *sdp) { 00233 msg_t b; 00234 00235 chDbgCheckClassI(); 00236 chDbgCheck(sdp != NULL, "sdRequestDataI"); 00237 00238 b = chOQGetI(&sdp->oqueue); 00239 if (b < Q_OK) 00240 chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); 00241 return b; 00242 } 00243 00244 #endif /* HAL_USE_SERIAL */ 00245 00246 /** @} */