From 653763a3916cf5105b9f665b497f3c15c92f6694 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 17:37:19 -0700 Subject: [PATCH 01/11] use inference for home_to_date_time --- .../DevPrograms/TestProgramSwitch.cpp | 13 +- .../Programs/NintendoSwitch_Navigation.cpp | 235 ++++++++++++++++++ .../Programs/NintendoSwitch_Navigation.h | 12 + 3 files changed, 259 insertions(+), 1 deletion(-) diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index aae7103704..8d3be498f9 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -122,7 +122,7 @@ #include "PokemonSwSh/MaxLair/Inference/PokemonSwSh_MaxLair_Detect_PokemonSwapMenu.h" #include "CommonTools/Images/ImageFilter.h" #include "NintendoSwitch/Options/NintendoSwitch_ModelType.h" - +#include "NintendoSwitch/Programs/NintendoSwitch_Navigation.h" #include #include @@ -316,11 +316,22 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& ProControllerContext context(scope, console.pro_controller()); VideoOverlaySet overlays(overlay); + +#if 1 + ImageFloatBox box(0.060, 0.75, 0.02, 0.08); + ImageFloatBox system_settings(0.685, 0.69, 0.05, 0.03); + ImageFloatBox other_setting1(0.615, 0.69, 0.05, 0.03); + ImageFloatBox other_setting2(0.545, 0.69, 0.05, 0.03); + cout << is_setting_selected(console, context, system_settings, other_setting1, other_setting2) << endl; +#endif + +#if 0 // std::terminate(); ImageRGB32 image("20250503-121259857603.png"); image = filter_rgb32_brightness(image, COLOR_RED, false, 0x00ffff01, 0, 200); image.save("temp.png"); +#endif #if 0 diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 23dbb39dc8..7c76035511 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -7,12 +7,247 @@ #include "Controllers/ControllerTypes.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" +#include "CommonFramework/ImageTools/ImageStats.h" +#include "CommonFramework/VideoPipeline/VideoFeed.h" +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" #include "NintendoSwitch_Navigation.h" +#include + namespace PokemonAutomation{ namespace NintendoSwitch{ +bool is_white_theme(VideoStream& stream, ProControllerContext& context){ + context.wait_for_all_requests(); + VideoSnapshot snapshot = stream.video().snapshot(); + ImageFloatBox window_top(0.60, 0.02, 0.35, 0.05); + ImageStats stats_window_top = image_stats(extract_box_reference(snapshot, window_top)); + bool white_theme = stats_window_top.average.sum() > 600; + return white_theme; +} + +bool is_setting_selected(VideoStream& stream, ProControllerContext& context, ImageFloatBox selected_box, ImageFloatBox unselected_box1, ImageFloatBox unselected_box2){ + VideoOverlaySet overlays(stream.overlay()); + overlays.add(COLOR_RED, selected_box); + overlays.add(COLOR_BLUE, unselected_box1); + overlays.add(COLOR_BLUE, unselected_box2); + context.wait_for(Milliseconds(100)); + context.wait_for_all_requests(); + VideoSnapshot snapshot = stream.video().snapshot(); + + ImageStats stats_unselected_box1 = image_stats(extract_box_reference(snapshot, unselected_box1)); + double unselected1_average_sum = stats_unselected_box1.average.sum(); + stream.log("unselected_average_sum1: " + std::to_string(unselected1_average_sum)); + + ImageStats stats_unselected_box2 = image_stats(extract_box_reference(snapshot, unselected_box2)); + double unselected2_average_sum = stats_unselected_box2.average.sum(); + stream.log("unselected_average_sum2: " + std::to_string(unselected2_average_sum)); + + double average_sum_unselected_diff = std::abs(unselected1_average_sum - unselected2_average_sum); + + ImageStats stats_selected_box = image_stats(extract_box_reference(snapshot, selected_box)); + double selected_average_sum = stats_selected_box.average.sum(); + stream.log("selected_average_sum: " + std::to_string(selected_average_sum)); + + if (is_white_theme(stream, context)){ // light mode + // unselected should be brighter than selected + return selected_average_sum < std::min(unselected1_average_sum, unselected2_average_sum) - average_sum_unselected_diff - 20 ; + }else{ // dark mode + // selected should be brighter than unselected + return selected_average_sum > std::max(unselected1_average_sum, unselected2_average_sum) + average_sum_unselected_diff + 20; + } +} + +void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast){ + switch (context->performance_class()){ + case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); + + // Down twice in case we drop one. + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 4); + + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); + + + + // Two A presses in case we drop the 1st one. + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + + // Just button mash it. lol + { + auto iterations = Milliseconds(1200) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + }while (--iterations); + } + + // Scroll left and press A to exit the sleep menu if we happened to + // land there. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 3); + ssf_press_button(context, BUTTON_A, 3); + + { + auto iterations = Milliseconds(312) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 24ms); + }while (--iterations); + } + + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 10); + ssf_press_dpad(context, DPAD_DOWN, 45, 40); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + + if (!to_date_change){ + // Triple up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 45); + return; + } + + // Triple up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + { + auto iterations = Milliseconds(250) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + }while (--iterations); + } +// ssf_issue_scroll(context, SSF_SCROLL_DOWN, 0); + + // Left scroll in case we missed landed in the language change or sleep + // confirmation menus. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms); + + break; + } + case ControllerPerformanceClass::SerialPABotBase_Wireless_ESP32:{ + Milliseconds tv = context->timing_variation(); + Milliseconds unit = 24ms + tv; + + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + + // Down twice in case we drop one. + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); + + // Press A multiple times to make sure one goes through. + pbf_press_button(context, BUTTON_A, 2*unit, unit); + pbf_press_button(context, BUTTON_A, 2*unit, unit); + pbf_press_button(context, BUTTON_A, 2*unit, unit); + + // Just button mash it. lol + { + auto iterations = Milliseconds(1100) / unit + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + }while (--iterations); + } + + // Scroll left and press A to exit the sleep menu if we happened to + // land there. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, unit); + ssf_press_button(context, BUTTON_A, unit, 2*unit, unit); + + { + auto iterations = Milliseconds(312) / unit + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + }while (--iterations); + } + + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 400ms, 2*unit, unit); + ssf_press_dpad(context, DPAD_DOWN, 360ms, 304ms); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + + if (!to_date_change){ + // Triple up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, unit); + ssf_press_button(context, BUTTON_A, unit); + ssf_press_button(context, BUTTON_A, 360ms, 2*unit, unit); + return; + } + + // Triple up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, unit); + ssf_press_button(context, BUTTON_A, unit); + ssf_press_button(context, BUTTON_A, unit); + { + auto iterations = Milliseconds(250) / unit + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + }while (--iterations); + } + + // Left scroll in case we missed landed in the language change or sleep + // confirmation menus. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); + + break; + } + default:{ + // Slow version for tick-imprecise controllers. + + Milliseconds tv = context->timing_variation(); +// ssf_do_nothing(context, 1500ms); + + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); + + // Down twice in case we drop one. + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); +// ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + + ssf_issue_scroll_ptv(context, SSF_SCROLL_LEFT); + + // Press A multiple times to make sure one goes through. + ssf_mash1_button(context, BUTTON_A, 200ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN, 2500ms, 2500ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT, 500ms, 500ms); + + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 500ms, tv, tv); + ssf_press_right_joystick(context, 128, 224, 1000ms, 300ms, tv); +// ssf_issue_scroll(context, SSF_SCROLL_DOWN, 1000ms, 250ms, tv); // Scroll down + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + + if (!to_date_change){ + ssf_press_button_ptv(context, BUTTON_A); + return; + } + + ssf_press_button_ptv(context, BUTTON_A, 1000ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + } + } + + + +} + + + void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast){ switch (context->performance_class()){ diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h index fa3518c7ab..8901457056 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h @@ -7,14 +7,26 @@ #ifndef PokemonAutomation_NintendoSwitch_Navigation_H #define PokemonAutomation_NintendoSwitch_Navigation_H +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include "CommonFramework/Tools/VideoStream.h" #include "NintendoSwitch/Controllers/NintendoSwitch_ProController.h" #include "NintendoSwitch/Controllers/NintendoSwitch_Joycon.h" namespace PokemonAutomation{ namespace NintendoSwitch{ +// return true if the Switch Settings uses White theme +// assumes we are currently in the Switch Settings. +bool is_white_theme(VideoStream& stream, ProControllerContext& context); +// return true if the area within the selected_box is highlighted, compared with the area within unselected_box +// This compares the brightness of the selected_box with the unselected_box. +// selected_box: the box where we expect the screen should be highlighted +// unselected_box 1 and 2: the boxes where we expect the screen should NOT be highlighted. These acts as the control, for comparison. +// the average sum of selected_box should be greater than the absolute difference of average sum between unselected_box 1 and 2. +bool is_setting_selected(VideoStream& stream, ProControllerContext& context, ImageFloatBox selected_box, ImageFloatBox unselected_box1, ImageFloatBox unselected_box2); +void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast); void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast); //Joycon must not be sideways From 04c59f337a7df2dfeb0299c404d58a45f96ea458 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 19:34:20 -0700 Subject: [PATCH 02/11] more udpates to home_to_date_time --- .../DevPrograms/TestProgramSwitch.cpp | 6 +- .../Programs/NintendoSwitch_Navigation.cpp | 74 +++++++++++++++++-- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index 8d3be498f9..af08666dbf 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -318,11 +318,7 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& #if 1 - ImageFloatBox box(0.060, 0.75, 0.02, 0.08); - ImageFloatBox system_settings(0.685, 0.69, 0.05, 0.03); - ImageFloatBox other_setting1(0.615, 0.69, 0.05, 0.03); - ImageFloatBox other_setting2(0.545, 0.69, 0.05, 0.03); - cout << is_setting_selected(console, context, system_settings, other_setting1, other_setting2) << endl; + home_to_date_time(console, context, true, false); #endif #if 0 diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 7c76035511..8a3cb89918 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -5,6 +5,7 @@ */ #include "Controllers/ControllerTypes.h" +#include "CommonFramework/Exceptions/OperationFailedException.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" #include "CommonFramework/ImageTools/ImageStats.h" @@ -32,8 +33,8 @@ bool is_setting_selected(VideoStream& stream, ProControllerContext& context, Ima overlays.add(COLOR_RED, selected_box); overlays.add(COLOR_BLUE, unselected_box1); overlays.add(COLOR_BLUE, unselected_box2); - context.wait_for(Milliseconds(100)); context.wait_for_all_requests(); + context.wait_for(Milliseconds(250)); VideoSnapshot snapshot = stream.video().snapshot(); ImageStats stats_unselected_box1 = image_stats(extract_box_reference(snapshot, unselected_box1)); @@ -72,7 +73,31 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); + // we expect to be at Settings icon + ImageFloatBox system_settings(0.685, 0.69, 0.05, 0.03); + ImageFloatBox other_setting1(0.615, 0.69, 0.05, 0.03); + ImageFloatBox other_setting2(0.545, 0.69, 0.05, 0.03); + if (!is_setting_selected(stream, context, system_settings, other_setting1, other_setting2)){ + // not at Settings Icon + // mash down, mash right. then left one + size_t iterations = Milliseconds(1200) / 24ms + 1; + for (size_t i = 0; i < iterations; i++){ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + } + for (size_t i = 0; i < iterations; i++){ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 24ms); + } + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); + + if (!is_setting_selected(stream, context, system_settings, other_setting1, other_setting2)){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "home_to_date_time(): Failed to reach settings gear on Home page after 2 attempts.", + stream + ); + } + } // Two A presses in case we drop the 1st one. ssf_press_button(context, BUTTON_A, 3); @@ -105,18 +130,51 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - if (!to_date_change){ - // Triple up this A press to make sure it gets through. + + // double up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + + context.wait_for_all_requests(); + // we expect to be within "Date and Time", with "Synchronize Clock via Internet" being highlighted + ImageFloatBox sync_clock(0.168, 0.185, 0.01, 0.1); + ImageFloatBox other_setting3(0.1, 0.185, 0.01, 0.1); + ImageFloatBox other_setting4(0.05, 0.185, 0.01, 0.1); + if (!is_setting_selected(stream, context, sync_clock, other_setting3, other_setting4)){ + // press B once, then mash Up. then try again to scroll down to Date and Time + pbf_press_button(context, BUTTON_B, 100ms, 100ms); + pbf_move_left_joystick(context, 128, 0, 3000ms, 100ms); + + size_t iterations = Milliseconds(1200) / 24ms + 1; + for (size_t i = 0; i < iterations; i++){ + ssf_issue_scroll(context, SSF_SCROLL_UP, 24ms); + } + + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 10); + ssf_press_dpad(context, DPAD_DOWN, 45, 40); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + + // double up this A press to make sure it gets through. ssf_press_button(context, BUTTON_A, 3); ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 45); + + if (!is_setting_selected(stream, context, sync_clock, other_setting3, other_setting4)){ + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "home_to_date_time(): Failed to reach settings gear on Home page after 2 attempts.", + stream + ); + } + + } + + if (!to_date_change){ return; } - // Triple up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 3); { auto iterations = Milliseconds(250) / 24ms + 1; do{ From 2e5d8ab4d13d19c6a6f78b99dd3ed2c8a3926441 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 19:55:02 -0700 Subject: [PATCH 03/11] more changes --- .../Programs/NintendoSwitch_Navigation.cpp | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 8a3cb89918..00f16895f0 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -35,29 +35,40 @@ bool is_setting_selected(VideoStream& stream, ProControllerContext& context, Ima overlays.add(COLOR_BLUE, unselected_box2); context.wait_for_all_requests(); context.wait_for(Milliseconds(250)); - VideoSnapshot snapshot = stream.video().snapshot(); - - ImageStats stats_unselected_box1 = image_stats(extract_box_reference(snapshot, unselected_box1)); - double unselected1_average_sum = stats_unselected_box1.average.sum(); - stream.log("unselected_average_sum1: " + std::to_string(unselected1_average_sum)); - - ImageStats stats_unselected_box2 = image_stats(extract_box_reference(snapshot, unselected_box2)); - double unselected2_average_sum = stats_unselected_box2.average.sum(); - stream.log("unselected_average_sum2: " + std::to_string(unselected2_average_sum)); - - double average_sum_unselected_diff = std::abs(unselected1_average_sum - unselected2_average_sum); - - ImageStats stats_selected_box = image_stats(extract_box_reference(snapshot, selected_box)); - double selected_average_sum = stats_selected_box.average.sum(); - stream.log("selected_average_sum: " + std::to_string(selected_average_sum)); + size_t max_attempts = 5; // multiple attempts because the highlighted icon/setting pulses. and sometimes there isn't enough contrast at the exact moment you take the snapshot. + bool is_selected = false; + for (size_t i = 0; i < max_attempts; i++){ + VideoSnapshot snapshot = stream.video().snapshot(); + + ImageStats stats_unselected_box1 = image_stats(extract_box_reference(snapshot, unselected_box1)); + double unselected1_average_sum = stats_unselected_box1.average.sum(); + stream.log("unselected_average_sum1: " + std::to_string(unselected1_average_sum)); + + ImageStats stats_unselected_box2 = image_stats(extract_box_reference(snapshot, unselected_box2)); + double unselected2_average_sum = stats_unselected_box2.average.sum(); + stream.log("unselected_average_sum2: " + std::to_string(unselected2_average_sum)); + + double average_sum_unselected_diff = std::abs(unselected1_average_sum - unselected2_average_sum); + + ImageStats stats_selected_box = image_stats(extract_box_reference(snapshot, selected_box)); + double selected_average_sum = stats_selected_box.average.sum(); + stream.log("selected_average_sum: " + std::to_string(selected_average_sum)); + + if (is_white_theme(stream, context)){ // light mode + // unselected should be brighter than selected + is_selected = selected_average_sum < std::min(unselected1_average_sum, unselected2_average_sum) - average_sum_unselected_diff - 20 ; + }else{ // dark mode + // selected should be brighter than unselected + is_selected = selected_average_sum > std::max(unselected1_average_sum, unselected2_average_sum) + average_sum_unselected_diff + 20; + } - if (is_white_theme(stream, context)){ // light mode - // unselected should be brighter than selected - return selected_average_sum < std::min(unselected1_average_sum, unselected2_average_sum) - average_sum_unselected_diff - 20 ; - }else{ // dark mode - // selected should be brighter than unselected - return selected_average_sum > std::max(unselected1_average_sum, unselected2_average_sum) + average_sum_unselected_diff + 20; + if(is_selected){ + return true; + } + context.wait_for(Milliseconds(200)); } + + return false; } void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast){ From a499c7615f49082bd82ef6d076a85c70b571f874 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 20:07:17 -0700 Subject: [PATCH 04/11] more updates --- .../NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 00f16895f0..8be0ae98d4 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -35,7 +35,7 @@ bool is_setting_selected(VideoStream& stream, ProControllerContext& context, Ima overlays.add(COLOR_BLUE, unselected_box2); context.wait_for_all_requests(); context.wait_for(Milliseconds(250)); - size_t max_attempts = 5; // multiple attempts because the highlighted icon/setting pulses. and sometimes there isn't enough contrast at the exact moment you take the snapshot. + size_t max_attempts = 10; // multiple attempts because the highlighted icon/setting pulses. and sometimes there isn't enough contrast at the exact moment you take the snapshot. bool is_selected = false; for (size_t i = 0; i < max_attempts; i++){ VideoSnapshot snapshot = stream.video().snapshot(); @@ -65,7 +65,7 @@ bool is_setting_selected(VideoStream& stream, ProControllerContext& context, Ima if(is_selected){ return true; } - context.wait_for(Milliseconds(200)); + context.wait_for(Milliseconds(100)); } return false; @@ -175,7 +175,7 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool if (!is_setting_selected(stream, context, sync_clock, other_setting3, other_setting4)){ OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, - "home_to_date_time(): Failed to reach settings gear on Home page after 2 attempts.", + "home_to_date_time(): Failed to reach 'Synchronize Clock via Internet', within 'Date and Time', after 2 attempts.", stream ); } From 2593bbb74cf7a2016476da7607affc7def05f442 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 22:56:24 -0700 Subject: [PATCH 05/11] create SelectedSettingWatcher --- SerialPrograms/CMakeLists.txt | 2 + ...NintendoSwitch_SelectedSettingDetector.cpp | 74 +++++++++++++ .../NintendoSwitch_SelectedSettingDetector.h | 44 ++++++++ .../Programs/NintendoSwitch_Navigation.cpp | 104 ++++++++---------- .../Programs/NintendoSwitch_Navigation.h | 6 +- 5 files changed, 167 insertions(+), 63 deletions(-) create mode 100644 SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp create mode 100644 SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index ffce29f085..a6c3894d93 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -957,6 +957,8 @@ file(GLOB MAIN_SOURCES Source/NintendoSwitch/Inference/NintendoSwitch_DateReader.h Source/NintendoSwitch/Inference/NintendoSwitch_DetectHome.cpp Source/NintendoSwitch/Inference/NintendoSwitch_DetectHome.h + Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp + Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h Source/NintendoSwitch/NintendoSwitch_ConsoleHandle.cpp Source/NintendoSwitch/NintendoSwitch_ConsoleHandle.h Source/NintendoSwitch/NintendoSwitch_MultiSwitchProgram.cpp diff --git a/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp new file mode 100644 index 0000000000..df6e8b061e --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp @@ -0,0 +1,74 @@ +/* Detect Home + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" +#include "CommonTools/Images/SolidColorTest.h" +#include "NintendoSwitch_SelectedSettingDetector.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + +SelectedSettingWatcher::~SelectedSettingWatcher() = default; + +SelectedSettingWatcher::SelectedSettingWatcher(ImageFloatBox selected_box, ImageFloatBox not_selected_box1, ImageFloatBox not_selected_box2) + : VisualInferenceCallback("SelectedSettingWatcher") + , m_selected_box(selected_box) + , m_not_selected_box1(not_selected_box1) + , m_not_selected_box2(not_selected_box2) +{} + +void SelectedSettingWatcher::make_overlays(VideoOverlaySet& items) const{ + items.add(COLOR_RED, m_selected_box); + items.add(COLOR_BLUE, m_not_selected_box1); + items.add(COLOR_BLUE, m_not_selected_box2); +} + +bool is_white_theme(const ImageViewRGB32& screen){ + ImageFloatBox window_top(0.60, 0.02, 0.35, 0.05); + ImageStats stats_window_top = image_stats(extract_box_reference(screen, window_top)); + bool white_theme = stats_window_top.average.sum() > 600; + return white_theme; +} + +bool SelectedSettingWatcher::process_frame(const ImageViewRGB32& screen, WallClock timestamp){ + +ImageStats stats_unselected_box1 = image_stats(extract_box_reference(screen, m_not_selected_box1)); + double unselected1_average_sum = stats_unselected_box1.average.sum(); + cout << "unselected_average_sum1: " << std::to_string(unselected1_average_sum) << endl; + + ImageStats stats_unselected_box2 = image_stats(extract_box_reference(screen, m_not_selected_box2)); + double unselected2_average_sum = stats_unselected_box2.average.sum(); + cout << "unselected_average_sum2: " << std::to_string(unselected2_average_sum) << endl; + + double average_sum_unselected_diff = std::abs(unselected1_average_sum - unselected2_average_sum); + + ImageStats stats_selected_box = image_stats(extract_box_reference(screen, m_selected_box)); + double selected_average_sum = stats_selected_box.average.sum(); + cout << "selected_average_sum: " << std::to_string(selected_average_sum) << endl; + + bool is_selected = false; + if (is_white_theme(screen)){ // light mode + // unselected should be brighter than selected + is_selected = selected_average_sum < std::min(unselected1_average_sum, unselected2_average_sum) - average_sum_unselected_diff - 20 ; + }else{ // dark mode + // selected should be brighter than unselected + is_selected = selected_average_sum > std::max(unselected1_average_sum, unselected2_average_sum) + average_sum_unselected_diff + 20; + } + + return is_selected; +} + + + + + + +} +} diff --git a/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h new file mode 100644 index 0000000000..e9ac585e0b --- /dev/null +++ b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h @@ -0,0 +1,44 @@ +/* Selected Setting Detector + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_NintendoSwitch_SelectedSettingDetector_H +#define PokemonAutomation_NintendoSwitch_SelectedSettingDetector_H + +#include "Common/Cpp/Color.h" +#include "CommonFramework/ImageTools/ImageBoxes.h" +#include "CommonTools/InferenceCallbacks/VisualInferenceCallback.h" +#include "CommonTools/VisualDetector.h" + +namespace PokemonAutomation{ +namespace NintendoSwitch{ + + +class SelectedSettingWatcher : public VisualInferenceCallback{ +public: + SelectedSettingWatcher(ImageFloatBox selected_box, ImageFloatBox not_selected_box1, ImageFloatBox not_selected_box2); + virtual ~SelectedSettingWatcher(); + + virtual void make_overlays(VideoOverlaySet& items) const override; + + // return true if the area within the selected_box is highlighted, compared with the area within unselected_box + // This compares the brightness of the selected_box with the unselected_box. + // selected_box: the box where we expect the screen should be highlighted + // not_selected_box 1 and 2: the boxes where we expect the screen should NOT be highlighted. These acts as the control, for comparison. + // the average sum of selected_box should be greater than the absolute difference of average sum between unselected_box 1 and 2. + virtual bool process_frame(const ImageViewRGB32& screen, WallClock timestamp) override; + + +protected: + ImageFloatBox m_selected_box; + ImageFloatBox m_not_selected_box1; + ImageFloatBox m_not_selected_box2; +}; + + +} +} +#endif + diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 8be0ae98d4..424e55e033 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -8,6 +8,8 @@ #include "CommonFramework/Exceptions/OperationFailedException.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h" #include "NintendoSwitch/Commands/NintendoSwitch_Commands_Superscalar.h" +#include "NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.h" +#include "CommonTools/Async/InferenceRoutines.h" #include "CommonFramework/ImageTools/ImageStats.h" #include "CommonFramework/VideoPipeline/VideoFeed.h" #include "CommonFramework/VideoPipeline/VideoOverlayScopes.h" @@ -72,6 +74,8 @@ bool is_setting_selected(VideoStream& stream, ProControllerContext& context, Ima } void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast){ + size_t max_attempts = 5; + for (size_t i = 0; i < max_attempts; i++){ switch (context->performance_class()){ case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); @@ -84,31 +88,9 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); - // we expect to be at Settings icon - ImageFloatBox system_settings(0.685, 0.69, 0.05, 0.03); - ImageFloatBox other_setting1(0.615, 0.69, 0.05, 0.03); - ImageFloatBox other_setting2(0.545, 0.69, 0.05, 0.03); - if (!is_setting_selected(stream, context, system_settings, other_setting1, other_setting2)){ - // not at Settings Icon - // mash down, mash right. then left one - size_t iterations = Milliseconds(1200) / 24ms + 1; - for (size_t i = 0; i < iterations; i++){ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); - } - - for (size_t i = 0; i < iterations; i++){ - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 24ms); - } - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); - - if (!is_setting_selected(stream, context, system_settings, other_setting1, other_setting2)){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "home_to_date_time(): Failed to reach settings gear on Home page after 2 attempts.", - stream - ); - } - } + // ImageFloatBox system_icon(0.685, 0.69, 0.05, 0.03); + // ImageFloatBox other_setting1(0.615, 0.69, 0.05, 0.03); + // ImageFloatBox other_setting2(0.545, 0.69, 0.05, 0.03); // Two A presses in case we drop the 1st one. ssf_press_button(context, BUTTON_A, 3); @@ -122,6 +104,25 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool }while (--iterations); } + // Should now be in System Settings, with System highlighted + ImageFloatBox system_setting_box(0.056, 0.74, 0.01, 0.1); + ImageFloatBox other_setting1(0.04, 0.74, 0.01, 0.1); + ImageFloatBox other_setting2(0.02, 0.74, 0.01, 0.1); + SelectedSettingWatcher system_setting(system_setting_box, other_setting1, other_setting2); + int ret = run_until( + stream, context, + [](ProControllerContext& context){ + for (int i = 0; i < 10; i++){ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + } + }, + {system_setting} + ); + if (ret < 0){ // failed to detect System highlighted. press home and re-try + pbf_press_button(context, BUTTON_HOME, 100ms, 100ms); + continue; + } + // Scroll left and press A to exit the sleep menu if we happened to // land there. ssf_issue_scroll(context, SSF_SCROLL_LEFT, 3); @@ -148,39 +149,20 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool context.wait_for_all_requests(); // we expect to be within "Date and Time", with "Synchronize Clock via Internet" being highlighted - ImageFloatBox sync_clock(0.168, 0.185, 0.01, 0.1); + ImageFloatBox sync_clock_box(0.168, 0.185, 0.01, 0.1); ImageFloatBox other_setting3(0.1, 0.185, 0.01, 0.1); ImageFloatBox other_setting4(0.05, 0.185, 0.01, 0.1); - if (!is_setting_selected(stream, context, sync_clock, other_setting3, other_setting4)){ - // press B once, then mash Up. then try again to scroll down to Date and Time - pbf_press_button(context, BUTTON_B, 100ms, 100ms); - pbf_move_left_joystick(context, 128, 0, 3000ms, 100ms); - - size_t iterations = Milliseconds(1200) / 24ms + 1; - for (size_t i = 0; i < iterations; i++){ - ssf_issue_scroll(context, SSF_SCROLL_UP, 24ms); - } - - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 10); - ssf_press_dpad(context, DPAD_DOWN, 45, 40); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - - // double up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 3); - - if (!is_setting_selected(stream, context, sync_clock, other_setting3, other_setting4)){ - OperationFailedException::fire( - ErrorReport::SEND_ERROR_REPORT, - "home_to_date_time(): Failed to reach 'Synchronize Clock via Internet', within 'Date and Time', after 2 attempts.", - stream - ); - } + SelectedSettingWatcher sync_clock(sync_clock_box, other_setting3, other_setting4); + ret = wait_until( + stream, context, + Milliseconds(2000), + {sync_clock} + ); + if (ret < 0){ // failed to detect System highlighted. press home and re-try + pbf_press_button(context, BUTTON_HOME, 100ms, 100ms); + continue; + } - } if (!to_date_change){ return; @@ -198,7 +180,7 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool // confirmation menus. ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms); - break; + return; } case ControllerPerformanceClass::SerialPABotBase_Wireless_ESP32:{ Milliseconds tv = context->timing_variation(); @@ -269,7 +251,7 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool // confirmation menus. ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); - break; + return; } default:{ // Slow version for tick-imprecise controllers. @@ -308,10 +290,16 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_press_button_ptv(context, BUTTON_A, 1000ms); ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + return; + } } } - + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "home_to_date_time(): Failed to reach Date and Time after several attempts.", + stream + ); } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h index 8901457056..e264c47c0b 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h @@ -19,11 +19,7 @@ namespace NintendoSwitch{ // assumes we are currently in the Switch Settings. bool is_white_theme(VideoStream& stream, ProControllerContext& context); -// return true if the area within the selected_box is highlighted, compared with the area within unselected_box -// This compares the brightness of the selected_box with the unselected_box. -// selected_box: the box where we expect the screen should be highlighted -// unselected_box 1 and 2: the boxes where we expect the screen should NOT be highlighted. These acts as the control, for comparison. -// the average sum of selected_box should be greater than the absolute difference of average sum between unselected_box 1 and 2. + bool is_setting_selected(VideoStream& stream, ProControllerContext& context, ImageFloatBox selected_box, ImageFloatBox unselected_box1, ImageFloatBox unselected_box2); void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast); From b269f2a3f9f96eb7fdb13a6f78959800c3ae42f9 Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 23:11:23 -0700 Subject: [PATCH 06/11] delete old code --- .../DevPrograms/TestProgramSwitch.cpp | 2 +- .../Programs/NintendoSwitch_Navigation.cpp | 62 ++----------------- .../Programs/NintendoSwitch_Navigation.h | 7 --- 3 files changed, 7 insertions(+), 64 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index af08666dbf..6ca1cfe2a8 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -318,7 +318,7 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& #if 1 - home_to_date_time(console, context, true, false); + home_to_date_time(console, context, false, false); #endif #if 0 diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 424e55e033..1366462229 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -21,58 +21,6 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -bool is_white_theme(VideoStream& stream, ProControllerContext& context){ - context.wait_for_all_requests(); - VideoSnapshot snapshot = stream.video().snapshot(); - ImageFloatBox window_top(0.60, 0.02, 0.35, 0.05); - ImageStats stats_window_top = image_stats(extract_box_reference(snapshot, window_top)); - bool white_theme = stats_window_top.average.sum() > 600; - return white_theme; -} - -bool is_setting_selected(VideoStream& stream, ProControllerContext& context, ImageFloatBox selected_box, ImageFloatBox unselected_box1, ImageFloatBox unselected_box2){ - VideoOverlaySet overlays(stream.overlay()); - overlays.add(COLOR_RED, selected_box); - overlays.add(COLOR_BLUE, unselected_box1); - overlays.add(COLOR_BLUE, unselected_box2); - context.wait_for_all_requests(); - context.wait_for(Milliseconds(250)); - size_t max_attempts = 10; // multiple attempts because the highlighted icon/setting pulses. and sometimes there isn't enough contrast at the exact moment you take the snapshot. - bool is_selected = false; - for (size_t i = 0; i < max_attempts; i++){ - VideoSnapshot snapshot = stream.video().snapshot(); - - ImageStats stats_unselected_box1 = image_stats(extract_box_reference(snapshot, unselected_box1)); - double unselected1_average_sum = stats_unselected_box1.average.sum(); - stream.log("unselected_average_sum1: " + std::to_string(unselected1_average_sum)); - - ImageStats stats_unselected_box2 = image_stats(extract_box_reference(snapshot, unselected_box2)); - double unselected2_average_sum = stats_unselected_box2.average.sum(); - stream.log("unselected_average_sum2: " + std::to_string(unselected2_average_sum)); - - double average_sum_unselected_diff = std::abs(unselected1_average_sum - unselected2_average_sum); - - ImageStats stats_selected_box = image_stats(extract_box_reference(snapshot, selected_box)); - double selected_average_sum = stats_selected_box.average.sum(); - stream.log("selected_average_sum: " + std::to_string(selected_average_sum)); - - if (is_white_theme(stream, context)){ // light mode - // unselected should be brighter than selected - is_selected = selected_average_sum < std::min(unselected1_average_sum, unselected2_average_sum) - average_sum_unselected_diff - 20 ; - }else{ // dark mode - // selected should be brighter than unselected - is_selected = selected_average_sum > std::max(unselected1_average_sum, unselected2_average_sum) + average_sum_unselected_diff + 20; - } - - if(is_selected){ - return true; - } - context.wait_for(Milliseconds(100)); - } - - return false; -} - void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast){ size_t max_attempts = 5; for (size_t i = 0; i < max_attempts; i++){ @@ -104,11 +52,12 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool }while (--iterations); } + context.wait_for_all_requests(); // Should now be in System Settings, with System highlighted ImageFloatBox system_setting_box(0.056, 0.74, 0.01, 0.1); ImageFloatBox other_setting1(0.04, 0.74, 0.01, 0.1); ImageFloatBox other_setting2(0.02, 0.74, 0.01, 0.1); - SelectedSettingWatcher system_setting(system_setting_box, other_setting1, other_setting2); + SelectedSettingWatcher system_setting_selected(system_setting_box, other_setting1, other_setting2); int ret = run_until( stream, context, [](ProControllerContext& context){ @@ -116,7 +65,7 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); } }, - {system_setting} + {system_setting_selected} ); if (ret < 0){ // failed to detect System highlighted. press home and re-try pbf_press_button(context, BUTTON_HOME, 100ms, 100ms); @@ -148,15 +97,16 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_press_button(context, BUTTON_A, 3); context.wait_for_all_requests(); + context.wait_for(Milliseconds(250)); // we expect to be within "Date and Time", with "Synchronize Clock via Internet" being highlighted ImageFloatBox sync_clock_box(0.168, 0.185, 0.01, 0.1); ImageFloatBox other_setting3(0.1, 0.185, 0.01, 0.1); ImageFloatBox other_setting4(0.05, 0.185, 0.01, 0.1); - SelectedSettingWatcher sync_clock(sync_clock_box, other_setting3, other_setting4); + SelectedSettingWatcher sync_clock_selected(sync_clock_box, other_setting3, other_setting4); ret = wait_until( stream, context, Milliseconds(2000), - {sync_clock} + {sync_clock_selected} ); if (ret < 0){ // failed to detect System highlighted. press home and re-try pbf_press_button(context, BUTTON_HOME, 100ms, 100ms); diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h index e264c47c0b..b75615b9e1 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h @@ -15,13 +15,6 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -// return true if the Switch Settings uses White theme -// assumes we are currently in the Switch Settings. -bool is_white_theme(VideoStream& stream, ProControllerContext& context); - - -bool is_setting_selected(VideoStream& stream, ProControllerContext& context, ImageFloatBox selected_box, ImageFloatBox unselected_box1, ImageFloatBox unselected_box2); - void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast); void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast); From a682f08bfd784c0cd47955c51c8663cfdb013faa Mon Sep 17 00:00:00 2001 From: jw098 Date: Thu, 5 Jun 2025 23:19:36 -0700 Subject: [PATCH 07/11] minor change --- .../Programs/NintendoSwitch_Navigation.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 1366462229..a82443c970 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -34,7 +34,10 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); ssf_issue_scroll(context, SSF_SCROLL_DOWN, 4); + // if (i > 0){ // intentionally create a failure, for testing ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); + // } + // ImageFloatBox system_icon(0.685, 0.69, 0.05, 0.03); // ImageFloatBox other_setting1(0.615, 0.69, 0.05, 0.03); @@ -68,7 +71,7 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool {system_setting_selected} ); if (ret < 0){ // failed to detect System highlighted. press home and re-try - pbf_press_button(context, BUTTON_HOME, 100ms, 100ms); + pbf_press_button(context, BUTTON_HOME, 100ms, 2000ms); continue; } @@ -89,7 +92,9 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_DOWN, 10); ssf_press_dpad(context, DPAD_DOWN, 45, 40); ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + // if (i > 1){ // intentionally create a failure, for testing ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + // } // double up this A press to make sure it gets through. @@ -109,7 +114,7 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool {sync_clock_selected} ); if (ret < 0){ // failed to detect System highlighted. press home and re-try - pbf_press_button(context, BUTTON_HOME, 100ms, 100ms); + pbf_press_button(context, BUTTON_HOME, 100ms, 2000ms); continue; } From 450f0fccea52f283cecf76200ac9b7070046d94d Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 6 Jun 2025 16:18:21 -0700 Subject: [PATCH 08/11] home_to_date_time: split function based on controller type --- .../DevPrograms/TestProgramSwitch.cpp | 2 +- ...NintendoSwitch_SelectedSettingDetector.cpp | 2 +- .../Programs/NintendoSwitch_Navigation.cpp | 419 +++++++----------- .../Programs/NintendoSwitch_Navigation.h | 10 +- 4 files changed, 172 insertions(+), 261 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index 6ca1cfe2a8..f82513ee68 100644 --- a/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp +++ b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp @@ -318,7 +318,7 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& #if 1 - home_to_date_time(console, context, false, false); + home_to_date_time(console, context, false); #endif #if 0 diff --git a/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp index df6e8b061e..4aaf9e0c28 100644 --- a/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp @@ -39,7 +39,7 @@ bool is_white_theme(const ImageViewRGB32& screen){ bool SelectedSettingWatcher::process_frame(const ImageViewRGB32& screen, WallClock timestamp){ -ImageStats stats_unselected_box1 = image_stats(extract_box_reference(screen, m_not_selected_box1)); + ImageStats stats_unselected_box1 = image_stats(extract_box_reference(screen, m_not_selected_box1)); double unselected1_average_sum = stats_unselected_box1.average.sum(); cout << "unselected_average_sum1: " << std::to_string(unselected1_average_sum) << endl; diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index a82443c970..8c37e2f2c7 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -21,11 +21,9 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast){ +void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProControllerContext& context, bool to_date_change){ size_t max_attempts = 5; for (size_t i = 0; i < max_attempts; i++){ - switch (context->performance_class()){ - case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); @@ -129,7 +127,6 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); }while (--iterations); } -// ssf_issue_scroll(context, SSF_SCROLL_DOWN, 0); // Left scroll in case we missed landed in the language change or sleep // confirmation menus. @@ -137,118 +134,6 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool return; } - case ControllerPerformanceClass::SerialPABotBase_Wireless_ESP32:{ - Milliseconds tv = context->timing_variation(); - Milliseconds unit = 24ms + tv; - - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - - // Down twice in case we drop one. - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); - - // Press A multiple times to make sure one goes through. - pbf_press_button(context, BUTTON_A, 2*unit, unit); - pbf_press_button(context, BUTTON_A, 2*unit, unit); - pbf_press_button(context, BUTTON_A, 2*unit, unit); - - // Just button mash it. lol - { - auto iterations = Milliseconds(1100) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - }while (--iterations); - } - - // Scroll left and press A to exit the sleep menu if we happened to - // land there. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, unit); - ssf_press_button(context, BUTTON_A, unit, 2*unit, unit); - - { - auto iterations = Milliseconds(312) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - }while (--iterations); - } - - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 400ms, 2*unit, unit); - ssf_press_dpad(context, DPAD_DOWN, 360ms, 304ms); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - - if (!to_date_change){ - // Triple up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, 360ms, 2*unit, unit); - return; - } - - // Triple up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, unit); - { - auto iterations = Milliseconds(250) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - }while (--iterations); - } - - // Left scroll in case we missed landed in the language change or sleep - // confirmation menus. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); - - return; - } - default:{ - // Slow version for tick-imprecise controllers. - - Milliseconds tv = context->timing_variation(); -// ssf_do_nothing(context, 1500ms); - - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); - - // Down twice in case we drop one. - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); -// ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - - ssf_issue_scroll_ptv(context, SSF_SCROLL_LEFT); - - // Press A multiple times to make sure one goes through. - ssf_mash1_button(context, BUTTON_A, 200ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN, 2500ms, 2500ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT, 500ms, 500ms); - - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 500ms, tv, tv); - ssf_press_right_joystick(context, 128, 224, 1000ms, 300ms, tv); -// ssf_issue_scroll(context, SSF_SCROLL_DOWN, 1000ms, 250ms, tv); // Scroll down - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - - if (!to_date_change){ - ssf_press_button_ptv(context, BUTTON_A); - return; - } - - ssf_press_button_ptv(context, BUTTON_A, 1000ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - return; - } - } - } OperationFailedException::fire( ErrorReport::SEND_ERROR_REPORT, @@ -259,187 +144,205 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool } +void home_to_date_time_Switch1_wired_blind(ProControllerContext& context, bool to_date_change, bool fast){ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); + // Down twice in case we drop one. + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 4); -void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast){ - switch (context->performance_class()){ - case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); - - // Down twice in case we drop one. - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 4); - - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); - - // Two A presses in case we drop the 1st one. - ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 3); + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); - // Just button mash it. lol - { - auto iterations = Milliseconds(1200) / 24ms + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); - }while (--iterations); - } + // Two A presses in case we drop the 1st one. + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); - // Scroll left and press A to exit the sleep menu if we happened to - // land there. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 3); - ssf_press_button(context, BUTTON_A, 3); + // Just button mash it. lol + { + auto iterations = Milliseconds(1200) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + }while (--iterations); + } - { - auto iterations = Milliseconds(312) / 24ms + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 24ms); - }while (--iterations); - } + // Scroll left and press A to exit the sleep menu if we happened to + // land there. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 3); + ssf_press_button(context, BUTTON_A, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 10); - ssf_press_dpad(context, DPAD_DOWN, 45, 40); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + { + auto iterations = Milliseconds(312) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 24ms); + }while (--iterations); + } - if (!to_date_change){ - // Triple up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 45); - return; - } + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 10); + ssf_press_dpad(context, DPAD_DOWN, 45, 40); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + if (!to_date_change){ // Triple up this A press to make sure it gets through. ssf_press_button(context, BUTTON_A, 3); ssf_press_button(context, BUTTON_A, 3); - ssf_press_button(context, BUTTON_A, 3); - { - auto iterations = Milliseconds(250) / 24ms + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); - }while (--iterations); - } -// ssf_issue_scroll(context, SSF_SCROLL_DOWN, 0); - - // Left scroll in case we missed landed in the language change or sleep - // confirmation menus. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms); + ssf_press_button(context, BUTTON_A, 45); + return; + } - break; + // Triple up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + ssf_press_button(context, BUTTON_A, 3); + { + auto iterations = Milliseconds(250) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + }while (--iterations); } - case ControllerPerformanceClass::SerialPABotBase_Wireless_ESP32:{ - Milliseconds tv = context->timing_variation(); - Milliseconds unit = 24ms + tv; +// ssf_issue_scroll(context, SSF_SCROLL_DOWN, 0); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + // Left scroll in case we missed landed in the language change or sleep + // confirmation menus. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms); +} - // Down twice in case we drop one. - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); +void home_to_date_time_Switch1_wireless_esp32_blind(ProControllerContext& context, bool to_date_change, bool fast){ + Milliseconds tv = context->timing_variation(); + Milliseconds unit = 24ms + tv; - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - // Press A multiple times to make sure one goes through. - pbf_press_button(context, BUTTON_A, 2*unit, unit); - pbf_press_button(context, BUTTON_A, 2*unit, unit); - pbf_press_button(context, BUTTON_A, 2*unit, unit); + // Down twice in case we drop one. + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - // Just button mash it. lol - { - auto iterations = Milliseconds(1100) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - }while (--iterations); - } + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); - // Scroll left and press A to exit the sleep menu if we happened to - // land there. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, unit); - ssf_press_button(context, BUTTON_A, unit, 2*unit, unit); + // Press A multiple times to make sure one goes through. + pbf_press_button(context, BUTTON_A, 2*unit, unit); + pbf_press_button(context, BUTTON_A, 2*unit, unit); + pbf_press_button(context, BUTTON_A, 2*unit, unit); - { - auto iterations = Milliseconds(312) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - }while (--iterations); - } + // Just button mash it. lol + { + auto iterations = Milliseconds(1100) / unit + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + }while (--iterations); + } - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 400ms, 2*unit, unit); - ssf_press_dpad(context, DPAD_DOWN, 360ms, 304ms); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + // Scroll left and press A to exit the sleep menu if we happened to + // land there. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, unit); + ssf_press_button(context, BUTTON_A, unit, 2*unit, unit); - if (!to_date_change){ - // Triple up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, 360ms, 2*unit, unit); - return; - } + { + auto iterations = Milliseconds(312) / unit + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); + }while (--iterations); + } + + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 400ms, 2*unit, unit); + ssf_press_dpad(context, DPAD_DOWN, 360ms, 304ms); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + if (!to_date_change){ // Triple up this A press to make sure it gets through. ssf_press_button(context, BUTTON_A, unit); ssf_press_button(context, BUTTON_A, unit); - ssf_press_button(context, BUTTON_A, unit); - { - auto iterations = Milliseconds(250) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - }while (--iterations); - } - - // Left scroll in case we missed landed in the language change or sleep - // confirmation menus. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); + ssf_press_button(context, BUTTON_A, 360ms, 2*unit, unit); + return; + } - break; + // Triple up this A press to make sure it gets through. + ssf_press_button(context, BUTTON_A, unit); + ssf_press_button(context, BUTTON_A, unit); + ssf_press_button(context, BUTTON_A, unit); + { + auto iterations = Milliseconds(250) / unit + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); + }while (--iterations); } - default:{ - // Slow version for tick-imprecise controllers. - Milliseconds tv = context->timing_variation(); + // Left scroll in case we missed landed in the language change or sleep + // confirmation menus. + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0ms, 2*unit, unit); + +} + +void home_to_date_time_Switch1_sbb_blind(ProControllerContext& context, bool to_date_change, bool fast){ + Milliseconds tv = context->timing_variation(); // ssf_do_nothing(context, 1500ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT); - // Down twice in case we drop one. - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + // Down twice in case we drop one. + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); // ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_LEFT); - - // Press A multiple times to make sure one goes through. - ssf_mash1_button(context, BUTTON_A, 200ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN, 2500ms, 2500ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT, 500ms, 500ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_LEFT); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll(context, SSF_SCROLL_DOWN, 500ms, tv, tv); - ssf_press_right_joystick(context, 128, 224, 1000ms, 300ms, tv); + // Press A multiple times to make sure one goes through. + ssf_mash1_button(context, BUTTON_A, 200ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN, 2500ms, 2500ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_RIGHT, 500ms, 500ms); + + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 500ms, tv, tv); + ssf_press_right_joystick(context, 128, 224, 1000ms, 300ms, tv); // ssf_issue_scroll(context, SSF_SCROLL_DOWN, 1000ms, 250ms, tv); // Scroll down - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - if (!to_date_change){ - ssf_press_button_ptv(context, BUTTON_A); - return; - } + if (!to_date_change){ + ssf_press_button_ptv(context, BUTTON_A); + return; + } - ssf_press_button_ptv(context, BUTTON_A, 1000ms); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); - ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_press_button_ptv(context, BUTTON_A, 1000ms); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); + ssf_issue_scroll_ptv(context, SSF_SCROLL_DOWN); +} + + +void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change){ + switch (context->performance_class()){ + case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ + home_to_date_time_Switch1_wired_with_feedback(stream, context, to_date_change); + break; + } } +} + +void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast){ + switch (context->performance_class()){ + case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ + home_to_date_time_Switch1_wired_blind(context, to_date_change, fast); + break; + } + case ControllerPerformanceClass::SerialPABotBase_Wireless_ESP32:{ + home_to_date_time_Switch1_wireless_esp32_blind(context, to_date_change, fast); + break; + } + default:{ + // Slow version for tick-imprecise controllers. + home_to_date_time_Switch1_sbb_blind(context, to_date_change, fast); + } } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h index b75615b9e1..aebd9d357c 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h @@ -15,7 +15,15 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change, bool fast); +void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProControllerContext& context, bool to_date_change); + +void home_to_date_time_Switch1_wired_blind(ProControllerContext& context, bool to_date_change, bool fast); +void home_to_date_time_Switch1_wireless_esp32_blind(ProControllerContext& context, bool to_date_change, bool fast); +void home_to_date_time_Switch1_sbb_blind(ProControllerContext& context, bool to_date_change, bool fast); + +// Navigates from Home screen to the Date and Time screen. Using visual inference. +void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool to_date_change); +// Navigates from Home screen to the Date and Time screen. Done blind, without inference. void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast); //Joycon must not be sideways From 8176282c2cd0b1c2c9152d15421c1dc771072675 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 6 Jun 2025 16:45:47 -0700 Subject: [PATCH 09/11] remove redundant button presses --- .../NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 8c37e2f2c7..320231ef78 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -73,10 +73,6 @@ void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProContr continue; } - // Scroll left and press A to exit the sleep menu if we happened to - // land there. - ssf_issue_scroll(context, SSF_SCROLL_LEFT, 3); - ssf_press_button(context, BUTTON_A, 3); { auto iterations = Milliseconds(312) / 24ms + 1; @@ -95,12 +91,10 @@ void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProContr // } - // double up this A press to make sure it gets through. - ssf_press_button(context, BUTTON_A, 3); ssf_press_button(context, BUTTON_A, 3); context.wait_for_all_requests(); - context.wait_for(Milliseconds(250)); + context.wait_for(Milliseconds(300)); // we expect to be within "Date and Time", with "Synchronize Clock via Internet" being highlighted ImageFloatBox sync_clock_box(0.168, 0.185, 0.01, 0.1); ImageFloatBox other_setting3(0.1, 0.185, 0.01, 0.1); From f57770a5fec42d5670423260b59f84b8e9ff0e67 Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 6 Jun 2025 17:00:06 -0700 Subject: [PATCH 10/11] update comments --- .../NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 320231ef78..9d242941d9 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -42,6 +42,7 @@ void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProContr // ImageFloatBox other_setting2(0.545, 0.69, 0.05, 0.03); // Two A presses in case we drop the 1st one. + // the program can self recover even if the second button press is registered. ssf_press_button(context, BUTTON_A, 3); ssf_press_button(context, BUTTON_A, 3); @@ -68,7 +69,7 @@ void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProContr }, {system_setting_selected} ); - if (ret < 0){ // failed to detect System highlighted. press home and re-try + if (ret < 0){ // failed to detect "System" being highlighted. press home and re-try pbf_press_button(context, BUTTON_HOME, 100ms, 2000ms); continue; } @@ -90,7 +91,8 @@ void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProContr ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); // } - + // only one ButtonA press since the program can self-recover if the button is dropped. + // furthermore, the program can't self-recover if a second button press is registered. ssf_press_button(context, BUTTON_A, 3); context.wait_for_all_requests(); @@ -105,7 +107,7 @@ void home_to_date_time_Switch1_wired_with_feedback(VideoStream& stream, ProContr Milliseconds(2000), {sync_clock_selected} ); - if (ret < 0){ // failed to detect System highlighted. press home and re-try + if (ret < 0){ // failed to detect "Synchronize clock" being highlighted. press home and re-try pbf_press_button(context, BUTTON_HOME, 100ms, 2000ms); continue; } From f296498569a9536b5cb91969dd0b13598e9147bc Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 6 Jun 2025 17:20:59 -0700 Subject: [PATCH 11/11] fix build --- .../NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp index 9d242941d9..4962131889 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -322,6 +322,10 @@ void home_to_date_time(VideoStream& stream, ProControllerContext& context, bool home_to_date_time_Switch1_wired_with_feedback(stream, context, to_date_change); break; } + default:{ + // Slow version for tick-imprecise controllers. Blind. + home_to_date_time_Switch1_sbb_blind(context, to_date_change, false); + } } }