|
@@ -4,15 +4,13 @@
|
|
* Description: This project is an APRS transceiver based on the ESP32 and CC1200.
|
|
* Description: This project is an APRS transceiver based on the ESP32 and CC1200.
|
|
* TODO: Refactor Code to isolate into seperate components
|
|
* TODO: Refactor Code to isolate into seperate components
|
|
* TODO: Isolate BT_SPP.C functionality
|
|
* 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: Transfer DSP functions to APRS folder
|
|
* TODO: Abstract includes to be nicer (#include aprs.h) for example
|
|
* 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 */
|
|
/* Standard Includes */
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
|
|
+#include <stddef.h>
|
|
|
|
|
|
/* ESP-IDF */
|
|
/* ESP-IDF */
|
|
#include "sdkconfig.h"
|
|
#include "sdkconfig.h"
|
|
@@ -34,6 +32,12 @@
|
|
|
|
|
|
|
|
|
|
/* Data Structures */
|
|
/* Data Structures */
|
|
|
|
+typedef enum {
|
|
|
|
+ TNC_TX=0,
|
|
|
|
+ TNC_RX,
|
|
|
|
+ TNC_IDLE
|
|
|
|
+} tnc_status_t;
|
|
|
|
+
|
|
typedef struct {
|
|
typedef struct {
|
|
uint8_t tnc_number;
|
|
uint8_t tnc_number;
|
|
uint8_t tx_delay;
|
|
uint8_t tx_delay;
|
|
@@ -41,15 +45,38 @@ typedef struct {
|
|
uint8_t slot_time;
|
|
uint8_t slot_time;
|
|
uint8_t full_duplex;
|
|
uint8_t full_duplex;
|
|
uint8_t tx_tail;
|
|
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;
|
|
} tnc_settings_t;
|
|
|
|
|
|
|
|
+
|
|
/* Public Variables */
|
|
/* Public Variables */
|
|
static tnc_settings_t tnc_settings;
|
|
static tnc_settings_t tnc_settings;
|
|
static SemaphoreHandle_t xRadioTXSemaphore;
|
|
static SemaphoreHandle_t xRadioTXSemaphore;
|
|
-
|
|
|
|
uint8_t ax25_rx_buf[1024];
|
|
uint8_t ax25_rx_buf[1024];
|
|
RingbufHandle_t ax25_tx_buf;
|
|
RingbufHandle_t ax25_tx_buf;
|
|
|
|
|
|
|
|
+uint32_t freq_table[16] = { 144390000, // APRS - North America
|
|
|
|
+ 145512500, // Arrow Test Freqs...
|
|
|
|
+ 145537500,
|
|
|
|
+ 145562500,
|
|
|
|
+ 145587500,
|
|
|
|
+ 145612500,
|
|
|
|
+ 145637500,
|
|
|
|
+ 145662500,
|
|
|
|
+ 145687500,
|
|
|
|
+ 145712500,
|
|
|
|
+ 145737500,
|
|
|
|
+ 145762500,
|
|
|
|
+ 145787500,
|
|
|
|
+ 145812500,
|
|
|
|
+ 145837500, // ...145.5 to 145.8 is experimential band
|
|
|
|
+ 145862500 }; // 25kHz spacing
|
|
|
|
+
|
|
/* Radio Callback Functions */
|
|
/* Radio Callback Functions */
|
|
|
|
|
|
void radio_rx_ax25_cb(uint8_t *frame, uint32_t len)
|
|
void radio_rx_ax25_cb(uint8_t *frame, uint32_t len)
|
|
@@ -75,10 +102,20 @@ void kiss_tx_cb(uint8_t *frame, uint32_t len)
|
|
ESP_LOGI("tnc", "kiss packet sent");
|
|
ESP_LOGI("tnc", "kiss packet sent");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void print_tnc_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_rx_cb(uint8_t *frame, uint32_t len)
|
|
void kiss_rx_cb(uint8_t *frame, uint32_t len)
|
|
{
|
|
{
|
|
uint8_t data_byte;
|
|
uint8_t data_byte;
|
|
- data_byte = frame[0] & 0x0F; // tnc_number information
|
|
|
|
|
|
+ data_byte = frame[0] & 0x0F; // remove tnc_number information
|
|
|
|
|
|
// process dataframe
|
|
// process dataframe
|
|
if (data_byte == KISS_DATAFRAME)
|
|
if (data_byte == KISS_DATAFRAME)
|
|
@@ -97,44 +134,73 @@ void kiss_rx_cb(uint8_t *frame, uint32_t len)
|
|
}
|
|
}
|
|
else // assume command
|
|
else // assume command
|
|
{
|
|
{
|
|
|
|
+ ESP_LOGI("tnc", "received tnc command");
|
|
switch(data_byte)
|
|
switch(data_byte)
|
|
{
|
|
{
|
|
case KISS_CMD_TXDELAY:
|
|
case KISS_CMD_TXDELAY:
|
|
- ESP_LOGI("tnc", "updated tx delay");
|
|
|
|
tnc_settings.tx_delay = frame[1];
|
|
tnc_settings.tx_delay = frame[1];
|
|
break;
|
|
break;
|
|
case KISS_CMD_P:
|
|
case KISS_CMD_P:
|
|
- ESP_LOGI("tnc", "updated persistance");
|
|
|
|
tnc_settings.P = frame[1];
|
|
tnc_settings.P = frame[1];
|
|
break;
|
|
break;
|
|
case KISS_CMD_SLOTTIME:
|
|
case KISS_CMD_SLOTTIME:
|
|
- ESP_LOGI("tnc", "updated slot time");
|
|
|
|
tnc_settings.slot_time = frame[1];
|
|
tnc_settings.slot_time = frame[1];
|
|
break;
|
|
break;
|
|
case KISS_CMD_TXTAIL:
|
|
case KISS_CMD_TXTAIL:
|
|
- ESP_LOGI("tnc", "updated tx tail");
|
|
|
|
tnc_settings.tx_tail = frame[1];
|
|
tnc_settings.tx_tail = frame[1];
|
|
break;
|
|
break;
|
|
case KISS_CMD_FULLDUPLEX:
|
|
case KISS_CMD_FULLDUPLEX:
|
|
- ESP_LOGI("tnc", "updated duplex setting");
|
|
|
|
tnc_settings.full_duplex = frame[1];
|
|
tnc_settings.full_duplex = frame[1];
|
|
break;
|
|
break;
|
|
case KISS_CMD_SETHARDWARE:
|
|
case KISS_CMD_SETHARDWARE:
|
|
- ESP_LOGI("tnc", "updated hardware settings");
|
|
|
|
- break;
|
|
|
|
- case KISS_CMD_RETURN:
|
|
|
|
- ESP_LOGI("tnc", "wtf is return");
|
|
|
|
|
|
+ {
|
|
|
|
+ uint8_t freq_index = frame[1] & 0x0F;
|
|
|
|
+ tnc_settings.freq = freq_table[freq_index];
|
|
break;
|
|
break;
|
|
|
|
+ }
|
|
default:
|
|
default:
|
|
ESP_LOGE("tnc", "unknown data byte for KISS protocol");
|
|
ESP_LOGE("tnc", "unknown data byte for KISS protocol");
|
|
}
|
|
}
|
|
|
|
|
|
- // reload for parameter changes to take effect
|
|
|
|
|
|
+ // 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
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print_tnc_settings();
|
|
|
|
+
|
|
|
|
+ // disable TNC task
|
|
|
|
+ vTaskSuspend(tnc_settings.tnc_task);
|
|
|
|
+ ESP_LOGW("tnc", "disabled tnc");
|
|
|
|
+
|
|
|
|
+ // re-initalize 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 */
|
|
/* TNC Tasks */
|
|
-
|
|
|
|
void tnc_task(void *para)
|
|
void tnc_task(void *para)
|
|
{
|
|
{
|
|
uint8_t *packet;
|
|
uint8_t *packet;
|
|
@@ -142,6 +208,7 @@ void tnc_task(void *para)
|
|
uint8_t P;
|
|
uint8_t P;
|
|
|
|
|
|
radio_packet_rx(NULL);
|
|
radio_packet_rx(NULL);
|
|
|
|
+ tnc_settings.status = TNC_RX;
|
|
|
|
|
|
while(1)
|
|
while(1)
|
|
{
|
|
{
|
|
@@ -173,7 +240,7 @@ void tnc_task(void *para)
|
|
else
|
|
else
|
|
{
|
|
{
|
|
ESP_LOGV("radio", "transmission postponed");
|
|
ESP_LOGV("radio", "transmission postponed");
|
|
- vTaskDelay(tnc_settings.slot_time * 10 / portTICK_PERIOD_MS);
|
|
|
|
|
|
+ vTaskDelay((tnc_settings.slot_time * 10) / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
else
|
|
@@ -192,10 +259,12 @@ void tnc_task(void *para)
|
|
while(packet != NULL)
|
|
while(packet != NULL)
|
|
{
|
|
{
|
|
// setup packet to be transmitted
|
|
// setup packet to be transmitted
|
|
|
|
+ tnc_settings.status = TNC_TX;
|
|
radio_packet_tx(packet, packet_size, NULL);
|
|
radio_packet_tx(packet, packet_size, NULL);
|
|
|
|
|
|
// sleep until packet is finished being sent
|
|
// sleep until packet is finished being sent
|
|
xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY);
|
|
xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY);
|
|
|
|
+ tnc_settings.status = TNC_IDLE;
|
|
|
|
|
|
// remove packet from ring buffer and load next one if it exists
|
|
// remove packet from ring buffer and load next one if it exists
|
|
vRingbufferReturnItem(ax25_tx_buf, (void *)packet);
|
|
vRingbufferReturnItem(ax25_tx_buf, (void *)packet);
|
|
@@ -208,6 +277,7 @@ void tnc_task(void *para)
|
|
}
|
|
}
|
|
// setup again for reception
|
|
// setup again for reception
|
|
radio_packet_rx(NULL);
|
|
radio_packet_rx(NULL);
|
|
|
|
+ tnc_settings.status = TNC_RX;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -228,14 +298,22 @@ void IRAM_ATTR app_main()
|
|
// Board IO Initialize
|
|
// Board IO Initialize
|
|
board_init();
|
|
board_init();
|
|
|
|
|
|
- // Load Settings from Flash
|
|
|
|
-
|
|
|
|
|
|
+ // 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
|
|
// Radio Initialize
|
|
ax25_param_t ax25_param;
|
|
ax25_param_t ax25_param;
|
|
|
|
|
|
- ax25_param.tx_tail = 10;
|
|
|
|
- ax25_param.tx_delay = 100;
|
|
|
|
|
|
+ ax25_param.tx_tail = tnc_settings.tx_tail;
|
|
|
|
+ ax25_param.tx_delay = tnc_settings.tx_delay;
|
|
ax25_param.sample_rate = 13200;
|
|
ax25_param.sample_rate = 13200;
|
|
ax25_param.symbol0_freq = 1200;
|
|
ax25_param.symbol0_freq = 1200;
|
|
ax25_param.symbol1_freq = 2200;
|
|
ax25_param.symbol1_freq = 2200;
|
|
@@ -245,21 +323,19 @@ void IRAM_ATTR app_main()
|
|
ax25_param.rx_buf_len = sizeof(ax25_rx_buf) / sizeof(ax25_rx_buf[0]);
|
|
ax25_param.rx_buf_len = sizeof(ax25_rx_buf) / sizeof(ax25_rx_buf[0]);
|
|
ax25_param.cpu_core = 1;
|
|
ax25_param.cpu_core = 1;
|
|
|
|
|
|
|
|
+ // TODO: setup switch statement for settings parameters or simplify....
|
|
|
|
+ print_tnc_settings();
|
|
radio_init(AX25, &ax25_param);
|
|
radio_init(AX25, &ax25_param);
|
|
|
|
|
|
|
|
+ radio_set_frequency(tnc_settings.freq);
|
|
|
|
+
|
|
// Kiss Decoder and Encoder
|
|
// Kiss Decoder and Encoder
|
|
- kiss_init(0, kiss_tx_cb, kiss_rx_cb);
|
|
|
|
|
|
+ kiss_init(tnc_settings.tnc_number, kiss_tx_cb, kiss_rx_cb);
|
|
|
|
|
|
// BLE and SPP
|
|
// BLE and SPP
|
|
bt_spp_init();
|
|
bt_spp_init();
|
|
|
|
|
|
- // TNC Settings
|
|
|
|
- tnc_settings.slot_time = 10;
|
|
|
|
- tnc_settings.P = 63;
|
|
|
|
- tnc_settings.tnc_number = 0;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
// Tasks
|
|
// Tasks
|
|
- xTaskCreatePinnedToCore(tnc_task, "tnc task", 1024*4, 0, 2, NULL, 1);
|
|
|
|
|
|
+ xTaskCreatePinnedToCore(tnc_task, "tnc task", 1024*4, 0, 2, &tnc_settings.tnc_task, 1);
|
|
|
|
|
|
}
|
|
}
|