123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /*
- * 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: Isolate KISS.C functionality
- * TODO: Remove any dependancies on Direwolf.
- * TODO: Transfer DSP functions to APRS folder
- * TODO: Abstract includes to be nicer (#include aprs.h) for example
- * TODO: Isolate CC1200 functions from other parts / maybe integrate most of TX scheme into task.
- */
- /* Standard Includes */
- #include <stdio.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 struct {
- uint8_t tnc_number;
- uint8_t tx_delay;
- uint8_t P;
- uint8_t slot_time;
- uint8_t full_duplex;
- uint8_t tx_tail;
- } 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;
- /* 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 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; // 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
- {
- switch(data_byte)
- {
- case KISS_CMD_TXDELAY:
- ESP_LOGI("tnc", "updated tx delay");
- tnc_settings.tx_delay = frame[1];
- break;
- case KISS_CMD_P:
- ESP_LOGI("tnc", "updated persistance");
- tnc_settings.P = frame[1];
- break;
- case KISS_CMD_SLOTTIME:
- ESP_LOGI("tnc", "updated slot time");
- tnc_settings.slot_time = frame[1];
- break;
- case KISS_CMD_TXTAIL:
- ESP_LOGI("tnc", "updated tx tail");
- tnc_settings.tx_tail = frame[1];
- break;
- case KISS_CMD_FULLDUPLEX:
- ESP_LOGI("tnc", "updated duplex setting");
- tnc_settings.full_duplex = frame[1];
- break;
- case KISS_CMD_SETHARDWARE:
- ESP_LOGI("tnc", "updated hardware settings");
- break;
- case KISS_CMD_RETURN:
- ESP_LOGI("tnc", "wtf is return");
- break;
- default:
- ESP_LOGE("tnc", "unknown data byte for KISS protocol");
- }
- // reload for parameter changes to take effect
- }
- }
- /* TNC Tasks */
- void tnc_task(void *para)
- {
- uint8_t *packet;
- size_t packet_size;
- uint8_t P;
- radio_packet_rx(NULL);
- 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
- radio_packet_tx(packet, packet_size, NULL);
- // sleep until packet is finished being sent
- xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY);
- // 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);
- }
- }
- void IRAM_ATTR 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 Settings from Flash
- // Radio Initialize
- ax25_param_t ax25_param;
- ax25_param.tx_tail = 10;
- ax25_param.tx_delay = 100;
- 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_init(AX25, &ax25_param);
- // Kiss Decoder and Encoder
- kiss_init(0, kiss_tx_cb, kiss_rx_cb);
- // BLE and SPP
- bt_spp_init();
- // TNC Settings
- tnc_settings.slot_time = 10;
- tnc_settings.P = 63;
- tnc_settings.tnc_number = 0;
- // Tasks
- xTaskCreatePinnedToCore(tnc_task, "tnc task", 1024*4, 0, 2, NULL, 1);
- }
|