ChibiOS/HAL  6.1.0
hal_serial.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_serial.c
19  * @brief Serial Driver code.
20  *
21  * @addtogroup SERIAL
22  * @{
23  */
24 
25 #include "hal.h"
26 
27 #if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__)
28 
29 /*===========================================================================*/
30 /* Driver local definitions. */
31 /*===========================================================================*/
32 
33 /*===========================================================================*/
34 /* Driver exported variables. */
35 /*===========================================================================*/
36 
37 /*===========================================================================*/
38 /* Driver local variables and types. */
39 /*===========================================================================*/
40 
41 /*===========================================================================*/
42 /* Driver local functions. */
43 /*===========================================================================*/
44 
45 /*
46  * Interface implementation, the following functions just invoke the equivalent
47  * queue-level function or macro.
48  */
49 
50 static size_t _write(void *ip, const uint8_t *bp, size_t n) {
51 
52  return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp,
53  n, TIME_INFINITE);
54 }
55 
56 static size_t _read(void *ip, uint8_t *bp, size_t n) {
57 
58  return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp,
59  n, TIME_INFINITE);
60 }
61 
62 static msg_t _put(void *ip, uint8_t b) {
63 
64  return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, TIME_INFINITE);
65 }
66 
67 static msg_t _get(void *ip) {
68 
69  return iqGetTimeout(&((SerialDriver *)ip)->iqueue, TIME_INFINITE);
70 }
71 
72 static msg_t _putt(void *ip, uint8_t b, sysinterval_t timeout) {
73 
74  return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout);
75 }
76 
77 static msg_t _gett(void *ip, sysinterval_t timeout) {
78 
79  return iqGetTimeout(&((SerialDriver *)ip)->iqueue, timeout);
80 }
81 
82 static size_t _writet(void *ip, const uint8_t *bp, size_t n,
83  sysinterval_t timeout) {
84 
85  return oqWriteTimeout(&((SerialDriver *)ip)->oqueue, bp, n, timeout);
86 }
87 
88 static size_t _readt(void *ip, uint8_t *bp, size_t n,
89  sysinterval_t timeout) {
90 
91  return iqReadTimeout(&((SerialDriver *)ip)->iqueue, bp, n, timeout);
92 }
93 
94 static msg_t _ctl(void *ip, unsigned int operation, void *arg) {
95  SerialDriver *sdp = (SerialDriver *)ip;
96 
97  osalDbgCheck(sdp != NULL);
98 
99  switch (operation) {
100  case CHN_CTL_NOP:
101  osalDbgCheck(arg == NULL);
102  break;
103  case CHN_CTL_INVALID:
104  osalDbgAssert(false, "invalid CTL operation");
105  break;
106  default:
107 #if defined(SD_LLD_IMPLEMENTS_CTL)
108  /* Delegating to the LLD if supported.*/
109  return sd_lld_control(sdp, operation, arg);
110 #else
111  break;
112 #endif
113  }
114  return MSG_OK;
115 }
116 
117 static const struct SerialDriverVMT vmt = {
118  (size_t)0,
119  _write, _read, _put, _get,
120  _putt, _gett, _writet, _readt,
121  _ctl
122 };
123 
124 /*===========================================================================*/
125 /* Driver exported functions. */
126 /*===========================================================================*/
127 
128 /**
129  * @brief Serial Driver initialization.
130  * @note This function is implicitly invoked by @p halInit(), there is
131  * no need to explicitly initialize the driver.
132  *
133  * @init
134  */
135 void sdInit(void) {
136 
137  sd_lld_init();
138 }
139 
140 /**
141  * @brief Initializes a generic full duplex driver object.
142  * @details The HW dependent part of the initialization has to be performed
143  * outside, usually in the hardware initialization code.
144  *
145  * @param[out] sdp pointer to a @p SerialDriver structure
146  * @param[in] inotify pointer to a callback function that is invoked when
147  * some data is read from the Queue. The value can be
148  * @p NULL.
149  * @param[in] onotify pointer to a callback function that is invoked when
150  * some data is written in the Queue. The value can be
151  * @p NULL.
152  *
153  * @init
154  */
155 #if !defined(SERIAL_ADVANCED_BUFFERING_SUPPORT) || \
156  (SERIAL_ADVANCED_BUFFERING_SUPPORT == FALSE) || \
157  defined(__DOXYGEN__)
158 void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) {
159 
160  sdp->vmt = &vmt;
161  osalEventObjectInit(&sdp->event);
162  sdp->state = SD_STOP;
163  iqObjectInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp);
164  oqObjectInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp);
165 }
166 #else
167 void sdObjectInit(SerialDriver *sdp) {
168 
169  sdp->vmt = &vmt;
170  osalEventObjectInit(&sdp->event);
171  sdp->state = SD_STOP;
172 }
173 #endif
174 
175 /**
176  * @brief Configures and starts the driver.
177  *
178  * @param[in] sdp pointer to a @p SerialDriver object
179  * @param[in] config the architecture-dependent serial driver configuration.
180  * If this parameter is set to @p NULL then a default
181  * configuration is used.
182  *
183  * @api
184  */
185 void sdStart(SerialDriver *sdp, const SerialConfig *config) {
186 
187  osalDbgCheck(sdp != NULL);
188 
189  osalSysLock();
190  osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY),
191  "invalid state");
192  sd_lld_start(sdp, config);
193  sdp->state = SD_READY;
194  osalSysUnlock();
195 }
196 
197 /**
198  * @brief Stops the driver.
199  * @details Any thread waiting on the driver's queues will be awakened with
200  * the message @p MSG_RESET.
201  *
202  * @param[in] sdp pointer to a @p SerialDriver object
203  *
204  * @api
205  */
206 void sdStop(SerialDriver *sdp) {
207 
208  osalDbgCheck(sdp != NULL);
209 
210  osalSysLock();
211 
212  osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY),
213  "invalid state");
214 
215  sd_lld_stop(sdp);
216  sdp->state = SD_STOP;
217  oqResetI(&sdp->oqueue);
218  iqResetI(&sdp->iqueue);
220 
221  osalSysUnlock();
222 }
223 
224 /**
225  * @brief Handles incoming data.
226  * @details This function must be called from the input interrupt service
227  * routine in order to enqueue incoming data and generate the
228  * related events.
229  * @note The incoming data event is only generated when the input queue
230  * becomes non-empty.
231  * @note In order to gain some performance it is suggested to not use
232  * this function directly but copy this code directly into the
233  * interrupt service routine.
234  *
235  * @param[in] sdp pointer to a @p SerialDriver structure
236  * @param[in] b the byte to be written in the driver's Input Queue
237  *
238  * @iclass
239  */
240 void sdIncomingDataI(SerialDriver *sdp, uint8_t b) {
241 
243  osalDbgCheck(sdp != NULL);
244 
245  if (iqIsEmptyI(&sdp->iqueue))
247  if (iqPutI(&sdp->iqueue, b) < MSG_OK)
249 }
250 
251 /**
252  * @brief Handles outgoing data.
253  * @details Must be called from the output interrupt service routine in order
254  * to get the next byte to be transmitted.
255  * @note In order to gain some performance it is suggested to not use
256  * this function directly but copy this code directly into the
257  * interrupt service routine.
258  *
259  * @param[in] sdp pointer to a @p SerialDriver structure
260  * @return The byte value read from the driver's output queue.
261  * @retval MSG_TIMEOUT if the queue is empty (the lower driver usually
262  * disables the interrupt source when this happens).
263  *
264  * @iclass
265  */
267  msg_t b;
268 
270  osalDbgCheck(sdp != NULL);
271 
272  b = oqGetI(&sdp->oqueue);
273  if (b < MSG_OK)
275  return b;
276 }
277 
278 /**
279  * @brief Direct output check on a @p SerialDriver.
280  * @note This function bypasses the indirect access to the channel and
281  * checks directly the output queue. This is faster but cannot
282  * be used to check different channels implementations.
283  *
284  * @param[in] sdp pointer to a @p SerialDriver structure
285  * @return The queue status.
286  * @retval false if the next write operation would not block.
287  * @retval true if the next write operation would block.
288  *
289  * @deprecated
290  *
291  * @api
292  */
294  bool b;
295 
296  osalSysLock();
297  b = oqIsFullI(&sdp->oqueue);
298  osalSysUnlock();
299 
300  return b;
301 }
302 
303 /**
304  * @brief Direct input check on a @p SerialDriver.
305  * @note This function bypasses the indirect access to the channel and
306  * checks directly the input queue. This is faster but cannot
307  * be used to check different channels implementations.
308  *
309  * @param[in] sdp pointer to a @p SerialDriver structure
310  * @return The queue status.
311  * @retval false if the next write operation would not block.
312  * @retval true if the next write operation would block.
313  *
314  * @deprecated
315  *
316  * @api
317  */
319  bool b;
320 
321  osalSysLock();
322  b = iqIsEmptyI(&sdp->iqueue);
323  osalSysUnlock();
324 
325  return b;
326 }
327 
328 /**
329  * @brief Control operation on a serial port.
330  *
331  * @param[in] sdp pointer to a @p SerialDriver object
332  * @param[in] operation control operation code
333  * @param[in,out] arg operation argument
334  *
335  * @return The control operation status.
336  * @retval MSG_OK in case of success.
337  * @retval MSG_TIMEOUT in case of operation timeout.
338  * @retval MSG_RESET in case of operation reset.
339  *
340  * @api
341  */
342 msg_t sdControl(SerialDriver *sdp, unsigned int operation, void *arg) {
343 
344  return _ctl((void *)sdp, operation, arg);
345 }
346 
347 #endif /* HAL_USE_SERIAL == TRUE */
348 
349 /** @} */
#define SERIAL_BUFFERS_SIZE
Serial buffers size.
Definition: hal_serial.h:73
void iqObjectInit(input_queue_t *iqp, uint8_t *bp, size_t size, qnotify_t infy, void *link)
Initializes an input queue.
Definition: hal_queues.c:177
msg_t iqGetTimeout(input_queue_t *iqp, sysinterval_t timeout)
Input queue read with timeout.
Definition: hal_queues.c:304
void sdStart(SerialDriver *sdp, const SerialConfig *config)
Configures and starts the driver.
Definition: hal_serial.c:185
void oqObjectInit(output_queue_t *oqp, uint8_t *bp, size_t size, qnotify_t onfy, void *link)
Initializes an output queue.
Definition: hal_queues.c:446
#define iqIsEmptyI(iqp)
Evaluates to true if the specified input queue is empty.
Definition: hal_queues.h:198
void iqResetI(input_queue_t *iqp)
Resets an input queue.
Definition: hal_queues.c:201
void sdInit(void)
Serial Driver initialization.
Definition: hal_serial.c:135
HAL subsystem header.
bool sdPutWouldBlock(SerialDriver *sdp)
Direct output check on a SerialDriver.
Definition: hal_serial.c:293
#define osalDbgCheckClassI()
I-Class state check.
Definition: osal.h:292
void oqResetI(output_queue_t *oqp)
Resets an output queue.
Definition: hal_queues.c:470
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:540
msg_t sdRequestDataI(SerialDriver *sdp)
Handles outgoing data.
Definition: hal_serial.c:266
void osalOsRescheduleS(void)
Checks if a reschedule is required and performs it.
Definition: osal.c:119
void sd_lld_init(void)
Low level serial driver initialization.
static void osalEventObjectInit(event_source_t *esp)
Initializes an event source object.
Definition: osal.h:665
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config)
Low level serial driver configuration and (re)start.
int32_t msg_t
Type of a message.
Definition: osal.h:160
void(* qnotify_t)(io_queue_t *qp)
Queue notification callback type.
Definition: hal_queues.h:65
const struct SerialDriverVMT * vmt
Virtual Methods Table.
Definition: hal_serial.h:125
size_t oqWriteTimeout(output_queue_t *oqp, const uint8_t *bp, size_t n, sysinterval_t timeout)
Output queue write with timeout.
Definition: hal_queues.c:658
#define oqIsFullI(oqp)
Evaluates to true if the specified output queue is full.
Definition: hal_queues.h:276
msg_t oqPutTimeout(output_queue_t *oqp, uint8_t b, sysinterval_t timeout)
Output queue write with timeout.
Definition: hal_queues.c:540
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
Full duplex serial driver class.
Definition: hal_serial.h:123
SerialDriver virtual methods table.
Definition: hal_serial.h:112
msg_t sdControl(SerialDriver *sdp, unsigned int operation, void *arg)
Control operation on a serial port.
Definition: hal_serial.c:342
uint32_t sysinterval_t
Type of system time interval.
Definition: osal.h:170
msg_t oqGetI(output_queue_t *oqp)
Output queue read.
Definition: hal_queues.c:581
void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify)
Initializes a generic full duplex driver object.
Definition: hal_serial.c:158
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:530
bool sdGetWouldBlock(SerialDriver *sdp)
Direct input check on a SerialDriver.
Definition: hal_serial.c:318
void sd_lld_stop(SerialDriver *sdp)
Low level serial driver stop.
void sdIncomingDataI(SerialDriver *sdp, uint8_t b)
Handles incoming data.
Definition: hal_serial.c:240
#define chnAddFlagsI(ip, flags)
Adds status flags to the listeners&#39;s flags mask.
Definition: hal_channels.h:308
msg_t iqPutI(input_queue_t *iqp, uint8_t b)
Input queue write.
Definition: hal_queues.c:224
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
#define CHN_OUTPUT_EMPTY
Output queue empty.
Definition: hal_channels.h:239
size_t iqReadTimeout(input_queue_t *iqp, uint8_t *bp, size_t n, sysinterval_t timeout)
Input queue read with timeout.
Definition: hal_queues.c:389
#define CHN_INPUT_AVAILABLE
Data available in the input queue.
Definition: hal_channels.h:237
#define SD_QUEUE_FULL_ERROR
Queue full.
Definition: hal_serial.h:43
PLATFORM Serial Driver configuration structure.
void sdStop(SerialDriver *sdp)
Stops the driver.
Definition: hal_serial.c:206