1 #ifndef _MAVLINK_HELPERS_H_
2 #define _MAVLINK_HELPERS_H_
6 #include "mavlink_types.h"
13 internal function to give access to the channel status for each channel
15 MAVLINK_HELPER mavlink_status_t
*mavlink_get_channel_status(uint8_t chan
)
17 static mavlink_status_t m_mavlink_status
[MAVLINK_COMM_NUM_BUFFERS
];
19 return &m_mavlink_status
[chan
];
23 internal function to give access to the channel buffer for each channel
25 MAVLINK_HELPER mavlink_message_t
*mavlink_get_channel_buffer(uint8_t chan
)
27 #if MAVLINK_EXTERNAL_RX_BUFFER
28 // No m_mavlink_message array defined in function,
29 // has to be defined externally
30 #ifndef m_mavlink_message
31 #error ERROR: IF #define MAVLINK_EXTERNAL_RX_BUFFER IS SET, THE BUFFER HAS TO BE ALLOCATED OUTSIDE OF THIS FUNCTION (mavlink_message_t m_mavlink_buffer[MAVLINK_COMM_NUM_BUFFERS];)
34 static mavlink_message_t m_mavlink_buffer
[MAVLINK_COMM_NUM_BUFFERS
];
36 return &m_mavlink_buffer
[chan
];
40 * @brief Finalize a MAVLink message with channel assignment
42 * This function calculates the checksum and sets length and aircraft id correctly.
43 * It assumes that the message id and the payload are already correctly set. This function
44 * can also be used if the message header has already been written before (as in mavlink_msg_xxx_pack
45 * instead of mavlink_msg_xxx_pack_headerless), it just introduces little extra overhead.
47 * @param msg Message to finalize
48 * @param system_id Id of the sending (this) system, 1-127
49 * @param length Message length
52 MAVLINK_HELPER
uint16_t mavlink_finalize_message_chan(mavlink_message_t
*msg
, uint8_t system_id
, uint8_t component_id
,
53 uint8_t chan
, uint8_t length
, uint8_t crc_extra
)
55 MAVLINK_HELPER
uint16_t mavlink_finalize_message_chan(mavlink_message_t
*msg
, uint8_t system_id
, uint8_t component_id
,
56 uint8_t chan
, uint8_t length
)
59 // This code part is the same for all messages;
62 msg
->magic
= MAVLINK_STX
;
64 msg
->sysid
= system_id
;
65 msg
->compid
= component_id
;
66 // One sequence number per component
67 msg
->seq
= mavlink_get_channel_status(chan
)->current_tx_seq
;
68 mavlink_get_channel_status(chan
)->current_tx_seq
= mavlink_get_channel_status(chan
)->current_tx_seq
+ 1;
69 checksum
= crc_calculate((uint8_t *)&msg
->len
, length
+ MAVLINK_CORE_HEADER_LEN
);
71 crc_accumulate(crc_extra
, &checksum
);
73 mavlink_ck_a(msg
) = (uint8_t)(checksum
& 0xFF);
74 mavlink_ck_b(msg
) = (uint8_t)(checksum
>> 8);
76 return length
+ MAVLINK_NUM_NON_PAYLOAD_BYTES
;
81 * @brief Finalize a MAVLink message with MAVLINK_COMM_0 as default channel
84 MAVLINK_HELPER
uint16_t mavlink_finalize_message(mavlink_message_t
*msg
, uint8_t system_id
, uint8_t component_id
,
85 uint8_t length
, uint8_t crc_extra
)
87 return mavlink_finalize_message_chan(msg
, system_id
, component_id
, MAVLINK_COMM_0
, length
, crc_extra
);
90 MAVLINK_HELPER
uint16_t mavlink_finalize_message(mavlink_message_t
*msg
, uint8_t system_id
, uint8_t component_id
,
93 return mavlink_finalize_message_chan(msg
, system_id
, component_id
, MAVLINK_COMM_0
, length
);
97 #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS
98 MAVLINK_HELPER
void _mavlink_send_uart(mavlink_channel_t chan
, const char *buf
, uint16_t len
);
101 * @brief Finalize a MAVLink message with channel assignment and send
103 #if MAVLINK_CRC_EXTRA
104 MAVLINK_HELPER
void _mav_finalize_message_chan_send(mavlink_channel_t chan
, uint8_t msgid
, const char *packet
,
105 uint8_t length
, uint8_t crc_extra
)
107 MAVLINK_HELPER
void _mav_finalize_message_chan_send(mavlink_channel_t chan
, uint8_t msgid
, const char *packet
, uint8_t length
)
111 uint8_t buf
[MAVLINK_NUM_HEADER_BYTES
];
113 mavlink_status_t
*status
= mavlink_get_channel_status(chan
);
115 buf
[0] = MAVLINK_STX
;
117 buf
[2] = status
->current_tx_seq
;
118 buf
[3] = mavlink_system
.sysid
;
119 buf
[4] = mavlink_system
.compid
;
121 status
->current_tx_seq
++;
122 checksum
= crc_calculate((uint8_t *)&buf
[1], MAVLINK_CORE_HEADER_LEN
);
123 crc_accumulate_buffer(&checksum
, packet
, length
);
124 #if MAVLINK_CRC_EXTRA
125 crc_accumulate(crc_extra
, &checksum
);
127 ck
[0] = (uint8_t)(checksum
& 0xFF);
128 ck
[1] = (uint8_t)(checksum
>> 8);
130 MAVLINK_START_UART_SEND(chan
, MAVLINK_NUM_NON_PAYLOAD_BYTES
+ (uint16_t)length
);
131 _mavlink_send_uart(chan
, (const char *)buf
, MAVLINK_NUM_HEADER_BYTES
);
132 _mavlink_send_uart(chan
, packet
, length
);
133 _mavlink_send_uart(chan
, (const char *)ck
, 2);
134 MAVLINK_END_UART_SEND(chan
, MAVLINK_NUM_NON_PAYLOAD_BYTES
+ (uint16_t)length
);
138 * @brief re-send a message over a uart channel
139 * this is more stack efficient than re-marshalling the message
141 MAVLINK_HELPER
void _mavlink_resend_uart(mavlink_channel_t chan
, const mavlink_message_t
*msg
)
145 ck
[0] = (uint8_t)(msg
->checksum
& 0xFF);
146 ck
[1] = (uint8_t)(msg
->checksum
>> 8);
148 MAVLINK_START_UART_SEND(chan
, MAVLINK_NUM_NON_PAYLOAD_BYTES
+ msg
->len
);
149 _mavlink_send_uart(chan
, (const char *)&msg
->magic
, MAVLINK_NUM_HEADER_BYTES
);
150 _mavlink_send_uart(chan
, _MAV_PAYLOAD(msg
), msg
->len
);
151 _mavlink_send_uart(chan
, (const char *)ck
, 2);
152 MAVLINK_END_UART_SEND(chan
, MAVLINK_NUM_NON_PAYLOAD_BYTES
+ msg
->len
);
154 #endif // MAVLINK_USE_CONVENIENCE_FUNCTIONS
157 * @brief Pack a message to send it over a serial byte stream
159 MAVLINK_HELPER
uint16_t mavlink_msg_to_send_buffer(uint8_t *buffer
, const mavlink_message_t
*msg
)
161 memcpy(buffer
, (const uint8_t *)&msg
->magic
, MAVLINK_NUM_NON_PAYLOAD_BYTES
+ (uint16_t)msg
->len
);
162 return MAVLINK_NUM_NON_PAYLOAD_BYTES
+ (uint16_t)msg
->len
;
165 union __mavlink_bitfield
{
175 MAVLINK_HELPER
void mavlink_start_checksum(mavlink_message_t
*msg
)
177 crc_init(&msg
->checksum
);
180 MAVLINK_HELPER
void mavlink_update_checksum(mavlink_message_t
*msg
, uint8_t c
)
182 crc_accumulate(c
, &msg
->checksum
);
186 * This is a convenience function which handles the complete MAVLink parsing.
187 * the function will parse one byte at a time and return the complete packet once
188 * it could be successfully decoded. Checksum and other failures will be silently
191 * @param chan ID of the current channel. This allows to parse different channels with this function.
192 * a channel is not a physical message channel like a serial port, but a logic partition of
193 * the communication streams in this case. COMM_NB is the limit for the number of channels
194 * on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows
195 * @param c The char to barse
197 * @param returnMsg NULL if no message could be decoded, the message data else
198 * @return 0 if no message could be decoded, 1 else
200 * A typical use scenario of this function call is:
203 * #include <inttypes.h> // For fixed-width uint8_t type
205 * mavlink_message_t msg;
209 * while(serial.bytesAvailable > 0)
211 * uint8_t byte = serial.getNextByte();
212 * if (mavlink_parse_char(chan, byte, &msg))
214 * printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid);
221 MAVLINK_HELPER
uint8_t mavlink_parse_char(uint8_t chan
, uint8_t c
, mavlink_message_t
*r_message
, mavlink_status_t
*r_mavlink_status
)
224 default message crc function. You can override this per-system to
225 put this data in a different memory segment
227 #if MAVLINK_CRC_EXTRA
228 #ifndef MAVLINK_MESSAGE_CRC
229 static const uint8_t mavlink_message_crcs
[256] = MAVLINK_MESSAGE_CRCS
;
230 #define MAVLINK_MESSAGE_CRC(msgid) mavlink_message_crcs[msgid]
234 /* Enable this option to check the length of each message.
235 This allows invalid messages to be caught much sooner. Use if the transmission
236 medium is prone to missing (or extra) characters (e.g. a radio that fades in
237 and out). Only use if the channel will only contain messages types listed in
240 #if MAVLINK_CHECK_MESSAGE_LENGTH
241 #ifndef MAVLINK_MESSAGE_LENGTH
242 static const uint8_t mavlink_message_lengths
[256] = MAVLINK_MESSAGE_LENGTHS
;
243 #define MAVLINK_MESSAGE_LENGTH(msgid) mavlink_message_lengths[msgid]
247 mavlink_message_t
*rxmsg
= mavlink_get_channel_buffer(chan
); ///< The currently decoded message
248 mavlink_status_t
*status
= mavlink_get_channel_status(chan
); ///< The current decode status
251 status
->msg_received
= 0;
253 switch (status
->parse_state
) {
254 case MAVLINK_PARSE_STATE_UNINIT
:
255 case MAVLINK_PARSE_STATE_IDLE
:
256 if (c
== MAVLINK_STX
) {
257 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_STX
;
260 mavlink_start_checksum(rxmsg
);
264 case MAVLINK_PARSE_STATE_GOT_STX
:
265 if (status
->msg_received
266 /* Support shorter buffers than the
267 default maximum packet size */
268 #if (MAVLINK_MAX_PAYLOAD_LEN < 255)
269 || c
> MAVLINK_MAX_PAYLOAD_LEN
272 status
->buffer_overrun
++;
273 status
->parse_error
++;
274 status
->msg_received
= 0;
275 status
->parse_state
= MAVLINK_PARSE_STATE_IDLE
;
277 // NOT counting STX, LENGTH, SEQ, SYSID, COMPID, MSGID, CRC1 and CRC2
279 status
->packet_idx
= 0;
280 mavlink_update_checksum(rxmsg
, c
);
281 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_LENGTH
;
285 case MAVLINK_PARSE_STATE_GOT_LENGTH
:
287 mavlink_update_checksum(rxmsg
, c
);
288 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_SEQ
;
291 case MAVLINK_PARSE_STATE_GOT_SEQ
:
293 mavlink_update_checksum(rxmsg
, c
);
294 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_SYSID
;
297 case MAVLINK_PARSE_STATE_GOT_SYSID
:
299 mavlink_update_checksum(rxmsg
, c
);
300 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_COMPID
;
303 case MAVLINK_PARSE_STATE_GOT_COMPID
:
304 #if MAVLINK_CHECK_MESSAGE_LENGTH
305 if (rxmsg
->len
!= MAVLINK_MESSAGE_LENGTH(c
)) {
306 status
->parse_error
++;
307 status
->parse_state
= MAVLINK_PARSE_STATE_IDLE
;
309 if (c
== MAVLINK_STX
) {
310 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_STX
;
311 mavlink_start_checksum(rxmsg
);
316 mavlink_update_checksum(rxmsg
, c
);
317 if (rxmsg
->len
== 0) {
318 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_PAYLOAD
;
320 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_MSGID
;
324 case MAVLINK_PARSE_STATE_GOT_MSGID
:
325 _MAV_PAYLOAD_NON_CONST(rxmsg
)[status
->packet_idx
++] = (char)c
;
326 mavlink_update_checksum(rxmsg
, c
);
327 if (status
->packet_idx
== rxmsg
->len
) {
328 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_PAYLOAD
;
332 case MAVLINK_PARSE_STATE_GOT_PAYLOAD
:
333 #if MAVLINK_CRC_EXTRA
334 mavlink_update_checksum(rxmsg
, MAVLINK_MESSAGE_CRC(rxmsg
->msgid
));
336 if (c
!= (rxmsg
->checksum
& 0xFF)) {
337 // Check first checksum byte
338 status
->parse_error
++;
339 status
->msg_received
= 0;
340 status
->parse_state
= MAVLINK_PARSE_STATE_IDLE
;
341 if (c
== MAVLINK_STX
) {
342 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_STX
;
344 mavlink_start_checksum(rxmsg
);
347 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_CRC1
;
348 _MAV_PAYLOAD_NON_CONST(rxmsg
)[status
->packet_idx
] = (char)c
;
352 case MAVLINK_PARSE_STATE_GOT_CRC1
:
353 if (c
!= (rxmsg
->checksum
>> 8)) {
354 // Check second checksum byte
355 status
->parse_error
++;
356 status
->msg_received
= 0;
357 status
->parse_state
= MAVLINK_PARSE_STATE_IDLE
;
358 if (c
== MAVLINK_STX
) {
359 status
->parse_state
= MAVLINK_PARSE_STATE_GOT_STX
;
361 mavlink_start_checksum(rxmsg
);
364 // Successfully got message
365 status
->msg_received
= 1;
366 status
->parse_state
= MAVLINK_PARSE_STATE_IDLE
;
367 _MAV_PAYLOAD_NON_CONST(rxmsg
)[status
->packet_idx
+ 1] = (char)c
;
368 memcpy(r_message
, rxmsg
, sizeof(mavlink_message_t
));
374 // If a message has been sucessfully decoded, check index
375 if (status
->msg_received
== 1) {
376 // while(status->current_seq != rxmsg->seq)
378 // status->packet_rx_drop_count++;
379 // status->current_seq++;
381 status
->current_rx_seq
= rxmsg
->seq
;
382 // Initial condition: If no packet has been received so far, drop count is undefined
383 if (status
->packet_rx_success_count
== 0) {
384 status
->packet_rx_drop_count
= 0;
386 // Count this packet as received
387 status
->packet_rx_success_count
++;
390 r_mavlink_status
->current_rx_seq
= status
->current_rx_seq
+ 1;
391 r_mavlink_status
->packet_rx_success_count
= status
->packet_rx_success_count
;
392 r_mavlink_status
->packet_rx_drop_count
= status
->parse_error
;
393 status
->parse_error
= 0;
394 return status
->msg_received
;
398 * @brief Put a bitfield of length 1-32 bit into the buffer
400 * @param b the value to add, will be encoded in the bitfield
401 * @param bits number of bits to use to encode b, e.g. 1 for boolean, 2, 3, etc.
402 * @param packet_index the position in the packet (the index of the first byte to use)
403 * @param bit_index the position in the byte (the index of the first bit to use)
404 * @param buffer packet buffer to write into
405 * @return new position of the last used byte in the buffer
407 MAVLINK_HELPER
uint8_t put_bitfield_n_by_index(int32_t b
, uint8_t bits
, uint8_t packet_index
, uint8_t bit_index
, uint8_t *r_bit_index
, uint8_t *buffer
)
409 uint16_t bits_remain
= bits
;
410 // Transform number into network order
412 uint8_t i_bit_index
, i_byte_index
, curr_bits_n
;
414 #if MAVLINK_NEED_BYTE_SWAP
420 bout
.b
[0] = bin
.b
[3];
421 bout
.b
[1] = bin
.b
[2];
422 bout
.b
[2] = bin
.b
[1];
423 bout
.b
[3] = bin
.b
[0];
430 // 01100000 01000000 00000000 11110001
432 // 11110001 00000000 01000000 01100000
434 // Existing partly filled byte (four free slots)
438 // 00001111 = 2^0 + 2^1 + 2^2 + 2^3 = 2^n - 1
439 // = ((uint32_t)(1 << n)) - 1; // = 2^n - 1
441 // Shift n bits into the right position
444 // Mask and shift bytes
445 i_bit_index
= bit_index
;
446 i_byte_index
= packet_index
;
448 // If bits were available at start, they were available
449 // in the byte before the current index
453 // While bits have not been packed yet
454 while (bits_remain
> 0) {
455 // Bits still have to be packed
456 // there can be more than 8 bits, so
457 // we might have to pack them into more than one byte
459 // First pack everything we can into the current 'open' byte
460 // curr_bits_n = bits_remain << 3; // Equals bits_remain mod 8
462 if (bits_remain
<= (uint8_t)(8 - i_bit_index
)) {
464 curr_bits_n
= (uint8_t)bits_remain
;
466 curr_bits_n
= (8 - i_bit_index
);
469 // Pack these n bits into the current byte
470 // Mask out whatever was at that position with ones (xxx11111)
471 buffer
[i_byte_index
] &= (0xFF >> (8 - curr_bits_n
));
472 // Put content to this position, by masking out the non-used part
473 buffer
[i_byte_index
] |= ((0x00 << curr_bits_n
) & v
);
475 // Increment the bit index
476 i_bit_index
+= curr_bits_n
;
478 // Now proceed to the next byte, if necessary
479 bits_remain
-= curr_bits_n
;
480 if (bits_remain
> 0) {
481 // Offer another 8 bits / one byte
487 *r_bit_index
= i_bit_index
;
488 // If a partly filled byte is present, mark this as consumed
489 if (i_bit_index
!= 7) {
492 return i_byte_index
- packet_index
;
495 #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS
497 // To make MAVLink work on your MCU, define comm_send_ch() if you wish
498 // to send 1 byte at a time, or MAVLINK_SEND_UART_BYTES() to send a
499 // whole packet at a time
503 #include "mavlink_types.h"
505 void comm_send_ch(mavlink_channel_t chan, uint8_t ch)
507 if (chan == MAVLINK_COMM_0)
511 if (chan == MAVLINK_COMM_1)
518 MAVLINK_HELPER
void _mavlink_send_uart(mavlink_channel_t chan
, const char *buf
, uint16_t len
)
520 #ifdef MAVLINK_SEND_UART_BYTES
521 /* this is the more efficient approach, if the platform
523 MAVLINK_SEND_UART_BYTES(chan
, (uint8_t *)buf
, len
);
525 /* fallback to one byte at a time */
527 for (i
= 0; i
< len
; i
++) {
528 comm_send_ch(chan
, (uint8_t)buf
[i
]);
532 #endif // MAVLINK_USE_CONVENIENCE_FUNCTIONS
534 #endif /* _MAVLINK_HELPERS_H_ */