File syn_mavlink.c¶
File List > proto > syn_mavlink.c
Go to the documentation of this file
#include "syntropic/proto/syn_mavlink.h"
#include <string.h>
enum {
STATE_STX = 0,
STATE_LEN,
STATE_INCOMPAT,
STATE_COMPAT,
STATE_SEQ,
STATE_SYS_ID,
STATE_COMP_ID,
STATE_MSG_ID0,
STATE_MSG_ID1,
STATE_MSG_ID2,
STATE_PAYLOAD,
STATE_CRC0,
STATE_CRC1
};
static uint8_t get_crc_extra(uint32_t msg_id)
{
switch (msg_id) {
case SYN_MAVLINK_MSG_HEARTBEAT:
return 50;
case SYN_MAVLINK_MSG_SYS_STATUS:
return 124;
case SYN_MAVLINK_MSG_ATTITUDE:
return 39;
case SYN_MAVLINK_MSG_GLOBAL_POSITION_INT:
return 96;
case SYN_MAVLINK_MSG_VFR_HUD:
return 20;
default:
return 0;
}
}
uint16_t syn_mavlink_crc_accumulate(uint8_t byte, uint16_t crc)
{
uint8_t tmp = byte ^ (uint8_t)(crc & 0xFF);
tmp ^= (tmp << 4);
return (crc >> 8) ^ ((uint16_t)tmp << 8) ^ ((uint16_t)tmp << 3) ^ ((uint16_t)tmp >> 4);
}
SYN_Status syn_mavlink_init(SYN_MAVLINK_Parser *parser)
{
if (!parser) {
return SYN_INVALID_PARAM;
}
memset(parser, 0, sizeof(*parser));
return SYN_OK;
}
SYN_Status syn_mavlink_parse_byte(SYN_MAVLINK_Parser *parser, uint8_t byte,
SYN_MAVLINK_Frame *frame)
{
if (!parser) {
return SYN_INVALID_PARAM;
}
switch (parser->state) {
case STATE_STX:
if (byte == SYN_MAVLINK_STX_V2) {
parser->state = STATE_LEN;
parser->crc = 0xFFFF;
}
return SYN_BUSY;
case STATE_LEN:
parser->payload_len = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_INCOMPAT;
return SYN_BUSY;
case STATE_INCOMPAT:
parser->incompat_flags = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_COMPAT;
return SYN_BUSY;
case STATE_COMPAT:
parser->compat_flags = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_SEQ;
return SYN_BUSY;
case STATE_SEQ:
parser->seq = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_SYS_ID;
return SYN_BUSY;
case STATE_SYS_ID:
parser->sys_id = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_COMP_ID;
return SYN_BUSY;
case STATE_COMP_ID:
parser->comp_id = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_MSG_ID0;
return SYN_BUSY;
case STATE_MSG_ID0:
parser->msg_id = byte;
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_MSG_ID1;
return SYN_BUSY;
case STATE_MSG_ID1:
parser->msg_id |= ((uint32_t)byte << 8);
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->state = STATE_MSG_ID2;
return SYN_BUSY;
case STATE_MSG_ID2:
parser->msg_id |= ((uint32_t)byte << 16);
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
parser->payload_idx = 0;
if (parser->payload_len == 0) {
parser->state = STATE_CRC0;
} else {
parser->state = STATE_PAYLOAD;
}
return SYN_BUSY;
case STATE_PAYLOAD:
if (parser->payload_idx < SYN_MAVLINK_MAX_PAYLOAD_LEN) {
parser->payload[parser->payload_idx++] = byte;
}
parser->crc = syn_mavlink_crc_accumulate(byte, parser->crc);
if (parser->payload_idx >= parser->payload_len) {
parser->state = STATE_CRC0;
}
return SYN_BUSY;
case STATE_CRC0:
/* Low byte of CRC */
parser->state = STATE_CRC1;
/* Store low byte for check */
parser->payload_idx = byte;
return SYN_BUSY;
case STATE_CRC1: {
parser->state = STATE_STX;
uint16_t rx_crc = (uint16_t)parser->payload_idx | ((uint16_t)byte << 8);
/* Accumulate CRC Extra byte */
uint8_t extra_crc = get_crc_extra(parser->msg_id);
parser->crc = syn_mavlink_crc_accumulate(extra_crc, parser->crc);
if (parser->crc == rx_crc) {
parser->packets_received++;
parser->last_frame.payload_len = parser->payload_len;
parser->last_frame.incompat_flags = parser->incompat_flags;
parser->last_frame.compat_flags = parser->compat_flags;
parser->last_frame.seq = parser->seq;
parser->last_frame.sys_id = parser->sys_id;
parser->last_frame.comp_id = parser->comp_id;
parser->last_frame.msg_id = parser->msg_id;
if (parser->payload_len > 0) {
memcpy(parser->last_frame.payload, parser->payload, parser->payload_len);
}
if (frame) {
*frame = parser->last_frame;
}
return SYN_OK;
} else {
parser->crc_errors++;
return SYN_ERROR;
}
}
default:
parser->state = STATE_STX;
return SYN_BUSY;
}
}
SYN_Status syn_mavlink_encode_msg(uint8_t sys_id, uint8_t comp_id, uint8_t seq, uint32_t msg_id,
uint8_t crc_extra, const uint8_t *payload, uint8_t payload_len,
uint8_t *buf_out, size_t *out_len)
{
if (!buf_out || !out_len) {
return SYN_INVALID_PARAM;
}
uint8_t idx = 0;
buf_out[idx++] = SYN_MAVLINK_STX_V2;
buf_out[idx++] = payload_len;
buf_out[idx++] = 0; /* Incompat flags */
buf_out[idx++] = 0; /* Compat flags */
buf_out[idx++] = seq;
buf_out[idx++] = sys_id;
buf_out[idx++] = comp_id;
buf_out[idx++] = (uint8_t)(msg_id & 0xFF);
buf_out[idx++] = (uint8_t)((msg_id >> 8) & 0xFF);
buf_out[idx++] = (uint8_t)((msg_id >> 16) & 0xFF);
uint16_t crc = 0xFFFF;
for (uint8_t i = 1; i < idx; i++) {
crc = syn_mavlink_crc_accumulate(buf_out[i], crc);
}
if (payload && payload_len > 0) {
for (uint8_t i = 0; i < payload_len; i++) {
buf_out[idx++] = payload[i];
crc = syn_mavlink_crc_accumulate(payload[i], crc);
}
}
/* Accumulate CRC Extra */
crc = syn_mavlink_crc_accumulate(crc_extra, crc);
buf_out[idx++] = (uint8_t)(crc & 0xFF);
buf_out[idx++] = (uint8_t)((crc >> 8) & 0xFF);
*out_len = idx;
return SYN_OK;
}