dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
msp.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  *
25  * Additional note on redistribution: The copyright and license notices above
26  * must be maintained in each individual source file that is a derivative work
27  * of this source file; otherwise redistribution is prohibited.
28  */
29 
30 #include "msp.h"
31 
32 #define MSP_OVERHEAD_BYTES (2 /* preamble */ \
33  + 1 /* direction */ \
34  + 1 /* size */ \
35  + 1 /* command */ \
36  + 1 /* checksum */)
37 
38 #define MSP_PARSER_MAGIC 0x32aedc07
39 
40 enum msp_state {
49 };
50 
51 struct msp_parser {
52  uint32_t magic;
53 
56 
59 
60  uint8_t data_len;
61  uint8_t command;
62  uint8_t checksum;
63  uint8_t data_buf[255];
64  uint8_t data_rcvd;
65 };
66 
67 static bool parser_validate(struct msp_parser *p)
68 {
69  return p != NULL && p->magic == MSP_PARSER_MAGIC;
70 }
71 
72 static bool call_handler(struct msp_parser *p, enum msp_message_id id, void *buf, uint8_t len)
73 {
74  if (!p->handler)
75  return false;
76  return p->handler(id, buf, len, p->handler_context);
77 }
78 
79 static enum msp_state msp_parse_idle(struct msp_parser *p, uint8_t b)
80 {
81  if (b == '$')
82  return MSP_STATE_PREAMBLE;
83  return MSP_STATE_IDLE;
84 }
85 
86 static enum msp_state msp_parse_preamble(struct msp_parser *p, uint8_t b)
87 {
88  if (b == 'M')
89  return MSP_STATE_DIRECTION;
90  return MSP_STATE_IDLE;
91 }
92 
93 static enum msp_state msp_parse_direction(struct msp_parser *p, uint8_t b)
94 {
95  switch (b) {
96  case '>':
97  if (p->type == MSP_PARSER_CLIENT)
98  return MSP_STATE_SIZE;
99  break;
100  case '<':
101  if (p->type == MSP_PARSER_SERVER)
102  return MSP_STATE_SIZE;
103  break;
104  default:
105  break;
106  }
107  return MSP_STATE_IDLE;
108 }
109 
110 static enum msp_state msp_parse_size(struct msp_parser *p, uint8_t b)
111 {
112  p->checksum = b;
113  p->data_len = b;
114  p->data_rcvd = 0;
115  return MSP_STATE_COMMAND;
116 }
117 
118 static enum msp_state msp_parse_command(struct msp_parser *p, uint8_t b)
119 {
120  p->checksum ^= b;
121  p->command = b;
122  if (p->data_len) {
123  if (p->data_len <= NELEMENTS(p->data_buf))
124  return MSP_STATE_DATA;
125  else
126  return MSP_STATE_DISCARD;
127  } else {
128  return MSP_STATE_CHECKSUM;
129  }
130 }
131 
132 static enum msp_state msp_parse_data(struct msp_parser *p, uint8_t b)
133 {
134  p->checksum ^= b;
135  p->data_buf[p->data_rcvd++] = b;
136  if (p->data_rcvd < p->data_len)
137  return MSP_STATE_DATA;
138  else
139  return MSP_STATE_CHECKSUM;
140 }
141 
142 static enum msp_state msp_parse_checksum(struct msp_parser *p, uint8_t b)
143 {
144  p->checksum ^= b;
145  if (!p->checksum)
146  call_handler(p, p->command, p->data_rcvd ? p->data_buf : NULL, p->data_rcvd);
147 
148  return MSP_STATE_IDLE;
149 }
150 
151 static enum msp_state msp_parse_discard(struct msp_parser *p, uint8_t b)
152 {
153  p->data_rcvd++;
154  /* consume checksum byte too */
155  if (p->data_rcvd <= p->data_len)
156  return MSP_STATE_DISCARD;
157  else
158  return MSP_STATE_IDLE;
159 }
160 
161 static void process_byte(struct msp_parser *p, uint8_t b)
162 {
163  switch (p->state) {
164  case MSP_STATE_IDLE:
165  p->state = msp_parse_idle(p, b);
166  break;
167  case MSP_STATE_PREAMBLE:
168  p->state = msp_parse_preamble(p, b);
169  break;
170  case MSP_STATE_DIRECTION:
171  p->state = msp_parse_direction(p, b);
172  break;
173  case MSP_STATE_SIZE:
174  p->state = msp_parse_size(p, b);
175  break;
176  case MSP_STATE_COMMAND:
177  p->state = msp_parse_command(p, b);
178  break;
179  case MSP_STATE_DATA:
180  p->state = msp_parse_data(p, b);
181  break;
182  case MSP_STATE_CHECKSUM:
183  p->state = msp_parse_checksum(p, b);
184  break;
185  case MSP_STATE_DISCARD:
186  p->state = msp_parse_discard(p, b);
187  break;
188  }
189 }
190 
191 /* public */
192 
194 {
195  struct msp_parser *p = PIOS_malloc(sizeof(*p));
196  if (!p)
197  return NULL;
198 
199  memset(p, 0, sizeof(*p));
200 
201  p->state = MSP_STATE_IDLE;
202  p->type = type;
203  p->magic = MSP_PARSER_MAGIC;
204 
205  return p;
206 }
207 
208 int32_t msp_process_buffer(struct msp_parser *parser, void *buf, uint8_t len)
209 {
210  if (!parser_validate(parser))
211  return -1;
212 
213  for (unsigned i = 0; i < len; i++)
214  process_byte(parser, ((uint8_t *)buf)[i]);
215 
216  return len;
217 }
218 
219 int32_t msp_process_com(struct msp_parser *parser, struct pios_com_dev *com)
220 {
221  if (!parser_validate(parser))
222  return -1;
223 
224  int32_t len = 0;
225  uint8_t b;
226  /* TODO: fix PIOS_COM to take a pointer */
227  while (PIOS_COM_ReceiveBuffer((uintptr_t)com, &b, 1, 0)) {
228  process_byte(parser, b);
229  len++;
230  }
231 
232  return len;
233 }
234 
235 int32_t msp_send_com(struct msp_parser *parser, struct pios_com_dev *com, enum msp_message_id msg_id, void *payload, uint8_t len)
236 {
237  if (!parser_validate(parser))
238  return -1;
239 
240  uint8_t dir = (parser->type == MSP_PARSER_SERVER) ? '>' : '<';
241  uint8_t hdr[] = {'$', 'M', dir, len, msg_id};
242  /* TODO: not assume success */
243  /* TODO: fix PIOS_COM to take a pointer */
244  int32_t written = PIOS_COM_SendBuffer((uintptr_t)com, hdr, NELEMENTS(hdr));
245  if (len)
246  written += PIOS_COM_SendBuffer((uintptr_t)com, payload, len);
247  uint8_t checksum = len ^ (uint8_t)msg_id;
248  for (unsigned i = 0; i < len; i++)
249  checksum ^= ((uint8_t *)payload)[i];
250  written += PIOS_COM_SendBuffer((uintptr_t)com, &checksum, 1);
251 
252  return written;
253 }
254 
256 {
257  if (!parser_validate(parser))
258  return -1;
259 
260  parser->handler = handler;
261  parser->handler_context = context;
262 
263  return 0;
264 }
265 
msp_handler_t handler
Definition: msp.c:54
int32_t msp_send_com(struct msp_parser *parser, struct pios_com_dev *com, enum msp_message_id msg_id, void *payload, uint8_t len)
Construct and send an MSP message via PIOS_COM.
Definition: msp.c:235
msp_parser_type
Definition: msp.h:51
static enum msp_state msp_parse_data(struct msp_parser *p, uint8_t b)
Definition: msp.c:132
#define NELEMENTS(x)
Definition: pios.h:192
uint8_t data_rcvd
Definition: msp.c:64
static enum msp_state msp_parse_size(struct msp_parser *p, uint8_t b)
Definition: msp.c:110
static enum msp_state msp_parse_discard(struct msp_parser *p, uint8_t b)
Definition: msp.c:151
int32_t msp_register_handler(struct msp_parser *parser, msp_handler_t handler, void *context)
Register a handler for valid received messages.
Definition: msp.c:255
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
uint8_t data_len
Definition: msp.c:60
uint8_t payload[CRSF_MAX_PAYLOAD+CRSF_CRC_LEN]
msp_state
Definition: msp.c:40
uint8_t checksum
Definition: msp.c:62
uint8_t data_buf[255]
Definition: msp.c:63
static void process_byte(struct msp_parser *p, uint8_t b)
Definition: msp.c:161
void * handler_context
Definition: msp.c:55
uint16_t PIOS_COM_ReceiveBuffer(uintptr_t com_id, uint8_t *buf, uint16_t buf_len, uint32_t timeout_ms)
static enum msp_state msp_parse_checksum(struct msp_parser *p, uint8_t b)
Definition: msp.c:142
msp_message_id
Definition: msp_messages.h:41
enum msp_parser_type type
Definition: msp.c:58
uint8_t command
Definition: msp.c:61
uint8_t i
Definition: msp_messages.h:97
static enum msp_state msp_parse_preamble(struct msp_parser *p, uint8_t b)
Definition: msp.c:86
static bool parser_validate(struct msp_parser *p)
Definition: msp.c:67
PIOS_COM_SendBuffer(shub_global->frsky_port, shub_global->serial_buf, msg_length)
int32_t msp_process_buffer(struct msp_parser *parser, void *buf, uint8_t len)
Process MSP stream from buffer.
Definition: msp.c:208
uint8_t type
bool(* msp_handler_t)(enum msp_message_id msg_id, void *data, uint8_t len, void *context)
Handler to be called when valid MSP messages are recieved.
Definition: msp.h:48
#define MSP_PARSER_MAGIC
Definition: msp.c:38
uint32_t magic
Definition: msp.c:52
int32_t msp_process_com(struct msp_parser *parser, struct pios_com_dev *com)
Process MSP stream from PIOS_COM.
Definition: msp.c:219
Definition: msp.c:51
uint8_t p
Definition: msp_messages.h:96
static enum msp_state msp_parse_idle(struct msp_parser *p, uint8_t b)
Definition: msp.c:79
struct msp_parser * msp_parser_init(enum msp_parser_type type)
Initialize a new parser instance.
Definition: msp.c:193
static bool call_handler(struct msp_parser *p, enum msp_message_id id, void *buf, uint8_t len)
Definition: msp.c:72
static enum msp_state msp_parse_command(struct msp_parser *p, uint8_t b)
Definition: msp.c:118
static enum msp_state msp_parse_direction(struct msp_parser *p, uint8_t b)
Definition: msp.c:93
enum msp_state state
Definition: msp.c:57