radio.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * radio.c
  3. *
  4. * Created on: Oct 11, 2019
  5. * Author: curiousmuch
  6. */
  7. #include <stdio.h>
  8. #include <stdint.h>
  9. #include <math.h>
  10. #include "freertos/FreeRTOS.h"
  11. #include "freertos/task.h"
  12. #include "freertos/semphr.h"
  13. #include "sdkconfig.h"
  14. #include "esp_log.h"
  15. #include "driver/timer.h"
  16. #include "radio.h"
  17. #include "cc1200.h"
  18. #include "cc1200_protocol.h"
  19. #include "afsk_modulator.h"
  20. #include "afsk_demodulator.h"
  21. #include "aprs_decoder.h"
  22. #include "aprs_encoder.h"
  23. /* Debugging Tag */
  24. #define RADIO_TAG "Radio"
  25. /* Local Global Variables */
  26. static radio_param_t radio_param; // radio configuraiton
  27. static SemaphoreHandle_t xRadioSemaphore; // semphore for sample timing
  28. /* Private Functions */
  29. void IRAM_ATTR radio_timer_isr(void *param)
  30. {
  31. //GPIO.out_w1ts = (1 << DEBUG_0);
  32. int timer_idx = (int) param; // cast to int for timer index
  33. TIMERG0.int_clr_timers.t0 = 1; // clear interrupt
  34. TIMERG0.hw_timer[0].config.alarm_en = TIMER_ALARM_EN; // re-enable timer alarm
  35. // provide unblocking semaphore
  36. static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  37. xSemaphoreGiveFromISR(xRadioSemaphore, &xHigherPriorityTaskWoken);
  38. if (xHigherPriorityTaskWoken == pdTRUE)
  39. {
  40. portYIELD_FROM_ISR();
  41. }
  42. //GPIO.out_w1tc = (1 << DEBUG_0);
  43. }
  44. #define RADIO_TIMER_GROUP TIMER_GROUP_0
  45. #define RADIO_TIMER TIMER_0
  46. void timer_radio_init(uint32_t sample_rate, void *timer_isr)
  47. {
  48. timer_config_t timer_config;
  49. timer_config.divider = 2;
  50. timer_config.counter_dir = TIMER_COUNT_UP;
  51. timer_config.counter_en = TIMER_PAUSE;
  52. timer_config.alarm_en = TIMER_ALARM_EN;
  53. timer_config.intr_type = TIMER_INTR_LEVEL;
  54. timer_config.auto_reload = TIMER_AUTORELOAD_EN;
  55. uint32_t timer_alarm;
  56. timer_alarm = (uint32_t)(40000000 / sample_rate);
  57. // TODO: confirm timer_alarm calculation
  58. timer_init(RADIO_TIMER_GROUP, RADIO_TIMER, &timer_config);
  59. timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
  60. timer_set_alarm_value(RADIO_TIMER_GROUP, RADIO_TIMER, 3030);
  61. timer_isr_register(RADIO_TIMER_GROUP, RADIO_TIMER, timer_isr,
  62. (void *) RADIO_TIMER, ESP_INTR_FLAG_IRAM, NULL);
  63. }
  64. void timer_radio_start(void)
  65. {
  66. timer_enable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
  67. timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
  68. timer_start(RADIO_TIMER_GROUP, RADIO_TIMER);
  69. }
  70. void timer_radio_stop(void)
  71. {
  72. timer_disable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
  73. timer_pause(RADIO_TIMER_GROUP, RADIO_TIMER);
  74. }
  75. /* HAL Layer */
  76. void radio_rx_task(void *para);
  77. void radio_idle(void)
  78. {
  79. // disable all radio tasks
  80. //vTaskSuspend(radio_rx_task);
  81. // disable all radio timers
  82. timer_radio_stop();
  83. cc1200_radio_idle();
  84. radio_param.status = RADIO_IDLE;
  85. }
  86. void radio_tx(void)
  87. {
  88. if (radio_param.status != RADIO_IDLE)
  89. radio_idle();
  90. cc1200_radio_tx();
  91. radio_param.status = RADIO_TX;
  92. }
  93. void radio_rx(void)
  94. {
  95. if (radio_param.status != RADIO_IDLE)
  96. radio_idle();
  97. cc1200_radio_rx();
  98. radio_param.status = RADIO_RX;
  99. }
  100. int8_t radio_get_cs()
  101. {
  102. if (radio_param.status != RADIO_RX)
  103. return 0;
  104. else
  105. return ax25_decoder_get_cs();
  106. }
  107. void radio_init(radio_config_t type, void *settings)
  108. {
  109. switch(type)
  110. {
  111. case AX25: {
  112. ESP_LOGI("Radio", "APRS Mode");
  113. radio_param.type = AX25;
  114. // cast setting struct
  115. ax25_param_t *p = (ax25_param_t *)settings;
  116. // setup LUT for AFSK demodulator
  117. afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  118. // setup frequency detectors for AFSK demodulator
  119. afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  120. // setup encoder for ax25
  121. ax25_encoder_init(p->tx_delay, p->tx_tail);
  122. // setup ax25 decoder
  123. ax25_decoder_init(p->rx_buf, p->rx_buf_len);
  124. radio_param.rx_cb = p->rx_cb;
  125. // setup timer for TX / RX
  126. timer_radio_init(p->sample_rate, radio_timer_isr);
  127. // configure CC1200
  128. cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
  129. // put chip to idle
  130. radio_idle();
  131. // task communication
  132. xRadioSemaphore = xSemaphoreCreateBinary();
  133. // create task for sampling
  134. // TODO: Reduce stack requirements?
  135. xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, NULL, p->cpu_core);
  136. //vTaskSuspend(radio_rx_task);
  137. break;
  138. }
  139. default: {
  140. ESP_LOGE(RADIO_TAG, "invalid configuration");
  141. radio_param.type = NOT_CONFIGURED;
  142. //TODO: Add assert to stop functionality
  143. break;
  144. }
  145. }
  146. }
  147. // this function will block and configure
  148. // the cc1200 for tx using the protocol setup by "radio_init"
  149. // the buffer holding the packet isn't copied and therefore must be held until
  150. // the function returns
  151. // TODO: Should this be non-blocking and start up a task / wait for an interrupt
  152. // then fire a callback function?
  153. void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
  154. {
  155. switch(radio_param.type)
  156. {
  157. case AX25: {
  158. ESP_LOGV(RADIO_TAG, "transmitting AX25 packet");
  159. // load ax25 encoder state machine
  160. ax25_encoder_encode(data, len);
  161. // variables for symbol timing (11 samples per symbol)
  162. uint32_t sample_count = 0; int8_t tone;
  163. uint8_t bit = ax25_encoder_get_bit();
  164. // configure radio to send CW
  165. radio_tx();
  166. // start sampling timer
  167. timer_radio_start();
  168. while(ax25_encoder_get_status() == READY)
  169. {
  170. // TODO: Do we need to feed the WDT here?
  171. // get amplitude for AFSK
  172. tone = afsk_get_amplitude(bit);
  173. // pause for semphore
  174. if (xSemaphoreTake(xRadioSemaphore, portMAX_DELAY) == pdTRUE)
  175. {
  176. // update carrier for AFSK
  177. cc1200_radio_write_CFM(tone);
  178. // inc symbol count
  179. sample_count++;
  180. if (sample_count > 11)
  181. {
  182. bit = ax25_encoder_get_bit();
  183. sample_count = 0;
  184. }
  185. }
  186. else
  187. {
  188. ESP_LOGE(RADIO_TAG, "sampling timeout error");
  189. break;
  190. }
  191. }
  192. radio_idle();
  193. ESP_LOGV(RADIO_TAG, "transmit complete");
  194. break;
  195. }
  196. default: {
  197. ESP_LOGE(RADIO_TAG, "invalid configuration");
  198. break;
  199. }
  200. }
  201. }
  202. void radio_rx_task(void *para)
  203. {
  204. // analog variables
  205. int8_t cfm_value=0;
  206. // demod variables
  207. uint8_t raw_bit=0, prev_raw_bit=0;
  208. // pll variables and settings
  209. int32_t d_pll=0, dpll_error=0, err_div=0;
  210. // TODO: The following group should be made user setable fed via the settings
  211. const int32_t SAMPLE_FREQUENCY = 132000;
  212. const int32_t BAUD_RATE = 1200;
  213. const int32_t SAMPLES_BIT = SAMPLE_FREQUENCY / BAUD_RATE;
  214. const int32_t D_PLL_INC = (SAMPLES_BIT * 1);
  215. const int32_t D_PLL_MAX = (D_PLL_INC * SAMPLES_BIT * 1);
  216. const int32_t D_PLL_MARGIN = 1;
  217. // decoder variables
  218. uint32_t success=0;
  219. // task
  220. while(1)
  221. {
  222. // block until semphore is given or there has been a timing error
  223. if (xSemaphoreTake(xRadioSemaphore, portMAX_DELAY) == pdTRUE)
  224. {
  225. // read register analog value from radio
  226. cfm_value = cc1200_radio_read_CFM();
  227. // afsk demod
  228. raw_bit = afsk_demod_add_sample(cfm_value);
  229. // clock synchronizer for sampling
  230. if (raw_bit != prev_raw_bit)
  231. {
  232. dpll_error = d_pll - (D_PLL_MAX / 2);
  233. if (dpll_error > D_PLL_MARGIN)
  234. {
  235. d_pll -= ax25_decoder_get_cs() ? D_PLL_MARGIN:
  236. (err_div + dpll_error); //(dpll_error + err_div / 2) / err_div;
  237. }
  238. else if (dpll_error < -D_PLL_MARGIN)
  239. {
  240. d_pll += ax25_decoder_get_cs() ? D_PLL_MARGIN :
  241. -(err_div + dpll_error); // (dpll_error + err_div / 2) / err_div;
  242. }
  243. }
  244. // increment clock
  245. d_pll += D_PLL_INC;
  246. // slice
  247. if (d_pll >= D_PLL_MAX)
  248. {
  249. switch (ax25_decoder_feed_bit(raw_bit))
  250. {
  251. case NORMAL:
  252. break;
  253. case FRAME_DECODED:
  254. ESP_LOGI("APRS RX", "AX.25 Frame Received [%d]", success++);
  255. // send via KISS TNC to over BLE SPP
  256. //ESP_LOG_BUFFER_HEXDUMP("APRS RX", aprs_buf, 100, ESP_LOG_INFO);
  257. //kiss_transmit(KISS_DATAFRAME, v.frame_buffer, v.frame_len);
  258. if (radio_param.rx_cb != NULL)
  259. radio_param.rx_cb(ax25_decoder_get_frame(), ax25_decoder_get_frame_len());
  260. break;
  261. case ERROR_FCS_MISMATCH:
  262. ESP_LOGV("APRS RX", "AX.25 FCS Error\n");
  263. break;
  264. default:
  265. //printf("Weird Error\n");
  266. break;
  267. }
  268. d_pll -= D_PLL_MAX;
  269. }
  270. prev_raw_bit = raw_bit;
  271. }
  272. else
  273. {
  274. ESP_LOGE(RADIO_TAG, "sampling timeout error");
  275. }
  276. }
  277. }
  278. // Functionality will depend on protocol
  279. // AX.25 - Non-Block and will activate callback function
  280. void radio_packet_rx(void *settings)
  281. {
  282. switch(radio_param.type)
  283. {
  284. case AX25: {
  285. // setup radio
  286. radio_rx();
  287. // setup sampling timer
  288. timer_radio_start();
  289. // unsuspend task
  290. vTaskResume(radio_rx_task); //??????? should this be top or bottom
  291. break;
  292. }
  293. default: {
  294. ESP_LOGE(RADIO_TAG, "invalid configuration");
  295. break;
  296. }
  297. }
  298. }