Explorar o código

execute scripts from menu
add message dialogs
add swd_idle_bits parameter

g3gg0 %!s(int64=2) %!d(string=hai) anos
pai
achega
431978bddd
Modificáronse 2 ficheiros con 198 adicións e 50 borrados
  1. 195 50
      swd_probe_app.c
  2. 3 0
      swd_probe_app.h

+ 195 - 50
swd_probe_app.c

@@ -17,6 +17,7 @@
 
 static void render_callback(Canvas* const canvas, void* cb_ctx);
 static bool swd_message_process(AppFSM* ctx);
+static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data);
 
 static const GpioPin* gpios[] = {
     &gpio_ext_pc0,
@@ -198,7 +199,9 @@ static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23,
     swd_set_data(ctx, false);
     swd_configure_pins(ctx, true);
 
-    swd_write_byte(ctx, 0, 8);
+    uint32_t idle = 0;
+    swd_write(ctx, (uint8_t*)&idle, ctx->swd_idle_bits);
+
     uint8_t request[] = {0};
 
     request[0] |= 0x01; /* start bit*/
@@ -269,6 +272,7 @@ static void swd_line_reset(AppFSM* const ctx) {
         swd_write_byte(ctx, 0xFF, 8);
     }
     swd_write_byte(ctx, 0, 8);
+    ctx->dp_regs.select_ok = false;
 }
 
 static void swd_abort(AppFSM* const ctx) {
@@ -280,6 +284,19 @@ static void swd_abort(AppFSM* const ctx) {
     uint32_t abort = 0x0E;
     swd_transfer(ctx, false, true, 0, &abort);
 }
+/*
+static uint8_t swd_transferxx(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data) {
+    uint8_t ret = 0;
+    for(int tries = 0; tries < 3; tries++) {
+        ret = swd_transfer(ctx, ap, write, a23, data);
+        if(ret == 1) {
+            return ret;
+        }
+        furi_log_print_format(FuriLogLevelDefault, TAG, "swd_transfer: failed: %d/3", tries);
+        swd_abort(ctx);
+    }
+    return 9;
+}*/
 
 static void swd_abort_simple(AppFSM* const ctx) {
     uint32_t abort = 0x0E;
@@ -294,10 +311,18 @@ static void swd_abort_simple(AppFSM* const ctx) {
 static uint8_t swd_select(AppFSM* const ctx, uint8_t ap_sel, uint8_t ap_bank, uint8_t dp_bank) {
     uint32_t bank_reg = (ap_sel << 24) | ((ap_bank & 0x0F) << 4) | (dp_bank & 0x0F);
 
+    if(ctx->dp_regs.select_ok && bank_reg == ctx->dp_regs.select) {
+        return 1;
+    }
+
     uint8_t ret = swd_transfer(ctx, false, true, 2, &bank_reg);
     if(ret != 1) {
+        ctx->dp_regs.select_ok = false;
         furi_log_print_format(FuriLogLevelDefault, TAG, "swd_select: failed: %d", ret);
     }
+
+    ctx->dp_regs.select = bank_reg;
+    ctx->dp_regs.select_ok = true;
     return ret;
 }
 
@@ -317,8 +342,6 @@ static uint8_t
         furi_log_print_format(FuriLogLevelDefault, TAG, "swd_read_dpbank: failed: %d", ret);
         return ret;
     }
-    /* reset bank to zero again */
-    ret = swd_select(ctx, 0, 0, 0);
     return ret;
 }
 
@@ -408,7 +431,9 @@ static uint8_t swd_read_memory_block(
     ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data);
 
     for(size_t pos = 0; pos < len; pos += 4) {
+        data = 0xDEADBEEF;
         ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data);
+        furi_log_print_format(FuriLogLevelDefault, TAG, "##read %lX", data);
 
         memcpy(&buf[pos], &data, 4);
 
@@ -735,6 +760,9 @@ static bool swd_scriptfunc_beep(ScriptContext* ctx) {
 static bool swd_scriptfunc_message(ScriptContext* ctx) {
     uint32_t wait_time = 0;
     char message[256];
+    char type[256];
+    bool success = true;
+    bool show_dialog = false;
 
     if(!swd_script_skip_whitespace(ctx)) {
         furi_log_print_format(FuriLogLevelDefault, TAG, "message: missing whitespace");
@@ -751,10 +779,50 @@ static bool swd_scriptfunc_message(ScriptContext* ctx) {
         return false;
     }
 
+    if(swd_script_get_string(ctx, type, sizeof(type))) {
+        if(!strcmp(type, "dialog")) {
+            show_dialog = true;
+        }
+    }
+
     if(wait_time <= 60 * 1000) {
         strcpy(ctx->app->state_string, message);
         swd_script_gui_refresh(ctx);
         furi_delay_ms(wait_time);
+        if(show_dialog) {
+            DialogMessage* message = dialog_message_alloc();
+            dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop);
+            dialog_message_set_icon(message, &I_app, 3, 2);
+            dialog_message_set_text(message, ctx->app->state_string, 3, 16, AlignLeft, AlignTop);
+            dialog_message_set_buttons(message, "Abort", "Ok", NULL);
+            success = dialog_message_show(ctx->app->dialogs, message) == DialogMessageButtonCenter;
+            dialog_message_free(message);
+        }
+    }
+
+    swd_script_seek_newline(ctx);
+
+    return success;
+}
+
+static bool swd_scriptfunc_swd_idle_bits(ScriptContext* ctx) {
+    uint32_t swd_idle_bits = 0;
+
+    if(!swd_script_skip_whitespace(ctx)) {
+        furi_log_print_format(FuriLogLevelDefault, TAG, "swd_idle_bits: missing whitespace");
+        return false;
+    }
+
+    if(!swd_script_get_number(ctx, &swd_idle_bits)) {
+        furi_log_print_format(FuriLogLevelDefault, TAG, "swd_idle_bits: failed to parse");
+        return false;
+    }
+
+    if(swd_idle_bits <= 32) {
+        ctx->app->swd_idle_bits = swd_idle_bits;
+    } else {
+        furi_log_print_format(
+            FuriLogLevelDefault, TAG, "swd_idle_bits: value must be between 1 and 32");
     }
 
     swd_script_seek_newline(ctx);
@@ -965,8 +1033,15 @@ static bool swd_scriptfunc_mem_dump(ScriptContext* ctx) {
                 furi_log_print_format(FuriLogLevelDefault, TAG, "mem_dump: aborting read");
                 break;
             }
-            uint32_t ret = swd_read_memory_block(
-                ctx->app, ctx->selected_ap, address + pos, buffer, ctx->block_size);
+            uint32_t ret = 0;
+
+            if(ctx->block_size > 4) {
+                ret = swd_read_memory_block(
+                    ctx->app, ctx->selected_ap, address + pos, buffer, ctx->block_size);
+            } else {
+                ret = swd_read_memory(
+                    ctx->app, ctx->selected_ap, address + pos, (uint8_t*)(void*)buffer);
+            }
             read_ok = (ret == 1);
 
             if(!read_ok) {
@@ -1144,6 +1219,7 @@ static const ScriptFunctionInfo script_funcs[] = {
     {"apselect", &swd_scriptfunc_apselect},
     {"max_tries", &swd_scriptfunc_maxtries},
     {"swd_clock_delay", &swd_scriptfunc_swd_clock_delay},
+    {"swd_idle_bits", &swd_scriptfunc_swd_idle_bits},
     {"block_size", &swd_scriptfunc_blocksize},
     {"abort", &swd_scriptfunc_abort},
     {"mem_dump", &swd_scriptfunc_mem_dump},
@@ -1196,7 +1272,20 @@ static bool swd_execute_script_line(ScriptContext* const ctx, File* file) {
         swd_script_gui_refresh(ctx);
 
         /* func function, execute */
-        return script_funcs[entry].func(ctx);
+        bool success = script_funcs[entry].func(ctx);
+
+        if(!success) {
+            furi_log_print_format(
+                FuriLogLevelDefault, TAG, "Command failed: %s", script_funcs[entry].prefix);
+            snprintf(
+                ctx->app->state_string,
+                sizeof(ctx->app->state_string),
+                "Command failed: %s",
+                script_funcs[entry].prefix);
+            return false;
+        }
+
+        return true;
     }
     furi_log_print_format(FuriLogLevelDefault, TAG, "unknown command");
 
@@ -1205,57 +1294,76 @@ static bool swd_execute_script_line(ScriptContext* const ctx, File* file) {
 
 static bool swd_execute_script(AppFSM* const ctx, const char* filename) {
     bool success = true;
+    bool restart = false;
 
-    ctx->script = malloc(sizeof(ScriptContext));
-
-    ctx->script->app = ctx;
-    ctx->script->max_tries = 1;
+    do {
+        success = true;
+        restart = false;
+        ctx->script = malloc(sizeof(ScriptContext));
 
-    if(!storage_file_exists(ctx->storage, filename)) {
-        furi_log_print_format(FuriLogLevelDefault, TAG, "Does not exist '%s'", filename);
-        free(ctx->script);
-        ctx->script = NULL;
-        return false;
-    }
+        ctx->script->app = ctx;
+        ctx->script->max_tries = 1;
 
-    /* first allocate a file object */
-    ctx->script->script_file = storage_file_alloc(ctx->storage);
+        if(!storage_file_exists(ctx->storage, filename)) {
+            furi_log_print_format(FuriLogLevelDefault, TAG, "Does not exist '%s'", filename);
+            free(ctx->script);
+            ctx->script = NULL;
+            return false;
+        }
 
-    /* then get our script opened */
-    if(!storage_file_open(ctx->script->script_file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) {
-        FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(ctx->script->script_file));
-        furi_log_print_format(FuriLogLevelDefault, TAG, "Failed to open '%s'", filename);
-        storage_file_free(ctx->script->script_file);
-        free(ctx->script);
-        ctx->script = NULL;
-        return false;
-    }
+        /* first allocate a file object */
+        ctx->script->script_file = storage_file_alloc(ctx->storage);
 
-    uint32_t line = 1;
-    while(line < SCRIPT_MAX_LINES) {
-        if(ctx->script->abort) {
-            furi_log_print_format(FuriLogLevelDefault, TAG, "Abort requested");
-            break;
-        }
-        if(storage_file_eof(ctx->script->script_file)) {
-            break;
+        /* then get our script opened */
+        if(!storage_file_open(ctx->script->script_file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) {
+            FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(ctx->script->script_file));
+            furi_log_print_format(FuriLogLevelDefault, TAG, "Failed to open '%s'", filename);
+            storage_file_free(ctx->script->script_file);
+            free(ctx->script);
+            ctx->script = NULL;
+            return false;
         }
-        furi_log_print_format(FuriLogLevelDefault, TAG, "line %lu", line);
-        if(!swd_execute_script_line(ctx->script, ctx->script->script_file)) {
-            furi_log_print_format(FuriLogLevelDefault, TAG, "Failed to execute line %lu", line);
-            success = false;
-            break;
+
+        uint32_t line = 1;
+        while(line < SCRIPT_MAX_LINES) {
+            if(ctx->script->abort) {
+                furi_log_print_format(FuriLogLevelDefault, TAG, "Abort requested");
+                break;
+            }
+            if(storage_file_eof(ctx->script->script_file)) {
+                break;
+            }
+            furi_log_print_format(FuriLogLevelDefault, TAG, "line %lu", line);
+            if(!swd_execute_script_line(ctx->script, ctx->script->script_file)) {
+                success = false;
+                break;
+            }
+            line++;
         }
-        line++;
-    }
 
-    furi_log_print_format(FuriLogLevelDefault, TAG, "Finished");
+        furi_log_print_format(FuriLogLevelDefault, TAG, "Finished");
 
-    storage_file_close(ctx->script->script_file);
-    storage_file_free(ctx->script->script_file);
-    free(ctx->script);
+        storage_file_close(ctx->script->script_file);
+        storage_file_free(ctx->script->script_file);
+        free(ctx->script);
 
-    ctx->script = NULL;
+        ctx->script = NULL;
+
+        if(!success) {
+            char text_buf[128];
+
+            snprintf(text_buf, sizeof(text_buf), "Line %lu failed:\n%s", line, ctx->state_string);
+            DialogMessage* message = dialog_message_alloc();
+            dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop);
+            dialog_message_set_icon(message, &I_app, 3, 2);
+            dialog_message_set_text(message, text_buf, 3, 16, AlignLeft, AlignTop);
+            dialog_message_set_buttons(message, "Back", "Retry", NULL);
+            if(dialog_message_show(ctx->dialogs, message) == DialogMessageButtonCenter) {
+                restart = true;
+            }
+            dialog_message_free(message);
+        }
+    } while(restart);
 
     return success;
 }
@@ -1320,6 +1428,7 @@ static void render_callback(Canvas* const canvas, void* cb_ctx) {
             y += 10;
 
             canvas_set_font(canvas, FontSecondary);
+            elements_button_left(canvas, "Script");
             elements_button_right(canvas, "DP Regs");
 
             break;
@@ -1552,6 +1661,7 @@ static void render_callback(Canvas* const canvas, void* cb_ctx) {
             canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Down to select");
             y += 10;
         }
+        elements_button_left(canvas, "Script");
     }
 
     release_mutex((ValueMutex*)cb_ctx, ctx);
@@ -1583,6 +1693,8 @@ static void app_init(AppFSM* const app) {
     app->io_swd = 0xFF;
     app->io_swc = 0xFF;
     app->hex_addr = 0x40002800;
+    app->swd_clock_delay = CLOCK_DELAY;
+    app->swd_idle_bits = IDLE_BITS;
 
     strcpy(app->state_string, "none");
     strcpy(app->script_detected, "");
@@ -1634,26 +1746,33 @@ static void on_timer_tick(AppFSM* ctx) {
             ctx->dpidr_info.designer = (ctx->dp_regs.dpidr >> 1) & 0x3FF;
 
             if(!has_multiple_bits(ctx->io_swc)) {
+                furi_log_print_format(FuriLogLevelDebug, TAG, " - Detected pins");
+                furi_log_print_format(FuriLogLevelDebug, TAG, " - Resetting error");
                 /* reset error */
                 uint8_t ack = swd_transfer(ctx, false, false, 1, &ctx->dp_regs.ctrlstat);
                 furi_log_print_format(
-                    FuriLogLevelDefault, TAG, "stat %02lX %d", ctx->dp_regs.ctrlstat, ack);
+                    FuriLogLevelDebug, TAG, "stat %02lX %d", ctx->dp_regs.ctrlstat, ack);
 
                 if(ack != 1 || (ctx->dp_regs.ctrlstat & STAT_ERROR_FLAGS)) {
-                    furi_log_print_format(FuriLogLevelDefault, TAG, "send ABORT");
+                    furi_log_print_format(FuriLogLevelDebug, TAG, "send ABORT");
                     swd_abort(ctx);
                 }
+                furi_log_print_format(FuriLogLevelDebug, TAG, " - Fetch CTRL/STAT");
                 ctx->dp_regs.ctrlstat_ok = swd_read_dpbank(ctx, 1, 0, &ctx->dp_regs.ctrlstat) == 1;
 
                 if(ctx->dpidr_info.version >= 1) {
+                    furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv1, read DLCR");
                     ctx->dp_regs.dlcr_ok = swd_read_dpbank(ctx, 1, 1, &ctx->dp_regs.dlcr) == 1;
                 }
 
                 if(ctx->dpidr_info.version >= 2) {
+                    furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv2, read TARGETID");
                     ctx->dp_regs.targetid_ok =
                         swd_read_dpbank(ctx, 1, 2, &ctx->dp_regs.targetid) == 1;
+                    furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv2, read EVENTSTAT");
                     ctx->dp_regs.eventstat_ok =
                         swd_read_dpbank(ctx, 1, 4, &ctx->dp_regs.eventstat) == 1;
+                    furi_log_print_format(FuriLogLevelDebug, TAG, " - DAPv2, read DLPIDR");
                     ctx->dp_regs.dlpidr_ok = swd_read_dpbank(ctx, 1, 3, &ctx->dp_regs.dlpidr) == 1;
                 }
 
@@ -1665,7 +1784,7 @@ static void on_timer_tick(AppFSM* ctx) {
 
                 if(!ctx->script_detected_executed && strlen(ctx->script_detected) > 0) {
                     furi_log_print_format(
-                        FuriLogLevelDefault, TAG, "Run detected script '%s'", ctx->script_detected);
+                        FuriLogLevelDefault, TAG, " - Run script '%s'", ctx->script_detected);
 
                     ctx->script_detected_executed = true;
 
@@ -1674,6 +1793,10 @@ static void on_timer_tick(AppFSM* ctx) {
                     ctx->mode_page = ModePageScan;
                 }
             }
+        } else {
+            if(!has_multiple_bits(ctx->io_swc)) {
+                furi_log_print_format(FuriLogLevelDebug, TAG, " - Lost device");
+            }
         }
 
         ctx->current_mask_id = (ctx->current_mask_id + 1) % COUNT(gpio_direction_mask);
@@ -1819,6 +1942,26 @@ static bool swd_message_process(AppFSM* ctx) {
                         if(ctx->hex_select < 7) {
                             ctx->hex_select++;
                         }
+                    } else if(ctx->mode_page == ModePageScan) {
+                        FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd"));
+                        FuriString* preselected = furi_string_alloc_printf(
+                            (strlen(ctx->script_detected) > 0) ? ctx->script_detected :
+                                                                 ANY_PATH("swd"));
+                        DialogsFileBrowserOptions options;
+
+                        dialog_file_browser_set_basic_options(&options, "swd", &I_swd);
+
+                        if(dialog_file_browser_show(
+                               ctx->dialogs, result_path, preselected, &options)) {
+                            const char* path = furi_string_get_cstr(result_path);
+                            ctx->mode_page = ModePageScript;
+                            swd_execute_script(ctx, path);
+                            ctx->mode_page = ModePageScan;
+                        }
+
+                        furi_string_free(result_path);
+                        furi_string_free(preselected);
+                        break;
                     } else {
                         if(ctx->mode_page > 0) {
                             ctx->mode_page--;
@@ -1886,6 +2029,8 @@ int32_t swd_probe_app_main(void* p) {
 
     notification_message_block(app->notification, &sequence_display_backlight_enforce_on);
 
+    swd_execute_script(app, ANY_PATH("swd/startup.swd"));
+
     DOLPHIN_DEED(DolphinDeedPluginGameStart);
 
     furi_timer_start(app->timer, furi_kernel_get_tick_frequency() / TIMER_HZ);

+ 3 - 0
swd_probe_app.h

@@ -23,6 +23,8 @@
 #define TIMER_HZ 50
 #define TIMEOUT 3
 #define QUEUE_SIZE 32
+#define IDLE_BITS 8
+#define CLOCK_DELAY 0
 
 #define MAX_FILE_LENGTH 128
 #define SCRIPT_MAX_LINES 1000
@@ -132,6 +134,7 @@ typedef struct {
     uint8_t io_num_swd;
     uint32_t detected_timeout;
     uint32_t swd_clock_delay;
+    uint32_t swd_idle_bits;
     bool detected;
     bool detected_device;
     bool detected_notified;