diff --git a/applications/dec_hex_converter/application.fam b/applications/dec_hex_converter/application.fam new file mode 100644 index 000000000..062c40b26 --- /dev/null +++ b/applications/dec_hex_converter/application.fam @@ -0,0 +1,10 @@ +App( + appid="dec_hex_converter", + name="Dec/Hex Converter", + apptype=FlipperAppType.PLUGIN, + entry_point="dec_hex_converter_app", + cdefines=["APP_DEC_HEX_CONVERTER"], + requires=["gui"], + stack_size=1 * 1024, + order=19, +) diff --git a/applications/dec_hex_converter/dec_hex_converter.c b/applications/dec_hex_converter/dec_hex_converter.c new file mode 100644 index 000000000..1661dbd16 --- /dev/null +++ b/applications/dec_hex_converter/dec_hex_converter.c @@ -0,0 +1,404 @@ +#include +#include +#include +#include + +#define DEC_HEX_CONVERTER_NUMBER_DIGITS 9 +#define DEC_HEX_CONVERTER_KEYS 18 +#define DEC_HEX_CONVERTER_KEY_DEL 16 +// #define DEC_HEX_CONVERTER_KEY_SWAP 17 // actually not used... + +#define DEC_HEX_CONVERTER_CHAR_DEL '<' +#define DEC_HEX_CONVERTER_CHAR_SWAP 's' +#define DEC_HEX_CONVERTER_CHAR_MODE '#' +#define DEC_HEX_CONVERTER_CHAR_OVERFLOW '#' + +#define DEC_HEX_CONVERTER_KEY_FRAME_MARGIN 3 +#define DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT 8 + +#define DEC_HEX_MAX_SUPORTED_DEC_INT 999999999 + +typedef enum { + EventTypeKey, +} EventType; + +typedef struct { + InputEvent input; + EventType type; +} DecHexConverterEvent; + +typedef enum { + ModeDec, + ModeHex, +} Mode; + +// setting up one char array next to the other one causes the canvas_draw_str to display both of them +// when addressing the first one if there's no string terminator or similar indicator. Adding a \0 seems +// to work fine to prevent that, so add a final last char outside the size constants (added on init +// and NEVER changed nor referenced again) +// +// (as a reference, canvas_draw_str ends up calling u8g2_DrawStr from u8g2_font.c, +// that finally ends up calling u8g2_draw_string) +typedef struct { + char dec_number[DEC_HEX_CONVERTER_NUMBER_DIGITS + 1]; + char hex_number[DEC_HEX_CONVERTER_NUMBER_DIGITS + 1]; + Mode mode; // dec / hex + int8_t cursor; // position on keyboard (includes digit letters and other options) + int8_t digit_pos; // current digit on selected mode +} DecHexConverterState; + +// move cursor left / right (TODO: implement menu nav in a more "standard" and reusable way?) +void dec_hex_converter_logic_move_cursor_lr( + DecHexConverterState* const dec_hex_converter_state, + int8_t d) { + dec_hex_converter_state->cursor += d; + + if(dec_hex_converter_state->cursor > DEC_HEX_CONVERTER_KEYS - 1) + dec_hex_converter_state->cursor = 0; + else if(dec_hex_converter_state->cursor < 0) + dec_hex_converter_state->cursor = DEC_HEX_CONVERTER_KEYS - 1; + + // if we're moving left / right to the letters keys on ModeDec just go to the closest available key + if(dec_hex_converter_state->mode == ModeDec) { + if(dec_hex_converter_state->cursor == 10) + dec_hex_converter_state->cursor = 16; + else if(dec_hex_converter_state->cursor == 15) + dec_hex_converter_state->cursor = 9; + } +} + +// move cursor up / down; there're two lines, so we basically toggle +void dec_hex_converter_logic_move_cursor_ud(DecHexConverterState* const dec_hex_converter_state) { + if(dec_hex_converter_state->cursor < 9) { + // move to second line ("down") + dec_hex_converter_state->cursor += 9; + + // if we're reaching the letter keys while ModeDec, just move left / right for the first available key + if(dec_hex_converter_state->mode == ModeDec && + (dec_hex_converter_state->cursor >= 10 && dec_hex_converter_state->cursor <= 15)) { + if(dec_hex_converter_state->cursor <= 12) + dec_hex_converter_state->cursor = 9; + else + dec_hex_converter_state->cursor = 16; + } + } else { + // move to first line ("up") + dec_hex_converter_state->cursor -= 9; + } +} + +// fetch number from current mode and modifies the destination one, RM dnt stel pls +// (if destination is shorter than the output value, overried with "-" chars or something similar) +void dec_hex_converter_logic_convert_number(DecHexConverterState* const dec_hex_converter_state) { + char* s_ptr; + char* d_ptr; + + char dest[DEC_HEX_CONVERTER_NUMBER_DIGITS]; + int i = 0; // current index on destination array + + if(dec_hex_converter_state->mode == ModeDec) { + // DEC to HEX cannot overflow if they're, at least, the same size + + s_ptr = dec_hex_converter_state->dec_number; + d_ptr = dec_hex_converter_state->hex_number; + + int a = atoi(s_ptr); + int r; + while(a != 0) { + r = a % 16; + dest[i] = r + (r < 10 ? '0' : ('A' - 10)); + a /= 16; + i++; + } + + } else { + s_ptr = dec_hex_converter_state->hex_number; + d_ptr = dec_hex_converter_state->dec_number; + + int a = strtol(s_ptr, NULL, 16); + if(a > DEC_HEX_MAX_SUPORTED_DEC_INT) { + // draw all "###" if there's an overflow + for(int j = 0; j < DEC_HEX_CONVERTER_NUMBER_DIGITS; j++) { + d_ptr[j] = DEC_HEX_CONVERTER_CHAR_OVERFLOW; + } + return; + } else { + while(a > 0) { + dest[i++] = (a % 10) + '0'; + a /= 10; + } + } + } + + // dest is reversed, copy to destination pointer and append empty chars at the end + for(int j = 0; j < DEC_HEX_CONVERTER_NUMBER_DIGITS; j++) { + if(i >= 1) + d_ptr[j] = dest[--i]; + else + d_ptr[j] = ' '; + } +} + +// change from DEC to HEX or HEX to DEC, set the digit_pos to the last position not empty on the destination mode +void dec_hex_converter_logic_swap_mode(DecHexConverterState* const dec_hex_converter_state) { + char* n_ptr; + if(dec_hex_converter_state->mode == ModeDec) { + dec_hex_converter_state->mode = ModeHex; + n_ptr = dec_hex_converter_state->hex_number; + } else { + dec_hex_converter_state->mode = ModeDec; + n_ptr = dec_hex_converter_state->dec_number; + } + + dec_hex_converter_state->digit_pos = DEC_HEX_CONVERTER_NUMBER_DIGITS; + for(int i = 0; i < DEC_HEX_CONVERTER_NUMBER_DIGITS; i++) { + if(n_ptr[i] == ' ') { + dec_hex_converter_state->digit_pos = i; + break; + } + } +} + +// removes the number on current digit on current mode +static void + dec_hex_converter_logic_del_number(DecHexConverterState* const dec_hex_converter_state) { + if(dec_hex_converter_state->digit_pos > 0) dec_hex_converter_state->digit_pos--; + + if(dec_hex_converter_state->mode == ModeDec) { + dec_hex_converter_state->dec_number[dec_hex_converter_state->digit_pos] = ' '; + } else { + dec_hex_converter_state->hex_number[dec_hex_converter_state->digit_pos] = ' '; + } +} + +// append a number to the digit on the current mode +static void dec_hex_converter_logic_add_number( + DecHexConverterState* const dec_hex_converter_state, + int8_t number) { + // ignore HEX values on DEC mode (probably button nav will be disabled too, so cannot reach); + // also do not add anything if we're out of bound + if((number > 9 && dec_hex_converter_state->mode == ModeDec) || + dec_hex_converter_state->digit_pos >= DEC_HEX_CONVERTER_NUMBER_DIGITS) + return; + + char* s_ptr; + + if(dec_hex_converter_state->mode == ModeDec) { + s_ptr = dec_hex_converter_state->dec_number; + } else { + s_ptr = dec_hex_converter_state->hex_number; + } + + if(number < 10) { + s_ptr[dec_hex_converter_state->digit_pos] = number + '0'; + } else { + s_ptr[dec_hex_converter_state->digit_pos] = (number - 10) + 'A'; // A-F (HEX only) + } + + dec_hex_converter_state->digit_pos++; +} + +// --------------- + +static void dec_hex_converter_render_callback(Canvas* const canvas, void* ctx) { + const DecHexConverterState* dec_hex_converter_state = acquire_mutex((ValueMutex*)ctx, 25); + if(dec_hex_converter_state == NULL) { + return; + } + + canvas_set_color(canvas, ColorBlack); + + // DEC + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 10, "DEC: "); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2 + 30, 10, dec_hex_converter_state->dec_number); + + // HEX + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 10 + 12, "HEX: "); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2 + 30, 10 + 12, dec_hex_converter_state->hex_number); + + // current mode indicator + // char buffer[4]; + // snprintf(buffer, sizeof(buffer), "%u", dec_hex_converter_state->digit_pos); // debug: show digit position instead of selected mode + if(dec_hex_converter_state->mode == ModeDec) { + canvas_draw_glyph(canvas, 128 - 10, 10, DEC_HEX_CONVERTER_CHAR_MODE); + } else { + canvas_draw_glyph(canvas, 128 - 10, 10 + 12, DEC_HEX_CONVERTER_CHAR_MODE); + } + + // draw the line + canvas_draw_line(canvas, 2, 25, 128 - 3, 25); + + // draw the keyboard + uint8_t _x = 5; + uint8_t _y = 25 + 15; // line + 10 + + for(int i = 0; i < DEC_HEX_CONVERTER_KEYS; i++) { + char g; + if(i < 10) + g = (i + '0'); + else if(i < 16) + g = ((i - 10) + 'A'); + else if(i == 16) + g = DEC_HEX_CONVERTER_CHAR_DEL; // '<' + else + g = DEC_HEX_CONVERTER_CHAR_SWAP; // 's' + + uint8_t g_w = canvas_glyph_width(canvas, g); + + // disable letters on DEC mode (but keep the previous width for visual purposes - show "blank keys") + if(dec_hex_converter_state->mode == ModeDec && i > 9 && i < 16) g = ' '; + + if(dec_hex_converter_state->cursor == i) { + canvas_draw_box( + canvas, + _x - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, + _y - (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN), + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN + g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, + DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2); + canvas_set_color(canvas, ColorWhite); + canvas_draw_glyph(canvas, _x, _y, g); + canvas_set_color(canvas, ColorBlack); + } else { + canvas_draw_frame( + canvas, + _x - DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, + _y - (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN), + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN + g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN, + DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2); + canvas_draw_glyph(canvas, _x, _y, g); + } + + if(i < 8) { + _x += g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2 + 2; + } else if(i == 8) { + _y += (DEC_HEX_CONVERTER_KEY_CHAR_HEIGHT + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2) + 3; + _x = 7; // some padding at the beginning on second line + } else { + _x += g_w + DEC_HEX_CONVERTER_KEY_FRAME_MARGIN * 2 + 1; + } + } + + release_mutex((ValueMutex*)ctx, dec_hex_converter_state); +} + +static void + dec_hex_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + DecHexConverterEvent event = {.type = EventTypeKey, .input = *input_event}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +static void dec_hex_converter_init(DecHexConverterState* const dec_hex_converter_state) { + dec_hex_converter_state->mode = ModeDec; + dec_hex_converter_state->digit_pos = 0; + + dec_hex_converter_state->dec_number[DEC_HEX_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminator + dec_hex_converter_state->hex_number[DEC_HEX_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminator + + for(int i = 0; i < DEC_HEX_CONVERTER_NUMBER_DIGITS; i++) { + dec_hex_converter_state->dec_number[i] = ' '; + dec_hex_converter_state->hex_number[i] = ' '; + } +} + +// main entry point +int32_t dec_hex_converter_app(void* p) { + UNUSED(p); + + // get event queue + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(DecHexConverterEvent)); + + // allocate state + DecHexConverterState* dec_hex_converter_state = malloc(sizeof(DecHexConverterState)); + + // set mutex for plugin state (different threads can access it) + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, dec_hex_converter_state, sizeof(dec_hex_converter_state))) { + FURI_LOG_E("DecHexConverter", "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + free(dec_hex_converter_state); + return 255; + } + + // register callbacks for drawing and input processing + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, dec_hex_converter_render_callback, &state_mutex); + view_port_input_callback_set(view_port, dec_hex_converter_input_callback, event_queue); + + // open GUI and register view_port + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + dec_hex_converter_init(dec_hex_converter_state); + + // main loop + DecHexConverterEvent event; + for(bool processing = true; processing;) { + FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); + DecHexConverterState* dec_hex_converter_state = + (DecHexConverterState*)acquire_mutex_block(&state_mutex); + + if(event_status == FuriStatusOk) { + // press events + if(event.type == EventTypeKey) { + if(event.input.type == InputTypePress) { + switch(event.input.key) { + default: + break; + case InputKeyUp: + case InputKeyDown: + dec_hex_converter_logic_move_cursor_ud(dec_hex_converter_state); + break; + case InputKeyRight: + dec_hex_converter_logic_move_cursor_lr(dec_hex_converter_state, 1); + break; + case InputKeyLeft: + dec_hex_converter_logic_move_cursor_lr(dec_hex_converter_state, -1); + break; + case InputKeyOk: + if(dec_hex_converter_state->cursor < DEC_HEX_CONVERTER_KEY_DEL) { + // positions from 0 to 15 works as regular numbers (DEC / HEX where applicable) + // (logic won't allow add numbers > 9 on ModeDec) + dec_hex_converter_logic_add_number( + dec_hex_converter_state, dec_hex_converter_state->cursor); + } else if(dec_hex_converter_state->cursor == DEC_HEX_CONVERTER_KEY_DEL) { + // del + dec_hex_converter_logic_del_number(dec_hex_converter_state); + } else { + // swap + dec_hex_converter_logic_swap_mode(dec_hex_converter_state); + } + + dec_hex_converter_logic_convert_number(dec_hex_converter_state); + break; + case InputKeyBack: + processing = false; + break; + } + } + } + } else { + // event timeout + } + + view_port_update(view_port); + release_mutex(&state_mutex, dec_hex_converter_state); + } + + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close("gui"); + view_port_free(view_port); + furi_message_queue_free(event_queue); + delete_mutex(&state_mutex); + free(dec_hex_converter_state); + + return 0; +} \ No newline at end of file diff --git a/applications/meta/application.fam b/applications/meta/application.fam index dfbafbf3c..fd8b64131 100644 --- a/applications/meta/application.fam +++ b/applications/meta/application.fam @@ -77,5 +77,6 @@ App( "esp8266_deauth", "wifi_scanner", "wav_player", + "dec_hex_converter", ], ) \ No newline at end of file diff --git a/assets/resources/Manifest b/assets/resources/Manifest index ce695f14d..24f05ca1b 100644 --- a/assets/resources/Manifest +++ b/assets/resources/Manifest @@ -1,5 +1,5 @@ V:0 -T:1659926106 +T:1659948399 D:badusb D:dolphin D:infrared @@ -255,7 +255,7 @@ F:27d732a3362969ac187c8f5ff0afc22a:286:subghz/assets/dangerous_settings F:111d2b8df83e27fd889fc5e270297865:3231:subghz/assets/keeloq_mfcodes F:9214f9c10463b746a27e82ce0b96e040:465:subghz/assets/keeloq_mfcodes_user F:653bd8d349055a41e1152e557d4a52d3:202:subghz/assets/nice_flor_s -F:b6ecaec5fcf45411622d4309c5769009:1590:subghz/assets/setting_user +F:470919d764538023a7f73ebae2853797:2106:subghz/assets/setting_user D:u2f/assets F:7e11e688e39034bbb9d88410044795e1:365:u2f/assets/cert.der F:f60b88c20ed479ed9684e249f7134618:264:u2f/assets/cert_key.u2f diff --git a/assets/resources/subghz/assets/setting_user b/assets/resources/subghz/assets/setting_user index 222b7691b..6d0102d6c 100644 --- a/assets/resources/subghz/assets/setting_user +++ b/assets/resources/subghz/assets/setting_user @@ -2,35 +2,58 @@ Filetype: Flipper SubGhz Setting File Version: 1 # Add All Standard frequencies -#Add_standard_frequencies: true +Add_standard_frequencies: false # Default Frequency: used as default for "Read" and "Read Raw" -#Default_frequency: 433920000 +Default_frequency: 433920000 # Frequencies used for "Read", "Read Raw" and "Frequency Analyzer" - they added after default ones if enabled in Add_standard_frequencies +Frequency: 300000000 Frequency: 302757000 +Frequency: 303875000 +Frequency: 304250000 Frequency: 307000000 Frequency: 307500000 Frequency: 307800000 Frequency: 309000000 +Frequency: 310000000 Frequency: 312000000 Frequency: 312100000 Frequency: 313850000 Frequency: 314000000 Frequency: 314350000 +Frequency: 315000000 +Frequency: 318000000 Frequency: 345000000 Frequency: 348000000 Frequency: 387000000 +Frequency: 390000000 +Frequency: 418000000 +Frequency: 433075000 Frequency: 433220000 +Frequency: 433420000 Frequency: 433889000 +Frequency: 433920000 +Frequency: 434420000 +Frequency: 434775000 +Frequency: 438900000 Frequency: 464000000 Frequency: 779000000 +Frequency: 868350000 +Frequency: 906400000 +Frequency: 915000000 +Frequency: 925000000 Frequency: 928000000 # Frequencies used for hopping mode (keep this list small or flipper will miss signal) - they added after default ones if enabled in Add_standard_frequencies -#Hopper_frequency: 300000000 +Hopper_frequency: 310000000 +Hopper_frequency: 315000000 +Hopper_frequency: 318000000 Hopper_frequency: 345000000 +Hopper_frequency: 390000000 +Hopper_frequency: 433920000 Hopper_frequency: 434420000 +Hopper_frequency: 868350000 # Custom preset # format for CC1101 "Custom_preset_data:" XX YY XX YY .. 00 00 ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ, where: XX-register, YY - register data, 00 00 - end load register, ZZ - 8 byte Pa table register