radio.c 11 KB

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