|
@@ -0,0 +1,243 @@
|
|
|
+/*
|
|
|
+ * aprs_decoder.c
|
|
|
+ *
|
|
|
+ * Created on: Aug 25, 2019
|
|
|
+ * Author: curiousmuch
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+typedef enum {
|
|
|
+ NORMAL,
|
|
|
+ FRAME_DECODED,
|
|
|
+ ERROR_FCS_MISMATCH,
|
|
|
+ ERROR_PACKET_FORMAT,
|
|
|
+ ERROR_BUFFER_OVERFLOW
|
|
|
+} decoder_output_t;
|
|
|
+
|
|
|
+typedef enum {
|
|
|
+ NONE,
|
|
|
+ BUFFER_OVERFLOW,
|
|
|
+ BIT_STUFFING_FAILURE,
|
|
|
+ FCS_MISMATCH,
|
|
|
+} decoder_error_t;
|
|
|
+
|
|
|
+typedef enum {
|
|
|
+ FLAG_SEARCH,
|
|
|
+ FLAG_FOUND,
|
|
|
+ FRAME_START,
|
|
|
+ PACKET_END,
|
|
|
+ FRAME_END,
|
|
|
+ ABORT,
|
|
|
+} decoder_state_t;
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ decoder_state_t decoder_state;
|
|
|
+ uint8_t *frame_buffer;
|
|
|
+ uint8_t frame_buffer_index;
|
|
|
+ uint8_t frame_buffer_len;
|
|
|
+ uint8_t flag_buffer;
|
|
|
+ uint8_t flag_buffer_index;
|
|
|
+ uint8_t byte_buffer;
|
|
|
+ uint8_t current_nrzi_bit;
|
|
|
+ uint8_t previous_nrzi_bit;
|
|
|
+ uint8_t current_bit;
|
|
|
+ uint8_t one_count;
|
|
|
+ uint32_t byte_buffer_index;
|
|
|
+ uint8_t skip_bit_flag;
|
|
|
+} decoder_varibles_t;
|
|
|
+
|
|
|
+decoder_varibles_t v;
|
|
|
+
|
|
|
+#define APRS_MAX_FRAME 256
|
|
|
+
|
|
|
+void frame_buffer_init(uint8_t *buf, uint8_t len)
|
|
|
+{
|
|
|
+ v.frame_buffer = buf;
|
|
|
+ v.frame_buffer_len = len;
|
|
|
+}
|
|
|
+
|
|
|
+void aprs_decode_init(void)
|
|
|
+{
|
|
|
+ v.decoder_state = FLAG_SEARCH;
|
|
|
+ v.frame_buffer_index = 0;
|
|
|
+ //v.frame_max_len = APRS_MAX_FRAME;
|
|
|
+ v.flag_buffer = 0;
|
|
|
+ v.flag_buffer_index = 0;
|
|
|
+ v.byte_buffer_index = 0;
|
|
|
+ v.byte_buffer = 0;
|
|
|
+ v.current_nrzi_bit = 0;
|
|
|
+ v.previous_nrzi_bit = 0;
|
|
|
+ v.current_bit = 0;
|
|
|
+ v.one_count = 0;
|
|
|
+ v.skip_bit_flag = 0;
|
|
|
+}
|
|
|
+
|
|
|
+uint8_t flag_found(void)
|
|
|
+{
|
|
|
+ if (v.flag_buffer == 0x7E)
|
|
|
+ return 1;
|
|
|
+ else
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+decoder_output_t aprs_decode_feed_bit(uint8_t nrzi_bit)
|
|
|
+{
|
|
|
+ v.current_nrzi_bit = nrzi_bit;
|
|
|
+
|
|
|
+ // decoder NRZI
|
|
|
+ if (v.previous_nrzi_bit == v.current_nrzi_bit)
|
|
|
+ {
|
|
|
+ v.current_bit = 1;
|
|
|
+ v.one_count =+ 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ v.current_bit = 0;
|
|
|
+ v.one_count = 0;
|
|
|
+ }
|
|
|
+ v.previous_nrzi_bit = v.current_nrzi_bit;
|
|
|
+
|
|
|
+ // load bit into flag buffer
|
|
|
+ v.flag_buffer = (v.flag_buffer >> 1) + (v.current_bit*0x80);
|
|
|
+
|
|
|
+ switch(v.decoder_state)
|
|
|
+ {
|
|
|
+ case FLAG_SEARCH:
|
|
|
+ if (flag_found())
|
|
|
+ {
|
|
|
+ // set state variable
|
|
|
+ v.decoder_state = FLAG_FOUND;
|
|
|
+
|
|
|
+ // re-initialize buffer indexes
|
|
|
+ v.flag_buffer_index = 0;
|
|
|
+ v.frame_buffer_index = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ v.decoder_state = FLAG_SEARCH;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case FLAG_FOUND:
|
|
|
+ if (v.flag_buffer_index == 7) // check every 8 bits for flag again
|
|
|
+ {
|
|
|
+ if (flag_found()) // if flag is found, payload hasn't started
|
|
|
+ {
|
|
|
+ v.decoder_state = FLAG_FOUND;
|
|
|
+ v.flag_buffer_index = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ v.decoder_state = FRAME_START;
|
|
|
+
|
|
|
+ // load current bits in byte buffer and remove 0 stuffing
|
|
|
+ uint8_t i, bit;
|
|
|
+ v.skip_bit_flag = 0;
|
|
|
+ v.byte_buffer_index = 0;
|
|
|
+ v.one_count = 0;
|
|
|
+
|
|
|
+ for (i=0;i<7;i++)
|
|
|
+ {
|
|
|
+ bit = (v.flag_buffer << i) & 0x80; // load bit
|
|
|
+
|
|
|
+ // count ones for to remove bit stuffing
|
|
|
+ if (bit)
|
|
|
+ v.one_count =+ 1;
|
|
|
+ else
|
|
|
+ v.one_count = 0;
|
|
|
+
|
|
|
+ // skip bit or store in v.byte_buffer
|
|
|
+ if (v.skip_bit_flag)
|
|
|
+ {
|
|
|
+ v.skip_bit_flag = 0;
|
|
|
+
|
|
|
+ // if "0" is not stuffed packet is invalid
|
|
|
+ if (bit != 0)
|
|
|
+ v.decoder_state = ABORT;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ v.byte_buffer |= bit*(0x8>>i);
|
|
|
+ v.byte_buffer_index =+ 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (v.one_count == 5)
|
|
|
+ v.skip_bit_flag = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // check if byte buffer is full
|
|
|
+ if (v.byte_buffer_index == 7)
|
|
|
+ {
|
|
|
+ v.frame_buffer[v.frame_buffer_index] = v.byte_buffer;
|
|
|
+ v.byte_buffer = 0;
|
|
|
+ v.byte_buffer_index = 0;
|
|
|
+ v.frame_buffer_index += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ v.flag_buffer_index =+ 1;
|
|
|
+ break;
|
|
|
+ case FRAME_START:
|
|
|
+ // skip stuffed "0"
|
|
|
+ if (v.skip_bit_flag == 1)
|
|
|
+ {
|
|
|
+ v.skip_bit_flag = 0;
|
|
|
+
|
|
|
+ // bit will only not be stuffed properly if the HDLC flag is being received
|
|
|
+ // indicating the end of the frame or the packet has become corrupted.
|
|
|
+ if (v.current_bit != 0)
|
|
|
+ {
|
|
|
+ v.decoder_state = PACKET_END;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // load bit
|
|
|
+ v.byte_buffer |= v.current_bit*(0x8>>v.byte_buffer_index);
|
|
|
+ v.byte_buffer_index =+ 1;
|
|
|
+
|
|
|
+ // check if byte buffer is full
|
|
|
+ if (v.byte_buffer_index == 7)
|
|
|
+ {
|
|
|
+ v.frame_buffer[v.frame_buffer_index] = v.byte_buffer;
|
|
|
+ v.byte_buffer = 0;
|
|
|
+ v.byte_buffer_index = 0;
|
|
|
+ v.frame_buffer_index += 1;
|
|
|
+
|
|
|
+ // check for overflow
|
|
|
+ if (v.frame_buffer_index == v.frame_buffer_len)
|
|
|
+ {
|
|
|
+ v.decoder_state = ABORT;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(v.one_count == 5)
|
|
|
+ v.skip_bit_flag = 1;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ // we're in trouble.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (v.decoder_state == FRAME_END)
|
|
|
+ {
|
|
|
+ // calculate CRC
|
|
|
+
|
|
|
+ // re-initialize state machine
|
|
|
+ return FRAME_DECODED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (v.decoder_state == ABORT)
|
|
|
+ {
|
|
|
+ // re-initialize state machine
|
|
|
+ aprs_decoder_init();
|
|
|
+ }
|
|
|
+ return NORMAL;
|
|
|
+}
|
|
|
+
|
|
|
+
|