-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
mavlink_decoder.h
264 lines (235 loc) · 7.45 KB
/
mavlink_decoder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
* Copyright (C) 2012 Xavier Gibert
* Copyright (C) 2013 Gautier Hattenberger
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
/** @file modules/datalink/mavlink_decoder.h
* @brief simple decoder of mavlink message
*/
#ifndef MAVLINK_DECODER_H
#define MAVLINK_DECODER_H
#include "std.h"
#include "subsystems/datalink/transport.h"
#include "mcu_periph/uart.h"
/* MAVLINK Transport
*/
#define STXMAV 0xFE
/** Mavlink v1.0 message structure.
*
* Mavlink Msg:
* STXMAV + len + { packet_seq + SYS/ID + COMPONENT/ID + MSG/ID + Payload } + ck_a + ck_b
*
* Payload starts after 4 bytes.
*
*/
struct mavlink_message {
uint8_t seq;
uint8_t sys_id;
uint8_t comp_id;
uint8_t msg_id;
uint8_t* payload;
};
#define MAVLINK_PAYLOAD_OFFSET 4
#define MAVLINK_SEQ_IDX 0
#define MAVLINK_SYS_ID_IDX 1
#define MAVLINK_COMP_ID_IDX 2
#define MAVLINK_MSG_ID_IDX 3
/** MAVLINK CHECKSUM */
#define X25_INIT_CRC 0xffff
#ifndef MAVLINK_NO_CRC_EXTRA
// CRC Extra (!!! staticaly calculated !!!)
extern uint8_t mavlink_crc_extra[256];
#endif
/**
* @brief Accumulate the X.25 CRC by adding one char at a time.
*
* The checksum function adds the hash of one char at a time to the
* 16 bit checksum (uint16_t).
*
* @param data new char to hash
* @param crcAccum the already accumulated checksum
*/
static inline void mavlink_crc_accumulate(uint8_t data, uint16_t *crcAccum)
{
/*Accumulate one byte of data into the CRC*/
uint8_t tmp;
tmp = data ^ (uint8_t)(*crcAccum &0xff);
tmp ^= (tmp<<4);
*crcAccum = (*crcAccum>>8) ^ (tmp<<8) ^ (tmp <<3) ^ (tmp>>4);
}
/**
* @brief Initiliaze the buffer for the X.25 CRC
*
* @param crcAccum the 16 bit X.25 CRC
*/
static inline void mavlink_crc_init(uint16_t* crcAccum)
{
*crcAccum = X25_INIT_CRC;
}
/**
* @brief Calculates the X.25 checksum on a byte buffer
*
* @param pBuffer buffer containing the byte array to hash
* @param length length of the byte array
* @return the checksum over the buffer bytes
**/
static inline uint16_t mavlink_crc_calculate(const uint8_t* pBuffer, uint16_t length)
{
uint16_t crcTmp;
mavlink_crc_init(&crcTmp);
while (length--) {
mavlink_crc_accumulate(*pBuffer++, &crcTmp);
}
return crcTmp;
}
/** Receiving mavlink messages */
// Mavlink parsing state machine
typedef enum {
MAVLINK_PARSE_STATE_UNINIT=0,
MAVLINK_PARSE_STATE_IDLE,
MAVLINK_PARSE_STATE_GOT_STX,
MAVLINK_PARSE_STATE_GOT_LENGTH,
MAVLINK_PARSE_STATE_GOT_PAYLOAD,
MAVLINK_PARSE_STATE_GOT_CRC1
} mavlink_parse_state; ///< The state machine for the comm parser
/** Structure to submit a callback
*/
struct mavlink_msg_req {
uint8_t msg_id; ///< Requested message ID
struct mavlink_message msg; ///< Mavlink message
void (*callback)(struct mavlink_message * msg); ///< Callback function
struct mavlink_msg_req * next;
};
/** Mavlink transport protocol
*/
struct mavlink_transport {
// generic interface
struct transport trans;
// specific mavlink transport variables
mavlink_parse_state status;
uint8_t payload_idx;
uint16_t checksum;
// linked list of callbacks
struct mavlink_msg_req * req;
};
extern struct mavlink_transport mavlink_tp;
#if MAVLINK_DECODER_DEBUG
/** Send debug frame over PPRZ telemetry.
*
* Activated with MAVLINK_DECODER_DEBUG flag
*/
extern void mavlink_send_debug(struct mavlink_transport * t);
#endif
/** Register a callback for a mavlink message
*/
static inline void mavlink_register_msg(struct mavlink_transport * t, struct mavlink_msg_req * req) {
// handle linked list of requests
req->next = t->req;
t->req = req;
}
/** Mavlink character parser
*/
static inline void parse_mavlink(struct mavlink_transport * t, uint8_t c ) {
switch (t->status) {
case MAVLINK_PARSE_STATE_UNINIT:
t->status = MAVLINK_PARSE_STATE_IDLE; // directly go to idle state (no break)
case MAVLINK_PARSE_STATE_IDLE:
if (c == STXMAV) {
t->status = MAVLINK_PARSE_STATE_GOT_STX;
mavlink_crc_init(&(t->checksum));
}
break;
case MAVLINK_PARSE_STATE_GOT_STX:
if (t->trans.msg_received) {
t->trans.ovrn++;
goto error;
}
t->trans.payload_len = c + MAVLINK_PAYLOAD_OFFSET; /* Not Counting STX, CRC1 and CRC2, adding LENGTH, SEQ, SYSID, COMPID, MSGID */
mavlink_crc_accumulate(c, &(t->checksum));
t->status = MAVLINK_PARSE_STATE_GOT_LENGTH;
t->payload_idx = 0;
break;
case MAVLINK_PARSE_STATE_GOT_LENGTH:
t->trans.payload[t->payload_idx] = c;
mavlink_crc_accumulate(c, &(t->checksum));
t->payload_idx++;
if (t->payload_idx == t->trans.payload_len)
t->status = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
break;
case MAVLINK_PARSE_STATE_GOT_PAYLOAD:
#if MAVLINK_DECODER_DEBUG
mavlink_send_debug(t);
#endif
#ifndef MAVLINK_NO_CRC_EXTRA
// add extra CRC
mavlink_crc_accumulate(mavlink_crc_extra[(t->trans.payload[MAVLINK_MSG_ID_IDX])], &(t->checksum));
#endif
if (c != (t->checksum & 0xFF))
goto error;
t->status = MAVLINK_PARSE_STATE_GOT_CRC1;
break;
case MAVLINK_PARSE_STATE_GOT_CRC1:
if (c != (t->checksum >> 8))
goto error;
t->trans.msg_received = TRUE;
goto restart;
default:
goto error;
}
return;
error:
t->trans.error++;
restart:
t->status = MAVLINK_PARSE_STATE_IDLE;
return;
}
static inline void mavlink_parse_payload(struct mavlink_transport * t) {
uint8_t i;
struct mavlink_msg_req * el;
// test the linked list and call callback if needed
for (el = t->req; el; el = el->next) {
if (el->msg_id == t->trans.payload[MAVLINK_MSG_ID_IDX]) {
// build message out of payload
el->msg.seq = t->trans.payload[MAVLINK_SEQ_IDX];
el->msg.sys_id = t->trans.payload[MAVLINK_SYS_ID_IDX];
el->msg.comp_id = t->trans.payload[MAVLINK_COMP_ID_IDX];
el->msg.msg_id = t->trans.payload[MAVLINK_MSG_ID_IDX];
// copy buffer
for(i = 0; i < t->trans.payload_len; i++)
el->msg.payload[i] = t->trans.payload[i+MAVLINK_PAYLOAD_OFFSET];
// callback
el->callback(&(el->msg));
}
}
}
#define MavlinkBuffer(_dev) TransportLink(_dev,ChAvailable())
#define ReadMavlinkBuffer(_dev,_trans) { while (TransportLink(_dev,ChAvailable())&&!(_trans.trans.msg_received)) parse_mavlink(&(_trans),TransportLink(_dev,Getch())); }
#define MavlinkCheckAndParse(_dev,_trans) { \
if (MavlinkBuffer(_dev)) { \
ReadMavlinkBuffer(_dev,_trans); \
if (_trans.trans.msg_received) { \
mavlink_parse_payload(&(_trans)); \
_trans.trans.msg_received = FALSE; \
} \
} \
}
/* Datalink Event Macro */
#define MavlinkDatalinkEvent() MavlinkCheckAndParse(MAVLINK_UART, mavlink_tp)
#endif /* MAVLINK_DECODER_H */