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/DevPrograms/TestProgramSwitch.cpp b/SerialPrograms/Source/NintendoSwitch/DevPrograms/TestProgramSwitch.cpp index aae7103704..f82513ee68 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,18 @@ void TestProgram::program(MultiSwitchProgramEnvironment& env, CancellableScope& ProControllerContext context(scope, console.pro_controller()); VideoOverlaySet overlays(overlay); + +#if 1 + home_to_date_time(console, context, false); +#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/Inference/NintendoSwitch_SelectedSettingDetector.cpp b/SerialPrograms/Source/NintendoSwitch/Inference/NintendoSwitch_SelectedSettingDetector.cpp new file mode 100644 index 0000000000..4aaf9e0c28 --- /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 23dbb39dc8..4962131889 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.cpp @@ -5,18 +5,25 @@ */ #include "Controllers/ControllerTypes.h" +#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" #include "NintendoSwitch_Navigation.h" +#include + namespace PokemonAutomation{ namespace NintendoSwitch{ - -void home_to_date_time(ProControllerContext& context, bool to_date_change, bool fast){ - switch (context->performance_class()){ - case ControllerPerformanceClass::SerialPABotBase_Wired_125Hz:{ +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++){ ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); ssf_issue_scroll(context, SSF_SCROLL_RIGHT, 4); @@ -25,9 +32,17 @@ void home_to_date_time(ProControllerContext& context, bool to_date_change, 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); + // 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); @@ -39,10 +54,26 @@ void home_to_date_time(ProControllerContext& context, bool to_date_change, bool }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); + 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_selected(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_selected} + ); + if (ret < 0){ // failed to detect "System" being highlighted. press home and re-try + pbf_press_button(context, BUTTON_HOME, 100ms, 2000ms); + continue; + } + { auto iterations = Milliseconds(312) / 24ms + 1; @@ -56,143 +87,262 @@ void home_to_date_time(ProControllerContext& context, bool to_date_change, 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); + // } + + // 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(); + 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); + ImageFloatBox other_setting4(0.05, 0.185, 0.01, 0.1); + SelectedSettingWatcher sync_clock_selected(sync_clock_box, other_setting3, other_setting4); + ret = wait_until( + stream, context, + Milliseconds(2000), + {sync_clock_selected} + ); + if (ret < 0){ // failed to detect "Synchronize clock" being highlighted. press home and re-try + pbf_press_button(context, BUTTON_HOME, 100ms, 2000ms); + continue; + } + 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; + 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); + OperationFailedException::fire( + ErrorReport::SEND_ERROR_REPORT, + "home_to_date_time(): Failed to reach Date and Time after several attempts.", + stream + ); - // 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); +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); - // Just button mash it. lol - { - auto iterations = Milliseconds(1100) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_DOWN, unit); - }while (--iterations); - } + // Down twice in case we drop one. + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 3); + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 4); - // 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); + ssf_issue_scroll(context, SSF_SCROLL_LEFT, 0); - { - auto iterations = Milliseconds(312) / unit + 1; - do{ - ssf_issue_scroll(context, SSF_SCROLL_RIGHT, unit); - }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); - 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); + // Just button mash it. lol + { + auto iterations = Milliseconds(1200) / 24ms + 1; + do{ + ssf_issue_scroll(context, SSF_SCROLL_DOWN, 24ms); + }while (--iterations); + } - 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; - } + // 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); +} + +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_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, 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); + 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); + // 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; + } + default:{ + // Slow version for tick-imprecise controllers. Blind. + home_to_date_time_Switch1_sbb_blind(context, to_date_change, false); + } } +} + +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 fa3518c7ab..aebd9d357c 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_Navigation.h @@ -7,14 +7,23 @@ #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{ +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