From 6f038da812d27bebcc9aa17b0e3d8b2b89314ed1 Mon Sep 17 00:00:00 2001 From: David Lee <5908330+leedave@users.noreply.github.com> Date: Sat, 6 Jan 2024 20:10:37 +0100 Subject: [PATCH 1/5] Started on UI for Station Id --- application.fam | 1 + helpers/gui/int_input.c | 863 ++++++++++++++++++++++++++ helpers/gui/int_input.h | 69 ++ helpers/meal_pager_custom_event.h | 1 + meal_pager.c | 13 + meal_pager.h | 2 +- meal_pager_i.h | 6 + scenes/meal_pager_scene_config.h | 3 +- scenes/meal_pager_scene_menu.c | 13 +- scenes/meal_pager_scene_set_station.c | 86 +++ 10 files changed, 1054 insertions(+), 3 deletions(-) create mode 100644 helpers/gui/int_input.c create mode 100644 helpers/gui/int_input.h create mode 100644 scenes/meal_pager_scene_set_station.c diff --git a/application.fam b/application.fam index a36b4ca43f9..804854a4e8e 100644 --- a/application.fam +++ b/application.fam @@ -8,6 +8,7 @@ App( fap_icon_assets="icons", fap_category="Sub-Ghz", fap_version="1.0", + fap_libs=["assets"], fap_author="leedave", fap_weburl="https://github.com/leedave/flipper-zero-meal-pager", fap_description="This app triggers restaurant pagers in a brute force manner, useful to test if devices are still functional.", diff --git a/helpers/gui/int_input.c b/helpers/gui/int_input.c new file mode 100644 index 00000000000..0e09e0828c5 --- /dev/null +++ b/helpers/gui/int_input.c @@ -0,0 +1,863 @@ +#include "int_input.h" + +#include +#include +#include + +/** IntInput type */ +struct IntInput { + View* view; +}; + +typedef struct { + const uint8_t value; + const uint8_t x; + const uint8_t y; +} IntInputKey; + +typedef struct { + const char* header; + uint8_t* bytes; + uint8_t bytes_count; + + IntInputCallback input_callback; + IntChangedCallback changed_callback; + void* callback_context; + + bool selected_high_nibble; + uint8_t selected_byte; + int8_t selected_row; // row -2 - mini_editor, -1 - input, row 0 & 1 - keyboard + uint8_t selected_column; + uint8_t first_visible_byte; +} IntInputModel; + +static const uint8_t keyboard_origin_x = 7; +static const uint8_t keyboard_origin_y = 31; +static const uint8_t keyboard_row_count = 2; +static const uint8_t enter_symbol = '\r'; +static const uint8_t backspace_symbol = '\b'; +static const uint8_t max_drawable_bytes = 8; + +static const IntInputKey keyboard_keys_row_1[] = { + {'0', 0, 12}, + {'1', 11, 12}, + {'2', 22, 12}, + {'3', 33, 12}, + {'4', 44, 12}, + {backspace_symbol, 103, 4}, +}; + +static const IntInputKey keyboard_keys_row_2[] = { + {'5', 0, 26}, + {'6', 11, 26}, + {'7', 22, 26}, + {'8', 33, 26}, + {'9', 44, 26}, + {enter_symbol, 95, 17}, +}; + +/** Get row size + * + * @param row_index Index of row + * + * @return uint8_t Row size + */ +static uint8_t int_input_get_row_size(uint8_t row_index) { + uint8_t row_size = 0; + + switch(row_index + 1) { + case 1: + row_size = COUNT_OF(keyboard_keys_row_1); + break; + case 2: + row_size = COUNT_OF(keyboard_keys_row_2); + break; + default: + furi_crash(); + } + + return row_size; +} + +/** Get row pointer + * + * @param row_index Index of row + * + * @return const IntInputKey* Row pointer + */ +static const IntInputKey* int_input_get_row(uint8_t row_index) { + const IntInputKey* row = NULL; + + switch(row_index + 1) { + case 1: + row = keyboard_keys_row_1; + break; + case 2: + row = keyboard_keys_row_2; + break; + default: + furi_crash(); + } + + return row; +} + +/** Get text from nibble + * + * @param byte byte value + * @param high_nibble Get from high nibble, otherwise low nibble + * + * @return char nibble text + */ +static char int_input_get_nibble_text(uint8_t byte, bool high_nibble) { + if(high_nibble) { + byte = byte >> 4; + } + byte = byte & 0x0F; + + switch(byte & 0x0F) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + case 0x8: + case 0x9: + byte = byte + '0'; + break; + case 0xA: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + case 0xF: + byte = byte - 0xA + 'A'; + break; + default: + byte = '!'; + break; + } + + return byte; +} + +const char num_to_char[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + +/** Draw input box (common view) + * + * @param canvas The canvas + * @param model The model + */ +static void int_input_draw_input(Canvas* canvas, IntInputModel* model) { + const uint8_t text_x = 8; + const uint8_t text_y = 25; + const uint8_t text_y2 = 40; + const bool draw_index_line = + (model->selected_row == -2) && + (model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes + 1) <= 100); + + elements_slightly_rounded_frame(canvas, 6, 14, 116, 15); + + canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5); + canvas_draw_icon(canvas, 123, 19, &I_ButtonRightSmall_3x5); + + for(uint8_t i = model->first_visible_byte; + i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes); + i++) { + uint8_t byte_position = i - model->first_visible_byte; + + if(i == model->selected_byte) { + canvas_draw_frame(canvas, text_x + byte_position * 14, text_y - 9, 15, 11); + if(model->selected_row == -2) { + canvas_draw_icon( + canvas, text_x + 6 + byte_position * 14, text_y - 14, &I_arrow_nano_up); + canvas_draw_icon( + canvas, text_x + 6 + byte_position * 14, text_y + 5, &I_arrow_nano_down); + } + + if(model->selected_high_nibble) { + canvas_draw_glyph( + canvas, + text_x + 8 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], false)); + canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 8, 7, 9); + canvas_invert_color(canvas); + canvas_draw_line( + canvas, + text_x + 14 + byte_position * 14, + text_y - 6, + text_x + 14 + byte_position * 14, + text_y - 2); + canvas_draw_glyph( + canvas, + text_x + 2 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], true)); + canvas_invert_color(canvas); + } else { + canvas_draw_box(canvas, text_x + 7 + byte_position * 14, text_y - 8, 7, 9); + canvas_draw_glyph( + canvas, + text_x + 2 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], true)); + canvas_invert_color(canvas); + canvas_draw_line( + canvas, + text_x + byte_position * 14, + text_y - 6, + text_x + byte_position * 14, + text_y - 2); + canvas_draw_glyph( + canvas, + text_x + 8 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], false)); + canvas_invert_color(canvas); + } + } else { + if(model->first_visible_byte > 0 && i == model->first_visible_byte) { + canvas_draw_icon( + canvas, + text_x + 2 + byte_position * 14, + text_y - 7, + &I_More_data_placeholder_5x7); + } else { + canvas_draw_glyph( + canvas, + text_x + 2 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], true)); + } + if(model->bytes_count - model->first_visible_byte > max_drawable_bytes && + i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) { + canvas_draw_icon( + canvas, + text_x + 8 + byte_position * 14, + text_y - 7, + &I_More_data_placeholder_5x7); + } else { + canvas_draw_glyph( + canvas, + text_x + 8 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], false)); + } + } + + if(draw_index_line) { + canvas_draw_icon(canvas, 1, text_y + 8, &I_Hashmark_7x7); + canvas_draw_glyph( + canvas, text_x + 2 + byte_position * 14, text_y2, num_to_char[(i + 1) / 10]); + + canvas_draw_glyph( + canvas, text_x + 8 + byte_position * 14, text_y2, num_to_char[(i + 1) % 10]); + } + } + + if((model->selected_row == -2) && + (model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes + 1) > 100)) { + char str[20]; + + canvas_set_font(canvas, FontSecondary); + snprintf(str, 20, "Selected index"); + canvas_draw_str(canvas, text_x, text_y2, str); + + canvas_set_font(canvas, FontPrimary); + snprintf(str, 20, "%u", (model->selected_byte + 1)); + canvas_draw_str(canvas, text_x + 75, text_y2, str); + } +} + +/** Draw input box (selected view) + * + * @param canvas The canvas + * @param model The model + */ +static void int_input_draw_input_selected(Canvas* canvas, IntInputModel* model) { + const uint8_t text_x = 7; + const uint8_t text_y = 25; + + canvas_draw_box(canvas, 0, 12, 127, 19); + canvas_invert_color(canvas); + + elements_slightly_rounded_frame(canvas, 6, 14, 115, 15); + canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5); + canvas_draw_icon(canvas, 122, 19, &I_ButtonRightSmall_3x5); + + for(uint8_t i = model->first_visible_byte; + i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes); + i++) { + uint8_t byte_position = i - model->first_visible_byte; + + if(i == model->selected_byte) { + canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 9, 13, 11); + canvas_invert_color(canvas); + canvas_draw_glyph( + canvas, + text_x + 2 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], true)); + canvas_draw_glyph( + canvas, + text_x + 8 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], false)); + canvas_invert_color(canvas); + } else { + if(model->first_visible_byte > 0 && i == model->first_visible_byte) { + canvas_draw_icon( + canvas, + text_x + 2 + byte_position * 14, + text_y - 7, + &I_More_data_placeholder_5x7); + } else { + canvas_draw_glyph( + canvas, + text_x + 2 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], true)); + } + if(model->bytes_count - model->first_visible_byte > max_drawable_bytes && + i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) { + canvas_draw_icon( + canvas, + text_x + 8 + byte_position * 14, + text_y - 7, + &I_More_data_placeholder_5x7); + } else { + canvas_draw_glyph( + canvas, + text_x + 8 + byte_position * 14, + text_y, + int_input_get_nibble_text(model->bytes[i], false)); + } + } + } + + canvas_invert_color(canvas); +} + +/** Set nibble at position + * + * @param data where to set nibble + * @param position byte position + * @param value char value + * @param high_nibble set high nibble + */ +/*static void int_input_set_nibble(uint8_t* data, uint8_t position, char value, bool high_nibble) { + switch(value) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + value = value - '0'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + value = value - 'A' + 10; + break; + default: + value = 0; + break; + } + + if(high_nibble) { + data[position] &= 0x0F; + data[position] |= value << 4; + } else { + data[position] &= 0xF0; + data[position] |= value; + } +}*/ + +/** What currently selected + * + * @param model The model + * + * @return true - keyboard selected, false - input selected + */ +static bool int_input_keyboard_selected(IntInputModel* model) { + return model->selected_row >= 0; +} + +/** Do transition from keyboard + * + * @param model The model + */ +static void int_input_transition_from_keyboard(IntInputModel* model) { + model->selected_row += 1; + model->selected_high_nibble = true; +} + +/** Increase selected byte position + * + * @param model The model + */ +static void int_input_inc_selected_byte(IntInputModel* model) { + if(model->selected_byte < model->bytes_count - 1) { + model->selected_byte += 1; + + if(model->bytes_count > max_drawable_bytes) { + if(model->selected_byte - model->first_visible_byte > (max_drawable_bytes - 2)) { + if(model->first_visible_byte < model->bytes_count - max_drawable_bytes) { + model->first_visible_byte++; + } + } + } + } +} + +static void int_input_inc_selected_byte_mini(IntInputModel* model) { + if((model->selected_byte < model->bytes_count - 1) || model->selected_high_nibble) { + if(!model->selected_high_nibble) { + model->selected_high_nibble = !model->selected_high_nibble; //-V547 + int_input_inc_selected_byte(model); + } else { + model->selected_high_nibble = !model->selected_high_nibble; //-V547 + } + } +} + +/** Decrease selected byte position + * + * @param model The model + */ +static void int_input_dec_selected_byte(IntInputModel* model) { + if(model->selected_byte > 0) { + model->selected_byte -= 1; + + furi_assert(model->selected_byte >= model->first_visible_byte); + if(model->selected_byte - model->first_visible_byte < 1) { + if(model->first_visible_byte > 0) { + model->first_visible_byte--; + } + } + } +} + +static void int_input_dec_selected_byte_mini(IntInputModel* model) { + if(model->selected_byte > 0 || !model->selected_high_nibble) { + if(model->selected_high_nibble) { + model->selected_high_nibble = !model->selected_high_nibble; //-V547 + int_input_dec_selected_byte(model); + } else { + model->selected_high_nibble = !model->selected_high_nibble; //-V547 + } + } +} + +/** Call input callback + * + * @param model The model + */ +static void int_input_call_input_callback(IntInputModel* model) { + if(model->input_callback != NULL) { + model->input_callback(model->callback_context); + } +} + +/** Call changed callback + * + * @param model The model + */ +static void int_input_call_changed_callback(IntInputModel* model) { + if(model->changed_callback != NULL) { + model->changed_callback(model->callback_context); + } +} + +/** Clear selected byte + * + * @param model The model + */ + +static void int_input_clear_selected_byte(IntInputModel* model) { + model->bytes[model->selected_byte] = 0; + model->selected_high_nibble = true; + int_input_dec_selected_byte(model); + int_input_call_changed_callback(model); +} + +/** Handle up button + * + * @param model The model + */ +static void int_input_handle_up(IntInputModel* model) { + if(model->selected_row > -2) { + model->selected_row -= 1; + } else if(model->selected_row == -2) { + if(!model->selected_high_nibble) { + model->bytes[model->selected_byte] = (model->bytes[model->selected_byte] & 0xF0) | + ((model->bytes[model->selected_byte] + 1) & 0x0F); + } else { + model->bytes[model->selected_byte] = + ((model->bytes[model->selected_byte] + 0x10) & 0xF0) | + (model->bytes[model->selected_byte] & 0x0F); + } + int_input_call_changed_callback(model); + } +} + +/** Handle down button + * + * @param model The model + */ +static void int_input_handle_down(IntInputModel* model) { + if(model->selected_row != -2) { + if(int_input_keyboard_selected(model)) { + if(model->selected_row < keyboard_row_count - 1) { + model->selected_row += 1; + } + } else { + int_input_transition_from_keyboard(model); + } + } else { + if(!model->selected_high_nibble) { + model->bytes[model->selected_byte] = (model->bytes[model->selected_byte] & 0xF0) | + ((model->bytes[model->selected_byte] - 1) & 0x0F); + } else { + model->bytes[model->selected_byte] = + ((model->bytes[model->selected_byte] - 0x10) & 0xF0) | + (model->bytes[model->selected_byte] & 0x0F); + } + int_input_call_changed_callback(model); + } +} + +/** Handle left button + * + * @param model The model + */ +static void int_input_handle_left(IntInputModel* model) { + if(int_input_keyboard_selected(model)) { + if(model->selected_column > 0) { + model->selected_column -= 1; + } else { + model->selected_column = int_input_get_row_size(model->selected_row) - 1; + } + } else { + if(model->selected_row != -2) { + int_input_dec_selected_byte(model); + } else { + int_input_dec_selected_byte_mini(model); + } + } +} + +/** Handle right button + * + * @param model The model + */ +static void int_input_handle_right(IntInputModel* model) { + if(int_input_keyboard_selected(model)) { + if(model->selected_column < int_input_get_row_size(model->selected_row) - 1) { + model->selected_column += 1; + } else { + model->selected_column = 0; + } + } else { + if(model->selected_row != -2) { + int_input_inc_selected_byte(model); + } else { + int_input_inc_selected_byte_mini(model); + } + } +} + +/** Handle OK button + * + * @param model The model + */ +static void int_input_handle_ok(IntInputModel* model) { + if(int_input_keyboard_selected(model)) { + uint8_t value = int_input_get_row(model->selected_row)[model->selected_column].value; + + if(value == enter_symbol) { + int_input_call_input_callback(model); + } else if(value == backspace_symbol) { + int_input_clear_selected_byte(model); + } else { + /*int_input_set_nibble( + model->bytes, model->selected_byte, value, model->selected_high_nibble); + if(model->selected_high_nibble == true) { + model->selected_high_nibble = false; + } else { + int_input_inc_selected_byte(model); + model->selected_high_nibble = true; + } + int_input_call_changed_callback(model);*/ + } + } else if(model->selected_row == -2) { + int_input_call_input_callback(model); + } else { + int_input_transition_from_keyboard(model); + } +} + +/** Draw callback + * + * @param canvas The canvas + * @param _model The model + */ +static void int_input_view_draw_callback(Canvas* canvas, void* _model) { + IntInputModel* model = _model; + + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontKeyboard); + + if(model->selected_row == -1) { + int_input_draw_input_selected(canvas, model); + } else { + int_input_draw_input(canvas, model); + } + + if(model->selected_row == -2) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_icon(canvas, 3, 1, &I_Pin_back_arrow_10x8); + canvas_draw_str_aligned(canvas, 16, 9, AlignLeft, AlignBottom, "back to keyboard"); + elements_button_center(canvas, "Save"); + } else { + // Draw the header + canvas_set_font(canvas, FontSecondary); + if(model->selected_row == -1) { + canvas_draw_str(canvas, 10, 9, "Move up for alternate input"); + canvas_draw_icon(canvas, 3, 4, &I_SmallArrowUp_3x5); + } else { + canvas_draw_str(canvas, 2, 9, model->header); + } + canvas_set_font(canvas, FontKeyboard); + // Draw keyboard + for(uint8_t row = 0; row < keyboard_row_count; row++) { + const uint8_t column_count = int_input_get_row_size(row); + const IntInputKey* keys = int_input_get_row(row); + + for(size_t column = 0; column < column_count; column++) { + if(keys[column].value == enter_symbol) { + canvas_set_color(canvas, ColorBlack); + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySaveSelected_24x11); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySave_24x11); + } + } else if(keys[column].value == backspace_symbol) { + canvas_set_color(canvas, ColorBlack); + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspaceSelected_16x9); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspace_16x9); + } + } else { + if(model->selected_row == row && model->selected_column == column) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_box( + canvas, + keyboard_origin_x + keys[column].x - 3, + keyboard_origin_y + keys[column].y - 10, + 11, + 13); + canvas_set_color(canvas, ColorWhite); + } else if( + model->selected_row == -1 && row == 0 && + model->selected_column == column) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_frame( + canvas, + keyboard_origin_x + keys[column].x - 3, + keyboard_origin_y + keys[column].y - 10, + 11, + 13); + } else { + canvas_set_color(canvas, ColorBlack); + } + + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + keys[column].value); + } + } + } + } +} + +/** Input callback + * + * @param event The event + * @param context The context + * + * @return true + * @return false + */ +static bool int_input_view_input_callback(InputEvent* event, void* context) { + IntInput* int_input = context; + furi_assert(int_input); + bool consumed = false; + + if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + switch(event->key) { + case InputKeyLeft: + with_view_model( + int_input->view, IntInputModel * model, { int_input_handle_left(model); }, true); + consumed = true; + break; + case InputKeyRight: + with_view_model( + int_input->view, + IntInputModel * model, + { int_input_handle_right(model); }, + true); + consumed = true; + break; + case InputKeyUp: + with_view_model( + int_input->view, IntInputModel * model, { int_input_handle_up(model); }, true); + consumed = true; + break; + case InputKeyDown: + with_view_model( + int_input->view, IntInputModel * model, { int_input_handle_down(model); }, true); + consumed = true; + break; + case InputKeyOk: + with_view_model( + int_input->view, IntInputModel * model, { int_input_handle_ok(model); }, true); + consumed = true; + break; + default: + break; + } + } + + if(event->type == InputTypeShort && event->key == InputKeyBack) { + // Back to keyboard + with_view_model( + int_input->view, + IntInputModel * model, + { + if(model->selected_row == -2) { + model->selected_row += 1; + consumed = true; + }; + }, + true); + } + + if((event->type == InputTypeLong || event->type == InputTypeRepeat) && + event->key == InputKeyBack) { + with_view_model( + int_input->view, + IntInputModel * model, + { int_input_clear_selected_byte(model); }, + true); + consumed = true; + } + + return consumed; +} + +/** Reset all input-related data in model + * + * @param model The model + */ +static void int_input_reset_model_input_data(IntInputModel* model) { + model->bytes = NULL; + model->bytes_count = 0; + model->selected_high_nibble = true; + model->selected_byte = 0; + model->selected_row = 0; + model->selected_column = 0; + model->first_visible_byte = 0; +} + +IntInput* int_input_alloc() { + IntInput* int_input = malloc(sizeof(IntInput)); + int_input->view = view_alloc(); + view_set_context(int_input->view, int_input); + view_allocate_model(int_input->view, ViewModelTypeLocking, sizeof(IntInputModel)); + view_set_draw_callback(int_input->view, int_input_view_draw_callback); + view_set_input_callback(int_input->view, int_input_view_input_callback); + + with_view_model( + int_input->view, + IntInputModel * model, + { + model->header = ""; + model->input_callback = NULL; + model->changed_callback = NULL; + model->callback_context = NULL; + int_input_reset_model_input_data(model); + }, + true); + + return int_input; +} + +void int_input_free(IntInput* int_input) { + furi_assert(int_input); + view_free(int_input->view); + free(int_input); +} + +View* int_input_get_view(IntInput* int_input) { + furi_assert(int_input); + return int_input->view; +} + +void int_input_set_result_callback( + IntInput* int_input, + IntInputCallback input_callback, + IntChangedCallback changed_callback, + void* callback_context, + uint8_t* bytes, + uint8_t bytes_count) { + with_view_model( + int_input->view, + IntInputModel * model, + { + int_input_reset_model_input_data(model); + model->input_callback = input_callback; + model->changed_callback = changed_callback; + model->callback_context = callback_context; + model->bytes = bytes; + model->bytes_count = bytes_count; + }, + true); +} + +void int_input_set_header_text(IntInput* int_input, const char* text) { + with_view_model( + int_input->view, IntInputModel * model, { model->header = text; }, true); +} diff --git a/helpers/gui/int_input.h b/helpers/gui/int_input.h new file mode 100644 index 00000000000..a8d747f6866 --- /dev/null +++ b/helpers/gui/int_input.h @@ -0,0 +1,69 @@ +/** + * @file int_input.h + * GUI: Integer keyboard view module API + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Int input anonymous structure */ +typedef struct IntInput IntInput; + +/** callback that is executed on save button press */ +typedef void (*IntInputCallback)(void* context); + +/** callback that is executed when byte buffer is changed */ +typedef void (*IntChangedCallback)(void* context); + +/** Allocate and initialize Int input. This Int input is used to enter Ints. + * + * @return IntInput instance pointer + */ +IntInput* int_input_alloc(); + +/** Deinitialize and free byte input + * + * @param int_input Int input instance + */ +void int_input_free(IntInput* int_input); + +/** Get byte input view + * + * @param int_input byte input instance + * + * @return View instance that can be used for embedding + */ +View* int_input_get_view(IntInput* int_input); + +/** Set byte input result callback + * + * @param int_input byte input instance + * @param input_callback input callback fn + * @param changed_callback changed callback fn + * @param callback_context callback context + * @param bytes buffer to use + * @param bytes_count buffer length + */ +void int_input_set_result_callback( + IntInput* int_input, + IntInputCallback input_callback, + IntChangedCallback changed_callback, + void* callback_context, + uint8_t* bytes, + uint8_t bytes_count); + +/** Set byte input header text + * + * @param int_input byte input instance + * @param text text to be shown + */ +void int_input_set_header_text(IntInput* int_input, const char* text); + +#ifdef __cplusplus +} +#endif diff --git a/helpers/meal_pager_custom_event.h b/helpers/meal_pager_custom_event.h index 4d0b73613c1..30fd69659e2 100644 --- a/helpers/meal_pager_custom_event.h +++ b/helpers/meal_pager_custom_event.h @@ -23,6 +23,7 @@ typedef enum { Meal_PagerCustomEventViewTransmitterSendStart, Meal_PagerCustomEventViewTransmitterSendStop, Meal_PagerCustomEventViewTransmitterError, + Meal_PagerCustomerEventIntInput, } Meal_PagerCustomEvent; enum Meal_PagerCustomEventType { diff --git a/meal_pager.c b/meal_pager.c index abbc715f642..462f6abcbba 100644 --- a/meal_pager.c +++ b/meal_pager.c @@ -58,6 +58,8 @@ Meal_Pager* meal_pager_app_alloc() { app->stop_transmit = false; app->repeats = 1; app->repeats_char = "1"; + app->max_station = 8191; + app->max_pager = 999; // Used for File Browser app->dialogs = furi_record_open(RECORD_DIALOGS); @@ -65,6 +67,9 @@ Meal_Pager* meal_pager_app_alloc() { app->subghz = subghz_alloc(); + // Custom made int keyboard + app->int_input = int_input_alloc(); + // Load configs meal_pager_read_settings(app); @@ -87,6 +92,12 @@ Meal_Pager* meal_pager_app_alloc() { Meal_PagerViewIdSettings, variable_item_list_get_view(app->variable_item_list)); + app->int_input = int_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + Meal_PagerViewIdIntInput, + int_input_get_view(app->int_input)); + //End Scene Additions return app; @@ -102,7 +113,9 @@ void meal_pager_app_free(Meal_Pager* app) { view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdMenu); view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdTransmit); view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdSettings); + view_dispatcher_remove_view(app->view_dispatcher, Meal_PagerViewIdIntInput); submenu_free(app->submenu); + int_input_free(app->int_input); view_dispatcher_free(app->view_dispatcher); furi_record_close(RECORD_GUI); diff --git a/meal_pager.h b/meal_pager.h index ad7de499f7d..0e1fd95650b 100644 --- a/meal_pager.h +++ b/meal_pager.h @@ -1,2 +1,2 @@ #pragma once -#include "meal_pager_i.h" \ No newline at end of file +#include "meal_pager_i.h" diff --git a/meal_pager_i.h b/meal_pager_i.h index 659aca28a34..79f2e0fb573 100644 --- a/meal_pager_i.h +++ b/meal_pager_i.h @@ -19,6 +19,7 @@ #include "helpers/meal_pager_storage.h" #include "helpers/subghz/subghz_types.h" #include "helpers/subghz/subghz.h" +#include "helpers/gui/int_input.h" #define TAG "Meal_Pager" @@ -59,6 +60,10 @@ typedef struct { bool stop_transmit; uint32_t repeats; char* repeats_char; + IntInput* int_input; + char* text_buffer; + uint32_t max_station; + uint32_t max_pager; } Meal_Pager; typedef enum { @@ -66,6 +71,7 @@ typedef enum { Meal_PagerViewIdMenu, Meal_PagerViewIdTransmit, Meal_PagerViewIdSettings, + Meal_PagerViewIdIntInput, } Meal_PagerViewId; typedef enum { diff --git a/scenes/meal_pager_scene_config.h b/scenes/meal_pager_scene_config.h index 9fb8580cfc2..f56e8fcbde4 100644 --- a/scenes/meal_pager_scene_config.h +++ b/scenes/meal_pager_scene_config.h @@ -1,4 +1,5 @@ ADD_SCENE(meal_pager, startscreen, Startscreen) ADD_SCENE(meal_pager, menu, Menu) ADD_SCENE(meal_pager, transmit, Transmit) -ADD_SCENE(meal_pager, settings, Settings) \ No newline at end of file +ADD_SCENE(meal_pager, settings, Settings) +ADD_SCENE(meal_pager, set_station, SetStation) \ No newline at end of file diff --git a/scenes/meal_pager_scene_menu.c b/scenes/meal_pager_scene_menu.c index 3dbd7a26832..90d3c478cf6 100644 --- a/scenes/meal_pager_scene_menu.c +++ b/scenes/meal_pager_scene_menu.c @@ -4,7 +4,7 @@ enum SubmenuIndex { SubmenuIndexTransmit = 10, - SubmenuIndexScene2, + SubmenuIndexSetStation, SubmenuIndexScene3, SubmenuIndexScene4, SubmenuIndexScene5, @@ -25,6 +25,12 @@ void meal_pager_scene_menu_on_enter(void* context) { SubmenuIndexTransmit, meal_pager_scene_menu_submenu_callback, app); + submenu_add_item( + app->submenu, + "Set Stations", + SubmenuIndexSetStation, + meal_pager_scene_menu_submenu_callback, + app); submenu_add_item( app->submenu, "Settings", @@ -62,6 +68,11 @@ bool meal_pager_scene_menu_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(app->subghz->txrx); FURI_LOG_D(TAG, "Stop Event from Menu"); return true; + } else if(event.event == SubmenuIndexSetStation) { + scene_manager_set_scene_state( + app->scene_manager, Meal_PagerSceneSetStation, SubmenuIndexSetStation); + scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSetStation); + return true; } } else if(event.type == SceneManagerEventTypeTick) { if(app->state_notifications == SubGhzNotificationStateTx) { diff --git a/scenes/meal_pager_scene_set_station.c b/scenes/meal_pager_scene_set_station.c new file mode 100644 index 00000000000..be145539e4f --- /dev/null +++ b/scenes/meal_pager_scene_set_station.c @@ -0,0 +1,86 @@ +#include "../meal_pager_i.h" +#include "../helpers/meal_pager_custom_event.h" +#include "../helpers/retekess/meal_pager_retekess_t119.h" +#include "../helpers/retekess/meal_pager_retekess_td157.h" +#include "../helpers/retekess/meal_pager_retekess_td165.h" +#include "../helpers/retekess/meal_pager_retekess_td174.h" +#include "../views/meal_pager_transmit.h" +#include "../helpers/meal_pager_led.h" +#include "../helpers/subghz/subghz.h" +#include "../views/meal_pager_transmit.h" +#include + +void meal_pager_set_station_callback(Meal_PagerCustomEvent event, void* context) { + furi_assert(context); + Meal_Pager* app = context; + + UNUSED(app); + UNUSED(event); +} + +/*static void meal_pager_int_input_callback(void* context) { + furi_assert(context); + Meal_Pager* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); +}*/ + +void meal_pager_scene_set_station_on_enter(void* context) { + furi_assert(context); + Meal_Pager* app = context; + IntInput* int_input = app->int_input; + uint8_t enter_name_length = 4; + + int_input_set_header_text(int_input, "Set first Station (0 - 8191)"); + + /*int_input_set_result_callback( + int_input, + meal_pager_int_input_callback, + context, + app->text_buffer, + &enter_name_length, + false);*/ + + UNUSED(app); + UNUSED(enter_name_length); + view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdIntInput); +} + + +bool meal_pager_scene_set_station_on_event(void* context, SceneManagerEvent event) { + Meal_Pager* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case Meal_PagerCustomEventTransmitLeft: + case Meal_PagerCustomEventTransmitRight: + break; + case Meal_PagerCustomEventTransmitUp: + case Meal_PagerCustomEventTransmitDown: + break; + case Meal_PagerCustomEventTransmitBack: + if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, Meal_PagerSceneMenu)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + consumed = true; + break; + } + } else if(event.type == SceneManagerEventTypeTick) { + if(app->state_notifications == SubGhzNotificationStateTx) { + app->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(app->subghz->txrx); + meal_pager_blink_stop(app); + meal_pager_transmit_model_set_sending(app->meal_pager_transmit, 0); + } + return true; + } + + return consumed; +} + +void meal_pager_scene_set_station_on_exit(void* context) { + Meal_Pager* app = context; + UNUSED(app); +} \ No newline at end of file From 11a23cee6dd1966beff174a34714db4a6be94438 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 7 Jan 2024 14:40:49 +0100 Subject: [PATCH 2/5] continue work on number input --- docs/changelog.md | 3 + helpers/gui/int_input.c | 662 ++++++-------------------- helpers/gui/int_input.h | 21 +- helpers/meal_pager_storage.c | 21 + helpers/meal_pager_storage.h | 3 +- scenes/meal_pager_scene_set_station.c | 21 +- 6 files changed, 195 insertions(+), 536 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 2c9adca3463..ba14f11653b 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,6 @@ +## v1.1 +- New UI to Set Stations + ## v1.0 - Added support for TD174 diff --git a/helpers/gui/int_input.c b/helpers/gui/int_input.c index 0e09e0828c5..6c07f065377 100644 --- a/helpers/gui/int_input.c +++ b/helpers/gui/int_input.c @@ -10,25 +10,23 @@ struct IntInput { }; typedef struct { - const uint8_t value; + const char text; const uint8_t x; const uint8_t y; } IntInputKey; typedef struct { const char* header; - uint8_t* bytes; - uint8_t bytes_count; - + char* text_buffer; + size_t text_buffer_size; + bool clear_default_text; + IntInputCallback input_callback; - IntChangedCallback changed_callback; + //IntChangedCallback changed_callback; void* callback_context; - bool selected_high_nibble; - uint8_t selected_byte; - int8_t selected_row; // row -2 - mini_editor, -1 - input, row 0 & 1 - keyboard + int8_t selected_row; uint8_t selected_column; - uint8_t first_visible_byte; } IntInputModel; static const uint8_t keyboard_origin_x = 7; @@ -36,7 +34,7 @@ static const uint8_t keyboard_origin_y = 31; static const uint8_t keyboard_row_count = 2; static const uint8_t enter_symbol = '\r'; static const uint8_t backspace_symbol = '\b'; -static const uint8_t max_drawable_bytes = 8; +//static const uint8_t max_drawable_digits = 4; static const IntInputKey keyboard_keys_row_1[] = { {'0', 0, 12}, @@ -102,69 +100,23 @@ static const IntInputKey* int_input_get_row(uint8_t row_index) { return row; } -/** Get text from nibble - * - * @param byte byte value - * @param high_nibble Get from high nibble, otherwise low nibble - * - * @return char nibble text - */ -static char int_input_get_nibble_text(uint8_t byte, bool high_nibble) { - if(high_nibble) { - byte = byte >> 4; - } - byte = byte & 0x0F; - - switch(byte & 0x0F) { - case 0x0: - case 0x1: - case 0x2: - case 0x3: - case 0x4: - case 0x5: - case 0x6: - case 0x7: - case 0x8: - case 0x9: - byte = byte + '0'; - break; - case 0xA: - case 0xB: - case 0xC: - case 0xD: - case 0xE: - case 0xF: - byte = byte - 0xA + 'A'; - break; - default: - byte = '!'; - break; - } - - return byte; -} - -const char num_to_char[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - /** Draw input box (common view) * * @param canvas The canvas * @param model The model */ static void int_input_draw_input(Canvas* canvas, IntInputModel* model) { - const uint8_t text_x = 8; - const uint8_t text_y = 25; - const uint8_t text_y2 = 40; - const bool draw_index_line = - (model->selected_row == -2) && - (model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes + 1) <= 100); - + //const uint8_t text_x = 8; + //const uint8_t text_y = 25; + //const uint8_t text_y2 = 40; + UNUSED(model); + elements_slightly_rounded_frame(canvas, 6, 14, 116, 15); - canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5); - canvas_draw_icon(canvas, 123, 19, &I_ButtonRightSmall_3x5); + //canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5); + //canvas_draw_icon(canvas, 123, 19, &I_ButtonRightSmall_3x5); - for(uint8_t i = model->first_visible_byte; + /*for(uint8_t i = model->first_visible_byte; i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes); i++) { uint8_t byte_position = i - model->first_visible_byte; @@ -248,249 +200,7 @@ static void int_input_draw_input(Canvas* canvas, IntInputModel* model) { int_input_get_nibble_text(model->bytes[i], false)); } } - - if(draw_index_line) { - canvas_draw_icon(canvas, 1, text_y + 8, &I_Hashmark_7x7); - canvas_draw_glyph( - canvas, text_x + 2 + byte_position * 14, text_y2, num_to_char[(i + 1) / 10]); - - canvas_draw_glyph( - canvas, text_x + 8 + byte_position * 14, text_y2, num_to_char[(i + 1) % 10]); - } - } - - if((model->selected_row == -2) && - (model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes + 1) > 100)) { - char str[20]; - - canvas_set_font(canvas, FontSecondary); - snprintf(str, 20, "Selected index"); - canvas_draw_str(canvas, text_x, text_y2, str); - - canvas_set_font(canvas, FontPrimary); - snprintf(str, 20, "%u", (model->selected_byte + 1)); - canvas_draw_str(canvas, text_x + 75, text_y2, str); - } -} - -/** Draw input box (selected view) - * - * @param canvas The canvas - * @param model The model - */ -static void int_input_draw_input_selected(Canvas* canvas, IntInputModel* model) { - const uint8_t text_x = 7; - const uint8_t text_y = 25; - - canvas_draw_box(canvas, 0, 12, 127, 19); - canvas_invert_color(canvas); - - elements_slightly_rounded_frame(canvas, 6, 14, 115, 15); - canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5); - canvas_draw_icon(canvas, 122, 19, &I_ButtonRightSmall_3x5); - - for(uint8_t i = model->first_visible_byte; - i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes); - i++) { - uint8_t byte_position = i - model->first_visible_byte; - - if(i == model->selected_byte) { - canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 9, 13, 11); - canvas_invert_color(canvas); - canvas_draw_glyph( - canvas, - text_x + 2 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], true)); - canvas_draw_glyph( - canvas, - text_x + 8 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], false)); - canvas_invert_color(canvas); - } else { - if(model->first_visible_byte > 0 && i == model->first_visible_byte) { - canvas_draw_icon( - canvas, - text_x + 2 + byte_position * 14, - text_y - 7, - &I_More_data_placeholder_5x7); - } else { - canvas_draw_glyph( - canvas, - text_x + 2 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], true)); - } - if(model->bytes_count - model->first_visible_byte > max_drawable_bytes && - i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) { - canvas_draw_icon( - canvas, - text_x + 8 + byte_position * 14, - text_y - 7, - &I_More_data_placeholder_5x7); - } else { - canvas_draw_glyph( - canvas, - text_x + 8 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], false)); - } - } - } - - canvas_invert_color(canvas); -} - -/** Set nibble at position - * - * @param data where to set nibble - * @param position byte position - * @param value char value - * @param high_nibble set high nibble - */ -/*static void int_input_set_nibble(uint8_t* data, uint8_t position, char value, bool high_nibble) { - switch(value) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - value = value - '0'; - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - value = value - 'A' + 10; - break; - default: - value = 0; - break; - } - - if(high_nibble) { - data[position] &= 0x0F; - data[position] |= value << 4; - } else { - data[position] &= 0xF0; - data[position] |= value; - } -}*/ - -/** What currently selected - * - * @param model The model - * - * @return true - keyboard selected, false - input selected - */ -static bool int_input_keyboard_selected(IntInputModel* model) { - return model->selected_row >= 0; -} - -/** Do transition from keyboard - * - * @param model The model - */ -static void int_input_transition_from_keyboard(IntInputModel* model) { - model->selected_row += 1; - model->selected_high_nibble = true; -} - -/** Increase selected byte position - * - * @param model The model - */ -static void int_input_inc_selected_byte(IntInputModel* model) { - if(model->selected_byte < model->bytes_count - 1) { - model->selected_byte += 1; - - if(model->bytes_count > max_drawable_bytes) { - if(model->selected_byte - model->first_visible_byte > (max_drawable_bytes - 2)) { - if(model->first_visible_byte < model->bytes_count - max_drawable_bytes) { - model->first_visible_byte++; - } - } - } - } -} - -static void int_input_inc_selected_byte_mini(IntInputModel* model) { - if((model->selected_byte < model->bytes_count - 1) || model->selected_high_nibble) { - if(!model->selected_high_nibble) { - model->selected_high_nibble = !model->selected_high_nibble; //-V547 - int_input_inc_selected_byte(model); - } else { - model->selected_high_nibble = !model->selected_high_nibble; //-V547 - } - } -} - -/** Decrease selected byte position - * - * @param model The model - */ -static void int_input_dec_selected_byte(IntInputModel* model) { - if(model->selected_byte > 0) { - model->selected_byte -= 1; - - furi_assert(model->selected_byte >= model->first_visible_byte); - if(model->selected_byte - model->first_visible_byte < 1) { - if(model->first_visible_byte > 0) { - model->first_visible_byte--; - } - } - } -} - -static void int_input_dec_selected_byte_mini(IntInputModel* model) { - if(model->selected_byte > 0 || !model->selected_high_nibble) { - if(model->selected_high_nibble) { - model->selected_high_nibble = !model->selected_high_nibble; //-V547 - int_input_dec_selected_byte(model); - } else { - model->selected_high_nibble = !model->selected_high_nibble; //-V547 - } - } -} - -/** Call input callback - * - * @param model The model - */ -static void int_input_call_input_callback(IntInputModel* model) { - if(model->input_callback != NULL) { - model->input_callback(model->callback_context); - } -} - -/** Call changed callback - * - * @param model The model - */ -static void int_input_call_changed_callback(IntInputModel* model) { - if(model->changed_callback != NULL) { - model->changed_callback(model->callback_context); - } -} - -/** Clear selected byte - * - * @param model The model - */ - -static void int_input_clear_selected_byte(IntInputModel* model) { - model->bytes[model->selected_byte] = 0; - model->selected_high_nibble = true; - int_input_dec_selected_byte(model); - int_input_call_changed_callback(model); + }*/ } /** Handle up button @@ -498,18 +208,8 @@ static void int_input_clear_selected_byte(IntInputModel* model) { * @param model The model */ static void int_input_handle_up(IntInputModel* model) { - if(model->selected_row > -2) { - model->selected_row -= 1; - } else if(model->selected_row == -2) { - if(!model->selected_high_nibble) { - model->bytes[model->selected_byte] = (model->bytes[model->selected_byte] & 0xF0) | - ((model->bytes[model->selected_byte] + 1) & 0x0F); - } else { - model->bytes[model->selected_byte] = - ((model->bytes[model->selected_byte] + 0x10) & 0xF0) | - (model->bytes[model->selected_byte] & 0x0F); - } - int_input_call_changed_callback(model); + if(model->selected_row > 0) { + model->selected_row--; } } @@ -518,24 +218,8 @@ static void int_input_handle_up(IntInputModel* model) { * @param model The model */ static void int_input_handle_down(IntInputModel* model) { - if(model->selected_row != -2) { - if(int_input_keyboard_selected(model)) { - if(model->selected_row < keyboard_row_count - 1) { - model->selected_row += 1; - } - } else { - int_input_transition_from_keyboard(model); - } - } else { - if(!model->selected_high_nibble) { - model->bytes[model->selected_byte] = (model->bytes[model->selected_byte] & 0xF0) | - ((model->bytes[model->selected_byte] - 1) & 0x0F); - } else { - model->bytes[model->selected_byte] = - ((model->bytes[model->selected_byte] - 0x10) & 0xF0) | - (model->bytes[model->selected_byte] & 0x0F); - } - int_input_call_changed_callback(model); + if(model->selected_row < keyboard_row_count - 1) { + model->selected_row += 1; } } @@ -544,18 +228,10 @@ static void int_input_handle_down(IntInputModel* model) { * @param model The model */ static void int_input_handle_left(IntInputModel* model) { - if(int_input_keyboard_selected(model)) { - if(model->selected_column > 0) { - model->selected_column -= 1; - } else { - model->selected_column = int_input_get_row_size(model->selected_row) - 1; - } + if(model->selected_column > 0) { + model->selected_column--; } else { - if(model->selected_row != -2) { - int_input_dec_selected_byte(model); - } else { - int_input_dec_selected_byte_mini(model); - } + model->selected_column = int_input_get_row_size(model->selected_row) - 1; } } @@ -564,18 +240,10 @@ static void int_input_handle_left(IntInputModel* model) { * @param model The model */ static void int_input_handle_right(IntInputModel* model) { - if(int_input_keyboard_selected(model)) { - if(model->selected_column < int_input_get_row_size(model->selected_row) - 1) { - model->selected_column += 1; - } else { - model->selected_column = 0; - } + if(model->selected_column < int_input_get_row_size(model->selected_row) - 1) { + model->selected_column++; } else { - if(model->selected_row != -2) { - int_input_inc_selected_byte(model); - } else { - int_input_inc_selected_byte_mini(model); - } + model->selected_column = 0; } } @@ -584,29 +252,26 @@ static void int_input_handle_right(IntInputModel* model) { * @param model The model */ static void int_input_handle_ok(IntInputModel* model) { - if(int_input_keyboard_selected(model)) { - uint8_t value = int_input_get_row(model->selected_row)[model->selected_column].value; - - if(value == enter_symbol) { - int_input_call_input_callback(model); - } else if(value == backspace_symbol) { - int_input_clear_selected_byte(model); - } else { - /*int_input_set_nibble( - model->bytes, model->selected_byte, value, model->selected_high_nibble); - if(model->selected_high_nibble == true) { - model->selected_high_nibble = false; - } else { - int_input_inc_selected_byte(model); - model->selected_high_nibble = true; - } - int_input_call_changed_callback(model);*/ - } - } else if(model->selected_row == -2) { - int_input_call_input_callback(model); + char selected = int_input_get_row(model->selected_row)[model->selected_column].text; + size_t text_length = strlen(model->text_buffer); +UNUSED(text_length); + if(selected == enter_symbol) { + // int_input_call_input_callback(model); + } else if(selected == backspace_symbol) { + //int_input_clear_selected_byte(model); } else { - int_input_transition_from_keyboard(model); + if (model->clear_default_text) { + text_length = 0; + } + if(text_length < (model->text_buffer_size - 1)) { + //model->text_buffer[text_length] = selected; + //model->text_buffer[text_length + 1] = 0; + //FURI_LOG_D("INT_INPUT", model->text_buffer); + FURI_LOG_D("INT_INPUT", "%u", text_length); + FURI_LOG_D("INT_INPUT", "%u", model->text_buffer_size); + } } + model->clear_default_text = false; } /** Draw callback @@ -616,98 +281,86 @@ static void int_input_handle_ok(IntInputModel* model) { */ static void int_input_view_draw_callback(Canvas* canvas, void* _model) { IntInputModel* model = _model; + uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; + UNUSED(text_length); + //uint8_t needed_string_width = canvas_width(canvas) - 8; + //uint8_t start_pos = 4; + + //const char* text = model->text_buffer; canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); + + int_input_draw_input(canvas, model); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 2, 9, model->header); canvas_set_font(canvas, FontKeyboard); - - if(model->selected_row == -1) { - int_input_draw_input_selected(canvas, model); - } else { - int_input_draw_input(canvas, model); - } - - if(model->selected_row == -2) { - canvas_set_font(canvas, FontSecondary); - canvas_draw_icon(canvas, 3, 1, &I_Pin_back_arrow_10x8); - canvas_draw_str_aligned(canvas, 16, 9, AlignLeft, AlignBottom, "back to keyboard"); - elements_button_center(canvas, "Save"); - } else { - // Draw the header - canvas_set_font(canvas, FontSecondary); - if(model->selected_row == -1) { - canvas_draw_str(canvas, 10, 9, "Move up for alternate input"); - canvas_draw_icon(canvas, 3, 4, &I_SmallArrowUp_3x5); - } else { - canvas_draw_str(canvas, 2, 9, model->header); - } - canvas_set_font(canvas, FontKeyboard); - // Draw keyboard - for(uint8_t row = 0; row < keyboard_row_count; row++) { - const uint8_t column_count = int_input_get_row_size(row); - const IntInputKey* keys = int_input_get_row(row); - - for(size_t column = 0; column < column_count; column++) { - if(keys[column].value == enter_symbol) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySaveSelected_24x11); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeySave_24x11); - } - } else if(keys[column].value == backspace_symbol) { - canvas_set_color(canvas, ColorBlack); - if(model->selected_row == row && model->selected_column == column) { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspaceSelected_16x9); - } else { - canvas_draw_icon( - canvas, - keyboard_origin_x + keys[column].x, - keyboard_origin_y + keys[column].y, - &I_KeyBackspace_16x9); - } + // Draw keyboard + for(uint8_t row = 0; row < keyboard_row_count; row++) { + const uint8_t column_count = int_input_get_row_size(row); + const IntInputKey* keys = int_input_get_row(row); + + for(size_t column = 0; column < column_count; column++) { + if(keys[column].text == enter_symbol) { + canvas_set_color(canvas, ColorBlack); + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeySaveSelected_24x11); } else { - if(model->selected_row == row && model->selected_column == column) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_box( - canvas, - keyboard_origin_x + keys[column].x - 3, - keyboard_origin_y + keys[column].y - 10, - 11, - 13); - canvas_set_color(canvas, ColorWhite); - } else if( - model->selected_row == -1 && row == 0 && - model->selected_column == column) { - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame( - canvas, - keyboard_origin_x + keys[column].x - 3, - keyboard_origin_y + keys[column].y - 10, - 11, - 13); - } else { - canvas_set_color(canvas, ColorBlack); - } - - canvas_draw_glyph( + canvas_draw_icon( canvas, keyboard_origin_x + keys[column].x, keyboard_origin_y + keys[column].y, - keys[column].value); + &I_KeySave_24x11); } + } else if(keys[column].text == backspace_symbol) { + canvas_set_color(canvas, ColorBlack); + if(model->selected_row == row && model->selected_column == column) { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspaceSelected_16x9); + } else { + canvas_draw_icon( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + &I_KeyBackspace_16x9); + } + } else { + if(model->selected_row == row && model->selected_column == column) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_box( + canvas, + keyboard_origin_x + keys[column].x - 3, + keyboard_origin_y + keys[column].y - 10, + 11, + 13); + canvas_set_color(canvas, ColorWhite); + } else if( + model->selected_row == -1 && row == 0 && + model->selected_column == column) { + canvas_set_color(canvas, ColorBlack); + canvas_draw_frame( + canvas, + keyboard_origin_x + keys[column].x - 3, + keyboard_origin_y + keys[column].y - 10, + 11, + 13); + } else { + canvas_set_color(canvas, ColorBlack); + } + + canvas_draw_glyph( + canvas, + keyboard_origin_x + keys[column].x, + keyboard_origin_y + keys[column].y, + keys[column].text); } } } @@ -724,66 +377,37 @@ static void int_input_view_draw_callback(Canvas* canvas, void* _model) { static bool int_input_view_input_callback(InputEvent* event, void* context) { IntInput* int_input = context; furi_assert(int_input); + bool consumed = false; + + // Fetch the model + IntInputModel* model = view_get_model(int_input->view); - if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + if(event->type == InputTypeShort || event->type == InputTypeLong || event->type == InputTypeRepeat) { + consumed = true; switch(event->key) { case InputKeyLeft: - with_view_model( - int_input->view, IntInputModel * model, { int_input_handle_left(model); }, true); - consumed = true; + int_input_handle_left(model); break; case InputKeyRight: - with_view_model( - int_input->view, - IntInputModel * model, - { int_input_handle_right(model); }, - true); - consumed = true; + int_input_handle_right(model); break; case InputKeyUp: - with_view_model( - int_input->view, IntInputModel * model, { int_input_handle_up(model); }, true); - consumed = true; + int_input_handle_up(model); break; case InputKeyDown: - with_view_model( - int_input->view, IntInputModel * model, { int_input_handle_down(model); }, true); - consumed = true; + int_input_handle_down(model); break; case InputKeyOk: - with_view_model( - int_input->view, IntInputModel * model, { int_input_handle_ok(model); }, true); - consumed = true; + int_input_handle_ok(model); break; default: break; } } - if(event->type == InputTypeShort && event->key == InputKeyBack) { - // Back to keyboard - with_view_model( - int_input->view, - IntInputModel * model, - { - if(model->selected_row == -2) { - model->selected_row += 1; - consumed = true; - }; - }, - true); - } - - if((event->type == InputTypeLong || event->type == InputTypeRepeat) && - event->key == InputKeyBack) { - with_view_model( - int_input->view, - IntInputModel * model, - { int_input_clear_selected_byte(model); }, - true); - consumed = true; - } + // commit view + view_commit_model(int_input->view, consumed); return consumed; } @@ -793,13 +417,8 @@ static bool int_input_view_input_callback(InputEvent* event, void* context) { * @param model The model */ static void int_input_reset_model_input_data(IntInputModel* model) { - model->bytes = NULL; - model->bytes_count = 0; - model->selected_high_nibble = true; - model->selected_byte = 0; model->selected_row = 0; model->selected_column = 0; - model->first_visible_byte = 0; } IntInput* int_input_alloc() { @@ -816,7 +435,7 @@ IntInput* int_input_alloc() { { model->header = ""; model->input_callback = NULL; - model->changed_callback = NULL; + // model->changed_callback = NULL; model->callback_context = NULL; int_input_reset_model_input_data(model); }, @@ -839,25 +458,32 @@ View* int_input_get_view(IntInput* int_input) { void int_input_set_result_callback( IntInput* int_input, IntInputCallback input_callback, - IntChangedCallback changed_callback, + //IntChangedCallback changed_callback, void* callback_context, - uint8_t* bytes, - uint8_t bytes_count) { + char* text_buffer, + size_t text_buffer_size, + bool clear_default_text) { + //UNUSED(changed_callback); with_view_model( int_input->view, IntInputModel * model, { int_input_reset_model_input_data(model); model->input_callback = input_callback; - model->changed_callback = changed_callback; model->callback_context = callback_context; - model->bytes = bytes; - model->bytes_count = bytes_count; + model->text_buffer = text_buffer; + model->text_buffer_size = text_buffer_size; + model->clear_default_text = clear_default_text; }, true); } void int_input_set_header_text(IntInput* int_input, const char* text) { with_view_model( - int_input->view, IntInputModel * model, { model->header = text; }, true); + int_input->view, + IntInputModel * model, + { + model->header = text; + }, + true); } diff --git a/helpers/gui/int_input.h b/helpers/gui/int_input.h index a8d747f6866..80003e3d57a 100644 --- a/helpers/gui/int_input.h +++ b/helpers/gui/int_input.h @@ -42,20 +42,23 @@ View* int_input_get_view(IntInput* int_input); /** Set byte input result callback * - * @param int_input byte input instance - * @param input_callback input callback fn - * @param changed_callback changed callback fn - * @param callback_context callback context - * @param bytes buffer to use - * @param bytes_count buffer length + * @param int_input byte input instance + * @param input_callback input callback fn + * @param changed_callback changed callback fn + * @param callback_context callback context + * @param text_buffer buffer to use + * @param text_buffer_size buffer length + * @param clear_default_text clear previous entry */ + void int_input_set_result_callback( IntInput* int_input, IntInputCallback input_callback, - IntChangedCallback changed_callback, + //IntChangedCallback changed_callback, void* callback_context, - uint8_t* bytes, - uint8_t bytes_count); + char* text_buffer, + size_t text_buffer_size, + bool clear_default_text); /** Set byte input header text * diff --git a/helpers/meal_pager_storage.c b/helpers/meal_pager_storage.c index fbb4b5b56bf..d0e6481a44a 100644 --- a/helpers/meal_pager_storage.c +++ b/helpers/meal_pager_storage.c @@ -178,6 +178,7 @@ void meal_pager_read_settings(void* context) { } flipper_format_read_uint32(fff_file, MEAL_PAGER_SETTINGS_KEY_PAGER_TYPE, &app->pager_type, 1); + meal_pager_set_max_values(app); flipper_format_read_uint32( fff_file, MEAL_PAGER_SETTINGS_KEY_FIRST_STATION, &app->first_station, 1); flipper_format_read_uint32( @@ -196,4 +197,24 @@ void meal_pager_read_settings(void* context) { meal_pager_close_config_file(fff_file); meal_pager_close_storage(); +} + +void meal_pager_set_max_values(void* context) +{ + Meal_Pager* app = context; + switch (app->pager_type) { + case Meal_PagerPagerTypeT119: + case Meal_PagerPagerTypeTD165: + app->max_station = 8191; + app->max_pager = 999; + break; + case Meal_PagerPagerTypeTD174: + app->max_station = 8191; + app->max_pager = 10; + break; + case Meal_PagerPagerTypeTD157: + app->max_station = 1023; + app->max_pager = 999; + break; + } } \ No newline at end of file diff --git a/helpers/meal_pager_storage.h b/helpers/meal_pager_storage.h index 816b99b0230..170037329f9 100644 --- a/helpers/meal_pager_storage.h +++ b/helpers/meal_pager_storage.h @@ -34,4 +34,5 @@ bool meal_pager_save_subghz_buffer_file_start(void* context, FlipperFormat* ff, void meal_pager_save_subghz_buffer_stop(void* context, FlipperFormat* ff); void meal_pager_save_settings(void* context); -void meal_pager_read_settings(void* context); \ No newline at end of file +void meal_pager_read_settings(void* context); +void meal_pager_set_max_values(void* context); \ No newline at end of file diff --git a/scenes/meal_pager_scene_set_station.c b/scenes/meal_pager_scene_set_station.c index be145539e4f..628d017cb03 100644 --- a/scenes/meal_pager_scene_set_station.c +++ b/scenes/meal_pager_scene_set_station.c @@ -1,5 +1,6 @@ #include "../meal_pager_i.h" #include "../helpers/meal_pager_custom_event.h" +#include "../helpers/meal_pager_storage.h" #include "../helpers/retekess/meal_pager_retekess_t119.h" #include "../helpers/retekess/meal_pager_retekess_td157.h" #include "../helpers/retekess/meal_pager_retekess_td165.h" @@ -18,27 +19,31 @@ void meal_pager_set_station_callback(Meal_PagerCustomEvent event, void* context) UNUSED(event); } -/*static void meal_pager_int_input_callback(void* context) { +static void meal_pager_int_input_callback(void* context) { furi_assert(context); Meal_Pager* app = context; view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); -}*/ +} void meal_pager_scene_set_station_on_enter(void* context) { furi_assert(context); Meal_Pager* app = context; IntInput* int_input = app->int_input; uint8_t enter_name_length = 4; - - int_input_set_header_text(int_input, "Set first Station (0 - 8191)"); - - /*int_input_set_result_callback( + meal_pager_set_max_values(app); + char *str = "Set first Station (0 - 9999)"; + const char *constStr = str; + snprintf(str, 36, "Set first Station (0 - %lu)", app->max_station); + + int_input_set_header_text(int_input, constStr); + + int_input_set_result_callback( int_input, meal_pager_int_input_callback, context, app->text_buffer, - &enter_name_length, - false);*/ + enter_name_length, + false); UNUSED(app); UNUSED(enter_name_length); From e1c72bb76692b2dc64bfbd8f3044a9a8e7b3e963 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 7 Jan 2024 18:03:54 +0100 Subject: [PATCH 3/5] Struggling with null pointers in int_input form --- helpers/gui/int_input.c | 58 +++++++++++++-------------- meal_pager.c | 3 ++ scenes/meal_pager_scene_set_station.c | 19 ++++----- 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/helpers/gui/int_input.c b/helpers/gui/int_input.c index 6c07f065377..7608e71f551 100644 --- a/helpers/gui/int_input.c +++ b/helpers/gui/int_input.c @@ -21,7 +21,7 @@ typedef struct { size_t text_buffer_size; bool clear_default_text; - IntInputCallback input_callback; + IntInputCallback callback; //IntChangedCallback changed_callback; void* callback_context; @@ -263,13 +263,14 @@ UNUSED(text_length); if (model->clear_default_text) { text_length = 0; } - if(text_length < (model->text_buffer_size - 1)) { + //if(text_length < (model->text_buffer_size - 1)) { //model->text_buffer[text_length] = selected; //model->text_buffer[text_length + 1] = 0; - //FURI_LOG_D("INT_INPUT", model->text_buffer); - FURI_LOG_D("INT_INPUT", "%u", text_length); - FURI_LOG_D("INT_INPUT", "%u", model->text_buffer_size); - } + FURI_LOG_D("INT_INPUT", model->text_buffer); + //FURI_LOG_D("INT_INPUT", "%u", text_length); + //FURI_LOG_D("INT_INPUT", "%u", model->text_buffer_size); + FURI_LOG_D("INT_INPUT", "%d", selected); + //} } model->clear_default_text = false; } @@ -402,6 +403,7 @@ static bool int_input_view_input_callback(InputEvent* event, void* context) { int_input_handle_ok(model); break; default: + consumed = false; break; } } @@ -412,15 +414,26 @@ static bool int_input_view_input_callback(InputEvent* event, void* context) { return consumed; } -/** Reset all input-related data in model - * - * @param model The model - */ -static void int_input_reset_model_input_data(IntInputModel* model) { - model->selected_row = 0; - model->selected_column = 0; +void int_input_reset(IntInput* int_input) { + FURI_LOG_D("INT_INPUT", "Resetting Model"); + furi_assert(int_input); + with_view_model( + int_input->view, + IntInputModel * model, + { + model->header = ""; + model->selected_row = 0; + model->selected_column = 0; + model->clear_default_text = false; + model->text_buffer = ""; + model->text_buffer_size = 0; + model->callback = NULL; + model->callback_context = NULL; + }, + true); } + IntInput* int_input_alloc() { IntInput* int_input = malloc(sizeof(IntInput)); int_input->view = view_alloc(); @@ -429,17 +442,7 @@ IntInput* int_input_alloc() { view_set_draw_callback(int_input->view, int_input_view_draw_callback); view_set_input_callback(int_input->view, int_input_view_input_callback); - with_view_model( - int_input->view, - IntInputModel * model, - { - model->header = ""; - model->input_callback = NULL; - // model->changed_callback = NULL; - model->callback_context = NULL; - int_input_reset_model_input_data(model); - }, - true); + int_input_reset(int_input); return int_input; } @@ -457,19 +460,16 @@ View* int_input_get_view(IntInput* int_input) { void int_input_set_result_callback( IntInput* int_input, - IntInputCallback input_callback, - //IntChangedCallback changed_callback, + IntInputCallback callback, void* callback_context, char* text_buffer, size_t text_buffer_size, bool clear_default_text) { - //UNUSED(changed_callback); with_view_model( int_input->view, IntInputModel * model, { - int_input_reset_model_input_data(model); - model->input_callback = input_callback; + model->callback = callback; model->callback_context = callback_context; model->text_buffer = text_buffer; model->text_buffer_size = text_buffer_size; diff --git a/meal_pager.c b/meal_pager.c index 462f6abcbba..59877ff5611 100644 --- a/meal_pager.c +++ b/meal_pager.c @@ -61,6 +61,9 @@ Meal_Pager* meal_pager_app_alloc() { app->max_station = 8191; app->max_pager = 999; + snprintf(app->text_buffer, 32, "%lu", app->first_station); + //app->text_buffer = text_buffer; + // Used for File Browser app->dialogs = furi_record_open(RECORD_DIALOGS); app->file_path = furi_string_alloc(); diff --git a/scenes/meal_pager_scene_set_station.c b/scenes/meal_pager_scene_set_station.c index 628d017cb03..7da604c1851 100644 --- a/scenes/meal_pager_scene_set_station.c +++ b/scenes/meal_pager_scene_set_station.c @@ -11,25 +11,23 @@ #include "../views/meal_pager_transmit.h" #include -void meal_pager_set_station_callback(Meal_PagerCustomEvent event, void* context) { +void meal_pager_set_station_callback(void* context) { furi_assert(context); Meal_Pager* app = context; - - UNUSED(app); - UNUSED(event); + view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); } -static void meal_pager_int_input_callback(void* context) { +/*static void meal_pager_int_input_callback(void* context) { furi_assert(context); Meal_Pager* app = context; view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); -} +}*/ void meal_pager_scene_set_station_on_enter(void* context) { furi_assert(context); Meal_Pager* app = context; IntInput* int_input = app->int_input; - uint8_t enter_name_length = 4; + size_t enter_name_length = 4; meal_pager_set_max_values(app); char *str = "Set first Station (0 - 9999)"; const char *constStr = str; @@ -39,7 +37,7 @@ void meal_pager_scene_set_station_on_enter(void* context) { int_input_set_result_callback( int_input, - meal_pager_int_input_callback, + meal_pager_set_station_callback, context, app->text_buffer, enter_name_length, @@ -55,7 +53,10 @@ bool meal_pager_scene_set_station_on_event(void* context, SceneManagerEvent even Meal_Pager* app = context; bool consumed = false; - if(event.type == SceneManagerEventTypeCustom) { + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case Meal_PagerCustomEventTransmitLeft: case Meal_PagerCustomEventTransmitRight: From a627f9a5e3950926a01017c3614aec7edf8ce1a5 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 7 Jan 2024 23:21:02 +0100 Subject: [PATCH 4/5] Added new UI to define stations/pagers range --- README.md | 5 +- application.fam | 2 +- docs/changelog.md | 12 +- helpers/gui/int_input.c | 153 ++++--------------- helpers/gui/int_input.h | 1 - helpers/meal_pager_custom_event.h | 1 + helpers/meal_pager_led.c | 12 +- helpers/meal_pager_storage.c | 48 +++--- helpers/meal_pager_storage.h | 6 +- helpers/retekess/meal_pager_retekess_t119.c | 3 +- helpers/retekess/meal_pager_retekess_td157.c | 3 +- helpers/retekess/meal_pager_retekess_td165.c | 3 +- helpers/retekess/meal_pager_retekess_td174.c | 3 +- meal_pager.c | 12 +- meal_pager_i.h | 1 + scenes/meal_pager_scene_config.h | 5 +- scenes/meal_pager_scene_menu.c | 50 +++++- scenes/meal_pager_scene_set_first_pager.c | 63 ++++++++ scenes/meal_pager_scene_set_first_station.c | 63 ++++++++ scenes/meal_pager_scene_set_last_pager.c | 63 ++++++++ scenes/meal_pager_scene_set_last_station.c | 63 ++++++++ scenes/meal_pager_scene_set_station.c | 92 ----------- scenes/meal_pager_scene_settings.c | 48 ++---- scenes/meal_pager_scene_transmit.c | 2 +- 24 files changed, 412 insertions(+), 302 deletions(-) create mode 100644 scenes/meal_pager_scene_set_first_pager.c create mode 100644 scenes/meal_pager_scene_set_first_station.c create mode 100644 scenes/meal_pager_scene_set_last_pager.c create mode 100644 scenes/meal_pager_scene_set_last_station.c delete mode 100644 scenes/meal_pager_scene_set_station.c diff --git a/README.md b/README.md index 956557ec0ea..dbc530819c4 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ This app triggers restaurant pagers in a brute force manner, useful to test if d - Retekess TD174 ### Features -- Select range of stations (needs improving for full range) -- Select range of pagers (needs improving for full range) +- Send a Range of Signals +- Select range of stations +- Select range of pagers ## How to install on Flipper Zero - If you do not have one, download a firmware onto your PC via git
diff --git a/application.fam b/application.fam index 804854a4e8e..01eb0d23379 100644 --- a/application.fam +++ b/application.fam @@ -7,7 +7,7 @@ App( fap_icon="icons/meal_pager_10px.png", fap_icon_assets="icons", fap_category="Sub-Ghz", - fap_version="1.0", + fap_version="1.1", fap_libs=["assets"], fap_author="leedave", fap_weburl="https://github.com/leedave/flipper-zero-meal-pager", diff --git a/docs/changelog.md b/docs/changelog.md index ba14f11653b..64f39d6e03d 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,15 @@ ## v1.1 -- New UI to Set Stations +- Created a new UI Input View as FW does not supply one for numbers +- New UI to Set First Station +- New UI to Set Last Station +- New UI to Set First Page +- New UI to Set Last Pager +- Removed Vibro/Sound settings as not used + +Known issues +- After setting last station, the settings view is weird. Some kindo of memory bug. But data remains correct. +- Extensive use can cause crashes, must be some memory leak left + ## v1.0 - Added support for TD174 diff --git a/helpers/gui/int_input.c b/helpers/gui/int_input.c index 7608e71f551..b93ce3126af 100644 --- a/helpers/gui/int_input.c +++ b/helpers/gui/int_input.c @@ -20,12 +20,11 @@ typedef struct { char* text_buffer; size_t text_buffer_size; bool clear_default_text; - + IntInputCallback callback; - //IntChangedCallback changed_callback; void* callback_context; - int8_t selected_row; + int8_t selected_row; uint8_t selected_column; } IntInputModel; @@ -34,7 +33,6 @@ static const uint8_t keyboard_origin_y = 31; static const uint8_t keyboard_row_count = 2; static const uint8_t enter_symbol = '\r'; static const uint8_t backspace_symbol = '\b'; -//static const uint8_t max_drawable_digits = 4; static const IntInputKey keyboard_keys_row_1[] = { {'0', 0, 12}, @@ -106,101 +104,20 @@ static const IntInputKey* int_input_get_row(uint8_t row_index) { * @param model The model */ static void int_input_draw_input(Canvas* canvas, IntInputModel* model) { - //const uint8_t text_x = 8; - //const uint8_t text_y = 25; - //const uint8_t text_y2 = 40; - UNUSED(model); - + const uint8_t text_x = 8; + const uint8_t text_y = 25; + elements_slightly_rounded_frame(canvas, 6, 14, 116, 15); - //canvas_draw_icon(canvas, 2, 19, &I_ButtonLeftSmall_3x5); - //canvas_draw_icon(canvas, 123, 19, &I_ButtonRightSmall_3x5); - - /*for(uint8_t i = model->first_visible_byte; - i < model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes); - i++) { - uint8_t byte_position = i - model->first_visible_byte; - - if(i == model->selected_byte) { - canvas_draw_frame(canvas, text_x + byte_position * 14, text_y - 9, 15, 11); - if(model->selected_row == -2) { - canvas_draw_icon( - canvas, text_x + 6 + byte_position * 14, text_y - 14, &I_arrow_nano_up); - canvas_draw_icon( - canvas, text_x + 6 + byte_position * 14, text_y + 5, &I_arrow_nano_down); - } + const char* text = model->text_buffer; + canvas_draw_str(canvas, text_x, text_y, text); +} - if(model->selected_high_nibble) { - canvas_draw_glyph( - canvas, - text_x + 8 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], false)); - canvas_draw_box(canvas, text_x + 1 + byte_position * 14, text_y - 8, 7, 9); - canvas_invert_color(canvas); - canvas_draw_line( - canvas, - text_x + 14 + byte_position * 14, - text_y - 6, - text_x + 14 + byte_position * 14, - text_y - 2); - canvas_draw_glyph( - canvas, - text_x + 2 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], true)); - canvas_invert_color(canvas); - } else { - canvas_draw_box(canvas, text_x + 7 + byte_position * 14, text_y - 8, 7, 9); - canvas_draw_glyph( - canvas, - text_x + 2 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], true)); - canvas_invert_color(canvas); - canvas_draw_line( - canvas, - text_x + byte_position * 14, - text_y - 6, - text_x + byte_position * 14, - text_y - 2); - canvas_draw_glyph( - canvas, - text_x + 8 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], false)); - canvas_invert_color(canvas); - } - } else { - if(model->first_visible_byte > 0 && i == model->first_visible_byte) { - canvas_draw_icon( - canvas, - text_x + 2 + byte_position * 14, - text_y - 7, - &I_More_data_placeholder_5x7); - } else { - canvas_draw_glyph( - canvas, - text_x + 2 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], true)); - } - if(model->bytes_count - model->first_visible_byte > max_drawable_bytes && - i == model->first_visible_byte + MIN(model->bytes_count, max_drawable_bytes) - 1) { - canvas_draw_icon( - canvas, - text_x + 8 + byte_position * 14, - text_y - 7, - &I_More_data_placeholder_5x7); - } else { - canvas_draw_glyph( - canvas, - text_x + 8 + byte_position * 14, - text_y, - int_input_get_nibble_text(model->bytes[i], false)); - } - } - }*/ +static void int_input_backspace_cb(IntInputModel* model) { + uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer); + if(text_length > 0) { + model->text_buffer[text_length - 1] = 0; + } } /** Handle up button @@ -254,23 +171,18 @@ static void int_input_handle_right(IntInputModel* model) { static void int_input_handle_ok(IntInputModel* model) { char selected = int_input_get_row(model->selected_row)[model->selected_column].text; size_t text_length = strlen(model->text_buffer); -UNUSED(text_length); if(selected == enter_symbol) { - // int_input_call_input_callback(model); + model->callback(model->callback_context); } else if(selected == backspace_symbol) { - //int_input_clear_selected_byte(model); + int_input_backspace_cb(model); } else { - if (model->clear_default_text) { + if(model->clear_default_text) { text_length = 0; } - //if(text_length < (model->text_buffer_size - 1)) { - //model->text_buffer[text_length] = selected; - //model->text_buffer[text_length + 1] = 0; - FURI_LOG_D("INT_INPUT", model->text_buffer); - //FURI_LOG_D("INT_INPUT", "%u", text_length); - //FURI_LOG_D("INT_INPUT", "%u", model->text_buffer_size); - FURI_LOG_D("INT_INPUT", "%d", selected); - //} + if(text_length < (model->text_buffer_size - 1)) { + model->text_buffer[text_length] = selected; + model->text_buffer[text_length + 1] = 0; + } } model->clear_default_text = false; } @@ -284,16 +196,12 @@ static void int_input_view_draw_callback(Canvas* canvas, void* _model) { IntInputModel* model = _model; uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0; UNUSED(text_length); - //uint8_t needed_string_width = canvas_width(canvas) - 8; - //uint8_t start_pos = 4; - - //const char* text = model->text_buffer; canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); - + int_input_draw_input(canvas, model); - + canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 2, 9, model->header); canvas_set_font(canvas, FontKeyboard); @@ -343,9 +251,7 @@ static void int_input_view_draw_callback(Canvas* canvas, void* _model) { 11, 13); canvas_set_color(canvas, ColorWhite); - } else if( - model->selected_row == -1 && row == 0 && - model->selected_column == column) { + } else if(model->selected_row == -1 && row == 0 && model->selected_column == column) { canvas_set_color(canvas, ColorBlack); canvas_draw_frame( canvas, @@ -380,11 +286,12 @@ static bool int_input_view_input_callback(InputEvent* event, void* context) { furi_assert(int_input); bool consumed = false; - + // Fetch the model IntInputModel* model = view_get_model(int_input->view); - if(event->type == InputTypeShort || event->type == InputTypeLong || event->type == InputTypeRepeat) { + if(event->type == InputTypeShort || event->type == InputTypeLong || + event->type == InputTypeRepeat) { consumed = true; switch(event->key) { case InputKeyLeft: @@ -433,7 +340,6 @@ void int_input_reset(IntInput* int_input) { true); } - IntInput* int_input_alloc() { IntInput* int_input = malloc(sizeof(IntInput)); int_input->view = view_alloc(); @@ -480,10 +386,5 @@ void int_input_set_result_callback( void int_input_set_header_text(IntInput* int_input, const char* text) { with_view_model( - int_input->view, - IntInputModel * model, - { - model->header = text; - }, - true); + int_input->view, IntInputModel * model, { model->header = text; }, true); } diff --git a/helpers/gui/int_input.h b/helpers/gui/int_input.h index 80003e3d57a..87d5bee5cad 100644 --- a/helpers/gui/int_input.h +++ b/helpers/gui/int_input.h @@ -54,7 +54,6 @@ View* int_input_get_view(IntInput* int_input); void int_input_set_result_callback( IntInput* int_input, IntInputCallback input_callback, - //IntChangedCallback changed_callback, void* callback_context, char* text_buffer, size_t text_buffer_size, diff --git a/helpers/meal_pager_custom_event.h b/helpers/meal_pager_custom_event.h index 30fd69659e2..44d02f86739 100644 --- a/helpers/meal_pager_custom_event.h +++ b/helpers/meal_pager_custom_event.h @@ -24,6 +24,7 @@ typedef enum { Meal_PagerCustomEventViewTransmitterSendStop, Meal_PagerCustomEventViewTransmitterError, Meal_PagerCustomerEventIntInput, + Meal_PagerCustomEventViewIntInputOk, } Meal_PagerCustomEvent; enum Meal_PagerCustomEventType { diff --git a/helpers/meal_pager_led.c b/helpers/meal_pager_led.c index 626ce71e137..68c449f8174 100644 --- a/helpers/meal_pager_led.c +++ b/helpers/meal_pager_led.c @@ -2,14 +2,18 @@ void meal_pager_blink_start_subghz(Meal_Pager* app) { furi_assert(app); - notification_message(app->notification, &sequence_blink_stop); - notification_message(app->notification, &sequence_blink_start_magenta); + if(app->led == 1) { + notification_message(app->notification, &sequence_blink_stop); + notification_message(app->notification, &sequence_blink_start_magenta); + } } void meal_pager_blink_start_compile(Meal_Pager* app) { furi_assert(app); - notification_message(app->notification, &sequence_blink_stop); - notification_message(app->notification, &sequence_blink_start_yellow); + if(app->led == 1) { + notification_message(app->notification, &sequence_blink_stop); + notification_message(app->notification, &sequence_blink_start_yellow); + } } void meal_pager_blink_stop(Meal_Pager* app) { diff --git a/helpers/meal_pager_storage.c b/helpers/meal_pager_storage.c index d0e6481a44a..aec3ddd10fc 100644 --- a/helpers/meal_pager_storage.c +++ b/helpers/meal_pager_storage.c @@ -15,7 +15,11 @@ static void meal_pager_close_config_file(FlipperFormat* file) { flipper_format_free(file); } -bool meal_pager_save_subghz_buffer_file_start(void* context, FlipperFormat* ff, Storage* storage, char* frequency) { +bool meal_pager_save_subghz_buffer_file_start( + void* context, + FlipperFormat* ff, + Storage* storage, + char* frequency) { // SubGhz TXRX can only be loaded with files, makes sense as to save RAM Meal_Pager* app = context; UNUSED(app); @@ -53,12 +57,11 @@ bool meal_pager_save_subghz_buffer_file_start(void* context, FlipperFormat* ff, return success; } - success = - flipper_format_write_header_cstr( - ff, MEAL_PAGER_SUBGHZ_FILE_TYPE, MEAL_PAGER_SUBGHZ_FILE_VERSION) && - flipper_format_write_string_cstr(ff, "Frequency", frequency) && - flipper_format_write_string_cstr(ff, "Preset", MEAL_PAGER_SUBGHZ_FILE_PRESET) && - flipper_format_write_string_cstr(ff, "Protocol", MEAL_PAGER_SUBGHZ_FILE_Protocol); + success = flipper_format_write_header_cstr( + ff, MEAL_PAGER_SUBGHZ_FILE_TYPE, MEAL_PAGER_SUBGHZ_FILE_VERSION) && + flipper_format_write_string_cstr(ff, "Frequency", frequency) && + flipper_format_write_string_cstr(ff, "Preset", MEAL_PAGER_SUBGHZ_FILE_PRESET) && + flipper_format_write_string_cstr(ff, "Protocol", MEAL_PAGER_SUBGHZ_FILE_Protocol); return success; } @@ -199,22 +202,21 @@ void meal_pager_read_settings(void* context) { meal_pager_close_storage(); } -void meal_pager_set_max_values(void* context) -{ +void meal_pager_set_max_values(void* context) { Meal_Pager* app = context; - switch (app->pager_type) { - case Meal_PagerPagerTypeT119: - case Meal_PagerPagerTypeTD165: - app->max_station = 8191; - app->max_pager = 999; - break; - case Meal_PagerPagerTypeTD174: - app->max_station = 8191; - app->max_pager = 10; - break; - case Meal_PagerPagerTypeTD157: - app->max_station = 1023; - app->max_pager = 999; - break; + switch(app->pager_type) { + case Meal_PagerPagerTypeT119: + case Meal_PagerPagerTypeTD165: + app->max_station = 8191; + app->max_pager = 999; + break; + case Meal_PagerPagerTypeTD174: + app->max_station = 8191; + app->max_pager = 10; + break; + case Meal_PagerPagerTypeTD157: + app->max_station = 1023; + app->max_pager = 999; + break; } } \ No newline at end of file diff --git a/helpers/meal_pager_storage.h b/helpers/meal_pager_storage.h index 170037329f9..748a961cbf4 100644 --- a/helpers/meal_pager_storage.h +++ b/helpers/meal_pager_storage.h @@ -29,7 +29,11 @@ #define MEAL_PAGER_SUBGHZ_FILE_PRESET "FuriHalSubGhzPresetOok650Async" #define MEAL_PAGER_SUBGHZ_FILE_Protocol "RAW" -bool meal_pager_save_subghz_buffer_file_start(void* context, FlipperFormat* ff, Storage* storage, char* frequency); +bool meal_pager_save_subghz_buffer_file_start( + void* context, + FlipperFormat* ff, + Storage* storage, + char* frequency); void meal_pager_save_subghz_buffer_stop(void* context, FlipperFormat* ff); diff --git a/helpers/retekess/meal_pager_retekess_t119.c b/helpers/retekess/meal_pager_retekess_t119.c index 79b9c70553d..fa6415537af 100644 --- a/helpers/retekess/meal_pager_retekess_t119.c +++ b/helpers/retekess/meal_pager_retekess_t119.c @@ -107,7 +107,8 @@ bool meal_pager_retekess_t119_generate_all(void* context) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); - bool success = meal_pager_save_subghz_buffer_file_start(app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_FREQUENCY); + bool success = meal_pager_save_subghz_buffer_file_start( + app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_FREQUENCY); if(!success) { FURI_LOG_D(TAG, "failed to save to buffer"); diff --git a/helpers/retekess/meal_pager_retekess_td157.c b/helpers/retekess/meal_pager_retekess_td157.c index d9c08cfc638..6467927ee0a 100644 --- a/helpers/retekess/meal_pager_retekess_td157.c +++ b/helpers/retekess/meal_pager_retekess_td157.c @@ -93,7 +93,8 @@ bool meal_pager_retekess_td157_generate_all(void* context) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); - bool success = meal_pager_save_subghz_buffer_file_start(app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_FREQUENCY); + bool success = meal_pager_save_subghz_buffer_file_start( + app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_FREQUENCY); if(!success) { FURI_LOG_D(TAG, "failed to save to buffer"); diff --git a/helpers/retekess/meal_pager_retekess_td165.c b/helpers/retekess/meal_pager_retekess_td165.c index f052f0e026c..0f81f281b96 100644 --- a/helpers/retekess/meal_pager_retekess_td165.c +++ b/helpers/retekess/meal_pager_retekess_td165.c @@ -95,7 +95,8 @@ bool meal_pager_retekess_td165_generate_all(void* context) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); - bool success = meal_pager_save_subghz_buffer_file_start(app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_FREQUENCY); + bool success = meal_pager_save_subghz_buffer_file_start( + app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_FREQUENCY); if(!success) { FURI_LOG_D(TAG, "failed to save to buffer"); diff --git a/helpers/retekess/meal_pager_retekess_td174.c b/helpers/retekess/meal_pager_retekess_td174.c index afc354b19c5..312bf900fdd 100644 --- a/helpers/retekess/meal_pager_retekess_td174.c +++ b/helpers/retekess/meal_pager_retekess_td174.c @@ -98,7 +98,8 @@ bool meal_pager_retekess_td174_generate_all(void* context) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); - bool success = meal_pager_save_subghz_buffer_file_start(app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_ALT_FREQUENCY); + bool success = meal_pager_save_subghz_buffer_file_start( + app, ff, storage, MEAL_PAGER_SUBGHZ_FILE_ALT_FREQUENCY); if(!success) { FURI_LOG_D(TAG, "failed to save to buffer"); diff --git a/meal_pager.c b/meal_pager.c index 59877ff5611..5a66f3babd7 100644 --- a/meal_pager.c +++ b/meal_pager.c @@ -61,8 +61,7 @@ Meal_Pager* meal_pager_app_alloc() { app->max_station = 8191; app->max_pager = 999; - snprintf(app->text_buffer, 32, "%lu", app->first_station); - //app->text_buffer = text_buffer; + snprintf(app->text_store[0], 32, "%lu", app->first_station); // Used for File Browser app->dialogs = furi_record_open(RECORD_DIALOGS); @@ -97,12 +96,15 @@ Meal_Pager* meal_pager_app_alloc() { app->int_input = int_input_alloc(); view_dispatcher_add_view( - app->view_dispatcher, - Meal_PagerViewIdIntInput, - int_input_get_view(app->int_input)); + app->view_dispatcher, Meal_PagerViewIdIntInput, int_input_get_view(app->int_input)); //End Scene Additions + snprintf(app->text_store[0], 20, "%lu", app->first_station); + snprintf(app->text_store[1], 20, "%lu", app->last_station); + snprintf(app->text_store[2], 20, "%lu", app->first_pager); + snprintf(app->text_store[3], 20, "%lu", app->last_pager); + return app; } diff --git a/meal_pager_i.h b/meal_pager_i.h index 79f2e0fb573..fab22e07bf8 100644 --- a/meal_pager_i.h +++ b/meal_pager_i.h @@ -64,6 +64,7 @@ typedef struct { char* text_buffer; uint32_t max_station; uint32_t max_pager; + char text_store[6][129]; } Meal_Pager; typedef enum { diff --git a/scenes/meal_pager_scene_config.h b/scenes/meal_pager_scene_config.h index f56e8fcbde4..7165afd98c6 100644 --- a/scenes/meal_pager_scene_config.h +++ b/scenes/meal_pager_scene_config.h @@ -2,4 +2,7 @@ ADD_SCENE(meal_pager, startscreen, Startscreen) ADD_SCENE(meal_pager, menu, Menu) ADD_SCENE(meal_pager, transmit, Transmit) ADD_SCENE(meal_pager, settings, Settings) -ADD_SCENE(meal_pager, set_station, SetStation) \ No newline at end of file +ADD_SCENE(meal_pager, set_first_station, SetFirstStation) +ADD_SCENE(meal_pager, set_last_station, SetLastStation) +ADD_SCENE(meal_pager, set_first_pager, SetFirstPager) +ADD_SCENE(meal_pager, set_last_pager, SetLastPager) \ No newline at end of file diff --git a/scenes/meal_pager_scene_menu.c b/scenes/meal_pager_scene_menu.c index 90d3c478cf6..f30daac5a86 100644 --- a/scenes/meal_pager_scene_menu.c +++ b/scenes/meal_pager_scene_menu.c @@ -4,7 +4,10 @@ enum SubmenuIndex { SubmenuIndexTransmit = 10, - SubmenuIndexSetStation, + SubmenuIndexSetFirstStation, + SubmenuIndexSetLastStation, + SubmenuIndexSetFirstPager, + SubmenuIndexSetLastPager, SubmenuIndexScene3, SubmenuIndexScene4, SubmenuIndexScene5, @@ -27,10 +30,28 @@ void meal_pager_scene_menu_on_enter(void* context) { app); submenu_add_item( app->submenu, - "Set Stations", - SubmenuIndexSetStation, + "Set First Station", + SubmenuIndexSetFirstStation, meal_pager_scene_menu_submenu_callback, - app); + app); + submenu_add_item( + app->submenu, + "Set Last Station", + SubmenuIndexSetLastStation, + meal_pager_scene_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Set First Pager", + SubmenuIndexSetFirstPager, + meal_pager_scene_menu_submenu_callback, + app); + submenu_add_item( + app->submenu, + "Set Last Pager", + SubmenuIndexSetLastPager, + meal_pager_scene_menu_submenu_callback, + app); submenu_add_item( app->submenu, "Settings", @@ -68,10 +89,25 @@ bool meal_pager_scene_menu_on_event(void* context, SceneManagerEvent event) { subghz_txrx_stop(app->subghz->txrx); FURI_LOG_D(TAG, "Stop Event from Menu"); return true; - } else if(event.event == SubmenuIndexSetStation) { + } else if(event.event == SubmenuIndexSetFirstStation) { + scene_manager_set_scene_state( + app->scene_manager, Meal_PagerSceneSetFirstStation, SubmenuIndexSetFirstStation); + scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSetFirstStation); + return true; + } else if(event.event == SubmenuIndexSetLastStation) { + scene_manager_set_scene_state( + app->scene_manager, Meal_PagerSceneSetLastStation, SubmenuIndexSetLastStation); + scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSetLastStation); + return true; + } else if(event.event == SubmenuIndexSetFirstPager) { + scene_manager_set_scene_state( + app->scene_manager, Meal_PagerSceneSetFirstPager, SubmenuIndexSetFirstPager); + scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSetFirstPager); + return true; + } else if(event.event == SubmenuIndexSetLastPager) { scene_manager_set_scene_state( - app->scene_manager, Meal_PagerSceneSetStation, SubmenuIndexSetStation); - scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSetStation); + app->scene_manager, Meal_PagerSceneSetLastPager, SubmenuIndexSetLastPager); + scene_manager_next_scene(app->scene_manager, Meal_PagerSceneSetLastPager); return true; } } else if(event.type == SceneManagerEventTypeTick) { diff --git a/scenes/meal_pager_scene_set_first_pager.c b/scenes/meal_pager_scene_set_first_pager.c new file mode 100644 index 00000000000..5ee2b0990b1 --- /dev/null +++ b/scenes/meal_pager_scene_set_first_pager.c @@ -0,0 +1,63 @@ +#include "../meal_pager_i.h" +#include "../helpers/meal_pager_custom_event.h" +#include "../helpers/meal_pager_led.h" +#include + +void meal_pager_set_first_pager_callback(void* context) { + furi_assert(context); + Meal_Pager* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); +} + +void meal_pager_scene_set_first_pager_on_enter(void* context) { + furi_assert(context); + Meal_Pager* app = context; + IntInput* int_input = app->int_input; + size_t enter_name_length = 5; + meal_pager_set_max_values(app); + char* str = "Set First Pager (0 - 999)"; + const char* constStr = str; + snprintf(str, 36, "Set First Pager (0 - %lu)", app->max_pager); + + int_input_set_header_text(int_input, constStr); + + int_input_set_result_callback( + int_input, + meal_pager_set_first_pager_callback, + context, + app->text_store[2], + enter_name_length, + false); + + view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdIntInput); +} + +bool meal_pager_scene_set_first_pager_on_event(void* context, SceneManagerEvent event) { + Meal_Pager* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + app->first_pager = atoi(app->text_store[2]); + app->first_pager_char = app->text_store[2]; + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeTick) { + if(app->state_notifications == SubGhzNotificationStateTx) { + app->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(app->subghz->txrx); + meal_pager_blink_stop(app); + meal_pager_transmit_model_set_sending(app->meal_pager_transmit, 0); + } + return true; + } + + return consumed; +} + +void meal_pager_scene_set_first_pager_on_exit(void* context) { + Meal_Pager* app = context; + UNUSED(app); +} \ No newline at end of file diff --git a/scenes/meal_pager_scene_set_first_station.c b/scenes/meal_pager_scene_set_first_station.c new file mode 100644 index 00000000000..0711823d050 --- /dev/null +++ b/scenes/meal_pager_scene_set_first_station.c @@ -0,0 +1,63 @@ +#include "../meal_pager_i.h" +#include "../helpers/meal_pager_custom_event.h" +#include "../helpers/meal_pager_led.h" +#include + +void meal_pager_set_first_station_callback(void* context) { + furi_assert(context); + Meal_Pager* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); +} + +void meal_pager_scene_set_first_station_on_enter(void* context) { + furi_assert(context); + Meal_Pager* app = context; + IntInput* int_input = app->int_input; + size_t enter_name_length = 5; + meal_pager_set_max_values(app); + char* str = "Set First Station (0 - 9999)"; + const char* constStr = str; + snprintf(str, 36, "Set First Station (0 - %lu)", app->max_station); + + int_input_set_header_text(int_input, constStr); + + int_input_set_result_callback( + int_input, + meal_pager_set_first_station_callback, + context, + app->text_store[0], + enter_name_length, + false); + + view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdIntInput); +} + +bool meal_pager_scene_set_first_station_on_event(void* context, SceneManagerEvent event) { + Meal_Pager* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + app->first_station = atoi(app->text_store[0]); + app->first_station_char = app->text_store[0]; + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeTick) { + if(app->state_notifications == SubGhzNotificationStateTx) { + app->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(app->subghz->txrx); + meal_pager_blink_stop(app); + meal_pager_transmit_model_set_sending(app->meal_pager_transmit, 0); + } + return true; + } + + return consumed; +} + +void meal_pager_scene_set_first_station_on_exit(void* context) { + Meal_Pager* app = context; + UNUSED(app); +} \ No newline at end of file diff --git a/scenes/meal_pager_scene_set_last_pager.c b/scenes/meal_pager_scene_set_last_pager.c new file mode 100644 index 00000000000..6cfd83f3990 --- /dev/null +++ b/scenes/meal_pager_scene_set_last_pager.c @@ -0,0 +1,63 @@ +#include "../meal_pager_i.h" +#include "../helpers/meal_pager_custom_event.h" +#include "../helpers/meal_pager_led.h" +#include + +void meal_pager_set_last_pager_callback(void* context) { + furi_assert(context); + Meal_Pager* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); +} + +void meal_pager_scene_set_last_pager_on_enter(void* context) { + furi_assert(context); + Meal_Pager* app = context; + IntInput* int_input = app->int_input; + size_t enter_name_length = 5; + meal_pager_set_max_values(app); + char* str = "Set Last Pager (0 - 999)"; + const char* constStr = str; + snprintf(str, 36, "Set Last Pager (%lu - %lu)", app->first_pager, app->max_pager); + + int_input_set_header_text(int_input, constStr); + + int_input_set_result_callback( + int_input, + meal_pager_set_last_pager_callback, + context, + app->text_store[3], + enter_name_length, + false); + + view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdIntInput); +} + +bool meal_pager_scene_set_last_pager_on_event(void* context, SceneManagerEvent event) { + Meal_Pager* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + app->last_pager = atoi(app->text_store[3]); + app->last_pager_char = app->text_store[3]; + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeTick) { + if(app->state_notifications == SubGhzNotificationStateTx) { + app->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(app->subghz->txrx); + meal_pager_blink_stop(app); + meal_pager_transmit_model_set_sending(app->meal_pager_transmit, 0); + } + return true; + } + + return consumed; +} + +void meal_pager_scene_set_last_pager_on_exit(void* context) { + Meal_Pager* app = context; + UNUSED(app); +} \ No newline at end of file diff --git a/scenes/meal_pager_scene_set_last_station.c b/scenes/meal_pager_scene_set_last_station.c new file mode 100644 index 00000000000..67eb633923f --- /dev/null +++ b/scenes/meal_pager_scene_set_last_station.c @@ -0,0 +1,63 @@ +#include "../meal_pager_i.h" +#include "../helpers/meal_pager_custom_event.h" +#include "../helpers/meal_pager_led.h" +#include + +void meal_pager_set_last_station_callback(void* context) { + furi_assert(context); + Meal_Pager* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); +} + +void meal_pager_scene_set_last_station_on_enter(void* context) { + furi_assert(context); + Meal_Pager* app = context; + IntInput* int_input = app->int_input; + size_t enter_name_length = 5; + meal_pager_set_max_values(app); + char* str = "Set Last Station (0 - 9999)"; + const char* constStr = str; + snprintf(str, 36, "Set Last Station (%lu - %lu)", app->last_station, app->max_station); + + int_input_set_header_text(int_input, constStr); + + int_input_set_result_callback( + int_input, + meal_pager_set_last_station_callback, + context, + app->text_store[1], + enter_name_length, + false); + + view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdIntInput); +} + +bool meal_pager_scene_set_last_station_on_event(void* context, SceneManagerEvent event) { + Meal_Pager* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + app->last_station = atoi(app->text_store[1]); + app->last_station_char = app->text_store[1]; + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeTick) { + if(app->state_notifications == SubGhzNotificationStateTx) { + app->state_notifications = SubGhzNotificationStateIDLE; + subghz_txrx_stop(app->subghz->txrx); + meal_pager_blink_stop(app); + meal_pager_transmit_model_set_sending(app->meal_pager_transmit, 0); + } + return true; + } + + return consumed; +} + +void meal_pager_scene_set_last_station_on_exit(void* context) { + Meal_Pager* app = context; + UNUSED(app); +} \ No newline at end of file diff --git a/scenes/meal_pager_scene_set_station.c b/scenes/meal_pager_scene_set_station.c deleted file mode 100644 index 7da604c1851..00000000000 --- a/scenes/meal_pager_scene_set_station.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "../meal_pager_i.h" -#include "../helpers/meal_pager_custom_event.h" -#include "../helpers/meal_pager_storage.h" -#include "../helpers/retekess/meal_pager_retekess_t119.h" -#include "../helpers/retekess/meal_pager_retekess_td157.h" -#include "../helpers/retekess/meal_pager_retekess_td165.h" -#include "../helpers/retekess/meal_pager_retekess_td174.h" -#include "../views/meal_pager_transmit.h" -#include "../helpers/meal_pager_led.h" -#include "../helpers/subghz/subghz.h" -#include "../views/meal_pager_transmit.h" -#include - -void meal_pager_set_station_callback(void* context) { - furi_assert(context); - Meal_Pager* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); -} - -/*static void meal_pager_int_input_callback(void* context) { - furi_assert(context); - Meal_Pager* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, Meal_PagerCustomerEventIntInput); -}*/ - -void meal_pager_scene_set_station_on_enter(void* context) { - furi_assert(context); - Meal_Pager* app = context; - IntInput* int_input = app->int_input; - size_t enter_name_length = 4; - meal_pager_set_max_values(app); - char *str = "Set first Station (0 - 9999)"; - const char *constStr = str; - snprintf(str, 36, "Set first Station (0 - %lu)", app->max_station); - - int_input_set_header_text(int_input, constStr); - - int_input_set_result_callback( - int_input, - meal_pager_set_station_callback, - context, - app->text_buffer, - enter_name_length, - false); - - UNUSED(app); - UNUSED(enter_name_length); - view_dispatcher_switch_to_view(app->view_dispatcher, Meal_PagerViewIdIntInput); -} - - -bool meal_pager_scene_set_station_on_event(void* context, SceneManagerEvent event) { - Meal_Pager* app = context; - bool consumed = false; - - if(event.type == SceneManagerEventTypeBack) { - scene_manager_previous_scene(app->scene_manager); - return true; - } else if(event.type == SceneManagerEventTypeCustom) { - switch(event.event) { - case Meal_PagerCustomEventTransmitLeft: - case Meal_PagerCustomEventTransmitRight: - break; - case Meal_PagerCustomEventTransmitUp: - case Meal_PagerCustomEventTransmitDown: - break; - case Meal_PagerCustomEventTransmitBack: - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, Meal_PagerSceneMenu)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - consumed = true; - break; - } - } else if(event.type == SceneManagerEventTypeTick) { - if(app->state_notifications == SubGhzNotificationStateTx) { - app->state_notifications = SubGhzNotificationStateIDLE; - subghz_txrx_stop(app->subghz->txrx); - meal_pager_blink_stop(app); - meal_pager_transmit_model_set_sending(app->meal_pager_transmit, 0); - } - return true; - } - - return consumed; -} - -void meal_pager_scene_set_station_on_exit(void* context) { - Meal_Pager* app = context; - UNUSED(app); -} \ No newline at end of file diff --git a/scenes/meal_pager_scene_settings.c b/scenes/meal_pager_scene_settings.c index 082870160a8..d60efe52da4 100644 --- a/scenes/meal_pager_scene_settings.c +++ b/scenes/meal_pager_scene_settings.c @@ -66,21 +66,11 @@ static void meal_pager_scene_settings_set_pager_type(VariableItem* item) { } static void meal_pager_scene_settings_set_first_station(VariableItem* item) { - Meal_Pager* app = variable_item_get_context(item); - uint32_t index = variable_item_get_current_value_index(item); - - snprintf(app->first_station_char, 20, "%lu", index); - variable_item_set_current_value_text(item, app->first_station_char); - app->first_station = index; + UNUSED(item); } static void meal_pager_scene_settings_set_last_station(VariableItem* item) { - Meal_Pager* app = variable_item_get_context(item); - uint32_t index = variable_item_get_current_value_index(item); - - snprintf(app->last_station_char, 20, "%lu", index); - variable_item_set_current_value_text(item, app->last_station_char); - app->last_station = index; + UNUSED(item); } static void meal_pager_scene_settings_set_first_pager(VariableItem* item) { @@ -110,7 +100,7 @@ static void meal_pager_scene_settings_set_repeats(VariableItem* item) { app->repeats = index; } -static void meal_pager_scene_settings_set_haptic(VariableItem* item) { +/*static void meal_pager_scene_settings_set_haptic(VariableItem* item) { Meal_Pager* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); @@ -123,7 +113,7 @@ static void meal_pager_scene_settings_set_speaker(VariableItem* item) { uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, speaker_text[index]); app->speaker = speaker_value[index]; -} +}*/ static void meal_pager_scene_settings_set_led(VariableItem* item) { Meal_Pager* app = variable_item_get_context(item); @@ -151,11 +141,7 @@ void meal_pager_scene_settings_on_enter(void* context) { // Pager Type item = variable_item_list_add( - app->variable_item_list, - "Pager Type:", - 4, - meal_pager_scene_settings_set_pager_type, - app); + app->variable_item_list, "Pager Type:", 4, meal_pager_scene_settings_set_pager_type, app); value_index = value_index_uint32(app->pager_type, pager_type_value, 4); variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, pager_type_text[value_index]); @@ -164,10 +150,9 @@ void meal_pager_scene_settings_on_enter(void* context) { item = variable_item_list_add( app->variable_item_list, "First Station", - 255, + 1, meal_pager_scene_settings_set_first_station, app); - variable_item_set_current_value_index(item, app->first_station); snprintf(app->first_pager_char, 20, "%lu", app->first_station); variable_item_set_current_value_text(item, app->first_station_char); @@ -175,24 +160,21 @@ void meal_pager_scene_settings_on_enter(void* context) { item = variable_item_list_add( app->variable_item_list, "Last Station", - 255, + 1, meal_pager_scene_settings_set_last_station, app); - variable_item_set_current_value_index(item, app->last_station); snprintf(app->last_station_char, 20, "%lu", app->last_station); variable_item_set_current_value_text(item, app->last_station_char); // First Pager item = variable_item_list_add( - app->variable_item_list, "First Pager", 99, meal_pager_scene_settings_set_first_pager, app); - variable_item_set_current_value_index(item, app->first_pager); + app->variable_item_list, "First Pager", 1, meal_pager_scene_settings_set_first_pager, app); snprintf(app->first_pager_char, 20, "%lu", app->first_pager); variable_item_set_current_value_text(item, app->first_pager_char); // Last Pager item = variable_item_list_add( - app->variable_item_list, "Last Pager", 99, meal_pager_scene_settings_set_last_pager, app); - variable_item_set_current_value_index(item, app->last_pager); + app->variable_item_list, "Last Pager", 1, meal_pager_scene_settings_set_last_pager, app); snprintf(app->last_pager_char, 20, "%lu", app->last_pager); variable_item_set_current_value_text(item, app->last_pager_char); @@ -203,19 +185,19 @@ void meal_pager_scene_settings_on_enter(void* context) { snprintf(app->repeats_char, 20, "%lu", app->repeats); variable_item_set_current_value_text(item, app->repeats_char); - // Vibro on/off - item = variable_item_list_add( + // Vibro on/off Disabled until used + /*item = variable_item_list_add( app->variable_item_list, "Vibro/Haptic:", 2, meal_pager_scene_settings_set_haptic, app); value_index = value_index_uint32(app->haptic, haptic_value, 2); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, haptic_text[value_index]); + variable_item_set_current_value_text(item, haptic_text[value_index]);*/ - // Sound on/off - item = variable_item_list_add( + // Sound on/off Disabled until used + /*item = variable_item_list_add( app->variable_item_list, "Sound:", 2, meal_pager_scene_settings_set_speaker, app); value_index = value_index_uint32(app->speaker, speaker_value, 2); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, speaker_text[value_index]); + variable_item_set_current_value_text(item, speaker_text[value_index]);*/ // LED Effects on/off item = variable_item_list_add( diff --git a/scenes/meal_pager_scene_transmit.c b/scenes/meal_pager_scene_transmit.c index 142c35ff2d5..dc49d2911a7 100644 --- a/scenes/meal_pager_scene_transmit.c +++ b/scenes/meal_pager_scene_transmit.c @@ -93,7 +93,7 @@ bool meal_pager_scene_transmit_on_event(void* context, SceneManagerEvent event) break; } } else if(event.type == SceneManagerEventTypeTick) { - if(app->state_notifications == SubGhzNotificationStateTx) { + if(app->state_notifications == SubGhzNotificationStateTx && app->led == 1) { notification_message(app->notification, &sequence_blink_magenta_10); } return true; From 9d8cc15258c5730f58c2a476d79e03bd81e03ac1 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 7 Jan 2024 23:24:51 +0100 Subject: [PATCH 5/5] Fix Memory Leak --- helpers/meal_pager_storage.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/helpers/meal_pager_storage.c b/helpers/meal_pager_storage.c index aec3ddd10fc..83d9a1796bf 100644 --- a/helpers/meal_pager_storage.c +++ b/helpers/meal_pager_storage.c @@ -198,6 +198,8 @@ void meal_pager_read_settings(void* context) { flipper_format_rewind(fff_file); + furi_string_free(temp_str); + meal_pager_close_config_file(fff_file); meal_pager_close_storage(); }