-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathTimeFixer.cpp
More file actions
435 lines (375 loc) · 14.9 KB
/
TimeFixer.cpp
File metadata and controls
435 lines (375 loc) · 14.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
//--------------------------------------------------------------------------------------
// TimeFixer.cpp
//
// Tool to set clock past 2025 while offline.
//--------------------------------------------------------------------------------------
#include <xtl.h>
#include <AtgApp.h>
#include <AtgFont.h>
#include <AtgInput.h>
#include <AtgUtil.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "TimeFixer.h"
#define TICK_RATE 1000 // 1 tick = 1 ms
#define MAX_TICKS ((1ULL << 40) - 1ULL)
#define LEFT_THUMB_DEADZONE 16384 // -32768 - 32768
#define RIGHT_THUMB_DEADZONE 16384
char print_buffer[32];
wchar_t wide_print_buffer[32];
int selected_field = 0;
struct tm temp_tm;
struct tm xbox_epoch_tm = {0};
struct tm xbox_anti_epoch_tm = {0};
bool show_text = false;
float text_start_time = 0.0f; // in seconds
float text_duration = 5.0f; // 5 seconds
wchar_t status_message[255];
class Lightshow : public ATG::Application {
ATG::Font m_Font16; // 16-point font class
ATG::Font m_Font12; // 12-point font class
ATG::GAMEPAD* m_pGamepad;
HRESULT DrawTextContent();
private:
virtual HRESULT Initialize();
virtual HRESULT Update();
virtual HRESULT Render();
};
VOID __cdecl main() {
Lightshow atgApp;
ATG::GetVideoSettings( &atgApp.m_d3dpp.BackBufferWidth, &atgApp.m_d3dpp.BackBufferHeight );
atgApp.m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
atgApp.Run();
}
HRESULT Lightshow::Initialize() {
if( FAILED( m_Font16.Create( "game:\\Media\\Fonts\\Arial_16.xpr" ) ) )
return ATGAPPERR_MEDIANOTFOUND;
if( FAILED( m_Font12.Create( "game:\\Media\\Fonts\\Arial_12.xpr" ) ) )
return ATGAPPERR_MEDIANOTFOUND;
m_Font12.SetWindow( ATG::GetTitleSafeArea() );
m_Font16.SetWindow( ATG::GetTitleSafeArea() );
// 00:00:00 11/15/2001
xbox_epoch_tm.tm_year = 2001 - 1900; // tm is years since 1900
xbox_epoch_tm.tm_mon = 10; // November = month 10
xbox_epoch_tm.tm_mday = 15; // 15th
// 19:53:47 09/17/2036
xbox_anti_epoch_tm.tm_year = 2036 - 1900; // tm is years since 1900
xbox_anti_epoch_tm.tm_mon = 8; // September = month 9
xbox_anti_epoch_tm.tm_mday = 17; // 17th
//xbox_anti_epoch_tm.tm_hour = 19;
//xbox_anti_epoch_tm.tm_min = 53;
//xbox_anti_epoch_tm.tm_sec = 46;
GetRTCDate();
// Load current date into editable field
time_t decoded_rtc = decode_smc_rtc(m_SMCEditable);
gmtime_s(&temp_tm, &decoded_rtc);
return S_OK;
}
HRESULT Lightshow::Update() {
// Get the current gamepad status
m_pGamepad = ATG::Input::GetMergedInput();
// Update selected selected_field (0-5); MM/DD/YYYY HH:mm:ss
if (m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_DPAD_LEFT || m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ) {
selected_field--;
if (selected_field < 0) {
selected_field = 5;
}
}
else if (m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_DPAD_RIGHT || m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ) {
selected_field++;
}
selected_field = selected_field % 6;
// Increment/decrement selected field; MM/DD/YYYY HH:mm:ss
if (m_pGamepad->sThumbLY > LEFT_THUMB_DEADZONE || m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_DPAD_UP || m_pGamepad->bRightTrigger) {
switch(selected_field){
case 0: //MM
temp_tm.tm_mon++;
break;
case 1: //DD
temp_tm.tm_mday++;
break;
case 2: //YYYY
temp_tm.tm_year++;
break;
case 3: //HH
temp_tm.tm_hour++;
break;
case 4: //mm
temp_tm.tm_min++;
break;
case 5: //ss
temp_tm.tm_sec++;
break;
default:
selected_field = 0;
break;
}
}
else if (m_pGamepad->sThumbLY < -LEFT_THUMB_DEADZONE || m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_DPAD_DOWN || m_pGamepad->bLeftTrigger ) {
switch(selected_field){
case 0: //MM
temp_tm.tm_mon--;
break;
case 1: //DD
temp_tm.tm_mday--;
break;
case 2: //YYYY
temp_tm.tm_year--;
break;
case 3: //HH
temp_tm.tm_hour--;
break;
case 4: //mm
temp_tm.tm_min--;
break;
case 5: //ss
temp_tm.tm_sec--;
break;
default:
selected_field = 0;
break;
}
}
// Check that it's after the Xbox epoch - 00:00:00 11/15/2001
if ( (temp_tm.tm_year < 101) ||
(temp_tm.tm_year == 101 && temp_tm.tm_mon < 10) ||
(temp_tm.tm_year == 101 && temp_tm.tm_mon == 10 && temp_tm.tm_mday < 15) ) {
//printf("\nDate before Xbox epoch, resetting to epoch");
temp_tm = xbox_epoch_tm;
}
// Check that it's before the Xbox anti-epoch - 19:53:47 09/17/2036
if ( (temp_tm.tm_year > 136) ||
(temp_tm.tm_year == 136 && temp_tm.tm_mon > 8) ||
(temp_tm.tm_year == 136 && temp_tm.tm_mon == 8 && temp_tm.tm_mday >= 17) ) {
//printf("\nDate after Xbox anti-epoch, resetting to anti-epoch");
temp_tm = xbox_anti_epoch_tm;
temp_tm.tm_mday--;
}
// Normalize overflow/underflows, 6:6:6 if error
if (mktime(&temp_tm) == (time_t)-1) {
temp_tm.tm_hour = 6;
temp_tm.tm_min = 6;
temp_tm.tm_sec = 6;
}
if( ( m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_A ) || ( m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_START ) ) {
// Set to chosen time
unsigned char encoded_bytes[8];
// Convert temp_tm into bytes
time_t edited_time = _mkgmtime(&temp_tm);
encode_smc_rtc(edited_time, encoded_bytes);
memcpy(m_SMCEditable, &encoded_bytes, sizeof(uint64_t));
SetRTCDate();
ShowTextForSeconds(L"Time has been set", 5);
}
else if( m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_B ) {
// Reboot
HalReturnToFirmware(6);
}
/*
else if( ( m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_X ) ) {
// Set to test time
uint64_t timestamp = 0x8500FEFFFFFF0100ULL; // Right before anti-epoch
memcpy(m_SMCEditable, ×tamp, sizeof(uint64_t));
SetRTCDate();
}
else if( ( m_pGamepad->wPressedButtons & XINPUT_GAMEPAD_Y ) ) {
// Get current time
GetRTCDate();
}
*/
return S_OK;
}
HRESULT Lightshow::DrawTextContent() {
D3DRECT rc = m_Font16.m_rcWindow;
//// BIG TEXT
m_Font16.Begin();
m_Font16.DrawText( ( rc.x2 - rc.x1 ) / 2.0f, 50, 0xffffffff, L"Time Fixer", ATGFONT_CENTER_X );
// Print current ticks to debug
//printf("\nCurrent time:");
//printf("%02X%02X%02X%02X%02X%02X%02X%02X\n", (unsigned char)m_SMCEditable[0], (unsigned char)m_SMCEditable[1], (unsigned char)m_SMCEditable[2], (unsigned char)m_SMCEditable[3], (unsigned char)m_SMCEditable[4], (unsigned char)m_SMCEditable[5], (unsigned char)m_SMCEditable[6], (unsigned char)m_SMCEditable[7]);
// Print current ticks to screen
//sprintf_s(print_buffer, sizeof(print_buffer), "%02X %02X %02X %02X %02X %02X %02X %02X", m_SMCEditable[0], m_SMCEditable[1], m_SMCEditable[2], m_SMCEditable[3], m_SMCEditable[4], m_SMCEditable[5], m_SMCEditable[6], m_SMCEditable[7]);
//mbstowcs(wide_print_buffer, print_buffer, 32);
//m_Font16.DrawText( ( rc.x2 - rc.x1 ) / 2.0f, 400, 0xffffffff, wide_print_buffer, ATGFONT_CENTER_X );
// Print current MM:DD:YYYY HH:mm:ss to debug
//time_t decoded_rtc = decode_smc_rtc(m_SMCEditable);
//gmtime_s(&temp_tm, &decoded_rtc);
//printf("Decoded UTC = %04d-%02d-%02d %02d:%02d:%02d\n",
// temp_tm.tm_year + 1900, temp_tm.tm_mon + 1, temp_tm.tm_mday,
// temp_tm.tm_hour, temp_tm.tm_min, temp_tm.tm_sec);
// Print current MM:DD:YYYY HH:mm:ss to screen
//sprintf_s(print_buffer, sizeof(print_buffer), "Decoded UTC = %04d-%02d-%02d %02d:%02d:%02d",
// temp_tm.tm_year + 1900, temp_tm.tm_mon + 1, temp_tm.tm_mday,
// temp_tm.tm_hour, temp_tm.tm_min, temp_tm.tm_sec);
//Month (MM)
sprintf_s(print_buffer, sizeof(print_buffer), "%02d", temp_tm.tm_mon + 1);
mbstowcs(wide_print_buffer, print_buffer, 64);
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 150, 120, 0xffffffff, wide_print_buffer, ATGFONT_RIGHT );
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 135, 120, 0xffffffff, L"/", ATGFONT_RIGHT );
//Day (DD)
sprintf_s(print_buffer, sizeof(print_buffer), "%02d", temp_tm.tm_mday);
mbstowcs(wide_print_buffer, print_buffer, 64);
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 105, 120, 0xffffffff, wide_print_buffer, ATGFONT_RIGHT );
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 90, 120, 0xffffffff, L"/", ATGFONT_RIGHT );
//Year (YYYY)
sprintf_s(print_buffer, sizeof(print_buffer), "%04d", temp_tm.tm_year + 1900);
mbstowcs(wide_print_buffer, print_buffer, 64);
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 35, 120, 0xffffffff, wide_print_buffer, ATGFONT_RIGHT );
//Hour (HH)
sprintf_s(print_buffer, sizeof(print_buffer), "%02d", temp_tm.tm_hour);
mbstowcs(wide_print_buffer, print_buffer, 64);
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 50, 120, 0xffffffff, wide_print_buffer, ATGFONT_RIGHT );
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 60, 120, 0xffffffff, L":", ATGFONT_RIGHT );
//Minute (mm)
sprintf_s(print_buffer, sizeof(print_buffer), "%02d", temp_tm.tm_min);
mbstowcs(wide_print_buffer, print_buffer, 64);
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 85, 120, 0xffffffff, wide_print_buffer, ATGFONT_RIGHT );
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 95, 120, 0xffffffff, L":", ATGFONT_RIGHT );
//Second (SS)
sprintf_s(print_buffer, sizeof(print_buffer), "%02d", temp_tm.tm_sec);
mbstowcs(wide_print_buffer, print_buffer, 64);
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 120, 120, 0xffffffff, wide_print_buffer, ATGFONT_RIGHT );
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 175, 120, 0xffffffff, L"UTC", ATGFONT_RIGHT );
//Underline selected field
switch(selected_field){
case 0: //MM
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 150, 125, 0xffffffff, L"__", ATGFONT_RIGHT );
break;
case 1: //DD
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 105, 125, 0xffffffff, L"__", ATGFONT_RIGHT );
break;
case 2: //YYYY
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) - 35, 125, 0xffffffff, L"____", ATGFONT_RIGHT );
break;
case 3: //HH
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 50, 125, 0xffffffff, L"__", ATGFONT_RIGHT );
break;
case 4: //mm
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 85, 125, 0xffffffff, L"__", ATGFONT_RIGHT );
break;
case 5: //ss
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f) + 120, 125, 0xffffffff, L"__", ATGFONT_RIGHT );
break;
default:
selected_field = 0;
break;
}
// Temporary message printed to screen
if (show_text) {
// Compute time elapsed since start of showing text
LARGE_INTEGER freq, counter;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&counter);
float now = (float)counter.QuadPart / (float)freq.QuadPart;
float elapsed = now - text_start_time;
// Hide after 5 seconds
if (elapsed < text_duration) {
m_Font16.DrawText( (( rc.x2 - rc.x1 ) / 2.0f), 350, 0xffffffff, status_message, ATGFONT_CENTER_X );
}
else {
show_text = false;
}
}
m_Font16.End();
//// SMALL TEXT
m_Font12.Begin();
m_Font12.DrawText( ( rc.x2 - rc.x1 ) / 2.0f - 160, 200, 0xffffffff, L"DPAD Left / Right or LB / RB to choose field\nDPAD Up / Down or LT / RT to change time\nPress (A) to save the chosen time\nPress (B) to reboot\n\nReboot is required for change to take effect.", ATGFONT_LEFT );
m_Font12.DrawText( rc.x1 - 200.0f, rc.y2 - 100.0f, 0xffffffff, L"Made by Derf\nConsoleMods.org", ATGFONT_LEFT );
m_Font12.End();
return S_OK;
}
HRESULT Lightshow::Render() {
ATG::RenderBackground( 0x00000000, 0x00000000 ); //Black
DrawTextContent();
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
return S_OK;
}
void PrepareBuffers() {
ZeroMemory( m_SMCMessage, sizeof(m_SMCMessage) );
ZeroMemory( m_SMCReturn, sizeof(m_SMCReturn) );
}
void GetRTCDate() {
PrepareBuffers();
m_SMCMessage[0] = 0x04; //read clock
HalSendSMCMessage(m_SMCMessage, m_SMCReturn);
/*
printf("\nCurrent time:", m_SMCReturn);
printf("%02X%02X%02X%02X%02X%02X%02X%02X\n", (unsigned char)m_SMCReturn[0], (unsigned char)m_SMCReturn[1], (unsigned char)m_SMCReturn[2], (unsigned char)m_SMCReturn[3], (unsigned char)m_SMCReturn[4], (unsigned char)m_SMCReturn[5], (unsigned char)m_SMCReturn[6], (unsigned char)m_SMCReturn[7]);
for (int i=0; i<8; i++) {
printf("m_SMCReturn[%d] = %02X\n", i, (unsigned char)m_SMCReturn[i]);
}*/
memcpy(&m_SMCEditable, m_SMCReturn, sizeof(m_SMCEditable));
}
void SetRTCDate() {
PrepareBuffers();
memcpy(m_SMCMessage, &m_SMCEditable, sizeof(m_SMCEditable));
m_SMCMessage[0] = 0x85; //set clock
//printf("\nAbout to send:");
//printf("%02X%02X%02X%02X%02X%02X%02X%02X\n", (unsigned char)m_SMCMessage[0], (unsigned char)m_SMCMessage[1], (unsigned char)m_SMCMessage[2], (unsigned char)m_SMCMessage[3], (unsigned char)m_SMCMessage[4], (unsigned char)m_SMCMessage[5], (unsigned char)m_SMCMessage[6], (unsigned char)m_SMCMessage[7]);
HalSendSMCMessage(m_SMCMessage, NULL);
GetRTCDate();
}
int hex_to_bytes(const char *hex, unsigned char *out, size_t max_len) {
size_t len = 0;
while (*hex && hex[1]) {
if (len >= max_len) {
return -1;
}
char c1 = *hex++;
char c2 = *hex++;
if (!isxdigit(c1) || !isxdigit(c2)) {
return -2;
}
unsigned char b =
((isdigit(c1) ? c1 - '0' : (toupper(c1) - 'A' + 10)) << 4) |
(isdigit(c2) ? c2 - '0' : (toupper(c2) - 'A' + 10));
out[len++] = b;
}
return (int)len;
}
time_t decode_smc_rtc(const unsigned char *data) {
uint64_t ticks =
((uint64_t)(unsigned)data[1]) |
((uint64_t)(unsigned)data[2] << 8) |
((uint64_t)(unsigned)data[3] << 16) |
((uint64_t)(unsigned)data[4] << 24) |
((uint64_t)(unsigned)data[5] << 32);
uint64_t seconds = ticks / TICK_RATE;
//printf("Decoded seconds = %ld\n", (long)seconds);
time_t xbox_epoch = _mkgmtime(&xbox_epoch_tm);
return xbox_epoch + (time_t)seconds;
}
void encode_smc_rtc(time_t t, unsigned char out[7]) {
time_t xbox_epoch = _mkgmtime(&xbox_epoch_tm);
if (t < xbox_epoch) {
//printf("Date is before Xbox epoch!\n");
return;
}
uint64_t delta_sec = (uint64_t)(t - xbox_epoch);
uint64_t ticks = delta_sec * TICK_RATE;
if (ticks > MAX_TICKS) {
//printf("Date exceeds 40-bit tick limit!\n");
return;
}
// Output packet
out[0] = 0x04; // Command = query date
out[1] = (ticks) & 0xFF; // Tick - Least significant byte
out[2] = (ticks >> 8) & 0xFF; // Tick
out[3] = (ticks >> 16) & 0xFF; // Tick
out[4] = (ticks >> 24) & 0xFF; // Tick
out[5] = (ticks >> 32) & 0xFF; // Tick - Most significant byte
out[6] = 0x01; // In sync; should always be true
out[7] = 0x00; // Reserved?
}
void ShowTextForSeconds(const wchar_t* message, float seconds) {
show_text = true;
wcsncpy(status_message, message, 255);
LARGE_INTEGER freq, counter;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&counter);
text_start_time = (float)counter.QuadPart / (float)freq.QuadPart;
text_duration = seconds;
}