cc1101-workaround.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "flipper.h"
  2. #include "cc1101-workaround/cc1101.h"
  3. #define RSSI_DELAY 5000 //rssi delay in micro second
  4. #define CHAN_SPA 0.05 // channel spacing
  5. #define F_OSC 26e6
  6. int16_t rssi_to_dbm(uint8_t rssi_dec, uint8_t rssiOffset) {
  7. int16_t rssi;
  8. if(rssi_dec >= 128) {
  9. rssi = (int16_t)((int16_t)(rssi_dec - 256) / 2) - rssiOffset;
  10. } else {
  11. rssi = (rssi_dec / 2) - rssiOffset;
  12. }
  13. return rssi;
  14. }
  15. typedef struct {
  16. float base_freq;
  17. uint8_t reg[3]; // FREQ2, FREQ1, FREQ0
  18. uint8_t first_channel;
  19. uint8_t last_channel;
  20. uint8_t rssi_offset;
  21. } Band;
  22. typedef struct {
  23. const Band* band;
  24. uint16_t channel;
  25. } FreqConfig;
  26. void setup_freq(CC1101* cc1101, const FreqConfig* config) {
  27. // cc1101->SpiWriteReg(CC1101_MCSM0, 0x08); // disalbe FS_AUTOCAL
  28. cc1101->SpiWriteReg(CC1101_AGCCTRL2, 0x43 | 0x0C); // MAX_DVGA_GAIN to 11 for fast rssi
  29. cc1101->SpiWriteReg(CC1101_AGCCTRL0, 0xB0); // max AGC WAIT_TIME; 0 filter_length
  30. cc1101->SetMod(GFSK); // set to GFSK for fast rssi measurement | +8 is dcfilter off
  31. uint32_t freq_reg = config->band->base_freq * 1e6 / (F_OSC / 65536);
  32. cc1101->SetFreq((freq_reg >> 16) & 0xFF, (freq_reg >> 8) & 0xFF, (freq_reg)&0xFF);
  33. cc1101->SetChannel(config->channel);
  34. /*
  35. //set test0 to 0x09
  36. cc1101->SpiWriteReg(CC1101_TEST0, 0x09);
  37. //set FSCAL2 to 0x2A to force VCO HIGH
  38. cc1101->SpiWriteReg(CC1101_FSCAL2, 0x2A);
  39. // perform a manual calibration by issuing SCAL command
  40. cc1101->SpiStrobe(CC1101_SCAL);
  41. */
  42. }
  43. int16_t rx_rssi(CC1101* cc1101, const FreqConfig* config) {
  44. cc1101->SetReceive();
  45. delay_us(RSSI_DELAY);
  46. // 1.4.8) read PKTSTATUS register while the radio is in RX state
  47. /*uint8_t _pkt_status = */ cc1101->SpiReadStatus(CC1101_PKTSTATUS);
  48. // 1.4.9) enter IDLE state by issuing a SIDLE command
  49. cc1101->SpiStrobe(CC1101_SIDLE);
  50. // //read rssi value and converto to dBm form
  51. uint8_t rssi_dec = (uint8_t)cc1101->SpiReadStatus(CC1101_RSSI);
  52. int16_t rssi_dBm = rssi_to_dbm(rssi_dec, config->band->rssi_offset);
  53. return rssi_dBm;
  54. }
  55. void tx(CC1101* cc1101, const FreqConfig* config) {
  56. /*
  57. cc1101->SpiWriteReg(CC1101_MCSM0, 0x18); //enable FS_AUTOCAL
  58. cc1101->SpiWriteReg(CC1101_AGCCTRL2, 0x43); //back to recommended config
  59. cc1101->SpiWriteReg(CC1101_AGCCTRL0, 0x91); //back to recommended config
  60. */
  61. uint32_t freq_reg = config->band->base_freq * 1e6 / (F_OSC / 65536);
  62. cc1101->SetFreq((freq_reg >> 16) & 0xFF, (freq_reg >> 8) & 0xFF, (freq_reg)&0xFF);
  63. cc1101->SetChannel(config->channel);
  64. cc1101->SetTransmit();
  65. }
  66. void idle(CC1101* cc1101) {
  67. cc1101->SpiStrobe(CC1101_SIDLE);
  68. }
  69. // f = (f_osc/65536) * (FREQ + CHAN * (256 + CH_SP_M) * 2^(CH_SP_E - 2))
  70. // FREQ = f / (f_osc/65536)
  71. // CHAN = 0
  72. // TODO: CHAN number not implemented!
  73. // TODO: reg values not affetcts
  74. const Band bands[] = {
  75. {300., {0x00, 0x00, 0x00}, 0, 255, 74},
  76. {315., {0x00, 0x00, 0x00}, 0, 255, 74},
  77. {348., {0x00, 0x00, 0x00}, 0, 255, 74},
  78. {387., {0x00, 0x00, 0x00}, 0, 255, 74},
  79. {433., {0x00, 0x00, 0x00}, 0, 255, 74},
  80. {464., {0x00, 0x00, 0x00}, 0, 255, 74},
  81. {779., {0x00, 0x00, 0x00}, 0, 255, 74},
  82. {868., {0x00, 0x00, 0x00}, 0, 255, 74},
  83. {915., {0x00, 0x00, 0x00}, 0, 255, 74},
  84. {928., {0x00, 0x00, 0x00}, 0, 255, 74},
  85. };
  86. const FreqConfig FREQ_LIST[] = {
  87. {&bands[0], 0},
  88. {&bands[1], 0},
  89. {&bands[2], 0},
  90. {&bands[3], 0},
  91. {&bands[4], 0},
  92. {&bands[5], 0},
  93. {&bands[6], 0},
  94. {&bands[7], 0},
  95. {&bands[8], 0},
  96. {&bands[9], 0},
  97. };
  98. typedef enum {
  99. EventTypeTick,
  100. EventTypeKey,
  101. } EventType;
  102. typedef struct {
  103. union {
  104. InputEvent input;
  105. } value;
  106. EventType type;
  107. } AppEvent;
  108. typedef enum { ModeRx, ModeTx } Mode;
  109. typedef struct {
  110. int16_t dbm;
  111. uint8_t reg;
  112. } TxLevel;
  113. const TxLevel TX_LEVELS[] = {
  114. {-10, 0},
  115. {-5, 0},
  116. {0, 0},
  117. {5, 0},
  118. };
  119. typedef struct {
  120. Mode mode;
  121. size_t active_freq;
  122. int16_t last_rssi;
  123. size_t tx_level;
  124. bool need_cc1101_conf;
  125. } State;
  126. static void render_callback(CanvasApi* canvas, void* ctx) {
  127. State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
  128. canvas->clear(canvas);
  129. canvas->set_color(canvas, ColorBlack);
  130. canvas->set_font(canvas, FontPrimary);
  131. canvas->draw_str(canvas, 2, 12, "cc1101 workaround");
  132. {
  133. char buf[24];
  134. FreqConfig conf = FREQ_LIST[state->active_freq];
  135. float freq = conf.band->base_freq + CHAN_SPA * conf.channel;
  136. sprintf(buf, "freq: %ld.%02ld MHz", (uint32_t)freq, (uint32_t)(freq * 100.) % 100);
  137. canvas->set_font(canvas, FontSecondary);
  138. canvas->draw_str(canvas, 2, 25, buf);
  139. }
  140. {
  141. canvas->set_font(canvas, FontSecondary);
  142. if(state->need_cc1101_conf) {
  143. canvas->draw_str(canvas, 2, 36, "mode: configuring...");
  144. } else if(state->mode == ModeRx) {
  145. canvas->draw_str(canvas, 2, 36, "mode: RX");
  146. } else if(state->mode == ModeTx) {
  147. canvas->draw_str(canvas, 2, 36, "mode: TX");
  148. } else {
  149. canvas->draw_str(canvas, 2, 36, "mode: unknown");
  150. }
  151. }
  152. {
  153. if(!state->need_cc1101_conf && state->mode == ModeRx) {
  154. char buf[24];
  155. sprintf(buf, "RSSI: %d dBm", state->last_rssi);
  156. canvas->set_font(canvas, FontSecondary);
  157. canvas->draw_str(canvas, 2, 48, buf);
  158. }
  159. }
  160. {
  161. char buf[24];
  162. sprintf(buf, "tx level: %d dBm", TX_LEVELS[state->tx_level].dbm);
  163. canvas->set_font(canvas, FontSecondary);
  164. canvas->draw_str(canvas, 2, 63, buf);
  165. }
  166. release_mutex((ValueMutex*)ctx, state);
  167. }
  168. static void input_callback(InputEvent* input_event, void* ctx) {
  169. osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
  170. AppEvent event;
  171. event.type = EventTypeKey;
  172. event.value.input = *input_event;
  173. osMessageQueuePut(event_queue, &event, 0, 0);
  174. }
  175. extern "C" void cc1101_workaround(void* p) {
  176. osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL);
  177. furi_check(event_queue);
  178. State _state;
  179. _state.mode = ModeRx;
  180. _state.active_freq = 0;
  181. _state.need_cc1101_conf = true;
  182. _state.last_rssi = 0;
  183. _state.tx_level = 0;
  184. ValueMutex state_mutex;
  185. if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
  186. printf("[cc1101] cannot create mutex\n");
  187. furiac_exit(NULL);
  188. }
  189. Widget* widget = widget_alloc();
  190. widget_draw_callback_set(widget, render_callback, &state_mutex);
  191. widget_input_callback_set(widget, input_callback, event_queue);
  192. // Open GUI and register widget
  193. GuiApi* gui = (GuiApi*)furi_open("gui");
  194. if(gui == NULL) {
  195. printf("[cc1101] gui is not available\n");
  196. furiac_exit(NULL);
  197. }
  198. gui->add_widget(gui, widget, GuiLayerFullscreen);
  199. printf("[cc1101] creating device\n");
  200. GpioPin cs_pin = {CC1101_CS_GPIO_Port, CC1101_CS_Pin};
  201. // TODO open record
  202. GpioPin* cs_pin_record = &cs_pin;
  203. CC1101 cc1101(cs_pin_record);
  204. printf("[cc1101] init device\n");
  205. uint8_t address = cc1101.Init();
  206. if(address > 0) {
  207. printf("[cc1101] init done: %d\n", address);
  208. } else {
  209. printf("[cc1101] init fail\n");
  210. furiac_exit(NULL);
  211. }
  212. // RX filter bandwidth 58.035714(0xFD) 100k(0xCD) 200k(0x8D)
  213. cc1101.SpiWriteReg(CC1101_MDMCFG4, 0xCD);
  214. // datarate config 250kBaud for the purpose of fast rssi measurement
  215. cc1101.SpiWriteReg(CC1101_MDMCFG3, 0x3B);
  216. // FEC preamble etc. last 2 bits for channel spacing
  217. cc1101.SpiWriteReg(CC1101_MDMCFG1, 0x20);
  218. // 50khz channel spacing
  219. cc1101.SpiWriteReg(CC1101_MDMCFG0, 0xF8);
  220. // TODO open record
  221. GpioPin* led_record = (GpioPin*)&led_gpio[1];
  222. // configure pin
  223. gpio_init(led_record, GpioModeOutputOpenDrain);
  224. const int16_t RSSI_THRESHOLD = -89;
  225. AppEvent event;
  226. while(1) {
  227. osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 150);
  228. State* state = (State*)acquire_mutex_block(&state_mutex);
  229. if(event_status == osOK) {
  230. if(event.type == EventTypeKey) {
  231. if(event.value.input.state && event.value.input.input == InputBack) {
  232. printf("[cc1101] bye!\n");
  233. // TODO remove all widgets create by app
  234. widget_enabled_set(widget, false);
  235. furiac_exit(NULL);
  236. }
  237. if(event.value.input.state && event.value.input.input == InputUp) {
  238. if(state->active_freq > 0) {
  239. state->active_freq--;
  240. state->need_cc1101_conf = true;
  241. }
  242. }
  243. if(event.value.input.state && event.value.input.input == InputDown) {
  244. if(state->active_freq < (sizeof(FREQ_LIST) / sizeof(FREQ_LIST[0]) - 1)) {
  245. state->active_freq++;
  246. state->need_cc1101_conf = true;
  247. }
  248. }
  249. if(event.value.input.state && event.value.input.input == InputLeft) {
  250. if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) {
  251. state->tx_level++;
  252. } else {
  253. state->tx_level = 0;
  254. }
  255. state->need_cc1101_conf = true;
  256. }
  257. if(event.value.input.input == InputOk) {
  258. state->mode = event.value.input.state ? ModeTx : ModeRx;
  259. state->need_cc1101_conf = true;
  260. }
  261. }
  262. } else {
  263. if(!state->need_cc1101_conf && state->mode == ModeRx) {
  264. state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq]);
  265. }
  266. }
  267. if(state->need_cc1101_conf) {
  268. if(state->mode == ModeRx) {
  269. setup_freq(&cc1101, &FREQ_LIST[state->active_freq]);
  270. state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq]);
  271. // idle(&cc1101);
  272. } else if(state->mode == ModeTx) {
  273. tx(&cc1101, &FREQ_LIST[state->active_freq]);
  274. }
  275. state->need_cc1101_conf = false;
  276. }
  277. gpio_write(
  278. led_record,
  279. (state->last_rssi > RSSI_THRESHOLD && !state->need_cc1101_conf) ? false : true);
  280. release_mutex(&state_mutex, state);
  281. widget_update(widget);
  282. }
  283. }