77#include " Common/Cpp/Time.h"
88#include " CommonFramework/Exceptions/OperationFailedException.h"
99#include " CommonFramework/ImageTools/ImageBoxes.h"
10+ #include " CommonFramework/ImageTools/ImageStats.h"
11+ #include " CommonFramework/VideoPipeline/VideoFeed.h"
12+ #include " CommonFramework/VideoPipeline/VideoOverlayScopes.h"
1013#include " CommonTools/Async/InferenceRoutines.h"
1114#include " Controllers/SerialPABotBase/Connection/MessageConverter.h"
1215#include " NintendoSwitch/Commands/NintendoSwitch_Commands_PushButtons.h"
@@ -21,75 +24,204 @@ namespace NintendoSwitch{
2124namespace PokemonLGPE {
2225
2326void verify_date_time_menu_selected (ConsoleHandle& console, JoyconContext& context){
24- // Verify that "Date and Time" menu item is selected (not "Time Zone")
25- // After home_to_date_time(..., true), we should be in the "Date and Time" menu screen
26- // Menu items: "Synchronize Clock via Internet" (top), "Time Zone" (middle), "Date and Time" (bottom)
27- // We need "Date and Time" (bottom) to be selected before rolling the date
27+ // Comprehensive verification: ensure we're on "Date and Time" menu item AND Sync Clock is OFF
28+ // Menu structure: "Synchronize Clock via Internet" (top), "Time Zone" (middle), "Date and Time" (bottom)
29+ // CRITICAL: Must be on "Date and Time" before rolling date, never on "Time Zone" or "Sync Clock"
2830
2931 context.wait_for_all_requests ();
30- context.wait_for (Milliseconds (300 ));
32+ context.wait_for (Milliseconds (400 ));
33+
34+ Milliseconds tv = context->timing_variation ();
35+ Milliseconds unit = 100ms + tv;
3136
32- // Use single snapshot check instead of polling to avoid visual pulsing
37+ // STEP 1: Check and disable "Synchronize Clock via Internet" if it's ON
38+ console.log (" Step 1: Checking 'Synchronize Clock via Internet' status..." );
3339 VideoSnapshot snapshot = console.video ().snapshot ();
3440 if (!snapshot){
35- console.log (" WARNING: No video available for menu verification . Proceeding anyway ..." , COLOR_RED);
41+ console.log (" WARNING: No video available. Proceeding blind ..." , COLOR_RED);
3642 return ;
3743 }
3844
39- // Box positions based on Switch menu layout - "Date and Time" text is at bottom
40- ImageFloatBox date_time_box (0.50 , 0.78 , 0.15 , 0.03 ); // "Date and Time" menu item (bottom)
41- ImageFloatBox time_zone_box (0.50 , 0.70 , 0.15 , 0.03 ); // "Time Zone" menu item (middle)
42- ImageFloatBox sync_clock_box (0.50 , 0.62 , 0.15 , 0.03 ); // "Synchronize Clock via Internet" (top)
45+ // Add visual overlay boxes so you can see where we're looking
46+ VideoOverlaySet overlays (console.overlay ());
4347
44- // Check once if "Date and Time" is selected (using snapshot timestamp, no polling)
45- SelectedSettingWatcher date_time_watcher (date_time_box, time_zone_box, sync_clock_box);
46- bool date_time_selected = date_time_watcher.process_frame (*snapshot, snapshot.timestamp ());
48+ // Based on your screenshot: menu items are in the lower half of the screen
49+ // "Synchronize Clock via Internet" is the first item, with "On"/"Off" status on the right
50+ // "Time Zone" shows "Denver" on the right around y=0.70
51+ // So "Synchronize Clock" status should be above that, around y=0.55-0.65
4752
48- if (date_time_selected){
49- // Successfully detected "Date and Time" is selected
50- console.log (" Verified 'Date and Time' menu item is selected." );
51- return ;
52- }
53+ ImageFloatBox sync_status_box1 (0.78 , 0.21 , 0.05 , 0.05 ); // Try y=0.50
5354
54- // "Date and Time" is not selected - navigate to it
55- console.log (" 'Date and Time' not selected. Navigating to it..." , COLOR_YELLOW);
55+ overlays.add (COLOR_RED, sync_status_box1);
5656
57- Milliseconds tv = context->timing_variation ();
58- Milliseconds unit = 80ms + tv;
57+ ImageStats sync_status1 = image_stats (extract_box_reference (snapshot, sync_status_box1));
5958
60- // Check if "Time Zone" is selected (middle option)
61- SelectedSettingWatcher time_zone_watcher (time_zone_box, date_time_box, sync_clock_box);
62- bool time_zone_selected = time_zone_watcher.process_frame (*snapshot, snapshot.timestamp ());
59+ // Debug: Log all positions
60+ console.log (" Box1 (RED, y:0.21) RGB: [" + std::to_string ((int )sync_status1.average .r ) + " , " +
61+ std::to_string ((int )sync_status1.average .g ) + " , " +
62+ std::to_string ((int )sync_status1.average .b ) + " ] sum=" +
63+ std::to_string ((int )sync_status1.average .sum ()));
64+ console.log (" LOOK AT THE COLORED BOXES ON SCREEN - which one covers the 'On' or 'Off' text?" );
6365
64- if (time_zone_selected){
65- // "Time Zone" is selected, need to go down one more to reach "Date and Time"
66- console.log (" 'Time Zone' selected. Moving down one to 'Date and Time'..." , COLOR_YELLOW);
67- pbf_move_joystick (context, 128 , 255 , unit, unit);
66+ // Use the detected values
67+ ImageStats sync_status = sync_status1;
68+
69+ // "On" is cyan/teal text: green and blue are higher than red
70+ // "Off" is white text: all RGB components are similar and high
71+ // The cyan "On" text shows as [43, 56, 53] - green and blue slightly higher than red
72+ // Detection: if G > R+5 AND B > R, it's likely cyan "On"
73+ // If all components are similar (within 10 of each other), it's white "Off"
74+
75+ bool is_cyan = (sync_status.average .g > sync_status.average .r + 5 ) &&
76+ (sync_status.average .b >= sync_status.average .r );
77+ bool is_white = (std::abs (sync_status.average .r - sync_status.average .g ) < 10 ) &&
78+ (std::abs (sync_status.average .r - sync_status.average .b ) < 10 ) &&
79+ (std::abs (sync_status.average .g - sync_status.average .b ) < 10 );
80+
81+ bool sync_appears_on = is_cyan && !is_white;
82+
83+ console.log (" Is cyan: " + std::string (is_cyan ? " YES" : " NO" ) +
84+ " , Is white: " + std::string (is_white ? " YES" : " NO" ) +
85+ " , Appears ON: " + std::string (sync_appears_on ? " YES" : " NO" ));
86+
87+ if (sync_appears_on){
88+ console.log (" DETECTED: 'Synchronize Clock via Internet' is ON. Disabling it..." , COLOR_YELLOW);
89+
90+ // Strategy: First scroll down to bottom (Date and Time), then scroll up exactly 2 times to Sync Clock
91+ // This ensures we know exactly where we are
92+ console.log (" Navigating to bottom of menu first..." );
93+ for (int i = 0 ; i < 5 ; i++){
94+ pbf_move_joystick (context, 128 , 255 , unit, unit); // Down - go to bottom
95+ context.wait_for_all_requests ();
96+ context.wait_for (Milliseconds (100 ));
97+ }
98+
99+ console.log (" Now navigating UP to 'Synchronize Clock via Internet'..." );
100+ // From "Date and Time" (bottom), go up 2 times to reach "Synchronize Clock" (top)
101+ pbf_move_joystick (context, 128 , 0 , unit, unit); // Up to Time Zone
68102 context.wait_for_all_requests ();
69- context.wait_for (Milliseconds (300 ));
70- } else {
71- // Might be on "Synchronize Clock via Internet" (top) - need to go down twice
72- console.log (" Top option selected. Moving down twice to 'Date and Time'..." , COLOR_YELLOW);
73- pbf_move_joystick (context, 128 , 255 , unit, unit);
103+ context.wait_for (Milliseconds (250 ));
104+ pbf_move_joystick (context, 128 , 0 , unit, unit); // Up to Synchronize Clock
74105 context.wait_for_all_requests ();
75- context.wait_for (Milliseconds (200 ));
76- pbf_move_joystick (context, 128 , 255 , unit, unit);
106+ context.wait_for (Milliseconds (400 ));
107+
108+ // Press A to toggle it OFF
109+ console.log (" Pressing A to toggle OFF..." );
110+ pbf_press_button (context, BUTTON_A, unit, unit);
111+ context.wait_for_all_requests ();
112+ context.wait_for (Milliseconds (600 )); // Wait for toggle animation
113+
114+ console.log (" Toggled 'Synchronize Clock via Internet' OFF. Now navigating back to 'Date and Time'..." );
115+
116+ // Navigate back down to "Date and Time" (2 times down)
117+ pbf_move_joystick (context, 128 , 255 , unit, unit); // Down to Time Zone
118+ context.wait_for_all_requests ();
119+ context.wait_for (Milliseconds (250 ));
120+ pbf_move_joystick (context, 128 , 255 , unit, unit); // Down to Date and Time
121+ context.wait_for_all_requests ();
122+ context.wait_for (Milliseconds (400 ));
123+
124+ console.log (" Back on 'Date and Time' menu item." );
125+ } else {
126+ console.log (" 'Synchronize Clock via Internet' is OFF (or detection failed - check RGB values above)." );
127+ }
128+
129+ // STEP 2: Ensure we're on "Date and Time" menu item (bottom option)
130+ console.log (" Step 2: Ensuring 'Date and Time' menu item is selected..." );
131+
132+ // After handling Sync Clock, we should be on "Date and Time" already if we navigated correctly
133+ // But let's verify and fix if needed
134+
135+ // Simple approach: Just scroll down multiple times to guarantee we're at the bottom
136+ // The menu will stop at "Date and Time" (bottom item) even if we scroll too much
137+ console.log (" Scrolling to bottom to ensure 'Date and Time' is selected..." );
138+ for (int i = 0 ; i < 5 ; i++){
139+ pbf_move_joystick (context, 128 , 255 , unit, unit); // Down
77140 context.wait_for_all_requests ();
78- context.wait_for (Milliseconds (300 ));
141+ context.wait_for (Milliseconds (150 ));
79142 }
80143
81- // Final quick check after navigation (single snapshot, no polling)
82144 context.wait_for_all_requests ();
83- context.wait_for (Milliseconds (200 ));
145+ context.wait_for (Milliseconds (400 ));
146+
147+ // Final verification with visual boxes to see where menu items actually are
84148 snapshot = console.video ().snapshot ();
85149 if (snapshot){
86- date_time_selected = date_time_watcher.process_frame (*snapshot, snapshot.timestamp ());
87- if (!date_time_selected){
88- console.log (" WARNING: Could not verify 'Date and Time' is selected after navigation. Proceeding anyway..." , COLOR_RED);
89- } else {
90- console.log (" Successfully navigated to 'Date and Time' menu item." );
91- }
150+ // Show boxes at different Y positions to find where menu items are
151+ // These boxes cover the LEFT side where menu item TEXT appears (not status text)
152+ ImageFloatBox menu_check_box1 (0.15 , 0.15 , 0.40 , 0.05 ); // Very top
153+ ImageFloatBox menu_check_box2 (0.15 , 0.25 , 0.40 , 0.05 ); // Upper area
154+ ImageFloatBox menu_check_box3 (0.15 , 0.35 , 0.40 , 0.05 ); // Middle area
155+ ImageFloatBox menu_check_box4 (0.15 , 0.45 , 0.40 , 0.05 ); // Lower-middle area
156+ ImageFloatBox menu_check_box5 (0.15 , 0.55 , 0.40 , 0.05 ); // Lower area
157+
158+ VideoOverlaySet menu_overlays (console.overlay ());
159+ menu_overlays.add (COLOR_CYAN, menu_check_box1);
160+ menu_overlays.add (COLOR_MAGENTA, menu_check_box2);
161+ menu_overlays.add (COLOR_GREEN, menu_check_box3);
162+ menu_overlays.add (COLOR_ORANGE, menu_check_box4);
163+ menu_overlays.add (COLOR_PURPLE, menu_check_box5);
164+
165+ ImageStats menu_stats1 = image_stats (extract_box_reference (snapshot, menu_check_box1));
166+ ImageStats menu_stats2 = image_stats (extract_box_reference (snapshot, menu_check_box2));
167+ ImageStats menu_stats3 = image_stats (extract_box_reference (snapshot, menu_check_box3));
168+ ImageStats menu_stats4 = image_stats (extract_box_reference (snapshot, menu_check_box4));
169+ ImageStats menu_stats5 = image_stats (extract_box_reference (snapshot, menu_check_box5));
170+
171+ console.log (" Menu boxes - CYAN(y:0.15):" + std::to_string ((int )menu_stats1.average .sum ()) +
172+ " MAGENTA(y:0.25):" + std::to_string ((int )menu_stats2.average .sum ()) +
173+ " GREEN(y:0.35):" + std::to_string ((int )menu_stats3.average .sum ()) +
174+ " ORANGE(y:0.45):" + std::to_string ((int )menu_stats4.average .sum ()) +
175+ " PURPLE(y:0.55):" + std::to_string ((int )menu_stats5.average .sum ()));
176+ console.log (" LOOK: Which colored box covers the HIGHLIGHTED menu item (should have blue border)?" );
177+ console.log (" The highlighted item should be 'Date and Time' (bottom option)." );
178+ }
179+
180+ console.log (" Ready to roll date. 'Date and Time' should now be selected." );
181+ }
182+
183+ void reset_sync_clock_state (ConsoleHandle& console, JoyconContext& context){
184+ // Reset the menu state by toggling "Synchronize Clock via Internet" ON then OFF
185+ // This helps clear any accumulated navigation errors
186+
187+ console.log (" === RESETTING SYNC CLOCK STATE ===" , COLOR_BLUE);
188+
189+ Milliseconds tv = context->timing_variation ();
190+ Milliseconds unit = 100ms + tv;
191+
192+ context.wait_for_all_requests ();
193+ context.wait_for (Milliseconds (300 ));
194+
195+ // Navigate to bottom first to establish known position
196+ console.log (" Scrolling to bottom..." );
197+ for (int i = 0 ; i < 5 ; i++){
198+ pbf_move_joystick (context, 128 , 255 , unit, unit);
199+ context.wait_for_all_requests ();
200+ context.wait_for (Milliseconds (100 ));
92201 }
202+
203+ // Navigate up to "Synchronize Clock via Internet" (top item)
204+ console.log (" Navigating UP to 'Synchronize Clock via Internet'..." );
205+ pbf_move_joystick (context, 128 , 0 , unit, unit); // Up to Time Zone
206+ context.wait_for_all_requests ();
207+ context.wait_for (Milliseconds (200 ));
208+ pbf_move_joystick (context, 128 , 0 , unit, unit); // Up to Synchronize Clock
209+ context.wait_for_all_requests ();
210+ context.wait_for (Milliseconds (400 ));
211+
212+ // Toggle it ON
213+ console.log (" Toggling ON..." );
214+ pbf_press_button (context, BUTTON_A, unit, unit);
215+ context.wait_for_all_requests ();
216+ context.wait_for (Milliseconds (500 ));
217+
218+ // Toggle it OFF
219+ console.log (" Toggling OFF..." );
220+ pbf_press_button (context, BUTTON_A, unit, unit);
221+ context.wait_for_all_requests ();
222+ context.wait_for (Milliseconds (500 ));
223+
224+ console.log (" Sync clock state reset complete." );
93225}
94226
95227void roll_date_forward_1 (JoyconContext& context){
0 commit comments