ChibiOS/HAL 9.0.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
50static 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
56static 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
62static msg_t _put(void *ip, uint8_t b) {
63
64 return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, TIME_INFINITE);
65}
66
67static msg_t _get(void *ip) {
68
69 return iqGetTimeout(&((SerialDriver *)ip)->iqueue, TIME_INFINITE);
70}
71
72static msg_t _putt(void *ip, uint8_t b, sysinterval_t timeout) {
73
74 return oqPutTimeout(&((SerialDriver *)ip)->oqueue, b, timeout);
75}
76
77static msg_t _gett(void *ip, sysinterval_t timeout) {
78
79 return iqGetTimeout(&((SerialDriver *)ip)->iqueue, timeout);
80}
81
82static 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
88static 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
94static 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 return HAL_RET_UNKNOWN_CTL;
105 default:
106#if defined(SD_LLD_IMPLEMENTS_CTL)
107 /* Delegating to the LLD if supported.*/
108 return sd_lld_control(sdp, operation, arg);
109#else
110 return HAL_RET_UNKNOWN_CTL;
111#endif
112 }
113 return HAL_RET_SUCCESS;
114}
115
116static const struct SerialDriverVMT vmt = {
117 (size_t)0,
120 _ctl
121};
122
123/*===========================================================================*/
124/* Driver exported functions. */
125/*===========================================================================*/
126
127/**
128 * @brief Serial Driver initialization.
129 * @note This function is implicitly invoked by @p halInit(), there is
130 * no need to explicitly initialize the driver.
131 *
132 * @init
133 */
134void sdInit(void) {
135
136 sd_lld_init();
137}
138
139/**
140 * @brief Initializes a generic serial driver object.
141 * @details The HW dependent part of the initialization has to be performed
142 * outside, usually in the hardware initialization code.
143 *
144 * @param[out] sdp pointer to a @p SerialDriver structure
145 * @param[in] inotify pointer to a callback function that is invoked when
146 * some data is read from the Queue. The value can be
147 * @p NULL.
148 * @param[in] onotify pointer to a callback function that is invoked when
149 * some data is written in the Queue. The value can be
150 * @p NULL.
151 *
152 * @init
153 */
154#if !defined(SERIAL_ADVANCED_BUFFERING_SUPPORT) || \
155 (SERIAL_ADVANCED_BUFFERING_SUPPORT == FALSE) || \
156 defined(__DOXYGEN__)
157void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) {
158
159 sdp->vmt = &vmt;
160 osalEventObjectInit(&sdp->event);
161 sdp->state = SD_STOP;
162 iqObjectInit(&sdp->iqueue, sdp->ib, SERIAL_BUFFERS_SIZE, inotify, sdp);
163 oqObjectInit(&sdp->oqueue, sdp->ob, SERIAL_BUFFERS_SIZE, onotify, sdp);
164}
165#else
166void sdObjectInit(SerialDriver *sdp) {
167
168 sdp->vmt = &vmt;
169 osalEventObjectInit(&sdp->event);
170 sdp->state = SD_STOP;
171}
172#endif
173
174/**
175 * @brief Configures and starts the driver.
176 *
177 * @param[in] sdp pointer to a @p SerialDriver object
178 * @param[in] config the architecture-dependent serial driver configuration.
179 * If this parameter is set to @p NULL then a default
180 * configuration is used.
181 * @return The operation status.
182 *
183 * @api
184 */
186 msg_t msg;
187
188 osalDbgCheck(sdp != NULL);
189
190 osalSysLock();
191 osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY),
192 "invalid state");
193
194#if defined(SD_LLD_ENHANCED_API)
195 msg = sd_lld_start(sdp, config);
196 if (msg == HAL_RET_SUCCESS) {
197 sdp->state = SD_READY;
198 }
199 else {
200 sdp->state = SD_STOP;
201 }
202#else
203 sd_lld_start(sdp, config);
204 sdp->state = SD_READY;
205 msg = HAL_RET_SUCCESS;
206#endif
207
209
210 return msg;
211}
212
213/**
214 * @brief Stops the driver.
215 * @details Any thread waiting on the driver's queues will be awakened with
216 * the message @p MSG_RESET.
217 *
218 * @param[in] sdp pointer to a @p SerialDriver object
219 *
220 * @api
221 */
223
224 osalDbgCheck(sdp != NULL);
225
226 osalSysLock();
227
228 osalDbgAssert((sdp->state == SD_STOP) || (sdp->state == SD_READY),
229 "invalid state");
230
231 sd_lld_stop(sdp);
232 sdp->state = SD_STOP;
233 oqResetI(&sdp->oqueue);
234 iqResetI(&sdp->iqueue);
236
238}
239
240/**
241 * @brief Handles incoming data.
242 * @details This function must be called from the input interrupt service
243 * routine in order to enqueue incoming data and generate the
244 * related events.
245 * @note The incoming data event is only generated when the input queue
246 * becomes non-empty.
247 * @note In order to gain some performance it is suggested to not use
248 * this function directly but copy this code directly into the
249 * interrupt service routine.
250 *
251 * @param[in] sdp pointer to a @p SerialDriver structure
252 * @param[in] b the byte to be written in the driver's Input Queue
253 *
254 * @iclass
255 */
256void sdIncomingDataI(SerialDriver *sdp, uint8_t b) {
257
259 osalDbgCheck(sdp != NULL);
260
261 if (iqIsEmptyI(&sdp->iqueue))
263 if (iqPutI(&sdp->iqueue, b) < MSG_OK)
265}
266
267/**
268 * @brief Handles outgoing data.
269 * @details Must be called from the output interrupt service routine in order
270 * to get the next byte to be transmitted.
271 * @note In order to gain some performance it is suggested to not use
272 * this function directly but copy this code directly into the
273 * interrupt service routine.
274 *
275 * @param[in] sdp pointer to a @p SerialDriver structure
276 * @return The byte value read from the driver's output queue.
277 * @retval MSG_TIMEOUT if the queue is empty (the lower driver usually
278 * disables the interrupt source when this happens).
279 *
280 * @iclass
281 */
283 msg_t b;
284
286 osalDbgCheck(sdp != NULL);
287
288 b = oqGetI(&sdp->oqueue);
289 if (b < MSG_OK)
291 return b;
292}
293
294/**
295 * @brief Direct output check on a @p SerialDriver.
296 * @note This function bypasses the indirect access to the channel and
297 * checks directly the output queue. This is faster but cannot
298 * be used to check different channels implementations.
299 *
300 * @param[in] sdp pointer to a @p SerialDriver structure
301 * @return The queue status.
302 * @retval false if the next write operation would not block.
303 * @retval true if the next write operation would block.
304 *
305 * @deprecated
306 *
307 * @api
308 */
310 bool b;
311
312 osalSysLock();
313 b = oqIsFullI(&sdp->oqueue);
315
316 return b;
317}
318
319/**
320 * @brief Direct input check on a @p SerialDriver.
321 * @note This function bypasses the indirect access to the channel and
322 * checks directly the input queue. This is faster but cannot
323 * be used to check different channels implementations.
324 *
325 * @param[in] sdp pointer to a @p SerialDriver structure
326 * @return The queue status.
327 * @retval false if the next write operation would not block.
328 * @retval true if the next write operation would block.
329 *
330 * @deprecated
331 *
332 * @api
333 */
335 bool b;
336
337 osalSysLock();
338 b = iqIsEmptyI(&sdp->iqueue);
340
341 return b;
342}
343
344/**
345 * @brief Control operation on a serial port.
346 *
347 * @param[in] sdp pointer to a @p SerialDriver object
348 * @param[in] operation control operation code
349 * @param[in,out] arg operation argument
350 *
351 * @return The control operation status.
352 * @retval MSG_OK in case of success.
353 * @retval MSG_TIMEOUT in case of operation timeout.
354 * @retval MSG_RESET in case of operation reset.
355 *
356 * @api
357 */
358msg_t sdControl(SerialDriver *sdp, unsigned int operation, void *arg) {
359
360 return _ctl((void *)sdp, operation, arg);
361}
362
363#endif /* HAL_USE_SERIAL == TRUE */
364
365/** @} */
static const struct EFlashDriverVMT vmt
Definition hal_efl.c:71
void iqResetI(input_queue_t *iqp)
Resets an input queue.
Definition hal_queues.c:201
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:651
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:302
#define iqIsEmptyI(iqp)
Evaluates to true if the specified input queue is empty.
Definition hal_queues.h:198
msg_t iqPutI(input_queue_t *iqp, uint8_t b)
Input queue write.
Definition hal_queues.c:224
void oqResetI(output_queue_t *oqp)
Resets an output queue.
Definition hal_queues.c:467
void(* qnotify_t)(io_queue_t *qp)
Queue notification callback type.
Definition hal_queues.h:65
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:386
msg_t oqPutTimeout(output_queue_t *oqp, uint8_t b, sysinterval_t timeout)
Output queue write with timeout.
Definition hal_queues.c:535
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:443
msg_t oqGetI(output_queue_t *oqp)
Output queue read.
Definition hal_queues.c:576
#define oqIsFullI(oqp)
Evaluates to true if the specified output queue is full.
Definition hal_queues.h:276
#define HAL_RET_SUCCESS
Definition hal.h:93
#define HAL_RET_UNKNOWN_CTL
Unknown control code.
Definition hal.h:119
#define CHN_OUTPUT_EMPTY
Output queue empty.
#define CHN_CTL_INVALID
Invalid operation code.
#define CHN_INPUT_AVAILABLE
Data available in the input queue.
#define CHN_CTL_NOP
Does nothing.
#define chnAddFlagsI(ip, flags)
Adds status flags to the listeners's flags mask.
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition osal.h:601
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition osal.h:611
int32_t msg_t
Type of a message.
Definition osal.h:159
uint32_t sysinterval_t
Type of system time interval.
Definition osal.h:169
#define MSG_OK
Definition osal.h:56
void osalOsRescheduleS(void)
Checks if a reschedule is required and performs it.
Definition osal.c:119
static void osalEventObjectInit(event_source_t *esp)
Initializes an event source object.
Definition osal.h:737
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define TIME_INFINITE
Definition osal.h:66
#define osalDbgCheckClassI()
I-Class state check.
Definition osal.h:298
static size_t _writet(void *ip, const uint8_t *bp, size_t n, sysinterval_t timeout)
Definition hal_serial.c:82
static msg_t _get(void *ip)
Definition hal_serial.c:67
static msg_t _gett(void *ip, sysinterval_t timeout)
Definition hal_serial.c:77
static msg_t _ctl(void *ip, unsigned int operation, void *arg)
Definition hal_serial.c:94
static msg_t _put(void *ip, uint8_t b)
Definition hal_serial.c:62
msg_t sdStart(SerialDriver *sdp, const SerialConfig *config)
Configures and starts the driver.
Definition hal_serial.c:185
struct hal_serial_driver SerialDriver
Structure representing a serial driver.
Definition hal_serial.h:97
static size_t _write(void *ip, const uint8_t *bp, size_t n)
Definition hal_serial.c:50
static msg_t _putt(void *ip, uint8_t b, sysinterval_t timeout)
Definition hal_serial.c:72
#define SERIAL_BUFFERS_SIZE
Serial buffers size.
Definition hal_serial.h:73
msg_t sdControl(SerialDriver *sdp, unsigned int operation, void *arg)
Control operation on a serial port.
Definition hal_serial.c:358
static size_t _readt(void *ip, uint8_t *bp, size_t n, sysinterval_t timeout)
Definition hal_serial.c:88
bool sdGetWouldBlock(SerialDriver *sdp)
Direct input check on a SerialDriver.
Definition hal_serial.c:334
#define SD_QUEUE_FULL_ERROR
Definition hal_serial.h:43
static size_t _read(void *ip, uint8_t *bp, size_t n)
Definition hal_serial.c:56
void sdIncomingDataI(SerialDriver *sdp, uint8_t b)
Handles incoming data.
Definition hal_serial.c:256
void sdStop(SerialDriver *sdp)
Stops the driver.
Definition hal_serial.c:222
void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify)
Initializes a generic serial driver object.
Definition hal_serial.c:157
struct hal_serial_config SerialConfig
PLATFORM Serial Driver configuration structure.
void sd_lld_start(SerialDriver *sdp, const SerialConfig *config)
Low level serial driver configuration and (re)start.
void sdInit(void)
Serial Driver initialization.
Definition hal_serial.c:134
void sd_lld_init(void)
Low level serial driver initialization.
bool sdPutWouldBlock(SerialDriver *sdp)
Direct output check on a SerialDriver.
Definition hal_serial.c:309
void sd_lld_stop(SerialDriver *sdp)
Low level serial driver stop.
msg_t sdRequestDataI(SerialDriver *sdp)
Handles outgoing data.
Definition hal_serial.c:282
@ SD_STOP
Definition hal_serial.h:90
@ SD_READY
Definition hal_serial.h:91
HAL subsystem header.
SerialDriver virtual methods table.
Definition hal_serial.h:112
const struct SerialDriverVMT * vmt
Virtual Methods Table.
Definition hal_serial.h:125