forked from arendst/Tasmota
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xdrv_99_debug.ino
643 lines (547 loc) · 20 KB
/
xdrv_99_debug.ino
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
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
/*
xdrv_99_debug.ino - debug support for Tasmota
Copyright (C) 2020 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#define USE_DEBUG_DRIVER
#ifdef DEBUG_THEO
#ifndef USE_DEBUG_DRIVER
#define USE_DEBUG_DRIVER
#endif // USE_DEBUG_DRIVER
#endif // DEBUG_THEO
#ifdef USE_DEBUG_DRIVER
/*********************************************************************************************\
* Virtual debugging support - Part1
*
* Needs file zzzz_debug.ino due to DEFINE processing
\*********************************************************************************************/
#define XDRV_99 99
#ifndef CPU_LOAD_CHECK
#define CPU_LOAD_CHECK 1 // Seconds between each CPU_LOAD log
#endif
/*********************************************************************************************\
* Debug commands
\*********************************************************************************************/
#define D_CMND_CFGDUMP "CfgDump"
#define D_CMND_CFGPEEK "CfgPeek"
#define D_CMND_CFGPOKE "CfgPoke"
#define D_CMND_CFGSHOW "CfgShow"
#define D_CMND_CFGXOR "CfgXor"
#define D_CMND_CPUCHECK "CpuChk"
#define D_CMND_EXCEPTION "Exception"
#define D_CMND_FLASHDUMP "FlashDump"
#define D_CMND_FLASHMODE "FlashMode"
#define D_CMND_FREEMEM "FreeMem"
#define D_CMND_HELP "Help"
#define D_CMND_RTCDUMP "RtcDump"
#define D_CMND_SETSENSOR "SetSensor"
#define D_CMND_I2CWRITE "I2CWrite"
#define D_CMND_I2CREAD "I2CRead"
#define D_CMND_I2CSTRETCH "I2CStretch"
#define D_CMND_I2CCLOCK "I2CClock"
const char kDebugCommands[] PROGMEM = "|" // No prefix
D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|"
#ifdef USE_WEBSERVER
D_CMND_CFGXOR "|"
#endif
D_CMND_CPUCHECK "|"
#ifdef DEBUG_THEO
D_CMND_EXCEPTION "|"
#endif
D_CMND_FLASHDUMP "|" D_CMND_FLASHMODE "|" D_CMND_FREEMEM"|" D_CMND_HELP "|" D_CMND_RTCDUMP "|" D_CMND_SETSENSOR "|"
#ifdef USE_I2C
D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK
#endif
;
void (* const DebugCommand[])(void) PROGMEM = {
&CmndCfgDump, &CmndCfgPeek, &CmndCfgPoke,
#ifdef USE_WEBSERVER
&CmndCfgXor,
#endif
&CmndCpuCheck,
#ifdef DEBUG_THEO
&CmndException,
#endif
&CmndFlashDump, &CmndFlashMode, &CmndFreemem, &CmndHelp, &CmndRtcDump, &CmndSetSensor,
#ifdef USE_I2C
&CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock
#endif
};
uint32_t CPU_loops = 0;
uint32_t CPU_last_millis = 0;
uint32_t CPU_last_loop_time = 0;
uint8_t CPU_load_check = 0;
uint8_t CPU_show_freemem = 0;
/*******************************************************************************************/
#ifdef DEBUG_THEO
void ExceptionTest(uint8_t type)
{
/*
Exception (28):
epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000007 depc=0x00000000
ctx: cont
sp: 3fff1f30 end: 3fff2840 offset: 01a0
>>>stack>>>
3fff20d0: 202c3573 756f7247 2c302070 646e4920
3fff20e0: 40236a6e 7954202c 45206570 00454358
3fff20f0: 00000010 00000007 00000000 3fff2180
3fff2100: 3fff2190 40107bfc 3fff3e4c 3fff22c0
3fff2110: 40261934 000000f0 3fff22c0 401004d8
3fff2120: 40238fcf 00000050 3fff2100 4021fc10
3fff2130: 3fff32bc 4021680c 3ffeade1 4021ff7d
3fff2140: 3fff2190 3fff2180 0000000c 7fffffff
3fff2150: 00000019 00000000 00000000 3fff21c0
3fff2160: 3fff23f3 3ffe8e08 00000000 4021ffb4
3fff2170: 3fff2190 3fff2180 0000000c 40201118
3fff2180: 3fff21c0 0000003c 3ffef840 00000007
3fff2190: 00000000 00000000 00000000 40201128
3fff21a0: 3fff23f3 000000f1 3fff23ec 4020fafb
3fff21b0: 3fff23f3 3fff21c0 3fff21d0 3fff23f6
3fff21c0: 00000000 3fff23fb 4022321b 00000000
Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
Decoding 14 results
0x40236a6e: ets_vsnprintf at ?? line ?
0x40107bfc: vsnprintf at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/libc_replacements.c line 387
0x40261934: bignum_exptmod at ?? line ?
0x401004d8: malloc at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664
0x40238fcf: wifi_station_get_connect_status at ?? line ?
0x4021fc10: operator new[](unsigned int) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/abi.cpp line 57
0x4021680c: ESP8266WiFiSTAClass::status() at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.cpp line 569
0x4021ff7d: vsnprintf_P(char*, unsigned int, char const*, __va_list_tag) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
0x4021ffb4: snprintf_P(char*, unsigned int, char const*, ...) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
0x40201118: atol at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
0x40201128: atoi at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
00:00:08 MQTT: tele/tasmota/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"}
*/
if (1 == type) {
char svalue[10];
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr)
}
/*
14:50:52 osWatch: FreeRam 25896, rssi 68, last_run 0
14:51:02 osWatch: FreeRam 25896, rssi 58, last_run 0
14:51:03 CMND: exception 2
14:51:12 osWatch: FreeRam 25360, rssi 60, last_run 8771
14:51:22 osWatch: FreeRam 25360, rssi 62, last_run 18771
14:51:32 osWatch: FreeRam 25360, rssi 62, last_run 28771
14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771
14:51:42 osWatch: Warning, loop blocked. Restart now
*/
if (2 == type) {
while(1) delay(1000); // this will trigger the os watch
}
}
#endif // DEBUG_THEO
/*******************************************************************************************/
void CpuLoadLoop(void)
{
CPU_last_loop_time = millis();
if (CPU_load_check && CPU_last_millis) {
CPU_loops ++;
if ((CPU_last_millis + (CPU_load_check *1000)) <= CPU_last_loop_time) {
#if defined(F_CPU) && (F_CPU == 160000000L)
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *800) );
CPU_loops = CPU_loops / CPU_load_check;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(160MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#else
int CPU_load = 100 - ( (CPU_loops*(1 + 30*sleep)) / (CPU_load_check *400) );
CPU_loops = CPU_loops / CPU_load_check;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, CPU %d%%(80MHz), Loops/sec %d"), ESP.getFreeHeap(), CPU_load, CPU_loops);
#endif
CPU_last_millis = CPU_last_loop_time;
CPU_loops = 0;
}
}
}
/*******************************************************************************************/
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1)
// All version before core 2.4.2
// https://github.com/esp8266/Arduino/issues/2557
extern "C" {
#include <cont.h>
extern cont_t g_cont;
}
void DebugFreeMem(void)
{
register uint32_t *sp asm("a1");
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d, UnmodifiedStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_cont.stack), cont_get_free_stack(&g_cont), XdrvMailbox.data);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_cont.stack), XdrvMailbox.data);
}
#else
// All version from core 2.4.2
// https://github.com/esp8266/Arduino/pull/5018
// https://github.com/esp8266/Arduino/pull/4553
extern "C" {
#include <cont.h>
extern cont_t* g_pcont;
}
void DebugFreeMem(void)
{
register uint32_t *sp asm("a1");
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_pcont->stack), XdrvMailbox.data);
}
#endif // ARDUINO_ESP8266_RELEASE_2_x_x
/*******************************************************************************************/
void DebugRtcDump(char* parms)
{
#define CFG_COLS 16
uint16_t idx;
uint16_t maxrow;
uint16_t row;
uint16_t col;
char *p;
// |<--SDK data (256 bytes)-->|<--User data (512 bytes)-->|
// 000 - 0FF: SDK
// 000 - 01B: SDK rst_info
// 100 - 2FF: User
// 280 - 283: Tasmota RtcReboot (Offset 100 (x 4bytes) - sizeof(RTCRBT) (x 4bytes))
// 290 - 2EB: Tasmota RtcSettings (Offset 100 (x 4bytes))
uint8_t buffer[768];
// ESP.rtcUserMemoryRead(0, (uint32_t*)&buffer, sizeof(buffer));
system_rtc_mem_read(0, (uint32_t*)&buffer, sizeof(buffer));
maxrow = ((sizeof(buffer)+CFG_COLS)/CFG_COLS);
uint16_t srow = strtol(parms, &p, 16) / CFG_COLS;
uint16_t mrow = strtol(p, &p, 10);
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow);
if (0 == mrow) { // Default only 8 lines
mrow = 8;
}
if (srow > maxrow) {
srow = maxrow - mrow;
}
if (mrow < (maxrow - srow)) {
maxrow = srow + mrow;
}
for (row = srow; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (col = 0; col < CFG_COLS; col++) {
// if (!(col%4)) {
// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
// }
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
}
}
/*******************************************************************************************/
void DebugCfgDump(char* parms)
{
#define CFG_COLS 16
uint16_t idx;
uint16_t maxrow;
uint16_t row;
uint16_t col;
char *p;
uint8_t *buffer = (uint8_t *) &Settings;
maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS);
uint16_t srow = strtol(parms, &p, 16) / CFG_COLS;
uint16_t mrow = strtol(p, &p, 10);
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow);
if (0 == mrow) { // Default only 8 lines
mrow = 8;
}
if (srow > maxrow) {
srow = maxrow - mrow;
}
if (mrow < (maxrow - srow)) {
maxrow = srow + mrow;
}
for (row = srow; row < maxrow; row++) {
idx = row * CFG_COLS;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), idx);
for (col = 0; col < CFG_COLS; col++) {
if (!(col%4)) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[idx + col]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (col = 0; col < CFG_COLS; col++) {
// if (!(col%4)) {
// snprintf_P(log_data, sizeof(log_data), PSTR("%s "), log_data);
// }
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s|"), log_data);
AddLog(LOG_LEVEL_INFO);
delay(1);
}
}
void DebugCfgPeek(char* parms)
{
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
address = (address >> 2) << 2;
uint8_t *buffer = (uint8_t *) &Settings;
uint8_t data8 = buffer[address];
uint16_t data16 = (buffer[address +1] << 8) + buffer[address];
uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + data16;
snprintf_P(log_data, sizeof(log_data), PSTR("%03X:"), address);
for (uint32_t i = 0; i < 4; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, buffer[address +i]);
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s |"), log_data);
for (uint32_t i = 0; i < 4; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s%c"), log_data, ((buffer[address +i] > 0x20) && (buffer[address +i] < 0x7F)) ? (char)buffer[address +i] : ' ');
}
snprintf_P(log_data, sizeof(log_data), PSTR("%s| 0x%02X (%d), 0x%04X (%d), 0x%0LX (%lu)"), log_data, data8, data8, data16, data16, data32, data32);
AddLog(LOG_LEVEL_INFO);
}
void DebugCfgPoke(char* parms)
{
char *p;
uint16_t address = strtol(parms, &p, 16);
if (address > sizeof(SYSCFG)) address = sizeof(SYSCFG) -4;
address = (address >> 2) << 2;
uint32_t data = strtol(p, &p, 16);
uint8_t *buffer = (uint8_t *) &Settings;
uint32_t data32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address];
uint8_t *nbuffer = (uint8_t *) &data;
for (uint32_t i = 0; i < 4; i++) { buffer[address +i] = nbuffer[+i]; }
uint32_t ndata32 = (buffer[address +3] << 24) + (buffer[address +2] << 16) + (buffer[address +1] << 8) + buffer[address];
AddLog_P2(LOG_LEVEL_INFO, PSTR("%03X: 0x%0LX (%lu) poked to 0x%0LX (%lu)"), address, data32, data32, ndata32, ndata32);
}
void SetFlashMode(uint8_t mode)
{
uint8_t *_buffer;
uint32_t address;
address = 0;
_buffer = new uint8_t[FLASH_SECTOR_SIZE];
if (ESP.flashRead(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE)) {
if (_buffer[2] != mode) { // DOUT
_buffer[2] = mode;
if (ESP.flashEraseSector(address / FLASH_SECTOR_SIZE)) {
ESP.flashWrite(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE);
}
}
}
delete[] _buffer;
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
void CmndHelp(void)
{
AddLog_P(LOG_LEVEL_INFO, PSTR("HLP: "), kDebugCommands);
ResponseCmndDone();
}
void CmndRtcDump(void)
{
DebugRtcDump(XdrvMailbox.data);
ResponseCmndDone();
}
void CmndCfgDump(void)
{
DebugCfgDump(XdrvMailbox.data);
ResponseCmndDone();
}
void CmndCfgPeek(void)
{
DebugCfgPeek(XdrvMailbox.data);
ResponseCmndDone();
}
void CmndCfgPoke(void)
{
DebugCfgPoke(XdrvMailbox.data);
ResponseCmndDone();
}
#ifdef USE_WEBSERVER
void CmndCfgXor(void)
{
if (XdrvMailbox.data_len > 0) {
Web.config_xor_on_set = XdrvMailbox.payload;
}
ResponseCmndNumber(Web.config_xor_on_set);
}
#endif // USE_WEBSERVER
#ifdef DEBUG_THEO
void CmndException(void)
{
if (XdrvMailbox.data_len > 0) { ExceptionTest(XdrvMailbox.payload); }
ResponseCmndDone();
}
#endif // DEBUG_THEO
void CmndCpuCheck(void)
{
if (XdrvMailbox.data_len > 0) {
CPU_load_check = XdrvMailbox.payload;
CPU_last_millis = CPU_last_loop_time;
}
ResponseCmndNumber(CPU_load_check);
}
void CmndFreemem(void)
{
if (XdrvMailbox.data_len > 0) {
CPU_show_freemem = XdrvMailbox.payload;
}
ResponseCmndNumber(CPU_show_freemem);
}
void CmndSetSensor(void)
{
if (XdrvMailbox.index < MAX_XSNS_DRIVERS) {
if (XdrvMailbox.payload >= 0) {
bitWrite(Settings.sensors[XdrvMailbox.index / 32], XdrvMailbox.index % 32, XdrvMailbox.payload &1);
if (1 == XdrvMailbox.payload) {
restart_flag = 2; // To safely re-enable a sensor currently most sensor need to follow complete restart init cycle
}
}
Response_P(PSTR("{\"" D_CMND_SETSENSOR "\":"));
XsnsSensorState();
ResponseJsonEnd();
}
}
void CmndFlashMode(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
SetFlashMode(XdrvMailbox.payload);
}
ResponseCmndNumber(ESP.getFlashChipMode());
}
uint32_t DebugSwap32(uint32_t x) {
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
((x >> 8) & 0x0000ff00 ) |
((x >> 24) & 0x000000ff );
}
void CmndFlashDump(void)
{
// FlashDump
// FlashDump 0xFF000
// FlashDump 0xFC000 10
const uint32_t flash_start = 0x40200000; // Start address flash
const uint8_t bytes_per_cols = 0x20;
const uint32_t max = (SPIFFS_END + 5) * SPI_FLASH_SEC_SIZE; // 0x100000 for 1M flash, 0x400000 for 4M flash
uint32_t start = flash_start;
uint32_t rows = 8;
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= (max - bytes_per_cols))) {
start += (XdrvMailbox.payload &0x7FFFFFFC); // Fix exception as flash access is only allowed on 4 byte boundary
char *p;
uint32_t is_payload = strtol(XdrvMailbox.data, &p, 16);
rows = strtol(p, &p, 10);
if (0 == rows) { rows = 8; }
}
uint32_t end = start + (rows * bytes_per_cols);
if ((end - flash_start) > max) {
end = flash_start + max;
}
for (uint32_t pos = start; pos < end; pos += bytes_per_cols) {
uint32_t* values = (uint32_t*)(pos);
AddLog_P2(LOG_LEVEL_INFO, PSTR("%06X: %08X %08X %08X %08X %08X %08X %08X %08X"), pos - flash_start,
DebugSwap32(values[0]), DebugSwap32(values[1]), DebugSwap32(values[2]), DebugSwap32(values[3]),
DebugSwap32(values[4]), DebugSwap32(values[5]), DebugSwap32(values[6]), DebugSwap32(values[7]));
}
ResponseCmndDone();
}
#ifdef USE_I2C
void CmndI2cWrite(void)
{
// I2cWrite <address>,<data>..
if (i2c_flg) {
char* parms = XdrvMailbox.data;
uint8_t buffer[100];
uint32_t index = 0;
char *p;
char *data = strtok_r(parms, " ,", &p);
while (data != NULL && index < sizeof(buffer)) {
buffer[index++] = strtol(data, nullptr, 16);
data = strtok_r(nullptr, " ,", &p);
}
if (index > 1) {
AddLogBuffer(LOG_LEVEL_INFO, buffer, index);
Wire.beginTransmission(buffer[0]);
for (uint32_t i = 1; i < index; i++) {
Wire.write(buffer[i]);
}
int result = Wire.endTransmission();
AddLog_P2(LOG_LEVEL_INFO, PSTR("I2C: Result %d"), result);
}
}
ResponseCmndDone();
}
void CmndI2cRead(void)
{
// I2cRead <address>,<size>
if (i2c_flg) {
char* parms = XdrvMailbox.data;
uint8_t buffer[100];
uint32_t index = 0;
char *p;
char *data = strtok_r(parms, " ,", &p);
while (data != NULL && index < sizeof(buffer)) {
buffer[index++] = strtol(data, nullptr, 16);
data = strtok_r(nullptr, " ,", &p);
}
if (index > 0) {
uint8_t size = 1;
if (index > 1) {
size = buffer[1];
}
Wire.requestFrom(buffer[0], size);
index = 0;
while (Wire.available() && index < sizeof(buffer)) {
buffer[index++] = Wire.read();
}
if (index > 0) {
AddLogBuffer(LOG_LEVEL_INFO, buffer, index);
}
}
}
ResponseCmndDone();
}
void CmndI2cStretch(void)
{
if (i2c_flg && (XdrvMailbox.payload > 0)) {
Wire.setClockStretchLimit(XdrvMailbox.payload);
}
ResponseCmndDone();
}
void CmndI2cClock(void)
{
if (i2c_flg && (XdrvMailbox.payload > 0)) {
Wire.setClock(XdrvMailbox.payload);
}
ResponseCmndDone();
}
#endif // USE_I2C
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv99(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_LOOP:
CpuLoadLoop();
break;
case FUNC_FREE_MEM:
if (CPU_show_freemem) { DebugFreeMem(); }
break;
case FUNC_PRE_INIT:
CPU_last_millis = millis();
break;
case FUNC_COMMAND:
result = DecodeCommand(kDebugCommands, DebugCommand);
break;
}
return result;
}
#endif // USE_DEBUG_DRIVER