163 lines
5.6 KiB
C
163 lines
5.6 KiB
C
/**
|
|
* @file app_uart_protocol.c
|
|
* @brief Table-driven incremental UART packet parser and checksum helpers.
|
|
*/
|
|
|
|
#include "app_uart_protocol.h"
|
|
|
|
#include <string.h>
|
|
|
|
static const app_packet_descriptor_t g_packet_descriptors[] = {
|
|
{APP_PACKET_HEADER_WORK_CONFIG, APP_PACKET_BYTES_WORK_CONFIG, APP_PACKET_WORDS_WORK_CONFIG, 13, APP_PACKET_KIND_WORK_CONFIG},
|
|
{APP_PACKET_HEADER_DEFAULTS, 2u, 0u, -1, APP_PACKET_KIND_DEFAULTS},
|
|
{APP_PACKET_HEADER_TX_CURRENT, 2u, 0u, -1, APP_PACKET_KIND_TX_CURRENT},
|
|
{APP_PACKET_HEADER_QUERY_STATE, 2u, 0u, -1, APP_PACKET_KIND_QUERY_STATE},
|
|
{APP_PACKET_HEADER_PROFILE_SAVE_CONTROL, APP_PACKET_BYTES_PROFILE_SAVE_CONTROL, APP_PACKET_WORDS_PROFILE_SAVE_CONTROL, 13, APP_PACKET_KIND_PROFILE_SAVE_CONTROL},
|
|
{APP_PACKET_HEADER_AD9102_CONTROL, APP_PACKET_BYTES_SHORT_CONTROL, APP_PACKET_WORDS_SHORT_CONTROL, 3, APP_PACKET_KIND_AD9102_CONTROL},
|
|
{APP_PACKET_HEADER_AD9833_CONTROL, APP_PACKET_BYTES_SHORT_CONTROL, APP_PACKET_WORDS_SHORT_CONTROL, 3, APP_PACKET_KIND_AD9833_CONTROL},
|
|
{APP_PACKET_HEADER_DS1809_CONTROL, APP_PACKET_BYTES_SHORT_CONTROL, APP_PACKET_WORDS_SHORT_CONTROL, 3, APP_PACKET_KIND_DS1809_CONTROL},
|
|
{APP_PACKET_HEADER_STM32_DAC_CONTROL, APP_PACKET_BYTES_SHORT_CONTROL, APP_PACKET_WORDS_SHORT_CONTROL, 3, APP_PACKET_KIND_STM32_DAC_CONTROL},
|
|
{APP_PACKET_HEADER_AD9102_WAVE_CONTROL, APP_PACKET_BYTES_SHORT_CONTROL, APP_PACKET_WORDS_SHORT_CONTROL, 3, APP_PACKET_KIND_AD9102_WAVE_CONTROL},
|
|
{APP_PACKET_HEADER_AD9102_WAVE_DATA, APP_PACKET_BYTES_AD9102_WAVE_DATA, APP_PACKET_WORDS_AD9102_WAVE_DATA, 13, APP_PACKET_KIND_AD9102_WAVE_DATA},
|
|
{APP_PACKET_HEADER_PROFILE_SAVE_DATA, APP_PACKET_BYTES_PROFILE_SAVE_DATA, APP_PACKET_WORDS_PROFILE_SAVE_DATA, 13, APP_PACKET_KIND_PROFILE_SAVE_DATA}
|
|
};
|
|
|
|
static const app_packet_descriptor_t *app_uart_protocol_find_descriptor(uint16_t header)
|
|
{
|
|
size_t index;
|
|
|
|
for (index = 0u; index < (sizeof(g_packet_descriptors) / sizeof(g_packet_descriptors[0])); ++index)
|
|
{
|
|
if (g_packet_descriptors[index].header == header)
|
|
{
|
|
return &g_packet_descriptors[index];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint16_t app_protocol_calculate_checksum(const uint16_t *words, uint16_t word_count)
|
|
{
|
|
uint16_t checksum;
|
|
uint16_t index;
|
|
|
|
if ((words == NULL) || (word_count == 0u))
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
checksum = words[0];
|
|
for (index = 1u; index < word_count; ++index)
|
|
{
|
|
checksum ^= words[index];
|
|
}
|
|
|
|
return checksum;
|
|
}
|
|
|
|
void app_uart_protocol_init(app_uart_protocol_parser_t *parser)
|
|
{
|
|
if (parser != NULL)
|
|
{
|
|
memset(parser, 0, sizeof(*parser));
|
|
}
|
|
}
|
|
|
|
void app_uart_protocol_reset(app_uart_protocol_parser_t *parser)
|
|
{
|
|
app_uart_protocol_init(parser);
|
|
}
|
|
|
|
app_protocol_feed_result_t app_uart_protocol_feed_byte(app_uart_protocol_parser_t *parser,
|
|
uint8_t byte,
|
|
app_packet_t *out_packet)
|
|
{
|
|
uint8_t word_index;
|
|
|
|
if ((parser == NULL) || (out_packet == NULL))
|
|
{
|
|
return APP_PROTOCOL_FEED_IN_PROGRESS;
|
|
}
|
|
|
|
if (parser->bytes_received == 0u)
|
|
{
|
|
parser->buffer[0] = byte;
|
|
parser->partial_header = byte;
|
|
parser->bytes_received = 1u;
|
|
return APP_PROTOCOL_FEED_IN_PROGRESS;
|
|
}
|
|
|
|
if (parser->bytes_received == 1u)
|
|
{
|
|
parser->buffer[1] = byte;
|
|
parser->partial_header = (uint16_t)(parser->partial_header | ((uint16_t)byte << 8));
|
|
parser->descriptor = app_uart_protocol_find_descriptor(parser->partial_header);
|
|
|
|
if (parser->descriptor == NULL)
|
|
{
|
|
app_uart_protocol_reset(parser);
|
|
return APP_PROTOCOL_FEED_INVALID_HEADER;
|
|
}
|
|
|
|
parser->bytes_received = 2u;
|
|
if (parser->descriptor->total_bytes == 2u)
|
|
{
|
|
memset(out_packet, 0, sizeof(*out_packet));
|
|
out_packet->kind = parser->descriptor->kind;
|
|
out_packet->header = parser->descriptor->header;
|
|
out_packet->checksum_valid = true;
|
|
app_uart_protocol_reset(parser);
|
|
return APP_PROTOCOL_FEED_PACKET_READY;
|
|
}
|
|
|
|
return APP_PROTOCOL_FEED_IN_PROGRESS;
|
|
}
|
|
|
|
if (parser->descriptor == NULL)
|
|
{
|
|
app_uart_protocol_reset(parser);
|
|
return APP_PROTOCOL_FEED_INVALID_HEADER;
|
|
}
|
|
|
|
if (parser->bytes_received >= parser->descriptor->total_bytes)
|
|
{
|
|
app_uart_protocol_reset(parser);
|
|
return APP_PROTOCOL_FEED_INVALID_HEADER;
|
|
}
|
|
|
|
parser->buffer[parser->bytes_received] = byte;
|
|
++parser->bytes_received;
|
|
|
|
if (parser->bytes_received < parser->descriptor->total_bytes)
|
|
{
|
|
return APP_PROTOCOL_FEED_IN_PROGRESS;
|
|
}
|
|
|
|
memset(out_packet, 0, sizeof(*out_packet));
|
|
out_packet->kind = parser->descriptor->kind;
|
|
out_packet->header = parser->descriptor->header;
|
|
out_packet->payload_words = parser->descriptor->payload_words;
|
|
|
|
for (word_index = 0u; word_index < parser->descriptor->payload_words; ++word_index)
|
|
{
|
|
uint8_t byte_offset = (uint8_t)(2u + (word_index * 2u));
|
|
out_packet->words[word_index] = (uint16_t)(parser->buffer[byte_offset] |
|
|
((uint16_t)parser->buffer[byte_offset + 1u] << 8));
|
|
}
|
|
|
|
if (parser->descriptor->checksum_word_index >= 0)
|
|
{
|
|
uint8_t checksum_index = (uint8_t)parser->descriptor->checksum_word_index;
|
|
out_packet->checksum_valid =
|
|
app_protocol_calculate_checksum(out_packet->words, checksum_index) == out_packet->words[checksum_index];
|
|
}
|
|
else
|
|
{
|
|
out_packet->checksum_valid = true;
|
|
}
|
|
|
|
app_uart_protocol_reset(parser);
|
|
return APP_PROTOCOL_FEED_PACKET_READY;
|
|
}
|