123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*
- * radio.c
- *
- * Created on: Oct 11, 2019
- * Author: curiousmuch
- */
- #include <stdio.h>
- #include <stdint.h>
- #include <math.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/semphr.h"
- #include "freertos/task.h"
- #include "sdkconfig.h"
- #include "esp_log.h"
- #include "radio.h"
- #include "cc1200.h"
- #include "afsk_modulator.h"
- #include "afsk_demodulator.h"
- #include "aprs_decoder.h"
- #include "aprs_encoder.h"
- /* Debugging Tag */
- #define RADIO_TAG "Radio"
- /* Public Variables */
- radio_param_t radio_param; // radio configuraiton
- SemaphoreHandle_t xRadioSemaphore; // semphore for sample timing
- /* Private Functions */
- void IRAM_ATTR radio_timer_isr(void *param)
- {
- //GPIO.out_w1ts = (1 << DEBUG_0);
- int timer_idx = (int) param; // cast to int for timer index
- TIMERG0.int_clr_timers.t0 = 1; // clear interrupt
- TIMERG0.hw_timer[0].config.alarm_en = TIMER_ALARM_EN; // re-enable timer alarm
- // provide unblocking semaphore
- static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- xSemaphoreGiveFromISR(xRadioSemaphore, &xHigherPriorityTaskWoken);
- if (xHigherPriorityTaskWoken == pdTRUE)
- {
- portYIELD_FROM_ISR();
- }
- //GPIO.out_w1tc = (1 << DEBUG_0);
- }
- #define RADIO_TIMER_GROUP TIMER_GROUP_0
- #define RADIO_TIMER TIMER_0
- void timer_radio_init(uint32_t sample_rate, void *timer_isr)
- {
- timer_config_t timer_config;
- timer_config.divider = 2;
- timer_config.counter_dir = TIMER_COUNT_UP;
- timer_config.counter_en = TIMER_PAUSE;
- timer_config.alarm_en = TIMER_ALARM_EN;
- timer_config.intr_type = TIMER_INTR_LEVEL;
- timer_config.auto_reload = TIMER_AUTORELOAD_EN;
- uint32_t timer_alarm;
- timer_alarm = (uint32_t)(40000000 / sample_rate);
- // TODO: confirm timer_alarm calculation
- timer_init(RADIO_TIMER_GROUP, RADIO_TIMER, &timer_config);
- timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
- timer_set_alarm_value(RADIO_TIMER_GROUP, RADIO_TIMER, 3030);
- timer_isr_register(RADIO_TIMER_GROUP, RADIO_TIMER, timer_isr,
- (void *) RADIO_TIMER, ESP_INTR_FLAG_IRAM, NULL);
- }
- void timer_radio_start(void)
- {
- timer_enable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
- timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
- timer_start(RADIO_TIMER_GROUP, RADIO_TIMER);
- }
- void timer_radio_stop(void)
- {
- timer_disable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
- timer_pause(RADIO_TIMER_GROUP, RADIO_TIMER);
- }
- /* HAL Layer */
- void radio_tx(void)
- {
- cc1200_radio_tx();
- radio_param.status = RADIO_TX;
- }
- void radio_rx(void)
- {
- cc1200_radio_rx();
- radio_param.status = RADIO_RX;
- }
- void radio_idle(void)
- {
- cc1200_radio_idle();
- radio_param.status = RADIO_IDLE;
- }
- 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 timer for TX / RX
- timer_radio_init(p->sample_rate, radio_timer_isr);
- // create task for sampling
- // TODO: Reduce stack requirements?
- // TODO: Should there be an option on which core the driver pins the task too>
- xTaskCreatePinnedToCore(radio_rx_task, "AFSK Sample Task", 1024*4, 0, 1, NULL, 1);
- // xTaskCreatePinnedToCore()
- vTaskSuspend(radio_rx_task);
- // configure CC1200
- cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
- // put chip to idle
- radio_idle();
- break;
- }
- default: {
- ESP_LOGE(RADIO_TAG, "invalid configuration");
- radio_param.type = NOT_CONFIGURED;
- //TODO: Add assert to stop functionality
- 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)
- {
- switch(radio_param.type)
- {
- case AX25: {
- ESP_LOGV(RADIO_TAG, "transmitting AX25 packet");
- // load ax25 encoder state machine
- ax25_encoder_encode(data, len);
- // variables for symbol timing (11 samples per symbol)
- uint32_t sample_count = 0; int8_t tone;
- uint8_t bit = ax25_encoder_get_bit();
- // configure radio to send CW
- radio_tx();
- // start sampling timer
- timer_radio_start();
- while(ax25_encoder_get_status == READY)
- {
- // TODO: Do we need to feed the WDT here?
- // get amplitude for AFSK
- tone = afsk_get_amplitude(bit);
- // 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
- {
- ESP_LOGE(RADIO_TAG, "sample timeout error");
- break;
- }
- }
- radio_idle();
- ESP_LOGV(RADIO_TAG, "transmit complete");
- break;
- }
- default: {
- ESP_LOGE(RADIO_TAG, "invalid configuration");
- break;
- }
- }
- }
- void radio_rx_task(void *para)
- {
- // setup
- // task
- while(1)
- {
- }
- }
- // Functionality will depend on protocol
- // AX.25 - Non-Block and will activate callback function
- void radio_packet_rx(void *settings)
- {
- switch(radio_param.type)
- {
- case AX25: {
- // setup sampling timer
- // un-suspend sampling task
- break;
- }
- default: {
- ESP_LOGE(RADIO_TAG, "invalid configuration");
- break;
- }
- }
- cc1200_radio_rx();
- }
|