Version 1.1

See the new Usage.md for more information.  Bug fixes and changes, see Changes.md.
This commit is contained in:
GuruSR 2021-10-13 22:27:45 -04:00 committed by GitHub
parent cdcafa6d4d
commit ad17fd78e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 902 additions and 416 deletions

View File

@ -6,7 +6,7 @@
//display //display
#define SOFTWARE_VERSION_MAJOR 1 #define SOFTWARE_VERSION_MAJOR 1
#define SOFTWARE_VERSION_MINOR 0 #define SOFTWARE_VERSION_MINOR 1
#define SOFTWARE_VERSION_PATCH 0 #define SOFTWARE_VERSION_PATCH 0
#define HARDWARE_VERSION_MAJOR 1 #define HARDWARE_VERSION_MAJOR 1
#define HARDWARE_VERSION_MINOR 0 #define HARDWARE_VERSION_MINOR 0
@ -15,6 +15,11 @@
#define WiFi_AP_SSID "Watchy Connect" #define WiFi_AP_SSID "Watchy Connect"
#define WiFi_AP_PSWD "Watchy123" #define WiFi_AP_PSWD "Watchy123"
#define WiFi_AP_HIDE false #define WiFi_AP_HIDE false
#define WiFi_SSID_MAX 32
#define WiFi_PASS_MAX 63
// Use instead of Watchy Connect (if necessary)
#define WiFi_DEF_SSID ""
#define WiFi_DEF_PASS ""
// Battery // Battery
#define MinBattery 3.58 #define MinBattery 3.58
@ -54,22 +59,23 @@
#define MENU_ALARM2 5 #define MENU_ALARM2 5
#define MENU_ALARM3 6 #define MENU_ALARM3 6
#define MENU_ALARM4 7 #define MENU_ALARM4 7
#define MENU_TIMEDN 8 #define MENU_TONES 8
#define MENU_TIMEUP 9 #define MENU_TIMEDN 9
#define MENU_DISP 10 #define MENU_TIMEUP 10
#define MENU_BRDR 11 #define MENU_DISP 11
#define MENU_SIDE 12 #define MENU_BRDR 12
#define MENU_SWAP 13 #define MENU_SIDE 13
#define MENU_ORNT 14 #define MENU_SWAP 14
#define MENU_MODE 15 #define MENU_ORNT 15
#define MENU_FEED 16 #define MENU_MODE 16
#define MENU_TRBO 17 #define MENU_FEED 17
#define MENU_SCRN 18 #define MENU_TRBO 18
#define MENU_SYNC 19 #define MENU_SCRN 19
#define MENU_WIFI 20 #define MENU_SYNC 20
#define MENU_OTAU 21 #define MENU_WIFI 21
#define MENU_OTAM 22 #define MENU_OTAU 22
#define MENU_RSET 23 #define MENU_OTAM 23
#define MENU_RSET 24
// Menu segments. // Menu segments.
#define MENU_INNORMAL 0 #define MENU_INNORMAL 0

View File

@ -10,6 +10,19 @@ static const char UserAgent[] PROGMEM = "Watchy";
// AlarmVBs[] = {"0111111110", "0011001100", "0110110110", "0101001010"}; // AlarmVBs[] = {"0111111110", "0011001100", "0110110110", "0101001010"};
int AlarmVBs[] = {0x01FE, 0x00CC, 0x01B6, 0x014A}; int AlarmVBs[] = {0x01FE, 0x00CC, 0x01B6, 0x014A};
const uint16_t Bits[10] = {1,2,4,8,16,32,64,128,256,512}; const uint16_t Bits[10] = {1,2,4,8,16,32,64,128,256,512};
const float Reduce[5] = {1.0,0.8,0.6,0.4,0.2};
RTC_DATA_ATTR struct GSRWireless {
bool Requested; // Request WiFi.
bool Working; // Working on getting WiFi.
bool Results; // Results of WiFi, found an AP?
uint8_t Index; // 10 = built-in, roll backwards to 0.
struct APInfo {
char APID[33];
char PASS[64];
} AP[10]; // Using APID to avoid internal confusion with SSID.
unsigned long Last; // Used with millis() to maintain sanity.
} GSRWiFi;
RTC_DATA_ATTR struct Stepping { RTC_DATA_ATTR struct Stepping {
uint8_t Hour; uint8_t Hour;
@ -27,6 +40,7 @@ RTC_DATA_ATTR struct Optional {
bool Swapped; // Menu and Back buttons swap ends (vertically). bool Swapped; // Menu and Back buttons swap ends (vertically).
bool Orientated; // Set to false to not bother which way the buttons are. bool Orientated; // Set to false to not bother which way the buttons are.
uint8_t Turbo; // 0-10 seconds. uint8_t Turbo; // 0-10 seconds.
uint8_t MasterRepeats; // Done for ease, will be in the Alarms menu.
} Options; } Options;
RTC_DATA_ATTR int GuiMode; RTC_DATA_ATTR int GuiMode;
@ -54,6 +68,7 @@ RTC_DATA_ATTR struct Countdown {
uint8_t MaxMins; uint8_t MaxMins;
uint8_t Tone; // 10 to start. uint8_t Tone; // 10 to start.
uint8_t ToneLeft; // 30 to start. uint8_t ToneLeft; // 30 to start.
uint8_t MaxTones; // 0-4 (20-80%) tone duration reduction.
time_t LastUTC; time_t LastUTC;
} TimerDown; } TimerDown;
@ -117,6 +132,7 @@ RTC_DATA_ATTR uint8_t Alarms_Minutes[4];
RTC_DATA_ATTR uint16_t Alarms_Active[4]; // Bits 0-6 (days of week), 7 Repeat, 8 Active, 9 Tripped (meaning if it isn't repeating, don't fire). RTC_DATA_ATTR uint16_t Alarms_Active[4]; // Bits 0-6 (days of week), 7 Repeat, 8 Active, 9 Tripped (meaning if it isn't repeating, don't fire).
RTC_DATA_ATTR uint8_t Alarms_Times[4]; // Set to 10 to start, ends when zero. RTC_DATA_ATTR uint8_t Alarms_Times[4]; // Set to 10 to start, ends when zero.
RTC_DATA_ATTR uint8_t Alarms_Playing[4]; // Means the alarm tripped and it is to be played (goes to 0 when it finishes). RTC_DATA_ATTR uint8_t Alarms_Playing[4]; // Means the alarm tripped and it is to be played (goes to 0 when it finishes).
RTC_DATA_ATTR uint8_t Alarms_Repeats[4]; // 0-4 (20-80%) reduction in repetitions.
//} Alarms[4]; //} Alarms[4];
WiFiClient WiFiC; // Tz WiFiClient WiFiC; // Tz
@ -147,6 +163,7 @@ void WatchyGSR::setupDefaults(){
Options.Lefty = false; Options.Lefty = false;
Options.Swapped = false; Options.Swapped = false;
Options.Turbo = 3; Options.Turbo = 3;
Options.MasterRepeats = 0; // 100%.
Steps.Hour = 6; Steps.Hour = 6;
Steps.Minutes = 0; Steps.Minutes = 0;
} }
@ -155,7 +172,7 @@ void WatchyGSR::init(){
uint64_t wakeupBit; uint64_t wakeupBit;
time_t NTPWaiting, RightNOW, LastCheck; time_t NTPWaiting, RightNOW, LastCheck;
int AlarmIndex, Pushed; // Alarm being played. int AlarmIndex, Pushed; // Alarm being played.
bool AlarmsOn, WaitForNext, AP, Pulse; bool AlarmsOn, WaitForNext, Pulse, DoOnce;
unsigned long Since, AlarmReset, APLoop; unsigned long Since, AlarmReset, APLoop;
esp_sleep_wakeup_cause_t wakeup_reason; esp_sleep_wakeup_cause_t wakeup_reason;
@ -169,6 +186,7 @@ void WatchyGSR::init(){
wakeup_reason = esp_sleep_get_wakeup_cause(); //get wake up reason wakeup_reason = esp_sleep_get_wakeup_cause(); //get wake up reason
wakeupBit = esp_sleep_get_ext1_wakeup_status(); wakeupBit = esp_sleep_get_ext1_wakeup_status();
DoOnce = true;
switch (wakeup_reason) switch (wakeup_reason)
{ {
@ -211,13 +229,14 @@ void WatchyGSR::init(){
_bmaConfig(); _bmaConfig();
} }
// Detect NTP state, alarms playing and loop here until it is finished.
if (Button > 0) { handleButtonPress(Button); Button = 0; } if (Button > 0) { handleButtonPress(Button); Button = 0; }
CalculateTones(); monitorSteps(); CalculateTones(); monitorSteps();
AlarmsOn =(Alarms_Times[0] > 0 || Alarms_Times[1] > 0 || Alarms_Times[2] > 0 || Alarms_Times[3] > 0 || TimerDown.ToneLeft > 0); AlarmsOn =(Alarms_Times[0] > 0 || Alarms_Times[1] > 0 || Alarms_Times[2] > 0 || Alarms_Times[3] > 0 || TimerDown.ToneLeft > 0);
ActiveMode = (InTurbo() || NTPData.State > 0 || AlarmsOn || WatchyAPOn || OTAUpdate); ActiveMode = (InTurbo() || NTPData.State > 0 || AlarmsOn || WatchyAPOn || OTAUpdate);
while(DoOnce || Button > 0){
DoOnce = false; // Do this whole thing once, catch late button presses at the END of the loop just before Deep Sleep.
if (UpdateDisp) showWatchFace(); //partial updates on tick if (UpdateDisp) showWatchFace(); //partial updates on tick
NTPWaiting = WatchTime.UTC_RAW; NTPWaiting = WatchTime.UTC_RAW;
RightNOW = WatchTime.UTC_RAW; RightNOW = WatchTime.UTC_RAW;
@ -228,6 +247,9 @@ void WatchyGSR::init(){
OTAFail = Since; OTAFail = Since;
if (ActiveMode){ if (ActiveMode){
while (ActiveMode == true) { // Here, we hijack the init and LOOP until the NTP is done, watching for the proper time when we *SHOULD* update the screen to keep time with everything. while (ActiveMode == true) { // Here, we hijack the init and LOOP until the NTP is done, watching for the proper time when we *SHOULD* update the screen to keep time with everything.
processWiFiRequest(); // Process any WiFi requests.
if (!(OTAUpdate && Menu.SubItem == 3)){ if (!(OTAUpdate && Menu.SubItem == 3)){
if (NTPData.State > 0 && !WatchyAPOn && !OTAUpdate){ if (NTPData.State > 0 && !WatchyAPOn && !OTAUpdate){
if (NTPData.Pause == 0) ProcessNTP(); else NTPData.Pause--; if (NTPData.Pause == 0) ProcessNTP(); else NTPData.Pause--;
@ -316,11 +338,11 @@ void WatchyGSR::init(){
WiFi.setHostname(WiFi_AP_SSID); WiFi.setHostname(WiFi_AP_SSID);
wifiManager.setConfigPortalBlocking(false); wifiManager.setConfigPortalBlocking(false);
wifiManager.setWiFiAPHidden(WiFi_AP_HIDE); wifiManager.setWiFiAPHidden(WiFi_AP_HIDE);
AP = WiFi.softAP(WiFi_AP_SSID,WiFi_AP_PSWD,1,WiFi_AP_HIDE); if (!WiFi.softAP(WiFi_AP_SSID,WiFi_AP_PSWD,1,WiFi_AP_HIDE)) OTAEnd = true;
}else if (WiFi.getMode() == WIFI_AP){ }else if (WiFi.getMode() == WIFI_AP){
wifiManager.startWebPortal(); wifiManager.startWebPortal();
Menu.SubItem++; Menu.SubItem++;
setStatus("AP"); setStatus("WiFi-AP");
UpdateDisp=true; UpdateDisp=true;
APLoop=millis(); APLoop=millis();
}else Menu.SubItem = 0; // Fail, something is amiss. }else Menu.SubItem = 0; // Fail, something is amiss.
@ -343,22 +365,12 @@ void WatchyGSR::init(){
} }
} }
} }
} }
if (OTAUpdate){ if (OTAUpdate){
switch (Menu.SubItem){ switch (Menu.SubItem){
case 1: // Turn on WiFi and connect. case 1: // Wait for WiFi to connect or fail.
if (WiFi.status() != WL_CONNECTED && OTATry < 3){ if (WiFi.status() != WL_CONNECTED && currentWiFi() != WL_CONNECT_FAILED) OTATimer = millis();
if (millis() - OTATimer > 4000 || WiFi.getMode() != WIFI_STA){ else if (WiFi.status() == WL_CONNECTED){
WiFi.disconnect();
WiFi.setHostname(WiFi_AP_SSID);
WiFi.mode(WIFI_STA);
OTATimer = millis();
OTATry++;
if(WiFi.begin() == WL_CONNECT_FAILED) OTAEnd=true;
}
}else if (WiFi.status() == WL_CONNECTED){
setStatus("WiFi");
Menu.SubItem++; Menu.SubItem++;
UpdateDisp = true; UpdateDisp = true;
}else OTAEnd=true; }else OTAEnd=true;
@ -373,11 +385,9 @@ void WatchyGSR::init(){
Type = "sketch"; Type = "sketch";
else // U_SPIFFS else // U_SPIFFS
Type = "filesystem"; Type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
//Serial.println("Start updating " + Type); //Serial.println("Start updating " + Type);
}) })
.onEnd([]() { .onEnd([]() {
OTAEnd = true; OTAEnd = true;
//Serial.println("\nEnd"); //Serial.println("\nEnd");
@ -395,27 +405,44 @@ void WatchyGSR::init(){
else if (error == OTA_END_ERROR) Serial.println("End Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed");
*/ */
}); });
ArduinoOTA.begin(); ArduinoOTA.begin();
}else if (Menu.Item == MENU_OTAM){ }else if (Menu.Item == MENU_OTAM){
/*return index page which is stored in basicIndex */ /*return index page which is stored in basicIndex */
server.on("/", HTTP_GET, [=]() { server.on("/", HTTP_GET, [=]() {
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/html", basicIndex); server.send(200, "text/html", basicIndex);
OTATimer=millis();
}); });
server.on("/settings", HTTP_GET, [=]() { server.on("/settings", HTTP_GET, [=]() {
String S = settingsA + GetSettings() + settingsB; String S = settingsA + GetSettings() + settingsB;
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/html", S); server.send(200, "text/html", S);
OTATimer=millis();
});
server.on("/wifi", HTTP_GET, [=]() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", buildWiFiAPPage());
OTATimer=millis();
}); });
server.on("/update", HTTP_GET, [=]() { server.on("/update", HTTP_GET, [=]() {
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/html", updateIndex); server.send(200, "text/html", updateIndex);
OTATimer=millis();
}); });
server.on("/settings", HTTP_POST, [=](){ server.on("/settings", HTTP_POST, [=](){
if (server.argName(0) == "settings") StoreSettings(server.arg(0)); if (server.argName(0) == "settings") StoreSettings(server.arg(0));
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/html", settingsDone); server.send(200, "text/html", settingsDone);
OTATimer=millis();
});
server.on("/wifi", HTTP_POST, [=](){
uint8_t I = 0;
while (I < server.args()){
parseWiFiPageArg(server.argName(I),server.arg(I)); I++;
}
server.sendHeader("Connection", "close");
server.send(200, "text/html", wifiDone);
OTAFail = millis() - 598000;
}); });
server.on("/update", HTTP_POST, [](){ server.on("/update", HTTP_POST, [](){
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
@ -463,17 +490,16 @@ void WatchyGSR::init(){
OTAEnd=false; OTAEnd=false;
OTAUpdate=false; OTAUpdate=false;
WatchyAPOn = false; WatchyAPOn = false;
WiFi.disconnect(); endWiFi();
WiFi.mode(WIFI_OFF);
btStop();
Menu.SubItem=0; Menu.SubItem=0;
setStatus(""); UpdateUTC();
UpdateClock();
Battery.UpCount=0; // Stop it from thinking the battery went wild.
UpdateDisp=true; UpdateDisp=true;
} }
// Don't do anything time sensitive while in OTA Update. // Don't do anything time sensitive while in OTA Update.
if (!(OTAUpdate && Menu.SubItem == 3)){ if (!(OTAUpdate && Menu.SubItem == 3)){
CalculateTones(); monitorSteps(); CalculateTones(); monitorSteps();
AlarmsOn =(Alarms_Times[0] > 0 || Alarms_Times[1] > 0 || Alarms_Times[2] > 0 || Alarms_Times[3] > 0 || TimerDown.ToneLeft > 0); AlarmsOn =(Alarms_Times[0] > 0 || Alarms_Times[1] > 0 || Alarms_Times[2] > 0 || Alarms_Times[3] > 0 || TimerDown.ToneLeft > 0);
ActiveMode = (InTurbo() || NTPData.State > 0 || AlarmsOn || WatchyAPOn || OTAUpdate); ActiveMode = (InTurbo() || NTPData.State > 0 || AlarmsOn || WatchyAPOn || OTAUpdate);
@ -495,6 +521,7 @@ void WatchyGSR::init(){
if (Button > 0) { handleButtonPress(Button); Button = 0; } if (Button > 0) { handleButtonPress(Button); Button = 0; }
if (UpdateDisp) showWatchFace(); //partial updates on tick if (UpdateDisp) showWatchFace(); //partial updates on tick
}
deepSleep(); deepSleep();
} }
@ -635,24 +662,31 @@ void WatchyGSR::drawMenu(){
break; break;
case MENU_ALARM1: case MENU_ALARM1:
if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 1 Time"; if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 1 Time";
else if (Menu.SubItem > 3) O = "Alarm 1 Options"; else if (Menu.SubItem == 4) O = "A1 Tone Repeats";
else if (Menu.SubItem > 4) O = "Alarm 1 Options";
else O = "Alarm 1"; else O = "Alarm 1";
break; break;
case MENU_ALARM2: case MENU_ALARM2:
if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 2 Time"; if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 2 Time";
else if (Menu.SubItem > 3) O = "Alarm 2 Options"; else if (Menu.SubItem == 4) O = "A2 Tone Repeats";
else if (Menu.SubItem > 4) O = "Alarm 2 Options";
else O = "Alarm 2"; else O = "Alarm 2";
break; break;
case MENU_ALARM3: case MENU_ALARM3:
if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 3 Time"; if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 3 Time";
else if (Menu.SubItem > 3) O = "Alarm 3 Options"; else if (Menu.SubItem == 4) O = "A3 Tone Repeats";
else if (Menu.SubItem > 4) O = "Alarm 3 Options";
else O = "Alarm 3"; else O = "Alarm 3";
break; break;
case MENU_ALARM4: case MENU_ALARM4:
if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 4 Time"; if (Menu.SubItem > 0 && Menu.SubItem < 4) O = "Alarm 4 Time";
else if (Menu.SubItem > 3) O = "Alarm 4 Options"; else if (Menu.SubItem == 4) O = "A4 Tone Repeats";
else if (Menu.SubItem > 4) O = "Alarm 4 Options";
else O = "Alarm 4"; else O = "Alarm 4";
break; break;
case MENU_TONES:
O = "Tone Repeats";
break;
case MENU_TIMEDN: case MENU_TIMEDN:
O = "Countdown Timer"; O = "Countdown Timer";
break; break;
@ -732,79 +766,83 @@ void WatchyGSR::drawMenu(){
O = "MENU to Select"; O = "MENU to Select";
}else if (Menu.Item >= MENU_ALARM1 && Menu.Item <= MENU_ALARM4){ // Alarms }else if (Menu.Item >= MENU_ALARM1 && Menu.Item <= MENU_ALARM4){ // Alarms
O = ""; O = "";
S=MakeMinutes(Alarms_Minutes[Menu.Item - MENU_ALARM1]);
switch (Menu.SubItem){ switch (Menu.SubItem){
case 0: // Menu to Edit. case 0: // Menu to Edit.
O="Menu to Edit"; O="Menu to Edit";
break; break;
case 1: // Hour. case 1: // Hour.
O="[" + MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + "]:" + MakeMinutes(Alarms_Minutes[Menu.Item - MENU_ALARM1]) + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM" : " AM") ; O="[" + MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + "]:" + S + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM " : " AM ") + getReduce(Alarms_Repeats[Menu.Item - MENU_ALARM1]);
break; break;
case 2: // x0 minutes. case 2: // x0 minutes.
S=MakeMinutes(Alarms_Minutes[Menu.Item - MENU_ALARM1]); O=MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + ":[" + S.charAt(0) + "]" + S.charAt(1) + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM " : " AM ") + getReduce(Alarms_Repeats[Menu.Item - MENU_ALARM1]);
O=MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + ":[" + S.charAt(0) + "]" + S.charAt(1) + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM" : " AM") ;
break; break;
case 3: // 0x minutes. case 3: // 0x minutes.
S=MakeMinutes(Alarms_Minutes[Menu.Item - MENU_ALARM1]); O=MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + ":" + S.charAt(0) + "[" + S.charAt(1) + "]" + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM " : " AM ") + getReduce(Alarms_Repeats[Menu.Item - MENU_ALARM1]);
O=MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + ":" + S.charAt(0) + "[" + S.charAt(1) + "]" + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM" : " AM") ;
break; break;
case 4: // Sunday. case 4: // Repeats
O=MakeHour(Alarms_Hour[Menu.Item - MENU_ALARM1]) + ":" + S.charAt(0) + S.charAt(1) + ((Alarms_Hour[Menu.Item - MENU_ALARM1] > 11) ? " PM " : " AM ") + "[" + getReduce(Alarms_Repeats[Menu.Item - MENU_ALARM1]) + "]";
break;
case 5: // Sunday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[0]) == Bits[0]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[0]) == Bits[0]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(1); O=dayStr(1);
break; break;
case 5: // Monday. case 6: // Monday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[1]) == Bits[1]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[1]) == Bits[1]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(2); O=dayStr(2);
break; break;
case 6: // Tuesday. case 7: // Tuesday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[2]) == Bits[2]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[2]) == Bits[2]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(3); O=dayStr(3);
break; break;
case 7: // Wedmesday. case 8: // Wedmesday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[3]) == Bits[3]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[3]) == Bits[3]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(4); O=dayStr(4);
break; break;
case 8: // Thursday. case 9: // Thursday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[4]) == Bits[4]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[4]) == Bits[4]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(5); O=dayStr(5);
break; break;
case 9: // Friday. case 10: // Friday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[5]) == Bits[5]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[5]) == Bits[5]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(6); O=dayStr(6);
break; break;
case 10: // Saturday. case 11: // Saturday.
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[6]) == Bits[6]) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & Bits[6]) == Bits[6]) ? GxEPD_WHITE : GxEPD_BLACK);
O=dayStr(7); O=dayStr(7);
break; break;
case 11: // Repeat case 12: // Repeat
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & ALARM_REPEAT) == ALARM_REPEAT) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & ALARM_REPEAT) == ALARM_REPEAT) ? GxEPD_WHITE : GxEPD_BLACK);
O="Repeat"; O="Repeat";
break; break;
case 12: // Active case 13: // Active
display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & ALARM_ACTIVE) == ALARM_ACTIVE) ? GxEPD_WHITE : GxEPD_BLACK); display.setTextColor(((Alarms_Active[Menu.Item - MENU_ALARM1] & ALARM_ACTIVE) == ALARM_ACTIVE) ? GxEPD_WHITE : GxEPD_BLACK);
O="Active"; O="Active";
} }
}else if (Menu.Item == MENU_TONES){ // Repeats on Alarms.
O = getReduce(Options.MasterRepeats) + " repeats";
}else if (Menu.Item == MENU_TIMERS){ // Timers }else if (Menu.Item == MENU_TIMERS){ // Timers
O = "MENU to Select"; O = "MENU to Select";
}else if (Menu.Item == MENU_TIMEDN){ // Countdown }else if (Menu.Item == MENU_TIMEDN){ // Countdown
S=MakeMinutes(TimerDown.Active ? TimerDown.Mins : TimerDown.MaxMins);
switch (Menu.SubItem){ switch (Menu.SubItem){
case 0: case 0:
O = "MENU to Edit"; O = "MENU to Edit";
break; break;
case 1: // Hours case 1: // Hours
S=MakeMinutes(TimerDown.Active ? TimerDown.Mins : TimerDown.MaxMins); O="[" + String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + "]:" + S + " " + getReduce(TimerDown.MaxTones) + " " + (TimerDown.Active ? "Off" : "On");
O="[" + String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + "]:" + S + (TimerDown.Active ? " Stop" : " Start");
break; break;
case 2: // 1x minutes. case 2: // 1x minutes.
S=MakeMinutes(TimerDown.Active ? TimerDown.Mins : TimerDown.MaxMins); O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":[" + S.charAt(0) + "]" + S.charAt(1) + " " + getReduce(TimerDown.MaxTones) + " " + (TimerDown.Active ? "Off" : "On");
O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":[" + S.charAt(0) + "]" + S.charAt(1) + (TimerDown.Active ? " Stop" : " Start");
break; break;
case 3: // x1 minutes. case 3: // x1 minutes.
S=MakeMinutes(TimerDown.Active ? TimerDown.Mins : TimerDown.MaxMins); O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":" + S.charAt(0) + "[" + S.charAt(1) + "] " + getReduce(TimerDown.MaxTones) + " " + (TimerDown.Active ? "Off" : "On");
O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":" + S.charAt(0) + "[" + S.charAt(1) + "]" + (TimerDown.Active ? " Stop" : " Start");
break; break;
case 4: // Button. case 4: // %
S=MakeMinutes(TimerDown.Active ? TimerDown.Mins : TimerDown.MaxMins); O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":" + S.charAt(0) + S.charAt(1) + " [" + getReduce(TimerDown.MaxTones) + "] " + (TimerDown.Active ? "Off" : "On");
O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":" + S + (TimerDown.Active ? " [Stop]" : " [Start]"); break;
case 5: // Button.
O=String(TimerDown.Active ? TimerDown.Hours : TimerDown.MaxHours) + ":" + S + " " + getReduce(TimerDown.MaxTones) + " " + (TimerDown.Active ? " [Off]" : " [On]");
} }
}else if (Menu.Item == MENU_TIMEUP){ // Elapsed }else if (Menu.Item == MENU_TIMEUP){ // Elapsed
switch (Menu.SubItem){ switch (Menu.SubItem){
@ -814,7 +852,7 @@ void WatchyGSR::drawMenu(){
case 1: case 1:
if (TimerUp.Active) { y1 = ((WatchTime.UTC_RAW - (TimerUp.SetAt + WatchTime.UTC.Second)) / 3600); x1 = (((WatchTime.UTC_RAW - (TimerUp.SetAt + WatchTime.UTC.Second)) + 3600 * y1) / 60); } if (TimerUp.Active) { y1 = ((WatchTime.UTC_RAW - (TimerUp.SetAt + WatchTime.UTC.Second)) / 3600); x1 = (((WatchTime.UTC_RAW - (TimerUp.SetAt + WatchTime.UTC.Second)) + 3600 * y1) / 60); }
else { y1 = ((TimerUp.StopAt - TimerUp.SetAt) / 3600); x1 = (((TimerUp.StopAt - TimerUp.SetAt) + 3600 * y1) / 60); } else { y1 = ((TimerUp.StopAt - TimerUp.SetAt) / 3600); x1 = (((TimerUp.StopAt - TimerUp.SetAt) + 3600 * y1) / 60); }
O=String(y1) + ":" + MakeMinutes(x1) + (TimerUp.Active ? " [Stop]" : " [Start]"); O=String(y1) + ":" + MakeMinutes(x1) + (TimerUp.Active ? " [Off]" : " [On]");
} }
}else if (Menu.Item == MENU_OPTIONS){ // Options Menu }else if (Menu.Item == MENU_OPTIONS){ // Options Menu
O = "MENU to Enter"; O = "MENU to Enter";
@ -926,9 +964,18 @@ void WatchyGSR::detectBattery(){
BATOff = CBAT - Battery.Last; BATOff = CBAT - Battery.Last;
//Detect Power direction //Detect Power direction
if (BATOff > 0.02){ if (BATOff > 0.03){
Battery.UpCount++; Battery.UpCount++;
if (Battery.UpCount > 3){ Battery.Direction = 1; Battery.UpCount = 0; Battery.DownCount = 0; Battery.Last = CBAT; } if (Battery.UpCount > 3){
Battery.Direction = 1; Battery.UpCount = 0; Battery.DownCount = 0; Battery.Last = CBAT;
// Check if the NTP has been done.
if (WatchTime.UTC_RAW - NTPData.Last > 14400 && NTPData.State == 0){
NTPData.State = 1;
NTPData.TimeZone = (WatchTime.POSIX[0] == 0); // No Timezone, go get one!
NTPData.UpdateUTC = true;
AskForWiFi();
}
}
}else{ }else{
if (BATOff < 0.00) Battery.DownCount++; if (BATOff < 0.00) Battery.DownCount++;
if (Battery.DownCount > 2){ Battery.Direction = -1; Battery.UpCount = 0; Battery.DownCount = 0; Battery.Last = CBAT; } if (Battery.DownCount > 2){ Battery.Direction = -1; Battery.UpCount = 0; Battery.DownCount = 0; Battery.Last = CBAT; }
@ -941,12 +988,8 @@ void WatchyGSR::ProcessNTP(){
// Start WiFi and Connect. // Start WiFi and Connect.
case 1:{ case 1:{
HTTP.setUserAgent(UserAgent); HTTP.setUserAgent(UserAgent);
setStatus("WiFi");
if (WiFi.status() != WL_CONNECTED){ if (WiFi.status() != WL_CONNECTED){
WiFi.disconnect(); if(currentWiFi() == WL_CONNECT_FAILED){
WiFi.setHostname(WiFi_AP_SSID);
WiFi.mode(WIFI_STA);
if(WiFi.begin() == WL_CONNECT_FAILED){
NTPData.Pause = 0; NTPData.Pause = 0;
NTPData.State = 99; NTPData.State = 99;
break; break;
@ -961,8 +1004,7 @@ void WatchyGSR::ProcessNTP(){
// Am I Connected? If so, ask for NTP. // Am I Connected? If so, ask for NTP.
case 2:{ case 2:{
if (WiFi.status() != WL_CONNECTED){ if (WiFi.status() != WL_CONNECTED){
WiFi.disconnect(); if(currentWiFi() == WL_CONNECT_FAILED){
if(WiFi.begin() == WL_CONNECT_FAILED){
NTPData.Pause = 0; NTPData.Pause = 0;
NTPData.State = 99; NTPData.State = 99;
break; break;
@ -1026,6 +1068,7 @@ void WatchyGSR::ProcessNTP(){
NTPData.Wait = 0; NTPData.Wait = 0;
NTPData.Pause = 0; NTPData.Pause = 0;
NTPData.State++; NTPData.State++;
if (!NTPData.UpdateUTC) UpdateDisp=true;
break; break;
} }
@ -1057,23 +1100,19 @@ void WatchyGSR::ProcessNTP(){
tmElements_t TM; tmElements_t TM;
breakTime(WatchTime.UTC_RAW,TM); breakTime(WatchTime.UTC_RAW,TM);
RTC.write(TM); RTC.write(TM);
UpdateUTC();
UpdateClock();
NTPData.Pause = 0; NTPData.Pause = 0;
NTPData.State = 99; NTPData.State = 99;
break; break;
} }
case 99:{ case 99:{
WiFi.disconnect(); OTAEnd = true;
WiFi.mode(WIFI_OFF);
btStop();
NTPData.Wait = 0; NTPData.Wait = 0;
NTPData.Pause = 0; NTPData.Pause = 0;
NTPData.State = 0; NTPData.State = 0;
NTPData.UpdateUTC = false; NTPData.UpdateUTC = false;
NTPData.TimeZone = false; NTPData.TimeZone = false;
setStatus(""); Battery.UpCount=0; // Stop it from thinking the battery went wild.
} }
} }
} }
@ -1085,12 +1124,6 @@ void WatchyGSR::drawChargeMe(){
// Show Battery charging bitmap. // Show Battery charging bitmap.
display.drawBitmap(155, 178, Charging, 40, 17, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE); display.drawBitmap(155, 178, Charging, 40, 17, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE);
D = 2; D = 2;
// Check if the NTP has been done.
if (WatchTime.UTC_RAW - NTPData.Last > 14400 && NTPData.State == 0){
NTPData.State = 1;
NTPData.TimeZone = (WatchTime.POSIX[0] == 0); // No Timezone, go get one!
NTPData.UpdateUTC = true;
}
}else if (Battery.Direction == -1 && getBatteryVoltage() < MinBattery){ }else if (Battery.Direction == -1 && getBatteryVoltage() < MinBattery){
// Show Battery needs charging bitmap. // Show Battery needs charging bitmap.
display.drawBitmap(155, 178, ChargeMe, 40, 17, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE); display.drawBitmap(155, 178, ChargeMe, 40, 17, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE);
@ -1104,9 +1137,15 @@ void WatchyGSR::drawStatus(){
if (WatchyStatus > ""){ if (WatchyStatus > ""){
display.fillRect(NTPX, NTPY - 19, 60, 20, Options.LightMode ? GxEPD_WHITE : GxEPD_BLACK); display.fillRect(NTPX, NTPY - 19, 60, 20, Options.LightMode ? GxEPD_WHITE : GxEPD_BLACK);
display.setFont(&Bronova_Regular13pt7b); display.setFont(&Bronova_Regular13pt7b);
display.setCursor(NTPX, NTPY); display.setCursor(NTPX + 17, NTPY);
display.setTextColor(Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE); // display.setTextColor(Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE);
display.print(WatchyStatus); // display.print(WatchyStatus);
if (WatchyStatus.startsWith("WiFi")){
display.drawBitmap(NTPX, NTPY - 18, iWiFi, 19, 19, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE);
display.print(WatchyStatus.substring(4));
}
else if (WatchyStatus == "TZ") display.drawBitmap(NTPX, NTPY - 18, iTZ, 19, 19, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE);
else if (WatchyStatus == "NTP") display.drawBitmap(NTPX, NTPY - 18, iSync, 19, 19, Options.LightMode ? GxEPD_BLACK : GxEPD_WHITE);
} }
} }
@ -1202,31 +1241,41 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
UpdateDisp = true; UpdateDisp = true;
SetTurbo(); SetTurbo();
}else if (Menu.Item >= MENU_ALARM1 && Menu.Item <= MENU_ALARM4){ // Alarms }else if (Menu.Item >= MENU_ALARM1 && Menu.Item <= MENU_ALARM4){ // Alarms
if (Menu.SubItem < 4){ if (Menu.SubItem < 5){
Menu.SubItem++; Menu.SubItem++;
if (Menu.SubItem == 4) Menu.SubItem += WatchTime.Local.Wday; // Jump ahead to the day. if (Menu.SubItem == 5) Menu.SubItem += WatchTime.Local.Wday; // Jump ahead to the day.
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
}else if (Menu.SubItem > 3 && Menu.SubItem < 11){ }else if (Menu.SubItem > 4 && Menu.SubItem < 12){
Alarms_Active[Menu.Item - MENU_ALARM1] ^= Bits[Menu.SubItem - 4]; // Toggle day. Alarms_Active[Menu.Item - MENU_ALARM1] ^= Bits[Menu.SubItem - 5]; // Toggle day.
Menu.LastItem=""; // Forces a redraw.
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
}else if (Menu.SubItem == 11){
Alarms_Active[Menu.Item - MENU_ALARM1] ^= ALARM_REPEAT; // Toggle repeat.
Menu.LastItem=""; // Forces a redraw. Menu.LastItem=""; // Forces a redraw.
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
}else if (Menu.SubItem == 12){ }else if (Menu.SubItem == 12){
Alarms_Active[Menu.Item - MENU_ALARM1] ^= ALARM_REPEAT; // Toggle repeat.
Menu.LastItem=""; // Forces a redraw.
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
}else if (Menu.SubItem == 13){
Alarms_Active[Menu.Item - MENU_ALARM1] ^= ALARM_ACTIVE; // Toggle Active. Alarms_Active[Menu.Item - MENU_ALARM1] ^= ALARM_ACTIVE; // Toggle Active.
Menu.LastItem=""; // Forces a redraw. Menu.LastItem=""; // Forces a redraw.
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
} }
}else if (Menu.Item == MENU_TONES){ // Tones.
Options.MasterRepeats = clamp(Options.MasterRepeats + 1, 0, 4);
Alarms_Repeats[0] = Options.MasterRepeats;
Alarms_Repeats[1] = Options.MasterRepeats;
Alarms_Repeats[2] = Options.MasterRepeats;
Alarms_Repeats[3] = Options.MasterRepeats;
Menu.LastItem=""; // Forces a redraw.
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
}else if (Menu.Item == MENU_TIMERS){ // Timers menu. }else if (Menu.Item == MENU_TIMERS){ // Timers menu.
Menu.Style = MENU_INTIMERS; Menu.Style = MENU_INTIMERS;
Menu.Item = MENU_TIMEDN; Menu.Item = MENU_TIMEDN;
@ -1234,7 +1283,7 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
UpdateDisp = true; UpdateDisp = true;
SetTurbo(); SetTurbo();
}else if (Menu.Item == MENU_TIMEDN){ }else if (Menu.Item == MENU_TIMEDN){
if (Menu.SubItem == 4){ if (Menu.SubItem == 5){
if (TimerDown.Active){ if (TimerDown.Active){
TimerDown.Active=false; TimerDown.Active=false;
DoHaptic = true; DoHaptic = true;
@ -1251,8 +1300,8 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
} }
}else{ }else{
Menu.SubItem++; Menu.SubItem++;
if (TimerDown.MaxMins + TimerDown.MaxHours == 0 && Menu.SubItem == 4) Menu.SubItem = 3; //Stop it from being startable. if (TimerDown.MaxMins + TimerDown.MaxHours == 0 && Menu.SubItem == 5) Menu.SubItem = 4; //Stop it from being startable.
if (TimerDown.Active) Menu.SubItem = 4; if (TimerDown.Active) Menu.SubItem = 5;
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
@ -1287,7 +1336,7 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
switch (Menu.SubItem){ switch (Menu.SubItem){
case 1: case 1:
NTPData.UpdateUTC = true; NTPData.UpdateUTC = true;
NTPData.TimeZone = false; NTPData.TimeZone = (WatchTime.POSIX[0] == 0); // No Timezone, go get one!
break; break;
case 2: case 2:
NTPData.UpdateUTC = false; NTPData.UpdateUTC = false;
@ -1297,15 +1346,15 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
NTPData.TimeZone = true; NTPData.TimeZone = true;
NTPData.UpdateUTC = true; NTPData.UpdateUTC = true;
} }
NTPData.TimeZone = (WatchTime.POSIX[0] == 0); // No Timezone, go get one!
GuiMode = WATCHON; GuiMode = WATCHON;
WatchTime.LastDay=""; WatchTime.LastDay="";
WatchTime.LastDate=""; WatchTime.LastDate="";
Menu.Item = MENU_STEPS; Menu.Item = MENU_DISP;
Menu.SubItem = 0; Menu.SubItem = 0;
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
AskForWiFi();
} }
}else if (Menu.Item == MENU_DISP){ // Switch Mode }else if (Menu.Item == MENU_DISP){ // Switch Mode
Options.LightMode = !Options.LightMode; Options.LightMode = !Options.LightMode;
@ -1376,6 +1425,7 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
AskForWiFi();
}else if (Menu.Item == MENU_RSET){ // Watchy Reboot }else if (Menu.Item == MENU_RSET){ // Watchy Reboot
ESP.restart(); ESP.restart();
} }
@ -1390,9 +1440,9 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
}else if (Menu.Item >= MENU_ALARM1 && Menu.Item <= MENU_ALARM4 && Menu.SubItem > 0){ }else if (Menu.Item >= MENU_ALARM1 && Menu.Item <= MENU_ALARM4 && Menu.SubItem > 0){
if (Menu.SubItem < 4 && Menu.SubItem > 0){ if (Menu.SubItem < 5 && Menu.SubItem > 0){
Menu.SubItem--; Menu.SubItem--;
}else if (Menu.SubItem > 3){ }else if (Menu.SubItem > 4){
Menu.SubItem = 1; Menu.SubItem = 1;
} }
DoHaptic = true; DoHaptic = true;
@ -1510,8 +1560,13 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
}else if (Menu.SubItem > 3){ }else if (Menu.SubItem == 4){ // Repeats.
Menu.SubItem = roller(Menu.SubItem + 1, 4, 12); Alarms_Repeats[Menu.Item - MENU_ALARM1] = roller(Alarms_Repeats[Menu.Item - MENU_ALARM1] - 1, 0, 4);
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
}else if (Menu.SubItem > 4){
Menu.SubItem = roller(Menu.SubItem + 1, 5, 13);
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
@ -1544,6 +1599,13 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
break;
case 4: //Repeats
TimerDown.MaxTones = roller(TimerDown.MaxTones - 1, 0, 4);
StopCD();
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
} }
}else if (Menu.Item == MENU_SYNC && Menu.SubItem > 0){ }else if (Menu.Item == MENU_SYNC && Menu.SubItem > 0){
Menu.SubItem = roller(Menu.SubItem - 1, 1, 3); Menu.SubItem = roller(Menu.SubItem - 1, 1, 3);
@ -1556,7 +1618,7 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
if (Menu.Style == MENU_INOPTIONS){ if (Menu.Style == MENU_INOPTIONS){
Menu.Item = roller(Menu.Item - 1, MENU_DISP, (NTPData.State > 0 || WatchyAPOn || OTAUpdate || getBatteryVoltage() < MinBattery) ? MENU_SCRN : MENU_RSET); Menu.Item = roller(Menu.Item - 1, MENU_DISP, (NTPData.State > 0 || WatchyAPOn || OTAUpdate || getBatteryVoltage() < MinBattery) ? MENU_SCRN : MENU_RSET);
}else if (Menu.Style == MENU_INALARMS){ }else if (Menu.Style == MENU_INALARMS){
Menu.Item = roller(Menu.Item - 1, MENU_ALARM1, MENU_ALARM4); Menu.Item = roller(Menu.Item - 1, MENU_ALARM1, MENU_TONES);
}else if (Menu.Style == MENU_INTIMERS){ }else if (Menu.Style == MENU_INTIMERS){
Menu.Item = roller(Menu.Item - 1, MENU_TIMEDN, MENU_TIMEUP); Menu.Item = roller(Menu.Item - 1, MENU_TIMEDN, MENU_TIMEUP);
}else{ }else{
@ -1627,8 +1689,13 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
}else if (Menu.SubItem > 3){ }else if (Menu.SubItem == 4){ // Repeats.
Menu.SubItem = roller(Menu.SubItem - 1, 4, 12); Alarms_Repeats[Menu.Item - MENU_ALARM1] = roller(Alarms_Repeats[Menu.Item - MENU_ALARM1] + 1, 0, 4);
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
}else if (Menu.SubItem > 4){
Menu.SubItem = roller(Menu.SubItem - 1, 5, 13);
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
@ -1661,6 +1728,13 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
DoHaptic = true; DoHaptic = true;
UpdateDisp = true; // Quick Update. UpdateDisp = true; // Quick Update.
SetTurbo(); SetTurbo();
break;
case 4: //Repeats
TimerDown.MaxTones = roller(TimerDown.MaxTones + 1, 0, 4);
StopCD();
DoHaptic = true;
UpdateDisp = true; // Quick Update.
SetTurbo();
} }
}else if (Menu.Item == MENU_SYNC && Menu.SubItem > 0){ }else if (Menu.Item == MENU_SYNC && Menu.SubItem > 0){
Menu.SubItem = roller(Menu.SubItem + 1, 1, 3); Menu.SubItem = roller(Menu.SubItem + 1, 1, 3);
@ -1673,7 +1747,7 @@ void WatchyGSR::handleButtonPress(uint8_t Pressed){
if (Menu.Style == MENU_INOPTIONS){ if (Menu.Style == MENU_INOPTIONS){
Menu.Item = roller(Menu.Item + 1, MENU_DISP, (NTPData.State > 0 || WatchyAPOn || OTAUpdate || getBatteryVoltage() < MinBattery) ? MENU_SCRN : MENU_RSET); Menu.Item = roller(Menu.Item + 1, MENU_DISP, (NTPData.State > 0 || WatchyAPOn || OTAUpdate || getBatteryVoltage() < MinBattery) ? MENU_SCRN : MENU_RSET);
}else if (Menu.Style == MENU_INALARMS){ }else if (Menu.Style == MENU_INALARMS){
Menu.Item = roller(Menu.Item + 1, MENU_ALARM1, MENU_ALARM4); Menu.Item = roller(Menu.Item + 1, MENU_ALARM1, MENU_TONES);
}else if (Menu.Style == MENU_INTIMERS){ }else if (Menu.Style == MENU_INTIMERS){
Menu.Item = roller(Menu.Item + 1, MENU_TIMEDN, MENU_TIMEUP); Menu.Item = roller(Menu.Item + 1, MENU_TIMEDN, MENU_TIMEUP);
}else{ }else{
@ -1949,23 +2023,23 @@ void WatchyGSR::CalculateTones(){
if (Alarms_Times[3] > 0) Count++; if (Alarms_Times[3] > 0) Count++;
if (TimerDown.ToneLeft > 0) Count++; if (TimerDown.ToneLeft > 0) Count++;
if (Count == 5){ if (Count == 5){
if (Alarms_Times[0] == 255) Alarms_Times[0] = 7; if (Alarms_Times[0] == 255) Alarms_Times[0] = 7 * Reduce[Alarms_Repeats[0]];
if (Alarms_Times[1] == 255) Alarms_Times[1] = 7; if (Alarms_Times[1] == 255) Alarms_Times[1] = 7 * Reduce[Alarms_Repeats[1]];
if (Alarms_Times[2] == 255) Alarms_Times[2] = 7; if (Alarms_Times[2] == 255) Alarms_Times[2] = 7 * Reduce[Alarms_Repeats[2]];
if (Alarms_Times[3] == 255) Alarms_Times[3] = 7; if (Alarms_Times[3] == 255) Alarms_Times[3] = 7 * Reduce[Alarms_Repeats[3]];
if (TimerDown.ToneLeft == 255) TimerDown.ToneLeft = 10; if (TimerDown.ToneLeft == 255) TimerDown.ToneLeft = 10 * Reduce[TimerDown.MaxTones];
}else if (Count == 4){ }else if (Count == 4){
if (Alarms_Times[0] == 255) Alarms_Times[0] = 8; if (Alarms_Times[0] == 255) Alarms_Times[0] = 8 * Reduce[Alarms_Repeats[0]];
if (Alarms_Times[1] == 255) Alarms_Times[1] = 8; if (Alarms_Times[1] == 255) Alarms_Times[1] = 8 * Reduce[Alarms_Repeats[1]];
if (Alarms_Times[2] == 255) Alarms_Times[2] = 8; if (Alarms_Times[2] == 255) Alarms_Times[2] = 8 * Reduce[Alarms_Repeats[2]];
if (Alarms_Times[3] == 255) Alarms_Times[3] = 8; if (Alarms_Times[3] == 255) Alarms_Times[3] = 8 * Reduce[Alarms_Repeats[3]];
if (TimerDown.ToneLeft == 255) TimerDown.ToneLeft = 12; if (TimerDown.ToneLeft == 255) TimerDown.ToneLeft = 12 * Reduce[TimerDown.MaxTones];
}else{ }else{
if (Alarms_Times[0] == 255) Alarms_Times[0] = 10; if (Alarms_Times[0] == 255) Alarms_Times[0] = 10 * Reduce[Alarms_Repeats[0]];
if (Alarms_Times[1] == 255) Alarms_Times[1] = 10; if (Alarms_Times[1] == 255) Alarms_Times[1] = 10 * Reduce[Alarms_Repeats[1]];
if (Alarms_Times[2] == 255) Alarms_Times[2] = 10; if (Alarms_Times[2] == 255) Alarms_Times[2] = 10 * Reduce[Alarms_Repeats[2]];
if (Alarms_Times[3] == 255) Alarms_Times[3] = 10; if (Alarms_Times[3] == 255) Alarms_Times[3] = 10 * Reduce[Alarms_Repeats[3]];
if (TimerDown.ToneLeft == 255) TimerDown.ToneLeft = 15; if (TimerDown.ToneLeft == 255) TimerDown.ToneLeft = 15 * Reduce[TimerDown.MaxTones];
} }
} }
@ -1981,6 +2055,20 @@ uint8_t WatchyGSR::getToneTimes(uint8_t ToneIndex){
return Alarms_Times[ToneIndex]; return Alarms_Times[ToneIndex];
} }
String WatchyGSR::getReduce(uint8_t Amount){
switch (Amount){
case 0:
return "Full";
case 1:
return "80%";
case 2:
return "60%";
case 3:
return "40%";
}
return "20%";
}
// Catches Steps and moves "Yesterday" into the other setting. // Catches Steps and moves "Yesterday" into the other setting.
void WatchyGSR::monitorSteps(){ void WatchyGSR::monitorSteps(){
if (Steps.Hour == WatchTime.Local.Hour && Steps.Minutes == WatchTime.Local.Minute){ if (Steps.Hour == WatchTime.Local.Hour && Steps.Minutes == WatchTime.Local.Minute){
@ -2106,7 +2194,115 @@ void WatchyGSR::ScreenRefresh(){
Updates.Full=false; Updates.Full=false;
} }
void WatchyGSR::AskForWiFi(){ if (!GSRWiFi.Requested && !GSRWiFi.Working) GSRWiFi.Requested = true; }
void WatchyGSR::processWiFiRequest(){
wl_status_t WiFiE = WL_CONNECT_FAILED;
wl_status_t rWiFi = WiFi.status();
String AP, PA;
if (GSRWiFi.Requested){
GSRWiFi.Requested = false;
WiFi.disconnect();
WiFi.setHostname(WiFi_AP_SSID);
WiFi.mode(WIFI_STA);
GSRWiFi.Working = true;
GSRWiFi.Index = 0;
GSRWiFi.Last = 0;
}
if (GSRWiFi.Working) {
if (rWiFi == WL_CONNECTED) { GSRWiFi.Working = false; GSRWiFi.Results = true; return; } // We got connected.
if (GSRWiFi.Last == 0 || millis() - GSRWiFi.Last > 30000){
if (GSRWiFi.Index < 11){
if (GSRWiFi.Last != 0) GSRWiFi.Index++;
GSRWiFi.Last = millis();
if (GSRWiFi.Index == 0){
setStatus("WiFi-X");
WiFi.onEvent(WatchyGSR::WiFiStationDisconnected, SYSTEM_EVENT_STA_DISCONNECTED);
if (WiFi_DEF_SSID > "") WiFiE = WiFi.begin(WiFi_DEF_SSID,WiFi_DEF_PASS); else WiFiE = WiFi.begin();
if (WiFiE == WL_CONNECT_FAILED) { GSRWiFi.Last = 0; GSRWiFi.Index++; } // Try the next one instantly.
}
if (GSRWiFi.Index > 0){
AP = APIDtoString(GSRWiFi.Index - 1); PA = PASStoString(GSRWiFi.Index - 1);
if (AP > ""){
setStatus("WiFi-" + char(64 + GSRWiFi.Index));
WiFi.disconnect();
WiFi.onEvent(WatchyGSR::WiFiStationDisconnected, SYSTEM_EVENT_STA_DISCONNECTED);
WiFiE = WiFi.begin(AP.c_str(),PA.c_str());
}
if (WiFiE == WL_CONNECT_FAILED) { GSRWiFi.Last = 0; GSRWiFi.Index++; } // Try the next one instantly.
}
}else endWiFi();
}
}
}
wl_status_t WatchyGSR::currentWiFi(){
if (WiFi.status() == WL_CONNECTED) return WL_CONNECTED;
if (GSRWiFi.Working) return WL_IDLE_STATUS; // Make like it is relaxing doing nothing.
return WL_CONNECT_FAILED;
}
void WatchyGSR::endWiFi(){
GSRWiFi.Requested = false;
GSRWiFi.Working = false;
GSRWiFi.Results = false;
GSRWiFi.Index = 0;
setStatus("");
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
}
void WatchyGSR::WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info){
GSRWiFi.Last = 0;
}
String WatchyGSR::buildWiFiAPPage(){
String S = wifiIndexA;
String T;
int I = 0;
while (I < 10){
T = wifiIndexB;
T.replace("$",String(char(65 + I)));
T.replace("#",String(char(48 + I)));
T.replace("?",APIDtoString(I));
S += T;
T = wifiIndexC;
T.replace("#",String(char(48 + I)));
T.replace("$",PASStoString(I));
S += (T + (I < 9 ? "</tr>" : ""));
I++;
}
return S + wifiIndexD;
}
void WatchyGSR::parseWiFiPageArg(String ARG, String DATA){
uint8_t I = String(ARG.charAt(2)).toInt();
String S = ARG.substring(0,2);
if (S == "AP") strcpy(GSRWiFi.AP[I].APID, DATA.c_str());
if (S == "PA") strcpy(GSRWiFi.AP[I].PASS, DATA.c_str());
}
String WatchyGSR::APIDtoString(uint8_t Index){
String S = "";
uint8_t I = 0;
while (GSRWiFi.AP[Index].APID[I] != 0 && I < 32) { S += char(GSRWiFi.AP[Index].APID[I]); I++; }
return S;
}
String WatchyGSR::PASStoString(uint8_t Index){
String S = "";
uint8_t I = 0;
while (GSRWiFi.AP[Index].PASS[I] != 0 && I < 63) { S += char(GSRWiFi.AP[Index].PASS[I]); I++; }
return S;
}
void WatchyGSR::initZeros(){ void WatchyGSR::initZeros(){
String S = "";
GuiMode = WATCHON; GuiMode = WATCHON;
ScreenOn = true; ScreenOn = true;
VibeMode = 0; VibeMode = 0;
@ -2141,6 +2337,34 @@ void WatchyGSR::initZeros(){
Alarms_Playing[1]=0; Alarms_Playing[1]=0;
Alarms_Playing[2]=0; Alarms_Playing[2]=0;
Alarms_Playing[3]=0; Alarms_Playing[3]=0;
Alarms_Repeats[0]=0;
Alarms_Repeats[1]=0;
Alarms_Repeats[2]=0;
Alarms_Repeats[3]=0;
GSRWiFi.Requested=false;
GSRWiFi.Working=false;
GSRWiFi.Results=false;
GSRWiFi.Index=0;
strcpy(GSRWiFi.AP[0].APID,S.c_str());
strcpy(GSRWiFi.AP[0].PASS,S.c_str());
strcpy(GSRWiFi.AP[1].APID,S.c_str());
strcpy(GSRWiFi.AP[1].PASS,S.c_str());
strcpy(GSRWiFi.AP[2].APID,S.c_str());
strcpy(GSRWiFi.AP[2].PASS,S.c_str());
strcpy(GSRWiFi.AP[3].APID,S.c_str());
strcpy(GSRWiFi.AP[3].PASS,S.c_str());
strcpy(GSRWiFi.AP[4].APID,S.c_str());
strcpy(GSRWiFi.AP[4].PASS,S.c_str());
strcpy(GSRWiFi.AP[5].APID,S.c_str());
strcpy(GSRWiFi.AP[5].PASS,S.c_str());
strcpy(GSRWiFi.AP[6].APID,S.c_str());
strcpy(GSRWiFi.AP[6].PASS,S.c_str());
strcpy(GSRWiFi.AP[7].APID,S.c_str());
strcpy(GSRWiFi.AP[7].PASS,S.c_str());
strcpy(GSRWiFi.AP[8].APID,S.c_str());
strcpy(GSRWiFi.AP[8].PASS,S.c_str());
strcpy(GSRWiFi.AP[9].APID,S.c_str());
strcpy(GSRWiFi.AP[9].PASS,S.c_str());
NTPData.TimeZone=true; NTPData.TimeZone=true;
NTPData.UpdateUTC=true; NTPData.UpdateUTC=true;
NTPData.State=1; NTPData.State=1;
@ -2150,16 +2374,19 @@ void WatchyGSR::initZeros(){
TimerDown.MaxHours = 0; TimerDown.MaxHours = 0;
TimerDown.Mins = 0; TimerDown.Mins = 0;
TimerDown.Hours = 0; TimerDown.Hours = 0;
TimerDown.MaxTones = 0;
TimerDown.Active = false; TimerDown.Active = false;
AskForWiFi();
} }
// Settings Storage & Retrieval here. // Settings Storage & Retrieval here.
String WatchyGSR::GetSettings(){ String WatchyGSR::GetSettings(){
unsigned char I[96]; unsigned char I[2048];
unsigned char O[96]; unsigned char O[2048];
int K = 0; int K = 0;
int J = 6; int J = 6;
uint8_t X, Y, W;
uint16_t V; uint16_t V;
String S; String S;
size_t L; size_t L;
@ -2175,21 +2402,40 @@ String WatchyGSR::GetSettings(){
K |= Options.Lefty ? 16 : 0; K |= Options.Lefty ? 16 : 0;
K |= Options.Swapped ? 32 : 0; K |= Options.Swapped ? 32 : 0;
K |= Options.Orientated ? 64 : 0; K |= Options.Orientated ? 64 : 0;
I[2] = (K); I[3] = Options.Turbo; I[2] = (K); V = (Options.MasterRepeats << 5); I[3] = (Options.Turbo | V);
I[4] = (TimerDown.MaxHours); V = (TimerDown.MaxTones << 5);
I[4] = ((TimerDown.MaxHours) | V);
I[5] = (TimerDown.MaxMins); I[5] = (TimerDown.MaxMins);
for (K = 0; K < 4; K++){ for (K = 0; K < 4; K++){
I[J] = (Alarms_Hour[K]); J++; V = (Alarms_Repeats[K] << 5);
I[J] = (Alarms_Hour[K] | V); J++;
I[J] = (Alarms_Minutes[K]); J++; I[J] = (Alarms_Minutes[K]); J++;
V = (Alarms_Active[K] & ALARM_NOTRIGGER); V = (Alarms_Active[K] & ALARM_NOTRIGGER);
I[J] = (V & 255); J++; I[J] = (V & 255); J++;
I[J] = ((V >> 8) & 255); J++; I[J] = ((V >> 8) & 255); J++;
} }
for (X = 0; X < 10; X++){
S = APIDtoString(X);
if (S > "") {
W = S.length();
I[J] = W; J++;
for (Y = 0; Y < W; Y++){
I[J] = S.charAt(Y); J++;
}
S = PASStoString(X);
W = S.length();
I[J] = W; J++;
for (Y = 0; Y < W; Y++){
I[J] = S.charAt(Y); J++;
}
}
}
I[J] = 0; J++; I[J] = 0; J++;
mbedtls_base64_encode(&O[0], 96, &L, &I[0], J); mbedtls_base64_encode(&O[0], 2047, &L, &I[0], J);
O[L]=0; O[L]=0;
S = reinterpret_cast<const char *>(O); S = reinterpret_cast<const char *>(O);
@ -2197,15 +2443,18 @@ String WatchyGSR::GetSettings(){
} }
void WatchyGSR::StoreSettings(String FromUser){ void WatchyGSR::StoreSettings(String FromUser){
unsigned char O[96], E[96]; unsigned char O[2048], E[2048];
int K = 0; int K = 0;
int J = 0; int J = 0;
uint16_t V; uint16_t V;
size_t L; size_t L;
bool Ok;
uint8_t I, A, W; // For WiFi storage.
String S;
J = FromUser.length(); for (K = 0; K < J; K++) E[K] = FromUser.charAt(K); J = FromUser.length(); for (K = 0; K < J; K++) E[K] = FromUser.charAt(K);
mbedtls_base64_decode(&O[0], 96, &L, &E[0], J); L--; // Take dead zero off end. mbedtls_base64_decode(&O[0], 2047, &L, &E[0], J); L--; // Take dead zero off end.
J = 0; if (L > J) Steps.Hour = clamp(O[J],0,23); J = 0; if (L > J) Steps.Hour = clamp(O[J],0,23);
J++; if (L > J) Steps.Minutes = clamp(O[J],0,59); J++; if (L > J) Steps.Minutes = clamp(O[J],0,59);
@ -2220,18 +2469,59 @@ void WatchyGSR::StoreSettings(String FromUser){
Options.Swapped = (V & 32) ? true : false; Options.Swapped = (V & 32) ? true : false;
Options.Orientated = (V & 64) ? true : false; Options.Orientated = (V & 64) ? true : false;
} }
J++; if (L > J) Options.Turbo = clamp(O[J],0,10); J++; if (L > J){
J++; if (L > J) TimerDown.MaxHours = clamp(O[J],0,23); V = ((O[J] & 224) >> 5);
Options.MasterRepeats = V;
Options.Turbo = clamp((O[J] & 31),0,10);
}
J++; if (L > J){
V = ((O[J] & 224) >> 5);
TimerDown.MaxTones = V;
TimerDown.MaxHours = clamp((O[J] & 31),0,23);
}
J++; if (L > J) TimerDown.MaxMins = clamp(O[J],0,59); J++; if (L > J) TimerDown.MaxMins = clamp(O[J],0,59);
for (K = 0; K < 4; K++){ for (K = 0; K < 4; K++){
J++; if (L > J) Alarms_Hour[K] = clamp(O[J],0,23); J++; if (L > J){
V = ((O[J] & 224) >> 5);
Alarms_Repeats[K] = V;
Alarms_Hour[K] = clamp((O[J] & 31),0,23);
}
J++; if (L > J) Alarms_Minutes[K] = clamp(O[J],0,59); J++; if (L > J) Alarms_Minutes[K] = clamp(O[J],0,59);
J++; if (L > J + 1){ J++; if (L > J + 1){
V = ((O[J + 1] & 255) << 8); V = ((O[J + 1] & 255) << 8);
Alarms_Active[K] = ((O[J] | V) & ALARM_NOTRIGGER); J++; Alarms_Active[K] = ((O[J] | V) & ALARM_NOTRIGGER); J++;
} }
} }
S = ""; for (I = 0; I < 10; I++) { strcpy(GSRWiFi.AP[I].APID,S.c_str()); strcpy(GSRWiFi.AP[I].PASS,S.c_str()); }
J++; A = 0;
while (L > J){
Ok = false;
if (L > J){ // get APx
W = O[J]; J++; S = "";
if (L > J + (W - 1)) { // Read APx.
for (I = 0; L > J && I < W; I++){
S += String(char(O[J])); J++;
}
strcpy(GSRWiFi.AP[A].APID,S.c_str());
Ok = true;
}
if (L > J){ // get APx
W = O[J]; J++; S = "";
if (L > J + (W - 1)) { // Read PAx.
for (I = 0; L > J && I < W; I++){
S += String(char(O[J])); J++;
}
strcpy(GSRWiFi.AP[A].PASS,S.c_str());
Ok = true;
}
}
}
if (Ok) A++;
}
OTAFail = millis() - 598000; OTAFail = millis() - 598000;
} }

View File

@ -77,6 +77,7 @@ class WatchyGSR{
void CalculateTones(); void CalculateTones();
void StopCD(); void StopCD();
uint8_t getToneTimes(uint8_t ToneIndex); uint8_t getToneTimes(uint8_t ToneIndex);
String getReduce(uint8_t Amount);
void monitorSteps(); void monitorSteps();
// String GetStoredTimezone(); // String GetStoredTimezone();
// virtual bool StoreTimezone(String Timezone); // virtual bool StoreTimezone(String Timezone);
@ -84,7 +85,16 @@ class WatchyGSR{
uint8_t getButtonMaskToID(uint64_t HW); uint8_t getButtonMaskToID(uint64_t HW);
uint8_t getSwapped(uint8_t pIn); uint8_t getSwapped(uint8_t pIn);
void ScreenRefresh(); void ScreenRefresh();
void AskForWiFi();
void processWiFiRequest();
wl_status_t currentWiFi();
void endWiFi();
static void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
String buildWiFiAPPage();
void parseWiFiPageArg(String ARG, String DATA);
void setupDefaults(); void setupDefaults();
String APIDtoString(uint8_t Index);
String PASStoString(uint8_t Index);
void initZeros(); void initZeros();
String GetSettings(); String GetSettings();
void StoreSettings(String FromUser); void StoreSettings(String FromUser);

View File

@ -40,14 +40,20 @@ static const char basicIndex[] = {
0x69, 0x74, 0x27, 0x3E, 0x42, 0x61, 0x63, 0x6B, 0x75, 0x70, 0x20, 0x26, 0x20, 0x52, 0x65, 0x73, 0x69, 0x74, 0x27, 0x3E, 0x42, 0x61, 0x63, 0x6B, 0x75, 0x70, 0x20, 0x26, 0x20, 0x52, 0x65, 0x73,
0x74, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x3C, 0x2F, 0x62, 0x74, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x3C, 0x2F, 0x62,
0x75, 0x74, 0x74, 0x6F, 0x6E, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x66, 0x6F, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x66, 0x6F,
0x72, 0x6D, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x3D, 0x27, 0x2F, 0x75, 0x70, 0x64, 0x61, 0x72, 0x6D, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x3D, 0x27, 0x2F, 0x77, 0x69, 0x66,
0x74, 0x65, 0x27, 0x3E, 0x3C, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x20, 0x74, 0x79, 0x70, 0x65, 0x69, 0x27, 0x3E, 0x3C, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D,
0x3D, 0x27, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27, 0x3E, 0x55, 0x70, 0x6C, 0x6F, 0x61, 0x64, 0x27, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27, 0x3E, 0x45, 0x64, 0x69, 0x74, 0x20, 0x41, 0x64,
0x20, 0x4E, 0x65, 0x77, 0x20, 0x46, 0x69, 0x72, 0x6D, 0x77, 0x61, 0x72, 0x65, 0x3C, 0x2F, 0x62, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x69, 0x46, 0x69, 0x20, 0x41, 0x63,
0x75, 0x74, 0x74, 0x6F, 0x6E, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x2F, 0x66, 0x63, 0x65, 0x73, 0x73, 0x20, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x73, 0x3C, 0x2F, 0x62, 0x75, 0x74,
0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x6F, 0x6E, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x66, 0x6F, 0x72, 0x6D,
0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x3D, 0x27, 0x2F, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x74, 0x6D, 0x6C, 0x3E, 0x00 0x27, 0x3E, 0x3C, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27,
0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27, 0x3E, 0x55, 0x70, 0x6C, 0x6F, 0x61, 0x64, 0x20, 0x4E,
0x65, 0x77, 0x20, 0x46, 0x69, 0x72, 0x6D, 0x77, 0x61, 0x72, 0x65, 0x3C, 0x2F, 0x62, 0x75, 0x74,
0x74, 0x6F, 0x6E, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E,
0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x61,
0x62, 0x6C, 0x65, 0x3E, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D,
0x6C, 0x3E, 0x00
}; };
static const char settingsA[] = { static const char settingsA[] = {
@ -76,47 +82,45 @@ static const char settingsA[] = {
0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2D, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2D, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x3A, 0x20, 0x23, 0x41, 0x30, 0x39, 0x46, 0x39, 0x46, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3A, 0x20, 0x23, 0x41, 0x30, 0x39, 0x46, 0x39, 0x46, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x61, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x61,
0x72, 0x65, 0x61, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x72, 0x65, 0x61, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F,
0x65, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x3A, 0x20, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6E, 0x3B,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2D, 0x73, 0x70, 0x61, 0x63, 0x20, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x0D, 0x0A,
0x65, 0x3A, 0x20, 0x6E, 0x6F, 0x77, 0x72, 0x61, 0x70, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x73,
0x20, 0x20, 0x20, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x2D, 0x78, 0x3A, 0x20, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x3C, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x6D, 0x65, 0x74,
0x61, 0x75, 0x74, 0x6F, 0x3B, 0x20, 0x2F, 0x2A, 0x20, 0x6F, 0x72, 0x20, 0x68, 0x69, 0x64, 0x64, 0x68, 0x6F, 0x64, 0x3D, 0x27, 0x50, 0x4F, 0x53, 0x54, 0x27, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6F,
0x65, 0x6E, 0x20, 0x2A, 0x2F, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x6E, 0x3D, 0x27, 0x2F, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x27, 0x20, 0x65, 0x6E,
0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x3C, 0x66, 0x63, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27, 0x6D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74,
0x6F, 0x72, 0x6D, 0x20, 0x6D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x3D, 0x27, 0x50, 0x4F, 0x53, 0x54, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x2D, 0x64, 0x61, 0x74, 0x61, 0x27, 0x20, 0x69, 0x64, 0x3D, 0x27,
0x27, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x3D, 0x27, 0x2F, 0x73, 0x65, 0x74, 0x74, 0x69, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x5F, 0x66, 0x6F, 0x72, 0x6D, 0x27, 0x3E, 0x3C,
0x6E, 0x67, 0x73, 0x27, 0x20, 0x65, 0x6E, 0x63, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27, 0x6D, 0x75, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3D, 0x27, 0x32, 0x30, 0x25,
0x6C, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x2D, 0x64, 0x61, 0x74, 0x27, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x27,
0x61, 0x27, 0x20, 0x69, 0x64, 0x3D, 0x27, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x5F, 0x3E, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x6F, 0x6C, 0x73, 0x70, 0x61, 0x6E,
0x66, 0x6F, 0x72, 0x6D, 0x27, 0x3E, 0x3C, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x64, 0x3D, 0x32, 0x3E, 0x3C, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74,
0x74, 0x68, 0x3D, 0x27, 0x32, 0x30, 0x25, 0x27, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x34, 0x3E, 0x3C, 0x62, 0x3E, 0x3C, 0x75, 0x3E, 0x57, 0x61,
0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x27, 0x3E, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x74, 0x63, 0x68, 0x79, 0x20, 0x42, 0x61, 0x63, 0x6B, 0x75, 0x70, 0x20, 0x26, 0x20, 0x52, 0x65,
0x63, 0x6F, 0x6C, 0x73, 0x70, 0x61, 0x6E, 0x3D, 0x32, 0x3E, 0x3C, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x3C, 0x2F,
0x72, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x34, 0x3E, 0x3C, 0x75, 0x3E, 0x3C, 0x2F, 0x62, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x63,
0x62, 0x3E, 0x3C, 0x75, 0x3E, 0x57, 0x61, 0x74, 0x63, 0x68, 0x79, 0x20, 0x42, 0x61, 0x63, 0x6B, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C,
0x75, 0x70, 0x20, 0x26, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x65, 0x74, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x6C,
0x74, 0x69, 0x6E, 0x67, 0x73, 0x3C, 0x2F, 0x75, 0x3E, 0x3C, 0x2F, 0x62, 0x3E, 0x3C, 0x2F, 0x66, 0x65, 0x66, 0x74, 0x27, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x62, 0x6F, 0x74,
0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3E, 0x3C, 0x62, 0x72, 0x74, 0x6F, 0x6D, 0x27, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D,
0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x3E, 0x3C, 0x32, 0x3E, 0x3C, 0x74, 0x65, 0x78, 0x74, 0x61, 0x72, 0x65, 0x61, 0x20, 0x69, 0x64, 0x3D, 0x27,
0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x32, 0x3E, 0x3C, 0x74, 0x65, 0x78, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x27, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x3D, 0x27,
0x74, 0x61, 0x72, 0x65, 0x61, 0x20, 0x69, 0x64, 0x3D, 0x27, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x27, 0x20, 0x72, 0x6F, 0x77, 0x73, 0x3D, 0x27,
0x67, 0x73, 0x27, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x3D, 0x27, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x35, 0x32, 0x27, 0x20, 0x63, 0x6F, 0x6C, 0x73, 0x3D, 0x27, 0x34, 0x30, 0x27, 0x3E, 0x00
0x67, 0x73, 0x27, 0x20, 0x63, 0x6F, 0x6C, 0x73, 0x3D, 0x27, 0x35, 0x30, 0x27, 0x20, 0x72, 0x6F,
0x77, 0x73, 0x3D, 0x27, 0x31, 0x27, 0x3E, 0x00
}; };
static const char settingsB[] = { static const char settingsB[] = {
0x3C, 0x2F, 0x74, 0x65, 0x78, 0x74, 0x61, 0x72, 0x65, 0x61, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x65, 0x78, 0x74, 0x61, 0x72, 0x65, 0x61, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E,
0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x62, 0x3D, 0x27, 0x72, 0x69, 0x67, 0x68, 0x74, 0x27, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D,
0x6F, 0x74, 0x74, 0x6F, 0x6D, 0x27, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x27, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D, 0x27, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73,
0x65, 0x3D, 0x32, 0x3E, 0x3C, 0x69, 0x6E, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x69, 0x7A, 0x65, 0x3D, 0x32, 0x3E, 0x3C, 0x69, 0x6E, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70,
0x27, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x3D, 0x27, 0x65, 0x3D, 0x27, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65,
0x53, 0x74, 0x6F, 0x72, 0x65, 0x27, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x3D, 0x27, 0x53, 0x74, 0x6F, 0x72, 0x65, 0x27, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x66,
0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x61, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x2F,
0x62, 0x6C, 0x65, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x2F, 0x62,
0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x00 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x00
}; };
static const char settingsDone[] = { static const char settingsDone[] = {
@ -170,6 +174,7 @@ static const char settingsDone[] = {
0x62, 0x6C, 0x65, 0x3E, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x62, 0x6C, 0x65, 0x3E, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D,
0x6C, 0x3E, 0x00 0x6C, 0x3E, 0x00
}; };
static const char updateIndex[] = { static const char updateIndex[] = {
0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x3C, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6F, 0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x3C, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6F,
0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x66, 0x67, 0x63, 0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x66, 0x67, 0x63,
@ -225,7 +230,7 @@ static const char updateIndex[] = {
0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3E, 0x3C, 0x66, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, 0x72, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3E, 0x3C, 0x66,
0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x3D, 0x32, 0x3E, 0x3C, 0x69, 0x6E, 0x70, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x3D, 0x32, 0x3E, 0x3C, 0x69, 0x6E, 0x70,
0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x27,
0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x3D, 0x27, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x27, 0x3E, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x3D, 0x27, 0x55, 0x70, 0x6C, 0x6F, 0x61, 0x64, 0x27, 0x3E,
0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E,
0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x0D, 0x0A, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x0D, 0x0A, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x63,
0x6F, 0x6C, 0x73, 0x70, 0x61, 0x6E, 0x3D, 0x32, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x63, 0x65, 0x6F, 0x6C, 0x73, 0x70, 0x61, 0x6E, 0x3D, 0x32, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x63, 0x65,
@ -280,3 +285,156 @@ static const char updateIndex[] = {
0x7D, 0x0D, 0x0A, 0x7D, 0x29, 0x3B, 0x0D, 0x0A, 0x7D, 0x29, 0x3B, 0x0D, 0x0A, 0x3C, 0x2F, 0x73, 0x7D, 0x0D, 0x0A, 0x7D, 0x29, 0x3B, 0x0D, 0x0A, 0x7D, 0x29, 0x3B, 0x0D, 0x0A, 0x3C, 0x2F, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x00 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x00
}; };
static const char wifiIndexA[] = {
0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x3C, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6F,
0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x66, 0x67, 0x63,
0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x3E, 0x3C,
0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x61,
0x62, 0x6C, 0x65, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70,
0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x32, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x32, 0x70,
0x78, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x23, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x3B,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72,
0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E,
0x64, 0x2D, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x41, 0x30, 0x39, 0x46, 0x39, 0x46,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2D,
0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3A, 0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74,
0x64, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x20, 0x7B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A,
0x20, 0x32, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62,
0x6F, 0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x30, 0x70, 0x78, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x64,
0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73,
0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2D, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x3A, 0x20, 0x23, 0x41, 0x30, 0x39, 0x46, 0x39, 0x46, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C,
0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x70,
0x6C, 0x61, 0x79, 0x3A, 0x20, 0x69, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x2D, 0x62, 0x6C, 0x6F, 0x63,
0x6B, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74,
0x2D, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3A, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x3B, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F,
0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x3C, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20,
0x6C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3D, 0x27, 0x6A, 0x61, 0x76, 0x61, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x27, 0x3E, 0x0D, 0x0A, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E,
0x20, 0x74, 0x6F, 0x67, 0x67, 0x6C, 0x65, 0x28, 0x6D, 0x6F, 0x69, 0x29, 0x20, 0x7B, 0x0D, 0x0A,
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x78, 0x20, 0x3D, 0x20, 0x64, 0x6F, 0x63, 0x75, 0x6D, 0x65,
0x6E, 0x74, 0x2E, 0x67, 0x65, 0x74, 0x45, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x42, 0x79, 0x49,
0x64, 0x28, 0x6D, 0x6F, 0x69, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x78,
0x2E, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3D, 0x3D, 0x3D, 0x20, 0x22, 0x70, 0x61, 0x73, 0x73, 0x77,
0x6F, 0x72, 0x64, 0x22, 0x29, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x78, 0x2E, 0x74,
0x79, 0x70, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x3B, 0x0D, 0x0A, 0x20,
0x20, 0x7D, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x78,
0x2E, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72,
0x64, 0x22, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x7D, 0x0D, 0x0A, 0x3C, 0x2F, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0D, 0x0A, 0x3C, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x6D, 0x65,
0x74, 0x68, 0x6F, 0x64, 0x3D, 0x27, 0x50, 0x4F, 0x53, 0x54, 0x27, 0x20, 0x61, 0x63, 0x74, 0x69,
0x6F, 0x6E, 0x3D, 0x27, 0x2F, 0x77, 0x69, 0x66, 0x69, 0x27, 0x20, 0x65, 0x6E, 0x63, 0x74, 0x79,
0x70, 0x65, 0x3D, 0x27, 0x6D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x2F, 0x66, 0x6F,
0x72, 0x6D, 0x2D, 0x64, 0x61, 0x74, 0x61, 0x27, 0x20, 0x69, 0x64, 0x3D, 0x27, 0x77, 0x69, 0x66,
0x69, 0x5F, 0x66, 0x6F, 0x72, 0x6D, 0x27, 0x3E, 0x3C, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x77,
0x69, 0x64, 0x74, 0x68, 0x3D, 0x27, 0x32, 0x30, 0x25, 0x27, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
0x3D, 0x27, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x27, 0x3E, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74,
0x64, 0x20, 0x63, 0x6F, 0x6C, 0x73, 0x70, 0x61, 0x6E, 0x3D, 0x34, 0x3E, 0x3C, 0x63, 0x65, 0x6E,
0x74, 0x65, 0x72, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x34,
0x3E, 0x3C, 0x62, 0x3E, 0x3C, 0x75, 0x3E, 0x57, 0x61, 0x74, 0x63, 0x68, 0x79, 0x20, 0x41, 0x64,
0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x69, 0x46, 0x69, 0x20, 0x41, 0x63,
0x63, 0x65, 0x73, 0x73, 0x20, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69,
0x6E, 0x67, 0x73, 0x3C, 0x2F, 0x75, 0x3E, 0x3C, 0x2F, 0x62, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E,
0x74, 0x3E, 0x3C, 0x2F, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C,
0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x00
};
static const char wifiIndexB[] = {
0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x6C,
0x65, 0x66, 0x74, 0x27, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D,
0x32, 0x3E, 0x41, 0x50, 0x20, 0x24, 0x3A, 0x3C, 0x69, 0x6E, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79,
0x70, 0x65, 0x3D, 0x27, 0x74, 0x65, 0x78, 0x74, 0x27, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x3D, 0x27,
0x41, 0x50, 0x23, 0x27, 0x20, 0x69, 0x64, 0x3D, 0x27, 0x41, 0x50, 0x23, 0x27, 0x20, 0x73, 0x69,
0x7A, 0x65, 0x3D, 0x33, 0x32, 0x20, 0x6D, 0x61, 0x78, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x3D,
0x33, 0x32, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x3D, 0x27, 0x3F, 0x27, 0x3E, 0x3C, 0x2F, 0x66,
0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x00
};
static const char wifiIndexC[] = {
0x3C, 0x74, 0x64, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x6C, 0x65, 0x66, 0x74, 0x27,
0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x32, 0x3E, 0x50, 0x41,
0x53, 0x53, 0x3A, 0x3C, 0x69, 0x6E, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27,
0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, 0x27, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x3D, 0x27,
0x50, 0x41, 0x23, 0x27, 0x20, 0x69, 0x64, 0x3D, 0x27, 0x50, 0x41, 0x23, 0x27, 0x20, 0x73, 0x69,
0x7A, 0x65, 0x3D, 0x36, 0x33, 0x20, 0x6D, 0x61, 0x78, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x3D,
0x36, 0x33, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x3D, 0x27, 0x24, 0x27, 0x3E, 0x3C, 0x2F, 0x69,
0x6E, 0x70, 0x75, 0x74, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74, 0x64,
0x3E, 0x3C, 0x74, 0x64, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x62, 0x6F, 0x74,
0x74, 0x6F, 0x6D, 0x27, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x6C, 0x65, 0x66, 0x74,
0x27, 0x3E, 0x3C, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x6F, 0x6E, 0x63, 0x6C, 0x69, 0x63, 0x6B,
0x3D, 0x22, 0x74, 0x6F, 0x67, 0x67, 0x6C, 0x65, 0x28, 0x27, 0x50, 0x41, 0x23, 0x27, 0x29, 0x22,
0x3E, 0x3F, 0x3C, 0x2F, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x00
};
static const char wifiIndexD[] = {
0x3C, 0x74, 0x64, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x72, 0x69, 0x67, 0x68, 0x74,
0x27, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D,
0x27, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x32, 0x3E, 0x3C,
0x69, 0x6E, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x27, 0x73, 0x75, 0x62, 0x6D,
0x69, 0x74, 0x27, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x3D, 0x27, 0x53, 0x74, 0x6F, 0x72, 0x65,
0x27, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x74,
0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x3C,
0x2F, 0x66, 0x6F, 0x72, 0x6D, 0x3E, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68,
0x74, 0x6D, 0x6C, 0x3E, 0x00
};
static const char wifiDone[] = {
0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x3C, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6F,
0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x20, 0x66, 0x67, 0x63,
0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x22, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x3E, 0x3C,
0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x61,
0x62, 0x6C, 0x65, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70,
0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x32, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x32, 0x70,
0x78, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x23, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x3B,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72,
0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E,
0x64, 0x2D, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x41, 0x30, 0x39, 0x46, 0x39, 0x46,
0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2D,
0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3A, 0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74,
0x64, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x20, 0x7B, 0x0D, 0x0A,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A,
0x20, 0x32, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62,
0x6F, 0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x30, 0x70, 0x78, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x64,
0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73,
0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2D, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x3A, 0x20, 0x23, 0x41, 0x30, 0x39, 0x46, 0x39, 0x46, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x61,
0x72, 0x65, 0x61, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x0D, 0x0A, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2D, 0x73, 0x70, 0x61, 0x63,
0x65, 0x3A, 0x20, 0x6E, 0x6F, 0x77, 0x72, 0x61, 0x70, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x2D, 0x78, 0x3A, 0x20,
0x73, 0x63, 0x72, 0x6F, 0x6C, 0x6C, 0x3B, 0x20, 0x2F, 0x2A, 0x20, 0x6F, 0x72, 0x20, 0x68, 0x69,
0x64, 0x64, 0x65, 0x6E, 0x20, 0x2A, 0x2F, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D,
0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x2F, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A,
0x3C, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3D, 0x27, 0x32, 0x30,
0x25, 0x27, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x27, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72,
0x27, 0x3E, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x64, 0x3E, 0x3C, 0x63, 0x65, 0x6E, 0x74, 0x65,
0x72, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3D, 0x34, 0x3E, 0x3C,
0x62, 0x3E, 0x3C, 0x75, 0x3E, 0x57, 0x61, 0x74, 0x63, 0x68, 0x79, 0x20, 0x41, 0x64, 0x64, 0x69,
0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x50, 0x6F,
0x69, 0x6E, 0x74, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x3C, 0x2F, 0x75, 0x3E,
0x3C, 0x2F, 0x62, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F, 0x63, 0x65, 0x6E,
0x74, 0x65, 0x72, 0x3E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74,
0x72, 0x3E, 0x3C, 0x74, 0x64, 0x3E, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65,
0x3D, 0x33, 0x3E, 0x57, 0x61, 0x74, 0x63, 0x68, 0x79, 0x20, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69,
0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x41, 0x50, 0x73, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x21, 0x20, 0x20, 0x4F, 0x54, 0x41, 0x20, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x20, 0x4F,
0x66, 0x66, 0x2E, 0x3C, 0x62, 0x72, 0x3E, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x3C, 0x2F,
0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x3C, 0x2F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E,
0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x00
};

View File

@ -300,3 +300,25 @@ const unsigned char OptionsMenuBackground [] PROGMEM = {
const unsigned char PMIndicator [] PROGMEM = { const unsigned char PMIndicator [] PROGMEM = {
0x78, 0xfc, 0xfc, 0xfc, 0xfc, 0x78 0x78, 0xfc, 0xfc, 0xfc, 0xfc, 0x78
}; };
// 'Sync', 19x19px
const unsigned char iSync [] PROGMEM = {
0x07, 0xfc, 0x00, 0x1f, 0xff, 0x00, 0x3c, 0x07, 0x80, 0x70, 0x41, 0xc0, 0x60, 0xe0, 0xc0, 0xe0,
0xe0, 0xe0, 0xc0, 0xe0, 0x60, 0xc0, 0xe0, 0x60, 0xc0, 0xe0, 0x60, 0xc0, 0xe0, 0x60, 0xc0, 0x70,
0x60, 0xc0, 0x38, 0x60, 0xc0, 0x1c, 0x60, 0xe0, 0x0e, 0xe0, 0x60, 0x00, 0xc0, 0x70, 0x01, 0xc0,
0x3c, 0x07, 0x80, 0x1f, 0xff, 0x00, 0x07, 0xfc, 0x00
};
// 'TZ', 19x19px
const unsigned char iTZ [] PROGMEM = {
0x07, 0xfc, 0x00, 0x1f, 0xff, 0x00, 0x3c, 0x47, 0x80, 0x70, 0xa1, 0xc0, 0x61, 0x10, 0xc0, 0xe2,
0x08, 0xe0, 0xc2, 0x08, 0x60, 0xff, 0xff, 0xe0, 0xc2, 0x08, 0x60, 0xc2, 0x08, 0x60, 0xc2, 0x08,
0x60, 0xff, 0xff, 0xe0, 0xc2, 0x08, 0x60, 0xe2, 0x08, 0xe0, 0x61, 0x10, 0xc0, 0x70, 0xa1, 0xc0,
0x3c, 0x47, 0x80, 0x1f, 0xff, 0x00, 0x07, 0xfc, 0x00
};
// 'WiFi', 19x19px
const unsigned char iWiFi [] PROGMEM = {
0x22, 0x08, 0x80, 0x44, 0x44, 0x40, 0x44, 0xe4, 0x40, 0x44, 0xe4, 0x40, 0x44, 0xe4, 0x40, 0x44,
0x44, 0x40, 0x22, 0x48, 0x80, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xe0,
0x00, 0x00, 0xe0, 0x00, 0x01, 0xf0, 0x00, 0x01, 0x10, 0x00, 0x03, 0x18, 0x00, 0x02, 0x08, 0x00,
0x06, 0x0c, 0x00, 0x0c, 0x06, 0x00, 0x18, 0x03, 0x00
};