2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_COM COM layer functions
6 * @brief Hardware communication layer
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
11 * Parts by Thorsten Klose (tk@midibox.org)
12 * @brief COM layer functions
13 * @see The GNU Public License (GPL) Version 3
15 *****************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 /* Project Includes */
35 #if defined(PIOS_INCLUDE_COM)
37 #include "fifo_buffer.h"
38 #include <pios_com_priv.h>
40 #if !defined(PIOS_INCLUDE_FREERTOS)
41 #include "pios_delay.h" /* PIOS_DELAY_WaitmS */
44 enum pios_com_dev_magic
{
45 PIOS_COM_DEV_MAGIC
= 0xaa55aa55,
49 enum pios_com_dev_magic magic
;
51 const struct pios_com_driver
*driver
;
53 #if defined(PIOS_INCLUDE_FREERTOS)
54 xSemaphoreHandle tx_sem
;
55 xSemaphoreHandle rx_sem
;
65 static bool PIOS_COM_validate(struct pios_com_dev
*com_dev
)
67 return com_dev
&& (com_dev
->magic
== PIOS_COM_DEV_MAGIC
);
70 #if defined(PIOS_INCLUDE_FREERTOS) && 0
71 // static struct pios_com_dev * PIOS_COM_alloc(void)
73 // struct pios_com_dev * com_dev;
75 // com_dev = (struct pios_com_dev *)malloc(sizeof(*com_dev));
76 // if (!com_dev) return (NULL);
78 // com_dev->magic = PIOS_COM_DEV_MAGIC;
82 static struct pios_com_dev pios_com_devs
[PIOS_COM_MAX_DEVS
];
83 static uint8_t pios_com_num_devs
;
84 static uint32_t PIOS_COM_create(void)
86 struct pios_com_dev
*com_dev
;
88 if (pios_com_num_devs
>= PIOS_COM_MAX_DEVS
) {
89 return PIOS_COM_MAX_DEVS
+ 1;
92 com_dev
= &pios_com_devs
[pios_com_num_devs
++];
93 com_dev
->magic
= PIOS_COM_DEV_MAGIC
;
95 return pios_com_num_devs
;
97 static struct pios_com_dev
*PIOS_COM_find_dev(uint32_t com_dev_id
)
102 if (com_dev_id
> pios_com_num_devs
+ 1) {
105 return &pios_com_devs
[com_dev_id
- 1];
107 #endif /* if defined(PIOS_INCLUDE_FREERTOS) && 0 */
109 static uint16_t PIOS_COM_TxOutCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, bool *need_yield
);
110 static uint16_t PIOS_COM_RxInCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, bool *need_yield
);
111 static void PIOS_COM_UnblockRx(struct pios_com_dev
*com_dev
, bool *need_yield
);
112 static void PIOS_COM_UnblockTx(struct pios_com_dev
*com_dev
, bool *need_yield
);
115 * Initialises COM layer
119 * \return < 0 if initialisation failed
121 int32_t PIOS_COM_Init(uint32_t *com_id
, const struct pios_com_driver
*driver
, uint32_t lower_id
, uint8_t *rx_buffer
, uint16_t rx_buffer_len
, uint8_t *tx_buffer
, uint16_t tx_buffer_len
)
126 bool has_rx
= (rx_buffer
&& rx_buffer_len
> 0);
127 bool has_tx
= (tx_buffer
&& tx_buffer_len
> 0);
128 PIOS_Assert(has_rx
|| has_tx
);
129 PIOS_Assert(driver
->bind_tx_cb
|| !has_tx
);
130 PIOS_Assert(driver
->bind_rx_cb
|| !has_rx
);
133 struct pios_com_dev
*com_dev
;
135 com_dev_id
= PIOS_COM_create();
136 com_dev
= PIOS_COM_find_dev(com_dev_id
);
141 com_dev
->driver
= driver
;
142 com_dev
->lower_id
= lower_id
;
144 com_dev
->has_rx
= has_rx
;
145 com_dev
->has_tx
= has_tx
;
148 fifoBuf_init(&com_dev
->rx
, rx_buffer
, rx_buffer_len
);
149 #if defined(PIOS_INCLUDE_FREERTOS)
150 vSemaphoreCreateBinary(com_dev
->rx_sem
);
151 #endif /* PIOS_INCLUDE_FREERTOS */
152 (com_dev
->driver
->bind_rx_cb
)(lower_id
, PIOS_COM_RxInCallback
, com_dev_id
);
153 if (com_dev
->driver
->rx_start
) {
154 /* Start the receiver */
155 (com_dev
->driver
->rx_start
)(com_dev
->lower_id
,
156 fifoBuf_getFree(&com_dev
->rx
));
161 fifoBuf_init(&com_dev
->tx
, tx_buffer
, tx_buffer_len
);
162 #if defined(PIOS_INCLUDE_FREERTOS)
163 vSemaphoreCreateBinary(com_dev
->tx_sem
);
164 #endif /* PIOS_INCLUDE_FREERTOS */
165 (com_dev
->driver
->bind_tx_cb
)(lower_id
, PIOS_COM_TxOutCallback
, com_dev_id
);
168 *com_id
= com_dev_id
;
175 static void PIOS_COM_UnblockRx(struct pios_com_dev
*com_dev
, bool *need_yield
)
177 #if defined(PIOS_INCLUDE_FREERTOS)
178 static signed portBASE_TYPE xHigherPriorityTaskWoken
;
179 xSemaphoreGiveFromISR(com_dev
->rx_sem
, &xHigherPriorityTaskWoken
);
181 if (xHigherPriorityTaskWoken
!= pdFALSE
) {
191 static void PIOS_COM_UnblockTx(struct pios_com_dev
*com_dev
, bool *need_yield
)
193 #if defined(PIOS_INCLUDE_FREERTOS)
194 static signed portBASE_TYPE xHigherPriorityTaskWoken
;
195 xSemaphoreGiveFromISR(com_dev
->tx_sem
, &xHigherPriorityTaskWoken
);
197 if (xHigherPriorityTaskWoken
!= pdFALSE
) {
207 static uint16_t PIOS_COM_RxInCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, bool *need_yield
)
209 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(context
);
211 bool valid
= PIOS_COM_validate(com_dev
);
214 PIOS_Assert(com_dev
->has_rx
);
217 uint16_t bytes_into_fifo
= fifoBuf_putData(&com_dev
->rx
, buf
, buf_len
);
220 if (bytes_into_fifo
> 0) {
221 /* Data has been added to the buffer */
222 PIOS_COM_UnblockRx(com_dev
, need_yield
);
226 *headroom
= fifoBuf_getFree(&com_dev
->rx
);
229 return bytes_into_fifo
;
232 static uint16_t PIOS_COM_TxOutCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, bool *need_yield
)
234 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(context
);
236 bool valid
= PIOS_COM_validate(com_dev
);
240 PIOS_Assert(buf_len
);
241 PIOS_Assert(com_dev
->has_tx
);
244 uint16_t bytes_from_fifo
= fifoBuf_getData(&com_dev
->tx
, buf
, buf_len
);
247 if (bytes_from_fifo
> 0) {
248 /* More space has been made in the buffer */
249 PIOS_COM_UnblockTx(com_dev
, need_yield
);
253 *headroom
= fifoBuf_getUsed(&com_dev
->tx
);
256 return bytes_from_fifo
;
260 * Change the port speed without re-initializing
261 * \param[in] port COM port
262 * \param[in] baud Requested baud rate
263 * \return -1 if port not available
264 * \return 0 on success
266 int32_t PIOS_COM_ChangeBaud(uint32_t com_id
, uint32_t baud
)
268 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(com_id
);
270 if (!PIOS_COM_validate(com_dev
)) {
271 /* Undefined COM port for this board (see pios_board.c) */
275 /* Invoke the driver function if it exists */
276 if (com_dev
->driver
->set_baud
) {
277 com_dev
->driver
->set_baud(com_dev
->lower_id
, baud
);
284 * Sends a package over given port
285 * \param[in] port COM port
286 * \param[in] buffer character buffer
287 * \param[in] len buffer length
288 * \return -1 if port not available
289 * \return -2 if non-blocking mode activated: buffer is full
290 * caller should retry until buffer is free again
291 * \return 0 on success
293 int32_t PIOS_COM_SendBufferNonBlocking(uint32_t com_id
, const uint8_t *buffer
, uint16_t len
)
295 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(com_id
);
297 if (!PIOS_COM_validate(com_dev
)) {
298 /* Undefined COM port for this board (see pios_board.c) */
302 PIOS_Assert(com_dev
->has_tx
);
304 if (len
>= fifoBuf_getFree(&com_dev
->tx
)) {
305 /* Buffer cannot accept all requested bytes (retry) */
310 uint16_t bytes_into_fifo
= fifoBuf_putData(&com_dev
->tx
, buffer
, len
);
313 if (bytes_into_fifo
> 0) {
314 /* More data has been put in the tx buffer, make sure the tx is started */
315 if (com_dev
->driver
->tx_start
) {
316 com_dev
->driver
->tx_start(com_dev
->lower_id
,
317 fifoBuf_getUsed(&com_dev
->tx
));
325 * Sends a package over given port
326 * (blocking function)
327 * \param[in] port COM port
328 * \param[in] buffer character buffer
329 * \param[in] len buffer length
330 * \return -1 if port not available
331 * \return 0 on success
333 int32_t PIOS_COM_SendBuffer(uint32_t com_id
, const uint8_t *buffer
, uint16_t len
)
335 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(com_id
);
337 if (!PIOS_COM_validate(com_dev
)) {
338 /* Undefined COM port for this board (see pios_board.c) */
342 PIOS_Assert(com_dev
->has_tx
);
346 rc
= PIOS_COM_SendBufferNonBlocking(com_id
, buffer
, len
);
348 #if defined(PIOS_INCLUDE_FREERTOS)
350 /* Make sure the transmitter is running while we wait */
351 if (com_dev
->driver
->tx_start
) {
352 (com_dev
->driver
->tx_start
)(com_dev
->lower_id
,
353 fifoBuf_getUsed(&com_dev
->tx
));
355 if (xSemaphoreTake(com_dev
->tx_sem
, portMAX_DELAY
) != pdTRUE
) {
366 * Sends a single character over given port
367 * \param[in] port COM port
368 * \param[in] c character
369 * \return -1 if port not available
370 * \return -2 buffer is full
371 * caller should retry until buffer is free again
372 * \return 0 on success
374 int32_t PIOS_COM_SendCharNonBlocking(uint32_t com_id
, char c
)
376 return PIOS_COM_SendBufferNonBlocking(com_id
, (uint8_t *)&c
, 1);
380 * Sends a single character over given port
381 * (blocking function)
382 * \param[in] port COM port
383 * \param[in] c character
384 * \return -1 if port not available
385 * \return 0 on success
387 int32_t PIOS_COM_SendChar(uint32_t com_id
, char c
)
389 return PIOS_COM_SendBuffer(com_id
, (uint8_t *)&c
, 1);
393 * Sends a string over given port
394 * \param[in] port COM port
395 * \param[in] str zero-terminated string
396 * \return -1 if port not available
397 * \return -2 buffer is full
398 * caller should retry until buffer is free again
399 * \return 0 on success
401 int32_t PIOS_COM_SendStringNonBlocking(uint32_t com_id
, const char *str
)
403 return PIOS_COM_SendBufferNonBlocking(com_id
, (uint8_t *)str
, (uint16_t)strlen(str
));
407 * Sends a string over given port
408 * (blocking function)
409 * \param[in] port COM port
410 * \param[in] str zero-terminated string
411 * \return -1 if port not available
412 * \return 0 on success
414 int32_t PIOS_COM_SendString(uint32_t com_id
, const char *str
)
416 return PIOS_COM_SendBuffer(com_id
, (uint8_t *)str
, strlen(str
));
420 * Sends a formatted string (-> printf) over given port
421 * \param[in] port COM port
422 * \param[in] *format zero-terminated format string - 128 characters supported maximum!
423 * \param[in] ... optional arguments,
424 * 128 characters supported maximum!
425 * \return -2 if non-blocking mode activated: buffer is full
426 * caller should retry until buffer is free again
427 * \return 0 on success
429 int32_t PIOS_COM_SendFormattedStringNonBlocking(uint32_t com_id
, const char *format
, ...)
431 uint8_t buffer
[128]; // TODO: tmp!!! Provide a streamed COM method later!
435 va_start(args
, format
);
436 vsprintf((char *)buffer
, format
, args
);
437 return PIOS_COM_SendBufferNonBlocking(com_id
, buffer
, (uint16_t)strlen((char *)buffer
));
441 * Sends a formatted string (-> printf) over given port
442 * (blocking function)
443 * \param[in] port COM port
444 * \param[in] *format zero-terminated format string - 128 characters supported maximum!
445 * \param[in] ... optional arguments,
446 * \return -1 if port not available
447 * \return 0 on success
449 int32_t PIOS_COM_SendFormattedString(uint32_t com_id
, const char *format
, ...)
451 uint8_t buffer
[128]; // TODO: tmp!!! Provide a streamed COM method later!
454 va_start(args
, format
);
455 vsprintf((char *)buffer
, format
, args
);
456 return PIOS_COM_SendBuffer(com_id
, buffer
, (uint16_t)strlen((char *)buffer
));
460 * Transfer bytes from port buffers into another buffer
461 * \param[in] port COM port
462 * \returns Byte from buffer
464 uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id
, uint8_t *buf
, uint16_t buf_len
, uint32_t timeout_ms
)
467 PIOS_Assert(buf_len
);
469 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(com_id
);
471 if (!PIOS_COM_validate(com_dev
)) {
472 /* Undefined COM port for this board (see pios_board.c) */
475 PIOS_Assert(com_dev
->has_rx
);
479 uint16_t bytes_from_fifo
= fifoBuf_getData(&com_dev
->rx
, buf
, buf_len
);
482 if (bytes_from_fifo
== 0 && timeout_ms
> 0) {
483 /* No more bytes in receive buffer */
484 /* Make sure the receiver is running while we wait */
485 if (com_dev
->driver
->rx_start
) {
486 /* Notify the lower layer that there is now room in the rx buffer */
487 (com_dev
->driver
->rx_start
)(com_dev
->lower_id
,
488 fifoBuf_getFree(&com_dev
->rx
));
490 #if defined(PIOS_INCLUDE_FREERTOS)
491 if (xSemaphoreTake(com_dev
->rx_sem
, timeout_ms
/ portTICK_RATE_MS
) == pdTRUE
) {
492 /* Make sure we don't come back here again */
497 PIOS_DELAY_WaitmS(1);
503 /* Return received byte */
504 return bytes_from_fifo
;
508 * Query if a com port is available for use. That can be
509 * used to check a link is established even if the device
512 uint32_t PIOS_COM_Available(uint32_t com_id
)
514 struct pios_com_dev
*com_dev
= PIOS_COM_find_dev(com_id
);
516 if (!PIOS_COM_validate(com_dev
)) {
517 return COM_AVAILABLE_NONE
;
520 // If a driver does not provide a query method assume always
521 // available if valid
522 if (com_dev
->driver
->available
== NULL
) {
523 if (com_dev
->has_rx
&& com_dev
->has_tx
) {
524 return COM_AVAILABLE_RXTX
;
525 } else if (com_dev
->has_rx
) {
526 return COM_AVAILABLE_RX
;
527 } else if (com_dev
->has_tx
) {
528 return COM_AVAILABLE_TX
;
531 return COM_AVAILABLE_NONE
; /* can this really happen? */
534 return (com_dev
->driver
->available
)(com_dev
->lower_id
);
537 #endif /* if defined(PIOS_INCLUDE_COM) */