6.3.0.9 Add dynamic delay in loop

6.3.0.9 20181118
 * Moved command SetSensorXX to debugging driver freeing user code space
 * Add dynamic delay to main loop providing time for wifi background tasks
 * Remove delays introduced in 6.3.0.1 (#4233)
This commit is contained in:
Theo Arends 2018-11-18 15:02:52 +01:00
parent 61b8586384
commit 18997e841f
9 changed files with 380 additions and 314 deletions

View File

@ -1,4 +1,9 @@
/* 6.3.0.8 20181115
/* 6.3.0.9 20181118
* Moved command SetSensorXX to debugging driver freeing user code space
* Add dynamic delay to main loop providing time for wifi background tasks
* Remove delays introduced in 6.3.0.1 (#4233)
*
* 6.3.0.8 20181115
* Stop enforcing flashmode dout but it is still mandatory
* Moved bootcount update (being first) flash write to 10 seconds after restart
* Add support for Armtronix dimmers. See wiki for info (#4321)

View File

@ -184,7 +184,6 @@
#define D_CMND_DRIVER "Driver"
#define D_CMND_SAVEDATA "SaveData"
#define D_CMND_SETOPTION "SetOption"
#define D_CMND_SETSENSOR "SetSensor"
#define D_CMND_TEMPERATURE_RESOLUTION "TempRes"
#define D_CMND_HUMIDITY_RESOLUTION "HumRes"
#define D_CMND_PRESSURE_RESOLUTION "PressRes"

View File

@ -189,7 +189,8 @@ typedef unsigned long power_t; // Power (Relay) type
#define KNX_MAX_device_param 30
#define MAX_KNXTX_CMNDS 5
#define DRIVER_BOOT_DELAY 1 // Number of milliseconds to retard driver cycles during boot-up time to reduce overall CPU load whilst Wifi is connecting
#define DRIVER_BOOT_DELAY 1 // Number of milliseconds to retard driver cycles during boot-up time to reduce overall CPU load whilst Wifi is connecting
#define LOOP_SLEEP_DELAY 10 // Lowest number of milliseconds to go through the main loop using delay when needed
/*********************************************************************************************\
* Enumeration

View File

@ -81,7 +81,7 @@ enum TasmotaCommands {
CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE,
CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG,
CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_SETSENSOR,
CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE,
CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_TIMESTD, CMND_TIMEDST, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE,
CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, CMND_DRIVER };
const char kTasmotaCommands[] PROGMEM =
@ -91,7 +91,7 @@ const char kTasmotaCommands[] PROGMEM =
D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|"
D_CMND_COUNTERDEBOUNCE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|"
D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_SETSENSOR "|"
D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|"
D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|"
D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER "|" D_CMND_DRIVER;
@ -777,13 +777,6 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, (2 == ptype) ? stemp1 : (1 == ptype) ? GetStateText(bitRead(Settings.flag3.data, pindex)) : GetStateText(bitRead(Settings.flag.data, pindex)));
}
}
else if ((CMND_SETSENSOR == command_code) && (index < MAX_XSNS_DRIVERS)) {
if ((payload >= 0) && XsnsPresent(index)) {
bitWrite(Settings.sensors[index / 32], index % 32, payload &1);
if (1 == payload) { restart_flag = 2; } // To safely re-enable a sensor currently most sensor need to follow complete restart init cycle
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_XVALUE, command, XsnsGetSensors().c_str());
}
else if (CMND_TEMPERATURE_RESOLUTION == command_code) {
if ((payload >= 0) && (payload <= 3)) {
Settings.flag2.temperature_resolution = payload;
@ -2753,6 +2746,8 @@ void setup(void)
void loop(void)
{
uint32_t my_sleep = millis();
XdrvCall(FUNC_LOOP);
OsWatchLoop();
@ -2791,6 +2786,9 @@ void loop(void)
while (arduino_ota_triggered) ArduinoOTA.handle();
#endif // USE_ARDUINO_OTA
// yield(); // yield == delay(0), delay contains yield, auto yield in loop
// yield(); // yield == delay(0), delay contains yield, auto yield in loop
delay(sleep); // https://github.com/esp8266/Arduino/issues/2021
uint32_t my_activity = millis() - my_sleep;
if (my_activity < LOOP_SLEEP_DELAY) { delay(LOOP_SLEEP_DELAY - my_activity); } // Provide time for background tasks like wifi
}

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
#define VERSION 0x06030008
#define VERSION 0x06030009
#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"

View File

@ -1,5 +1,5 @@
/*
xdrv_95_debug.ino - debug support for Sonoff-Tasmota
xdrv_99_debug.ino - debug support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
@ -27,10 +27,12 @@
#ifdef USE_DEBUG_DRIVER
/*********************************************************************************************\
* Virtual debugging support
* Virtual debugging support - Part1
*
* Needs file zzzz_debug.ino due to DEFINE processing
\*********************************************************************************************/
#define XDRV_95 95
#define XDRV_99 99
#ifndef CPU_LOAD_CHECK
#define CPU_LOAD_CHECK 1 // Seconds between each CPU_LOAD log
@ -50,9 +52,15 @@
#define D_CMND_FREEMEM "FreeMem"
#define D_CMND_RTCDUMP "RtcDump"
#define D_CMND_HELP "Help"
#define D_CMND_SETSENSOR "SetSensor"
#define D_CMND_FLASHMODE "FlashMode"
enum DebugCommands { CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGSHOW, CMND_CFGXOR, CMND_CPUCHECK, CMND_EXCEPTION, CMND_FREEMEM, CMND_RTCDUMP, CMND_HELP };
const char kDebugCommands[] PROGMEM = D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGSHOW "|" D_CMND_CFGXOR "|" D_CMND_CPUCHECK "|" D_CMND_EXCEPTION "|" D_CMND_FREEMEM "|" D_CMND_RTCDUMP "|" D_CMND_HELP;
enum DebugCommands {
CMND_CFGDUMP, CMND_CFGPEEK, CMND_CFGPOKE, CMND_CFGSHOW, CMND_CFGXOR,
CMND_CPUCHECK, CMND_EXCEPTION, CMND_FREEMEM, CMND_RTCDUMP, CMND_SETSENSOR, CMND_FLASHMODE, CMND_HELP };
const char kDebugCommands[] PROGMEM =
D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" D_CMND_CFGSHOW "|" D_CMND_CFGXOR "|"
D_CMND_CPUCHECK "|" D_CMND_EXCEPTION "|" D_CMND_FREEMEM "|" D_CMND_RTCDUMP "|" D_CMND_SETSENSOR "|" D_CMND_FLASHMODE "|" D_CMND_HELP;
uint32_t CPU_loops = 0;
uint32_t CPU_last_millis = 0;
@ -406,6 +414,23 @@ void DebugCfgShow(uint8_t more)
}
}
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;
}
/*******************************************************************************************/
boolean DebugCommand(void)
@ -469,6 +494,19 @@ boolean DebugCommand(void)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, CPU_show_freemem);
}
else if ((CMND_SETSENSOR == command_code) && (XdrvMailbox.index < MAX_XSNS_DRIVERS)) {
if ((XdrvMailbox.payload >= 0) && XsnsPresent(XdrvMailbox.index)) {
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
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_XVALUE, command, XsnsGetSensors().c_str());
}
else if (CMND_FLASHMODE == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
SetFlashMode(XdrvMailbox.payload);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, ESP.getFlashChipMode());
}
else serviced = false; // Unknown command
return serviced;
@ -478,7 +516,7 @@ boolean DebugCommand(void)
* Interface
\*********************************************************************************************/
boolean Xdrv95(byte function)
boolean Xdrv99(byte function)
{
boolean result = false;

View File

@ -238,7 +238,7 @@ boolean XdrvCall(byte Function)
boolean result = false;
for (byte x = 0; x < xdrv_present; x++) {
AppDelay();
// AppDelay();
result = xdrv_func_ptr[x](Function);
if (result) break;
}

View File

@ -265,310 +265,22 @@ boolean (* const xsns_func_ptr[])(byte) = { // Sensor Function Pointers for sim
const uint8_t xsns_present = sizeof(xsns_func_ptr) / sizeof(xsns_func_ptr[0]); // Number of External Sensors found
uint8_t xsns_index = 0;
#ifdef XFUNC_PTR_IN_ROM
const uint8_t kXsnsList[] PROGMEM = {
#else
const uint8_t kXsnsList[] = {
#endif
#ifdef XSNS_01
XSNS_01,
#endif
#ifdef XSNS_02
XSNS_02,
#endif
#ifdef XSNS_03
XSNS_03,
#endif
#ifdef XSNS_04
XSNS_04,
#endif
#ifdef XSNS_05
XSNS_05,
#endif
#ifdef XSNS_06
XSNS_06,
#endif
#ifdef XSNS_07
XSNS_07,
#endif
#ifdef XSNS_08
XSNS_08,
#endif
#ifdef XSNS_09
XSNS_09,
#endif
#ifdef XSNS_10
XSNS_10,
#endif
#ifdef XSNS_11
XSNS_11,
#endif
#ifdef XSNS_12
XSNS_12,
#endif
#ifdef XSNS_13
XSNS_13,
#endif
#ifdef XSNS_14
XSNS_14,
#endif
#ifdef XSNS_15
XSNS_15,
#endif
#ifdef XSNS_16
XSNS_16,
#endif
#ifdef XSNS_17
XSNS_17,
#endif
#ifdef XSNS_18
XSNS_18,
#endif
#ifdef XSNS_19
XSNS_19,
#endif
#ifdef XSNS_20
XSNS_20,
#endif
#ifdef XSNS_21
XSNS_21,
#endif
#ifdef XSNS_22
XSNS_22,
#endif
#ifdef XSNS_23
XSNS_23,
#endif
#ifdef XSNS_24
XSNS_24,
#endif
#ifdef XSNS_25
XSNS_25,
#endif
#ifdef XSNS_26
XSNS_26,
#endif
#ifdef XSNS_27
XSNS_27,
#endif
#ifdef XSNS_28
XSNS_28,
#endif
#ifdef XSNS_29
XSNS_29,
#endif
#ifdef XSNS_30
XSNS_30,
#endif
#ifdef XSNS_31
XSNS_31,
#endif
#ifdef XSNS_32
XSNS_32,
#endif
#ifdef XSNS_33
XSNS_33,
#endif
#ifdef XSNS_34
XSNS_34,
#endif
#ifdef XSNS_35
XSNS_35,
#endif
#ifdef XSNS_36
XSNS_36,
#endif
#ifdef XSNS_37
XSNS_37,
#endif
#ifdef XSNS_38
XSNS_38,
#endif
#ifdef XSNS_39
XSNS_39,
#endif
#ifdef XSNS_40
XSNS_40,
#endif
#ifdef XSNS_41
XSNS_41,
#endif
#ifdef XSNS_42
XSNS_42,
#endif
#ifdef XSNS_43
XSNS_43,
#endif
#ifdef XSNS_44
XSNS_44,
#endif
#ifdef XSNS_45
XSNS_45,
#endif
#ifdef XSNS_46
XSNS_46,
#endif
#ifdef XSNS_47
XSNS_47,
#endif
#ifdef XSNS_48
XSNS_48,
#endif
#ifdef XSNS_49
XSNS_49,
#endif
#ifdef XSNS_50
XSNS_50,
#endif
// Optional user defined sensors in range 91 - 99
#ifdef XSNS_91
XSNS_91,
#endif
#ifdef XSNS_92
XSNS_92,
#endif
#ifdef XSNS_93
XSNS_93,
#endif
#ifdef XSNS_94
XSNS_94,
#endif
#ifdef XSNS_95
XSNS_95,
#endif
#ifdef XSNS_96
XSNS_96,
#endif
#ifdef XSNS_97
XSNS_97,
#endif
#ifdef XSNS_98
XSNS_98,
#endif
#ifdef XSNS_99
XSNS_99
#endif
};
/*********************************************************************************************\
* Function call to all xsns
\*********************************************************************************************/
boolean XsnsEnabled(byte sns_index)
{
if (sns_index < sizeof(kXsnsList)) {
#ifdef XFUNC_PTR_IN_ROM
uint8_t index = pgm_read_byte(kXsnsList + sns_index);
#else
uint8_t index = kXsnsList[sns_index];
#endif
return bitRead(Settings.sensors[index / 32], index % 32);
}
return 1;
}
boolean XsnsPresent(byte sns_index)
{
uint8_t index = 0;
for (byte i = 0; i < sizeof(kXsnsList); i++) {
#ifdef XFUNC_PTR_IN_ROM
index = pgm_read_byte(kXsnsList + i);
#else
index = kXsnsList[i];
#endif
if (index == sns_index) { return true; }
}
return false;
}
String XsnsGetSensors(void)
{
char state[2] = { 0 };
String data = F("[");
for (byte i = 0; i < MAX_XSNS_DRIVERS; i++) {
if (i && (!(i % 16))) { data += F(","); }
if (!(i % 16)) { data += F("\""); }
state[0] = '-';
if (XsnsPresent(i)) { state[0] = bitRead(Settings.sensors[i / 32], i % 32) ? '1' : '0'; }
data += String(state);
if (i && (!((i +1) % 16))) { data += F("\""); }
}
data += F("]");
return data;
}
boolean XsnsNextCall(byte Function)
{
xsns_index++;
if (xsns_index == xsns_present) { xsns_index = 0; }
#ifdef USE_DEBUG_DRIVER
while (!XsnsEnabled(xsns_index) && !xsns_index) { // Perform at least first sensor (counter)
xsns_index++;
if (xsns_index == xsns_present) { xsns_index = 0; }
}
AppDelay();
#endif
// AppDelay();
return xsns_func_ptr[xsns_index](Function);
}
@ -581,12 +293,14 @@ boolean XsnsCall(byte Function)
#endif // PROFILE_XSNS_EVERY_SECOND
for (byte x = 0; x < xsns_present; x++) {
#ifdef USE_DEBUG_DRIVER
if (XsnsEnabled(x)) {
#endif
#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND
uint32_t profile_start_millis = millis();
#endif // PROFILE_XSNS_SENSOR_EVERY_SECOND
AppDelay();
// AppDelay();
result = xsns_func_ptr[x](Function);
#ifdef PROFILE_XSNS_SENSOR_EVERY_SECOND
@ -600,7 +314,9 @@ boolean XsnsCall(byte Function)
#endif // PROFILE_XSNS_SENSOR_EVERY_SECOND
if (result) break;
#ifdef USE_DEBUG_DRIVER
}
#endif
}
#ifdef PROFILE_XSNS_EVERY_SECOND

309
sonoff/zzzz_debug.ino Normal file
View File

@ -0,0 +1,309 @@
/*
zzzz_debug.ino - debug support for Sonoff-Tasmota
Copyright (C) 2018 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/>.
*/
#ifdef USE_DEBUG_DRIVER
/*********************************************************************************************\
* Virtual debugging support - Part 2
*
* Needs to be the last alphabetical file due to DEFINE compile order
\*********************************************************************************************/
/*********************************************************************************************\
* Xsns available list
\*********************************************************************************************/
#ifdef XFUNC_PTR_IN_ROM
const uint8_t kXsnsList[] PROGMEM = {
#else
const uint8_t kXsnsList[] = {
#endif
#ifdef XSNS_01
XSNS_01,
#endif
#ifdef XSNS_02
XSNS_02,
#endif
#ifdef XSNS_03
XSNS_03,
#endif
#ifdef XSNS_04
XSNS_04,
#endif
#ifdef XSNS_05
XSNS_05,
#endif
#ifdef XSNS_06
XSNS_06,
#endif
#ifdef XSNS_07
XSNS_07,
#endif
#ifdef XSNS_08
XSNS_08,
#endif
#ifdef XSNS_09
XSNS_09,
#endif
#ifdef XSNS_10
XSNS_10,
#endif
#ifdef XSNS_11
XSNS_11,
#endif
#ifdef XSNS_12
XSNS_12,
#endif
#ifdef XSNS_13
XSNS_13,
#endif
#ifdef XSNS_14
XSNS_14,
#endif
#ifdef XSNS_15
XSNS_15,
#endif
#ifdef XSNS_16
XSNS_16,
#endif
#ifdef XSNS_17
XSNS_17,
#endif
#ifdef XSNS_18
XSNS_18,
#endif
#ifdef XSNS_19
XSNS_19,
#endif
#ifdef XSNS_20
XSNS_20,
#endif
#ifdef XSNS_21
XSNS_21,
#endif
#ifdef XSNS_22
XSNS_22,
#endif
#ifdef XSNS_23
XSNS_23,
#endif
#ifdef XSNS_24
XSNS_24,
#endif
#ifdef XSNS_25
XSNS_25,
#endif
#ifdef XSNS_26
XSNS_26,
#endif
#ifdef XSNS_27
XSNS_27,
#endif
#ifdef XSNS_28
XSNS_28,
#endif
#ifdef XSNS_29
XSNS_29,
#endif
#ifdef XSNS_30
XSNS_30,
#endif
#ifdef XSNS_31
XSNS_31,
#endif
#ifdef XSNS_32
XSNS_32,
#endif
#ifdef XSNS_33
XSNS_33,
#endif
#ifdef XSNS_34
XSNS_34,
#endif
#ifdef XSNS_35
XSNS_35,
#endif
#ifdef XSNS_36
XSNS_36,
#endif
#ifdef XSNS_37
XSNS_37,
#endif
#ifdef XSNS_38
XSNS_38,
#endif
#ifdef XSNS_39
XSNS_39,
#endif
#ifdef XSNS_40
XSNS_40,
#endif
#ifdef XSNS_41
XSNS_41,
#endif
#ifdef XSNS_42
XSNS_42,
#endif
#ifdef XSNS_43
XSNS_43,
#endif
#ifdef XSNS_44
XSNS_44,
#endif
#ifdef XSNS_45
XSNS_45,
#endif
#ifdef XSNS_46
XSNS_46,
#endif
#ifdef XSNS_47
XSNS_47,
#endif
#ifdef XSNS_48
XSNS_48,
#endif
#ifdef XSNS_49
XSNS_49,
#endif
#ifdef XSNS_50
XSNS_50,
#endif
// Optional user defined sensors in range 91 - 99
#ifdef XSNS_91
XSNS_91,
#endif
#ifdef XSNS_92
XSNS_92,
#endif
#ifdef XSNS_93
XSNS_93,
#endif
#ifdef XSNS_94
XSNS_94,
#endif
#ifdef XSNS_95
XSNS_95
#endif
};
/*********************************************************************************************\
* Xsns sensor control
\*********************************************************************************************/
boolean XsnsEnabled(byte sns_index)
{
if (sns_index < sizeof(kXsnsList)) {
#ifdef XFUNC_PTR_IN_ROM
uint8_t index = pgm_read_byte(kXsnsList + sns_index);
#else
uint8_t index = kXsnsList[sns_index];
#endif
return bitRead(Settings.sensors[index / 32], index % 32);
}
return 1;
}
boolean XsnsPresent(byte sns_index)
{
uint8_t index = 0;
for (byte i = 0; i < sizeof(kXsnsList); i++) {
#ifdef XFUNC_PTR_IN_ROM
index = pgm_read_byte(kXsnsList + i);
#else
index = kXsnsList[i];
#endif
if (index == sns_index) { return true; }
}
return false;
}
String XsnsGetSensors(void)
{
char state[2] = { 0 };
String data = F("[");
for (byte i = 0; i < MAX_XSNS_DRIVERS; i++) {
if (i && (!(i % 16))) { data += F(","); }
if (!(i % 16)) { data += F("\""); }
state[0] = '-';
if (XsnsPresent(i)) { state[0] = bitRead(Settings.sensors[i / 32], i % 32) ? '1' : '0'; }
data += String(state);
if (i && (!((i +1) % 16))) { data += F("\""); }
}
data += F("]");
return data;
}
#endif // USE_DEBUG_DRIVER