2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_COM COM MSG layer functions
6 * @brief Hardware communication layer
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
11 * @brief COM MSG layer functions
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #ifdef PIOS_INCLUDE_COM_MSG
37 #define PIOS_COM_MSG_MAX_LEN 63
39 struct pios_com_msg_dev
{
41 const struct pios_com_driver
*driver
;
43 uint8_t rx_msg_buffer
[PIOS_COM_MSG_MAX_LEN
];
44 volatile bool rx_msg_full
;
46 uint8_t tx_msg_buffer
[PIOS_COM_MSG_MAX_LEN
];
47 volatile bool tx_msg_full
;
50 static struct pios_com_msg_dev com_msg_dev
;
52 static uint16_t PIOS_COM_MSG_TxOutCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, bool *need_yield
);
53 static uint16_t PIOS_COM_MSG_RxInCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, bool *need_yield
);
55 int32_t PIOS_COM_MSG_Init(uint32_t *com_id
, const struct pios_com_driver
*driver
, uint32_t lower_id
)
60 PIOS_Assert(driver
->bind_tx_cb
);
61 PIOS_Assert(driver
->bind_rx_cb
);
63 struct pios_com_msg_dev
*com_dev
= &com_msg_dev
;
65 com_dev
->driver
= driver
;
66 com_dev
->lower_id
= lower_id
;
68 com_dev
->rx_msg_full
= false;
69 (com_dev
->driver
->bind_rx_cb
)(lower_id
, PIOS_COM_MSG_RxInCallback
, (uint32_t)com_dev
);
70 (com_dev
->driver
->rx_start
)(com_dev
->lower_id
, sizeof(com_dev
->rx_msg_buffer
));
72 com_dev
->tx_msg_full
= false;
73 (com_dev
->driver
->bind_tx_cb
)(lower_id
, PIOS_COM_MSG_TxOutCallback
, (uint32_t)com_dev
);
75 *com_id
= (uint32_t)com_dev
;
79 static uint16_t PIOS_COM_MSG_TxOutCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, __attribute__((unused
)) bool *need_yield
)
81 struct pios_com_msg_dev
*com_dev
= (struct pios_com_msg_dev
*)context
;
86 uint16_t bytes_from_fifo
= 0;
88 if (com_dev
->tx_msg_full
&& (buf_len
>= sizeof(com_dev
->tx_msg_buffer
))) {
89 /* Room for an entire message, send it */
90 memcpy(buf
, com_dev
->tx_msg_buffer
, sizeof(com_dev
->tx_msg_buffer
));
91 bytes_from_fifo
= sizeof(com_dev
->tx_msg_buffer
);
92 com_dev
->tx_msg_full
= false;
96 if (com_dev
->tx_msg_full
) {
97 *headroom
= sizeof(com_dev
->tx_msg_buffer
);
103 return bytes_from_fifo
;
106 static uint16_t PIOS_COM_MSG_RxInCallback(uint32_t context
, uint8_t *buf
, uint16_t buf_len
, uint16_t *headroom
, __attribute__((unused
)) bool *need_yield
)
108 struct pios_com_msg_dev
*com_dev
= (struct pios_com_msg_dev
*)context
;
110 uint16_t bytes_into_fifo
= 0;
112 if (!com_dev
->rx_msg_full
&& (buf_len
>= sizeof(com_dev
->rx_msg_buffer
))) {
113 memcpy(com_dev
->rx_msg_buffer
, buf
, sizeof(com_dev
->rx_msg_buffer
));
114 bytes_into_fifo
= sizeof(com_dev
->rx_msg_buffer
);
115 com_dev
->rx_msg_full
= true;
119 if (!com_dev
->rx_msg_full
) {
120 *headroom
= sizeof(com_dev
->rx_msg_buffer
);
126 return bytes_into_fifo
;
129 int32_t PIOS_COM_MSG_Send(uint32_t com_id
, const uint8_t *msg
, uint16_t msg_len
)
132 PIOS_Assert(msg_len
);
134 struct pios_com_msg_dev
*com_dev
= (struct pios_com_msg_dev
*)com_id
;
136 PIOS_Assert(msg_len
== sizeof(com_dev
->tx_msg_buffer
));
138 /* Wait forever for room in the tx buffer */
139 while (com_dev
->tx_msg_full
) {
140 /* Kick the transmitter while we wait */
141 if (com_dev
->driver
->tx_start
) {
142 (com_dev
->driver
->tx_start
)(com_dev
->lower_id
, sizeof(com_dev
->tx_msg_buffer
));
146 memcpy((void *)com_dev
->tx_msg_buffer
, msg
, msg_len
);
147 com_dev
->tx_msg_full
= true;
149 /* Kick the transmitter now that we've queued our message */
150 if (com_dev
->driver
->tx_start
) {
151 (com_dev
->driver
->tx_start
)(com_dev
->lower_id
, sizeof(com_dev
->tx_msg_buffer
));
157 uint16_t PIOS_COM_MSG_Receive(uint32_t com_id
, uint8_t *msg
, uint16_t msg_len
)
160 PIOS_Assert(msg_len
);
162 struct pios_com_msg_dev
*com_dev
= (struct pios_com_msg_dev
*)com_id
;
164 PIOS_Assert(msg_len
== sizeof(com_dev
->rx_msg_buffer
));
166 if (!com_dev
->rx_msg_full
) {
167 /* There's room in our buffer, kick the receiver */
168 (com_dev
->driver
->rx_start
)(com_dev
->lower_id
, sizeof(com_dev
->rx_msg_buffer
));
170 memcpy(msg
, com_dev
->rx_msg_buffer
, msg_len
);
171 com_dev
->rx_msg_full
= false;
180 * Change the port speed without re-initializing
181 * \param[in] port COM port
182 * \param[in] baud Requested baud rate
183 * \return -1 if port not available
184 * \return 0 on success
186 int32_t PIOS_COM_MSG_ChangeBaud(uint32_t com_id
, uint32_t baud
)
188 struct pios_com_msg_dev
*com_dev
= (struct pios_com_msg_dev
*)com_id
;
191 /* Undefined COM port for this board (see pios_board.c) */
195 /* Invoke the driver function if it exists */
196 if (com_dev
->driver
->set_baud
) {
197 com_dev
->driver
->set_baud(com_dev
->lower_id
, baud
);
203 #endif /* PIOS_INCLUDE_COM_MSG */