123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /*
- * Project: Arrow
- * Author: curiousmuch
- * Description: This project is an APRS transceiver based on the ESP32 and CC1200.
- * TODO: Refactor Code to isolate into seperate components
- * TODO: Isolate BT_SPP.C functionality
- * TODO: Transfer DSP functions to APRS folder
- * TODO: Abstract includes to be nicer (#include aprs.h) for example
- */
- /* Standard Includes */
- #include <stdio.h>
- #include <stddef.h>
- /* ESP-IDF */
- #include "sdkconfig.h"
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/semphr.h"
- #include "freertos/ringbuf.h"
- #include "nvs.h"
- #include "nvs_flash.h"
- #include "esp_log.h"
- /* Application Specific */
- #include "bt_spp.h"
- #include "board.h"
- #include "radio.h"
- #include "kiss.h"
- #include "fcs_calc.h"
- /* Data Structures */
- typedef enum {
- TNC_TX=0,
- TNC_RX,
- TNC_IDLE
- } tnc_status_t;
- typedef struct {
- uint8_t tnc_number;
- uint8_t tx_delay;
- uint8_t P;
- uint8_t slot_time;
- uint8_t full_duplex;
- uint8_t tx_tail;
- uint8_t frequency_index;
- uint8_t mode_index;
- uint32_t freq;
- radio_config_t mode;
- tnc_status_t status;
- TaskHandle_t tnc_task;
- } tnc_settings_t;
- /* Public Variables */
- static tnc_settings_t tnc_settings;
- static SemaphoreHandle_t xRadioTXSemaphore;
- uint8_t ax25_rx_buf[1024];
- RingbufHandle_t ax25_tx_buf;
- uint32_t ax_freq_table[16] = { 144390000, // APRS - North America
- 145512500, // Arrow - AX25 test frequencies...
- 145537500,
- 145562500,
- 145587500,
- 145612500,
- 145637500,
- 145662500,
- 145687500,
- 145712500,
- 145737500,
- 145762500,
- 145787500,
- 145812500,
- 145837500, // ...145.5 to 145.8 is experimental band
- 145862500 }; // 25kHz spacing
- /* Radio Callback Functions */
- void radio_rx_ax25_cb(uint8_t *frame, uint32_t len)
- {
- // TODO: move kiss processing to other core??
- kiss_transmit(KISS_DATAFRAME, frame, len);
- }
- void radio_tx_ax25_cb(void)
- {
- // unlock scheduling task to allow next packet to be sent
- xSemaphoreGive(xRadioTXSemaphore);
- }
- /* KISS callback Functions */
- void tnc_print_settings(void)
- {
- ESP_LOGI("tnc", "TX Delay: %d", tnc_settings.tx_delay*10);
- ESP_LOGI("tnc", "TX Tail: %d", tnc_settings.tx_tail*10);
- ESP_LOGI("tnc", "Slot Time: %d", tnc_settings.slot_time*10);
- ESP_LOGI("tnc", "P: %d", tnc_settings.P);
- ESP_LOGI("tnc", "Frequency: %d", tnc_settings.freq);
- }
- void kiss_tx_cb(uint8_t *frame, uint32_t len)
- {
- // TODO: move function to other core
- // TODO: Add functionality which indicates if BLE connection is present or not
- // send data to UART via bluetooth
- bt_spp_tx(frame, len);
- ESP_LOGI("tnc", "kiss packet sent");
- }
- void kiss_rx_cb(uint8_t *frame, uint32_t len)
- {
- uint8_t data_byte;
- data_byte = frame[0] & 0x0F; // remove tnc_number information
- // process dataframe
- if (data_byte == KISS_DATAFRAME)
- {
- ESP_LOGI("tnc", "kiss packet received");
- // feed packet to ring buffer
- uint32_t fcs = fcs_calc(&frame[1], len-1);
- frame[len] = fcs & 0xFF;
- frame[len+1] = fcs>>8 & 0xFF;
- if (xRingbufferSend(ax25_tx_buf, &frame[1], ((len+1)*sizeof(uint8_t)),10/portTICK_PERIOD_MS) == pdFALSE)
- {
- ESP_LOGE("tnc", "packet buffer overflow");
- }
- }
- else // assume command
- {
- ESP_LOGI("tnc", "received tnc command");
- switch(data_byte)
- {
- case KISS_CMD_TXDELAY:
- tnc_settings.tx_delay = frame[1];
- break;
- case KISS_CMD_P:
- tnc_settings.P = frame[1];
- break;
- case KISS_CMD_SLOTTIME:
- tnc_settings.slot_time = frame[1];
- break;
- case KISS_CMD_TXTAIL:
- tnc_settings.tx_tail = frame[1];
- break;
- case KISS_CMD_FULLDUPLEX:
- tnc_settings.full_duplex = frame[1];
- break;
- case KISS_CMD_SETHARDWARE:
- {
- uint8_t freq_index = frame[1] & 0x0F;
- tnc_settings.freq = ax_freq_table[freq_index];
- break;
- }
- default:
- ESP_LOGE("tnc", "unknown data byte for KISS protocol");
- }
- // wait for radio to finish transmitting
- ESP_LOGW("tnc", "waiting to disable tnc...");
- while(tnc_settings.status != TNC_RX)
- {
- vTaskDelay(100 / portTICK_PERIOD_MS); // wait 100ms and try again
- }
- // show user new settings
- tnc_print_settings();
- // disable TNC task
- vTaskSuspend(tnc_settings.tnc_task);
- ESP_LOGW("tnc", "disabled tnc");
- // re-initialize radio
- ax25_param_t ax25_param;
- ax25_param.tx_tail = tnc_settings.tx_tail;
- ax25_param.tx_delay = tnc_settings.tx_delay;
- ax25_param.sample_rate = 13200;
- ax25_param.symbol0_freq = 1200;
- ax25_param.symbol1_freq = 2200;
- ax25_param.rx_cb = radio_rx_ax25_cb;
- ax25_param.tx_cb = radio_tx_ax25_cb;
- ax25_param.rx_buf = ax25_rx_buf;
- ax25_param.rx_buf_len = sizeof(ax25_rx_buf) / sizeof(ax25_rx_buf[0]);
- ax25_param.cpu_core = 1;
- radio_reinit(AX25, &ax25_param);
- radio_set_frequency(tnc_settings.freq);
- // set radio back to RX
- radio_packet_rx(NULL);
- // resume TNC task
- vTaskResume(tnc_settings.tnc_task);
- ESP_LOGI("tnc", "re-enabled tnc");
- }
- }
- /* TNC Tasks */
- void tnc_task(void *para)
- {
- uint8_t *packet;
- size_t packet_size;
- uint8_t P;
- radio_packet_rx(NULL);
- tnc_settings.status = TNC_RX;
- while(1)
- {
- // indicate RX
- enable_green_led();
- disable_red_led();
- // check ring buffer for packet
- packet = xRingbufferReceive(ax25_tx_buf, &packet_size, portMAX_DELAY);
- ESP_LOGI("tnc", "scheduling transmission");
- if (packet != NULL)
- {
- // wait based on persistance algorithm
- while (1)
- {
- // TODO: carrier detect is causing a crash somehow when it gets locked on
- // to high. I'm confused as the unit should continue to run despite this...
- if (radio_get_cs() == 0)
- {
- ESP_LOGV("radio", "carrier not detected");
- P = (uint8_t) esp_random();
- if (P <= tnc_settings.P)
- {
- ESP_LOGI("radio", "transmission scheduled");
- break;
- }
- else
- {
- ESP_LOGV("radio", "transmission postponed");
- vTaskDelay((tnc_settings.slot_time * 10) / portTICK_PERIOD_MS);
- }
- }
- else
- {
- ESP_LOGV("radio", "carrier detected");
- vTaskDelay(10 / portTICK_PERIOD_MS); // re-check in 10ms
- }
- }
- // indicate TX
- enable_red_led();
- disable_green_led();
- // TODO: modify code so the full TX DELAY isn't used when multiple packets are sent.
- // dump all the packets in the buffer
- while(packet != NULL)
- {
- // setup packet to be transmitted
- tnc_settings.status = TNC_TX;
- radio_packet_tx(packet, packet_size, NULL);
- // sleep until packet is finished being sent
- xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY);
- tnc_settings.status = TNC_IDLE;
- // remove packet from ring buffer and load next one if it exists
- vRingbufferReturnItem(ax25_tx_buf, (void *)packet);
- packet = xRingbufferReceive(ax25_tx_buf, &packet_size, 0);
- }
- }
- else
- {
- ESP_LOGE("tnc", "buffer error");
- }
- // setup again for reception
- radio_packet_rx(NULL);
- tnc_settings.status = TNC_RX;
- }
- }
- void app_main()
- {
- // Inter-Task Communication
- ax25_tx_buf = xRingbufferCreate(1028, RINGBUF_TYPE_NOSPLIT);
- xRadioTXSemaphore = xSemaphoreCreateBinary();
- // Initialize Flash
- esp_err_t ret = nvs_flash_init();
- if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
- ESP_ERROR_CHECK(nvs_flash_erase());
- ret = nvs_flash_init();
- }
- ESP_ERROR_CHECK( ret );
- // Board IO Initialize
- board_init();
- // Load default TNC settings
- tnc_settings.P = 63;
- tnc_settings.tx_tail = 0; // 10ms units
- tnc_settings.tx_delay = 10; // 10ms units
- tnc_settings.P = 63;
- tnc_settings.slot_time = 10; // 10ms units
- tnc_settings.tnc_number = 0;
- tnc_settings.status = TNC_IDLE;
- tnc_settings.freq = 144390000;
- tnc_settings.mode = AX25;
- // Radio Initialize
- ax25_param_t ax25_param;
- ax25_param.tx_tail = tnc_settings.tx_tail;
- ax25_param.tx_delay = tnc_settings.tx_delay;
- ax25_param.sample_rate = 13200;
- ax25_param.symbol0_freq = 1200;
- ax25_param.symbol1_freq = 2200;
- ax25_param.rx_cb = radio_rx_ax25_cb;
- ax25_param.tx_cb = radio_tx_ax25_cb;
- ax25_param.rx_buf = ax25_rx_buf;
- ax25_param.rx_buf_len = sizeof(ax25_rx_buf) / sizeof(ax25_rx_buf[0]);
- ax25_param.cpu_core = 1;
- // TODO: setup switch statement for settings parameters or for mode....
- tnc_print_settings();
- radio_init(AX25, &ax25_param);
- radio_set_frequency(tnc_settings.freq);
- // Kiss Decoder and Encoder
- kiss_init(tnc_settings.tnc_number, kiss_tx_cb, kiss_rx_cb);
- // BLE and SPP
- bt_spp_init();
- // Tasks
- xTaskCreatePinnedToCore(tnc_task, "tnc task", 1024*4, 0, 2, &tnc_settings.tnc_task, 1);
- }
|