app.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved
  2. * See the LICENSE file for information about the license. */
  3. #pragma once
  4. #include <furi.h>
  5. #include <furi_hal.h>
  6. #include <input/input.h>
  7. #include <gui/gui.h>
  8. #include <stdlib.h>
  9. #include <gui/gui.h>
  10. #include <gui/view_dispatcher.h>
  11. #include <gui/scene_manager.h>
  12. #include <gui/modules/submenu.h>
  13. #include <gui/modules/variable_item_list.h>
  14. #include <gui/modules/widget.h>
  15. #include <gui/modules/text_input.h>
  16. #include <notification/notification_messages.h>
  17. #include <lib/subghz/subghz_setting.h>
  18. #include <lib/subghz/subghz_worker.h>
  19. #include <lib/subghz/receiver.h>
  20. #include <lib/subghz/transmitter.h>
  21. #include <lib/subghz/registry.h>
  22. #include "app_buffer.h"
  23. #define TAG "ProtoView"
  24. #define PROTOVIEW_RAW_VIEW_DEFAULT_SCALE 100 // 100us is 1 pixel by default
  25. #define BITMAP_SEEK_NOT_FOUND UINT32_MAX // Returned by function as sentinel
  26. #define PROTOVIEW_VIEW_PRIVDATA_LEN 64 // View specific private data len
  27. #define DEBUG_MSG 1
  28. typedef struct ProtoViewApp ProtoViewApp;
  29. /* Subghz system state */
  30. typedef enum {
  31. TxRxStateIDLE,
  32. TxRxStateRx,
  33. TxRxStateSleep,
  34. } TxRxState;
  35. /* Currently active view. */
  36. typedef enum {
  37. ViewRawPulses,
  38. ViewInfo,
  39. ViewFrequencySettings,
  40. ViewModulationSettings,
  41. ViewDirectSampling,
  42. ViewLast, /* Just a sentinel to wrap around. */
  43. } ProtoViewCurrentView;
  44. /* Used by app_switch_view() */
  45. typedef enum {
  46. AppNextView,
  47. AppPrevView
  48. } SwitchViewDirection;
  49. typedef struct {
  50. const char *name; // Name to show to the user.
  51. const char *id; // Identifier in the Flipper API/file.
  52. FuriHalSubGhzPreset preset; // The preset ID.
  53. uint8_t *custom; // If not null, a set of registers for
  54. // the CC1101, specifying a custom preset.
  55. } ProtoViewModulation;
  56. extern ProtoViewModulation ProtoViewModulations[]; /* In app_subghz.c */
  57. /* This is the context of our subghz worker and associated thread.
  58. * It receives data and we get our protocol "feed" callback called
  59. * with the level (1 or 0) and duration. */
  60. struct ProtoViewTxRx {
  61. bool freq_mod_changed; /* The user changed frequency and/or modulation
  62. from the interface. There is to restart the
  63. radio with the right parameters. */
  64. SubGhzWorker* worker; /* Our background worker. */
  65. SubGhzEnvironment* environment;
  66. SubGhzReceiver* receiver;
  67. TxRxState txrx_state; /* Receiving, idle or sleeping? */
  68. /* Timer sampling mode state. */
  69. bool debug_timer_sampling; /* Read data from GDO0 in a busy loop. Only
  70. for testing. */
  71. uint32_t last_g0_change_time; /* Last high->low (or reverse) switch. */
  72. bool last_g0_value; /* Current value (high or low): we are
  73. checking the duration in the timer
  74. handler. */
  75. };
  76. typedef struct ProtoViewTxRx ProtoViewTxRx;
  77. /* This stucture is filled by the decoder for specific protocols with the
  78. * informations about the message. ProtoView will display such information
  79. * in the message info view. */
  80. #define PROTOVIEW_MSG_STR_LEN 32
  81. typedef struct ProtoViewMsgInfo {
  82. char name[PROTOVIEW_MSG_STR_LEN]; /* Protocol name and version. */
  83. char raw[PROTOVIEW_MSG_STR_LEN]; /* Protocol specific raw representation.*/
  84. /* The following is what the decoder wants to show to user. Each decoder
  85. * can use the number of fileds it needs. */
  86. char info1[PROTOVIEW_MSG_STR_LEN]; /* Protocol specific info line 1. */
  87. char info2[PROTOVIEW_MSG_STR_LEN]; /* Protocol specific info line 2. */
  88. char info3[PROTOVIEW_MSG_STR_LEN]; /* Protocol specific info line 3. */
  89. char info4[PROTOVIEW_MSG_STR_LEN]; /* Protocol specific info line 4. */
  90. /* Low level information of the detected signal: the following are filled
  91. * by the protocol decoding function: */
  92. uint32_t start_off; /* Pulses start offset in the bitmap. */
  93. uint32_t pulses_count; /* Number of pulses of the full message. */
  94. /* The following are passed already filled to the decoder. */
  95. uint32_t short_pulse_dur; /* Microseconds duration of the short pulse. */
  96. /* The following are filled by ProtoView core after the decoder returned
  97. * success. */
  98. uint8_t *bits; /* Bitmap with the signal. */
  99. uint32_t bits_bytes; /* Number of full bytes in the bitmap, that
  100. is 'pulses_count/8' rounded to the next
  101. integer. */
  102. } ProtoViewMsgInfo;
  103. struct ProtoViewApp {
  104. /* GUI */
  105. Gui *gui;
  106. ViewPort *view_port; /* We just use a raw viewport and we render
  107. everything into the low level canvas. */
  108. ProtoViewCurrentView current_view; /* Active left-right view ID. */
  109. int current_subview[ViewLast]; /* Active up-down subview ID. */
  110. FuriMessageQueue *event_queue; /* Keypress events go here. */
  111. ViewDispatcher *view_dispatcher; /* Used only when we want to show
  112. the text_input view for a moment.
  113. Otherwise it is set to null. */
  114. TextInput *text_input;
  115. bool show_text_input;
  116. char *text_input_buffer;
  117. uint32_t text_input_buffer_len;
  118. void (*text_input_done_callback)(void*);
  119. /* Radio related. */
  120. ProtoViewTxRx *txrx; /* Radio state. */
  121. SubGhzSetting *setting; /* A list of valid frequencies. */
  122. /* Generic app state. */
  123. int running; /* Once false exists the app. */
  124. uint32_t signal_bestlen; /* Longest coherent signal observed so far. */
  125. uint32_t signal_last_scan_idx; /* Index of the buffer last time we
  126. performed the scan. */
  127. bool signal_decoded; /* Was the current signal decoded? */
  128. ProtoViewMsgInfo *msg_info; /* Decoded message info if not NULL. */
  129. bool direct_sampling_enabled; /* This special view needs an explicit
  130. acknowledge to work. */
  131. void *view_privdata; /* This is a piece of memory of total size
  132. PROTOVIEW_VIEW_PRIVDATA_LEN that it is
  133. initialized to zero when we switch to
  134. a a new view. While the view we are using
  135. is the same, it can be used by the view to
  136. store any kind of info inside, just casting
  137. the pointer to a few specific-data structure. */
  138. /* Raw view apps state. */
  139. uint32_t us_scale; /* microseconds per pixel. */
  140. uint32_t signal_offset; /* Long press left/right panning in raw view. */
  141. /* Configuration view app state. */
  142. uint32_t frequency; /* Current frequency. */
  143. uint8_t modulation; /* Current modulation ID, array index in the
  144. ProtoViewModulations table. */
  145. };
  146. typedef struct ProtoViewDecoder {
  147. const char *name; /* Protocol name. */
  148. /* The decode function takes a buffer that is actually a bitmap, with
  149. * high and low levels represented as 0 and 1. The number of high/low
  150. * pulses represented by the bitmap is passed as the 'numbits' argument,
  151. * while 'numbytes' represents the total size of the bitmap pointed by
  152. * 'bits'. So 'numbytes' is mainly useful to pass as argument to other
  153. * functions that perform bit extraction with bound checking, such as
  154. * bitmap_get() and so forth. */
  155. bool (*decode)(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info);
  156. } ProtoViewDecoder;
  157. extern RawSamplesBuffer *RawSamples, *DetectedSamples;
  158. /* app_radio.c */
  159. void radio_begin(ProtoViewApp* app);
  160. uint32_t radio_rx(ProtoViewApp* app);
  161. void radio_idle(ProtoViewApp* app);
  162. void radio_rx_end(ProtoViewApp* app);
  163. void radio_sleep(ProtoViewApp* app);
  164. void raw_sampling_worker_start(ProtoViewApp *app);
  165. void raw_sampling_worker_stop(ProtoViewApp *app);
  166. /* signal.c */
  167. uint32_t duration_delta(uint32_t a, uint32_t b);
  168. void reset_current_signal(ProtoViewApp *app);
  169. void scan_for_signal(ProtoViewApp *app);
  170. bool bitmap_get(uint8_t *b, uint32_t blen, uint32_t bitpos);
  171. void bitmap_set(uint8_t *b, uint32_t blen, uint32_t bitpos, bool val);
  172. void bitmap_copy(uint8_t *d, uint32_t dlen, uint32_t doff, uint8_t *s, uint32_t slen, uint32_t soff, uint32_t count);
  173. void bitmap_set_pattern(uint8_t *b, uint32_t blen, const char *pat);
  174. void bitmap_reverse_bytes(uint8_t *p, uint32_t len);
  175. bool bitmap_match_bits(uint8_t *b, uint32_t blen, uint32_t bitpos, const char *bits);
  176. uint32_t bitmap_seek_bits(uint8_t *b, uint32_t blen, uint32_t startpos, uint32_t maxbits, const char *bits);
  177. uint32_t convert_from_line_code(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t offset, const char *zero_pattern, const char *one_pattern);
  178. uint32_t convert_from_diff_manchester(uint8_t *buf, uint64_t buflen, uint8_t *bits, uint32_t len, uint32_t off, bool previous);
  179. void init_msg_info(ProtoViewMsgInfo *i, ProtoViewApp *app);
  180. void free_msg_info(ProtoViewMsgInfo *i);
  181. /* signal_file.c */
  182. bool save_signal(ProtoViewApp *app, const char *filename);
  183. /* view_*.c */
  184. void render_view_raw_pulses(Canvas *const canvas, ProtoViewApp *app);
  185. void process_input_raw_pulses(ProtoViewApp *app, InputEvent input);
  186. void render_view_settings(Canvas *const canvas, ProtoViewApp *app);
  187. void process_input_settings(ProtoViewApp *app, InputEvent input);
  188. void render_view_info(Canvas *const canvas, ProtoViewApp *app);
  189. void process_input_info(ProtoViewApp *app, InputEvent input);
  190. void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app);
  191. void process_input_direct_sampling(ProtoViewApp *app, InputEvent input);
  192. void view_enter_direct_sampling(ProtoViewApp *app);
  193. void view_exit_direct_sampling(ProtoViewApp *app);
  194. void view_exit_settings(ProtoViewApp *app);
  195. /* ui.c */
  196. int get_current_subview(ProtoViewApp *app);
  197. void show_available_subviews(Canvas *canvas, ProtoViewApp *app, int last_subview);
  198. bool process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview);
  199. void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color);
  200. void show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
  201. void (*done_callback)(void*));
  202. void dismiss_keyboard(ProtoViewApp *app);
  203. /* crc.c */
  204. uint8_t crc8(const uint8_t *data, size_t len, uint8_t init, uint8_t poly);