radio.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. uint8_t radio_get_cs(void)
  140. {
  141. return ax25_decoder_get_cs();
  142. }
  143. void radio_packet_tx(uint8_t *data, int32_t len, void *settings)
  144. {
  145. // configure radio for TX
  146. switch (radio_param.type) {
  147. case AX25: {
  148. ESP_LOGI(RADIO_TAG, "transmitting AX25 packet");
  149. // load ax25 encoder state machine
  150. ax25_encoder_encode(data, len);
  151. // configure radio to send CW
  152. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  153. radio_tx();
  154. xSemaphoreGive( xRadioMutex ); // unlock radio
  155. // start sampling timer
  156. timer_radio_start(RADIO_TIMER_TX);
  157. break;
  158. }
  159. default: {
  160. ESP_LOGE(RADIO_TAG, "invalid configuration");
  161. break;
  162. }
  163. }
  164. }
  165. void radio_tx_task(void *para)
  166. {
  167. // variables for transmission
  168. uint32_t sample_count = 0;
  169. uint8_t nrzi_bit = 0;
  170. int8_t amplitude = 0;
  171. // metrics
  172. uint32_t tx_count = 0;
  173. while(1)
  174. {
  175. // block until sampling timer is running
  176. if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
  177. {
  178. if (ax25_encoder_get_status() == READY)
  179. {
  180. // reset sample count used per RF symbol
  181. sample_count = 0;
  182. // setup first amplitude for tone
  183. nrzi_bit = ax25_encoder_get_bit();
  184. amplitude = afsk_get_amplitude(nrzi_bit);
  185. }
  186. else
  187. {
  188. // process error
  189. }
  190. }
  191. // run until packet is finished
  192. while(ax25_encoder_get_status() == READY)
  193. {
  194. // block until semaphore is given or there has been a timing error
  195. if (xSemaphoreTake(xRadioTXSemaphore, portMAX_DELAY) == pdTRUE)
  196. {
  197. // update carrier for AFSK
  198. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  199. cc1200_radio_write_CFM(amplitude);
  200. xSemaphoreGive( xRadioMutex ); // unlock radio
  201. // increment symbol count
  202. sample_count++;
  203. if (sample_count >= 11)
  204. {
  205. GPIO.out_w1ts = (1 << DEBUG_1);
  206. nrzi_bit = ax25_encoder_get_bit();
  207. sample_count = 0;
  208. GPIO.out_w1tc = (1 << DEBUG_1);
  209. }
  210. // get amplitude for next nrzi bit
  211. amplitude = afsk_get_amplitude(nrzi_bit);
  212. }
  213. else
  214. {
  215. ESP_LOGE(RADIO_TAG, "timing error");
  216. ESP_LOGI(RADIO_TAG, "canceling transmission");
  217. break;
  218. }
  219. }
  220. // stop sampling timer
  221. timer_radio_stop();
  222. // confirm if TX failed or not
  223. // ax25_encoder will not reach DONE if their is a timing failure
  224. switch(ax25_encoder_get_status()) {
  225. case STOP:
  226. ESP_LOGI(RADIO_TAG, "transmission complete: [%d]", tx_count++);
  227. break;
  228. case READY:
  229. ESP_LOGE(RADIO_TAG, "transmission failed");
  230. break;
  231. case ERROR:
  232. ESP_LOGE(RADIO_TAG, "encoder error");
  233. break;
  234. default:
  235. ESP_LOGE(RADIO_TAG, "unknown encoder error");
  236. }
  237. // active callback function
  238. if (radio_param.tx_cb != NULL)
  239. {
  240. radio_param.tx_cb();
  241. }
  242. }
  243. }
  244. void radio_rx_task(void *para)
  245. {
  246. // analog variables
  247. int8_t cfm_value=0;
  248. // demod variables
  249. uint8_t raw_bit=0, prev_raw_bit=0;
  250. // pll variables and settings
  251. int32_t d_pll=0, dpll_error=0, err_div=0;
  252. // TODO: The following group should be made user setable fed via the settings
  253. const int32_t SAMPLE_FREQUENCY = 13200;
  254. const int32_t BAUD_RATE = 1200;
  255. const int32_t SAMPLES_BIT = SAMPLE_FREQUENCY / BAUD_RATE;
  256. const int32_t D_PLL_INC = (SAMPLES_BIT * 1);
  257. const int32_t D_PLL_MAX = (D_PLL_INC * SAMPLES_BIT * 1);
  258. const int32_t D_PLL_MARGIN = 1;
  259. // decoder variables
  260. uint32_t success=0;
  261. // task
  262. while(1)
  263. {
  264. // block until semphore is given or there has been a timing error
  265. if (xSemaphoreTake(xRadioRXSemaphore, portMAX_DELAY) == pdTRUE)
  266. {
  267. // read register analog value from radio
  268. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  269. cfm_value = cc1200_radio_read_CFM();
  270. xSemaphoreGive( xRadioMutex ); // unlock radio
  271. // afsk demod
  272. raw_bit = afsk_demod_add_sample(cfm_value);
  273. // clock synchronizer for sampling
  274. if (raw_bit != prev_raw_bit)
  275. {
  276. dpll_error = d_pll - (D_PLL_MAX / 2);
  277. if (dpll_error > D_PLL_MARGIN)
  278. {
  279. d_pll -= ax25_decoder_get_cs() ? D_PLL_MARGIN:
  280. (err_div + dpll_error); //(dpll_error + err_div / 2) / err_div;
  281. }
  282. else if (dpll_error < -D_PLL_MARGIN)
  283. {
  284. d_pll += ax25_decoder_get_cs() ? D_PLL_MARGIN :
  285. -(err_div + dpll_error); // (dpll_error + err_div / 2) / err_div;
  286. }
  287. }
  288. // increment clock
  289. d_pll += D_PLL_INC;
  290. // slice
  291. if (d_pll >= D_PLL_MAX)
  292. {
  293. switch (ax25_decoder_feed_bit(raw_bit))
  294. {
  295. case NORMAL:
  296. break;
  297. case FRAME_DECODED:
  298. ESP_LOGI("radio", "AX25 transmission received: [%d]", success++);
  299. // send via KISS TNC to over BLE SPP
  300. //ESP_LOG_BUFFER_HEXDUMP("APRS RX", aprs_buf, 100, ESP_LOG_INFO);
  301. //kiss_transmit(KISS_DATAFRAME, v.frame_buffer, v.frame_len);
  302. if (radio_param.rx_cb != NULL)
  303. radio_param.rx_cb(ax25_decoder_get_frame(), ax25_decoder_get_frame_len());
  304. break;
  305. case ERROR_FCS_MISMATCH:
  306. ESP_LOGV("radio", "AX25 fcs error");
  307. break;
  308. default:
  309. //printf("Weird Error\n");
  310. break;
  311. }
  312. d_pll -= D_PLL_MAX;
  313. }
  314. prev_raw_bit = raw_bit;
  315. }
  316. else
  317. {
  318. ESP_LOGE(RADIO_TAG, "rx timing error");
  319. }
  320. }
  321. }
  322. // Functionality will depend on protocol
  323. // AX.25 - Non-Block and will activate callback function
  324. void radio_packet_rx(void *settings)
  325. {
  326. switch(radio_param.type)
  327. {
  328. case AX25: {
  329. // reset decoder
  330. ax25_decoder_reset(); // this is required because sometimes it locks up if stopped
  331. // by TX Task
  332. // setup radio
  333. xSemaphoreTake( xRadioMutex, portMAX_DELAY ); // lock radio
  334. radio_rx();
  335. xSemaphoreGive( xRadioMutex ); // unlock radio
  336. // setup sampling timer
  337. timer_radio_start(RADIO_TIMER_RX);
  338. break;
  339. }
  340. default: {
  341. ESP_LOGE(RADIO_TAG, "invalid configuration");
  342. break;
  343. }
  344. }
  345. }
  346. void radio_init(radio_config_t type, void *settings)
  347. {
  348. // create mutux so SPI transactions will be multi-thread safe
  349. // TODO: fix so mutex is only created one to avoid memory leak
  350. xRadioMutex = xSemaphoreCreateMutex();
  351. // lock radio
  352. xSemaphoreTake( xRadioMutex, portMAX_DELAY );
  353. switch(type)
  354. {
  355. case AX25: {
  356. ESP_LOGI("Radio", "APRS Mode");
  357. radio_param.type = AX25;
  358. // cast setting struct
  359. ax25_param_t *p = (ax25_param_t *)settings;
  360. // setup LUT for AFSK demodulator
  361. afsk_mod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  362. // setup frequency detectors for AFSK demodulator
  363. afsk_demod_init(p->sample_rate, p->symbol0_freq, p->symbol1_freq);
  364. // setup encoder for ax25
  365. ax25_encoder_init(p->tx_delay, p->tx_tail);
  366. // setup ax25 decoder
  367. ax25_decoder_init(p->rx_buf, p->rx_buf_len);
  368. radio_param.rx_cb = p->rx_cb;
  369. radio_param.tx_cb = p->tx_cb;
  370. // setup timer for TX / RX
  371. timer_radio_init(p->sample_rate, radio_timer_isr);
  372. // configure CC1200
  373. cc1200_radio_init(AX25_SETTINGS, sizeof(AX25_SETTINGS)/sizeof(cc1200_reg_settings_t));
  374. // put chip to idle
  375. radio_idle();
  376. // task communication
  377. xRadioRXSemaphore = xSemaphoreCreateBinary();
  378. xRadioTXSemaphore = xSemaphoreCreateBinary();
  379. // create task for sampling
  380. // TODO: Reduce stack requirements?
  381. xTaskCreatePinnedToCore(radio_rx_task, "radio rx", 1024*4, 0, 1, NULL, p->cpu_core);
  382. xTaskCreatePinnedToCore(radio_tx_task, "radio tx", 1024*4, 0, 2, NULL, p->cpu_core);
  383. //vTaskSuspend(radio_rx_task);
  384. break;
  385. }
  386. default: {
  387. ESP_LOGE(RADIO_TAG, "invalid configuration");
  388. radio_param.type = NOT_CONFIGURED;
  389. //TODO: Add assert to stop functionality
  390. break;
  391. }
  392. }
  393. // unlock radio
  394. xSemaphoreGive( xRadioMutex );
  395. }