Просмотр исходного кода

update ublox, game15, uart terminal, intervalometer, seader

MX 2 лет назад
Родитель
Сommit
1f7082fed7
24 измененных файлов с 297 добавлено и 60 удалено
  1. 0 0
      apps_source_code/ir_intervalometer/.github/workflows/build.yml
  2. 0 0
      apps_source_code/ir_intervalometer/README.md
  3. 3 3
      apps_source_code/ir_intervalometer/application.fam
  4. 0 0
      apps_source_code/ir_intervalometer/doc/img/app-icon.png
  5. 0 0
      apps_source_code/ir_intervalometer/doc/img/running-intervalometer.png
  6. 0 0
      apps_source_code/ir_intervalometer/doc/img/settings-burst.png
  7. 0 0
      apps_source_code/ir_intervalometer/doc/img/settings-edit.png
  8. 0 0
      apps_source_code/ir_intervalometer/doc/img/settings-initial.png
  9. 0 0
      apps_source_code/ir_intervalometer/icons/ArrowDown_3x5.png
  10. 0 0
      apps_source_code/ir_intervalometer/icons/ArrowUp_3x5.png
  11. 0 0
      apps_source_code/ir_intervalometer/img/1.png
  12. 0 0
      apps_source_code/ir_intervalometer/img/2.png
  13. 107 28
      apps_source_code/ir_intervalometer/intervalometer.c
  14. 0 0
      apps_source_code/ir_intervalometer/intervalometer.h
  15. 0 0
      apps_source_code/ir_intervalometer/intervalometer_10x.png
  16. 5 3
      base_pack/game15/game15.c
  17. 76 1
      base_pack/uart_terminal/scenes/uart_terminal_scene_console_output.c
  18. 4 4
      base_pack/uart_terminal/scenes/uart_terminal_scene_start.c
  19. 8 6
      non_catalog_apps/seader/readme.md
  20. 91 8
      non_catalog_apps/seader/seader_worker.c
  21. 1 1
      non_catalog_apps/ublox/README.md
  22. 1 1
      non_catalog_apps/ublox/application.fam
  23. 1 5
      non_catalog_apps/ublox/scenes/ublox_scene_enter_file_name.c
  24. BIN
      non_catalog_apps/ublox/screenshots/data_display_handheld.png

+ 0 - 0
apps_source_code/sony-intervalometer/.github/workflows/build.yml → apps_source_code/ir_intervalometer/.github/workflows/build.yml


+ 0 - 0
apps_source_code/sony-intervalometer/README.md → apps_source_code/ir_intervalometer/README.md


+ 3 - 3
apps_source_code/sony-intervalometer/application.fam → apps_source_code/ir_intervalometer/application.fam

@@ -1,6 +1,6 @@
 App(
 App(
-    appid="sony_intervalometer",
-    name="[Sony] Intervalometer",
+    appid="ir_intervalometer",
+    name="[IR] Intervalometer",
     apptype=FlipperAppType.EXTERNAL,
     apptype=FlipperAppType.EXTERNAL,
     entry_point="flipvalo_app",
     entry_point="flipvalo_app",
     requires=["gui"],
     requires=["gui"],
@@ -12,5 +12,5 @@ App(
     fap_author="@Nitepone",
     fap_author="@Nitepone",
     fap_weburl="https://github.com/Nitepone/flipper-intervalometer",
     fap_weburl="https://github.com/Nitepone/flipper-intervalometer",
     fap_version="1.1",
     fap_version="1.1",
-    fap_description="This is a simple configurable valometer app for Sony cameras. Works via Infrared port.",
+    fap_description="This is a simple configurable valometer app for DSLR cameras. Works via Infrared port.",
 )
 )

+ 0 - 0
apps_source_code/sony-intervalometer/doc/img/app-icon.png → apps_source_code/ir_intervalometer/doc/img/app-icon.png


+ 0 - 0
apps_source_code/sony-intervalometer/doc/img/running-intervalometer.png → apps_source_code/ir_intervalometer/doc/img/running-intervalometer.png


+ 0 - 0
apps_source_code/sony-intervalometer/doc/img/settings-burst.png → apps_source_code/ir_intervalometer/doc/img/settings-burst.png


+ 0 - 0
apps_source_code/sony-intervalometer/doc/img/settings-edit.png → apps_source_code/ir_intervalometer/doc/img/settings-edit.png


+ 0 - 0
apps_source_code/sony-intervalometer/doc/img/settings-initial.png → apps_source_code/ir_intervalometer/doc/img/settings-initial.png


+ 0 - 0
apps_source_code/sony-intervalometer/icons/ArrowDown_3x5.png → apps_source_code/ir_intervalometer/icons/ArrowDown_3x5.png


+ 0 - 0
apps_source_code/sony-intervalometer/icons/ArrowUp_3x5.png → apps_source_code/ir_intervalometer/icons/ArrowUp_3x5.png


+ 0 - 0
apps_source_code/sony-intervalometer/img/1.png → apps_source_code/ir_intervalometer/img/1.png


+ 0 - 0
apps_source_code/sony-intervalometer/img/2.png → apps_source_code/ir_intervalometer/img/2.png


+ 107 - 28
apps_source_code/sony-intervalometer/intervalometer.c → apps_source_code/ir_intervalometer/intervalometer.c

@@ -18,7 +18,7 @@
 #include <notification/notification.h>
 #include <notification/notification.h>
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
 
 
-#include <sony_intervalometer_icons.h>
+#include <ir_intervalometer_icons.h>
 
 
 // app ui scenes
 // app ui scenes
 enum flipvalo_ui_scene {
 enum flipvalo_ui_scene {
@@ -26,6 +26,20 @@ enum flipvalo_ui_scene {
     FVSceneConfig,
     FVSceneConfig,
 };
 };
 
 
+// defines a flipvalo camera trigger
+struct flipvalo_trigger {
+    const char* display_name;
+    int (*send)(void* output_config);
+};
+
+enum flipvalo_trigger_variants {
+    FvTrigMin = 0,
+    FvTrigSony = 0,
+    FvTrigCanon = 1,
+    FvTrigNikon = 2,
+    FvTrigMax = 2,
+};
+
 // run config for intervalometer
 // run config for intervalometer
 struct flipvalo_config {
 struct flipvalo_config {
     int init_delay_msec; // initial delay to start capture
     int init_delay_msec; // initial delay to start capture
@@ -34,11 +48,8 @@ struct flipvalo_config {
     int burst_count; // number of triggers in a shot
     int burst_count; // number of triggers in a shot
     int burst_delay_msec; // time between triggers in a shot
     int burst_delay_msec; // time between triggers in a shot
     int tickrate; // tick rate in "ticks per second"
     int tickrate; // tick rate in "ticks per second"
+    enum flipvalo_trigger_variants trigger; // current trigger
 
 
-    // camera control functions.
-    // a bit overkill atm, but this will allow us to drop in support
-    // for other cameras, bluetooth, and more adv. functions later.
-    int (*send_trigger_fn)(void* output_config);
     void* output_config;
     void* output_config;
 };
 };
 
 
@@ -67,7 +78,8 @@ enum flipvalo_config_edit_lines {
     FvConfigEditShotDelay,
     FvConfigEditShotDelay,
     FvConfigEditBurstCount,
     FvConfigEditBurstCount,
     FvConfigEditBurstDelay,
     FvConfigEditBurstDelay,
-    FvConfigEditMAX = FvConfigEditBurstDelay,
+    FvConfigEditTrigger,
+    FvConfigEditMAX = FvConfigEditTrigger,
 };
 };
 
 
 struct flipvalo_config_edit_view {
 struct flipvalo_config_edit_view {
@@ -107,11 +119,10 @@ struct plugin_event {
     InputEvent input;
     InputEvent input;
 };
 };
 
 
-// XXX(luna) settings experimental ui kludge
-
 enum flipvalo_config_edit_line_type {
 enum flipvalo_config_edit_line_type {
     FvConfigEditTypeTimer,
     FvConfigEditTypeTimer,
     FvConfigEditTypeCount,
     FvConfigEditTypeCount,
+    FvConfigEditTypeEnum,
 };
 };
 
 
 static void flipvalo_config_edit_view_init(struct flipvalo_config_edit_view* view) {
 static void flipvalo_config_edit_view_init(struct flipvalo_config_edit_view* view) {
@@ -122,6 +133,54 @@ static void flipvalo_config_edit_view_init(struct flipvalo_config_edit_view* vie
     view->edit_mode = false;
     view->edit_mode = false;
 }
 }
 
 
+static int sony_ir_trigger_send(void* ctx) {
+    UNUSED(ctx);
+    InfraredMessage message = {
+        .address = 0x1E3A,
+        .command = 0x2D,
+        .protocol = InfraredProtocolSIRC20,
+    };
+    infrared_send(&message, 1);
+    return 0;
+}
+
+uint32_t canon_ir_timings[] = {594, 7182, 593};
+static int canon_ir_trigger_send(void* ctx) {
+    UNUSED(ctx);
+    infrared_send_raw_ext(canon_ir_timings, 3, true, 38000, 0.33);
+    return 0;
+}
+
+uint32_t nikon_ir_timings[] =
+    {1945, 28253, 404, 1513, 410, 3611, 460, 70144, 1974, 28213, 455, 1493, 461, 3591, 409};
+static int nikon_ir_trigger_send(void* ctx) {
+    UNUSED(ctx);
+    infrared_send_raw_ext(nikon_ir_timings, 15, true, 38000, 0.33);
+    return 0;
+}
+
+struct flipvalo_trigger sony_ir_trigger = {.send = sony_ir_trigger_send, .display_name = "Sony IR"};
+
+struct flipvalo_trigger canon_ir_trigger = {
+    .send = canon_ir_trigger_send,
+    .display_name = "Canon IR"};
+
+struct flipvalo_trigger nikon_ir_trigger = {
+    .send = nikon_ir_trigger_send,
+    .display_name = "Nikon IR"};
+
+static struct flipvalo_trigger* flipvalo_get_trigger(enum flipvalo_trigger_variants variant) {
+    switch(variant) {
+    case FvTrigSony:
+        return &sony_ir_trigger;
+    case FvTrigCanon:
+        return &canon_ir_trigger;
+    case FvTrigNikon:
+        return &nikon_ir_trigger;
+    }
+    return NULL;
+}
+
 #define ITEM_H 64 / 3
 #define ITEM_H 64 / 3
 #define ITEM_W 128
 #define ITEM_W 128
 #define VALUE_X 100
 #define VALUE_X 100
@@ -129,6 +188,7 @@ static void flipvalo_config_edit_view_init(struct flipvalo_config_edit_view* vie
 static void flipvalo_config_edit_draw(Canvas* canvas, struct flipvalo_config_edit_view* view) {
 static void flipvalo_config_edit_draw(Canvas* canvas, struct flipvalo_config_edit_view* view) {
     int* line_value;
     int* line_value;
     char* line_label = NULL;
     char* line_label = NULL;
+    const char* line_disp_str = "";
     FuriString* temp_str = furi_string_alloc();
     FuriString* temp_str = furi_string_alloc();
     enum flipvalo_config_edit_line_type line_type;
     enum flipvalo_config_edit_line_type line_type;
     enum flipvalo_config_edit_lines selected_line;
     enum flipvalo_config_edit_lines selected_line;
@@ -161,6 +221,12 @@ static void flipvalo_config_edit_draw(Canvas* canvas, struct flipvalo_config_edi
             line_type = FvConfigEditTypeCount;
             line_type = FvConfigEditTypeCount;
             line_label = "Brst Count";
             line_label = "Brst Count";
             break;
             break;
+        case FvConfigEditTrigger:
+            line_value = NULL;
+            line_type = FvConfigEditTypeEnum;
+            line_label = "Trig Type";
+            line_disp_str = flipvalo_get_trigger(view->config->trigger)->display_name;
+            break;
         default:
         default:
             continue;
             continue;
         };
         };
@@ -232,6 +298,15 @@ static void flipvalo_config_edit_draw(Canvas* canvas, struct flipvalo_config_edi
             canvas_draw_str_aligned(
             canvas_draw_str_aligned(
                 canvas, VALUE_X + VALUE_W / 2, text_y, AlignCenter, AlignCenter, ">");
                 canvas, VALUE_X + VALUE_W / 2, text_y, AlignCenter, AlignCenter, ">");
             break;
             break;
+        case FvConfigEditTypeEnum:
+            furi_string_printf(temp_str, "%s", line_disp_str);
+            canvas_draw_str_aligned(
+                canvas, VALUE_X, text_y, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str));
+            canvas_draw_str_aligned(
+                canvas, VALUE_X - VALUE_W / 2, text_y, AlignCenter, AlignCenter, "<");
+            canvas_draw_str_aligned(
+                canvas, VALUE_X + VALUE_W / 2, text_y, AlignCenter, AlignCenter, ">");
+            break;
         }
         }
     }
     }
 
 
@@ -242,8 +317,11 @@ static void
     flipvalo_config_edit_input_move_cursor(struct flipvalo_config_edit_view* view, int dx, int dy) {
     flipvalo_config_edit_input_move_cursor(struct flipvalo_config_edit_view* view, int dx, int dy) {
     enum flipvalo_config_edit_lines new_line = 0;
     enum flipvalo_config_edit_lines new_line = 0;
 
 
-    int* line_value;
+    int* line_value = NULL;
     enum flipvalo_config_edit_line_type line_type;
     enum flipvalo_config_edit_line_type line_type;
+    // only used for enum type
+    int max_value;
+    int min_value;
 
 
     switch(view->cur_line) {
     switch(view->cur_line) {
     case FvConfigEditInitDelay:
     case FvConfigEditInitDelay:
@@ -266,6 +344,12 @@ static void
         line_value = &view->config->burst_count;
         line_value = &view->config->burst_count;
         line_type = FvConfigEditTypeCount;
         line_type = FvConfigEditTypeCount;
         break;
         break;
+    case FvConfigEditTrigger:
+        line_value = (int*)(&view->config->trigger);
+        line_type = FvConfigEditTypeEnum;
+        min_value = FvTrigMin;
+        max_value = FvTrigMax;
+        break;
     default:
     default:
         return;
         return;
     };
     };
@@ -288,18 +372,23 @@ static void
 
 
         // Do `dx` behavior
         // Do `dx` behavior
         switch(line_type) {
         switch(line_type) {
+        case FvConfigEditTypeTimer:
+            // no-op unless edit mode
+            break;
         case FvConfigEditTypeCount:
         case FvConfigEditTypeCount:
-            if(*line_value + dx >= 0) {
+            min_value = 0;
+            max_value = INT_MAX;
+            // fall through.
+        case FvConfigEditTypeEnum:
+            if((*line_value + dx) >= min_value && (*line_value + dx) <= max_value) {
                 *line_value += dx;
                 *line_value += dx;
             }
             }
             break;
             break;
-        case FvConfigEditTypeTimer:
-            // no-op unless edit mode
-            break;
         }
         }
     } else /* edit mode */ {
     } else /* edit mode */ {
         switch(line_type) {
         switch(line_type) {
         case FvConfigEditTypeCount:
         case FvConfigEditTypeCount:
+        case FvConfigEditTypeEnum:
             // If current line does not edit mode.. why are we in edit mode?
             // If current line does not edit mode.. why are we in edit mode?
             // Reaching this would be a bug, so lets go back to normal mode.
             // Reaching this would be a bug, so lets go back to normal mode.
             view->edit_mode = false;
             view->edit_mode = false;
@@ -386,17 +475,6 @@ static void flipvalo_run_state_init(struct flipvalo_run_state* fv_run_state) {
     fv_run_state->tick_cur = 0;
     fv_run_state->tick_cur = 0;
 }
 }
 
 
-static int sony_ir_trigger(void* ctx) {
-    UNUSED(ctx);
-    InfraredMessage message = {
-        .address = 0x1E3A,
-        .command = 0x2D,
-        .protocol = InfraredProtocolSIRC20,
-    };
-    infrared_send(&message, 1);
-    return 0;
-}
-
 static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
 static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
     furi_assert(event_queue);
     furi_assert(event_queue);
     struct plugin_event event = {.type = EventTypeKey, .input = *input_event};
     struct plugin_event event = {.type = EventTypeKey, .input = *input_event};
@@ -413,7 +491,7 @@ static void flipvalo_intv_tick(struct flipvalo_priv* fv_priv) {
     // check if action required
     // check if action required
     if(run->tick_cur++ >= run->tick_next) {
     if(run->tick_cur++ >= run->tick_next) {
         // call trigger function
         // call trigger function
-        conf->send_trigger_fn(conf->output_config);
+        flipvalo_get_trigger(conf->trigger)->send(conf->output_config);
         fv_priv->gui_shutter_blink = 3;
         fv_priv->gui_shutter_blink = 3;
         // end of burst, prepare next shot
         // end of burst, prepare next shot
         if(run->burst_cur >= conf->burst_count) {
         if(run->burst_cur >= conf->burst_count) {
@@ -523,7 +601,7 @@ static void flipvalo_config_init(struct flipvalo_config* fv_conf) {
     fv_conf->burst_count = 1;
     fv_conf->burst_count = 1;
     fv_conf->burst_delay_msec = 0;
     fv_conf->burst_delay_msec = 0;
     fv_conf->tickrate = 125;
     fv_conf->tickrate = 125;
-    fv_conf->send_trigger_fn = sony_ir_trigger;
+    fv_conf->trigger = FvTrigSony;
     fv_conf->output_config = NULL;
     fv_conf->output_config = NULL;
 }
 }
 
 
@@ -592,7 +670,7 @@ int32_t flipvalo_app() {
         case FVSceneMain:
         case FVSceneMain:
             // TODO(luna) Maybe give this a function.. look howl clean FVSceneConfig is...
             // TODO(luna) Maybe give this a function.. look howl clean FVSceneConfig is...
             if(event.type == EventTypeKey) {
             if(event.type == EventTypeKey) {
-                if(event.input.type == InputTypeShort) {
+                if(event.input.type == InputTypeShort || event.input.type == InputTypeLong) {
                     switch(event.input.key) {
                     switch(event.input.key) {
                     case InputKeyUp:
                     case InputKeyUp:
                         break;
                         break;
@@ -605,7 +683,8 @@ int32_t flipvalo_app() {
                         break;
                         break;
                     case InputKeyRight:
                     case InputKeyRight:
                         fv_priv->gui_shutter_blink = 3;
                         fv_priv->gui_shutter_blink = 3;
-                        fv_priv->config.send_trigger_fn(fv_priv->config.output_config);
+                        flipvalo_get_trigger(fv_priv->config.trigger)
+                            ->send(fv_priv->config.output_config);
                         break;
                         break;
                     case InputKeyOk:
                     case InputKeyOk:
                         if(flipvalo_intv_running(fv_priv)) {
                         if(flipvalo_intv_running(fv_priv)) {

+ 0 - 0
apps_source_code/sony-intervalometer/intervalometer.h → apps_source_code/ir_intervalometer/intervalometer.h


+ 0 - 0
apps_source_code/sony-intervalometer/intervalometer_10x.png → apps_source_code/ir_intervalometer/intervalometer_10x.png


+ 5 - 3
base_pack/game15/game15.c

@@ -224,8 +224,10 @@ static bool is_board_solved() {
 static void game_tick() {
 static void game_tick() {
     switch(game_state.scene) {
     switch(game_state.scene) {
     case ScenePlay:
     case ScenePlay:
-        game_state.tick_count++;
-        if(loaded_saving_ticks) loaded_saving_ticks--;
+        if (game_state.move_count >= 1)
+            game_state.tick_count++;
+        if (loaded_saving_ticks)
+            loaded_saving_ticks--;
         if(moving_cell.move_direction == DirectionNone && !key_stack_is_empty()) {
         if(moving_cell.move_direction == DirectionNone && !key_stack_is_empty()) {
             set_moving_cell_by_direction(key_stack_pop());
             set_moving_cell_by_direction(key_stack_pop());
             if(moving_cell.move_direction == DirectionNone) {
             if(moving_cell.move_direction == DirectionNone) {
@@ -363,7 +365,7 @@ static void render_callback(Canvas* const canvas) {
             canvas_draw_rbox(canvas, 20, 24, 88, 16, 4);
             canvas_draw_rbox(canvas, 20, 24, 88, 16, 4);
             canvas_set_color(canvas, ColorBlack);
             canvas_set_color(canvas, ColorBlack);
             canvas_draw_rframe(canvas, 20, 24, 88, 16, 4);
             canvas_draw_rframe(canvas, 20, 24, 88, 16, 4);
-            canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "Restore game ...");
+            canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "Restoring game ...");
         }
         }
     }
     }
 
 

+ 76 - 1
base_pack/uart_terminal/scenes/uart_terminal_scene_console_output.c

@@ -32,16 +32,66 @@ void uart_terminal_scene_console_output_on_enter(void* context) {
     }
     }
 
 
     //Change baudrate ///////////////////////////////////////////////////////////////////////////
     //Change baudrate ///////////////////////////////////////////////////////////////////////////
+    if(0 == strncmp("75", app->selected_tx_string, strlen("75")) && app->BAUDRATE != 75) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 75;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("110", app->selected_tx_string, strlen("110")) && app->BAUDRATE != 110) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 110;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("150", app->selected_tx_string, strlen("150")) && app->BAUDRATE != 150) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 150;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("300", app->selected_tx_string, strlen("300")) && app->BAUDRATE != 300) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 300;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("600", app->selected_tx_string, strlen("600")) && app->BAUDRATE != 600) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 600;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("1200", app->selected_tx_string, strlen("1200")) && app->BAUDRATE != 1200) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 1200;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("1800", app->selected_tx_string, strlen("1800")) && app->BAUDRATE != 1800) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 1800;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("2400", app->selected_tx_string, strlen("2400")) && app->BAUDRATE != 2400) {
     if(0 == strncmp("2400", app->selected_tx_string, strlen("2400")) && app->BAUDRATE != 2400) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
         app->BAUDRATE = 2400;
         app->BAUDRATE = 2400;
         app->uart = uart_terminal_uart_init(app);
         app->uart = uart_terminal_uart_init(app);
     }
     }
+    if(0 == strncmp("4800", app->selected_tx_string, strlen("4800")) && app->BAUDRATE != 4800) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 4800;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("7200", app->selected_tx_string, strlen("7200")) && app->BAUDRATE != 7200) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 7200;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("9600", app->selected_tx_string, strlen("9600")) && app->BAUDRATE != 9600) {
     if(0 == strncmp("9600", app->selected_tx_string, strlen("9600")) && app->BAUDRATE != 9600) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
         app->BAUDRATE = 9600;
         app->BAUDRATE = 9600;
         app->uart = uart_terminal_uart_init(app);
         app->uart = uart_terminal_uart_init(app);
     }
     }
+    if(0 == strncmp("14400", app->selected_tx_string, strlen("14400")) && app->BAUDRATE != 14400) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 14400;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("19200", app->selected_tx_string, strlen("19200")) && app->BAUDRATE != 19200) {
     if(0 == strncmp("19200", app->selected_tx_string, strlen("19200")) && app->BAUDRATE != 19200) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
         app->BAUDRATE = 19200;
         app->BAUDRATE = 19200;
@@ -52,23 +102,48 @@ void uart_terminal_scene_console_output_on_enter(void* context) {
         app->BAUDRATE = 38400;
         app->BAUDRATE = 38400;
         app->uart = uart_terminal_uart_init(app);
         app->uart = uart_terminal_uart_init(app);
     }
     }
+    if(0 == strncmp("56000", app->selected_tx_string, strlen("56000")) && app->BAUDRATE != 56000) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 56000;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("57600", app->selected_tx_string, strlen("57600")) && app->BAUDRATE != 57600) {
     if(0 == strncmp("57600", app->selected_tx_string, strlen("57600")) && app->BAUDRATE != 57600) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
         app->BAUDRATE = 57600;
         app->BAUDRATE = 57600;
         app->uart = uart_terminal_uart_init(app);
         app->uart = uart_terminal_uart_init(app);
     }
     }
+    if(0 == strncmp("76800", app->selected_tx_string, strlen("76800")) && app->BAUDRATE != 76800) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 76800;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("115200", app->selected_tx_string, strlen("115200")) &&
     if(0 == strncmp("115200", app->selected_tx_string, strlen("115200")) &&
        app->BAUDRATE != 115200) {
        app->BAUDRATE != 115200) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
         app->BAUDRATE = 115200;
         app->BAUDRATE = 115200;
         app->uart = uart_terminal_uart_init(app);
         app->uart = uart_terminal_uart_init(app);
     }
     }
+    if(0 == strncmp("128000", app->selected_tx_string, strlen("128000")) && app->BAUDRATE != 128000) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 128000;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("230400", app->selected_tx_string, strlen("230400")) &&
     if(0 == strncmp("230400", app->selected_tx_string, strlen("230400")) &&
        app->BAUDRATE != 230400) {
        app->BAUDRATE != 230400) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
         app->BAUDRATE = 230400;
         app->BAUDRATE = 230400;
         app->uart = uart_terminal_uart_init(app);
         app->uart = uart_terminal_uart_init(app);
     }
     }
+    if(0 == strncmp("250000", app->selected_tx_string, strlen("250000")) && app->BAUDRATE != 250000) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 250000;
+        app->uart = uart_terminal_uart_init(app);
+    }
+    if(0 == strncmp("256000", app->selected_tx_string, strlen("256000")) && app->BAUDRATE != 256000) {
+        uart_terminal_uart_free(app->uart);
+        app->BAUDRATE = 256000;
+        app->uart = uart_terminal_uart_init(app);
+    }
     if(0 == strncmp("460800", app->selected_tx_string, strlen("460800")) &&
     if(0 == strncmp("460800", app->selected_tx_string, strlen("460800")) &&
        app->BAUDRATE != 460800) {
        app->BAUDRATE != 460800) {
         uart_terminal_uart_free(app->uart);
         uart_terminal_uart_free(app->uart);
@@ -113,7 +188,7 @@ void uart_terminal_scene_console_output_on_enter(void* context) {
 
 
     // Send command with CR+LF or newline '\n'
     // Send command with CR+LF or newline '\n'
     if(app->is_command && app->selected_tx_string) {
     if(app->is_command && app->selected_tx_string) {
-        if(app->TERMINAL_MODE == 1) {
+        if(app->TERMINAL_MODE == 1){
             uart_terminal_uart_tx(
             uart_terminal_uart_tx(
                 (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
                 (uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
             uart_terminal_uart_tx((uint8_t*)("\r\n"), 2);
             uart_terminal_uart_tx((uint8_t*)("\r\n"), 2);

+ 4 - 4
base_pack/uart_terminal/scenes/uart_terminal_scene_start.c

@@ -10,7 +10,7 @@ typedef enum { FOCUS_CONSOLE_END = 0, FOCUS_CONSOLE_START, FOCUS_CONSOLE_TOGGLE
 #define SHOW_STOPSCAN_TIP (true)
 #define SHOW_STOPSCAN_TIP (true)
 #define NO_TIP (false)
 #define NO_TIP (false)
 
 
-#define MAX_OPTIONS (9)
+#define MAX_OPTIONS (25)
 typedef struct {
 typedef struct {
     const char* item_string;
     const char* item_string;
     const char* options_menu[MAX_OPTIONS];
     const char* options_menu[MAX_OPTIONS];
@@ -24,9 +24,9 @@ typedef struct {
 // NUM_MENU_ITEMS defined in uart_terminal_app_i.h - if you add an entry here, increment it!
 // NUM_MENU_ITEMS defined in uart_terminal_app_i.h - if you add an entry here, increment it!
 const UART_TerminalItem items[NUM_MENU_ITEMS] = {
 const UART_TerminalItem items[NUM_MENU_ITEMS] = {
     {"Console",
     {"Console",
-     {"115200", "2400", "9600", "19200", "38400", "57600", "230400", "460800", "921600"},
-     9,
-     {"115200", "2400", "9600", "19200", "38400", "57600", "230400", "460800", "921600"},
+     {"115200", "75", "110", "150", "300", "600", "1200", "1800", "2400", "4800", "7200", "9600", "14400", "19200", "31250", "38400", "56000", "57600", "76800", "128000", "230400", "250000", "256000", "460800", "921600"},
+     25,
+     {"115200", "75", "110", "150", "300", "600", "1200", "1800", "2400", "4800", "7200", "9600", "14400", "19200", "31250", "38400", "56000", "57600", "76800", "128000", "230400", "250000", "256000", "460800", "921600"},
      NO_ARGS,
      NO_ARGS,
      FOCUS_CONSOLE_END,
      FOCUS_CONSOLE_END,
      NO_TIP},
      NO_TIP},

+ 8 - 6
non_catalog_apps/seader/readme.md

@@ -17,14 +17,11 @@ Or build it yourself from the files in the [NARD repo](https://github.com/killer
 
 
 ### Option 2: Smart Card 2 Click
 ### Option 2: Smart Card 2 Click
 
 
-Put **[SAM](https://www.cdw.com/product/hp-sim-for-hid-iclass-for-hip2-reader-security-sim/4854794)** into **[adapter](https://a.co/d/1E9Zk1h)** (because of chip on top) and plug into **[reader](https://www.mikroe.com/smart-card-2-click)**. Connect reader to Flipper Zero (See `Connections` below).
+Put SAM ([USA](https://www.cdw.com/product/hp-sim-for-hid-iclass-for-hip2-reader-security-sim/4854794) [EU](https://www.rfideas-shop.com/en/kt-sim-se-sim-card-hid-iclass-and-seos-for-sphip-r.html) [CA](https://www.pc-canada.com/item/hp-sim-for-hid-iclass-se-and-hid-iclass-seos-for-hip2-reader/y7c07a)) into **[adapter](https://a.co/d/1E9Zk1h)** (because of chip on top) and plug into **[reader](https://www.mikroe.com/smart-card-2-click)**. Connect reader to Flipper Zero (See `Connections` below).
 
 
-## Development
-
-### To Build ASN1
+Optionally 3d print a [case designed by sean](https://www.printables.com/model/543149-case-for-flipper-zero-devboard-smart2click-samsim)
 
 
- * Install git version of [asnc1](https://github.com/vlm/asn1c) (`brew install asn1c --head` on macos)
- * Run `asn1c -D ./lib/asn1 -no-gen-example -pdu=all seader.asn` in in root to generate asn1c files
+## Development
 
 
 ### To Build App
 ### To Build App
 
 
@@ -32,6 +29,11 @@ Put **[SAM](https://www.cdw.com/product/hp-sim-for-hid-iclass-for-hip2-reader-se
  * `ufbt` to build
  * `ufbt` to build
  * `ufbt launch` to launch
  * `ufbt launch` to launch
 
 
+### To Build ASN1 (if you change seader.asn1)
+
+ * Install git version of [asnc1](https://github.com/vlm/asn1c) (`brew install asn1c --head` on macos)
+ * Run `asn1c -D ./lib/asn1 -no-gen-example -pdu=all seader.asn` in in root to generate asn1c files
+
 ## References
 ## References
 
 
 - [omnikey_5025_cl_software_developer_guide_mn_en](https://www.virtualsecurity.nl/amfile/file/download/file/18/product/1892/)
 - [omnikey_5025_cl_software_developer_guide_mn_en](https://www.virtualsecurity.nl/amfile/file/download/file/18/product/1892/)

+ 91 - 8
non_catalog_apps/seader/seader_worker.c

@@ -1,6 +1,8 @@
 #include "seader_worker_i.h"
 #include "seader_worker_i.h"
 
 
 #include <flipper_format/flipper_format.h>
 #include <flipper_format/flipper_format.h>
+#include <lib/nfc/protocols/nfc_util.h>
+#include <lib/lfrfid/tools/bit_lib.h>
 
 
 #define TAG "SeaderWorker"
 #define TAG "SeaderWorker"
 
 
@@ -230,8 +232,6 @@ bool seader_read_nfc(SeaderUartBridge* seader_uart) {
             } else if(seader_mf_classic_check_card_type(
             } else if(seader_mf_classic_check_card_type(
                           nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak)) {
                           nfc_data.atqa[0], nfc_data.atqa[1], nfc_data.sak)) {
                 FURI_LOG_D(TAG, "MFC");
                 FURI_LOG_D(TAG, "MFC");
-                OCTET_STRING_t atqa = {.buf = nfc_data.atqa, .size = sizeof(nfc_data.atqa)};
-                cardDetails->atqa = &atqa;
                 seader_send_card_detected(seader_uart, cardDetails);
                 seader_send_card_detected(seader_uart, cardDetails);
                 rtn = true;
                 rtn = true;
             } else if(nfc_data.interface == FuriHalNfcInterfaceIsoDep) {
             } else if(nfc_data.interface == FuriHalNfcInterfaceIsoDep) {
@@ -550,20 +550,100 @@ void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t l
     ASN_STRUCT_FREE(asn_DEF_Response, response);
     ASN_STRUCT_FREE(asn_DEF_Response, response);
 }
 }
 
 
-bool seader_iso14443a_transmit(SeaderWorker* seader_worker, uint8_t* buffer, size_t len) {
+bool seader_iso14443a_transmit(
+    SeaderWorker* seader_worker,
+    uint8_t* buffer,
+    size_t len,
+    uint16_t timeout,
+    uint8_t format[3]) {
     SeaderUartBridge* seader_uart = seader_worker->uart;
     SeaderUartBridge* seader_uart = seader_worker->uart;
     FuriHalNfcTxRxContext tx_rx = {.tx_rx_type = FuriHalNfcTxRxTypeDefault};
     FuriHalNfcTxRxContext tx_rx = {.tx_rx_type = FuriHalNfcTxRxTypeDefault};
+
     memcpy(&tx_rx.tx_data, buffer, len);
     memcpy(&tx_rx.tx_data, buffer, len);
     tx_rx.tx_bits = len * 8;
     tx_rx.tx_bits = len * 8;
 
 
-    if(furi_hal_nfc_tx_rx_full(&tx_rx)) {
+    if(format[0] == 0x00 && format[1] == 0xC0 && format[2] == 0x00) {
+        tx_rx.tx_rx_type = FuriHalNfcTxRxTypeRxNoCrc;
+        tx_rx.tx_bits -= 16;
+    } else if(
+        (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x40) ||
+        (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x24) ||
+        (format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x44)) {
+        tx_rx.tx_rx_type = FuriHalNfcTxRxTypeRaw;
+        tx_rx.tx_bits -= 8;
+        tx_rx.tx_parity[0] = 0;
+
+        // Don't forget to swap the bits of buffer[8]
+        for(size_t i = 0; i < 8 + 1; i++) {
+            bit_lib_reverse_bits(buffer + i, 0, 8);
+        }
+
+        // Pull out parity bits
+        for(size_t i = 0; i < 8; i++) {
+            bool val = bit_lib_get_bit(buffer + i + 1, i);
+            bit_lib_set_bit(tx_rx.tx_parity, i, val);
+        }
+
+        for(size_t i = 0; i < 8; i++) {
+            buffer[i] = (buffer[i] << i) | (buffer[i + 1] >> (8 - i));
+        }
+
+        for(size_t i = 0; i < 8; i++) {
+            bit_lib_reverse_bits(buffer + i, 0, 8);
+            tx_rx.tx_data[i] = buffer[i];
+        }
+    }
+
+    if(furi_hal_nfc_tx_rx(&tx_rx, timeout)) {
         furi_delay_ms(1);
         furi_delay_ms(1);
         size_t length = tx_rx.rx_bits / 8;
         size_t length = tx_rx.rx_bits / 8;
         memset(display, 0, sizeof(display));
         memset(display, 0, sizeof(display));
         for(uint8_t i = 0; i < length; i++) {
         for(uint8_t i = 0; i < length; i++) {
             snprintf(display + (i * 2), sizeof(display), "%02x", tx_rx.rx_data[i]);
             snprintf(display + (i * 2), sizeof(display), "%02x", tx_rx.rx_data[i]);
         }
         }
-        // FURI_LOG_D(TAG, "NFC Response %d: %s", length, display);
+        FURI_LOG_D(TAG, "NFC Response %d: %s [%02x]", length, display, tx_rx.rx_parity[0]);
+
+        if(tx_rx.tx_rx_type == FuriHalNfcTxRxTypeRaw) {
+            for(size_t i = 0; i < length; i++) {
+                bit_lib_reverse_bits(tx_rx.rx_data + i, 0, 8);
+            }
+
+            uint8_t with_parity[FURI_HAL_NFC_DATA_BUFF_SIZE];
+            memset(with_parity, 0, sizeof(with_parity));
+            length = length + (length / 8) + 1;
+
+            uint8_t parts = 1 + length / 9;
+            for(size_t p = 0; p < parts; p++) {
+                uint8_t doffset = p * 9;
+                uint8_t soffset = p * 8;
+
+                for(size_t i = 0; i < 9; i++) {
+                    with_parity[i + doffset] = tx_rx.rx_data[i + soffset] >> i;
+                    if(i > 0) {
+                        with_parity[i + doffset] |= tx_rx.rx_data[i + soffset - 1] << (9 - i);
+                    }
+
+                    if(i > 0) {
+                        bool val = bit_lib_get_bit(tx_rx.rx_parity, i - 1);
+                        bit_lib_set_bit(with_parity + i, i - 1, val);
+                    }
+                }
+            }
+
+            memcpy(tx_rx.rx_data, with_parity, length);
+
+            for(size_t i = 0; i < length; i++) {
+                bit_lib_reverse_bits(tx_rx.rx_data + i, 0, 8);
+            }
+        }
+
+        memset(display, 0, sizeof(display));
+
+        for(uint8_t i = 0; i < length; i++) {
+            snprintf(display + (i * 2), sizeof(display), "%02x", tx_rx.rx_data[i]);
+        }
+        FURI_LOG_D(TAG, "NFC Response %d: %s [%02x]", length, display, tx_rx.rx_parity[0]);
+
         seader_send_nfc_rx(seader_uart, tx_rx.rx_data, length);
         seader_send_nfc_rx(seader_uart, tx_rx.rx_data, length);
     } else {
     } else {
         FURI_LOG_W(TAG, "Bad exchange");
         FURI_LOG_W(TAG, "Bad exchange");
@@ -689,14 +769,17 @@ bool seader_parse_nfc_command_transmit(SeaderWorker* seader_worker, NFCSend_t* n
         nfcSend->data.size,
         nfcSend->data.size,
         display,
         display,
         protocolName);
         protocolName);
-#else
-    UNUSED(timeOut);
 #endif
 #endif
 
 
     if(frameProtocol == FrameProtocol_iclass) {
     if(frameProtocol == FrameProtocol_iclass) {
         return seader_iso15693_transmit(seader_worker, nfcSend->data.buf, nfcSend->data.size);
         return seader_iso15693_transmit(seader_worker, nfcSend->data.buf, nfcSend->data.size);
     } else if(frameProtocol == FrameProtocol_nfc) {
     } else if(frameProtocol == FrameProtocol_nfc) {
-        return seader_iso14443a_transmit(seader_worker, nfcSend->data.buf, nfcSend->data.size);
+        return seader_iso14443a_transmit(
+            seader_worker,
+            nfcSend->data.buf,
+            nfcSend->data.size,
+            (uint16_t)timeOut,
+            nfcSend->format->buf);
     }
     }
     return false;
     return false;
 }
 }

+ 1 - 1
non_catalog_apps/ublox/README.md

@@ -1,7 +1,7 @@
 # ublox
 # ublox
 Flipper Zero app to read from a u-blox GPS over I2C. This app can
 Flipper Zero app to read from a u-blox GPS over I2C. This app can
 display data, log a path to a KML file, and sync the Flipper's time to
 display data, log a path to a KML file, and sync the Flipper's time to
-GPS time.
+GPS time. Get the app and see more info on the Flipper app hub!
 
 
 This app used to reside in my "flipped" GitHub repository, but I made
 This app used to reside in my "flipped" GitHub repository, but I made
 it much better and moved it here.
 it much better and moved it here.

+ 1 - 1
non_catalog_apps/ublox/application.fam

@@ -12,7 +12,7 @@ App(
     ],
     ],
     stack_size=2 * 1024,
     stack_size=2 * 1024,
     order=20,
     order=20,
-    fap_version=(0, 1), # major, minor
+    fap_version=(0, 2), # major, minor
     fap_description="App to display and log data from u-blox GPS modules over I2C",
     fap_description="App to display and log data from u-blox GPS modules over I2C",
     fap_author="liamur",
     fap_author="liamur",
     fap_icon="ublox_app_icon.png",
     fap_icon="ublox_app_icon.png",

+ 1 - 5
non_catalog_apps/ublox/scenes/ublox_scene_enter_file_name.c

@@ -18,7 +18,7 @@ FuriString* ublox_scene_enter_file_name_get_timename() {
     // YMD sorts better
     // YMD sorts better
     furi_string_printf(
     furi_string_printf(
         s,
         s,
-        "gps-%.4d%.2d%.2d-%.2d%.2d%.2d.kml",
+        "ublox-%.4d%.2d%.2d-%.2d%.2d%.2d.kml",
         datetime.year,
         datetime.year,
         datetime.month,
         datetime.month,
         datetime.day,
         datetime.day,
@@ -39,8 +39,6 @@ void ublox_scene_enter_file_name_on_enter(void* context) {
     FuriString* fname = ublox_scene_enter_file_name_get_timename();
     FuriString* fname = ublox_scene_enter_file_name_get_timename();
     strcpy(ublox->text_store, furi_string_get_cstr(fname));
     strcpy(ublox->text_store, furi_string_get_cstr(fname));
 
 
-    //FuriString* full_fname = furi_string_alloc_set(folder_path);
-
     ValidatorIsFile* validator_is_file =
     ValidatorIsFile* validator_is_file =
         // app path folder, app extension, current file name
         // app path folder, app extension, current file name
         validator_is_file_alloc_init(
         validator_is_file_alloc_init(
@@ -58,10 +56,8 @@ bool ublox_scene_enter_file_name_on_event(void* context, SceneManagerEvent event
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == UbloxCustomEventTextInputDone) {
         if(event.event == UbloxCustomEventTextInputDone) {
-            //FuriString* fullname;
             FURI_LOG_I(TAG, "text: %s", ublox->text_store);
             FURI_LOG_I(TAG, "text: %s", ublox->text_store);
             ublox->log_state = UbloxLogStateStartLogging;
             ublox->log_state = UbloxLogStateStartLogging;
-            //scene_manager_next_scene(ublox->scene_manager, UbloxSceneDataDisplay);
             // don't add data_display as the next scene, instead go back to the last scene
             // don't add data_display as the next scene, instead go back to the last scene
             scene_manager_previous_scene(ublox->scene_manager);
             scene_manager_previous_scene(ublox->scene_manager);
             consumed = true;
             consumed = true;

BIN
non_catalog_apps/ublox/screenshots/data_display_handheld.png