radio.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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 "driver/gpio.h"
  17. #include "radio.h"
  18. #include "cc1200.h"
  19. #include "cc1200_protocol.h"
  20. #include "afsk_modulator.h"
  21. #include "afsk_demodulator.h"
  22. #include "aprs_decoder.h"
  23. #include "aprs_encoder.h"
  24. /* Debugging Tag */
  25. #define RADIO_TAG "radio"
  26. /* Data Structures */
  27. typedef enum {
  28. RADIO_TIMER_NO_CONFIG = 0,
  29. RADIO_TIMER_TX,
  30. RADIO_TIMER_RX,
  31. } timer_radio_semaphore_t;
  32. /* Local Global Variables */
  33. static radio_param_t radio_param = { .type = NOT_CONFIGURED,
  34. .status = RADIO_IDLE,
  35. .rx_cb = NULL,
  36. .tx_cb = NULL };
  37. static SemaphoreHandle_t xRadioTXSemaphore;
  38. static SemaphoreHandle_t xRadioRXSemaphore;
  39. static SemaphoreHandle_t xRadioMutex;
  40. static timer_radio_semaphore_t radio_semaphore;
  41. #define DEBUG_0 16
  42. #define DEBUG_1 4
  43. #define DEBUG_2 32
  44. #define DEBUG_3 33
  45. /* Private Functions */
  46. void IRAM_ATTR radio_timer_isr(void *param)
  47. {
  48. GPIO.out_w1ts = (1 << DEBUG_0);
  49. int timer_idx = (int) param; // cast to int for timer index
  50. TIMERG0.int_clr_timers.t0 = 1; // clear interrupt
  51. TIMERG0.hw_timer[0].config.alarm_en = TIMER_ALARM_EN; // re-enable timer alarm
  52. // provide unblocking semaphore
  53. static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  54. switch(radio_semaphore) {
  55. case RADIO_TIMER_NO_CONFIG:
  56. //ESP_LOGE(RADIO_TAG, "no configuration");
  57. break;
  58. case RADIO_TIMER_RX:
  59. xSemaphoreGiveFromISR(xRadioRXSemaphore, &xHigherPriorityTaskWoken);
  60. break;
  61. case RADIO_TIMER_TX:
  62. xSemaphoreGiveFromISR(xRadioTXSemaphore, &xHigherPriorityTaskWoken);
  63. break;
  64. default:
  65. //ESP_LOGE(RADIO_TAG, "invalid configuration");
  66. break;
  67. }
  68. // wake higher priority task if woken
  69. if (xHigherPriorityTaskWoken == pdTRUE)
  70. {
  71. portYIELD_FROM_ISR();
  72. }
  73. GPIO.out_w1tc = (1 << DEBUG_0);
  74. }
  75. #define RADIO_TIMER_GROUP TIMER_GROUP_0
  76. #define RADIO_TIMER TIMER_0
  77. void timer_radio_init(uint32_t sample_rate, void *timer_isr)
  78. {
  79. // setup timer settings
  80. timer_config_t timer_config;
  81. timer_config.divider = 2;
  82. timer_config.counter_dir = TIMER_COUNT_UP;
  83. timer_config.counter_en = TIMER_PAUSE;
  84. timer_config.alarm_en = TIMER_ALARM_EN;
  85. timer_config.intr_type = TIMER_INTR_LEVEL;
  86. timer_config.auto_reload = TIMER_AUTORELOAD_EN;
  87. // calculate value for timer alarm
  88. // TODO: confirm timer alarm value calculation
  89. uint32_t timer_alarm;
  90. timer_alarm = (uint32_t)(40000000 / sample_rate);
  91. // load timer settings
  92. timer_init(RADIO_TIMER_GROUP, RADIO_TIMER, &timer_config);
  93. timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
  94. timer_set_alarm_value(RADIO_TIMER_GROUP, RADIO_TIMER, 3030);
  95. timer_isr_register(RADIO_TIMER_GROUP, RADIO_TIMER, timer_isr,
  96. (void *) RADIO_TIMER, ESP_INTR_FLAG_IRAM, NULL);
  97. // setup timer ISR semaphore type
  98. radio_semaphore = RADIO_TIMER_NO_CONFIG;
  99. }
  100. void timer_radio_start(timer_radio_semaphore_t type)
  101. {
  102. // setup timer ISR semaphore type
  103. radio_semaphore = type;
  104. // start timer
  105. timer_enable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
  106. timer_set_counter_value(RADIO_TIMER_GROUP, RADIO_TIMER, 0x00000000ULL);
  107. timer_start(RADIO_TIMER_GROUP, RADIO_TIMER);
  108. }
  109. void timer_radio_stop(void)
  110. {
  111. // setup timer ISR semaphore type
  112. radio_semaphore = RADIO_TIMER_NO_CONFIG;
  113. // stop timer
  114. timer_disable_intr(RADIO_TIMER_GROUP, RADIO_TIMER);
  115. timer_pause(RADIO_TIMER_GROUP, RADIO_TIMER);
  116. }
  117. /* HAL Layer */
  118. void radio_rx_task(void *para);
  119. void radio_idle(void)
  120. {
  121. // disable all radio tasks
  122. //vTaskSuspend(radio_rx_task);
  123. // disable all radio timers
  124. timer_radio_stop();
  125. cc1200_radio_idle();
  126. radio_param.status = RADIO_IDLE;
  127. }
  128. void radio_tx(void)
  129. {
  130. if (radio_param.status != RADIO_IDLE)
  131. radio_idle();
  132. cc1200_radio_tx();
  133. radio_param.status = RADIO_TX;
  134. }
  135. void radio_rx(void)
  136. {
  137. if (radio_param.status != RADIO_IDLE)
  138. radio_idle();
  139. cc1200_radio_rx();
  140. radio_param.status = RADIO_RX;
  141. }
  142. radio_status_t radio_get_status(void)
  143. {
  144. return radio_param.status;
  145. }
  146. uint8_t radio_get_cs(void)
  147. {
  148. return ax25_decoder_get_cs();
  149. }
  150. void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
  151. {
  152. // configure radio for TX
  153. switch (radio_param.type) {
  154. case AX25: {
  155. ESP_LOGI(RADIO_TAG, "transmitting AX25 packet");
  156. // load ax25 encoder state machine
  157. ax25_encoder_encode(data, len);
  158. // configure radio to send CW
  159. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  160. radio_tx();
  161. xSemaphoreGive( xRadioMutex ); // unlock radio
  162. // start sampling timer
  163. timer_radio_start(RADIO_TIMER_TX);
  164. break;
  165. }
  166. default: {
  167. ESP_LOGE(RADIO_TAG, "invalid configuration");
  168. break;
  169. }
  170. }
  171. }
  172. void radio_set_frequency(uint32_t freq)
  173. {
  174. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  175. cc1200_radio_frequency(freq);
  176. xSemaphoreGive( xRadioMutex );
  177. }
  178. void radio_tx_task(void *para)
  179. {
  180. // variables for transmission
  181. uint32_t sample_count = 0;
  182. uint8_t nrzi_bit = 0;
  183. int8_t amplitude = 0;
  184. // metrics
  185. uint32_t tx_count = 0;
  186. while(1)
  187. {
  188. // block until sampling timer is running
  189. if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
  190. {
  191. if (ax25_encoder_get_status() == READY)
  192. {
  193. // reset sample count used per RF symbol
  194. sample_count = 0;
  195. // setup first amplitude for tone
  196. nrzi_bit = ax25_encoder_get_bit();
  197. amplitude = afsk_get_amplitude(nrzi_bit);
  198. }
  199. else
  200. {
  201. // process error
  202. }
  203. }
  204. // run until packet is finished
  205. while(ax25_encoder_get_status() == READY)
  206. {
  207. // block until semaphore is given or there has been a timing error
  208. if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
  209. {
  210. // update carrier for AFSK
  211. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  212. cc1200_radio_write_CFM(amplitude);
  213. xSemaphoreGive( xRadioMutex ); // unlock radio
  214. // increment symbol count
  215. sample_count++;
  216. if (sample_count >= 11)
  217. {
  218. GPIO.out_w1ts = (1 << DEBUG_1);
  219. nrzi_bit = ax25_encoder_get_bit();
  220. sample_count = 0;
  221. GPIO.out_w1tc = (1 << DEBUG_1);
  222. }
  223. // get amplitude for next nrzi bit
  224. amplitude = afsk_get_amplitude(nrzi_bit);
  225. }
  226. else
  227. {
  228. ESP_LOGE(RADIO_TAG, "timing error");
  229. ESP_LOGI(RADIO_TAG, "canceling transmission");
  230. break;
  231. }
  232. }
  233. // stop sampling timer
  234. timer_radio_stop();
  235. // confirm if TX failed or not
  236. // ax25_encoder will not reach DONE if their is a timing failure
  237. switch(ax25_encoder_get_status()) {
  238. case STOP:
  239. ESP_LOGI(RADIO_TAG, "transmission complete: [%d]", tx_count++);
  240. break;
  241. case READY:
  242. ESP_LOGE(RADIO_TAG, "transmission failed");
  243. break;
  244. case ERROR:
  245. ESP_LOGE(RADIO_TAG, "encoder error");
  246. break;
  247. default:
  248. ESP_LOGE(RADIO_TAG, "unknown encoder error");
  249. }
  250. // active callback function
  251. if (radio_param.tx_cb != NULL)
  252. {
  253. radio_param.tx_cb();
  254. }
  255. }
  256. }
  257. void radio_rx_task(void *para)
  258. {
  259. // analog variables
  260. int8_t cfm_value=0;
  261. // demod variables
  262. uint8_t raw_bit=0, prev_raw_bit=0;
  263. // pll variables and settings
  264. int32_t d_pll=0, dpll_error=0, err_div=0;
  265. // TODO: The following group should be made user setable fed via the settings
  266. const int32_t SAMPLE_FREQUENCY = 13200;
  267. const int32_t BAUD_RATE = 1200;
  268. const int32_t SAMPLES_BIT = SAMPLE_FREQUENCY / BAUD_RATE;
  269. const int32_t D_PLL_INC = (SAMPLES_BIT * 1);
  270. const int32_t D_PLL_MAX = (D_PLL_INC * SAMPLES_BIT * 1);
  271. const int32_t D_PLL_MARGIN = 1;
  272. // decoder variables
  273. uint32_t success=0;
  274. // task
  275. while(1)
  276. {
  277. // block until semphore is given or there has been a timing error
  278. if (xSemaphoreTake(xRadioRXSemaphore, portMAX_DELAY) == pdTRUE)
  279. {
  280. // read register analog value from radio
  281. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  282. cfm_value = cc1200_radio_read_CFM();
  283. xSemaphoreGive( xRadioMutex ); // unlock radio
  284. // afsk demod
  285. raw_bit = afsk_demod_add_sample(cfm_value);
  286. // clock synchronizer for sampling
  287. if (raw_bit != prev_raw_bit)
  288. {
  289. dpll_error = d_pll - (D_PLL_MAX / 2);
  290. if (dpll_error > D_PLL_MARGIN)
  291. {
  292. d_pll -= ax25_decoder_get_cs() ? D_PLL_MARGIN:
  293. (err_div + dpll_error); //(dpll_error + err_div / 2) / err_div;
  294. }
  295. else if (dpll_error < -D_PLL_MARGIN)
  296. {
  297. d_pll += ax25_decoder_get_cs() ? D_PLL_MARGIN :
  298. -(err_div + dpll_error); // (dpll_error + err_div / 2) / err_div;
  299. }
  300. }
  301. // increment clock
  302. d_pll += D_PLL_INC;
  303. // slice
  304. if (d_pll >= D_PLL_MAX)
  305. {
  306. switch (ax25_decoder_feed_bit(raw_bit))
  307. {
  308. case NORMAL:
  309. break;
  310. case FRAME_DECODED:
  311. ESP_LOGI("radio", "AX25 transmission received: [%d]", success++);
  312. // send via KISS TNC to over BLE SPP
  313. //ESP_LOG_BUFFER_HEXDUMP("APRS RX", aprs_buf, 100, ESP_LOG_INFO);
  314. //kiss_transmit(KISS_DATAFRAME, v.frame_buffer, v.frame_len);
  315. if (radio_param.rx_cb != NULL)
  316. radio_param.rx_cb(ax25_decoder_get_frame(), ax25_decoder_get_frame_len());
  317. break;
  318. case ERROR_FCS_MISMATCH:
  319. ESP_LOGV("radio", "AX25 fcs error");
  320. break;
  321. default:
  322. //printf("Weird Error\n");
  323. break;
  324. }
  325. d_pll -= D_PLL_MAX;
  326. }
  327. prev_raw_bit = raw_bit;
  328. }
  329. else
  330. {
  331. ESP_LOGE(RADIO_TAG, "rx timing error");
  332. }
  333. }
  334. }
  335. // Functionality will depend on protocol
  336. // AX.25 - Non-Block and will activate callback function
  337. void radio_packet_rx(void *settings)
  338. {
  339. switch(radio_param.type)
  340. {
  341. case AX25: {
  342. // reset decoder
  343. ax25_decoder_reset(); // this is required because sometimes it locks up if stopped
  344. // by TX Task
  345. // setup radio
  346. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  347. radio_rx();
  348. xSemaphoreGive( xRadioMutex ); // unlock radio
  349. // setup sampling timer
  350. timer_radio_start(RADIO_TIMER_RX);
  351. break;
  352. }
  353. default: {
  354. ESP_LOGE(RADIO_TAG, "invalid configuration");
  355. break;
  356. }
  357. }
  358. }
  359. void radio_reinit(radio_config_t type, void *settings)
  360. {
  361. // lock radio
  362. xSemaphoreTake(xRadioMutex, portMAX_DELAY);
  363. // disable radio
  364. radio_idle();
  365. // suspend radio tasks
  366. if (radio_param.type == AX25)
  367. {
  368. vTaskSuspend(radio_param.tx_task);
  369. vTaskSuspend(radio_param.rx_task);
  370. }
  371. switch(type)
  372. {
  373. case AX25:
  374. ESP_LOGI(RADIO_TAG, "APRS Mode");
  375. radio_param.type = AX25;
  376. // cast setting struct
  377. ax25_param_t *p = (ax25_param_t *)settings;
  378. // setup LUT for AFSK demodulator
  379. afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  380. // setup frequency detectors for AFSK demodulator
  381. afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  382. // setup encoder for ax25
  383. ax25_encoder_init(p->tx_delay, p->tx_tail);
  384. // setup ax25 decoder
  385. ax25_decoder_init(p->rx_buf, p->rx_buf_len);
  386. radio_param.rx_cb = p->rx_cb;
  387. radio_param.tx_cb = p->tx_cb;
  388. // load AX25_settings without reseting / reloading SPI
  389. cc1200_radio_config(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
  390. // put chip to idle
  391. radio_idle();
  392. // resume radio tasks
  393. break;
  394. default:
  395. ESP_LOGE(RADIO_TAG, "invalid configuration");
  396. radio_param.type = NOT_CONFIGURED;
  397. break;
  398. }
  399. // resume tasks
  400. // suspend radio tasks
  401. if (radio_param.type == AX25)
  402. {
  403. vTaskResume(radio_param.tx_task);
  404. vTaskResume(radio_param.rx_task);
  405. }
  406. xSemaphoreGive(xRadioMutex);
  407. }
  408. void radio_init(radio_config_t type, void *settings)
  409. {
  410. // create mutux so SPI transactions will be multi-thread safe
  411. // TODO: fix so mutex is only created one to avoid memory leak
  412. xRadioMutex = xSemaphoreCreateMutex();
  413. // lock radio
  414. xSemaphoreTake( xRadioMutex, portMAX_DELAY );
  415. switch(type)
  416. {
  417. case AX25: {
  418. ESP_LOGI("Radio", "APRS Mode");
  419. radio_param.type = AX25;
  420. // cast setting struct
  421. ax25_param_t *p = (ax25_param_t *)settings;
  422. // setup LUT for AFSK demodulator
  423. afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  424. // setup frequency detectors for AFSK demodulator
  425. afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  426. // setup encoder for ax25
  427. ax25_encoder_init(p->tx_delay, p->tx_tail);
  428. // setup ax25 decoder
  429. ax25_decoder_init(p->rx_buf, p->rx_buf_len);
  430. radio_param.rx_cb = p->rx_cb;
  431. radio_param.tx_cb = p->tx_cb;
  432. // setup timer for TX / RX
  433. timer_radio_init(p->sample_rate, radio_timer_isr);
  434. // configure CC1200
  435. cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
  436. // put chip to idle
  437. radio_idle();
  438. // task communication
  439. xRadioRXSemaphore = xSemaphoreCreateBinary();
  440. xRadioTXSemaphore = xSemaphoreCreateBinary();
  441. // create task for sampling
  442. // TODO: Reduce stack requirements?
  443. xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, &radio_param.tx_task, p->cpu_core);
  444. xTaskCreatePinnedToCore(radio_tx_task, "radio tx", 1024*4, 0, 2, &radio_param.rx_task, p->cpu_core);
  445. //vTaskSuspend(radio_rx_task);
  446. break;
  447. }
  448. default: {
  449. ESP_LOGE(RADIO_TAG, "invalid configuration");
  450. radio_param.type = NOT_CONFIGURED;
  451. //TODO: Add assert to stop functionality
  452. break;
  453. }
  454. }
  455. // unlock radio
  456. xSemaphoreGive( xRadioMutex );
  457. }