subghz_test_packet.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "subghz_test_packet.h"
  2. #include "../subghz_i.h"
  3. #include <math.h>
  4. #include <furi.h>
  5. #include <api-hal.h>
  6. #include <input/input.h>
  7. #include <toolbox/level_duration.h>
  8. #include <lib/subghz/protocols/subghz_protocol_princeton.h>
  9. #define SUBGHZ_TEST_PACKET_COUNT 1000
  10. #define SUBGHZ_PT_SHORT 376
  11. #define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3)
  12. #define SUBGHZ_PT_GUARD 10600
  13. struct SubghzTestPacket {
  14. View* view;
  15. osTimerId timer;
  16. size_t tx_buffer_size;
  17. uint32_t* tx_buffer;
  18. SubGhzProtocolPrinceton* princeton;
  19. volatile size_t packet_rx;
  20. };
  21. typedef enum {
  22. SubghzTestPacketModelStatusRx,
  23. SubghzTestPacketModelStatusTx,
  24. } SubghzTestPacketModelStatus;
  25. typedef struct {
  26. uint8_t frequency;
  27. uint32_t real_frequency;
  28. ApiHalSubGhzPath path;
  29. float rssi;
  30. size_t packets;
  31. SubghzTestPacketModelStatus status;
  32. } SubghzTestPacketModel;
  33. volatile bool subghz_test_packet_overrun = false;
  34. static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void* context) {
  35. furi_assert(context);
  36. SubghzTestPacket* instance = context;
  37. subghz_protocol_princeton_parse(instance->princeton, level, duration);
  38. }
  39. static void subghz_test_packet_rx_pt_callback(SubGhzProtocolCommon* parser, void* context) {
  40. furi_assert(context);
  41. SubghzTestPacket* instance = context;
  42. instance->packet_rx++;
  43. }
  44. static void subghz_test_packet_rssi_timer_callback(void* context) {
  45. furi_assert(context);
  46. SubghzTestPacket* instance = context;
  47. with_view_model(
  48. instance->view, (SubghzTestPacketModel * model) {
  49. if(model->status == SubghzTestPacketModelStatusRx) {
  50. model->rssi = api_hal_subghz_get_rssi();
  51. model->packets = instance->packet_rx;
  52. } else {
  53. model->packets =
  54. SUBGHZ_TEST_PACKET_COUNT - api_hal_subghz_get_async_tx_repeat_left();
  55. }
  56. return true;
  57. });
  58. }
  59. static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model) {
  60. char buffer[64];
  61. canvas_set_color(canvas, ColorBlack);
  62. canvas_set_font(canvas, FontPrimary);
  63. canvas_draw_str(canvas, 0, 8, "CC1101 Packet Test");
  64. canvas_set_font(canvas, FontSecondary);
  65. // Frequency
  66. snprintf(
  67. buffer,
  68. sizeof(buffer),
  69. "Freq: %03ld.%03ld.%03ld Hz",
  70. model->real_frequency / 1000000 % 1000,
  71. model->real_frequency / 1000 % 1000,
  72. model->real_frequency % 1000);
  73. canvas_draw_str(canvas, 0, 20, buffer);
  74. // Path
  75. char* path_name = "Unknown";
  76. if(model->path == ApiHalSubGhzPathIsolate) {
  77. path_name = "isolate";
  78. } else if(model->path == ApiHalSubGhzPath433) {
  79. path_name = "433MHz";
  80. } else if(model->path == ApiHalSubGhzPath315) {
  81. path_name = "315MHz";
  82. } else if(model->path == ApiHalSubGhzPath868) {
  83. path_name = "868MHz";
  84. }
  85. snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name);
  86. canvas_draw_str(canvas, 0, 31, buffer);
  87. snprintf(buffer, sizeof(buffer), "Packets: %d", model->packets);
  88. canvas_draw_str(canvas, 0, 42, buffer);
  89. if(model->status == SubghzTestPacketModelStatusRx) {
  90. snprintf(
  91. buffer,
  92. sizeof(buffer),
  93. "RSSI: %ld.%ld dBm",
  94. (int32_t)(model->rssi),
  95. (int32_t)fabs(model->rssi * 10) % 10);
  96. canvas_draw_str(canvas, 0, 53, buffer);
  97. } else {
  98. canvas_draw_str(canvas, 0, 53, "TX");
  99. }
  100. }
  101. static bool subghz_test_packet_input(InputEvent* event, void* context) {
  102. furi_assert(context);
  103. SubghzTestPacket* instance = context;
  104. if(event->key == InputKeyBack) {
  105. return false;
  106. }
  107. with_view_model(
  108. instance->view, (SubghzTestPacketModel * model) {
  109. if(model->status == SubghzTestPacketModelStatusRx) {
  110. api_hal_subghz_stop_async_rx();
  111. } else {
  112. api_hal_subghz_stop_async_tx();
  113. }
  114. if(event->type == InputTypeShort) {
  115. if(event->key == InputKeyLeft) {
  116. if(model->frequency > 0) model->frequency--;
  117. } else if(event->key == InputKeyRight) {
  118. if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
  119. } else if(event->key == InputKeyDown) {
  120. if(model->path > 0) model->path--;
  121. } else if(event->key == InputKeyUp) {
  122. if(model->path < ApiHalSubGhzPath868) model->path++;
  123. } else if(event->key == InputKeyOk) {
  124. if(model->status == SubghzTestPacketModelStatusTx) {
  125. model->status = SubghzTestPacketModelStatusRx;
  126. } else {
  127. model->status = SubghzTestPacketModelStatusTx;
  128. }
  129. }
  130. model->real_frequency =
  131. api_hal_subghz_set_frequency(subghz_frequencies[model->frequency]);
  132. api_hal_subghz_set_path(model->path);
  133. }
  134. if(model->status == SubghzTestPacketModelStatusRx) {
  135. api_hal_subghz_start_async_rx();
  136. } else {
  137. api_hal_subghz_start_async_tx(
  138. instance->tx_buffer, instance->tx_buffer_size, SUBGHZ_TEST_PACKET_COUNT);
  139. }
  140. return true;
  141. });
  142. return true;
  143. }
  144. void subghz_test_packet_enter(void* context) {
  145. furi_assert(context);
  146. SubghzTestPacket* instance = context;
  147. instance->tx_buffer_size = 25 * 2 * sizeof(uint32_t);
  148. instance->tx_buffer = furi_alloc(instance->tx_buffer_size);
  149. const uint32_t key = 0x00ABCDEF;
  150. size_t pos = 0;
  151. for(uint8_t i = 0; i < 24; i++) {
  152. uint8_t byte = i / 8;
  153. uint8_t bit = i % 8;
  154. bool value = (((uint8_t*)&key)[2 - byte] >> (7 - bit)) & 1;
  155. if(value) {
  156. instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT;
  157. instance->tx_buffer[pos++] = SUBGHZ_PT_LONG;
  158. } else {
  159. instance->tx_buffer[pos++] = SUBGHZ_PT_LONG;
  160. instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT;
  161. }
  162. }
  163. instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT;
  164. instance->tx_buffer[pos++] = SUBGHZ_PT_SHORT + SUBGHZ_PT_GUARD;
  165. api_hal_subghz_reset();
  166. api_hal_subghz_load_preset(ApiHalSubGhzPresetOokAsync);
  167. api_hal_subghz_set_async_rx_callback(subghz_test_packet_rx_callback, instance);
  168. with_view_model(
  169. instance->view, (SubghzTestPacketModel * model) {
  170. model->frequency = subghz_frequencies_433_92;
  171. model->real_frequency =
  172. api_hal_subghz_set_frequency(subghz_frequencies[model->frequency]);
  173. model->path = ApiHalSubGhzPathIsolate; // isolate
  174. model->rssi = 0.0f;
  175. model->status = SubghzTestPacketModelStatusRx;
  176. return true;
  177. });
  178. api_hal_subghz_start_async_rx();
  179. osTimerStart(instance->timer, 1024 / 4);
  180. }
  181. void subghz_test_packet_exit(void* context) {
  182. furi_assert(context);
  183. SubghzTestPacket* instance = context;
  184. osTimerStop(instance->timer);
  185. // Reinitialize IC to default state
  186. with_view_model(
  187. instance->view, (SubghzTestPacketModel * model) {
  188. if(model->status == SubghzTestPacketModelStatusRx) {
  189. api_hal_subghz_stop_async_rx();
  190. } else {
  191. api_hal_subghz_stop_async_tx();
  192. }
  193. return true;
  194. });
  195. api_hal_subghz_set_async_rx_callback(NULL, NULL);
  196. api_hal_subghz_sleep();
  197. }
  198. uint32_t subghz_test_packet_back(void* context) {
  199. return SubGhzViewMenu;
  200. }
  201. SubghzTestPacket* subghz_test_packet_alloc() {
  202. SubghzTestPacket* instance = furi_alloc(sizeof(SubghzTestPacket));
  203. // View allocation and configuration
  204. instance->view = view_alloc();
  205. view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(SubghzTestPacketModel));
  206. view_set_context(instance->view, instance);
  207. view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw);
  208. view_set_input_callback(instance->view, subghz_test_packet_input);
  209. view_set_enter_callback(instance->view, subghz_test_packet_enter);
  210. view_set_exit_callback(instance->view, subghz_test_packet_exit);
  211. view_set_previous_callback(instance->view, subghz_test_packet_back);
  212. instance->timer =
  213. osTimerNew(subghz_test_packet_rssi_timer_callback, osTimerPeriodic, instance, NULL);
  214. instance->princeton = subghz_protocol_princeton_alloc();
  215. subghz_protocol_common_set_callback(
  216. (SubGhzProtocolCommon*)instance->princeton, subghz_test_packet_rx_pt_callback, instance);
  217. return instance;
  218. }
  219. void subghz_test_packet_free(SubghzTestPacket* instance) {
  220. furi_assert(instance);
  221. subghz_protocol_princeton_free(instance->princeton);
  222. osTimerDelete(instance->timer);
  223. view_free(instance->view);
  224. free(instance);
  225. }
  226. View* subghz_test_packet_get_view(SubghzTestPacket* instance) {
  227. furi_assert(instance);
  228. return instance->view;
  229. }