|
@@ -28,16 +28,32 @@
|
|
#include "aprs_encoder.h"
|
|
#include "aprs_encoder.h"
|
|
|
|
|
|
/* Debugging Tag */
|
|
/* Debugging Tag */
|
|
-#define RADIO_TAG "Radio"
|
|
|
|
|
|
+#define RADIO_TAG "radio"
|
|
|
|
+
|
|
|
|
+/* Data Structures */
|
|
|
|
+typedef enum {
|
|
|
|
+ RADIO_TIMER_NO_CONFIG = 0,
|
|
|
|
+ RADIO_TIMER_TX,
|
|
|
|
+ RADIO_TIMER_RX,
|
|
|
|
+} timer_radio_semaphore_t;
|
|
|
|
|
|
/* Local Global Variables */
|
|
/* Local Global Variables */
|
|
static radio_param_t radio_param; // radio configuraiton
|
|
static radio_param_t radio_param; // radio configuraiton
|
|
-static SemaphoreHandle_t xRadioSemaphore; // semphore for sample timing
|
|
|
|
|
|
+//static SemaphoreHandle_t xRadioSemaphore; // semphore for sample timing
|
|
|
|
+static SemaphoreHandle_t xRadioTXSemaphore;
|
|
|
|
+static SemaphoreHandle_t xRadioRXSemaphore;
|
|
|
|
+static SemaphoreHandle_t xRadioMutex;
|
|
|
|
+static timer_radio_semaphore_t radio_semaphore;
|
|
|
|
+
|
|
|
|
+#define DEBUG_0 16
|
|
|
|
+#define DEBUG_1 4
|
|
|
|
+#define DEBUG_2 32
|
|
|
|
+#define DEBUG_3 33
|
|
|
|
|
|
/* Private Functions */
|
|
/* Private Functions */
|
|
void IRAM_ATTR radio_timer_isr(void *param)
|
|
void IRAM_ATTR radio_timer_isr(void *param)
|
|
{
|
|
{
|
|
- //GPIO.out_w1ts = (1 << DEBUG_0);
|
|
|
|
|
|
+ GPIO.out_w1ts = (1 << DEBUG_0);
|
|
|
|
|
|
int timer_idx = (int) param; // cast to int for timer index
|
|
int timer_idx = (int) param; // cast to int for timer index
|
|
TIMERG0.int_clr_timers.t0 = 1; // clear interrupt
|
|
TIMERG0.int_clr_timers.t0 = 1; // clear interrupt
|
|
@@ -45,13 +61,28 @@ void IRAM_ATTR radio_timer_isr(void *param)
|
|
|
|
|
|
// provide unblocking semaphore
|
|
// provide unblocking semaphore
|
|
static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
- xSemaphoreGiveFromISR(xRadioSemaphore, &xHigherPriorityTaskWoken);
|
|
|
|
|
|
+ switch(radio_semaphore) {
|
|
|
|
+ case RADIO_TIMER_NO_CONFIG:
|
|
|
|
+ //ESP_LOGE(RADIO_TAG, "no configuration");
|
|
|
|
+ break;
|
|
|
|
+ case RADIO_TIMER_RX:
|
|
|
|
+ xSemaphoreGiveFromISR(xRadioRXSemaphore, &xHigherPriorityTaskWoken);
|
|
|
|
+ break;
|
|
|
|
+ case RADIO_TIMER_TX:
|
|
|
|
+ xSemaphoreGiveFromISR(xRadioTXSemaphore, &xHigherPriorityTaskWoken);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ //ESP_LOGE(RADIO_TAG, "invalid configuration");
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // wake higher priority task if woken
|
|
if (xHigherPriorityTaskWoken == pdTRUE)
|
|
if (xHigherPriorityTaskWoken == pdTRUE)
|
|
{
|
|
{
|
|
portYIELD_FROM_ISR();
|
|
portYIELD_FROM_ISR();
|
|
}
|
|
}
|
|
|
|
|
|
- //GPIO.out_w1tc = (1 << DEBUG_0);
|
|
|
|
|
|
+ GPIO.out_w1tc = (1 << DEBUG_0);
|
|
}
|
|
}
|
|
|
|
|
|
#define RADIO_TIMER_GROUP TIMER_GROUP_0
|
|
#define RADIO_TIMER_GROUP TIMER_GROUP_0
|
|
@@ -59,6 +90,7 @@ void IRAM_ATTR radio_timer_isr(void *param)
|
|
|
|
|
|
void timer_radio_init(uint32_t sample_rate, void *timer_isr)
|
|
void timer_radio_init(uint32_t sample_rate, void *timer_isr)
|
|
{
|
|
{
|
|
|
|
+ // setup timer settings
|
|
timer_config_t timer_config;
|
|
timer_config_t timer_config;
|
|
|
|
|
|
timer_config.divider = 2;
|
|
timer_config.divider = 2;
|
|
@@ -68,21 +100,28 @@ void timer_radio_init(uint32_t sample_rate, void *timer_isr)
|
|
timer_config.intr_type = TIMER_INTR_LEVEL;
|
|
timer_config.intr_type = TIMER_INTR_LEVEL;
|
|
timer_config.auto_reload = TIMER_AUTORELOAD_EN;
|
|
timer_config.auto_reload = TIMER_AUTORELOAD_EN;
|
|
|
|
|
|
-
|
|
|
|
|
|
+ // calculate value for timer alarm
|
|
|
|
+ // TODO: confirm timer alarm value calculation
|
|
uint32_t timer_alarm;
|
|
uint32_t timer_alarm;
|
|
timer_alarm = (uint32_t)(40000000 / sample_rate);
|
|
timer_alarm = (uint32_t)(40000000 / sample_rate);
|
|
|
|
|
|
- // TODO: confirm timer_alarm calculation
|
|
|
|
-
|
|
|
|
|
|
+ // load timer settings
|
|
timer_init(RADIO_TIMER_GROUP, RADIO_TIMER, &timer_config);
|
|
timer_init(RADIO_TIMER_GROUP, RADIO_TIMER, &timer_config);
|
|
timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
|
|
timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
|
|
timer_set_alarm_value(RADIO_TIMER_GROUP, RADIO_TIMER, 3030);
|
|
timer_set_alarm_value(RADIO_TIMER_GROUP, RADIO_TIMER, 3030);
|
|
timer_isr_register(RADIO_TIMER_GROUP, RADIO_TIMER, timer_isr,
|
|
timer_isr_register(RADIO_TIMER_GROUP, RADIO_TIMER, timer_isr,
|
|
(void *) RADIO_TIMER, ESP_INTR_FLAG_IRAM, NULL);
|
|
(void *) RADIO_TIMER, ESP_INTR_FLAG_IRAM, NULL);
|
|
|
|
+
|
|
|
|
+ // setup timer ISR semaphore type
|
|
|
|
+ radio_semaphore = RADIO_TIMER_NO_CONFIG;
|
|
}
|
|
}
|
|
|
|
|
|
-void timer_radio_start(void)
|
|
|
|
|
|
+void timer_radio_start(timer_radio_semaphore_t type)
|
|
{
|
|
{
|
|
|
|
+ // setup timer ISR semaphore type
|
|
|
|
+ radio_semaphore = type;
|
|
|
|
+
|
|
|
|
+ // start timer
|
|
timer_enable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
timer_enable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
|
|
timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
|
|
timer_start(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
timer_start(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
@@ -90,6 +129,10 @@ void timer_radio_start(void)
|
|
|
|
|
|
void timer_radio_stop(void)
|
|
void timer_radio_stop(void)
|
|
{
|
|
{
|
|
|
|
+ // setup timer ISR semaphore type
|
|
|
|
+ radio_semaphore = RADIO_TIMER_NO_CONFIG;
|
|
|
|
+
|
|
|
|
+ // stop timer
|
|
timer_disable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
timer_disable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
timer_pause(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
timer_pause(RADIO_TIMER_GROUP, RADIO_TIMER);
|
|
}
|
|
}
|
|
@@ -136,120 +179,131 @@ int8_t radio_get_cs()
|
|
return ax25_decoder_get_cs();
|
|
return ax25_decoder_get_cs();
|
|
}
|
|
}
|
|
|
|
|
|
-void radio_init(radio_config_t type, void *settings)
|
|
|
|
-{
|
|
|
|
- switch(type)
|
|
|
|
- {
|
|
|
|
- case AX25: {
|
|
|
|
- ESP_LOGI("Radio", "APRS Mode");
|
|
|
|
- radio_param.type = AX25;
|
|
|
|
-
|
|
|
|
- // cast setting struct
|
|
|
|
- ax25_param_t *p = (ax25_param_t *)settings;
|
|
|
|
|
|
|
|
- // setup LUT for AFSK demodulator
|
|
|
|
- afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
|
|
|
|
|
|
|
|
- // setup frequency detectors for AFSK demodulator
|
|
|
|
- afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
|
|
|
|
|
|
|
|
- // setup encoder for ax25
|
|
|
|
- ax25_encoder_init(p->tx_delay, p->tx_tail);
|
|
|
|
-
|
|
|
|
- // setup ax25 decoder
|
|
|
|
- ax25_decoder_init(p->rx_buf, p->rx_buf_len);
|
|
|
|
- radio_param.rx_cb = p->rx_cb;
|
|
|
|
-
|
|
|
|
- // setup timer for TX / RX
|
|
|
|
- timer_radio_init(p->sample_rate, radio_timer_isr);
|
|
|
|
|
|
+void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
|
|
|
|
+{
|
|
|
|
|
|
- // configure CC1200
|
|
|
|
- cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
|
|
|
|
|
|
|
|
- // put chip to idle
|
|
|
|
- radio_idle();
|
|
|
|
|
|
+ // configure radio for TX
|
|
|
|
+ switch (radio_param.type) {
|
|
|
|
+ case AX25: {
|
|
|
|
+ ESP_LOGI(RADIO_TAG, "transmitting AX25 packet");
|
|
|
|
|
|
- // task communication
|
|
|
|
- xRadioSemaphore = xSemaphoreCreateBinary();
|
|
|
|
|
|
+ // load ax25 encoder state machine
|
|
|
|
+ ax25_encoder_encode(data, len);
|
|
|
|
|
|
- // create task for sampling
|
|
|
|
- // TODO: Reduce stack requirements?
|
|
|
|
- xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, NULL, p->cpu_core);
|
|
|
|
- //vTaskSuspend(radio_rx_task);
|
|
|
|
|
|
+ // configure radio to send CW
|
|
|
|
+ xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
|
|
|
|
+ radio_tx();
|
|
|
|
+ xSemaphoreGive( xRadioMutex ); // unlock radio
|
|
|
|
|
|
|
|
+ // start sampling timer
|
|
|
|
+ timer_radio_start(RADIO_TIMER_TX);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
default: {
|
|
default: {
|
|
ESP_LOGE(RADIO_TAG, "invalid configuration");
|
|
ESP_LOGE(RADIO_TAG, "invalid configuration");
|
|
- radio_param.type = NOT_CONFIGURED;
|
|
|
|
- //TODO: Add assert to stop functionality
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
-// this function will block and configure
|
|
|
|
-// the cc1200 for tx using the protocol setup by "radio_init"
|
|
|
|
-// the buffer holding the packet isn't copied and therefore must be held until
|
|
|
|
-// the function returns
|
|
|
|
-// TODO: Should this be non-blocking and start up a task / wait for an interrupt
|
|
|
|
-// then fire a callback function?
|
|
|
|
-void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
|
|
|
|
|
|
+void radio_tx_task(void *para)
|
|
{
|
|
{
|
|
- switch(radio_param.type)
|
|
|
|
- {
|
|
|
|
- case AX25: {
|
|
|
|
- ESP_LOGV(RADIO_TAG, "transmitting AX25 packet");
|
|
|
|
|
|
+ // variables for transmission
|
|
|
|
+ uint32_t sample_count = 0;
|
|
|
|
+ uint8_t nrzi_bit = 0;
|
|
|
|
+ int8_t amplitude = 0;
|
|
|
|
|
|
- // load ax25 encoder state machine
|
|
|
|
- ax25_encoder_encode(data, len);
|
|
|
|
|
|
+ // metrics
|
|
|
|
+ uint32_t tx_count = 0;
|
|
|
|
|
|
- // variables for symbol timing (11 samples per symbol)
|
|
|
|
- uint32_t sample_count = 0; int8_t tone;
|
|
|
|
- uint8_t bit = ax25_encoder_get_bit();
|
|
|
|
|
|
+ while(1)
|
|
|
|
+ {
|
|
|
|
|
|
- // configure radio to send CW
|
|
|
|
- radio_tx();
|
|
|
|
|
|
+ // block until sampling timer is running
|
|
|
|
+ if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
|
|
|
|
+ {
|
|
|
|
+ if (ax25_encoder_get_status() == READY)
|
|
|
|
+ {
|
|
|
|
+ // reset sample count used per RF symbol
|
|
|
|
+ sample_count = 0;
|
|
|
|
|
|
- // start sampling timer
|
|
|
|
- timer_radio_start();
|
|
|
|
|
|
+ // setup first amplitude for tone
|
|
|
|
+ nrzi_bit = ax25_encoder_get_bit();
|
|
|
|
+ amplitude = afsk_get_amplitude(nrzi_bit);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // process error
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- while(ax25_encoder_get_status() == READY)
|
|
|
|
|
|
+ // run until packet is finished
|
|
|
|
+ while(ax25_encoder_get_status() == READY)
|
|
|
|
+ {
|
|
|
|
+ // block until semaphore is given or there has been a timing error
|
|
|
|
+ if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
|
|
{
|
|
{
|
|
- // TODO: Do we need to feed the WDT here?
|
|
|
|
|
|
+ // update carrier for AFSK
|
|
|
|
+ xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
|
|
|
|
|
|
- // get amplitude for AFSK
|
|
|
|
- tone = afsk_get_amplitude(bit);
|
|
|
|
|
|
+ cc1200_radio_write_CFM(amplitude);
|
|
|
|
|
|
- // pause for semphore
|
|
|
|
- if (xSemaphoreTake(xRadioSemaphore, portMAX_DELAY) == pdTRUE)
|
|
|
|
- {
|
|
|
|
- // update carrier for AFSK
|
|
|
|
- cc1200_radio_write_CFM(tone);
|
|
|
|
-
|
|
|
|
- // inc symbol count
|
|
|
|
- sample_count++;
|
|
|
|
- if (sample_count > 11)
|
|
|
|
- {
|
|
|
|
- bit = ax25_encoder_get_bit();
|
|
|
|
- sample_count = 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ xSemaphoreGive( xRadioMutex ); // unlock radio
|
|
|
|
+
|
|
|
|
+ // increment symbol count
|
|
|
|
+ sample_count++;
|
|
|
|
+ if (sample_count >= 11)
|
|
{
|
|
{
|
|
- ESP_LOGE(RADIO_TAG, "sampling timeout error");
|
|
|
|
- break;
|
|
|
|
|
|
+ GPIO.out_w1ts = (1 << DEBUG_1);
|
|
|
|
+
|
|
|
|
+ nrzi_bit = ax25_encoder_get_bit();
|
|
|
|
+ sample_count = 0;
|
|
|
|
+
|
|
|
|
+ GPIO.out_w1tc = (1 << DEBUG_1);
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // get amplitude for next nrzi bit
|
|
|
|
+ amplitude = afsk_get_amplitude(nrzi_bit);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ ESP_LOGE(RADIO_TAG, "timing error");
|
|
|
|
+ ESP_LOGI(RADIO_TAG, "canceling transmission");
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
- radio_idle();
|
|
|
|
- ESP_LOGV(RADIO_TAG, "transmit complete");
|
|
|
|
- break;
|
|
|
|
}
|
|
}
|
|
- default: {
|
|
|
|
- ESP_LOGE(RADIO_TAG, "invalid configuration");
|
|
|
|
- break;
|
|
|
|
|
|
+
|
|
|
|
+ // stop sampling timer
|
|
|
|
+ timer_radio_stop();
|
|
|
|
+
|
|
|
|
+ // confirm if TX failed or not
|
|
|
|
+ // ax25_encoder will not reach DONE if their is a timing failure
|
|
|
|
+ switch(ax25_encoder_get_status()) {
|
|
|
|
+ case STOP:
|
|
|
|
+ ESP_LOGI(RADIO_TAG, "transmission complete: [%d]", tx_count++);
|
|
|
|
+ break;
|
|
|
|
+ case READY:
|
|
|
|
+ ESP_LOGE(RADIO_TAG, "transmission failed");
|
|
|
|
+ break;
|
|
|
|
+ case ERROR:
|
|
|
|
+ ESP_LOGE(RADIO_TAG, "encoder error");
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ ESP_LOGE(RADIO_TAG, "unknown encoder error");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // active callback function
|
|
|
|
+ if (radio_param.tx_cb != NULL)
|
|
|
|
+ {
|
|
|
|
+ radio_param.tx_cb();
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -265,11 +319,9 @@ void radio_rx_task(void *para)
|
|
int32_t d_pll=0, dpll_error=0, err_div=0;
|
|
int32_t d_pll=0, dpll_error=0, err_div=0;
|
|
|
|
|
|
// TODO: The following group should be made user setable fed via the settings
|
|
// TODO: The following group should be made user setable fed via the settings
|
|
- const int32_t SAMPLE_FREQUENCY = 132000;
|
|
|
|
|
|
+ const int32_t SAMPLE_FREQUENCY = 13200;
|
|
const int32_t BAUD_RATE = 1200;
|
|
const int32_t BAUD_RATE = 1200;
|
|
const int32_t SAMPLES_BIT = SAMPLE_FREQUENCY / BAUD_RATE;
|
|
const int32_t SAMPLES_BIT = SAMPLE_FREQUENCY / BAUD_RATE;
|
|
-
|
|
|
|
-
|
|
|
|
const int32_t D_PLL_INC = (SAMPLES_BIT * 1);
|
|
const int32_t D_PLL_INC = (SAMPLES_BIT * 1);
|
|
const int32_t D_PLL_MAX = (D_PLL_INC * SAMPLES_BIT * 1);
|
|
const int32_t D_PLL_MAX = (D_PLL_INC * SAMPLES_BIT * 1);
|
|
const int32_t D_PLL_MARGIN = 1;
|
|
const int32_t D_PLL_MARGIN = 1;
|
|
@@ -281,10 +333,12 @@ void radio_rx_task(void *para)
|
|
while(1)
|
|
while(1)
|
|
{
|
|
{
|
|
// block until semphore is given or there has been a timing error
|
|
// block until semphore is given or there has been a timing error
|
|
- if (xSemaphoreTake(xRadioSemaphore, portMAX_DELAY) == pdTRUE)
|
|
|
|
|
|
+ if (xSemaphoreTake(xRadioRXSemaphore, portMAX_DELAY) == pdTRUE)
|
|
{
|
|
{
|
|
// read register analog value from radio
|
|
// read register analog value from radio
|
|
|
|
+ xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
|
|
cfm_value = cc1200_radio_read_CFM();
|
|
cfm_value = cc1200_radio_read_CFM();
|
|
|
|
+ xSemaphoreGive( xRadioMutex ); // unlock radio
|
|
|
|
|
|
// afsk demod
|
|
// afsk demod
|
|
raw_bit = afsk_demod_add_sample(cfm_value);
|
|
raw_bit = afsk_demod_add_sample(cfm_value);
|
|
@@ -318,7 +372,7 @@ void radio_rx_task(void *para)
|
|
case NORMAL:
|
|
case NORMAL:
|
|
break;
|
|
break;
|
|
case FRAME_DECODED:
|
|
case FRAME_DECODED:
|
|
- ESP_LOGI("APRS RX", "AX.25 Frame Received [%d]", success++);
|
|
|
|
|
|
+ ESP_LOGI("radio", "AX25 transmission received: [%d]", success++);
|
|
// send via KISS TNC to over BLE SPP
|
|
// send via KISS TNC to over BLE SPP
|
|
//ESP_LOG_BUFFER_HEXDUMP("APRS RX", aprs_buf, 100, ESP_LOG_INFO);
|
|
//ESP_LOG_BUFFER_HEXDUMP("APRS RX", aprs_buf, 100, ESP_LOG_INFO);
|
|
//kiss_transmit(KISS_DATAFRAME, v.frame_buffer, v.frame_len);
|
|
//kiss_transmit(KISS_DATAFRAME, v.frame_buffer, v.frame_len);
|
|
@@ -326,7 +380,7 @@ void radio_rx_task(void *para)
|
|
radio_param.rx_cb(ax25_decoder_get_frame(), ax25_decoder_get_frame_len());
|
|
radio_param.rx_cb(ax25_decoder_get_frame(), ax25_decoder_get_frame_len());
|
|
break;
|
|
break;
|
|
case ERROR_FCS_MISMATCH:
|
|
case ERROR_FCS_MISMATCH:
|
|
- ESP_LOGV("APRS RX", "AX.25 FCS Error\n");
|
|
|
|
|
|
+ ESP_LOGV("radio", "AX25 fcs error");
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
//printf("Weird Error\n");
|
|
//printf("Weird Error\n");
|
|
@@ -338,7 +392,7 @@ void radio_rx_task(void *para)
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- ESP_LOGE(RADIO_TAG, "sampling timeout error");
|
|
|
|
|
|
+ ESP_LOGE(RADIO_TAG, "rx timing error");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -351,14 +405,15 @@ void radio_packet_rx(void *settings)
|
|
{
|
|
{
|
|
case AX25: {
|
|
case AX25: {
|
|
// setup radio
|
|
// setup radio
|
|
|
|
+ xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
|
|
radio_rx();
|
|
radio_rx();
|
|
-
|
|
|
|
|
|
+ xSemaphoreGive( xRadioMutex ); // unlock radio
|
|
// setup sampling timer
|
|
// setup sampling timer
|
|
- timer_radio_start();
|
|
|
|
-
|
|
|
|
|
|
+ // TODO: This may cause a race condition as this will start a task which requires the
|
|
|
|
+ // token to start.
|
|
|
|
+ timer_radio_start(RADIO_TIMER_RX);
|
|
// unsuspend task
|
|
// unsuspend task
|
|
- vTaskResume(radio_rx_task); //??????? should this be top or bottom
|
|
|
|
-
|
|
|
|
|
|
+ //vTaskResume(radio_rx_task); //??????? should this be top or bottom
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
default: {
|
|
default: {
|
|
@@ -367,4 +422,69 @@ void radio_packet_rx(void *settings)
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void radio_init(radio_config_t type, void *settings)
|
|
|
|
+{
|
|
|
|
+ // create mutux so SPI transactions will be multi-thread safe
|
|
|
|
+ // TODO: fix so mutex is only created one to avoid memory leak
|
|
|
|
+ xRadioMutex = xSemaphoreCreateMutex();
|
|
|
|
+
|
|
|
|
+ // lock radio
|
|
|
|
+ xSemaphoreTake( xRadioMutex, portMAX_DELAY );
|
|
|
|
+
|
|
|
|
+ switch(type)
|
|
|
|
+ {
|
|
|
|
+ case AX25: {
|
|
|
|
+ ESP_LOGI("Radio", "APRS Mode");
|
|
|
|
+ radio_param.type = AX25;
|
|
|
|
+
|
|
|
|
+ // cast setting struct
|
|
|
|
+ ax25_param_t *p = (ax25_param_t *)settings;
|
|
|
|
+
|
|
|
|
+ // setup LUT for AFSK demodulator
|
|
|
|
+ afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
|
|
|
|
+
|
|
|
|
+ // setup frequency detectors for AFSK demodulator
|
|
|
|
+ afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
|
|
|
|
+
|
|
|
|
+ // setup encoder for ax25
|
|
|
|
+ ax25_encoder_init(p->tx_delay, p->tx_tail);
|
|
|
|
+
|
|
|
|
+ // setup ax25 decoder
|
|
|
|
+ ax25_decoder_init(p->rx_buf, p->rx_buf_len);
|
|
|
|
+ radio_param.rx_cb = p->rx_cb;
|
|
|
|
+ radio_param.tx_cb = p->tx_cb;
|
|
|
|
+
|
|
|
|
+ // setup timer for TX / RX
|
|
|
|
+ timer_radio_init(p->sample_rate, radio_timer_isr);
|
|
|
|
+
|
|
|
|
+ // configure CC1200
|
|
|
|
+ cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
|
|
|
|
+
|
|
|
|
+ // put chip to idle
|
|
|
|
+ radio_idle();
|
|
|
|
+
|
|
|
|
+ // task communication
|
|
|
|
+ xRadioRXSemaphore = xSemaphoreCreateBinary();
|
|
|
|
+ xRadioTXSemaphore = xSemaphoreCreateBinary();
|
|
|
|
+
|
|
|
|
+ // create task for sampling
|
|
|
|
+ // TODO: Reduce stack requirements?
|
|
|
|
+ xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, NULL, p->cpu_core);
|
|
|
|
+ xTaskCreatePinnedToCore(radio_tx_task, "radio tx", 1024*4, 0, 2, NULL, p->cpu_core);
|
|
|
|
+ //vTaskSuspend(radio_rx_task);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ default: {
|
|
|
|
+ ESP_LOGE(RADIO_TAG, "invalid configuration");
|
|
|
|
+ radio_param.type = NOT_CONFIGURED;
|
|
|
|
+ //TODO: Add assert to stop functionality
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // unlock radio
|
|
|
|
+ xSemaphoreGive( xRadioMutex );
|
|
}
|
|
}
|