/* * aprs_encoder.c * * Created on: Oct 21, 2019 * Author: curiousmuch */ #include #include #include #include "freertos/FreeRTOS.h" #include "esp_log.h" #include "sdkconfig.h" #include "aprs_encoder.h" /* Debugging Tag */ #define ENC_TAG "AX.25 Encoder" /* Public Variables */ ax25_enc_var_t enc_var; // TODO: Should this be stored in DRAM? ax25_enc_param_t enc_param; /* Private Functions */ void ax25_encoder_reset(void) { // reset buffer variables enc_var.frame = NULL; enc_var.frame_len = 0; // reset internal variables enc_var.index = 0; enc_var.bit_index = 0; enc_var.one_count = 0; enc_var.cur_bit = 0; enc_var.prev_bit = 0; enc_var.nrzi_bit = 0; enc_var.byte = 0; // reset state machine state enc_var.state = PREAMBLE; } /* Public Functions */ void ax25_encoder_init(uint8_t tx_delay, uint8_t tx_tail) { // set preamble and tx_tail length enc_param.tx_delay = round(tx_delay * 1.5 + 1); // calculate the number of enc_param.tx_tail = round(tx_tail * 1.5 + 1); //enc_var.state = STOP; enc_var.status = STOP; } // feed frame to state machine ax25_enc_status_t ax25_encoder_encode(uint8_t *frame, int32_t frame_len) { if (enc_var.status != STOP) { ESP_LOGE(ENC_TAG, "two packets can not be encoded at once"); enc_var.status = ERROR; return enc_var.status; // TODO: Assert??? } // re-init state machine variables ax25_encoder_reset(); // store frame ptr enc_var.frame = frame; enc_var.frame_len = frame_len; // setup state-machine enc_var.status = READY; return enc_var.status; } ax25_enc_status_t ax25_encoder_get_status(void) { return enc_var.status; } // TODO: clean up reused code to inline functions uint8_t ax25_encoder_get_bit(void) { switch (enc_var.state) { case PREAMBLE: { // reset when index runs down if (enc_var.bit_index == 0) { enc_var.byte = 0x7E; } enc_var.cur_bit = enc_var.byte & 0x01; // NRZ-I encode if (enc_var.cur_bit) { // do nothing enc_var.one_count++; } else { enc_var.nrzi_bit = enc_var.nrzi_bit ^ 1; // switch tone enc_var.one_count = 0; } // prepare for next bit enc_var.byte = (enc_var.byte >> 1); enc_var.bit_index++; if (enc_var.bit_index >= 8) { enc_var.bit_index = 0; enc_var.flag_count++; // exit to frame when flags have been sent for tx_delay if (enc_var.flag_count >= enc_param.tx_delay) { enc_var.state = FRAME; enc_var.bit_index = 0; enc_var.index = 0; } } return enc_var.nrzi_bit; break; } case FRAME: { // load byte from frame buffer when finished sending byte if (enc_var.bit_index == 0) { enc_var.byte = enc_var.frame[enc_var.index]; } // zero-stuff if needed if (enc_var.one_count == 5) { enc_var.nrzi_bit = enc_var.nrzi_bit ^ 1; enc_var.one_count = 0; return enc_var.nrzi_bit; } // select next bit from current byte enc_var.cur_bit = enc_var.byte & 0x01; // NRZI encode if (enc_var.cur_bit) { // do nothing enc_var.one_count++; } else { enc_var.nrzi_bit = enc_var.nrzi_bit ^ 1; // switch tone enc_var.one_count = 0; } // prepare for next bit enc_var.byte = (enc_var.byte >> 1); enc_var.bit_index++; if (enc_var.bit_index >= 8) { enc_var.bit_index = 0; enc_var.index++; if (enc_var.index >= enc_var.frame_len) { enc_var.state = TAIL; enc_var.bit_index = 0; } } return enc_var.nrzi_bit; break; } case TAIL: { // reset when index runs down if (enc_var.bit_index == 0) { enc_var.byte = 0x7E; } enc_var.cur_bit = enc_var.byte & 0x01; // NRZ-I encode if (enc_var.cur_bit) { // do nothing enc_var.one_count++; } else { enc_var.nrzi_bit = enc_var.nrzi_bit ^ 1; // switch tone enc_var.one_count = 0; } // prepare for next bit enc_var.byte = (enc_var.byte >> 1); enc_var.bit_index++; if (enc_var.bit_index >= 8) { enc_var.bit_index = 0; enc_var.flag_count++; // exit to frame when flags have been sent for tx_tail if (enc_var.flag_count >= enc_param.tx_tail) { enc_var.state = DONE; enc_var.bit_index = 0; enc_var.index = 0; enc_var.status = STOP; } } return enc_var.nrzi_bit; break; } case DONE: { break; } default: { ESP_LOGE(ENC_TAG, "undefined state"); enc_var.status = ERROR; // TODO: Assert break; } } return 0; // for DONE and DEFAULT states }