From 1e579804dad9b00cfff9ec1e1c26b4ae9059df81 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 31 Dec 2020 14:19:50 +0100 Subject: [PATCH 01/78] universal file system inital commit --- tasmota/xdrv_98_filesystem.ino | 494 +++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 tasmota/xdrv_98_filesystem.ino diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino new file mode 100644 index 000000000..5ea685109 --- /dev/null +++ b/tasmota/xdrv_98_filesystem.ino @@ -0,0 +1,494 @@ +/* + xdrv_98_filesystem.ino - unified file system for Tasmota + + Copyright (C) 2020 Gerhard Mutz and 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 . +*/ + +/* +this driver adds universal file system support for +ESP8266 (sd card or littlfs on > 1 M devices with special linker file e.g. eagle.flash.4m2m.ld) +(makes no sense on 1M devices without sd card) +and +ESP32 (sd card or fatfile system) +the sd card chip select is the standard SPI_CS or when not found SDCARD_CS_PIN +initializes the FS System Pointer ufsp which can be used by all standard file system calls +the only specific call is ufs_fsinfo() which gets the total size (0) and free size (1) +a button is created in the setup section to show up the file directory to download and upload files +subdirectories are supported + +console calls : + +ufs fs info +ufstype get filesytem type 0=none 1=SD 2=Flashfile +ufssize total size in kB +ufsfree free size in kB + +driver enabled by + +#define USE_UFILESYS + +*/ + + +#ifdef USE_UFILESYS + +#define XDRV_98 98 + +#ifdef ESP8266 +#include +#include +#include +#include +#else +#include +#include "FFat.h" +#include "FS.h" +#include "SPIFFS.h" +#endif + +#define UFS_FILE_WRITE "w" +#define UFS_FILE_READ "r" + +// global file system pointer +FS *ufsp; +char ufs_path[48]; +File ufs_upload_file; + + +#ifndef SDCARD_CS_PIN +#define SDCARD_CS_PIN 4 +#endif + +// 0 = none, 1 = SD, 2 = Flash +// spiffs should be obsolete +uint8_t ufs_type; +#define UFS_TNONE 0 +#define UFS_TSDC 1 +#define UFS_TFAT 2 +#define UFS_TSPIFFS 3 + +#ifndef UFS_SDCS +#define UFS_SDCS 4 +#endif + +void UFSInit(void) { + ufs_type = 0; + // check for fs options, + // 1. check for SD card + // 2. check for littlefs or FAT + // 3. check for SPIFFS obsolete +// if (TasmotaGlobal.spi_enabled) { + if (1) { + int8_t cs; + if (!PinUsed(GPIO_SPI_CS)) { + cs = SDCARD_CS_PIN; + } else { + cs = Pin(GPIO_SPI_CS); + } + + if (SD.begin(cs)) { +#ifdef ESP8266 + ufsp = (FS*)&SD; +#else + ufsp = &SD; +#endif + ufs_type = 1; + return; + } + } + +// if no success with sd card try flash fs +#ifdef ESP8266 + ufsp = &LittleFS; + if (!fsp->begin()) { + return; + } +#else + ufsp = &FFat; + if (!FFat.begin(true)) { + return; + } +#endif + ufs_type = 2; + return; +} + +uint32_t ufs_fsinfo(uint32_t sel) { +uint32_t result = 0; + + switch (ufs_type) { + case UFS_TSDC: +#ifdef ESP32 + if (sel == 0) { + result = SD.totalBytes(); + } else { + result = (SD.totalBytes() - SD.usedBytes()); + } +#else + // currently no support on esp8266 +#endif + break; + case UFS_TFAT: +#ifdef ESP8266 + FSInfo64 fsinfo; + ufsp->info64(fsinfo); + if (sel == 0) { + result = fsinfo.totalBytes; + } else { + result = (fsinfo.totalBytes - fsinfo.usedBytes); + } +#else + if (sel == 0) { + result = FFat.totalBytes(); + } else { + result = FFat.freeBytes(); + } +#endif + break; + case UFS_TSPIFFS: + break; + } + return result / 10000; +} + +#if USE_LONG_FILE_NAMES>0 +#undef REJCMPL +#define REJCMPL 6 +#else +#undef REJCMPL +#define REJCMPL 8 +#endif + +uint8_t ufs_reject(char *name) { + + char *lcp = strrchr(name,'/'); + if (lcp) { + name = lcp + 1; + } + + while (*name=='/') name++; + if (*name=='_') return 1; + if (*name=='.') return 1; + + if (!strncasecmp(name, "SPOTLI~1", REJCMPL)) return 1; + if (!strncasecmp(name, "TRASHE~1", REJCMPL)) return 1; + if (!strncasecmp(name, "FSEVEN~1", REJCMPL)) return 1; + if (!strncasecmp(name, "SYSTEM~1", REJCMPL)) return 1; + if (!strncasecmp(name, "System Volume", 13)) return 1; + return 0; +} + +// format number with thousand marker +void UFS_form1000(uint32_t number, char *dp, char sc) { + char str[32]; + sprintf(str, "%d", number); + char *sp = str; + uint32_t inum = strlen(sp)/3; + uint32_t fnum = strlen(sp)%3; + if (!fnum) inum--; + for (uint32_t count=0; count<=inum; count++) { + if (fnum){ + memcpy(dp,sp,fnum); + dp+=fnum; + sp+=fnum; + fnum=0; + } else { + memcpy(dp,sp,3); + dp+=3; + sp+=3; + } + if (count!=inum) { + *dp++=sc; + } + } + *dp=0; +} + + +const char kUFSCommands[] PROGMEM = "UFS" "|" // Prefix + "|" "TYPE" "|" "SIZE" "|" "FREE"; + +void (* const kUFSCommand[])(void) PROGMEM = { + &UFS_info, &UFS_type, &UFS_size, &UFS_free}; + +void UFS_info(void) { + Response_P(PSTR("{\"UFS\":{\"TYPE\":%d,\"SIZE\":%d,\"FREE\":%d}}"),ufs_type,ufs_fsinfo(0),ufs_fsinfo(1)); +} +void UFS_type(void) { + ResponseCmndNumber(ufs_type); +} +void UFS_size(void) { + ResponseCmndNumber(ufs_fsinfo(0)); +} +void UFS_free(void) { + ResponseCmndNumber(ufs_fsinfo(1)); +} + +const char UFS_WEB_DIR[] PROGMEM = + "

"; +const char UFS_FILE_UPLOAD[] PROGMEM = D_SDCARD_DIR; +const char UFS_FORM_FILE_UPLOAD[] PROGMEM = +"
" +"
 %s" " "; +const char UFS_FORM_FILE_UPG[] PROGMEM = +"
" +"

" +"
"; +const char UFS_FORM_FILE_UPGc[] PROGMEM = +"
total size: %s kB - free: %s kB
"; +const char UFS_FORM_SDC_DIRa[] PROGMEM = +"
"; +const char UFS_FORM_SDC_DIRc[] PROGMEM = +"
"; +const char UFS_FORM_FILE_UPGb[] PROGMEM = +"
" +"
" +""; +const char UFS_FORM_SDC_DIRd[] PROGMEM = +"
%s
"; +const char UFS_FORM_SDC_DIRb[] PROGMEM = + "
%s     %s : %8d
"; +const char UFS_FORM_SDC_HREF[] PROGMEM = + "http://%s/ufsd?download=%s/%s"; + +void UFSdirectory(void) { + uint8_t depth = 0; + + strcpy(ufs_path, "/"); + if (!HttpCheckPriviledgedAccess()) { return; } + + if (Webserver->hasArg("download")) { + String stmp = Webserver->arg("download"); + char *cp = (char*)stmp.c_str(); + if (UFS_DownloadFile(cp)) { + // is directory + strcpy(ufs_path, cp); + } + } + + WSContentStart_P(UFS_FILE_UPLOAD); + WSContentSendStyle(); + WSContentSend_P(UFS_FORM_FILE_UPLOAD,D_SDCARD_DIR); + WSContentSend_P(UFS_FORM_FILE_UPG, D_SCRIPT_UPLOAD); + char ts[16]; + char fs[16]; + UFS_form1000(ufs_fsinfo(0), ts, '.'); + UFS_form1000(ufs_fsinfo(1), fs, '.'); + WSContentSend_P(UFS_FORM_FILE_UPGc, ts, fs); + WSContentSend_P(UFS_FORM_SDC_DIRa); + if (ufs_type) { + UFS_ListDir(ufs_path, depth); + } + WSContentSend_P(UFS_FORM_SDC_DIRc); + WSContentSend_P(UFS_FORM_FILE_UPGb); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentStop(); + Web.upload_error = 0; + +} + +void UFS_ListDir(char *path, uint8_t depth) { + char name[32]; + char npath[128]; + char format[12]; + sprintf(format, "%%-%ds", 24 - depth); + + File dir = ufsp->open(path, UFS_FILE_READ); + if (dir) { + dir.rewindDirectory(); + if (strlen(path)>1) { + snprintf_P(npath, sizeof(npath), PSTR("http://%s/ufsd?download=%s"), WiFi.localIP().toString().c_str(),path); + for (uint8_t cnt = strlen(npath) - 1; cnt>0; cnt--) { + if (npath[cnt]=='/') { + if (npath[cnt - 1]=='=') npath[cnt + 1] = 0; + else npath[cnt] = 0; + break; + } + } + WSContentSend_P(UFS_FORM_SDC_DIRd, npath,path, ".."); + } + char *ep; + while (true) { + File entry = dir.openNextFile(); + if (!entry) { + break; + } + // esp32 returns path here, shorten to filename + ep = (char*)entry.name(); + if (*ep=='/') ep++; + char *lcp = strrchr(ep,'/'); + if (lcp) { + ep = lcp + 1; + } + time_t tm = entry.getLastWrite(); + char tstr[24]; + strftime(tstr, 22, "%d-%m-%Y - %H:%M:%S ", localtime(&tm)); + + char *pp = path; + if (!*(pp + 1)) pp++; + char *cp = name; + // osx formatted disks contain a lot of stuff we dont want + if (ufs_reject((char*)ep)) goto fclose; + + for (uint8_t cnt = 0; cnt1) { + strcat(path, "/"); + } + strcat(path, ep); + UFS_ListDir(path, depth + 4); + path[plen] = 0; + } else { + snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp,ep); + WSContentSend_P(UFS_FORM_SDC_DIRb, npath, ep, name, tstr, entry.size()); + } + fclose: + entry.close(); + } + dir.close(); + } +} + +uint8_t UFS_DownloadFile(char *file) { + File download_file; + WiFiClient download_Client; + + if (!ufsp->exists(file)) { + AddLog_P(LOG_LEVEL_INFO, PSTR("file not found")); + return 0; + } + + download_file = ufsp->open(file, UFS_FILE_READ); + if (!download_file) { + AddLog_P(LOG_LEVEL_INFO, PSTR("could not open file")); + return 0; + } + + if (download_file.isDirectory()) { + download_file.close(); + return 1; + } + + uint32_t flen = download_file.size(); + + download_Client = Webserver->client(); + Webserver->setContentLength(flen); + + char attachment[100]; + char *cp; + for (uint8_t cnt = strlen(file); cnt>=0; cnt--) { + if (file[cnt]=='/') { + cp = &file[cnt + 1]; + break; + } + } + snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), cp); + Webserver->sendHeader(F("Content-Disposition"), attachment); + WSSend(200, CT_STREAM, ""); + + uint8_t buff[512]; + uint16_t bread; + + // transfer is about 150kb/s + uint8_t cnt = 0; + while (download_file.available()) { + bread = download_file.read(buff, sizeof(buff)); + uint16_t bw = download_Client.write((const char*)buff, bread); + if (!bw) break; + cnt++; + if (cnt>7) { + cnt = 0; + //if (glob_script_mem.script_loglevel & 0x80) { + // this indeed multitasks, but is slower 50 kB/s + // loop(); + //} + } + } + download_file.close(); + download_Client.stop(); + return 0; +} + +void UFS_Upload(void) { + HTTPUpload& upload = Webserver->upload(); + if (upload.status == UPLOAD_FILE_START) { + char npath[48]; + sprintf(npath, "%s/%s", ufs_path, upload.filename.c_str()); + ufsp->remove(npath); + ufs_upload_file = ufsp->open(npath, UFS_FILE_WRITE); + if (!ufs_upload_file) Web.upload_error = 1; + } else if(upload.status == UPLOAD_FILE_WRITE) { + if (ufs_upload_file) ufs_upload_file.write(upload.buf, upload.currentSize); + } else if(upload.status == UPLOAD_FILE_END) { + if (ufs_upload_file) ufs_upload_file.close(); + if (Web.upload_error) { + AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: upload error")); + } + } else { + Web.upload_error=1; + Webserver->send(500, "text/plain", "500: couldn't create file"); + } +} + +void UFSFileUploadSuccess(void) { + WSContentStart_P(PSTR(D_INFORMATION)); + WSContentSendStyle(); + WSContentSend_P(PSTR("
" D_UPLOAD " " D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS)); + WSContentSend_P(PSTR("

")); + WSContentSend_P(PSTR("

"),"/ufsd",D_UPL_DONE); + WSContentStop(); +} + +#define D_UFSDIR "UFS directory" + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv98(uint8_t function) { + bool result = false; + + switch (function) { + case FUNC_PRE_INIT: + UFSInit(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kUFSCommands, kUFSCommand); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_ADD_BUTTON: + if (ufs_type) { + WSContentSend_PD(UFS_WEB_DIR,D_UFSDIR); + } + break; + case FUNC_WEB_ADD_HANDLER: + Webserver->on("/ufsd", UFSdirectory); + Webserver->on("/ufsu", HTTP_GET, UFSFileUploadSuccess); + Webserver->on("/ufsu", HTTP_POST,[]() { Webserver->sendHeader("Location","/ufsu");Webserver->send(303);}, UFS_Upload); + break; +#endif // USE_WEBSERVER + } + return result; +} +#endif // USE_UFILESYS From a8fbdcabd3a2a951877a2b32a57241d2604d2fd7 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 31 Dec 2020 15:07:08 +0100 Subject: [PATCH 02/78] Create esp32_partition_app1984k_ffat64k.csv --- esp32_partition_app1984k_ffat64k.csv | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 esp32_partition_app1984k_ffat64k.csv diff --git a/esp32_partition_app1984k_ffat64k.csv b/esp32_partition_app1984k_ffat64k.csv new file mode 100644 index 000000000..98ce760eb --- /dev/null +++ b/esp32_partition_app1984k_ffat64k.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1F0000, +app1, app, ota_1, 0x200000, 0x1F0000, +ffat, data, fat, 0x3F0000,0x10000, From 9c9d7e0eef35f786fab67cdfaf188c18c5949495 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 31 Dec 2020 16:41:58 +0100 Subject: [PATCH 03/78] spiffs --- tasmota/xdrv_98_filesystem.ino | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 5ea685109..3615ebbaa 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -105,7 +105,7 @@ void UFSInit(void) { #else ufsp = &SD; #endif - ufs_type = 1; + ufs_type = UFS_TSDC; return; } } @@ -119,10 +119,17 @@ void UFSInit(void) { #else ufsp = &FFat; if (!FFat.begin(true)) { + if (!SPIFFS.begin(true)) { + return; + } + ufsp = &SPIFFS; + ufs_type = UFS_TSPIFFS; return; } + + #endif - ufs_type = 2; + ufs_type = UFS_TFAT; return; } @@ -159,9 +166,14 @@ uint32_t result = 0; #endif break; case UFS_TSPIFFS: + if (sel == 0) { + result = SPIFFS.totalBytes(); + } else { + result = SPIFFS.totalBytes() - SPIFFS.usedBytes(); + } break; } - return result / 10000; + return result / 1000; } #if USE_LONG_FILE_NAMES>0 @@ -373,6 +385,10 @@ uint8_t UFS_DownloadFile(char *file) { File download_file; WiFiClient download_Client; + AddLog_P(LOG_LEVEL_INFO, PSTR("file not found %s"),file); + + if (*file == '/') file++; + if (!ufsp->exists(file)) { AddLog_P(LOG_LEVEL_INFO, PSTR("file not found")); return 0; From 0de64f33761b075cfd93c45d8b364375bb8350dd Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 31 Dec 2020 18:05:42 +0100 Subject: [PATCH 04/78] esp32 littlefs --- lib/libesp32/LITTLEFS/LICENSE | 339 ++ lib/libesp32/LITTLEFS/README.md | 104 + .../examples/LITTLEFS_PlatformIO/.gitignore | 4 + .../examples/LITTLEFS_PlatformIO/README.md | 68 + .../LITTLEFS_PlatformIO/data/file1.txt | 1 + .../data/testfolder/test2.txt | 1 + .../include/.placeholder.txt | 0 .../LITTLEFS_PlatformIO/lib/.placeholder.txt | 0 .../LITTLEFS_PlatformIO/littlefsbuilder.py | 2 + .../LITTLEFS_PlatformIO/partitions_custom.csv | 6 + .../LITTLEFS_PlatformIO/platformio.ini | 35 + .../examples/LITTLEFS_PlatformIO/src/main.cpp | 291 + .../examples/LITTLEFS_time/LITTLEFS_time.ino | 219 + .../examples/LittleFS_test/LittleFS_test.ino | 270 + lib/libesp32/LITTLEFS/library.json | 22 + lib/libesp32/LITTLEFS/library.properties | 9 + lib/libesp32/LITTLEFS/src/LICENSE | 7 + lib/libesp32/LITTLEFS/src/LICENSE.md | 24 + lib/libesp32/LITTLEFS/src/LITTLEFS.cpp | 105 + lib/libesp32/LITTLEFS/src/LITTLEFS.h | 38 + lib/libesp32/LITTLEFS/src/esp_littlefs.c | 1626 ++++++ lib/libesp32/LITTLEFS/src/esp_littlefs.h | 118 + lib/libesp32/LITTLEFS/src/lfs.c | 4918 +++++++++++++++++ lib/libesp32/LITTLEFS/src/lfs.h | 655 +++ lib/libesp32/LITTLEFS/src/lfs_util.c | 33 + lib/libesp32/LITTLEFS/src/lfs_util.h | 234 + lib/libesp32/LITTLEFS/src/littlefs_api.c | 58 + lib/libesp32/LITTLEFS/src/littlefs_api.h | 106 + tasmota/xdrv_98_filesystem.ino | 39 +- 29 files changed, 9320 insertions(+), 12 deletions(-) create mode 100755 lib/libesp32/LITTLEFS/LICENSE create mode 100755 lib/libesp32/LITTLEFS/README.md create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp create mode 100755 lib/libesp32/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino create mode 100755 lib/libesp32/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino create mode 100755 lib/libesp32/LITTLEFS/library.json create mode 100755 lib/libesp32/LITTLEFS/library.properties create mode 100755 lib/libesp32/LITTLEFS/src/LICENSE create mode 100755 lib/libesp32/LITTLEFS/src/LICENSE.md create mode 100755 lib/libesp32/LITTLEFS/src/LITTLEFS.cpp create mode 100755 lib/libesp32/LITTLEFS/src/LITTLEFS.h create mode 100755 lib/libesp32/LITTLEFS/src/esp_littlefs.c create mode 100755 lib/libesp32/LITTLEFS/src/esp_littlefs.h create mode 100755 lib/libesp32/LITTLEFS/src/lfs.c create mode 100755 lib/libesp32/LITTLEFS/src/lfs.h create mode 100755 lib/libesp32/LITTLEFS/src/lfs_util.c create mode 100755 lib/libesp32/LITTLEFS/src/lfs_util.h create mode 100755 lib/libesp32/LITTLEFS/src/littlefs_api.c create mode 100755 lib/libesp32/LITTLEFS/src/littlefs_api.h diff --git a/lib/libesp32/LITTLEFS/LICENSE b/lib/libesp32/LITTLEFS/LICENSE new file mode 100755 index 000000000..d159169d1 --- /dev/null +++ b/lib/libesp32/LITTLEFS/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/lib/libesp32/LITTLEFS/README.md b/lib/libesp32/LITTLEFS/README.md new file mode 100755 index 000000000..8c5cec1d6 --- /dev/null +++ b/lib/libesp32/LITTLEFS/README.md @@ -0,0 +1,104 @@ +# LittleFS_esp32 + +#### ***Notice: The Library is been integrated to [Arduino esp32 core idf-release/v4.2 branch](https://github.com/espressif/arduino-esp32/tree/idf-release/v4.2 ) for future major core release. On built-in library, #define tweaks below will be unavailable.*** + + +## LittleFS library for arduino-esp32 + +- A LittleFS wrapper for Arduino ESP32 of [littlefs-project](https://github.com/littlefs-project/littlefs) +- Based on [ESP-IDF port of joltwallet/esp_littlefs](https://github.com/joltwallet/esp_littlefs) , thank you Brian! +- As a reference, see [LillteFS library for ESP8266 core](https://github.com/esp8266/Arduino/tree/master/libraries/LittleFS) +- [PR](https://github.com/espressif/arduino-esp32/pull/4096) and [merge](https://github.com/espressif/arduino-esp32/pull/4483) at esp32 core development +- [PR](https://github.com/espressif/esp-idf/pull/5469) at esp-idf development +- The functionality is similar to SPIFFS + +### Installation + +- Use **Arduino Library Manager** +- Or download / use **git** to have latest repository of **LITTLEFS** added to Arduino IDE **/libraries** folder +(File > Preferences > Sketchbook location). +- See ``` #define CONFIG_LITTLEFS_FOR_IDF_3_2 ``` in **esp_littlefs.c**. +Now it is defined / undefined automatically by detecting the IDF version and core version. +When defined, the library works with old and new IDFs 3.2 - 4.x but file timestamp feature is removed. +See LITTLEFS_time example. +- See ``` #define CONFIG_LITTLEFS_SPIFFS_COMPAT ``` in **esp_littlefs.c**. +When set to 1, folders are recursively created or deleted if empty on creating/deleting a new file like SPIFFS. Default is 0. +- The other ``` #define CONFIG_LITTLEFS_xxxxx ``` are set to optimal default values. +Read [here](https://github.com/joltwallet/esp_littlefs/blob/master/Kconfig) and [here](https://github.com/littlefs-project//littlefs/blob/master/README.md) if you want to modify. +- For low-level default error reporting modifications, see the defines at beginning of the **lfs.c** here. + +### Usage + +- Use LITTLEFS [with identical methods as SPIFFS](https://diyprojects.io/esp32-get-started-spiff-library-read-write-modify-files/) plus mkdir() and rmdir() +- A quick startup based on your existing code you can re-define SPIFFS +``` +#define USE_LittleFS + +#include +#ifdef USE_LittleFS + #define SPIFFS LITTLEFS + #include +#else + #include +#endif + ``` + - Note, this may not work if your sketch uses other libraries that use SPIFFS themselves. + - See also [esp_partition.h](https://github.com/espressif/esp-idf/blob/master/components/spi_flash/include/esp_partition.h) . LITTLEFS re-uses same type and subtype as SPIFFS + +### Differences with SPIFFS + +- LittleFS has folders, you need to iterate files in folders unless you set ``` #define CONFIG_LITTLEFS_SPIFFS_COMPAT 1 ``` +- At root a "/folder" = "folder" +- Requires a label for mount point, NULL will not work. Recommended is to use default LITTLEFS.begin() +- maxOpenFiles parameter is unused, kept for compatibility +- LITTLEFS.mkdir(path) and LITTLEFS.rmdir(path) are available +- file.seek() behaves like on FFat see [more details](https://github.com/lorol/LITTLEFS/issues/11) +- file.write() and file.print() when partition space is ending may return different than really written bytes (on other FS is also inconsistent). +- Speed comparison based on **LittleFS_test.ino** sketch (for a file 1048576 bytes): + +|Filesystem|Read time [ms]|Write time [ms]| +|----|----|----| +|FAT|276|14493| +|LITTLEFS|446*|16387| +|SPIFFS|767|65622| + +*The read speed improved by changing ```#define CONFIG_LITTLEFS_CACHE_SIZE``` from 128 to 512 + + +### Arduino ESP32 LittleFS filesystem upload tool + +- Use (replace if exists) [arduino-esp32fs-plugin](https://github.com/me-no-dev/arduino-esp32fs-plugin/pull/23 ) with [this variant](https://github.com/lorol/arduino-esp32fs-plugin), which supports SPIFFS, LittleFS and FatFS +- Requires [mklittlefs executable](https://github.com/earlephilhower/mklittlefs) which is available [in releases section here](https://github.com/lorol/arduino-esp32fs-plugin ) or download the zipped binary [here](https://github.com/earlephilhower/mklittlefs/releases) or from **esp-quick-toolchain** releases [here](https://github.com/earlephilhower/esp-quick-toolchain/releases) +- Copy it to **/tools** folder of esp32 platform where **espota** and **esptool** (.py or.exe) tools are located +- Restart Arduino IDE. + +### PlatformIO + +- See [LITTLEFS_PlatformIO example here](https://github.com/lorol/LITTLEFS/tree/master/examples/LITTLEFS_PlatformIO) + ( based on notes below from [BlueAndi](https://github.com/BlueAndi) ) +- Add to _platformio.ini_: + `extra_scripts = replace_fs.py` + +- Add _replace_fs.py_ to project root directory (where platformio.ini is located): + + ```python + Import("env") + print("Replace MKSPIFFSTOOL with mklittlefs.exe") + env.Replace (MKSPIFFSTOOL = "mklittlefs.exe") + ``` + +- Add _mklittlefs.exe_ to project root directory as well. + +## Credits and license + +- This work is based on [littlefs-project](https://github.com/littlefs-project/littlefs) , [ESP-IDF port of joltwallet/esp_littlefs](https://github.com/joltwallet/esp_littlefs) , [Espressif Arduino core for the ESP32, the ESP-IDF - SPIFFS Library](https://github.com/espressif/arduino-esp32/tree/master/libraries/SPIFFS) +- Licensed under GPL v2 ([text](LICENSE)) + +## To Do + - [x] Submit to be added to Arduino Library Manager + - [x] Optional drop-in compatibility with SPIFFS' lack of folders, similar to esp8266' way - implemented as a choice by a #define + - [recursive folders auto creation](https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.cpp#L60) when a new file is created at non-existing path + - [recursive folders auto deletion](https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h#L149) on "last file" deletion (SPIFFS cannot have "folder w/o file") + - review other differences: opendir(), rmdir(), unlink() + - [ ] Retire this library when released by esp32 Arduino core + - [ ] Cleanup examples diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore new file mode 100755 index 000000000..87515a624 --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore @@ -0,0 +1,4 @@ +.pio +.vscode +mklittlefs.exe +mklittlefs \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md new file mode 100755 index 000000000..773445b6d --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md @@ -0,0 +1,68 @@ +# How to run on PlatformIO IDE + +- Download and extract to this project root a **mklittlefs** executable for your OS [from a zipped binary here](https://github.com/earlephilhower/mklittlefs/releases) +- Open **LITTLEFS_PlatformIO** folder +- Run PlatformIO project task: **Upload Filesystem Image** +- Run PlatformIO project task: **Upload and Monitor** +- You will see a Serial output like: +``` +--- Miniterm on COM5 115200,8,N,1 --- +--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- +ets Jun 8 2016 00:22:57 + +rst:0x1 (POWERON_RESET),boot:0x13 (Snfigsip: 0, SPIWP:0xee +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:2 +load:0x3fff0018,len:4 +load:0x3fff001c,len:1044 +load:0x40078000,len:10044 +load:0x40080400,len:5872 +entry 0x400806ac +Listing directory: / + FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 + DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 +Creating Dir: /mydir +Dir created +Writing file: /mydir/hello2.txt +- file written +Listing directory: / + FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 + DIR : /mydir LAST WRITE: 1970-01-01 00:00:00 +Listing directory: /mydir + FILE: /mydir/hello2.txt SIZE: 6 LAST WRITE: 1970-01-01 00:00:00 + DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 +Listing directory: /testfolder + FILE: /testfolder/test2.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 +Deleting file: /mydir/hello2.txt +- file deleted +Removing Dir: /mydir +Dir removed +Listing directory: / + FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 + DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 +Listing directory: /testfolder + FILE: /testfolder/test2.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 +Writing file: /hello.txt +- file written +Appending to file: /hello.txt +- message appended +Reading file: /hello.txt +- read from file: +Hello World! +Renaming file /hello.txt to /foo.txt +- file renamed +Reading file: /foo.txt +- read from file: +Hello World! +Deleting file: /foo.txt +- file deleted +Testing file I/O with /test.txt +- writing................................................................ + - 1048576 bytes written in 12006 ms +- reading................................................................ +- 1048576 bytes read in 547 ms +Deleting file: /test.txt +- file deleted +Test complete +``` +- If you have a module with more than 4MB flash, you can uncomment **partitions_custom.csv** in **platformio.ini** and modify the csv file accordingly \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt new file mode 100755 index 000000000..7c4a013e5 --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt @@ -0,0 +1 @@ +aaa \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt new file mode 100755 index 000000000..01f02e32c --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt @@ -0,0 +1 @@ +bbb \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt new file mode 100755 index 000000000..e69de29bb diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt new file mode 100755 index 000000000..e69de29bb diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py new file mode 100755 index 000000000..93937e296 --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py @@ -0,0 +1,2 @@ +Import("env") +env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' ) \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv new file mode 100755 index 000000000..97846fa59 --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +ota_0, app, ota_0, 0x10000, 0x1A0000, +ota_1, app, ota_1, , 0x1A0000, +otadata, data, ota, 0x350000, 0x2000, +nvs, data, nvs, , 0x6000, +data, data, spiffs, , 0xA8000, diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini new file mode 100755 index 000000000..43e34ec0d --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini @@ -0,0 +1,35 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = esp32 + +[env] +framework = arduino + +[env:esp32] +platform = espressif32 +;platform = https://github.com/platformio/platform-espressif32.git +;board_build.mcu = esp32 +platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git + +build_flags = + ${env.build_flags} + -D=${PIOENV} + ;-D CONFIG_LITTLEFS_FOR_IDF_3_2 + +lib_deps = https://github.com/lorol/LITTLEFS.git + +board = esp32dev +;board_build.partitions = partitions_custom.csv +monitor_filters = esp32_exception_decoder +monitor_speed = 115200 + +extra_scripts = ./littlefsbuilder.py diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp new file mode 100755 index 000000000..786f04380 --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp @@ -0,0 +1,291 @@ +#include +#include "FS.h" +#include + +#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 + #include +#endif + +/* You only need to format LITTLEFS the first time you run a + test or else use the LITTLEFS plugin to create a partition + https://github.com/lorol/arduino-esp32littlefs-plugin */ + +#define FORMAT_LITTLEFS_IF_FAILED true + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("- failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + +#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2 + Serial.println(file.name()); +#else + Serial.print(file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); +#endif + + if(levels){ + listDir(fs, file.name(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + +#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2 + Serial.println(file.size()); +#else + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); +#endif + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + + File file = fs.open(path); + if(!file || file.isDirectory()){ + Serial.println("- failed to open file for reading"); + return; + } + + Serial.println("- read from file:"); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\r\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("- failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("- message appended"); + } else { + Serial.println("- append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\r\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("- file renamed"); + } else { + Serial.println("- rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\r\n", path); + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } +} + +// SPIFFS-like write and delete file, better use #define CONFIG_LITTLEFS_SPIFFS_COMPAT 1 + +void writeFile2(fs::FS &fs, const char * path, const char * message){ + if(!fs.exists(path)){ + if (strchr(path, '/')) { + Serial.printf("Create missing folders of: %s\r\n", path); + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strchr(pathStr, '/'); + while (ptr) { + *ptr = 0; + fs.mkdir(pathStr); + *ptr = '/'; + ptr = strchr(ptr+1, '/'); + } + } + free(pathStr); + } + } + + Serial.printf("Writing file to: %s\r\n", path); + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void deleteFile2(fs::FS &fs, const char * path){ + Serial.printf("Deleting file and empty folders on path: %s\r\n", path); + + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } + + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strrchr(pathStr, '/'); + if (ptr) { + Serial.printf("Removing all empty folders on path: %s\r\n", path); + } + while (ptr) { + *ptr = 0; + fs.rmdir(pathStr); + ptr = strrchr(pathStr, '/'); + } + free(pathStr); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + Serial.printf("Testing file I/O with %s\r\n", path); + + static uint8_t buf[512]; + size_t len = 0; + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + + size_t i; + Serial.print("- writing" ); + uint32_t start = millis(); + for(i=0; i<2048; i++){ + if ((i & 0x001F) == 0x001F){ + Serial.print("."); + } + file.write(buf, 512); + } + Serial.println(""); + uint32_t end = millis() - start; + Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end); + file.close(); + + file = fs.open(path); + start = millis(); + end = start; + i = 0; + if(file && !file.isDirectory()){ + len = file.size(); + size_t flen = len; + start = millis(); + Serial.print("- reading" ); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + if ((i++ & 0x001F) == 0x001F){ + Serial.print("."); + } + len -= toRead; + } + Serial.println(""); + end = millis() - start; + Serial.printf("- %u bytes read in %u ms\r\n", flen, end); + file.close(); + } else { + Serial.println("- failed to open file for reading"); + } +} + +void setup(){ + Serial.begin(115200); + if(!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ + Serial.println("LITTLEFS Mount Failed"); + return; + } + + listDir(LITTLEFS, "/", 0); + createDir(LITTLEFS, "/mydir"); + writeFile(LITTLEFS, "/mydir/hello2.txt", "Hello2"); + //writeFile(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3"); + writeFile2(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3"); + listDir(LITTLEFS, "/", 3); + deleteFile(LITTLEFS, "/mydir/hello2.txt"); + //deleteFile(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt"); + deleteFile2(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt"); + removeDir(LITTLEFS, "/mydir"); + listDir(LITTLEFS, "/", 3); + writeFile(LITTLEFS, "/hello.txt", "Hello "); + appendFile(LITTLEFS, "/hello.txt", "World!\r\n"); + readFile(LITTLEFS, "/hello.txt"); + renameFile(LITTLEFS, "/hello.txt", "/foo.txt"); + readFile(LITTLEFS, "/foo.txt"); + deleteFile(LITTLEFS, "/foo.txt"); + testFileIO(LITTLEFS, "/test.txt"); + deleteFile(LITTLEFS, "/test.txt"); + + Serial.println( "Test complete" ); +} + +void loop(){ + +} diff --git a/lib/libesp32/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino b/lib/libesp32/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino new file mode 100755 index 000000000..933cd4f3b --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino @@ -0,0 +1,219 @@ +#include "FS.h" +//#include "SPIFFS.h" +#include "LITTLEFS.h" +#include +#include + +#define SPIFFS LITTLEFS + +/* This examples uses "quick re-define" of SPIFFS to run + an existing sketch with LITTLEFS instead of SPIFFS + + To get time/date stamps by file.getLastWrite(), you need an + esp32 core on IDF 3.3 and comment a line in file esp_littlefs.c: + + //#define CONFIG_LITTLEFS_FOR_IDF_3_2 + + You only need to format LITTLEFS the first time you run a + test or else use the LITTLEFS plugin to create a partition + https://github.com/lorol/arduino-esp32littlefs-plugin */ + +#define FORMAT_LITTLEFS_IF_FAILED true + +const char* ssid = "yourssid"; +const char* password = "yourpass"; + +long timezone = 1; +byte daysavetime = 1; + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.print (file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + if(levels){ + listDir(fs, file.name(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup(){ + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + + if(!SPIFFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ + Serial.println("LITTLEFS Mount Failed"); + return; + } + + Serial.println("----list 1----"); + listDir(SPIFFS, "/", 1); + + Serial.println("----remove old dir----"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----create a new dir----"); + createDir(SPIFFS, "/mydir"); + + Serial.println("----remove the new dir----"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----create the new again----"); + createDir(SPIFFS, "/mydir"); + + Serial.println("----create and work with file----"); + writeFile(SPIFFS, "/mydir/hello.txt", "Hello "); + appendFile(SPIFFS, "/mydir/hello.txt", "World!\n"); + + Serial.println("----list 2----"); + listDir(SPIFFS, "/", 1); + + Serial.println("----attempt to remove dir w/ file----"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----remove dir after deleting file----"); + deleteFile(SPIFFS, "/mydir/hello.txt"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----list 3----"); + listDir(SPIFFS, "/", 1); + + Serial.println( "Test complete" ); + +} + +void loop(){ + +} diff --git a/lib/libesp32/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino b/lib/libesp32/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino new file mode 100755 index 000000000..3abb8908e --- /dev/null +++ b/lib/libesp32/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino @@ -0,0 +1,270 @@ +#include +#include "FS.h" +#include + +/* You only need to format LITTLEFS the first time you run a + test or else use the LITTLEFS plugin to create a partition + https://github.com/lorol/arduino-esp32littlefs-plugin */ + +#define FORMAT_LITTLEFS_IF_FAILED true + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("- failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.name(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print("\tSIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + + File file = fs.open(path); + if(!file || file.isDirectory()){ + Serial.println("- failed to open file for reading"); + return; + } + + Serial.println("- read from file:"); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\r\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("- failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("- message appended"); + } else { + Serial.println("- append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\r\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("- file renamed"); + } else { + Serial.println("- rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\r\n", path); + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } +} + +// SPIFFS-like write and delete file, better use #define CONFIG_LITTLEFS_SPIFFS_COMPAT 1 + +void writeFile2(fs::FS &fs, const char * path, const char * message){ + if(!fs.exists(path)){ + if (strchr(path, '/')) { + Serial.printf("Create missing folders of: %s\r\n", path); + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strchr(pathStr, '/'); + while (ptr) { + *ptr = 0; + fs.mkdir(pathStr); + *ptr = '/'; + ptr = strchr(ptr+1, '/'); + } + } + free(pathStr); + } + } + + Serial.printf("Writing file to: %s\r\n", path); + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void deleteFile2(fs::FS &fs, const char * path){ + Serial.printf("Deleting file and empty folders on path: %s\r\n", path); + + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } + + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strrchr(pathStr, '/'); + if (ptr) { + Serial.printf("Removing all empty folders on path: %s\r\n", path); + } + while (ptr) { + *ptr = 0; + fs.rmdir(pathStr); + ptr = strrchr(pathStr, '/'); + } + free(pathStr); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + Serial.printf("Testing file I/O with %s\r\n", path); + + static uint8_t buf[512]; + size_t len = 0; + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + + size_t i; + Serial.print("- writing" ); + uint32_t start = millis(); + for(i=0; i<2048; i++){ + if ((i & 0x001F) == 0x001F){ + Serial.print("."); + } + file.write(buf, 512); + } + Serial.println(""); + uint32_t end = millis() - start; + Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end); + file.close(); + + file = fs.open(path); + start = millis(); + end = start; + i = 0; + if(file && !file.isDirectory()){ + len = file.size(); + size_t flen = len; + start = millis(); + Serial.print("- reading" ); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + if ((i++ & 0x001F) == 0x001F){ + Serial.print("."); + } + len -= toRead; + } + Serial.println(""); + end = millis() - start; + Serial.printf("- %u bytes read in %u ms\r\n", flen, end); + file.close(); + } else { + Serial.println("- failed to open file for reading"); + } +} + +void setup(){ + Serial.begin(115200); + if(!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ + Serial.println("LITTLEFS Mount Failed"); + return; + } + Serial.println( "SPIFFS-like write file to new path and delete it w/folders" ); + writeFile2(LITTLEFS, "/new1/new2/new3/hello3.txt", "Hello3"); + listDir(LITTLEFS, "/", 3); + deleteFile2(LITTLEFS, "/new1/new2/new3/hello3.txt"); + + listDir(LITTLEFS, "/", 3); + createDir(LITTLEFS, "/mydir"); + writeFile(LITTLEFS, "/mydir/hello2.txt", "Hello2"); + listDir(LITTLEFS, "/", 1); + deleteFile(LITTLEFS, "/mydir/hello2.txt"); + removeDir(LITTLEFS, "/mydir"); + listDir(LITTLEFS, "/", 1); + writeFile(LITTLEFS, "/hello.txt", "Hello "); + appendFile(LITTLEFS, "/hello.txt", "World!\r\n"); + readFile(LITTLEFS, "/hello.txt"); + renameFile(LITTLEFS, "/hello.txt", "/foo.txt"); + readFile(LITTLEFS, "/foo.txt"); + deleteFile(LITTLEFS, "/foo.txt"); + testFileIO(LITTLEFS, "/test.txt"); + deleteFile(LITTLEFS, "/test.txt"); + + Serial.println( "Test complete" ); +} + +void loop(){ + +} diff --git a/lib/libesp32/LITTLEFS/library.json b/lib/libesp32/LITTLEFS/library.json new file mode 100755 index 000000000..8c5f76fc2 --- /dev/null +++ b/lib/libesp32/LITTLEFS/library.json @@ -0,0 +1,22 @@ +{ + "name":"LittleFS_esp32", + "description":"LittleFS for esp32", + "keywords":"littlefs, spiffs", + "authors": + { + "name": "lorol", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "https://github.com/lorol/LITTLEFS.git" + }, + "version": "1.0.5", + "license": "LGPL-2.0", + "frameworks": "arduino", + "platforms": "espressif32", + "build": { + "libCompatMode": 2 + } +} \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/library.properties b/lib/libesp32/LITTLEFS/library.properties new file mode 100755 index 000000000..262590f63 --- /dev/null +++ b/lib/libesp32/LITTLEFS/library.properties @@ -0,0 +1,9 @@ +name=LittleFS_esp32 +version=1.0.5 +author=lorol +maintainer=lorol +sentence=LittleFS for esp32 based on esp_littlefs IDF component. Use esp32 core-provided LITTLEFS library instead of this one when available in future core releases. +paragraph= For esp32 core 1.0.4 release, use #define CONFIG_LITTLEFS_FOR_IDF_3_2 and for more SPIFFS compatibility, set #define CONFIG_LITTLEFS_SPIFFS_COMPAT 1 +category=Data Storage +url=https://github.com/lorol/LITTLEFS +architectures=esp32 \ No newline at end of file diff --git a/lib/libesp32/LITTLEFS/src/LICENSE b/lib/libesp32/LITTLEFS/src/LICENSE new file mode 100755 index 000000000..54a9f1e0e --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/LICENSE @@ -0,0 +1,7 @@ +Copyright 2020 Brian Pugh + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/libesp32/LITTLEFS/src/LICENSE.md b/lib/libesp32/LITTLEFS/src/LICENSE.md new file mode 100755 index 000000000..ed69bea47 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/LICENSE.md @@ -0,0 +1,24 @@ +Copyright (c) 2017, Arm Limited. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. +- Neither the name of ARM nor the names of its contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/libesp32/LITTLEFS/src/LITTLEFS.cpp b/lib/libesp32/LITTLEFS/src/LITTLEFS.cpp new file mode 100755 index 000000000..a188d65f0 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/LITTLEFS.cpp @@ -0,0 +1,105 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +static constexpr const char LFS_NAME[] = "spiffs"; + +#include "vfs_api.h" + +extern "C" { +#include +#include +#include +#include "esp_littlefs.h" +} + +#include "LITTLEFS.h" + +using namespace fs; + +LITTLEFSFS::LITTLEFSFS() : FS(FSImplPtr(new VFSImpl())) +{ + +} + +bool LITTLEFSFS::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFiles) +{ + if(esp_littlefs_mounted(LFS_NAME)){ + log_w("LITTLEFS Already Mounted!"); + return true; + } + + esp_vfs_littlefs_conf_t conf = { + .base_path = basePath, + .partition_label = LFS_NAME, + .format_if_mount_failed = false + }; + + esp_err_t err = esp_vfs_littlefs_register(&conf); + if(err == ESP_FAIL && formatOnFail){ + if(format()){ + err = esp_vfs_littlefs_register(&conf); + } + } + if(err != ESP_OK){ + log_e("Mounting LITTLEFS failed! Error: %d", err); + return false; + } + _impl->mountpoint(basePath); + return true; +} + +void LITTLEFSFS::end() +{ + if(esp_littlefs_mounted(LFS_NAME)){ + esp_err_t err = esp_vfs_littlefs_unregister(LFS_NAME); + if(err){ + log_e("Unmounting LITTLEFS failed! Error: %d", err); + return; + } + _impl->mountpoint(NULL); + } +} + +bool LITTLEFSFS::format() +{ + disableCore0WDT(); + esp_err_t err = esp_littlefs_format(LFS_NAME); + enableCore0WDT(); + if(err){ + log_e("Formatting LITTLEFS failed! Error: %d", err); + return false; + } + return true; +} + +size_t LITTLEFSFS::totalBytes() +{ + size_t total,used; + if(esp_littlefs_info(LFS_NAME, &total, &used)){ + return 0; + } + return total; +} + +size_t LITTLEFSFS::usedBytes() +{ + size_t total,used; + if(esp_littlefs_info(LFS_NAME, &total, &used)){ + return 0; + } + return used; +} + +LITTLEFSFS LITTLEFS; + diff --git a/lib/libesp32/LITTLEFS/src/LITTLEFS.h b/lib/libesp32/LITTLEFS/src/LITTLEFS.h new file mode 100755 index 000000000..fbd6f09e1 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/LITTLEFS.h @@ -0,0 +1,38 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _LITTLEFS_H_ +#define _LITTLEFS_H_ + +#include "FS.h" + +namespace fs +{ + +class LITTLEFSFS : public FS +{ +public: + LITTLEFSFS(); + bool begin(bool formatOnFail=false, const char * basePath="/littlefs", uint8_t maxOpenFiles=5); + bool format(); + size_t totalBytes(); + size_t usedBytes(); + void end(); +}; + +} + +extern fs::LITTLEFSFS LITTLEFS; + + +#endif diff --git a/lib/libesp32/LITTLEFS/src/esp_littlefs.c b/lib/libesp32/LITTLEFS/src/esp_littlefs.c new file mode 100755 index 000000000..2b0c2e4cf --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/esp_littlefs.c @@ -0,0 +1,1626 @@ +/** + * @file esp_littlefs.c + * @brief Maps LittleFS <-> ESP_VFS + * @author Brian Pugh + * + * @note Modified and used by lorol for Arduino esp32 core + * + * Copyright 2020 Brian Pugh + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +//#define LOG_LOCAL_LEVEL 5 + +#if __has_include("esp_arduino_version.h") +#include "esp_arduino_version.h" +#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) +#warning("Use the built-in LITTLEFS library") +#endif +#else +//#warning("LITTLEFS: no esp_arduino_version.h file, likely 1.0.x") +#endif + +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(3, 3, 0) +//#warning("IDF is 3.3 or later, LittleFS file timestamps are enabled") +#endif +#else +#define CONFIG_LITTLEFS_FOR_IDF_3_2 /* For old IDF 3.2 compatibility, core release 1.0.4 - no timestamps */ +//#warning("IDF < 3.3, no LittleFS file timestamps") +#endif + +//#define CONFIG_LITTLEFS_USE_ONLY_HASH +#define CONFIG_LITTLEFS_HUMAN_READABLE 0 /* Use 1 for verbose errors */ +#define CONFIG_LITTLEFS_SPIFFS_COMPAT 0 /* Use 1 for better drop-in replacement of SPIFFS */ +#define CONFIG_LITTLEFS_MAX_PARTITIONS 3 +#define CONFIG_LITTLEFS_PAGE_SIZE 256 +#define CONFIG_LITTLEFS_OBJ_NAME_LEN 64 +#define CONFIG_LITTLEFS_READ_SIZE 128 +#define CONFIG_LITTLEFS_WRITE_SIZE 128 +#define CONFIG_LITTLEFS_LOOKAHEAD_SIZE 128 +#define CONFIG_LITTLEFS_CACHE_SIZE 512 /* Old value was 128 */ +#define CONFIG_LITTLEFS_BLOCK_CYCLES 512 + +#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2 + #define CONFIG_LITTLEFS_USE_MTIME 0 +#else + #define CONFIG_LITTLEFS_USE_MTIME 1 + #define CONFIG_LITTLEFS_MTIME_USE_SECONDS 1 +#endif + +#include "esp_log.h" +#include "esp_spi_flash.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include +#include +#include +#include +#include +#include + +#if __has_include("esp32/rom/spi_flash.h") +//#warning("LITTLEFS: IDF 4, spi_flash.h file location different from IDF 3") +#include "esp32/rom/spi_flash.h" +#else +//#warning("LITTLEFS: IDF 3") +#include "rom/spi_flash.h" +#endif + +#include "esp_system.h" + +#include "esp_littlefs.h" +#include "littlefs_api.h" + + +static const char TAG[] = "esp_littlefs"; + +#define CONFIG_LITTLEFS_BLOCK_SIZE 4096 /* ESP32 can only operate at 4kb */ + +/* File Descriptor Caching Params */ +#define CONFIG_LITTLEFS_FD_CACHE_REALLOC_FACTOR 2 /* Amount to resize FD cache by */ +#define CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE 4 /* Minimum size of FD cache */ +#define CONFIG_LITTLEFS_FD_CACHE_HYST 4 /* When shrinking, leave this many trailing FD slots available */ + +/** + * @brief littlefs DIR structure + */ +typedef struct { + DIR dir; /*!< VFS DIR struct */ + lfs_dir_t d; /*!< littlefs DIR struct */ + struct dirent e; /*!< Last open dirent */ + long offset; /*!< Offset of the current dirent */ + char *path; /*!< Requested directory name */ +} vfs_littlefs_dir_t; + +static int vfs_littlefs_open(void* ctx, const char * path, int flags, int mode); +static ssize_t vfs_littlefs_write(void* ctx, int fd, const void * data, size_t size); +static ssize_t vfs_littlefs_read(void* ctx, int fd, void * dst, size_t size); +static int vfs_littlefs_close(void* ctx, int fd); +static off_t vfs_littlefs_lseek(void* ctx, int fd, off_t offset, int mode); +static int vfs_littlefs_stat(void* ctx, const char * path, struct stat * st); +static int vfs_littlefs_unlink(void* ctx, const char *path); +static int vfs_littlefs_rename(void* ctx, const char *src, const char *dst); +static DIR* vfs_littlefs_opendir(void* ctx, const char* name); +static int vfs_littlefs_closedir(void* ctx, DIR* pdir); +static struct dirent* vfs_littlefs_readdir(void* ctx, DIR* pdir); +static int vfs_littlefs_readdir_r(void* ctx, DIR* pdir, + struct dirent* entry, struct dirent** out_dirent); +static long vfs_littlefs_telldir(void* ctx, DIR* pdir); +static void vfs_littlefs_seekdir(void* ctx, DIR* pdir, long offset); +static int vfs_littlefs_mkdir(void* ctx, const char* name, mode_t mode); +static int vfs_littlefs_rmdir(void* ctx, const char* name); +static int vfs_littlefs_fsync(void* ctx, int fd); + +static esp_err_t esp_littlefs_init(const esp_vfs_littlefs_conf_t* conf); +static esp_err_t esp_littlefs_erase_partition(const char *partition_label); +static esp_err_t esp_littlefs_by_label(const char* label, int * index); +static esp_err_t esp_littlefs_get_empty(int *index); +static void esp_littlefs_free(esp_littlefs_t ** efs); +static void esp_littlefs_dir_free(vfs_littlefs_dir_t *dir); +static int esp_littlefs_flags_conv(int m); +#if CONFIG_LITTLEFS_USE_MTIME +static int vfs_littlefs_utime(void *ctx, const char *path, const struct utimbuf *times); +static void vfs_littlefs_update_mtime(esp_littlefs_t *efs, const char *path); +static int vfs_littlefs_update_mtime_value(esp_littlefs_t *efs, const char *path, time_t t); +static time_t vfs_littlefs_get_mtime(esp_littlefs_t *efs, const char *path); +#endif + +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH +/* The only way in LittleFS to get info is via a path (lfs_stat), so it cannot + * be done if the path isn't stored. */ +static int vfs_littlefs_fstat(void* ctx, int fd, struct stat * st); +#endif + +#if CONFIG_LITTLEFS_SPIFFS_COMPAT +static void mkdirs(esp_littlefs_t * efs, const char *dir); +static void rmdirs(esp_littlefs_t * efs, const char *dir); +#endif // CONFIG_LITTLEFS_SPIFFS_COMPAT + +static int sem_take(esp_littlefs_t *efs); +static int sem_give(esp_littlefs_t *efs); + +static SemaphoreHandle_t _efs_lock = NULL; +static esp_littlefs_t * _efs[CONFIG_LITTLEFS_MAX_PARTITIONS] = { 0 }; + +/******************** + * Helper Functions * + ********************/ +void esp_littlefs_free_fds(esp_littlefs_t * efs) { + /* Need to free all files that were opened */ + while (efs->file) { + vfs_littlefs_file_t * next = efs->file->next; + free(efs->file); + efs->file = next; + } + free(efs->cache); + efs->cache = 0; + efs->cache_size = efs->fd_count = 0; +} + + +/******************** + * Public Functions * + ********************/ + +bool esp_littlefs_mounted(const char* partition_label) { + int index; + esp_err_t err; + + err = esp_littlefs_by_label(partition_label, &index); + if(err != ESP_OK) return false; + return _efs[index]->cache_size > 0; +} + +esp_err_t esp_littlefs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes){ + int index; + esp_err_t err; + esp_littlefs_t *efs = NULL; + + err = esp_littlefs_by_label(partition_label, &index); + if(err != ESP_OK) return false; + efs = _efs[index]; + + if(total_bytes) *total_bytes = efs->cfg.block_size * efs->cfg.block_count; + if(used_bytes) *used_bytes = efs->cfg.block_size * lfs_fs_size(efs->fs); + + return ESP_OK; +} + +esp_err_t esp_vfs_littlefs_register(const esp_vfs_littlefs_conf_t * conf) +{ + assert(conf->base_path); + const esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_CONTEXT_PTR, + .write_p = &vfs_littlefs_write, + .lseek_p = &vfs_littlefs_lseek, + .read_p = &vfs_littlefs_read, + .open_p = &vfs_littlefs_open, + .close_p = &vfs_littlefs_close, +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + .fstat_p = &vfs_littlefs_fstat, +#else + .fstat_p = NULL, /* Not supported */ +#endif + .stat_p = &vfs_littlefs_stat, + .link_p = NULL, /* Not Supported */ + .unlink_p = &vfs_littlefs_unlink, + .rename_p = &vfs_littlefs_rename, + .opendir_p = &vfs_littlefs_opendir, + .closedir_p = &vfs_littlefs_closedir, + .readdir_p = &vfs_littlefs_readdir, + .readdir_r_p = &vfs_littlefs_readdir_r, + .seekdir_p = &vfs_littlefs_seekdir, + .telldir_p = &vfs_littlefs_telldir, + .mkdir_p = &vfs_littlefs_mkdir, + .rmdir_p = &vfs_littlefs_rmdir, + .fsync_p = &vfs_littlefs_fsync, +#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 +#if CONFIG_LITTLEFS_USE_MTIME + .utime_p = &vfs_littlefs_utime, +#else + .utime_p = NULL, +#endif // CONFIG_LITTLEFS_USE_MTIME +#endif //CONFIG_LITTLEFS_FOR_IDF_3_2 + }; + + esp_err_t err = esp_littlefs_init(conf); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize LittleFS"); + return err; + } + + int index; + if (esp_littlefs_by_label(conf->partition_label, &index) != ESP_OK) { + ESP_LOGE(TAG, "Unable to find partition \"%s\"", conf->partition_label); + return ESP_ERR_NOT_FOUND; + } + + strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1); + err = esp_vfs_register(conf->base_path, &vfs, _efs[index]); + if (err != ESP_OK) { + esp_littlefs_free(&_efs[index]); + ESP_LOGE(TAG, "Failed to register Littlefs to \"%s\"", conf->base_path); + return err; + } + + ESP_LOGV(TAG, "Successfully registered LittleFS to \"%s\"", conf->base_path); + return ESP_OK; +} + +esp_err_t esp_vfs_littlefs_unregister(const char* partition_label) +{ + assert(partition_label); + int index; + if (esp_littlefs_by_label(partition_label, &index) != ESP_OK) { + ESP_LOGE(TAG, "Partition was never registered."); + return ESP_ERR_INVALID_STATE; + } + ESP_LOGV(TAG, "Unregistering \"%s\"", partition_label); + esp_err_t err = esp_vfs_unregister(_efs[index]->base_path); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to unregister \"%s\"", partition_label); + return err; + } + esp_littlefs_free(&_efs[index]); + _efs[index] = NULL; + return ESP_OK; +} + +esp_err_t esp_littlefs_format(const char* partition_label) { + assert( partition_label ); + + bool was_mounted = false; + bool efs_free = false; + int index = -1; + esp_err_t err; + esp_littlefs_t *efs = NULL; + + ESP_LOGV(TAG, "Formatting \"%s\"", partition_label); + + /* Get a context */ + err = esp_littlefs_by_label(partition_label, &index); + + if( err != ESP_OK ){ + /* Create a tmp context */ + ESP_LOGV(TAG, "Temporarily creating EFS context."); + efs_free = true; + const esp_vfs_littlefs_conf_t conf = { + /* base_name not necessary for initializing */ + .dont_mount = true, + .partition_label = partition_label, + }; + err = esp_littlefs_init(&conf); /* Internally MIGHT call esp_littlefs_format */ + if( err != ESP_OK ) { + ESP_LOGE(TAG, "Failed to initialize to format."); + goto exit; + } + + err = esp_littlefs_by_label(partition_label, &index); + if ( err != ESP_OK) { + ESP_LOGE(TAG, "Error obtaining context."); + goto exit; + } + } + + efs = _efs[index]; + assert( efs ); + + /* Unmount if mounted */ + if(efs->cache_size > 0){ + int res; + ESP_LOGV(TAG, "Partition was mounted. Unmounting..."); + was_mounted = true; + res = lfs_unmount(efs->fs); + if(res != LFS_ERR_OK){ + ESP_LOGE(TAG, "Failed to unmount."); + return ESP_FAIL; + } + esp_littlefs_free_fds(efs); + } + + /* Erase and Format */ + { + int res; + ESP_LOGV(TAG, "Formatting filesystem"); + esp_littlefs_erase_partition(partition_label); + res = lfs_format(efs->fs, &efs->cfg); + if( res != LFS_ERR_OK ) { + ESP_LOGE(TAG, "Failed to format filesystem"); + return ESP_FAIL; + } + } + + /* Mount filesystem */ + if( was_mounted ) { + int res; + /* Remount the partition */ + ESP_LOGV(TAG, "Remounting formatted partition"); + res = lfs_mount(efs->fs, &efs->cfg); + if( res != LFS_ERR_OK ) { + ESP_LOGE(TAG, "Failed to re-mount filesystem"); + return ESP_FAIL; + } + efs->cache_size = CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE; // Initial size of cache; will resize ondemand + efs->cache = calloc(sizeof(*efs->cache), efs->cache_size); + } + ESP_LOGV(TAG, "Format Success!"); + + err = ESP_OK; + +exit: + if(efs_free && index>=0) esp_littlefs_free(&_efs[index]); + return err; +} + +#if CONFIG_LITTLEFS_HUMAN_READABLE +/** + * @brief converts an enumerated lfs error into a string. + * @param lfs_error The littlefs error. + */ +const char * esp_littlefs_errno(enum lfs_error lfs_errno) { + switch(lfs_errno){ + case LFS_ERR_OK: return "LFS_ERR_OK"; + case LFS_ERR_IO: return "LFS_ERR_IO"; + case LFS_ERR_CORRUPT: return "LFS_ERR_CORRUPT"; + case LFS_ERR_NOENT: return "LFS_ERR_NOENT"; + case LFS_ERR_EXIST: return "LFS_ERR_EXIST"; + case LFS_ERR_NOTDIR: return "LFS_ERR_NOTDIR"; + case LFS_ERR_ISDIR: return "LFS_ERR_ISDIR"; + case LFS_ERR_NOTEMPTY: return "LFS_ERR_NOTEMPTY"; + case LFS_ERR_BADF: return "LFS_ERR_BADF"; + case LFS_ERR_FBIG: return "LFS_ERR_FBIG"; + case LFS_ERR_INVAL: return "LFS_ERR_INVAL"; + case LFS_ERR_NOSPC: return "LFS_ERR_NOSPC"; + case LFS_ERR_NOMEM: return "LFS_ERR_NOMEM"; + case LFS_ERR_NOATTR: return "LFS_ERR_NOATTR"; + case LFS_ERR_NAMETOOLONG: return "LFS_ERR_NAMETOOLONG"; + default: return "LFS_ERR_UNDEFINED"; + } + return ""; +} +#else +#define esp_littlefs_errno(x) "" +#endif + +/******************** + * Static Functions * + ********************/ + +/*** Helpers ***/ + +/** + * @brief Free and clear a littlefs definition structure. + * @param efs Pointer to pointer to struct. Done this way so we can also zero + * out the pointer. + */ +static void esp_littlefs_free(esp_littlefs_t ** efs) +{ + esp_littlefs_t * e = *efs; + if (e == NULL) return; + *efs = NULL; + + if (e->fs) { + if(e->cache_size > 0) lfs_unmount(e->fs); + free(e->fs); + } + if(e->lock) vSemaphoreDelete(e->lock); + esp_littlefs_free_fds(e); + free(e); +} + +/** + * @brief Free a vfs_littlefs_dir_t struct. + */ +static void esp_littlefs_dir_free(vfs_littlefs_dir_t *dir){ + if(dir == NULL) return; + if(dir->path) free(dir->path); + free(dir); +} + +/** + * Get a mounted littlefs filesystem by label. + * @param[in] label + * @param[out] index index into _efs + * @return ESP_OK on success + */ +static esp_err_t esp_littlefs_by_label(const char* label, int * index){ + int i; + esp_littlefs_t * p; + + if(!label || !index) return ESP_ERR_INVALID_ARG; + + ESP_LOGV(TAG, "Searching for existing filesystem for partition \"%s\"", label); + + for (i = 0; i < CONFIG_LITTLEFS_MAX_PARTITIONS; i++) { + p = _efs[i]; + if (p) { + if (strncmp(label, p->partition->label, 17) == 0) { + *index = i; + ESP_LOGV(TAG, "Found existing filesystem \"%s\" at index %d", label, *index); + return ESP_OK; + } + } + } + + ESP_LOGV(TAG, "Existing filesystem \"%s\" not found", label); + return ESP_ERR_NOT_FOUND; +} + +/** + * @brief Get the index of an unallocated LittleFS slot. + * @param[out] index Indexd of free LittleFS slot + * @return ESP_OK on success + */ +static esp_err_t esp_littlefs_get_empty(int *index) { + assert(index); + for(uint8_t i=0; i < CONFIG_LITTLEFS_MAX_PARTITIONS; i++){ + if( _efs[i] == NULL ){ + *index = i; + return ESP_OK; + } + } + ESP_LOGE(TAG, "No more free partitions available."); + return ESP_FAIL; +} + +/** + * @brief erase a partition; make sure LittleFS is unmounted first. + * @param partition_label NULL-terminated string of partition to erase + * @return ESP_OK on success + */ +static esp_err_t esp_littlefs_erase_partition(const char *partition_label) { + ESP_LOGV(TAG, "Erasing partition..."); + + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, + partition_label); + if (!partition) { + ESP_LOGE(TAG, "partition \"%s\" could not be found", partition_label); + return ESP_ERR_NOT_FOUND; + } + + if( esp_partition_erase_range(partition, 0, partition->size) != ESP_OK ) { + ESP_LOGE(TAG, "Failed to erase partition"); + return ESP_FAIL; + } + + return ESP_OK; +} + +/** + * @brief Convert fcntl flags to littlefs flags + * @param m fcntl flags + * @return lfs flags + */ +static int esp_littlefs_flags_conv(int m) { + int lfs_flags = 0; + if (m == O_APPEND) {ESP_LOGV(TAG, "O_APPEND"); lfs_flags |= LFS_O_APPEND;} + if (m == O_RDONLY) {ESP_LOGV(TAG, "O_RDONLY"); lfs_flags |= LFS_O_RDONLY;} + if (m & O_WRONLY) {ESP_LOGV(TAG, "O_WRONLY"); lfs_flags |= LFS_O_WRONLY;} + if (m & O_RDWR) {ESP_LOGV(TAG, "O_RDWR"); lfs_flags |= LFS_O_RDWR;} + if (m & O_EXCL) {ESP_LOGV(TAG, "O_EXCL"); lfs_flags |= LFS_O_EXCL;} + if (m & O_CREAT) {ESP_LOGV(TAG, "O_CREAT"); lfs_flags |= LFS_O_CREAT;} + if (m & O_TRUNC) {ESP_LOGV(TAG, "O_TRUNC"); lfs_flags |= LFS_O_TRUNC;} + return lfs_flags; +} + +/** + * @brief Initialize and mount littlefs + * @param[in] conf Filesystem Configuration + * @return ESP_OK on success + */ +static esp_err_t esp_littlefs_init(const esp_vfs_littlefs_conf_t* conf) +{ + int index = -1; + esp_err_t err = ESP_FAIL; + const esp_partition_t* partition = NULL; + esp_littlefs_t * efs = NULL; + + if( _efs_lock == NULL ){ + static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL(&mux); + if( _efs_lock == NULL ){ + _efs_lock = xSemaphoreCreateMutex(); + assert(_efs_lock); + } + portEXIT_CRITICAL(&mux); + } + + xSemaphoreTake(_efs_lock, portMAX_DELAY); + + if (esp_littlefs_get_empty(&index) != ESP_OK) { + ESP_LOGE(TAG, "max mounted partitions reached"); + err = ESP_ERR_INVALID_STATE; + goto exit; + } + + /* Input and Environment Validation */ + if (esp_littlefs_by_label(conf->partition_label, &index) == ESP_OK) { + ESP_LOGE(TAG, "Partition already used"); + err = ESP_ERR_INVALID_STATE; + goto exit; + } + + { + uint32_t flash_page_size = g_rom_flashchip.page_size; + uint32_t log_page_size = CONFIG_LITTLEFS_PAGE_SIZE; + if (log_page_size % flash_page_size != 0) { + ESP_LOGE(TAG, "LITTLEFS_PAGE_SIZE is not multiple of flash chip page size (%d)", + flash_page_size); + err = ESP_ERR_INVALID_ARG; + goto exit; + } + } + + if ( NULL == conf->partition_label ) { + ESP_LOGE(TAG, "Partition label must be provided."); + err = ESP_ERR_INVALID_ARG; + goto exit; + } + + partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, + conf->partition_label); + + if (!partition) { + ESP_LOGE(TAG, "partition \"%s\" could not be found", conf->partition_label); + err = ESP_ERR_NOT_FOUND; + goto exit; + } + + /* Allocate Context */ + efs = calloc(1, sizeof(esp_littlefs_t)); + if (efs == NULL) { + ESP_LOGE(TAG, "esp_littlefs could not be malloced"); + err = ESP_ERR_NO_MEM; + goto exit; + } + efs->partition = partition; + + { /* LittleFS Configuration */ + efs->cfg.context = efs; + + // block device operations + efs->cfg.read = littlefs_api_read; + efs->cfg.prog = littlefs_api_prog; + efs->cfg.erase = littlefs_api_erase; + efs->cfg.sync = littlefs_api_sync; + + // block device configuration + efs->cfg.read_size = CONFIG_LITTLEFS_READ_SIZE; + efs->cfg.prog_size = CONFIG_LITTLEFS_WRITE_SIZE; + efs->cfg.block_size = CONFIG_LITTLEFS_BLOCK_SIZE;; + efs->cfg.block_count = efs->partition->size / efs->cfg.block_size; + efs->cfg.cache_size = CONFIG_LITTLEFS_CACHE_SIZE; + efs->cfg.lookahead_size = CONFIG_LITTLEFS_LOOKAHEAD_SIZE; + efs->cfg.block_cycles = CONFIG_LITTLEFS_BLOCK_CYCLES; + } + + efs->lock = xSemaphoreCreateRecursiveMutex(); + if (efs->lock == NULL) { + ESP_LOGE(TAG, "mutex lock could not be created"); + err = ESP_ERR_NO_MEM; + goto exit; + } + + efs->fs = calloc(1, sizeof(lfs_t)); + if (efs->fs == NULL) { + ESP_LOGE(TAG, "littlefs could not be malloced"); + err = ESP_ERR_NO_MEM; + goto exit; + } + + // Mount and Error Check + _efs[index] = efs; + if(!conf->dont_mount){ + int res = lfs_mount(efs->fs, &efs->cfg); + + if (conf->format_if_mount_failed && res != LFS_ERR_OK) { + esp_err_t err; + ESP_LOGW(TAG, "mount failed, %s (%i). formatting...", esp_littlefs_errno(res), res); + err = esp_littlefs_format(efs->partition->label); + if(err != ESP_OK) { + ESP_LOGE(TAG, "format failed"); + err = ESP_FAIL; + goto exit; + } + res = lfs_mount(efs->fs, &efs->cfg); + } + if (res != LFS_ERR_OK) { + ESP_LOGE(TAG, "mount failed, %s (%i)", esp_littlefs_errno(res), res); + err = ESP_FAIL; + goto exit; + } + efs->cache_size = 4; + efs->cache = calloc(sizeof(*efs->cache), efs->cache_size); + } + + err = ESP_OK; + +exit: + if(err != ESP_OK){ + if( index >= 0 ) { + esp_littlefs_free(&_efs[index]); + } + else{ + esp_littlefs_free(&efs); + } + } + xSemaphoreGive(_efs_lock); + return err; +} + +/** + * @brief + * @parameter efs file system context + */ +static inline int sem_take(esp_littlefs_t *efs) { + int res; +#if LOG_LOCAL_LEVEL >= 5 + ESP_LOGV(TAG, "------------------------ Sem Taking [%s]", pcTaskGetTaskName(NULL)); +#endif + res = xSemaphoreTakeRecursive(efs->lock, portMAX_DELAY); +#if LOG_LOCAL_LEVEL >= 5 + ESP_LOGV(TAG, "--------------------->>> Sem Taken [%s]", pcTaskGetTaskName(NULL)); +#endif + return res; +} + +/** + * @brief + * @parameter efs file system context + */ +static inline int sem_give(esp_littlefs_t *efs) { +#if LOG_LOCAL_LEVEL >= 5 + ESP_LOGV(TAG, "---------------------<<< Sem Give [%s]", pcTaskGetTaskName(NULL)); +#endif + return xSemaphoreGiveRecursive(efs->lock); +} + + +/* We are using a double allocation system here, which an array and a linked list. + The array contains the pointer to the file descriptor (the index in the array is what's returned to the user). + The linked list is used for file descriptors. + This means that position of nodes in the list must stay consistent: + - Allocation is obvious (append to the list from the head, and realloc the pointers array) + There is still a O(N) search in the cache for a free position to store + - Searching is a O(1) process (good) + - Deallocation is more tricky. That is, for example, + if you need to remove node 5 in a 12 nodes list, you'll have to: + 1) Mark the 5th position as freed (if it's the last position of the array realloc smaller) + 2) Walk the list until finding the pointer to the node O(N) and scrub the node so the chained list stays consistent + 3) Deallocate the node +*/ + +/** + * @brief Get a file descriptor + * @param[in,out] efs file system context + * @param[out] file pointer to a file that'll be filled with a file object + * @param[in] path_len the length of the filepath in bytes (including terminating zero byte) + * @return integer file descriptor. Returns -1 if a FD cannot be obtained. + * @warning This must be called with lock taken + */ +static int esp_littlefs_allocate_fd(esp_littlefs_t *efs, vfs_littlefs_file_t ** file +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + , const size_t path_len +#endif + ) +{ + int i = -1; + + assert( efs->fd_count < UINT16_MAX ); + assert( efs->cache_size < UINT16_MAX ); + + /* Make sure there is enough space in the cache to store new fd */ + if (efs->fd_count + 1 > efs->cache_size) { + uint16_t new_size = (uint16_t)MIN(UINT16_MAX, CONFIG_LITTLEFS_FD_CACHE_REALLOC_FACTOR * efs->cache_size); + /* Resize the cache */ + vfs_littlefs_file_t ** new_cache = realloc(efs->cache, new_size * sizeof(*efs->cache)); + if (!new_cache) { + ESP_LOGE(TAG, "Unable to allocate file cache"); + return -1; /* If it fails here, no harm is done to the filesystem, so it's safe */ + } + /* Zero out the new portions of the cache */ + memset(&new_cache[efs->cache_size], 0, (new_size - efs->cache_size) * sizeof(*efs->cache)); + efs->cache = new_cache; + efs->cache_size = new_size; + } + + + /* Allocate file descriptor here now */ +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + *file = calloc(1, sizeof(**file) + path_len); +#else + *file = calloc(1, sizeof(**file)); +#endif + + if (*file == NULL) { + /* If it fails here, the file system might have a larger cache, but it's harmless, no need to reverse it */ + ESP_LOGE(TAG, "Unable to allocate FD"); + return -1; + } + + /* Starting from here, nothing can fail anymore */ + +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + /* The trick here is to avoid dual allocation so the path pointer + should point to the next byte after it: + file => [ lfs_file | # | next | path | free_space ] + | /\ + |__/ + */ + (*file)->path = (char*)(*file) + sizeof(**file); +#endif + + /* Now find a free place in cache */ + for(i=0; i < efs->cache_size; i++) { + if (efs->cache[i] == NULL) { + efs->cache[i] = *file; + break; + } + } + /* Save file in the list */ + (*file)->next = efs->file; + efs->file = *file; + efs->fd_count++; + return i; +} + +/** + * @brief Release a file descriptor + * @param[in,out] efs file system context + * @param[in] fd File Descriptor to release + * @return 0 on success. -1 if a FD cannot be obtained. + * @warning This must be called with lock taken + */ +static int esp_littlefs_free_fd(esp_littlefs_t *efs, int fd){ + vfs_littlefs_file_t * file, * head; + + if((uint32_t)fd >= efs->cache_size) { + ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); + return -1; + } + + /* Get the file descriptor to free it */ + file = efs->cache[fd]; + head = efs->file; + /* Search for file in SLL to remove it */ + if (file == head) { + /* Last file, can't fail */ + efs->file = efs->file->next; + } else { + while (head && head->next != file) { + head = head->next; + } + if (!head) { + ESP_LOGE(TAG, "Inconsistent list"); + return -1; + } + /* Transaction starts here and can't fail anymore */ + head->next = file->next; + } + efs->cache[fd] = NULL; + efs->fd_count--; + + ESP_LOGV(TAG, "Clearing FD"); + free(file); + +#if 0 + /* Realloc smaller if its possible + * * Find and realloc based on number of trailing NULL ptrs in cache + * * Leave some hysteris to prevent thrashing around resize points + * This is disabled for now because it adds unnecessary complexity + * and binary size increase that outweights its ebenfits. + */ + if(efs->cache_size > CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE) { + uint16_t n_free; + uint16_t new_size = efs->cache_size / CONFIG_LITTLEFS_FD_CACHE_REALLOC_FACTOR; + + if(new_size >= CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE) { + /* Count number of trailing NULL ptrs */ + for(n_free=0; n_free < efs->cache_size; n_free++) { + if(efs->cache[efs->cache_size - n_free - 1] != NULL) { + break; + } + } + + if(n_free >= (efs->cache_size - new_size)){ + new_size += CONFIG_LITTLEFS_FD_CACHE_HYST; + ESP_LOGV(TAG, "Reallocating cache %i -> %i", efs->cache_size, new_size); + vfs_littlefs_file_t ** new_cache; + new_cache = realloc(efs->cache, new_size * sizeof(*efs->cache)); + /* No harm on realloc failure, continue using the oversized cache */ + if(new_cache) { + efs->cache = new_cache; + efs->cache_size = new_size; + } + } + } + } +#endif + + return 0; +} + +/** + * @brief Compute the 32bit DJB2 hash of the given string. + * @param[in] path the path to hash + * @returns the hash for this path + */ +static uint32_t compute_hash(const char * path) { + uint32_t hash = 5381; + char c; + + while ((c = *path++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + +/** + * @brief finds an open file descriptor by file name. + * @param[in,out] efs file system context + * @param[in] path File path to check. + * @returns integer file descriptor. Returns -1 if not found. + * @warning This must be called with lock taken + * @warning if CONFIG_LITTLEFS_USE_ONLY_HASH, there is a slim chance an + * erroneous FD may be returned on hash collision. + */ +static int esp_littlefs_get_fd_by_name(esp_littlefs_t *efs, const char *path){ + uint32_t hash = compute_hash(path); + + for(uint16_t i=0, j=0; i < efs->cache_size && j < efs->fd_count; i++){ + if (efs->cache[i]) { + ++j; + + if ( + efs->cache[i]->hash == hash // Faster than strcmp +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + && strcmp(path, efs->cache[i]->path) == 0 // May as well check incase of hash collision. Usually short-circuited. +#endif + ) { + ESP_LOGV(TAG, "Found \"%s\" at FD %d.", path, i); + return i; + } + } + } + ESP_LOGV(TAG, "Unable to get a find FD for \"%s\"", path); + return -1; +} + +/*** Filesystem Hooks ***/ + +static int vfs_littlefs_open(void* ctx, const char * path, int flags, int mode) { + /* Note: mode is currently unused */ + int fd=-1, lfs_flags, res; + esp_littlefs_t *efs = (esp_littlefs_t *)ctx; + vfs_littlefs_file_t *file = NULL; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + size_t path_len = strlen(path) + 1; // include NULL terminator +#endif + assert(path); + + ESP_LOGV(TAG, "Opening %s", path); + + /* Convert flags to lfs flags */ + lfs_flags = esp_littlefs_flags_conv(flags); + + /* Get a FD */ + sem_take(efs); + + fd = esp_littlefs_allocate_fd(efs, &file +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + , path_len +#endif + ); + + if(fd < 0) { + errno = -fd; + sem_give(efs); + ESP_LOGV(TAG, "Error obtaining FD"); + return LFS_ERR_INVAL; + } + +#if CONFIG_LITTLEFS_SPIFFS_COMPAT + /* Create all parent directories (if necessary) */ + ESP_LOGV(TAG, "LITTLEFS_SPIFFS_COMPAT attempting to create all directories for %s", path); + mkdirs(efs, path); +#endif // CONFIG_LITTLEFS_SPIFFS_COMPAT + + /* Open File */ + res = lfs_file_open(efs->fs, &file->file, path, lfs_flags); + + if( res < 0 ) { + errno = -res; + esp_littlefs_free_fd(efs, fd); + sem_give(efs); +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to open file %s. Error %s (%d)", + path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to open file. Error %s (%d)", + esp_littlefs_errno(res), res); +#endif + return LFS_ERR_INVAL; + } + + /* Sync after opening. If we are overwriting a file, this will free that + * file's blocks in storage, prevent OOS errors. + * See TEST_CASE: + * "Rewriting file frees space immediately (#7426)" + */ + res = lfs_file_sync(efs->fs, &file->file); + if(res < 0){ + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to sync at opening file \"%s\". Error %s (%d)", + file->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to sync at opening file %d. Error %d", fd, res); +#endif + } + + file->hash = compute_hash(path); +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + memcpy(file->path, path, path_len); +#endif + +#if CONFIG_LITTLEFS_USE_MTIME + if (lfs_flags != LFS_O_RDONLY) { + /* If this is being opened as not read-only */ + vfs_littlefs_update_mtime(efs, path); + } +#endif + + sem_give(efs); + ESP_LOGV(TAG, "Done opening %s", path); + return fd; +} + +static ssize_t vfs_littlefs_write(void* ctx, int fd, const void * data, size_t size) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + ssize_t res; + vfs_littlefs_file_t *file = NULL; + + sem_take(efs); + if((uint32_t)fd > efs->cache_size) { + sem_give(efs); + ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); + return LFS_ERR_BADF; + } + file = efs->cache[fd]; + res = lfs_file_write(efs->fs, &file->file, data, size); + sem_give(efs); + + if(res < 0){ + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to write FD %d; path \"%s\". Error %s (%d)", + fd, file->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to write FD %d. Error %s (%d)", + fd, esp_littlefs_errno(res), res); +#endif + return res; + } + + return res; +} + +static ssize_t vfs_littlefs_read(void* ctx, int fd, void * dst, size_t size) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + ssize_t res; + vfs_littlefs_file_t *file = NULL; + + + sem_take(efs); + if((uint32_t)fd > efs->cache_size) { + sem_give(efs); + ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); + return LFS_ERR_BADF; + } + file = efs->cache[fd]; + res = lfs_file_read(efs->fs, &file->file, dst, size); + sem_give(efs); + + if(res < 0){ + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to read file \"%s\". Error %s (%d)", + file->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to read FD %d. Error %s (%d)", + fd, esp_littlefs_errno(res), res); +#endif + return res; + } + + return res; +} + +static int vfs_littlefs_close(void* ctx, int fd) { + // TODO update mtime on close? SPIFFS doesn't do this + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + int res; + vfs_littlefs_file_t *file = NULL; + + sem_take(efs); + if((uint32_t)fd > efs->cache_size) { + sem_give(efs); + ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); + return LFS_ERR_BADF; + } + file = efs->cache[fd]; + res = lfs_file_close(efs->fs, &file->file); + if(res < 0){ + errno = -res; + sem_give(efs); +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to close file \"%s\". Error %s (%d)", + file->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to close Fd %d. Error %s (%d)", + fd, esp_littlefs_errno(res), res); +#endif + return res; + } + esp_littlefs_free_fd(efs, fd); + sem_give(efs); + return res; +} + +static off_t vfs_littlefs_lseek(void* ctx, int fd, off_t offset, int mode) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + lfs_soff_t res; + vfs_littlefs_file_t *file = NULL; + int whence; + + switch (mode) { + case SEEK_SET: whence = LFS_SEEK_SET; break; + case SEEK_CUR: whence = LFS_SEEK_CUR; break; + case SEEK_END: whence = LFS_SEEK_END; break; + default: + ESP_LOGE(TAG, "Invalid mode"); + return -1; + } + + sem_take(efs); + if((uint32_t)fd > efs->cache_size) { + sem_give(efs); + ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); + return LFS_ERR_BADF; + } + file = efs->cache[fd]; + res = lfs_file_seek(efs->fs, &file->file, offset, whence); + sem_give(efs); + + if(res < 0){ + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to seek file \"%s\" to offset %08x. Error %s (%d)", + file->path, (unsigned int)offset, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to seek FD %d to offset %08x. Error (%d)", + fd, (unsigned int)offset, res); +#endif + return res; + } + + return res; +} + +static int vfs_littlefs_fsync(void* ctx, int fd) +{ + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + ssize_t res; + vfs_littlefs_file_t *file = NULL; + + + sem_take(efs); + if((uint32_t)fd > efs->cache_size) { + sem_give(efs); + ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); + return LFS_ERR_BADF; + } + file = efs->cache[fd]; + res = lfs_file_sync(efs->fs, &file->file); + sem_give(efs); + + if(res < 0){ + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to sync file \"%s\". Error %s (%d)", + file->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to sync file %d. Error %d", fd, res); +#endif + return res; + } + + return res; +} + + +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH +static int vfs_littlefs_fstat(void* ctx, int fd, struct stat * st) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + struct lfs_info info; + int res; + vfs_littlefs_file_t *file = NULL; + + memset(st, 0, sizeof(struct stat)); + st->st_blksize = efs->cfg.block_size; + + sem_take(efs); + if((uint32_t)fd > efs->cache_size) { + sem_give(efs); + ESP_LOGE(TAG, "FD must be <%d.", efs->cache_size); + return LFS_ERR_BADF; + } + file = efs->cache[fd]; + res = lfs_stat(efs->fs, file->path, &info); + if (res < 0) { + errno = -res; + sem_give(efs); + ESP_LOGV(TAG, "Failed to stat file \"%s\". Error %s (%d)", + file->path, esp_littlefs_errno(res), res); + return res; + } + +#if CONFIG_LITTLEFS_USE_MTIME + st->st_mtime = vfs_littlefs_get_mtime(efs, file->path); +#endif + + sem_give(efs); + + st->st_size = info.size; + st->st_mode = ((info.type==LFS_TYPE_REG)?S_IFREG:S_IFDIR); + return 0; +} +#endif + +static int vfs_littlefs_stat(void* ctx, const char * path, struct stat * st) { + assert(path); + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + struct lfs_info info; + int res; + + memset(st, 0, sizeof(struct stat)); + st->st_blksize = efs->cfg.block_size; + + sem_take(efs); + res = lfs_stat(efs->fs, path, &info); + if (res < 0) { + errno = -res; + sem_give(efs); + /* Not strictly an error, since stat can be used to check + * if a file exists */ + ESP_LOGV(TAG, "Failed to stat path \"%s\". Error %s (%d)", + path, esp_littlefs_errno(res), res); + return res; + } +#if CONFIG_LITTLEFS_USE_MTIME + st->st_mtime = vfs_littlefs_get_mtime(efs, path); +#endif + sem_give(efs); + st->st_size = info.size; + st->st_mode = ((info.type==LFS_TYPE_REG)?S_IFREG:S_IFDIR); + return 0; +} + +static int vfs_littlefs_unlink(void* ctx, const char *path) { +#define fail_str_1 "Failed to unlink path \"%s\"." + assert(path); + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + struct lfs_info info; + int res; + + sem_take(efs); + res = lfs_stat(efs->fs, path, &info); + if (res < 0) { + errno = -res; + sem_give(efs); + ESP_LOGV(TAG, fail_str_1 " Error %s (%d)", + path, esp_littlefs_errno(res), res); + return res; + } + + if(esp_littlefs_get_fd_by_name(efs, path) >= 0) { + sem_give(efs); + ESP_LOGE(TAG, fail_str_1 " Has open FD.", path); + return -1; + } +/* commented for old core revisions compatibility */ +/* + if (info.type == LFS_TYPE_DIR) { + sem_give(efs); + ESP_LOGV(TAG, "Cannot unlink a directory."); + return LFS_ERR_ISDIR; + } +*/ + res = lfs_remove(efs->fs, path); + if (res < 0) { + errno = -res; + sem_give(efs); + ESP_LOGV(TAG, fail_str_1 " Error %s (%d)", + path, esp_littlefs_errno(res), res); + return res; + } + +#if CONFIG_LITTLEFS_SPIFFS_COMPAT + /* Attempt to delete all parent directories that are empty */ + rmdirs(efs, path); +#endif // CONFIG_LITTLEFS_SPIFFS_COMPAT + + sem_give(efs); + + return 0; +#undef fail_str_1 +} + +static int vfs_littlefs_rename(void* ctx, const char *src, const char *dst) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + int res; + + sem_take(efs); + + if(esp_littlefs_get_fd_by_name(efs, src) >= 0){ + sem_give(efs); + ESP_LOGE(TAG, "Cannot rename; src \"%s\" is open.", src); + return -1; + } + else if(esp_littlefs_get_fd_by_name(efs, dst) >= 0){ + sem_give(efs); + ESP_LOGE(TAG, "Cannot rename; dst \"%s\" is open.", dst); + return -1; + } + + res = lfs_rename(efs->fs, src, dst); + sem_give(efs); + if (res < 0) { + errno = -res; + ESP_LOGV(TAG, "Failed to rename \"%s\" -> \"%s\". Error %s (%d)", + src, dst, esp_littlefs_errno(res), res); + return res; + } + + return 0; +} + +static DIR* vfs_littlefs_opendir(void* ctx, const char* name) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + int res; + vfs_littlefs_dir_t *dir = NULL; + + dir = calloc(1, sizeof(vfs_littlefs_dir_t)); + if( dir == NULL ) { + ESP_LOGE(TAG, "dir struct could not be malloced"); + goto exit; + } + + dir->path = strdup(name); + if(dir->path == NULL){ + ESP_LOGE(TAG, "dir path name could not be malloced"); + goto exit; + } + + sem_take(efs); + res = lfs_dir_open(efs->fs, &dir->d, dir->path); + sem_give(efs); + if (res < 0) { + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to opendir \"%s\". Error %s (%d)", + dir->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to opendir \"%s\". Error %d", dir->path, res); +#endif + goto exit; + } + + return (DIR *)dir; + +exit: + esp_littlefs_dir_free(dir); + return NULL; +} + +static int vfs_littlefs_closedir(void* ctx, DIR* pdir) { + assert(pdir); + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; + int res; + + sem_take(efs); + res = lfs_dir_close(efs->fs, &dir->d); + sem_give(efs); + if (res < 0) { + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to closedir \"%s\". Error %s (%d)", + dir->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to closedir \"%s\". Error %d", dir->path, res); +#endif + return res; + } + + esp_littlefs_dir_free(dir); + return 0; +} + +static struct dirent* vfs_littlefs_readdir(void* ctx, DIR* pdir) { + assert(pdir); + vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; + int res; + struct dirent* out_dirent; + + res = vfs_littlefs_readdir_r(ctx, pdir, &dir->e, &out_dirent); + if (res != 0) return NULL; + return out_dirent; +} + +static int vfs_littlefs_readdir_r(void* ctx, DIR* pdir, + struct dirent* entry, struct dirent** out_dirent) { + assert(pdir); + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; + int res; + struct lfs_info info = { 0 }; + + sem_take(efs); + do{ /* Read until we get a real object name */ + res = lfs_dir_read(efs->fs, &dir->d, &info); + }while( res>0 && (strcmp(info.name, ".") == 0 || strcmp(info.name, "..") == 0)); + sem_give(efs); + if (res < 0) { + errno = -res; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to readdir \"%s\". Error %s (%d)", + dir->path, esp_littlefs_errno(res), res); +#else + ESP_LOGV(TAG, "Failed to readdir \"%s\". Error %d", dir->path, res); +#endif + return -1; + } + + if(info.type == LFS_TYPE_REG) { + ESP_LOGV(TAG, "readdir a file of size %d named \"%s\"", + info.size, info.name); + } + else { + ESP_LOGV(TAG, "readdir a dir named \"%s\"", info.name); + } + + if(res == 0) { + /* End of Objs */ + ESP_LOGV(TAG, "Reached the end of the directory."); + *out_dirent = NULL; + } + else { + entry->d_ino = 0; + entry->d_type = info.type == LFS_TYPE_REG ? DT_REG : DT_DIR; + strncpy(entry->d_name, info.name, sizeof(entry->d_name)); + *out_dirent = entry; + } + dir->offset++; + + return 0; +} + +static long vfs_littlefs_telldir(void* ctx, DIR* pdir) { + assert(pdir); + vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; + return dir->offset; +} + +static void vfs_littlefs_seekdir(void* ctx, DIR* pdir, long offset) { + assert(pdir); + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; + int res; + + if (offset < dir->offset) { + /* close and re-open dir to rewind to beginning */ + sem_take(efs); + res = lfs_dir_rewind(efs->fs, &dir->d); + sem_give(efs); + if (res < 0) { + errno = -res; + ESP_LOGV(TAG, "Failed to rewind dir \"%s\". Error %s (%d)", + dir->path, esp_littlefs_errno(res), res); + return; + } + dir->offset = 0; + } + + while(dir->offset < offset){ + struct dirent *out_dirent; + res = vfs_littlefs_readdir_r(ctx, pdir, &dir->e, &out_dirent); + if( res != 0 ){ + ESP_LOGE(TAG, "Error readdir_r"); + return; + } + } +} + +static int vfs_littlefs_mkdir(void* ctx, const char* name, mode_t mode) { + /* Note: mode is currently unused */ + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + int res; + ESP_LOGV(TAG, "mkdir \"%s\"", name); + + sem_take(efs); + res = lfs_mkdir(efs->fs, name); + sem_give(efs); + if (res < 0) { + errno = -res; + ESP_LOGV(TAG, "Failed to mkdir \"%s\". Error %s (%d)", + name, esp_littlefs_errno(res), res); + return res; + } + return 0; +} + +static int vfs_littlefs_rmdir(void* ctx, const char* name) { + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + struct lfs_info info; + int res; + + /* Error Checking */ + sem_take(efs); + res = lfs_stat(efs->fs, name, &info); + if (res < 0) { + errno = -res; + sem_give(efs); + ESP_LOGV(TAG, "\"%s\" doesn't exist.", name); + return -1; + } + + if (info.type != LFS_TYPE_DIR) { + sem_give(efs); + ESP_LOGV(TAG, "\"%s\" is not a directory.", name); + return -1; + } + + /* Unlink the dir */ + res = lfs_remove(efs->fs, name); + sem_give(efs); + if ( res < 0) { + errno = -res; + ESP_LOGV(TAG, "Failed to unlink path \"%s\". Error %s (%d)", + name, esp_littlefs_errno(res), res); + return -1; + } + + return 0; +} + +#if CONFIG_LITTLEFS_USE_MTIME +/** + * Sets the mtime attr to t. + */ +static int vfs_littlefs_update_mtime_value(esp_littlefs_t *efs, const char *path, time_t t) +{ + int res; + res = lfs_setattr(efs->fs, path, LITTLEFS_ATTR_MTIME, + &t, sizeof(t)); + if( res < 0 ) { + errno = -res; + ESP_LOGV(TAG, "Failed to update mtime (%d)", res); + } + + return res; +} + +/** + * Sets the mtime attr to an appropriate value + */ +static void vfs_littlefs_update_mtime(esp_littlefs_t *efs, const char *path) +{ + vfs_littlefs_utime(efs, path, NULL); +} + + +static int vfs_littlefs_utime(void *ctx, const char *path, const struct utimbuf *times) +{ + esp_littlefs_t * efs = (esp_littlefs_t *)ctx; + time_t t; + + assert(path); + + if (times) { + t = times->modtime; + } else { +#if CONFIG_LITTLEFS_MTIME_USE_SECONDS + // use current time + t = time(NULL); +#elif CONFIG_LITTLEFS_MTIME_USE_NONCE + assert( sizeof(time_t) == 4 ); + t = vfs_littlefs_get_mtime(efs, path); + if( 0 == t ) t = esp_random(); + else t += 1; + + if( 0 == t ) t = 1; +#else +#error "Invalid MTIME configuration" +#endif + } + + int ret = vfs_littlefs_update_mtime_value(efs, path, t); + return ret; +} + +static time_t vfs_littlefs_get_mtime(esp_littlefs_t *efs, const char *path) +{ + time_t t = 0; + int size; + size = lfs_getattr(efs->fs, path, LITTLEFS_ATTR_MTIME, + &t, sizeof(t)); + if( size < 0 ) { + errno = -size; +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + ESP_LOGV(TAG, "Failed to get mtime attribute %s (%d)", + esp_littlefs_errno(size), size); +#else + ESP_LOGV(TAG, "Failed to get mtime attribute %d", size); +#endif + } + return t; +} +#endif //CONFIG_LITTLEFS_USE_MTIME + +#if CONFIG_LITTLEFS_SPIFFS_COMPAT +/** + * @brief Recursively make all parent directories for a file. + * @param[in] dir Path of directories to make up to. The last element + * of the path is assumed to be the file and IS NOT created. + * e.g. + * "foo/bar/baz" + * will create directories "foo" and "bar" + */ +static void mkdirs(esp_littlefs_t * efs, const char *dir) { + char tmp[CONFIG_LITTLEFS_OBJ_NAME_LEN]; + char *p = NULL; + + strlcpy(tmp, dir, sizeof(tmp)); + for(p = tmp + 1; *p; p++) { + if(*p == '/') { + *p = '\0'; + vfs_littlefs_mkdir((void*)efs, tmp, S_IRWXU); + *p = '/'; + } + } +} + +/** + * @brief Recursively attempt to delete all empty directories for a file. + * @param[in] dir Path of directories to delete. The last element of the path + * is assumed to be the file and IS NOT deleted. + * e.g. + * "foo/bar/baz" + * will attempt to delete directories (in order): + * 1. "foo/bar/baz" + * 2. "foo/bar" + * 3. "foo" + */ + +static void rmdirs(esp_littlefs_t * efs, const char *dir) { + char tmp[CONFIG_LITTLEFS_OBJ_NAME_LEN]; + char *p = NULL; + + strlcpy(tmp, dir, sizeof(tmp)); + for(p = tmp + strlen(tmp) - 1; p != tmp; p--) { + if(*p == '/') { + *p = '\0'; + vfs_littlefs_rmdir((void*)efs, tmp); + *p = '/'; + } + } +} + +#endif // CONFIG_LITTLEFS_SPIFFS_COMPAT diff --git a/lib/libesp32/LITTLEFS/src/esp_littlefs.h b/lib/libesp32/LITTLEFS/src/esp_littlefs.h new file mode 100755 index 000000000..549c967e6 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/esp_littlefs.h @@ -0,0 +1,118 @@ +#ifndef ESP_LITTLEFS_H__ +#define ESP_LITTLEFS_H__ + +#include +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "esp_err.h" +#include +#include +#include +#include +#include +#include +#include +#include "sdkconfig.h" + +#include "lfs.h" //#include "littlefs/lfs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Last Modified Time + * + * Use 't' for LITTLEFS_ATTR_MTIME to match example: + * https://github.com/ARMmbed/littlefs/issues/23#issuecomment-482293539 + * And to match other external tools such as: + * https://github.com/earlephilhower/mklittlefs + */ +#define LITTLEFS_ATTR_MTIME ((uint8_t) 't') + +/** + *Configuration structure for esp_vfs_littlefs_register. + */ +typedef struct { + const char *base_path; /**< Mounting point. */ + const char *partition_label; /**< Label of partition to use. */ + uint8_t format_if_mount_failed:1; /**< Format the file system if it fails to mount. */ + uint8_t dont_mount:1; /**< Don't attempt to mount or format. Overrides format_if_mount_failed */ +} esp_vfs_littlefs_conf_t; + +/** + * Register and mount littlefs to VFS with given path prefix. + * + * @param conf Pointer to esp_vfs_littlefs_conf_t configuration structure + * + * @return + * - ESP_OK if success + * - ESP_ERR_NO_MEM if objects could not be allocated + * - ESP_ERR_INVALID_STATE if already mounted or partition is encrypted + * - ESP_ERR_NOT_FOUND if partition for littlefs was not found + * - ESP_FAIL if mount or format fails + */ +esp_err_t esp_vfs_littlefs_register(const esp_vfs_littlefs_conf_t * conf); + +/** + * Unregister and unmount littlefs from VFS + * + * @param partition_label Label of the partition to unregister. + * + * @return + * - ESP_OK if successful + * - ESP_ERR_INVALID_STATE already unregistered + */ +esp_err_t esp_vfs_littlefs_unregister(const char* partition_label); + +/** + * Check if littlefs is mounted + * + * @param partition_label Label of the partition to check. + * + * @return + * - true if mounted + * - false if not mounted + */ +bool esp_littlefs_mounted(const char* partition_label); + +/** + * Format the littlefs partition + * + * @param partition_label Label of the partition to format. + * @return + * - ESP_OK if successful + * - ESP_FAIL on error + */ +esp_err_t esp_littlefs_format(const char* partition_label); + +/** + * Get information for littlefs + * + * @param partition_label Optional, label of the partition to get info for. + * @param[out] total_bytes Size of the file system + * @param[out] used_bytes Current used bytes in the file system + * + * @return + * - ESP_OK if success + * - ESP_ERR_INVALID_STATE if not mounted + */ +esp_err_t esp_littlefs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes); + +#if CONFIG_LITTLEFS_HUMAN_READABLE +/** + * @brief converts an enumerated lfs error into a string. + * @param lfs_errno The enumerated littlefs error. + */ +const char * esp_littlefs_errno(enum lfs_error lfs_errno); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/lib/libesp32/LITTLEFS/src/lfs.c b/lib/libesp32/LITTLEFS/src/lfs.c new file mode 100755 index 000000000..a5bfb914e --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/lfs.c @@ -0,0 +1,4918 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * + * @note Modified and used by lorol for Arduino esp32 core tests + */ + +//#define LFS_NO_ERROR /* Change default error reporting level: LFS_NO_DEBUG, LFS_NO_WARN, LFS_NO_ERROR, LFS_YES_TRACE */ + +#include "lfs.h" +#include "lfs_util.h" + +#define LFS_BLOCK_NULL ((lfs_block_t)-1) +#define LFS_BLOCK_INLINE ((lfs_block_t)-2) + +/// Caching block device operations /// +static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { + // do not zero, cheaper if cache is readonly or only going to be + // written with identical data (during relocates) + (void)lfs; + rcache->block = LFS_BLOCK_NULL; +} + +static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { + // zero to avoid information leak + memset(pcache->buffer, 0xff, lfs->cfg->cache_size); + pcache->block = LFS_BLOCK_NULL; +} + +static int lfs_bd_read(lfs_t *lfs, + const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, + lfs_block_t block, lfs_off_t off, + void *buffer, lfs_size_t size) { + uint8_t *data = buffer; + if (block >= lfs->cfg->block_count || + off+size > lfs->cfg->block_size) { + return LFS_ERR_CORRUPT; + } + + while (size > 0) { + lfs_size_t diff = size; + + if (pcache && block == pcache->block && + off < pcache->off + pcache->size) { + if (off >= pcache->off) { + // is already in pcache? + diff = lfs_min(diff, pcache->size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // pcache takes priority + diff = lfs_min(diff, pcache->off-off); + } + + if (block == rcache->block && + off < rcache->off + rcache->size) { + if (off >= rcache->off) { + // is already in rcache? + diff = lfs_min(diff, rcache->size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // rcache takes priority + diff = lfs_min(diff, rcache->off-off); + } + + if (size >= hint && off % lfs->cfg->read_size == 0 && + size >= lfs->cfg->read_size) { + // bypass cache? + diff = lfs_aligndown(diff, lfs->cfg->read_size); + int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); + if (err) { + return err; + } + + data += diff; + off += diff; + size -= diff; + continue; + } + + // load to cache, first condition can no longer fail + LFS_ASSERT(block < lfs->cfg->block_count); + rcache->block = block; + rcache->off = lfs_aligndown(off, lfs->cfg->read_size); + rcache->size = lfs_min( + lfs_min( + lfs_alignup(off+hint, lfs->cfg->read_size), + lfs->cfg->block_size) + - rcache->off, + lfs->cfg->cache_size); + int err = lfs->cfg->read(lfs->cfg, rcache->block, + rcache->off, rcache->buffer, rcache->size); + LFS_ASSERT(err <= 0); + if (err) { + return err; + } + } + + return 0; +} + +enum { + LFS_CMP_EQ = 0, + LFS_CMP_LT = 1, + LFS_CMP_GT = 2, +}; + +static int lfs_bd_cmp(lfs_t *lfs, + const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, + lfs_block_t block, lfs_off_t off, + const void *buffer, lfs_size_t size) { + const uint8_t *data = buffer; + + for (lfs_off_t i = 0; i < size; i++) { + uint8_t dat; + int err = lfs_bd_read(lfs, + pcache, rcache, hint-i, + block, off+i, &dat, 1); + if (err) { + return err; + } + + if (dat != data[i]) { + return (dat < data[i]) ? LFS_CMP_LT : LFS_CMP_GT; + } + } + + return LFS_CMP_EQ; +} + +static int lfs_bd_flush(lfs_t *lfs, + lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { + if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) { + LFS_ASSERT(pcache->block < lfs->cfg->block_count); + lfs_size_t diff = lfs_alignup(pcache->size, lfs->cfg->prog_size); + int err = lfs->cfg->prog(lfs->cfg, pcache->block, + pcache->off, pcache->buffer, diff); + LFS_ASSERT(err <= 0); + if (err) { + return err; + } + + if (validate) { + // check data on disk + lfs_cache_drop(lfs, rcache); + int res = lfs_bd_cmp(lfs, + NULL, rcache, diff, + pcache->block, pcache->off, pcache->buffer, diff); + if (res < 0) { + return res; + } + + if (res != LFS_CMP_EQ) { + return LFS_ERR_CORRUPT; + } + } + + lfs_cache_zero(lfs, pcache); + } + + return 0; +} + +static int lfs_bd_sync(lfs_t *lfs, + lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { + lfs_cache_drop(lfs, rcache); + + int err = lfs_bd_flush(lfs, pcache, rcache, validate); + if (err) { + return err; + } + + err = lfs->cfg->sync(lfs->cfg); + LFS_ASSERT(err <= 0); + return err; +} + +static int lfs_bd_prog(lfs_t *lfs, + lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate, + lfs_block_t block, lfs_off_t off, + const void *buffer, lfs_size_t size) { + const uint8_t *data = buffer; + LFS_ASSERT(block == LFS_BLOCK_INLINE || block < lfs->cfg->block_count); + LFS_ASSERT(off + size <= lfs->cfg->block_size); + + while (size > 0) { + if (block == pcache->block && + off >= pcache->off && + off < pcache->off + lfs->cfg->cache_size) { + // already fits in pcache? + lfs_size_t diff = lfs_min(size, + lfs->cfg->cache_size - (off-pcache->off)); + memcpy(&pcache->buffer[off-pcache->off], data, diff); + + data += diff; + off += diff; + size -= diff; + + pcache->size = lfs_max(pcache->size, off - pcache->off); + if (pcache->size == lfs->cfg->cache_size) { + // eagerly flush out pcache if we fill up + int err = lfs_bd_flush(lfs, pcache, rcache, validate); + if (err) { + return err; + } + } + + continue; + } + + // pcache must have been flushed, either by programming and + // entire block or manually flushing the pcache + LFS_ASSERT(pcache->block == LFS_BLOCK_NULL); + + // prepare pcache, first condition can no longer fail + pcache->block = block; + pcache->off = lfs_aligndown(off, lfs->cfg->prog_size); + pcache->size = 0; + } + + return 0; +} + +static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { + LFS_ASSERT(block < lfs->cfg->block_count); + int err = lfs->cfg->erase(lfs->cfg, block); + LFS_ASSERT(err <= 0); + return err; +} + + +/// Small type-level utilities /// +// operations on block pairs +static inline void lfs_pair_swap(lfs_block_t pair[2]) { + lfs_block_t t = pair[0]; + pair[0] = pair[1]; + pair[1] = t; +} + +static inline bool lfs_pair_isnull(const lfs_block_t pair[2]) { + return pair[0] == LFS_BLOCK_NULL || pair[1] == LFS_BLOCK_NULL; +} + +static inline int lfs_pair_cmp( + const lfs_block_t paira[2], + const lfs_block_t pairb[2]) { + return !(paira[0] == pairb[0] || paira[1] == pairb[1] || + paira[0] == pairb[1] || paira[1] == pairb[0]); +} + +static inline bool lfs_pair_sync( + const lfs_block_t paira[2], + const lfs_block_t pairb[2]) { + return (paira[0] == pairb[0] && paira[1] == pairb[1]) || + (paira[0] == pairb[1] && paira[1] == pairb[0]); +} + +static inline void lfs_pair_fromle32(lfs_block_t pair[2]) { + pair[0] = lfs_fromle32(pair[0]); + pair[1] = lfs_fromle32(pair[1]); +} + +static inline void lfs_pair_tole32(lfs_block_t pair[2]) { + pair[0] = lfs_tole32(pair[0]); + pair[1] = lfs_tole32(pair[1]); +} + +// operations on 32-bit entry tags +typedef uint32_t lfs_tag_t; +typedef int32_t lfs_stag_t; + +#define LFS_MKTAG(type, id, size) \ + (((lfs_tag_t)(type) << 20) | ((lfs_tag_t)(id) << 10) | (lfs_tag_t)(size)) + +#define LFS_MKTAG_IF(cond, type, id, size) \ + ((cond) ? LFS_MKTAG(type, id, size) : LFS_MKTAG(LFS_FROM_NOOP, 0, 0)) + +#define LFS_MKTAG_IF_ELSE(cond, type1, id1, size1, type2, id2, size2) \ + ((cond) ? LFS_MKTAG(type1, id1, size1) : LFS_MKTAG(type2, id2, size2)) + +static inline bool lfs_tag_isvalid(lfs_tag_t tag) { + return !(tag & 0x80000000); +} + +static inline bool lfs_tag_isdelete(lfs_tag_t tag) { + return ((int32_t)(tag << 22) >> 22) == -1; +} + +static inline uint16_t lfs_tag_type1(lfs_tag_t tag) { + return (tag & 0x70000000) >> 20; +} + +static inline uint16_t lfs_tag_type3(lfs_tag_t tag) { + return (tag & 0x7ff00000) >> 20; +} + +static inline uint8_t lfs_tag_chunk(lfs_tag_t tag) { + return (tag & 0x0ff00000) >> 20; +} + +static inline int8_t lfs_tag_splice(lfs_tag_t tag) { + return (int8_t)lfs_tag_chunk(tag); +} + +static inline uint16_t lfs_tag_id(lfs_tag_t tag) { + return (tag & 0x000ffc00) >> 10; +} + +static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) { + return tag & 0x000003ff; +} + +static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) { + return sizeof(tag) + lfs_tag_size(tag + lfs_tag_isdelete(tag)); +} + +// operations on attributes in attribute lists +struct lfs_mattr { + lfs_tag_t tag; + const void *buffer; +}; + +struct lfs_diskoff { + lfs_block_t block; + lfs_off_t off; +}; + +#define LFS_MKATTRS(...) \ + (struct lfs_mattr[]){__VA_ARGS__}, \ + sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr) + +// operations on global state +static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) { + for (int i = 0; i < 3; i++) { + ((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i]; + } +} + +static inline bool lfs_gstate_iszero(const lfs_gstate_t *a) { + for (int i = 0; i < 3; i++) { + if (((uint32_t*)a)[i] != 0) { + return false; + } + } + return true; +} + +static inline bool lfs_gstate_hasorphans(const lfs_gstate_t *a) { + return lfs_tag_size(a->tag); +} + +static inline uint8_t lfs_gstate_getorphans(const lfs_gstate_t *a) { + return lfs_tag_size(a->tag); +} + +static inline bool lfs_gstate_hasmove(const lfs_gstate_t *a) { + return lfs_tag_type1(a->tag); +} + +static inline bool lfs_gstate_hasmovehere(const lfs_gstate_t *a, + const lfs_block_t *pair) { + return lfs_tag_type1(a->tag) && lfs_pair_cmp(a->pair, pair) == 0; +} + +static inline void lfs_gstate_fromle32(lfs_gstate_t *a) { + a->tag = lfs_fromle32(a->tag); + a->pair[0] = lfs_fromle32(a->pair[0]); + a->pair[1] = lfs_fromle32(a->pair[1]); +} + +static inline void lfs_gstate_tole32(lfs_gstate_t *a) { + a->tag = lfs_tole32(a->tag); + a->pair[0] = lfs_tole32(a->pair[0]); + a->pair[1] = lfs_tole32(a->pair[1]); +} + +// other endianness operations +static void lfs_ctz_fromle32(struct lfs_ctz *ctz) { + ctz->head = lfs_fromle32(ctz->head); + ctz->size = lfs_fromle32(ctz->size); +} + +static void lfs_ctz_tole32(struct lfs_ctz *ctz) { + ctz->head = lfs_tole32(ctz->head); + ctz->size = lfs_tole32(ctz->size); +} + +static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { + superblock->version = lfs_fromle32(superblock->version); + superblock->block_size = lfs_fromle32(superblock->block_size); + superblock->block_count = lfs_fromle32(superblock->block_count); + superblock->name_max = lfs_fromle32(superblock->name_max); + superblock->file_max = lfs_fromle32(superblock->file_max); + superblock->attr_max = lfs_fromle32(superblock->attr_max); +} + +static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { + superblock->version = lfs_tole32(superblock->version); + superblock->block_size = lfs_tole32(superblock->block_size); + superblock->block_count = lfs_tole32(superblock->block_count); + superblock->name_max = lfs_tole32(superblock->name_max); + superblock->file_max = lfs_tole32(superblock->file_max); + superblock->attr_max = lfs_tole32(superblock->attr_max); +} + + +/// Internal operations predeclared here /// +static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, + const struct lfs_mattr *attrs, int attrcount); +static int lfs_dir_compact(lfs_t *lfs, + lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, + lfs_mdir_t *source, uint16_t begin, uint16_t end); +static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); +static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); +static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); +static void lfs_fs_prepmove(lfs_t *lfs, + uint16_t id, const lfs_block_t pair[2]); +static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2], + lfs_mdir_t *pdir); +static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2], + lfs_mdir_t *parent); +static int lfs_fs_relocate(lfs_t *lfs, + const lfs_block_t oldpair[2], lfs_block_t newpair[2]); +int lfs_fs_traverseraw(lfs_t *lfs, + int (*cb)(void *data, lfs_block_t block), void *data, + bool includeorphans); +static int lfs_fs_forceconsistency(lfs_t *lfs); +static int lfs_deinit(lfs_t *lfs); +#ifdef LFS_MIGRATE +static int lfs1_traverse(lfs_t *lfs, + int (*cb)(void*, lfs_block_t), void *data); +#endif + +/// Block allocator /// +static int lfs_alloc_lookahead(void *p, lfs_block_t block) { + lfs_t *lfs = (lfs_t*)p; + lfs_block_t off = ((block - lfs->free.off) + + lfs->cfg->block_count) % lfs->cfg->block_count; + + if (off < lfs->free.size) { + lfs->free.buffer[off / 32] |= 1U << (off % 32); + } + + return 0; +} + +static void lfs_alloc_ack(lfs_t *lfs) { + lfs->free.ack = lfs->cfg->block_count; +} + +// Invalidate the lookahead buffer. This is done during mounting and +// failed traversals +static void lfs_alloc_reset(lfs_t *lfs) { + lfs->free.off = lfs->seed % lfs->cfg->block_count; //lfs->free.off = lfs->seed % lfs->cfg->block_size; + lfs->free.size = 0; + lfs->free.i = 0; + lfs_alloc_ack(lfs); +} + +static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { + while (true) { + while (lfs->free.i != lfs->free.size) { + lfs_block_t off = lfs->free.i; + lfs->free.i += 1; + lfs->free.ack -= 1; + + if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { + // found a free block + *block = (lfs->free.off + off) % lfs->cfg->block_count; + + // eagerly find next off so an alloc ack can + // discredit old lookahead blocks + while (lfs->free.i != lfs->free.size && + (lfs->free.buffer[lfs->free.i / 32] + & (1U << (lfs->free.i % 32)))) { + lfs->free.i += 1; + lfs->free.ack -= 1; + } + + return 0; + } + } + + // check if we have looked at all blocks since last ack + if (lfs->free.ack == 0) { + LFS_ERROR("No more free space %"PRIu32, + lfs->free.i + lfs->free.off); + return LFS_ERR_NOSPC; + } + + lfs->free.off = (lfs->free.off + lfs->free.size) + % lfs->cfg->block_count; + lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack); + lfs->free.i = 0; + + // find mask of free blocks from tree + memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); + int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); + if (err) { + lfs_alloc_reset(lfs); + return err; + } + } +} + +/// Metadata pair and directory operations /// +static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, + lfs_tag_t gmask, lfs_tag_t gtag, + lfs_off_t goff, void *gbuffer, lfs_size_t gsize) { + lfs_off_t off = dir->off; + lfs_tag_t ntag = dir->etag; + lfs_stag_t gdiff = 0; + + if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) && + lfs_tag_id(gmask) != 0 && + lfs_tag_id(lfs->gdisk.tag) <= lfs_tag_id(gtag)) { + // synthetic moves + gdiff -= LFS_MKTAG(0, 1, 0); + } + + // iterate over dir block backwards (for faster lookups) + while (off >= sizeof(lfs_tag_t) + lfs_tag_dsize(ntag)) { + off -= lfs_tag_dsize(ntag); + lfs_tag_t tag = ntag; + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, sizeof(ntag), + dir->pair[0], off, &ntag, sizeof(ntag)); + if (err) { + return err; + } + + ntag = (lfs_frombe32(ntag) ^ tag) & 0x7fffffff; + + if (lfs_tag_id(gmask) != 0 && + lfs_tag_type1(tag) == LFS_TYPE_SPLICE && + lfs_tag_id(tag) <= lfs_tag_id(gtag - gdiff)) { + if (tag == (LFS_MKTAG(LFS_TYPE_CREATE, 0, 0) | + (LFS_MKTAG(0, 0x3ff, 0) & (gtag - gdiff)))) { + // found where we were created + return LFS_ERR_NOENT; + } + + // move around splices + gdiff += LFS_MKTAG(0, lfs_tag_splice(tag), 0); + } + + if ((gmask & tag) == (gmask & (gtag - gdiff))) { + if (lfs_tag_isdelete(tag)) { + return LFS_ERR_NOENT; + } + + lfs_size_t diff = lfs_min(lfs_tag_size(tag), gsize); + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, diff, + dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff); + if (err) { + return err; + } + + memset((uint8_t*)gbuffer + diff, 0, gsize - diff); + + return tag + gdiff; + } + } + + return LFS_ERR_NOENT; +} + +static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir, + lfs_tag_t gmask, lfs_tag_t gtag, void *buffer) { + return lfs_dir_getslice(lfs, dir, + gmask, gtag, + 0, buffer, lfs_tag_size(gtag)); +} + +static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, + const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, + lfs_tag_t gmask, lfs_tag_t gtag, + lfs_off_t off, void *buffer, lfs_size_t size) { + uint8_t *data = buffer; + if (off+size > lfs->cfg->block_size) { + return LFS_ERR_CORRUPT; + } + + while (size > 0) { + lfs_size_t diff = size; + + if (pcache && pcache->block == LFS_BLOCK_INLINE && + off < pcache->off + pcache->size) { + if (off >= pcache->off) { + // is already in pcache? + diff = lfs_min(diff, pcache->size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // pcache takes priority + diff = lfs_min(diff, pcache->off-off); + } + + if (rcache->block == LFS_BLOCK_INLINE && + off < rcache->off + rcache->size) { + if (off >= rcache->off) { + // is already in rcache? + diff = lfs_min(diff, rcache->size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); + + data += diff; + off += diff; + size -= diff; + continue; + } + + // rcache takes priority + diff = lfs_min(diff, rcache->off-off); + } + + // load to cache, first condition can no longer fail + rcache->block = LFS_BLOCK_INLINE; + rcache->off = lfs_aligndown(off, lfs->cfg->read_size); + rcache->size = lfs_min(lfs_alignup(off+hint, lfs->cfg->read_size), + lfs->cfg->cache_size); + int err = lfs_dir_getslice(lfs, dir, gmask, gtag, + rcache->off, rcache->buffer, rcache->size); + if (err < 0) { + return err; + } + } + + return 0; +} + +static int lfs_dir_traverse_filter(void *p, + lfs_tag_t tag, const void *buffer) { + lfs_tag_t *filtertag = p; + (void)buffer; + + // which mask depends on unique bit in tag structure + uint32_t mask = (tag & LFS_MKTAG(0x100, 0, 0)) + ? LFS_MKTAG(0x7ff, 0x3ff, 0) + : LFS_MKTAG(0x700, 0x3ff, 0); + + // check for redundancy + if ((mask & tag) == (mask & *filtertag) || + lfs_tag_isdelete(*filtertag) || + (LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == ( + LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | + (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { + return true; + } + + // check if we need to adjust for created/deleted tags + if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE && + lfs_tag_id(tag) <= lfs_tag_id(*filtertag)) { + *filtertag += LFS_MKTAG(0, lfs_tag_splice(tag), 0); + } + + return false; +} + +static int lfs_dir_traverse(lfs_t *lfs, + const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag, + const struct lfs_mattr *attrs, int attrcount, + lfs_tag_t tmask, lfs_tag_t ttag, + uint16_t begin, uint16_t end, int16_t diff, + int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) { + // iterate over directory and attrs + while (true) { + lfs_tag_t tag; + const void *buffer; + struct lfs_diskoff disk; + if (off+lfs_tag_dsize(ptag) < dir->off) { + off += lfs_tag_dsize(ptag); + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, sizeof(tag), + dir->pair[0], off, &tag, sizeof(tag)); + if (err) { + return err; + } + + tag = (lfs_frombe32(tag) ^ ptag) | 0x80000000; + disk.block = dir->pair[0]; + disk.off = off+sizeof(lfs_tag_t); + buffer = &disk; + ptag = tag; + } else if (attrcount > 0) { + tag = attrs[0].tag; + buffer = attrs[0].buffer; + attrs += 1; + attrcount -= 1; + } else { + return 0; + } + + lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0); + if ((mask & tmask & tag) != (mask & tmask & ttag)) { + continue; + } + + // do we need to filter? inlining the filtering logic here allows + // for some minor optimizations + if (lfs_tag_id(tmask) != 0) { + // scan for duplicates and update tag based on creates/deletes + int filter = lfs_dir_traverse(lfs, + dir, off, ptag, attrs, attrcount, + 0, 0, 0, 0, 0, + lfs_dir_traverse_filter, &tag); + if (filter < 0) { + return filter; + } + + if (filter) { + continue; + } + + // in filter range? + if (!(lfs_tag_id(tag) >= begin && lfs_tag_id(tag) < end)) { + continue; + } + } + + // handle special cases for mcu-side operations + if (lfs_tag_type3(tag) == LFS_FROM_NOOP) { + // do nothing + } else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) { + uint16_t fromid = lfs_tag_size(tag); + uint16_t toid = lfs_tag_id(tag); + int err = lfs_dir_traverse(lfs, + buffer, 0, 0xffffffff, NULL, 0, + LFS_MKTAG(0x600, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, 0, 0), + fromid, fromid+1, toid-fromid+diff, + cb, data); + if (err) { + return err; + } + } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) { + for (unsigned i = 0; i < lfs_tag_size(tag); i++) { + const struct lfs_attr *a = buffer; + int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type, + lfs_tag_id(tag) + diff, a[i].size), a[i].buffer); + if (err) { + return err; + } + } + } else { + int err = cb(data, tag + LFS_MKTAG(0, diff, 0), buffer); + if (err) { + return err; + } + } + } +} + +static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, + lfs_mdir_t *dir, const lfs_block_t pair[2], + lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id, + int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) { + // we can find tag very efficiently during a fetch, since we're already + // scanning the entire directory + lfs_stag_t besttag = -1; + + // if either block address is invalid we return LFS_ERR_CORRUPT here, + // otherwise later writes to the pair could fail + if (pair[0] >= lfs->cfg->block_count || pair[1] >= lfs->cfg->block_count) { + return LFS_ERR_CORRUPT; + } + + // find the block with the most recent revision + uint32_t revs[2] = {0, 0}; + int r = 0; + for (int i = 0; i < 2; i++) { + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, sizeof(revs[i]), + pair[i], 0, &revs[i], sizeof(revs[i])); + revs[i] = lfs_fromle32(revs[i]); + if (err && err != LFS_ERR_CORRUPT) { + return err; + } + + if (err != LFS_ERR_CORRUPT && + lfs_scmp(revs[i], revs[(i+1)%2]) > 0) { + r = i; + } + } + + dir->pair[0] = pair[(r+0)%2]; + dir->pair[1] = pair[(r+1)%2]; + dir->rev = revs[(r+0)%2]; + dir->off = 0; // nonzero = found some commits + + // now scan tags to fetch the actual dir and find possible match + for (int i = 0; i < 2; i++) { + lfs_off_t off = 0; + lfs_tag_t ptag = 0xffffffff; + + uint16_t tempcount = 0; + lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; + bool tempsplit = false; + lfs_stag_t tempbesttag = besttag; + + dir->rev = lfs_tole32(dir->rev); + uint32_t crc = lfs_crc(0xffffffff, &dir->rev, sizeof(dir->rev)); + dir->rev = lfs_fromle32(dir->rev); + + while (true) { + // extract next tag + lfs_tag_t tag; + off += lfs_tag_dsize(ptag); + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, lfs->cfg->block_size, + dir->pair[0], off, &tag, sizeof(tag)); + if (err) { + if (err == LFS_ERR_CORRUPT) { + // can't continue? + dir->erased = false; + break; + } + return err; + } + + crc = lfs_crc(crc, &tag, sizeof(tag)); + tag = lfs_frombe32(tag) ^ ptag; + + // next commit not yet programmed or we're not in valid range + if (!lfs_tag_isvalid(tag)) { + dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC && + dir->off % lfs->cfg->prog_size == 0); + break; + } else if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) { + dir->erased = false; + break; + } + + ptag = tag; + + if (lfs_tag_type1(tag) == LFS_TYPE_CRC) { + // check the crc attr + uint32_t dcrc; + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, lfs->cfg->block_size, + dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc)); + if (err) { + if (err == LFS_ERR_CORRUPT) { + dir->erased = false; + break; + } + return err; + } + dcrc = lfs_fromle32(dcrc); + + if (crc != dcrc) { + dir->erased = false; + break; + } + + // reset the next bit if we need to + ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; + + // toss our crc into the filesystem seed for + // pseudorandom numbers + lfs->seed ^= crc; + + // update with what's found so far + besttag = tempbesttag; + dir->off = off + lfs_tag_dsize(tag); + dir->etag = ptag; + dir->count = tempcount; + dir->tail[0] = temptail[0]; + dir->tail[1] = temptail[1]; + dir->split = tempsplit; + + // reset crc + crc = 0xffffffff; + continue; + } + + // crc the entry first, hopefully leaving it in the cache + for (lfs_off_t j = sizeof(tag); j < lfs_tag_dsize(tag); j++) { + uint8_t dat; + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, lfs->cfg->block_size, + dir->pair[0], off+j, &dat, 1); + if (err) { + if (err == LFS_ERR_CORRUPT) { + dir->erased = false; + break; + } + return err; + } + + crc = lfs_crc(crc, &dat, 1); + } + + // directory modification tags? + if (lfs_tag_type1(tag) == LFS_TYPE_NAME) { + // increase count of files if necessary + if (lfs_tag_id(tag) >= tempcount) { + tempcount = lfs_tag_id(tag) + 1; + } + } else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) { + tempcount += lfs_tag_splice(tag); + + if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | + (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) { + tempbesttag |= 0x80000000; + } else if (tempbesttag != -1 && + lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) { + tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0); + } + } else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) { + tempsplit = (lfs_tag_chunk(tag) & 1); + + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, lfs->cfg->block_size, + dir->pair[0], off+sizeof(tag), &temptail, 8); + if (err) { + if (err == LFS_ERR_CORRUPT) { + dir->erased = false; + break; + } + } + lfs_pair_fromle32(temptail); + } + + // found a match for our fetcher? + if ((fmask & tag) == (fmask & ftag)) { + int res = cb(data, tag, &(struct lfs_diskoff){ + dir->pair[0], off+sizeof(tag)}); + if (res < 0) { + if (res == LFS_ERR_CORRUPT) { + dir->erased = false; + break; + } + return res; + } + + if (res == LFS_CMP_EQ) { + // found a match + tempbesttag = tag; + } else if ((LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == + (LFS_MKTAG(0x7ff, 0x3ff, 0) & tempbesttag)) { + // found an identical tag, but contents didn't match + // this must mean that our besttag has been overwritten + tempbesttag = -1; + } else if (res == LFS_CMP_GT && + lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) { + // found a greater match, keep track to keep things sorted + tempbesttag = tag | 0x80000000; + } + } + } + + // consider what we have good enough + if (dir->off > 0) { + // synthetic move + if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair)) { + if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(besttag)) { + besttag |= 0x80000000; + } else if (besttag != -1 && + lfs_tag_id(lfs->gdisk.tag) < lfs_tag_id(besttag)) { + besttag -= LFS_MKTAG(0, 1, 0); + } + } + + // found tag? or found best id? + if (id) { + *id = lfs_min(lfs_tag_id(besttag), dir->count); + } + + if (lfs_tag_isvalid(besttag)) { + return besttag; + } else if (lfs_tag_id(besttag) < dir->count) { + return LFS_ERR_NOENT; + } else { + return 0; + } + } + + // failed, try the other block? + lfs_pair_swap(dir->pair); + dir->rev = revs[(r+1)%2]; + } + + LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", + dir->pair[0], dir->pair[1]); + return LFS_ERR_CORRUPT; +} + +static int lfs_dir_fetch(lfs_t *lfs, + lfs_mdir_t *dir, const lfs_block_t pair[2]) { + // note, mask=-1, tag=-1 can never match a tag since this + // pattern has the invalid bit set + return (int)lfs_dir_fetchmatch(lfs, dir, pair, + (lfs_tag_t)-1, (lfs_tag_t)-1, NULL, NULL, NULL); +} + +static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir, + lfs_gstate_t *gstate) { + lfs_gstate_t temp; + lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0), + LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp); + if (res < 0 && res != LFS_ERR_NOENT) { + return res; + } + + if (res != LFS_ERR_NOENT) { + // xor together to find resulting gstate + lfs_gstate_fromle32(&temp); + lfs_gstate_xor(gstate, &temp); + } + + return 0; +} + +static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, + uint16_t id, struct lfs_info *info) { + if (id == 0x3ff) { + // special case for root + strcpy(info->name, "/"); + info->type = LFS_TYPE_DIR; + return 0; + } + + lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name); + if (tag < 0) { + return (int)tag; + } + + info->type = lfs_tag_type3(tag); + + struct lfs_ctz ctz; + tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz); + if (tag < 0) { + return (int)tag; + } + lfs_ctz_fromle32(&ctz); + + if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) { + info->size = ctz.size; + } else if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) { + info->size = lfs_tag_size(tag); + } + + return 0; +} + +struct lfs_dir_find_match { + lfs_t *lfs; + const void *name; + lfs_size_t size; +}; + +static int lfs_dir_find_match(void *data, + lfs_tag_t tag, const void *buffer) { + struct lfs_dir_find_match *name = data; + lfs_t *lfs = name->lfs; + const struct lfs_diskoff *disk = buffer; + + // compare with disk + lfs_size_t diff = lfs_min(name->size, lfs_tag_size(tag)); + int res = lfs_bd_cmp(lfs, + NULL, &lfs->rcache, diff, + disk->block, disk->off, name->name, diff); + if (res != LFS_CMP_EQ) { + return res; + } + + // only equal if our size is still the same + if (name->size != lfs_tag_size(tag)) { + return (name->size < lfs_tag_size(tag)) ? LFS_CMP_LT : LFS_CMP_GT; + } + + // found a match! + return LFS_CMP_EQ; +} + +static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, + const char **path, uint16_t *id) { + // we reduce path to a single name if we can find it + const char *name = *path; + if (id) { + *id = 0x3ff; + } + + // default to root dir + lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0); + dir->tail[0] = lfs->root[0]; + dir->tail[1] = lfs->root[1]; + + while (true) { +nextname: + // skip slashes + name += strspn(name, "/"); + lfs_size_t namelen = strcspn(name, "/"); + + // skip '.' and root '..' + if ((namelen == 1 && memcmp(name, ".", 1) == 0) || + (namelen == 2 && memcmp(name, "..", 2) == 0)) { + name += namelen; + goto nextname; + } + + // skip if matched by '..' in name + const char *suffix = name + namelen; + lfs_size_t sufflen; + int depth = 1; + while (true) { + suffix += strspn(suffix, "/"); + sufflen = strcspn(suffix, "/"); + if (sufflen == 0) { + break; + } + + if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + depth -= 1; + if (depth == 0) { + name = suffix + sufflen; + goto nextname; + } + } else { + depth += 1; + } + + suffix += sufflen; + } + + // found path + if (name[0] == '\0') { + return tag; + } + + // update what we've found so far + *path = name; + + // only continue if we hit a directory + if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { + return LFS_ERR_NOTDIR; + } + + // grab the entry data + if (lfs_tag_id(tag) != 0x3ff) { + lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), dir->tail); + if (res < 0) { + return res; + } + lfs_pair_fromle32(dir->tail); + } + + // find entry matching name + while (true) { + tag = lfs_dir_fetchmatch(lfs, dir, dir->tail, + LFS_MKTAG(0x780, 0, 0), + LFS_MKTAG(LFS_TYPE_NAME, 0, namelen), + // are we last name? + (strchr(name, '/') == NULL) ? id : NULL, + lfs_dir_find_match, &(struct lfs_dir_find_match){ + lfs, name, namelen}); + if (tag < 0) { + return tag; + } + + if (tag) { + break; + } + + if (!dir->split) { + return LFS_ERR_NOENT; + } + } + + // to next name + name += namelen; + } +} + +// commit logic +struct lfs_commit { + lfs_block_t block; + lfs_off_t off; + lfs_tag_t ptag; + uint32_t crc; + + lfs_off_t begin; + lfs_off_t end; +}; + +static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit, + const void *buffer, lfs_size_t size) { + int err = lfs_bd_prog(lfs, + &lfs->pcache, &lfs->rcache, false, + commit->block, commit->off , + (const uint8_t*)buffer, size); + if (err) { + return err; + } + + commit->crc = lfs_crc(commit->crc, buffer, size); + commit->off += size; + return 0; +} + +static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, + lfs_tag_t tag, const void *buffer) { + // check if we fit + lfs_size_t dsize = lfs_tag_dsize(tag); + if (commit->off + dsize > commit->end) { + return LFS_ERR_NOSPC; + } + + // write out tag + lfs_tag_t ntag = lfs_tobe32((tag & 0x7fffffff) ^ commit->ptag); + int err = lfs_dir_commitprog(lfs, commit, &ntag, sizeof(ntag)); + if (err) { + return err; + } + + if (!(tag & 0x80000000)) { + // from memory + err = lfs_dir_commitprog(lfs, commit, buffer, dsize-sizeof(tag)); + if (err) { + return err; + } + } else { + // from disk + const struct lfs_diskoff *disk = buffer; + for (lfs_off_t i = 0; i < dsize-sizeof(tag); i++) { + // rely on caching to make this efficient + uint8_t dat; + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, dsize-sizeof(tag)-i, + disk->block, disk->off+i, &dat, 1); + if (err) { + return err; + } + + err = lfs_dir_commitprog(lfs, commit, &dat, 1); + if (err) { + return err; + } + } + } + + commit->ptag = tag & 0x7fffffff; + return 0; +} + +static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { + const lfs_off_t off1 = commit->off; + const uint32_t crc1 = commit->crc; + // align to program units + const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t), + lfs->cfg->prog_size); + + // create crc tags to fill up remainder of commit, note that + // padding is not crced, which lets fetches skip padding but + // makes committing a bit more complicated + while (commit->off < end) { + lfs_off_t off = commit->off + sizeof(lfs_tag_t); + lfs_off_t noff = lfs_min(end - off, 0x3fe) + off; + if (noff < end) { + noff = lfs_min(noff, end - 2*sizeof(uint32_t)); + } + + // read erased state from next program unit + lfs_tag_t tag = 0xffffffff; + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, sizeof(tag), + commit->block, noff, &tag, sizeof(tag)); + if (err && err != LFS_ERR_CORRUPT) { + return err; + } + + // build crc tag + bool reset = ~lfs_frombe32(tag) >> 31; + tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, noff - off); + + // write out crc + uint32_t footer[2]; + footer[0] = lfs_tobe32(tag ^ commit->ptag); + commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0])); + footer[1] = lfs_tole32(commit->crc); + err = lfs_bd_prog(lfs, + &lfs->pcache, &lfs->rcache, false, + commit->block, commit->off, &footer, sizeof(footer)); + if (err) { + return err; + } + + commit->off += sizeof(tag)+lfs_tag_size(tag); + commit->ptag = tag ^ ((lfs_tag_t)reset << 31); + commit->crc = 0xffffffff; // reset crc for next "commit" + } + + // flush buffers + int err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); + if (err) { + return err; + } + + // successful commit, check checksums to make sure + lfs_off_t off = commit->begin; + lfs_off_t noff = off1 + sizeof(uint32_t); + while (off < end) { + uint32_t crc = 0xffffffff; + for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { + // check against written crc, may catch blocks that + // become readonly and match our commit size exactly + if (i == off1 && crc != crc1) { + return LFS_ERR_CORRUPT; + } + + // leave it up to caching to make this efficient + uint8_t dat; + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, noff+sizeof(uint32_t)-i, + commit->block, i, &dat, 1); + if (err) { + return err; + } + + crc = lfs_crc(crc, &dat, 1); + } + + // detected write error? + if (crc != 0) { + return LFS_ERR_CORRUPT; + } + + // skip padding + off = lfs_min(end - noff, 0x3fe) + noff; + if (off < end) { + off = lfs_min(off, end - 2*sizeof(uint32_t)); + } + noff = off + sizeof(uint32_t); + } + + return 0; +} + +static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { + // allocate pair of dir blocks (backwards, so we write block 1 first) + for (int i = 0; i < 2; i++) { + int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]); + if (err) { + return err; + } + } + + // zero for reproducability in case initial block is unreadable + dir->rev = 0; + + // rather than clobbering one of the blocks we just pretend + // the revision may be valid + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, sizeof(dir->rev), + dir->pair[0], 0, &dir->rev, sizeof(dir->rev)); + dir->rev = lfs_fromle32(dir->rev); + if (err && err != LFS_ERR_CORRUPT) { + return err; + } + + // make sure we don't immediately evict + dir->rev += dir->rev & 1; + + // set defaults + dir->off = sizeof(dir->rev); + dir->etag = 0xffffffff; + dir->count = 0; + dir->tail[0] = LFS_BLOCK_NULL; + dir->tail[1] = LFS_BLOCK_NULL; + dir->erased = false; + dir->split = false; + + // don't write out yet, let caller take care of that + return 0; +} + +static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { + // steal state + int err = lfs_dir_getgstate(lfs, tail, &lfs->gdelta); + if (err) { + return err; + } + + // steal tail + lfs_pair_tole32(tail->tail); + err = lfs_dir_commit(lfs, dir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail})); + lfs_pair_fromle32(tail->tail); + if (err) { + return err; + } + + return 0; +} + +static int lfs_dir_split(lfs_t *lfs, + lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, + lfs_mdir_t *source, uint16_t split, uint16_t end) { + // create tail directory + lfs_alloc_ack(lfs); + lfs_mdir_t tail; + int err = lfs_dir_alloc(lfs, &tail); + if (err) { + return err; + } + + tail.split = dir->split; + tail.tail[0] = dir->tail[0]; + tail.tail[1] = dir->tail[1]; + + err = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end); + if (err) { + return err; + } + + dir->tail[0] = tail.pair[0]; + dir->tail[1] = tail.pair[1]; + dir->split = true; + + // update root if needed + if (lfs_pair_cmp(dir->pair, lfs->root) == 0 && split == 0) { + lfs->root[0] = tail.pair[0]; + lfs->root[1] = tail.pair[1]; + } + + return 0; +} + +static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) { + lfs_size_t *size = p; + (void)buffer; + + *size += lfs_tag_dsize(tag); + return 0; +} + +struct lfs_dir_commit_commit { + lfs_t *lfs; + struct lfs_commit *commit; +}; + +static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) { + struct lfs_dir_commit_commit *commit = p; + return lfs_dir_commitattr(commit->lfs, commit->commit, tag, buffer); +} + +static int lfs_dir_compact(lfs_t *lfs, + lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, + lfs_mdir_t *source, uint16_t begin, uint16_t end) { + // save some state in case block is bad + const lfs_block_t oldpair[2] = {dir->pair[0], dir->pair[1]}; + bool relocated = false; + bool tired = false; + + // should we split? + while (end - begin > 1) { + // find size + lfs_size_t size = 0; + int err = lfs_dir_traverse(lfs, + source, 0, 0xffffffff, attrs, attrcount, + LFS_MKTAG(0x400, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_NAME, 0, 0), + begin, end, -begin, + lfs_dir_commit_size, &size); + if (err) { + return err; + } + + // space is complicated, we need room for tail, crc, gstate, + // cleanup delete, and we cap at half a block to give room + // for metadata updates. + if (end - begin < 0xff && + size <= lfs_min(lfs->cfg->block_size - 36, + lfs_alignup(lfs->cfg->block_size/2, + lfs->cfg->prog_size))) { + break; + } + + // can't fit, need to split, we should really be finding the + // largest size that fits with a small binary search, but right now + // it's not worth the code size + uint16_t split = (end - begin) / 2; + err = lfs_dir_split(lfs, dir, attrs, attrcount, + source, begin+split, end); + if (err) { + // if we fail to split, we may be able to overcompact, unless + // we're too big for even the full block, in which case our + // only option is to error + if (err == LFS_ERR_NOSPC && size <= lfs->cfg->block_size - 36) { + break; + } + return err; + } + + end = begin + split; + } + + // increment revision count + dir->rev += 1; + // If our revision count == n * block_cycles, we should force a relocation, + // this is how littlefs wear-levels at the metadata-pair level. Note that we + // actually use (block_cycles+1)|1, this is to avoid two corner cases: + // 1. block_cycles = 1, which would prevent relocations from terminating + // 2. block_cycles = 2n, which, due to aliasing, would only ever relocate + // one metadata block in the pair, effectively making this useless + if (lfs->cfg->block_cycles > 0 && + (dir->rev % ((lfs->cfg->block_cycles+1)|1) == 0)) { + if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { + // oh no! we're writing too much to the superblock, + // should we expand? + lfs_ssize_t res = lfs_fs_size(lfs); + if (res < 0) { + return res; + } + + // do we have extra space? littlefs can't reclaim this space + // by itself, so expand cautiously + if ((lfs_size_t)res < lfs->cfg->block_count/2) { + LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); + int err = lfs_dir_split(lfs, dir, attrs, attrcount, + source, begin, end); + if (err && err != LFS_ERR_NOSPC) { + return err; + } + + // welp, we tried, if we ran out of space there's not much + // we can do, we'll error later if we've become frozen + if (!err) { + end = begin; + } + } +#ifdef LFS_MIGRATE + } else if (lfs->lfs1) { + // do not proactively relocate blocks during migrations, this + // can cause a number of failure states such: clobbering the + // v1 superblock if we relocate root, and invalidating directory + // pointers if we relocate the head of a directory. On top of + // this, relocations increase the overall complexity of + // lfs_migration, which is already a delicate operation. +#endif + } else { + // we're writing too much, time to relocate + tired = true; + goto relocate; + } + } + + // begin loop to commit compaction to blocks until a compact sticks + while (true) { + { + // setup commit state + struct lfs_commit commit = { + .block = dir->pair[1], + .off = 0, + .ptag = 0xffffffff, + .crc = 0xffffffff, + + .begin = 0, + .end = lfs->cfg->block_size - 8, + }; + + // erase block to write to + int err = lfs_bd_erase(lfs, dir->pair[1]); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // write out header + dir->rev = lfs_tole32(dir->rev); + err = lfs_dir_commitprog(lfs, &commit, + &dir->rev, sizeof(dir->rev)); + dir->rev = lfs_fromle32(dir->rev); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // traverse the directory, this time writing out all unique tags + err = lfs_dir_traverse(lfs, + source, 0, 0xffffffff, attrs, attrcount, + LFS_MKTAG(0x400, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_NAME, 0, 0), + begin, end, -begin, + lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){ + lfs, &commit}); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // commit tail, which may be new after last size check + if (!lfs_pair_isnull(dir->tail)) { + lfs_pair_tole32(dir->tail); + err = lfs_dir_commitattr(lfs, &commit, + LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8), + dir->tail); + lfs_pair_fromle32(dir->tail); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // bring over gstate? + lfs_gstate_t delta = {0}; + if (!relocated) { + lfs_gstate_xor(&delta, &lfs->gdisk); + lfs_gstate_xor(&delta, &lfs->gstate); + } + lfs_gstate_xor(&delta, &lfs->gdelta); + delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff); + + err = lfs_dir_getgstate(lfs, dir, &delta); + if (err) { + return err; + } + + if (!lfs_gstate_iszero(&delta)) { + lfs_gstate_tole32(&delta); + err = lfs_dir_commitattr(lfs, &commit, + LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff, + sizeof(delta)), &delta); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // complete commit with crc + err = lfs_dir_commitcrc(lfs, &commit); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // successful compaction, swap dir pair to indicate most recent + LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); + lfs_pair_swap(dir->pair); + dir->count = end - begin; + dir->off = commit.off; + dir->etag = commit.ptag; + // update gstate + lfs->gdelta = (lfs_gstate_t){0}; + if (!relocated) { + lfs->gdisk = lfs->gstate; + } + } + break; + +relocate: + // commit was corrupted, drop caches and prepare to relocate block + relocated = true; + lfs_cache_drop(lfs, &lfs->pcache); + if (!tired) { + LFS_DEBUG("Bad block at 0x%"PRIx32, dir->pair[1]); + } + + // can't relocate superblock, filesystem is now frozen + if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { + LFS_WARN("Superblock 0x%"PRIx32" has become unwritable", + dir->pair[1]); + return LFS_ERR_NOSPC; + } + + // relocate half of pair + int err = lfs_alloc(lfs, &dir->pair[1]); + if (err && (err != LFS_ERR_NOSPC || !tired)) { + return err; + } + + tired = false; + continue; + } + + if (relocated) { + // update references if we relocated + LFS_DEBUG("Relocating {0x%"PRIx32", 0x%"PRIx32"} " + "-> {0x%"PRIx32", 0x%"PRIx32"}", + oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); + int err = lfs_fs_relocate(lfs, oldpair, dir->pair); + if (err) { + return err; + } + } + + return 0; +} + +static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, + const struct lfs_mattr *attrs, int attrcount) { + // check for any inline files that aren't RAM backed and + // forcefully evict them, needed for filesystem consistency + for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { + if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && + f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && + f->ctz.size > lfs->cfg->cache_size) { + int err = lfs_file_outline(lfs, f); + if (err) { + return err; + } + + err = lfs_file_flush(lfs, f); + if (err) { + return err; + } + } + } + + // calculate changes to the directory + lfs_mdir_t olddir = *dir; + bool hasdelete = false; + for (int i = 0; i < attrcount; i++) { + if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE) { + dir->count += 1; + } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE) { + LFS_ASSERT(dir->count > 0); + dir->count -= 1; + hasdelete = true; + } else if (lfs_tag_type1(attrs[i].tag) == LFS_TYPE_TAIL) { + dir->tail[0] = ((lfs_block_t*)attrs[i].buffer)[0]; + dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1]; + dir->split = (lfs_tag_chunk(attrs[i].tag) & 1); + lfs_pair_fromle32(dir->tail); + } + } + + // should we actually drop the directory block? + if (hasdelete && dir->count == 0) { + lfs_mdir_t pdir; + int err = lfs_fs_pred(lfs, dir->pair, &pdir); + if (err && err != LFS_ERR_NOENT) { + *dir = olddir; + return err; + } + + if (err != LFS_ERR_NOENT && pdir.split) { + err = lfs_dir_drop(lfs, &pdir, dir); + if (err) { + *dir = olddir; + return err; + } + } + } + + if (dir->erased || dir->count >= 0xff) { + // try to commit + struct lfs_commit commit = { + .block = dir->pair[0], + .off = dir->off, + .ptag = dir->etag, + .crc = 0xffffffff, + + .begin = dir->off, + .end = lfs->cfg->block_size - 8, + }; + + // traverse attrs that need to be written out + lfs_pair_tole32(dir->tail); + int err = lfs_dir_traverse(lfs, + dir, dir->off, dir->etag, attrs, attrcount, + 0, 0, 0, 0, 0, + lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){ + lfs, &commit}); + lfs_pair_fromle32(dir->tail); + if (err) { + if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { + goto compact; + } + *dir = olddir; + return err; + } + + // commit any global diffs if we have any + lfs_gstate_t delta = {0}; + lfs_gstate_xor(&delta, &lfs->gstate); + lfs_gstate_xor(&delta, &lfs->gdisk); + lfs_gstate_xor(&delta, &lfs->gdelta); + delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff); + if (!lfs_gstate_iszero(&delta)) { + err = lfs_dir_getgstate(lfs, dir, &delta); + if (err) { + *dir = olddir; + return err; + } + + lfs_gstate_tole32(&delta); + err = lfs_dir_commitattr(lfs, &commit, + LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff, + sizeof(delta)), &delta); + if (err) { + if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { + goto compact; + } + *dir = olddir; + return err; + } + } + + // finalize commit with the crc + err = lfs_dir_commitcrc(lfs, &commit); + if (err) { + if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { + goto compact; + } + *dir = olddir; + return err; + } + + // successful commit, update dir + LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); + dir->off = commit.off; + dir->etag = commit.ptag; + // and update gstate + lfs->gdisk = lfs->gstate; + lfs->gdelta = (lfs_gstate_t){0}; + } else { +compact: + // fall back to compaction + lfs_cache_drop(lfs, &lfs->pcache); + + int err = lfs_dir_compact(lfs, dir, attrs, attrcount, + dir, 0, dir->count); + if (err) { + *dir = olddir; + return err; + } + } + + // this complicated bit of logic is for fixing up any active + // metadata-pairs that we may have affected + // + // note we have to make two passes since the mdir passed to + // lfs_dir_commit could also be in this list, and even then + // we need to copy the pair so they don't get clobbered if we refetch + // our mdir. + for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { + if (&d->m != dir && lfs_pair_cmp(d->m.pair, olddir.pair) == 0) { + d->m = *dir; + for (int i = 0; i < attrcount; i++) { + if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE && + d->id == lfs_tag_id(attrs[i].tag)) { + d->m.pair[0] = LFS_BLOCK_NULL; + d->m.pair[1] = LFS_BLOCK_NULL; + } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE && + d->id > lfs_tag_id(attrs[i].tag)) { + d->id -= 1; + if (d->type == LFS_TYPE_DIR) { + ((lfs_dir_t*)d)->pos -= 1; + } + } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE && + d->id >= lfs_tag_id(attrs[i].tag)) { + d->id += 1; + if (d->type == LFS_TYPE_DIR) { + ((lfs_dir_t*)d)->pos += 1; + } + } + } + } + } + + for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { + if (lfs_pair_cmp(d->m.pair, olddir.pair) == 0) { + while (d->id >= d->m.count && d->m.split) { + // we split and id is on tail now + d->id -= d->m.count; + int err = lfs_dir_fetch(lfs, &d->m, d->m.tail); + if (err) { + return err; + } + } + } + } + + return 0; +} + + +/// Top level directory operations /// +int lfs_mkdir(lfs_t *lfs, const char *path) { + LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); + // deorphan if we haven't yet, needed at most once after poweron + int err = lfs_fs_forceconsistency(lfs); + if (err) { + LFS_TRACE("lfs_mkdir -> %d", err); + return err; + } + + struct lfs_mlist cwd; + cwd.next = lfs->mlist; + uint16_t id; + err = lfs_dir_find(lfs, &cwd.m, &path, &id); + if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { + LFS_TRACE("lfs_mkdir -> %d", (err < 0) ? err : LFS_ERR_EXIST); + return (err < 0) ? err : LFS_ERR_EXIST; + } + + // check that name fits + lfs_size_t nlen = strlen(path); + if (nlen > lfs->name_max) { + LFS_TRACE("lfs_mkdir -> %d", LFS_ERR_NAMETOOLONG); + return LFS_ERR_NAMETOOLONG; + } + + // build up new directory + lfs_alloc_ack(lfs); + lfs_mdir_t dir; + err = lfs_dir_alloc(lfs, &dir); + if (err) { + LFS_TRACE("lfs_mkdir -> %d", err); + return err; + } + + // find end of list + lfs_mdir_t pred = cwd.m; + while (pred.split) { + err = lfs_dir_fetch(lfs, &pred, pred.tail); + if (err) { + LFS_TRACE("lfs_mkdir -> %d", err); + return err; + } + } + + // setup dir + lfs_pair_tole32(pred.tail); + err = lfs_dir_commit(lfs, &dir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); + lfs_pair_fromle32(pred.tail); + if (err) { + LFS_TRACE("lfs_mkdir -> %d", err); + return err; + } + + // current block end of list? + if (cwd.m.split) { + // update tails, this creates a desync + lfs_fs_preporphans(lfs, +1); + + // it's possible our predecessor has to be relocated, and if + // our parent is our predecessor's predecessor, this could have + // caused our parent to go out of date, fortunately we can hook + // ourselves into littlefs to catch this + cwd.type = 0; + cwd.id = 0; + lfs->mlist = &cwd; + + lfs_pair_tole32(dir.pair); + err = lfs_dir_commit(lfs, &pred, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); + lfs_pair_fromle32(dir.pair); + if (err) { + lfs->mlist = cwd.next; + LFS_TRACE("lfs_mkdir -> %d", err); + return err; + } + + lfs->mlist = cwd.next; + lfs_fs_preporphans(lfs, -1); + } + + // now insert into our parent block + lfs_pair_tole32(dir.pair); + err = lfs_dir_commit(lfs, &cwd.m, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL}, + {LFS_MKTAG(LFS_TYPE_DIR, id, nlen), path}, + {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, id, 8), dir.pair}, + {LFS_MKTAG_IF(!cwd.m.split, + LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); + lfs_pair_fromle32(dir.pair); + if (err) { + LFS_TRACE("lfs_mkdir -> %d", err); + return err; + } + + LFS_TRACE("lfs_mkdir -> %d", 0); + return 0; +} + +int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { + LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); + lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL); + if (tag < 0) { + LFS_TRACE("lfs_dir_open -> %"PRId32, tag); + return tag; + } + + if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { + LFS_TRACE("lfs_dir_open -> %d", LFS_ERR_NOTDIR); + return LFS_ERR_NOTDIR; + } + + lfs_block_t pair[2]; + if (lfs_tag_id(tag) == 0x3ff) { + // handle root dir separately + pair[0] = lfs->root[0]; + pair[1] = lfs->root[1]; + } else { + // get dir pair from parent + lfs_stag_t res = lfs_dir_get(lfs, &dir->m, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); + if (res < 0) { + LFS_TRACE("lfs_dir_open -> %"PRId32, res); + return res; + } + lfs_pair_fromle32(pair); + } + + // fetch first pair + int err = lfs_dir_fetch(lfs, &dir->m, pair); + if (err) { + LFS_TRACE("lfs_dir_open -> %d", err); + return err; + } + + // setup entry + dir->head[0] = dir->m.pair[0]; + dir->head[1] = dir->m.pair[1]; + dir->id = 0; + dir->pos = 0; + + // add to list of mdirs + dir->type = LFS_TYPE_DIR; + dir->next = (lfs_dir_t*)lfs->mlist; + lfs->mlist = (struct lfs_mlist*)dir; + + LFS_TRACE("lfs_dir_open -> %d", 0); + return 0; +} + +int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { + LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); + // remove from list of mdirs + for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { + if (*p == (struct lfs_mlist*)dir) { + *p = (*p)->next; + break; + } + } + + LFS_TRACE("lfs_dir_close -> %d", 0); + return 0; +} + +int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { + LFS_TRACE("lfs_dir_read(%p, %p, %p)", + (void*)lfs, (void*)dir, (void*)info); + memset(info, 0, sizeof(*info)); + + // special offset for '.' and '..' + if (dir->pos == 0) { + info->type = LFS_TYPE_DIR; + strcpy(info->name, "."); + dir->pos += 1; + LFS_TRACE("lfs_dir_read -> %d", true); + return true; + } else if (dir->pos == 1) { + info->type = LFS_TYPE_DIR; + strcpy(info->name, ".."); + dir->pos += 1; + LFS_TRACE("lfs_dir_read -> %d", true); + return true; + } + + while (true) { + if (dir->id == dir->m.count) { + if (!dir->m.split) { + LFS_TRACE("lfs_dir_read -> %d", false); + return false; + } + + int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); + if (err) { + LFS_TRACE("lfs_dir_read -> %d", err); + return err; + } + + dir->id = 0; + } + + int err = lfs_dir_getinfo(lfs, &dir->m, dir->id, info); + if (err && err != LFS_ERR_NOENT) { + LFS_TRACE("lfs_dir_read -> %d", err); + return err; + } + + dir->id += 1; + if (err != LFS_ERR_NOENT) { + break; + } + } + + dir->pos += 1; + LFS_TRACE("lfs_dir_read -> %d", true); + return true; +} + +int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { + LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", + (void*)lfs, (void*)dir, off); + // simply walk from head dir + int err = lfs_dir_rewind(lfs, dir); + if (err) { + LFS_TRACE("lfs_dir_seek -> %d", err); + return err; + } + + // first two for ./.. + dir->pos = lfs_min(2, off); + off -= dir->pos; + + // skip superblock entry + dir->id = (off > 0 && lfs_pair_cmp(dir->head, lfs->root) == 0); + + while (off > 0) { + int diff = lfs_min(dir->m.count - dir->id, off); + dir->id += diff; + dir->pos += diff; + off -= diff; + + if (dir->id == dir->m.count) { + if (!dir->m.split) { + LFS_TRACE("lfs_dir_seek -> %d", LFS_ERR_INVAL); + return LFS_ERR_INVAL; + } + + err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); + if (err) { + LFS_TRACE("lfs_dir_seek -> %d", err); + return err; + } + + dir->id = 0; + } + } + + LFS_TRACE("lfs_dir_seek -> %d", 0); + return 0; +} + +lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { + LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); + (void)lfs; + LFS_TRACE("lfs_dir_tell -> %"PRId32, dir->pos); + return dir->pos; +} + +int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { + LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); + // reload the head dir + int err = lfs_dir_fetch(lfs, &dir->m, dir->head); + if (err) { + LFS_TRACE("lfs_dir_rewind -> %d", err); + return err; + } + + dir->id = 0; + dir->pos = 0; + LFS_TRACE("lfs_dir_rewind -> %d", 0); + return 0; +} + + +/// File index list operations /// +static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) { + lfs_off_t size = *off; + lfs_off_t b = lfs->cfg->block_size - 2*4; + lfs_off_t i = size / b; + if (i == 0) { + return 0; + } + + i = (size - 4*(lfs_popc(i-1)+2)) / b; + *off = size - b*i - 4*lfs_popc(i); + return i; +} + +static int lfs_ctz_find(lfs_t *lfs, + const lfs_cache_t *pcache, lfs_cache_t *rcache, + lfs_block_t head, lfs_size_t size, + lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) { + if (size == 0) { + *block = LFS_BLOCK_NULL; + *off = 0; + return 0; + } + + lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); + lfs_off_t target = lfs_ctz_index(lfs, &pos); + + while (current > target) { + lfs_size_t skip = lfs_min( + lfs_npw2(current-target+1) - 1, + lfs_ctz(current)); + + int err = lfs_bd_read(lfs, + pcache, rcache, sizeof(head), + head, 4*skip, &head, sizeof(head)); + head = lfs_fromle32(head); + if (err) { + return err; + } + + current -= 1 << skip; + } + + *block = head; + *off = pos; + return 0; +} + +static int lfs_ctz_extend(lfs_t *lfs, + lfs_cache_t *pcache, lfs_cache_t *rcache, + lfs_block_t head, lfs_size_t size, + lfs_block_t *block, lfs_off_t *off) { + while (true) { + // go ahead and grab a block + lfs_block_t nblock; + int err = lfs_alloc(lfs, &nblock); + if (err) { + return err; + } + + { + err = lfs_bd_erase(lfs, nblock); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (size == 0) { + *block = nblock; + *off = 0; + return 0; + } + + lfs_size_t noff = size - 1; + lfs_off_t index = lfs_ctz_index(lfs, &noff); + noff = noff + 1; + + // just copy out the last block if it is incomplete + if (noff != lfs->cfg->block_size) { + for (lfs_off_t i = 0; i < noff; i++) { + uint8_t data; + err = lfs_bd_read(lfs, + NULL, rcache, noff-i, + head, i, &data, 1); + if (err) { + return err; + } + + err = lfs_bd_prog(lfs, + pcache, rcache, true, + nblock, i, &data, 1); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + *block = nblock; + *off = noff; + return 0; + } + + // append block + index += 1; + lfs_size_t skips = lfs_ctz(index) + 1; + lfs_block_t nhead = head; + for (lfs_off_t i = 0; i < skips; i++) { + nhead = lfs_tole32(nhead); + err = lfs_bd_prog(lfs, pcache, rcache, true, + nblock, 4*i, &nhead, 4); + nhead = lfs_fromle32(nhead); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + if (i != skips-1) { + err = lfs_bd_read(lfs, + NULL, rcache, sizeof(nhead), + nhead, 4*i, &nhead, sizeof(nhead)); + nhead = lfs_fromle32(nhead); + if (err) { + return err; + } + } + } + + *block = nblock; + *off = 4*skips; + return 0; + } + +relocate: + LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); + + // just clear cache and try a new block + lfs_cache_drop(lfs, pcache); + } +} + +static int lfs_ctz_traverse(lfs_t *lfs, + const lfs_cache_t *pcache, lfs_cache_t *rcache, + lfs_block_t head, lfs_size_t size, + int (*cb)(void*, lfs_block_t), void *data) { + if (size == 0) { + return 0; + } + + lfs_off_t index = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); + + while (true) { + int err = cb(data, head); + if (err) { + return err; + } + + if (index == 0) { + return 0; + } + + lfs_block_t heads[2]; + int count = 2 - (index & 1); + err = lfs_bd_read(lfs, + pcache, rcache, count*sizeof(head), + head, 0, &heads, count*sizeof(head)); + heads[0] = lfs_fromle32(heads[0]); + heads[1] = lfs_fromle32(heads[1]); + if (err) { + return err; + } + + for (int i = 0; i < count-1; i++) { + err = cb(data, heads[i]); + if (err) { + return err; + } + } + + head = heads[count-1]; + index -= count; + } +} + + +/// Top level file operations /// +int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, + const char *path, int flags, + const struct lfs_file_config *cfg) { + LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" + ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", + (void*)lfs, (void*)file, path, flags, + (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); + + // deorphan if we haven't yet, needed at most once after poweron + if ((flags & 3) != LFS_O_RDONLY) { + int err = lfs_fs_forceconsistency(lfs); + if (err) { + LFS_TRACE("lfs_file_opencfg -> %d", err); + return err; + } + } + + // setup simple file details + int err; + file->cfg = cfg; + file->flags = flags | LFS_F_OPENED; + file->pos = 0; + file->off = 0; + file->cache.buffer = NULL; + + // allocate entry for file if it doesn't exist + lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id); + if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) { + err = tag; + goto cleanup; + } + + // get id, add to list of mdirs to catch update changes + file->type = LFS_TYPE_REG; + file->next = (lfs_file_t*)lfs->mlist; + lfs->mlist = (struct lfs_mlist*)file; + + if (tag == LFS_ERR_NOENT) { + if (!(flags & LFS_O_CREAT)) { + err = LFS_ERR_NOENT; + goto cleanup; + } + + // check that name fits + lfs_size_t nlen = strlen(path); + if (nlen > lfs->name_max) { + err = LFS_ERR_NAMETOOLONG; + goto cleanup; + } + + // get next slot and create entry to remember name + err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL}, + {LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path}, + {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL})); + if (err) { + err = LFS_ERR_NAMETOOLONG; + goto cleanup; + } + + tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0); + } else if (flags & LFS_O_EXCL) { + err = LFS_ERR_EXIST; + goto cleanup; + } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) { + err = LFS_ERR_ISDIR; + goto cleanup; + } else if (flags & LFS_O_TRUNC) { + // truncate if requested + tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0); + file->flags |= LFS_F_DIRTY; + } else { + // try to load what's on disk, if it's inlined we'll fix it later + tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz); + if (tag < 0) { + err = tag; + goto cleanup; + } + lfs_ctz_fromle32(&file->ctz); + } + + // fetch attrs + for (unsigned i = 0; i < file->cfg->attr_count; i++) { + if ((file->flags & 3) != LFS_O_WRONLY) { + lfs_stag_t res = lfs_dir_get(lfs, &file->m, + LFS_MKTAG(0x7ff, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, + file->id, file->cfg->attrs[i].size), + file->cfg->attrs[i].buffer); + if (res < 0 && res != LFS_ERR_NOENT) { + err = res; + goto cleanup; + } + } + + if ((file->flags & 3) != LFS_O_RDONLY) { + if (file->cfg->attrs[i].size > lfs->attr_max) { + err = LFS_ERR_NOSPC; + goto cleanup; + } + + file->flags |= LFS_F_DIRTY; + } + } + + // allocate buffer if needed + if (file->cfg->buffer) { + file->cache.buffer = file->cfg->buffer; + } else { + file->cache.buffer = lfs_malloc(lfs->cfg->cache_size); + if (!file->cache.buffer) { + err = LFS_ERR_NOMEM; + goto cleanup; + } + } + + // zero to avoid information leak + lfs_cache_zero(lfs, &file->cache); + + if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) { + // load inline files + file->ctz.head = LFS_BLOCK_INLINE; + file->ctz.size = lfs_tag_size(tag); + file->flags |= LFS_F_INLINE; + file->cache.block = file->ctz.head; + file->cache.off = 0; + file->cache.size = lfs->cfg->cache_size; + + // don't always read (may be new/trunc file) + if (file->ctz.size > 0) { + lfs_stag_t res = lfs_dir_get(lfs, &file->m, + LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, file->id, + lfs_min(file->cache.size, 0x3fe)), + file->cache.buffer); + if (res < 0) { + err = res; + goto cleanup; + } + } + } + + LFS_TRACE("lfs_file_opencfg -> %d", 0); + return 0; + +cleanup: + // clean up lingering resources + file->flags |= LFS_F_ERRED; + lfs_file_close(lfs, file); + LFS_TRACE("lfs_file_opencfg -> %d", err); + return err; +} + +int lfs_file_open(lfs_t *lfs, lfs_file_t *file, + const char *path, int flags) { + LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", + (void*)lfs, (void*)file, path, flags); + static const struct lfs_file_config defaults = {0}; + int err = lfs_file_opencfg(lfs, file, path, flags, &defaults); + LFS_TRACE("lfs_file_open -> %d", err); + return err; +} + +int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { + LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(file->flags & LFS_F_OPENED); + + int err = lfs_file_sync(lfs, file); + + // remove from list of mdirs + for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { + if (*p == (struct lfs_mlist*)file) { + *p = (*p)->next; + break; + } + } + + // clean up memory + if (!file->cfg->buffer) { + lfs_free(file->cache.buffer); + } + + file->flags &= ~LFS_F_OPENED; + LFS_TRACE("lfs_file_close -> %d", err); + return err; +} + +static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { + LFS_ASSERT(file->flags & LFS_F_OPENED); + + while (true) { + // just relocate what exists into new block + lfs_block_t nblock; + int err = lfs_alloc(lfs, &nblock); + if (err) { + return err; + } + + err = lfs_bd_erase(lfs, nblock); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + // either read from dirty cache or disk + for (lfs_off_t i = 0; i < file->off; i++) { + uint8_t data; + if (file->flags & LFS_F_INLINE) { + err = lfs_dir_getread(lfs, &file->m, + // note we evict inline files before they can be dirty + NULL, &file->cache, file->off-i, + LFS_MKTAG(0xfff, 0x1ff, 0), + LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), + i, &data, 1); + if (err) { + return err; + } + } else { + err = lfs_bd_read(lfs, + &file->cache, &lfs->rcache, file->off-i, + file->block, i, &data, 1); + if (err) { + return err; + } + } + + err = lfs_bd_prog(lfs, + &lfs->pcache, &lfs->rcache, true, + nblock, i, &data, 1); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + } + + // copy over new state of file + memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->cache_size); + file->cache.block = lfs->pcache.block; + file->cache.off = lfs->pcache.off; + file->cache.size = lfs->pcache.size; + lfs_cache_zero(lfs, &lfs->pcache); + + file->block = nblock; + file->flags |= LFS_F_WRITING; + return 0; + +relocate: + LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); + + // just clear cache and try a new block + lfs_cache_drop(lfs, &lfs->pcache); + } +} + +static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { + file->off = file->pos; + lfs_alloc_ack(lfs); + int err = lfs_file_relocate(lfs, file); + if (err) { + return err; + } + + file->flags &= ~LFS_F_INLINE; + return 0; +} + +static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { + LFS_ASSERT(file->flags & LFS_F_OPENED); + + if (file->flags & LFS_F_READING) { + if (!(file->flags & LFS_F_INLINE)) { + lfs_cache_drop(lfs, &file->cache); + } + file->flags &= ~LFS_F_READING; + } + + if (file->flags & LFS_F_WRITING) { + lfs_off_t pos = file->pos; + + if (!(file->flags & LFS_F_INLINE)) { + // copy over anything after current branch + lfs_file_t orig = { + .ctz.head = file->ctz.head, + .ctz.size = file->ctz.size, + .flags = LFS_O_RDONLY | LFS_F_OPENED, + .pos = file->pos, + .cache = lfs->rcache, + }; + lfs_cache_drop(lfs, &lfs->rcache); + + while (file->pos < file->ctz.size) { + // copy over a byte at a time, leave it up to caching + // to make this efficient + uint8_t data; + lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); + if (res < 0) { + return res; + } + + res = lfs_file_write(lfs, file, &data, 1); + if (res < 0) { + return res; + } + + // keep our reference to the rcache in sync + if (lfs->rcache.block != LFS_BLOCK_NULL) { + lfs_cache_drop(lfs, &orig.cache); + lfs_cache_drop(lfs, &lfs->rcache); + } + } + + // write out what we have + while (true) { + int err = lfs_bd_flush(lfs, &file->cache, &lfs->rcache, true); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + return err; + } + + break; + +relocate: + LFS_DEBUG("Bad block at 0x%"PRIx32, file->block); + err = lfs_file_relocate(lfs, file); + if (err) { + return err; + } + } + } else { + file->pos = lfs_max(file->pos, file->ctz.size); + } + + // actual file updates + file->ctz.head = file->block; + file->ctz.size = file->pos; + file->flags &= ~LFS_F_WRITING; + file->flags |= LFS_F_DIRTY; + + file->pos = pos; + } + + return 0; +} + +int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { + LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(file->flags & LFS_F_OPENED); + + if (file->flags & LFS_F_ERRED) { + // it's not safe to do anything if our file errored + LFS_TRACE("lfs_file_sync -> %d", 0); + return 0; + } + + int err = lfs_file_flush(lfs, file); + if (err) { + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_sync -> %d", err); + return err; + } + + if ((file->flags & LFS_F_DIRTY) && + !lfs_pair_isnull(file->m.pair)) { + // update dir entry + uint16_t type; + const void *buffer; + lfs_size_t size; + struct lfs_ctz ctz; + if (file->flags & LFS_F_INLINE) { + // inline the whole file + type = LFS_TYPE_INLINESTRUCT; + buffer = file->cache.buffer; + size = file->ctz.size; + } else { + // update the ctz reference + type = LFS_TYPE_CTZSTRUCT; + // copy ctz so alloc will work during a relocate + ctz = file->ctz; + lfs_ctz_tole32(&ctz); + buffer = &ctz; + size = sizeof(ctz); + } + + // commit file data and attributes + err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( + {LFS_MKTAG(type, file->id, size), buffer}, + {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, + file->cfg->attr_count), file->cfg->attrs})); + if (err) { + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_sync -> %d", err); + return err; + } + + file->flags &= ~LFS_F_DIRTY; + } + + LFS_TRACE("lfs_file_sync -> %d", 0); + return 0; +} + +lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size) { + LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", + (void*)lfs, (void*)file, buffer, size); + LFS_ASSERT(file->flags & LFS_F_OPENED); + LFS_ASSERT((file->flags & 3) != LFS_O_WRONLY); + + uint8_t *data = buffer; + lfs_size_t nsize = size; + + if (file->flags & LFS_F_WRITING) { + // flush out any writes + int err = lfs_file_flush(lfs, file); + if (err) { + LFS_TRACE("lfs_file_read -> %d", err); + return err; + } + } + + if (file->pos >= file->ctz.size) { + // eof if past end + LFS_TRACE("lfs_file_read -> %d", 0); + return 0; + } + + size = lfs_min(size, file->ctz.size - file->pos); + nsize = size; + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS_F_READING) || + file->off == lfs->cfg->block_size) { + if (!(file->flags & LFS_F_INLINE)) { + int err = lfs_ctz_find(lfs, NULL, &file->cache, + file->ctz.head, file->ctz.size, + file->pos, &file->block, &file->off); + if (err) { + LFS_TRACE("lfs_file_read -> %d", err); + return err; + } + } else { + file->block = LFS_BLOCK_INLINE; + file->off = file->pos; + } + + file->flags |= LFS_F_READING; + } + + // read as much as we can in current block + lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); + if (file->flags & LFS_F_INLINE) { + int err = lfs_dir_getread(lfs, &file->m, + NULL, &file->cache, lfs->cfg->block_size, + LFS_MKTAG(0xfff, 0x1ff, 0), + LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), + file->off, data, diff); + if (err) { + LFS_TRACE("lfs_file_read -> %d", err); + return err; + } + } else { + int err = lfs_bd_read(lfs, + NULL, &file->cache, lfs->cfg->block_size, + file->block, file->off, data, diff); + if (err) { + LFS_TRACE("lfs_file_read -> %d", err); + return err; + } + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + } + + LFS_TRACE("lfs_file_read -> %"PRId32, size); + return size; +} + +lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size) { + LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", + (void*)lfs, (void*)file, buffer, size); + LFS_ASSERT(file->flags & LFS_F_OPENED); + LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); + + const uint8_t *data = buffer; + lfs_size_t nsize = size; + + if (file->flags & LFS_F_READING) { + // drop any reads + int err = lfs_file_flush(lfs, file); + if (err) { + LFS_TRACE("lfs_file_write -> %d", err); + return err; + } + } + + if ((file->flags & LFS_O_APPEND) && file->pos < file->ctz.size) { + file->pos = file->ctz.size; + } + + if (file->pos + size > lfs->file_max) { + // Larger than file limit? + LFS_TRACE("lfs_file_write -> %d", LFS_ERR_FBIG); + return LFS_ERR_FBIG; + } + + if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) { + // fill with zeros + lfs_off_t pos = file->pos; + file->pos = file->ctz.size; + + while (file->pos < pos) { + lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + if (res < 0) { + LFS_TRACE("lfs_file_write -> %"PRId32, res); + return res; + } + } + } + + if ((file->flags & LFS_F_INLINE) && + lfs_max(file->pos+nsize, file->ctz.size) > + lfs_min(0x3fe, lfs_min( + lfs->cfg->cache_size, lfs->cfg->block_size/8))) { + // inline file doesn't fit anymore + int err = lfs_file_outline(lfs, file); + if (err) { + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_write -> %d", err); + return err; + } + } + + while (nsize > 0) { + // check if we need a new block + if (!(file->flags & LFS_F_WRITING) || + file->off == lfs->cfg->block_size) { + if (!(file->flags & LFS_F_INLINE)) { + if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { + // find out which block we're extending from + int err = lfs_ctz_find(lfs, NULL, &file->cache, + file->ctz.head, file->ctz.size, + file->pos-1, &file->block, &file->off); + if (err) { + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_write -> %d", err); + return err; + } + + // mark cache as dirty since we may have read data into it + lfs_cache_zero(lfs, &file->cache); + } + + // extend file with new blocks + lfs_alloc_ack(lfs); + int err = lfs_ctz_extend(lfs, &file->cache, &lfs->rcache, + file->block, file->pos, + &file->block, &file->off); + if (err) { + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_write -> %d", err); + return err; + } + } else { + file->block = LFS_BLOCK_INLINE; + file->off = file->pos; + } + + file->flags |= LFS_F_WRITING; + } + + // program as much as we can in current block + lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); + while (true) { + int err = lfs_bd_prog(lfs, &file->cache, &lfs->rcache, true, + file->block, file->off, data, diff); + if (err) { + if (err == LFS_ERR_CORRUPT) { + goto relocate; + } + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_write -> %d", err); + return err; + } + + break; +relocate: + err = lfs_file_relocate(lfs, file); + if (err) { + file->flags |= LFS_F_ERRED; + LFS_TRACE("lfs_file_write -> %d", err); + return err; + } + } + + file->pos += diff; + file->off += diff; + data += diff; + nsize -= diff; + + lfs_alloc_ack(lfs); + } + + file->flags &= ~LFS_F_ERRED; + LFS_TRACE("lfs_file_write -> %"PRId32, size); + return size; +} + +lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, + lfs_soff_t off, int whence) { + LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", + (void*)lfs, (void*)file, off, whence); + LFS_ASSERT(file->flags & LFS_F_OPENED); + + // write out everything beforehand, may be noop if rdonly + int err = lfs_file_flush(lfs, file); + if (err) { + LFS_TRACE("lfs_file_seek -> %d", err); + return err; + } + + // find new pos + lfs_off_t npos = file->pos; + if (whence == LFS_SEEK_SET) { + npos = off; + } else if (whence == LFS_SEEK_CUR) { + npos = file->pos + off; + } else if (whence == LFS_SEEK_END) { + npos = file->ctz.size + off; + } + + if (npos > lfs->file_max) { + // file position out of range + LFS_TRACE("lfs_file_seek -> %d", LFS_ERR_INVAL); + return LFS_ERR_INVAL; + } + + // update pos + file->pos = npos; + LFS_TRACE("lfs_file_seek -> %"PRId32, npos); + return npos; +} + +int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { + LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", + (void*)lfs, (void*)file, size); + LFS_ASSERT(file->flags & LFS_F_OPENED); + LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); + + if (size > LFS_FILE_MAX) { + LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_INVAL); + return LFS_ERR_INVAL; + } + + lfs_off_t pos = file->pos; + lfs_off_t oldsize = lfs_file_size(lfs, file); + if (size < oldsize) { + // need to flush since directly changing metadata + int err = lfs_file_flush(lfs, file); + if (err) { + LFS_TRACE("lfs_file_truncate -> %d", err); + return err; + } + + // lookup new head in ctz skip list + err = lfs_ctz_find(lfs, NULL, &file->cache, + file->ctz.head, file->ctz.size, + size, &file->block, &file->off); + if (err) { + LFS_TRACE("lfs_file_truncate -> %d", err); + return err; + } + + file->ctz.head = file->block; + file->ctz.size = size; + file->flags |= LFS_F_DIRTY | LFS_F_READING; + } else if (size > oldsize) { + // flush+seek if not already at end + if (file->pos != oldsize) { + lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); + if (res < 0) { + LFS_TRACE("lfs_file_truncate -> %"PRId32, res); + return (int)res; + } + } + + // fill with zeros + while (file->pos < size) { + lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + if (res < 0) { + LFS_TRACE("lfs_file_truncate -> %"PRId32, res); + return (int)res; + } + } + } + + // restore pos + lfs_soff_t res = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); + if (res < 0) { + LFS_TRACE("lfs_file_truncate -> %"PRId32, res); + return (int)res; + } + + LFS_TRACE("lfs_file_truncate -> %d", 0); + return 0; +} + +lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { + LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(file->flags & LFS_F_OPENED); + (void)lfs; + LFS_TRACE("lfs_file_tell -> %"PRId32, file->pos); + return file->pos; +} + +int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { + LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); + lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET); + if (res < 0) { + LFS_TRACE("lfs_file_rewind -> %"PRId32, res); + return (int)res; + } + + LFS_TRACE("lfs_file_rewind -> %d", 0); + return 0; +} + +lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { + LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(file->flags & LFS_F_OPENED); + (void)lfs; + if (file->flags & LFS_F_WRITING) { + LFS_TRACE("lfs_file_size -> %"PRId32, + lfs_max(file->pos, file->ctz.size)); + return lfs_max(file->pos, file->ctz.size); + } else { + LFS_TRACE("lfs_file_size -> %"PRId32, file->ctz.size); + return file->ctz.size; + } +} + + +/// General fs operations /// +int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { + LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); + lfs_mdir_t cwd; + lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); + if (tag < 0) { + LFS_TRACE("lfs_stat -> %"PRId32, tag); + return (int)tag; + } + + int err = lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); + LFS_TRACE("lfs_stat -> %d", err); + return err; +} + +int lfs_remove(lfs_t *lfs, const char *path) { + LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); + // deorphan if we haven't yet, needed at most once after poweron + int err = lfs_fs_forceconsistency(lfs); + if (err) { + LFS_TRACE("lfs_remove -> %d", err); + return err; + } + + lfs_mdir_t cwd; + lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); + if (tag < 0 || lfs_tag_id(tag) == 0x3ff) { + LFS_TRACE("lfs_remove -> %"PRId32, (tag < 0) ? tag : LFS_ERR_INVAL); + return (tag < 0) ? (int)tag : LFS_ERR_INVAL; + } + + struct lfs_mlist dir; + dir.next = lfs->mlist; + if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { + // must be empty before removal + lfs_block_t pair[2]; + lfs_stag_t res = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); + if (res < 0) { + LFS_TRACE("lfs_remove -> %"PRId32, res); + return (int)res; + } + lfs_pair_fromle32(pair); + + err = lfs_dir_fetch(lfs, &dir.m, pair); + if (err) { + LFS_TRACE("lfs_remove -> %d", err); + return err; + } + + if (dir.m.count > 0 || dir.m.split) { + LFS_TRACE("lfs_remove -> %d", LFS_ERR_NOTEMPTY); + return LFS_ERR_NOTEMPTY; + } + + // mark fs as orphaned + lfs_fs_preporphans(lfs, +1); + + // I know it's crazy but yes, dir can be changed by our parent's + // commit (if predecessor is child) + dir.type = 0; + dir.id = 0; + lfs->mlist = &dir; + } + + // delete the entry + err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0), NULL})); + if (err) { + lfs->mlist = dir.next; + LFS_TRACE("lfs_remove -> %d", err); + return err; + } + + lfs->mlist = dir.next; + if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { + // fix orphan + lfs_fs_preporphans(lfs, -1); + + err = lfs_fs_pred(lfs, dir.m.pair, &cwd); + if (err) { + LFS_TRACE("lfs_remove -> %d", err); + return err; + } + + err = lfs_dir_drop(lfs, &cwd, &dir.m); + if (err) { + LFS_TRACE("lfs_remove -> %d", err); + return err; + } + } + + LFS_TRACE("lfs_remove -> %d", 0); + return 0; +} + +int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { + LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); + + // deorphan if we haven't yet, needed at most once after poweron + int err = lfs_fs_forceconsistency(lfs); + if (err) { + LFS_TRACE("lfs_rename -> %d", err); + return err; + } + + // find old entry + lfs_mdir_t oldcwd; + lfs_stag_t oldtag = lfs_dir_find(lfs, &oldcwd, &oldpath, NULL); + if (oldtag < 0 || lfs_tag_id(oldtag) == 0x3ff) { + LFS_TRACE("lfs_rename -> %"PRId32, + (oldtag < 0) ? oldtag : LFS_ERR_INVAL); + return (oldtag < 0) ? (int)oldtag : LFS_ERR_INVAL; + } + + // find new entry + lfs_mdir_t newcwd; + uint16_t newid; + lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid); + if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) && + !(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) { + LFS_TRACE("lfs_rename -> %"PRId32, + (prevtag < 0) ? prevtag : LFS_ERR_INVAL); + return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL; + } + + // if we're in the same pair there's a few special cases... + bool samepair = (lfs_pair_cmp(oldcwd.pair, newcwd.pair) == 0); + uint16_t newoldid = lfs_tag_id(oldtag); + + struct lfs_mlist prevdir; + prevdir.next = lfs->mlist; + if (prevtag == LFS_ERR_NOENT) { + // check that name fits + lfs_size_t nlen = strlen(newpath); + if (nlen > lfs->name_max) { + LFS_TRACE("lfs_rename -> %d", LFS_ERR_NAMETOOLONG); + return LFS_ERR_NAMETOOLONG; + } + + // there is a small chance we are being renamed in the same + // directory/ to an id less than our old id, the global update + // to handle this is a bit messy + if (samepair && newid <= newoldid) { + newoldid += 1; + } + } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) { + LFS_TRACE("lfs_rename -> %d", LFS_ERR_ISDIR); + return LFS_ERR_ISDIR; + } else if (samepair && newid == newoldid) { + // we're renaming to ourselves?? + LFS_TRACE("lfs_rename -> %d", 0); + return 0; + } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { + // must be empty before removal + lfs_block_t prevpair[2]; + lfs_stag_t res = lfs_dir_get(lfs, &newcwd, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair); + if (res < 0) { + LFS_TRACE("lfs_rename -> %"PRId32, res); + return (int)res; + } + lfs_pair_fromle32(prevpair); + + // must be empty before removal + err = lfs_dir_fetch(lfs, &prevdir.m, prevpair); + if (err) { + LFS_TRACE("lfs_rename -> %d", err); + return err; + } + + if (prevdir.m.count > 0 || prevdir.m.split) { + LFS_TRACE("lfs_rename -> %d", LFS_ERR_NOTEMPTY); + return LFS_ERR_NOTEMPTY; + } + + // mark fs as orphaned + lfs_fs_preporphans(lfs, +1); + + // I know it's crazy but yes, dir can be changed by our parent's + // commit (if predecessor is child) + prevdir.type = 0; + prevdir.id = 0; + lfs->mlist = &prevdir; + } + + if (!samepair) { + lfs_fs_prepmove(lfs, newoldid, oldcwd.pair); + } + + // move over all attributes + err = lfs_dir_commit(lfs, &newcwd, LFS_MKATTRS( + {LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT, + LFS_TYPE_DELETE, newid, 0), NULL}, + {LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL}, + {LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)), newpath}, + {LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd}, + {LFS_MKTAG_IF(samepair, + LFS_TYPE_DELETE, newoldid, 0), NULL})); + if (err) { + lfs->mlist = prevdir.next; + LFS_TRACE("lfs_rename -> %d", err); + return err; + } + + // let commit clean up after move (if we're different! otherwise move + // logic already fixed it for us) + if (!samepair && lfs_gstate_hasmove(&lfs->gstate)) { + // prep gstate and delete move id + lfs_fs_prepmove(lfs, 0x3ff, NULL); + err = lfs_dir_commit(lfs, &oldcwd, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(oldtag), 0), NULL})); + if (err) { + lfs->mlist = prevdir.next; + LFS_TRACE("lfs_rename -> %d", err); + return err; + } + } + + lfs->mlist = prevdir.next; + if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { + // fix orphan + lfs_fs_preporphans(lfs, -1); + + err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd); + if (err) { + LFS_TRACE("lfs_rename -> %d", err); + return err; + } + + err = lfs_dir_drop(lfs, &newcwd, &prevdir.m); + if (err) { + LFS_TRACE("lfs_rename -> %d", err); + return err; + } + } + + LFS_TRACE("lfs_rename -> %d", 0); + return 0; +} + +lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, + uint8_t type, void *buffer, lfs_size_t size) { + LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs, path, type, buffer, size); + lfs_mdir_t cwd; + lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); + if (tag < 0) { + LFS_TRACE("lfs_getattr -> %"PRId32, tag); + return tag; + } + + uint16_t id = lfs_tag_id(tag); + if (id == 0x3ff) { + // special case for root + id = 0; + int err = lfs_dir_fetch(lfs, &cwd, lfs->root); + if (err) { + LFS_TRACE("lfs_getattr -> %d", err); + return err; + } + } + + tag = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x7ff, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_USERATTR + type, + id, lfs_min(size, lfs->attr_max)), + buffer); + if (tag < 0) { + if (tag == LFS_ERR_NOENT) { + LFS_TRACE("lfs_getattr -> %d", LFS_ERR_NOATTR); + return LFS_ERR_NOATTR; + } + + LFS_TRACE("lfs_getattr -> %"PRId32, tag); + return tag; + } + + size = lfs_tag_size(tag); + LFS_TRACE("lfs_getattr -> %"PRId32, size); + return size; +} + +static int lfs_commitattr(lfs_t *lfs, const char *path, + uint8_t type, const void *buffer, lfs_size_t size) { + lfs_mdir_t cwd; + lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); + if (tag < 0) { + return tag; + } + + uint16_t id = lfs_tag_id(tag); + if (id == 0x3ff) { + // special case for root + id = 0; + int err = lfs_dir_fetch(lfs, &cwd, lfs->root); + if (err) { + return err; + } + } + + return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); +} + +int lfs_setattr(lfs_t *lfs, const char *path, + uint8_t type, const void *buffer, lfs_size_t size) { + LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs, path, type, buffer, size); + if (size > lfs->attr_max) { + LFS_TRACE("lfs_setattr -> %d", LFS_ERR_NOSPC); + return LFS_ERR_NOSPC; + } + + int err = lfs_commitattr(lfs, path, type, buffer, size); + LFS_TRACE("lfs_setattr -> %d", err); + return err; +} + +int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { + LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); + int err = lfs_commitattr(lfs, path, type, NULL, 0x3ff); + LFS_TRACE("lfs_removeattr -> %d", err); + return err; +} + + +/// Filesystem operations /// +static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { + lfs->cfg = cfg; + int err = 0; + + // validate that the lfs-cfg sizes were initiated properly before + // performing any arithmetic logics with them + LFS_ASSERT(lfs->cfg->read_size != 0); + LFS_ASSERT(lfs->cfg->prog_size != 0); + LFS_ASSERT(lfs->cfg->cache_size != 0); + + // check that block size is a multiple of cache size is a multiple + // of prog and read sizes + LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0); + LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0); + LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0); + + // check that the block size is large enough to fit ctz pointers + LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) + <= lfs->cfg->block_size); + + // block_cycles = 0 is no longer supported. + // + // block_cycles is the number of erase cycles before littlefs evicts + // metadata logs as a part of wear leveling. Suggested values are in the + // range of 100-1000, or set block_cycles to -1 to disable block-level + // wear-leveling. + LFS_ASSERT(lfs->cfg->block_cycles != 0); + + + // setup read cache + if (lfs->cfg->read_buffer) { + lfs->rcache.buffer = lfs->cfg->read_buffer; + } else { + lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size); + if (!lfs->rcache.buffer) { + err = LFS_ERR_NOMEM; + goto cleanup; + } + } + + // setup program cache + if (lfs->cfg->prog_buffer) { + lfs->pcache.buffer = lfs->cfg->prog_buffer; + } else { + lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size); + if (!lfs->pcache.buffer) { + err = LFS_ERR_NOMEM; + goto cleanup; + } + } + + // zero to avoid information leaks + lfs_cache_zero(lfs, &lfs->rcache); + lfs_cache_zero(lfs, &lfs->pcache); + + // setup lookahead, must be multiple of 64-bits, 32-bit aligned + LFS_ASSERT(lfs->cfg->lookahead_size > 0); + LFS_ASSERT(lfs->cfg->lookahead_size % 8 == 0 && + (uintptr_t)lfs->cfg->lookahead_buffer % 4 == 0); + if (lfs->cfg->lookahead_buffer) { + lfs->free.buffer = lfs->cfg->lookahead_buffer; + } else { + lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead_size); + if (!lfs->free.buffer) { + err = LFS_ERR_NOMEM; + goto cleanup; + } + } + + // check that the size limits are sane + LFS_ASSERT(lfs->cfg->name_max <= LFS_NAME_MAX); + lfs->name_max = lfs->cfg->name_max; + if (!lfs->name_max) { + lfs->name_max = LFS_NAME_MAX; + } + + LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX); + lfs->file_max = lfs->cfg->file_max; + if (!lfs->file_max) { + lfs->file_max = LFS_FILE_MAX; + } + + LFS_ASSERT(lfs->cfg->attr_max <= LFS_ATTR_MAX); + lfs->attr_max = lfs->cfg->attr_max; + if (!lfs->attr_max) { + lfs->attr_max = LFS_ATTR_MAX; + } + + // setup default state + lfs->root[0] = LFS_BLOCK_NULL; + lfs->root[1] = LFS_BLOCK_NULL; + lfs->mlist = NULL; + lfs->seed = 0; + lfs->gdisk = (lfs_gstate_t){0}; + lfs->gstate = (lfs_gstate_t){0}; + lfs->gdelta = (lfs_gstate_t){0}; +#ifdef LFS_MIGRATE + lfs->lfs1 = NULL; +#endif + + return 0; + +cleanup: + lfs_deinit(lfs); + return err; +} + +static int lfs_deinit(lfs_t *lfs) { + // free allocated memory + if (!lfs->cfg->read_buffer) { + lfs_free(lfs->rcache.buffer); + } + + if (!lfs->cfg->prog_buffer) { + lfs_free(lfs->pcache.buffer); + } + + if (!lfs->cfg->lookahead_buffer) { + lfs_free(lfs->free.buffer); + } + + return 0; +} + +int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { + LFS_TRACE("lfs_format(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + int err = 0; + { + err = lfs_init(lfs, cfg); + if (err) { + LFS_TRACE("lfs_format -> %d", err); + return err; + } + + // create free lookahead + memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); + lfs->free.off = 0; + lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, + lfs->cfg->block_count); + lfs->free.i = 0; + lfs_alloc_ack(lfs); + + // create root dir + lfs_mdir_t root; + err = lfs_dir_alloc(lfs, &root); + if (err) { + goto cleanup; + } + + // write one superblock + lfs_superblock_t superblock = { + .version = LFS_DISK_VERSION, + .block_size = lfs->cfg->block_size, + .block_count = lfs->cfg->block_count, + .name_max = lfs->name_max, + .file_max = lfs->file_max, + .attr_max = lfs->attr_max, + }; + + lfs_superblock_tole32(&superblock); + err = lfs_dir_commit(lfs, &root, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL}, + {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, + {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})); + if (err) { + goto cleanup; + } + + // sanity check that fetch works + err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + // force compaction to prevent accidentally mounting any + // older version of littlefs that may live on disk + root.erased = false; + err = lfs_dir_commit(lfs, &root, NULL, 0); + if (err) { + goto cleanup; + } + } + +cleanup: + lfs_deinit(lfs); + LFS_TRACE("lfs_format -> %d", err); + return err; +} + +int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { + LFS_TRACE("lfs_mount(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + int err = lfs_init(lfs, cfg); + if (err) { + LFS_TRACE("lfs_mount -> %d", err); + return err; + } + + // scan directory blocks for superblock and any global updates + lfs_mdir_t dir = {.tail = {0, 1}}; + lfs_block_t cycle = 0; + while (!lfs_pair_isnull(dir.tail)) { + if (cycle >= lfs->cfg->block_count/2) { + // loop detected + err = LFS_ERR_CORRUPT; + goto cleanup; + } + cycle += 1; + + // fetch next block in tail list + lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, + LFS_MKTAG(0x7ff, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), + NULL, + lfs_dir_find_match, &(struct lfs_dir_find_match){ + lfs, "littlefs", 8}); + if (tag < 0) { + err = tag; + goto cleanup; + } + + // has superblock? + if (tag && !lfs_tag_isdelete(tag)) { + // update root + lfs->root[0] = dir.pair[0]; + lfs->root[1] = dir.pair[1]; + + // grab superblock + lfs_superblock_t superblock; + tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock); + if (tag < 0) { + err = tag; + goto cleanup; + } + lfs_superblock_fromle32(&superblock); + + // check version + uint16_t major_version = (0xffff & (superblock.version >> 16)); + uint16_t minor_version = (0xffff & (superblock.version >> 0)); + if ((major_version != LFS_DISK_VERSION_MAJOR || + minor_version > LFS_DISK_VERSION_MINOR)) { + LFS_ERROR("Invalid version v%"PRIu16".%"PRIu16, + major_version, minor_version); + err = LFS_ERR_INVAL; + goto cleanup; + } + + // check superblock configuration + if (superblock.name_max) { + if (superblock.name_max > lfs->name_max) { + LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", + superblock.name_max, lfs->name_max); + err = LFS_ERR_INVAL; + goto cleanup; + } + + lfs->name_max = superblock.name_max; + } + + if (superblock.file_max) { + if (superblock.file_max > lfs->file_max) { + LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")", + superblock.file_max, lfs->file_max); + err = LFS_ERR_INVAL; + goto cleanup; + } + + lfs->file_max = superblock.file_max; + } + + if (superblock.attr_max) { + if (superblock.attr_max > lfs->attr_max) { + LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", + superblock.attr_max, lfs->attr_max); + err = LFS_ERR_INVAL; + goto cleanup; + } + + lfs->attr_max = superblock.attr_max; + } + } + + // has gstate? + err = lfs_dir_getgstate(lfs, &dir, &lfs->gstate); + if (err) { + goto cleanup; + } + } + + // found superblock? + if (lfs_pair_isnull(lfs->root)) { + err = LFS_ERR_INVAL; + goto cleanup; + } + + // update littlefs with gstate + if (!lfs_gstate_iszero(&lfs->gstate)) { + LFS_DEBUG("Found pending gstate 0x%08"PRIx32"%08"PRIx32"%08"PRIx32, + lfs->gstate.tag, + lfs->gstate.pair[0], + lfs->gstate.pair[1]); + } + lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); + lfs->gdisk = lfs->gstate; + + // setup free lookahead + lfs_alloc_reset(lfs); + + LFS_TRACE("lfs_mount -> %d", 0); + return 0; + +cleanup: + lfs_unmount(lfs); + LFS_TRACE("lfs_mount -> %d", err); + return err; +} + +int lfs_unmount(lfs_t *lfs) { + LFS_TRACE("lfs_unmount(%p)", (void*)lfs); + int err = lfs_deinit(lfs); + LFS_TRACE("lfs_unmount -> %d", err); + return err; +} + + +/// Filesystem filesystem operations /// +int lfs_fs_traverseraw(lfs_t *lfs, + int (*cb)(void *data, lfs_block_t block), void *data, + bool includeorphans) { + // iterate over metadata pairs + lfs_mdir_t dir = {.tail = {0, 1}}; + +#ifdef LFS_MIGRATE + // also consider v1 blocks during migration + if (lfs->lfs1) { + int err = lfs1_traverse(lfs, cb, data); + if (err) { + return err; + } + + dir.tail[0] = lfs->root[0]; + dir.tail[1] = lfs->root[1]; + } +#endif + + lfs_block_t cycle = 0; + while (!lfs_pair_isnull(dir.tail)) { + if (cycle >= lfs->cfg->block_count/2) { + // loop detected + return LFS_ERR_CORRUPT; + } + cycle += 1; + + for (int i = 0; i < 2; i++) { + int err = cb(data, dir.tail[i]); + if (err) { + return err; + } + } + + // iterate through ids in directory + int err = lfs_dir_fetch(lfs, &dir, dir.tail); + if (err) { + return err; + } + + for (uint16_t id = 0; id < dir.count; id++) { + struct lfs_ctz ctz; + lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x700, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz); + if (tag < 0) { + if (tag == LFS_ERR_NOENT) { + continue; + } + return tag; + } + lfs_ctz_fromle32(&ctz); + + if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) { + err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache, + ctz.head, ctz.size, cb, data); + if (err) { + return err; + } + } else if (includeorphans && + lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) { + for (int i = 0; i < 2; i++) { + err = cb(data, (&ctz.head)[i]); + if (err) { + return err; + } + } + } + } + } + + // iterate over any open files + for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { + if (f->type != LFS_TYPE_REG) { + continue; + } + + if ((f->flags & LFS_F_DIRTY) && !(f->flags & LFS_F_INLINE)) { + int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache, + f->ctz.head, f->ctz.size, cb, data); + if (err) { + return err; + } + } + + if ((f->flags & LFS_F_WRITING) && !(f->flags & LFS_F_INLINE)) { + int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache, + f->block, f->pos, cb, data); + if (err) { + return err; + } + } + } + + return 0; +} + +int lfs_fs_traverse(lfs_t *lfs, + int (*cb)(void *data, lfs_block_t block), void *data) { + LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", + (void*)lfs, (void*)(uintptr_t)cb, data); + int err = lfs_fs_traverseraw(lfs, cb, data, true); + LFS_TRACE("lfs_fs_traverse -> %d", 0); + return err; +} + +static int lfs_fs_pred(lfs_t *lfs, + const lfs_block_t pair[2], lfs_mdir_t *pdir) { + // iterate over all directory directory entries + pdir->tail[0] = 0; + pdir->tail[1] = 1; + lfs_block_t cycle = 0; + while (!lfs_pair_isnull(pdir->tail)) { + if (cycle >= lfs->cfg->block_count/2) { + // loop detected + return LFS_ERR_CORRUPT; + } + cycle += 1; + + if (lfs_pair_cmp(pdir->tail, pair) == 0) { + return 0; + } + + int err = lfs_dir_fetch(lfs, pdir, pdir->tail); + if (err) { + return err; + } + } + + return LFS_ERR_NOENT; +} + +struct lfs_fs_parent_match { + lfs_t *lfs; + const lfs_block_t pair[2]; +}; + +static int lfs_fs_parent_match(void *data, + lfs_tag_t tag, const void *buffer) { + struct lfs_fs_parent_match *find = data; + lfs_t *lfs = find->lfs; + const struct lfs_diskoff *disk = buffer; + (void)tag; + + lfs_block_t child[2]; + int err = lfs_bd_read(lfs, + &lfs->pcache, &lfs->rcache, lfs->cfg->block_size, + disk->block, disk->off, &child, sizeof(child)); + if (err) { + return err; + } + + lfs_pair_fromle32(child); + return (lfs_pair_cmp(child, find->pair) == 0) ? LFS_CMP_EQ : LFS_CMP_LT; +} + +static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], + lfs_mdir_t *parent) { + // use fetchmatch with callback to find pairs + parent->tail[0] = 0; + parent->tail[1] = 1; + lfs_block_t cycle = 0; + while (!lfs_pair_isnull(parent->tail)) { + if (cycle >= lfs->cfg->block_count/2) { + // loop detected + return LFS_ERR_CORRUPT; + } + cycle += 1; + + lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail, + LFS_MKTAG(0x7ff, 0, 0x3ff), + LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8), + NULL, + lfs_fs_parent_match, &(struct lfs_fs_parent_match){ + lfs, {pair[0], pair[1]}}); + if (tag && tag != LFS_ERR_NOENT) { + return tag; + } + } + + return LFS_ERR_NOENT; +} + +static int lfs_fs_relocate(lfs_t *lfs, + const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { + // update internal root + if (lfs_pair_cmp(oldpair, lfs->root) == 0) { + lfs->root[0] = newpair[0]; + lfs->root[1] = newpair[1]; + } + + // update internally tracked dirs + for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { + if (lfs_pair_cmp(oldpair, d->m.pair) == 0) { + d->m.pair[0] = newpair[0]; + d->m.pair[1] = newpair[1]; + } + + if (d->type == LFS_TYPE_DIR && + lfs_pair_cmp(oldpair, ((lfs_dir_t*)d)->head) == 0) { + ((lfs_dir_t*)d)->head[0] = newpair[0]; + ((lfs_dir_t*)d)->head[1] = newpair[1]; + } + } + + // find parent + lfs_mdir_t parent; + lfs_stag_t tag = lfs_fs_parent(lfs, oldpair, &parent); + if (tag < 0 && tag != LFS_ERR_NOENT) { + return tag; + } + + if (tag != LFS_ERR_NOENT) { + // update disk, this creates a desync + lfs_fs_preporphans(lfs, +1); + + // fix pending move in this pair? this looks like an optimization but + // is in fact _required_ since relocating may outdate the move. + uint16_t moveid = 0x3ff; + if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { + moveid = lfs_tag_id(lfs->gstate.tag); + LFS_DEBUG("Fixing move while relocating " + "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", + parent.pair[0], parent.pair[1], moveid); + lfs_fs_prepmove(lfs, 0x3ff, NULL); + if (moveid < lfs_tag_id(tag)) { + tag -= LFS_MKTAG(0, 1, 0); + } + } + + lfs_pair_tole32(newpair); + int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( + {LFS_MKTAG_IF(moveid != 0x3ff, + LFS_TYPE_DELETE, moveid, 0), NULL}, + {tag, newpair})); + lfs_pair_fromle32(newpair); + if (err) { + return err; + } + + // next step, clean up orphans + lfs_fs_preporphans(lfs, -1); + } + + // find pred + int err = lfs_fs_pred(lfs, oldpair, &parent); + if (err && err != LFS_ERR_NOENT) { + return err; + } + + // if we can't find dir, it must be new + if (err != LFS_ERR_NOENT) { + // fix pending move in this pair? this looks like an optimization but + // is in fact _required_ since relocating may outdate the move. + uint16_t moveid = 0x3ff; + if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { + moveid = lfs_tag_id(lfs->gstate.tag); + LFS_DEBUG("Fixing move while relocating " + "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", + parent.pair[0], parent.pair[1], moveid); + lfs_fs_prepmove(lfs, 0x3ff, NULL); + } + + // replace bad pair, either we clean up desync, or no desync occured + lfs_pair_tole32(newpair); + err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( + {LFS_MKTAG_IF(moveid != 0x3ff, + LFS_TYPE_DELETE, moveid, 0), NULL}, + {LFS_MKTAG(LFS_TYPE_TAIL + parent.split, 0x3ff, 8), newpair})); + lfs_pair_fromle32(newpair); + if (err) { + return err; + } + } + + return 0; +} + +static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) { + LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0); + lfs->gstate.tag += orphans; + lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) | + ((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31)); +} + +static void lfs_fs_prepmove(lfs_t *lfs, + uint16_t id, const lfs_block_t pair[2]) { + lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x7ff, 0x3ff, 0)) | + ((id != 0x3ff) ? LFS_MKTAG(LFS_TYPE_DELETE, id, 0) : 0)); + lfs->gstate.pair[0] = (id != 0x3ff) ? pair[0] : 0; + lfs->gstate.pair[1] = (id != 0x3ff) ? pair[1] : 0; +} + +static int lfs_fs_demove(lfs_t *lfs) { + if (!lfs_gstate_hasmove(&lfs->gdisk)) { + return 0; + } + + // Fix bad moves + LFS_DEBUG("Fixing move {0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16, + lfs->gdisk.pair[0], + lfs->gdisk.pair[1], + lfs_tag_id(lfs->gdisk.tag)); + + // fetch and delete the moved entry + lfs_mdir_t movedir; + int err = lfs_dir_fetch(lfs, &movedir, lfs->gdisk.pair); + if (err) { + return err; + } + + // prep gstate and delete move id + uint16_t moveid = lfs_tag_id(lfs->gdisk.tag); + lfs_fs_prepmove(lfs, 0x3ff, NULL); + err = lfs_dir_commit(lfs, &movedir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_DELETE, moveid, 0), NULL})); + if (err) { + return err; + } + + return 0; +} + +static int lfs_fs_deorphan(lfs_t *lfs) { + if (!lfs_gstate_hasorphans(&lfs->gstate)) { + return 0; + } + + // Fix any orphans + lfs_mdir_t pdir = {.split = true, .tail = {0, 1}}; + lfs_mdir_t dir; + + // iterate over all directory directory entries + while (!lfs_pair_isnull(pdir.tail)) { + int err = lfs_dir_fetch(lfs, &dir, pdir.tail); + if (err) { + return err; + } + + // check head blocks for orphans + if (!pdir.split) { + // check if we have a parent + lfs_mdir_t parent; + lfs_stag_t tag = lfs_fs_parent(lfs, pdir.tail, &parent); + if (tag < 0 && tag != LFS_ERR_NOENT) { + return tag; + } + + if (tag == LFS_ERR_NOENT) { + // we are an orphan + LFS_DEBUG("Fixing orphan {0x%"PRIx32", 0x%"PRIx32"}", + pdir.tail[0], pdir.tail[1]); + + err = lfs_dir_drop(lfs, &pdir, &dir); + if (err) { + return err; + } + + // refetch tail + continue; + } + + lfs_block_t pair[2]; + lfs_stag_t res = lfs_dir_get(lfs, &parent, + LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair); + if (res < 0) { + return res; + } + lfs_pair_fromle32(pair); + + if (!lfs_pair_sync(pair, pdir.tail)) { + // we have desynced + LFS_DEBUG("Fixing half-orphan {0x%"PRIx32", 0x%"PRIx32"} " + "-> {0x%"PRIx32", 0x%"PRIx32"}", + pdir.tail[0], pdir.tail[1], pair[0], pair[1]); + + lfs_pair_tole32(pair); + err = lfs_dir_commit(lfs, &pdir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pair})); + lfs_pair_fromle32(pair); + if (err) { + return err; + } + + // refetch tail + continue; + } + } + + pdir = dir; + } + + // mark orphans as fixed + lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate)); + return 0; +} + +static int lfs_fs_forceconsistency(lfs_t *lfs) { + int err = lfs_fs_demove(lfs); + if (err) { + return err; + } + + err = lfs_fs_deorphan(lfs); + if (err) { + return err; + } + + return 0; +} + +static int lfs_fs_size_count(void *p, lfs_block_t block) { + (void)block; + lfs_size_t *size = p; + *size += 1; + return 0; +} + +lfs_ssize_t lfs_fs_size(lfs_t *lfs) { + LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); + lfs_size_t size = 0; + int err = lfs_fs_traverseraw(lfs, lfs_fs_size_count, &size, false); + if (err) { + LFS_TRACE("lfs_fs_size -> %d", err); + return err; + } + + LFS_TRACE("lfs_fs_size -> %d", err); + return size; +} + +#ifdef LFS_MIGRATE +////// Migration from littelfs v1 below this ////// + +/// Version info /// + +// Software library version +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS1_VERSION 0x00010007 +#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16)) +#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0)) + +// Version of On-disk data structures +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS1_DISK_VERSION 0x00010001 +#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16)) +#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0)) + + +/// v1 Definitions /// + +// File types +enum lfs1_type { + LFS1_TYPE_REG = 0x11, + LFS1_TYPE_DIR = 0x22, + LFS1_TYPE_SUPERBLOCK = 0x2e, +}; + +typedef struct lfs1 { + lfs_block_t root[2]; +} lfs1_t; + +typedef struct lfs1_entry { + lfs_off_t off; + + struct lfs1_disk_entry { + uint8_t type; + uint8_t elen; + uint8_t alen; + uint8_t nlen; + union { + struct { + lfs_block_t head; + lfs_size_t size; + } file; + lfs_block_t dir[2]; + } u; + } d; +} lfs1_entry_t; + +typedef struct lfs1_dir { + struct lfs1_dir *next; + lfs_block_t pair[2]; + lfs_off_t off; + + lfs_block_t head[2]; + lfs_off_t pos; + + struct lfs1_disk_dir { + uint32_t rev; + lfs_size_t size; + lfs_block_t tail[2]; + } d; +} lfs1_dir_t; + +typedef struct lfs1_superblock { + lfs_off_t off; + + struct lfs1_disk_superblock { + uint8_t type; + uint8_t elen; + uint8_t alen; + uint8_t nlen; + lfs_block_t root[2]; + uint32_t block_size; + uint32_t block_count; + uint32_t version; + char magic[8]; + } d; +} lfs1_superblock_t; + + +/// Low-level wrappers v1->v2 /// +static void lfs1_crc(uint32_t *crc, const void *buffer, size_t size) { + *crc = lfs_crc(*crc, buffer, size); +} + +static int lfs1_bd_read(lfs_t *lfs, lfs_block_t block, + lfs_off_t off, void *buffer, lfs_size_t size) { + // if we ever do more than writes to alternating pairs, + // this may need to consider pcache + return lfs_bd_read(lfs, &lfs->pcache, &lfs->rcache, size, + block, off, buffer, size); +} + +static int lfs1_bd_crc(lfs_t *lfs, lfs_block_t block, + lfs_off_t off, lfs_size_t size, uint32_t *crc) { + for (lfs_off_t i = 0; i < size; i++) { + uint8_t c; + int err = lfs1_bd_read(lfs, block, off+i, &c, 1); + if (err) { + return err; + } + + lfs1_crc(crc, &c, 1); + } + + return 0; +} + + +/// Endian swapping functions /// +static void lfs1_dir_fromle32(struct lfs1_disk_dir *d) { + d->rev = lfs_fromle32(d->rev); + d->size = lfs_fromle32(d->size); + d->tail[0] = lfs_fromle32(d->tail[0]); + d->tail[1] = lfs_fromle32(d->tail[1]); +} + +static void lfs1_dir_tole32(struct lfs1_disk_dir *d) { + d->rev = lfs_tole32(d->rev); + d->size = lfs_tole32(d->size); + d->tail[0] = lfs_tole32(d->tail[0]); + d->tail[1] = lfs_tole32(d->tail[1]); +} + +static void lfs1_entry_fromle32(struct lfs1_disk_entry *d) { + d->u.dir[0] = lfs_fromle32(d->u.dir[0]); + d->u.dir[1] = lfs_fromle32(d->u.dir[1]); +} + +static void lfs1_entry_tole32(struct lfs1_disk_entry *d) { + d->u.dir[0] = lfs_tole32(d->u.dir[0]); + d->u.dir[1] = lfs_tole32(d->u.dir[1]); +} + +static void lfs1_superblock_fromle32(struct lfs1_disk_superblock *d) { + d->root[0] = lfs_fromle32(d->root[0]); + d->root[1] = lfs_fromle32(d->root[1]); + d->block_size = lfs_fromle32(d->block_size); + d->block_count = lfs_fromle32(d->block_count); + d->version = lfs_fromle32(d->version); +} + + +///// Metadata pair and directory operations /// +static inline lfs_size_t lfs1_entry_size(const lfs1_entry_t *entry) { + return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; +} + +static int lfs1_dir_fetch(lfs_t *lfs, + lfs1_dir_t *dir, const lfs_block_t pair[2]) { + // copy out pair, otherwise may be aliasing dir + const lfs_block_t tpair[2] = {pair[0], pair[1]}; + bool valid = false; + + // check both blocks for the most recent revision + for (int i = 0; i < 2; i++) { + struct lfs1_disk_dir test; + int err = lfs1_bd_read(lfs, tpair[i], 0, &test, sizeof(test)); + lfs1_dir_fromle32(&test); + if (err) { + if (err == LFS_ERR_CORRUPT) { + continue; + } + return err; + } + + if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) { + continue; + } + + if ((0x7fffffff & test.size) < sizeof(test)+4 || + (0x7fffffff & test.size) > lfs->cfg->block_size) { + continue; + } + + uint32_t crc = 0xffffffff; + lfs1_dir_tole32(&test); + lfs1_crc(&crc, &test, sizeof(test)); + lfs1_dir_fromle32(&test); + err = lfs1_bd_crc(lfs, tpair[i], sizeof(test), + (0x7fffffff & test.size) - sizeof(test), &crc); + if (err) { + if (err == LFS_ERR_CORRUPT) { + continue; + } + return err; + } + + if (crc != 0) { + continue; + } + + valid = true; + + // setup dir in case it's valid + dir->pair[0] = tpair[(i+0) % 2]; + dir->pair[1] = tpair[(i+1) % 2]; + dir->off = sizeof(dir->d); + dir->d = test; + } + + if (!valid) { + LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", + tpair[0], tpair[1]); + return LFS_ERR_CORRUPT; + } + + return 0; +} + +static int lfs1_dir_next(lfs_t *lfs, lfs1_dir_t *dir, lfs1_entry_t *entry) { + while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { + if (!(0x80000000 & dir->d.size)) { + entry->off = dir->off; + return LFS_ERR_NOENT; + } + + int err = lfs1_dir_fetch(lfs, dir, dir->d.tail); + if (err) { + return err; + } + + dir->off = sizeof(dir->d); + dir->pos += sizeof(dir->d) + 4; + } + + int err = lfs1_bd_read(lfs, dir->pair[0], dir->off, + &entry->d, sizeof(entry->d)); + lfs1_entry_fromle32(&entry->d); + if (err) { + return err; + } + + entry->off = dir->off; + dir->off += lfs1_entry_size(entry); + dir->pos += lfs1_entry_size(entry); + return 0; +} + +/// littlefs v1 specific operations /// +int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { + if (lfs_pair_isnull(lfs->lfs1->root)) { + return 0; + } + + // iterate over metadata pairs + lfs1_dir_t dir; + lfs1_entry_t entry; + lfs_block_t cwd[2] = {0, 1}; + + while (true) { + for (int i = 0; i < 2; i++) { + int err = cb(data, cwd[i]); + if (err) { + return err; + } + } + + int err = lfs1_dir_fetch(lfs, &dir, cwd); + if (err) { + return err; + } + + // iterate over contents + while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { + err = lfs1_bd_read(lfs, dir.pair[0], dir.off, + &entry.d, sizeof(entry.d)); + lfs1_entry_fromle32(&entry.d); + if (err) { + return err; + } + + dir.off += lfs1_entry_size(&entry); + if ((0x70 & entry.d.type) == (0x70 & LFS1_TYPE_REG)) { + err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache, + entry.d.u.file.head, entry.d.u.file.size, cb, data); + if (err) { + return err; + } + } + } + + // we also need to check if we contain a threaded v2 directory + lfs_mdir_t dir2 = {.split=true, .tail={cwd[0], cwd[1]}}; + while (dir2.split) { + err = lfs_dir_fetch(lfs, &dir2, dir2.tail); + if (err) { + break; + } + + for (int i = 0; i < 2; i++) { + err = cb(data, dir2.pair[i]); + if (err) { + return err; + } + } + } + + cwd[0] = dir.d.tail[0]; + cwd[1] = dir.d.tail[1]; + + if (lfs_pair_isnull(cwd)) { + break; + } + } + + return 0; +} + +static int lfs1_moved(lfs_t *lfs, const void *e) { + if (lfs_pair_isnull(lfs->lfs1->root)) { + return 0; + } + + // skip superblock + lfs1_dir_t cwd; + int err = lfs1_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){0, 1}); + if (err) { + return err; + } + + // iterate over all directory directory entries + lfs1_entry_t entry; + while (!lfs_pair_isnull(cwd.d.tail)) { + err = lfs1_dir_fetch(lfs, &cwd, cwd.d.tail); + if (err) { + return err; + } + + while (true) { + err = lfs1_dir_next(lfs, &cwd, &entry); + if (err && err != LFS_ERR_NOENT) { + return err; + } + + if (err == LFS_ERR_NOENT) { + break; + } + + if (!(0x80 & entry.d.type) && + memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { + return true; + } + } + } + + return false; +} + +/// Filesystem operations /// +static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1, + const struct lfs_config *cfg) { + int err = 0; + { + err = lfs_init(lfs, cfg); + if (err) { + return err; + } + + lfs->lfs1 = lfs1; + lfs->lfs1->root[0] = LFS_BLOCK_NULL; + lfs->lfs1->root[1] = LFS_BLOCK_NULL; + + // setup free lookahead + lfs->free.off = 0; + lfs->free.size = 0; + lfs->free.i = 0; + lfs_alloc_ack(lfs); + + // load superblock + lfs1_dir_t dir; + lfs1_superblock_t superblock; + err = lfs1_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); + if (err && err != LFS_ERR_CORRUPT) { + goto cleanup; + } + + if (!err) { + err = lfs1_bd_read(lfs, dir.pair[0], sizeof(dir.d), + &superblock.d, sizeof(superblock.d)); + lfs1_superblock_fromle32(&superblock.d); + if (err) { + goto cleanup; + } + + lfs->lfs1->root[0] = superblock.d.root[0]; + lfs->lfs1->root[1] = superblock.d.root[1]; + } + + if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { + LFS_ERROR("Invalid superblock at {0x%"PRIx32", 0x%"PRIx32"}", + 0, 1); + err = LFS_ERR_CORRUPT; + goto cleanup; + } + + uint16_t major_version = (0xffff & (superblock.d.version >> 16)); + uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); + if ((major_version != LFS1_DISK_VERSION_MAJOR || + minor_version > LFS1_DISK_VERSION_MINOR)) { + LFS_ERROR("Invalid version v%d.%d", major_version, minor_version); + err = LFS_ERR_INVAL; + goto cleanup; + } + + return 0; + } + +cleanup: + lfs_deinit(lfs); + return err; +} + +static int lfs1_unmount(lfs_t *lfs) { + return lfs_deinit(lfs); +} + +/// v1 migration /// +int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { + LFS_TRACE("lfs_migrate(%p, %p {.context=%p, " + ".read=%p, .prog=%p, .erase=%p, .sync=%p, " + ".read_size=%"PRIu32", .prog_size=%"PRIu32", " + ".block_size=%"PRIu32", .block_count=%"PRIu32", " + ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + struct lfs1 lfs1; + int err = lfs1_mount(lfs, &lfs1, cfg); + if (err) { + LFS_TRACE("lfs_migrate -> %d", err); + return err; + } + + { + // iterate through each directory, copying over entries + // into new directory + lfs1_dir_t dir1; + lfs_mdir_t dir2; + dir1.d.tail[0] = lfs->lfs1->root[0]; + dir1.d.tail[1] = lfs->lfs1->root[1]; + while (!lfs_pair_isnull(dir1.d.tail)) { + // iterate old dir + err = lfs1_dir_fetch(lfs, &dir1, dir1.d.tail); + if (err) { + goto cleanup; + } + + // create new dir and bind as temporary pretend root + err = lfs_dir_alloc(lfs, &dir2); + if (err) { + goto cleanup; + } + + dir2.rev = dir1.d.rev; + dir1.head[0] = dir1.pair[0]; + dir1.head[1] = dir1.pair[1]; + lfs->root[0] = dir2.pair[0]; + lfs->root[1] = dir2.pair[1]; + + err = lfs_dir_commit(lfs, &dir2, NULL, 0); + if (err) { + goto cleanup; + } + + while (true) { + lfs1_entry_t entry1; + err = lfs1_dir_next(lfs, &dir1, &entry1); + if (err && err != LFS_ERR_NOENT) { + goto cleanup; + } + + if (err == LFS_ERR_NOENT) { + break; + } + + // check that entry has not been moved + if (entry1.d.type & 0x80) { + int moved = lfs1_moved(lfs, &entry1.d.u); + if (moved < 0) { + err = moved; + goto cleanup; + } + + if (moved) { + continue; + } + + entry1.d.type &= ~0x80; + } + + // also fetch name + char name[LFS_NAME_MAX+1]; + memset(name, 0, sizeof(name)); + err = lfs1_bd_read(lfs, dir1.pair[0], + entry1.off + 4+entry1.d.elen+entry1.d.alen, + name, entry1.d.nlen); + if (err) { + goto cleanup; + } + + bool isdir = (entry1.d.type == LFS1_TYPE_DIR); + + // create entry in new dir + err = lfs_dir_fetch(lfs, &dir2, lfs->root); + if (err) { + goto cleanup; + } + + uint16_t id; + err = lfs_dir_find(lfs, &dir2, &(const char*){name}, &id); + if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { + err = (err < 0) ? err : LFS_ERR_EXIST; + goto cleanup; + } + + lfs1_entry_tole32(&entry1.d); + err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_CREATE, id, 0)}, + {LFS_MKTAG_IF_ELSE(isdir, + LFS_TYPE_DIR, id, entry1.d.nlen, + LFS_TYPE_REG, id, entry1.d.nlen), + name}, + {LFS_MKTAG_IF_ELSE(isdir, + LFS_TYPE_DIRSTRUCT, id, sizeof(entry1.d.u), + LFS_TYPE_CTZSTRUCT, id, sizeof(entry1.d.u)), + &entry1.d.u})); + lfs1_entry_fromle32(&entry1.d); + if (err) { + goto cleanup; + } + } + + if (!lfs_pair_isnull(dir1.d.tail)) { + // find last block and update tail to thread into fs + err = lfs_dir_fetch(lfs, &dir2, lfs->root); + if (err) { + goto cleanup; + } + + while (dir2.split) { + err = lfs_dir_fetch(lfs, &dir2, dir2.tail); + if (err) { + goto cleanup; + } + } + + lfs_pair_tole32(dir2.pair); + err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir1.d.tail})); + lfs_pair_fromle32(dir2.pair); + if (err) { + goto cleanup; + } + } + + // Copy over first block to thread into fs. Unfortunately + // if this fails there is not much we can do. + LFS_DEBUG("Migrating {0x%"PRIx32", 0x%"PRIx32"} " + "-> {0x%"PRIx32", 0x%"PRIx32"}", + lfs->root[0], lfs->root[1], dir1.head[0], dir1.head[1]); + + err = lfs_bd_erase(lfs, dir1.head[1]); + if (err) { + goto cleanup; + } + + err = lfs_dir_fetch(lfs, &dir2, lfs->root); + if (err) { + goto cleanup; + } + + for (lfs_off_t i = 0; i < dir2.off; i++) { + uint8_t dat; + err = lfs_bd_read(lfs, + NULL, &lfs->rcache, dir2.off, + dir2.pair[0], i, &dat, 1); + if (err) { + goto cleanup; + } + + err = lfs_bd_prog(lfs, + &lfs->pcache, &lfs->rcache, true, + dir1.head[1], i, &dat, 1); + if (err) { + goto cleanup; + } + } + + err = lfs_bd_flush(lfs, &lfs->pcache, &lfs->rcache, true); + if (err) { + goto cleanup; + } + } + + // Create new superblock. This marks a successful migration! + err = lfs1_dir_fetch(lfs, &dir1, (const lfs_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + dir2.pair[0] = dir1.pair[0]; + dir2.pair[1] = dir1.pair[1]; + dir2.rev = dir1.d.rev; + dir2.off = sizeof(dir2.rev); + dir2.etag = 0xffffffff; + dir2.count = 0; + dir2.tail[0] = lfs->lfs1->root[0]; + dir2.tail[1] = lfs->lfs1->root[1]; + dir2.erased = false; + dir2.split = true; + + lfs_superblock_t superblock = { + .version = LFS_DISK_VERSION, + .block_size = lfs->cfg->block_size, + .block_count = lfs->cfg->block_count, + .name_max = lfs->name_max, + .file_max = lfs->file_max, + .attr_max = lfs->attr_max, + }; + + lfs_superblock_tole32(&superblock); + err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0)}, + {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, + {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})); + if (err) { + goto cleanup; + } + + // sanity check that fetch works + err = lfs_dir_fetch(lfs, &dir2, (const lfs_block_t[2]){0, 1}); + if (err) { + goto cleanup; + } + + // force compaction to prevent accidentally mounting v1 + dir2.erased = false; + err = lfs_dir_commit(lfs, &dir2, NULL, 0); + if (err) { + goto cleanup; + } + } + +cleanup: + lfs1_unmount(lfs); + LFS_TRACE("lfs_migrate -> %d", err); + return err; +} + +#endif diff --git a/lib/libesp32/LITTLEFS/src/lfs.h b/lib/libesp32/LITTLEFS/src/lfs.h new file mode 100755 index 000000000..35bbbabfa --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/lfs.h @@ -0,0 +1,655 @@ +/* + * The little filesystem + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS_H +#define LFS_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/// Version info /// + +// Software library version +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS_VERSION 0x00020002 +#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) +#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) + +// Version of On-disk data structures +// Major (top-nibble), incremented on backwards incompatible changes +// Minor (bottom-nibble), incremented on feature additions +#define LFS_DISK_VERSION 0x00020000 +#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) +#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0)) + + +/// Definitions /// + +// Type definitions +typedef uint32_t lfs_size_t; +typedef uint32_t lfs_off_t; + +typedef int32_t lfs_ssize_t; +typedef int32_t lfs_soff_t; + +typedef uint32_t lfs_block_t; + +// Maximum name size in bytes, may be redefined to reduce the size of the +// info struct. Limited to <= 1022. Stored in superblock and must be +// respected by other littlefs drivers. +#ifndef LFS_NAME_MAX +#define LFS_NAME_MAX 255 +#endif + +// Maximum size of a file in bytes, may be redefined to limit to support other +// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the +// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return +// incorrect values due to using signed integers. Stored in superblock and +// must be respected by other littlefs drivers. +#ifndef LFS_FILE_MAX +#define LFS_FILE_MAX 2147483647 +#endif + +// Maximum size of custom attributes in bytes, may be redefined, but there is +// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. +#ifndef LFS_ATTR_MAX +#define LFS_ATTR_MAX 1022 +#endif + +// Possible error codes, these are negative to allow +// valid positive return values +enum lfs_error { + LFS_ERR_OK = 0, // No error + LFS_ERR_IO = -5, // Error during device operation + LFS_ERR_CORRUPT = -84, // Corrupted + LFS_ERR_NOENT = -2, // No directory entry + LFS_ERR_EXIST = -17, // Entry already exists + LFS_ERR_NOTDIR = -20, // Entry is not a dir + LFS_ERR_ISDIR = -21, // Entry is a dir + LFS_ERR_NOTEMPTY = -39, // Dir is not empty + LFS_ERR_BADF = -9, // Bad file number + LFS_ERR_FBIG = -27, // File too large + LFS_ERR_INVAL = -22, // Invalid parameter + LFS_ERR_NOSPC = -28, // No space left on device + LFS_ERR_NOMEM = -12, // No more memory available + LFS_ERR_NOATTR = -61, // No data/attr available + LFS_ERR_NAMETOOLONG = -36, // File name too long +}; + +// File types +enum lfs_type { + // file types + LFS_TYPE_REG = 0x001, + LFS_TYPE_DIR = 0x002, + + // internally used types + LFS_TYPE_SPLICE = 0x400, + LFS_TYPE_NAME = 0x000, + LFS_TYPE_STRUCT = 0x200, + LFS_TYPE_USERATTR = 0x300, + LFS_TYPE_FROM = 0x100, + LFS_TYPE_TAIL = 0x600, + LFS_TYPE_GLOBALS = 0x700, + LFS_TYPE_CRC = 0x500, + + // internally used type specializations + LFS_TYPE_CREATE = 0x401, + LFS_TYPE_DELETE = 0x4ff, + LFS_TYPE_SUPERBLOCK = 0x0ff, + LFS_TYPE_DIRSTRUCT = 0x200, + LFS_TYPE_CTZSTRUCT = 0x202, + LFS_TYPE_INLINESTRUCT = 0x201, + LFS_TYPE_SOFTTAIL = 0x600, + LFS_TYPE_HARDTAIL = 0x601, + LFS_TYPE_MOVESTATE = 0x7ff, + + // internal chip sources + LFS_FROM_NOOP = 0x000, + LFS_FROM_MOVE = 0x101, + LFS_FROM_USERATTRS = 0x102, +}; + +// File open flags +enum lfs_open_flags { + // open flags + LFS_O_RDONLY = 1, // Open a file as read only + LFS_O_WRONLY = 2, // Open a file as write only + LFS_O_RDWR = 3, // Open a file as read and write + LFS_O_CREAT = 0x0100, // Create a file if it does not exist + LFS_O_EXCL = 0x0200, // Fail if a file already exists + LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size + LFS_O_APPEND = 0x0800, // Move to end of file on every write + + // internally used flags + LFS_F_DIRTY = 0x010000, // File does not match storage + LFS_F_WRITING = 0x020000, // File has been written since last flush + LFS_F_READING = 0x040000, // File has been read since last flush + LFS_F_ERRED = 0x080000, // An error occured during write + LFS_F_INLINE = 0x100000, // Currently inlined in directory entry + LFS_F_OPENED = 0x200000, // File has been opened +}; + +// File seek flags +enum lfs_whence_flags { + LFS_SEEK_SET = 0, // Seek relative to an absolute position + LFS_SEEK_CUR = 1, // Seek relative to the current file position + LFS_SEEK_END = 2, // Seek relative to the end of the file +}; + + +// Configuration provided during initialization of the littlefs +struct lfs_config { + // Opaque user provided context that can be used to pass + // information to the block device operations + void *context; + + // Read a region in a block. Negative error codes are propogated + // to the user. + int (*read)(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, void *buffer, lfs_size_t size); + + // Program a region in a block. The block must have previously + // been erased. Negative error codes are propogated to the user. + // May return LFS_ERR_CORRUPT if the block should be considered bad. + int (*prog)(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size); + + // Erase a block. A block must be erased before being programmed. + // The state of an erased block is undefined. Negative error codes + // are propogated to the user. + // May return LFS_ERR_CORRUPT if the block should be considered bad. + int (*erase)(const struct lfs_config *c, lfs_block_t block); + + // Sync the state of the underlying block device. Negative error codes + // are propogated to the user. + int (*sync)(const struct lfs_config *c); + + // Minimum size of a block read. All read operations will be a + // multiple of this value. + lfs_size_t read_size; + + // Minimum size of a block program. All program operations will be a + // multiple of this value. + lfs_size_t prog_size; + + // Size of an erasable block. This does not impact ram consumption and + // may be larger than the physical erase size. However, non-inlined files + // take up at minimum one block. Must be a multiple of the read + // and program sizes. + lfs_size_t block_size; + + // Number of erasable blocks on the device. + lfs_size_t block_count; + + // Number of erase cycles before littlefs evicts metadata logs and moves + // the metadata to another block. Suggested values are in the + // range 100-1000, with large values having better performance at the cost + // of less consistent wear distribution. + // + // Set to -1 to disable block-level wear-leveling. + int32_t block_cycles; + + // Size of block caches. Each cache buffers a portion of a block in RAM. + // The littlefs needs a read cache, a program cache, and one additional + // cache per file. Larger caches can improve performance by storing more + // data and reducing the number of disk accesses. Must be a multiple of + // the read and program sizes, and a factor of the block size. + lfs_size_t cache_size; + + // Size of the lookahead buffer in bytes. A larger lookahead buffer + // increases the number of blocks found during an allocation pass. The + // lookahead buffer is stored as a compact bitmap, so each byte of RAM + // can track 8 blocks. Must be a multiple of 8. + lfs_size_t lookahead_size; + + // Optional statically allocated read buffer. Must be cache_size. + // By default lfs_malloc is used to allocate this buffer. + void *read_buffer; + + // Optional statically allocated program buffer. Must be cache_size. + // By default lfs_malloc is used to allocate this buffer. + void *prog_buffer; + + // Optional statically allocated lookahead buffer. Must be lookahead_size + // and aligned to a 32-bit boundary. By default lfs_malloc is used to + // allocate this buffer. + void *lookahead_buffer; + + // Optional upper limit on length of file names in bytes. No downside for + // larger names except the size of the info struct which is controlled by + // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in + // superblock and must be respected by other littlefs drivers. + lfs_size_t name_max; + + // Optional upper limit on files in bytes. No downside for larger files + // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored + // in superblock and must be respected by other littlefs drivers. + lfs_size_t file_max; + + // Optional upper limit on custom attributes in bytes. No downside for + // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to + // LFS_ATTR_MAX when zero. + lfs_size_t attr_max; +}; + +// File info structure +struct lfs_info { + // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR + uint8_t type; + + // Size of the file, only valid for REG files. Limited to 32-bits. + lfs_size_t size; + + // Name of the file stored as a null-terminated string. Limited to + // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to + // reduce RAM. LFS_NAME_MAX is stored in superblock and must be + // respected by other littlefs drivers. + char name[LFS_NAME_MAX+1]; +}; + +// Custom attribute structure, used to describe custom attributes +// committed atomically during file writes. +struct lfs_attr { + // 8-bit type of attribute, provided by user and used to + // identify the attribute + uint8_t type; + + // Pointer to buffer containing the attribute + void *buffer; + + // Size of attribute in bytes, limited to LFS_ATTR_MAX + lfs_size_t size; +}; + +// Optional configuration provided during lfs_file_opencfg +struct lfs_file_config { + // Optional statically allocated file buffer. Must be cache_size. + // By default lfs_malloc is used to allocate this buffer. + void *buffer; + + // Optional list of custom attributes related to the file. If the file + // is opened with read access, these attributes will be read from disk + // during the open call. If the file is opened with write access, the + // attributes will be written to disk every file sync or close. This + // write occurs atomically with update to the file's contents. + // + // Custom attributes are uniquely identified by an 8-bit type and limited + // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller + // than the buffer, it will be padded with zeros. If the stored attribute + // is larger, then it will be silently truncated. If the attribute is not + // found, it will be created implicitly. + struct lfs_attr *attrs; + + // Number of custom attributes in the list + lfs_size_t attr_count; +}; + + +/// internal littlefs data structures /// +typedef struct lfs_cache { + lfs_block_t block; + lfs_off_t off; + lfs_size_t size; + uint8_t *buffer; +} lfs_cache_t; + +typedef struct lfs_mdir { + lfs_block_t pair[2]; + uint32_t rev; + lfs_off_t off; + uint32_t etag; + uint16_t count; + bool erased; + bool split; + lfs_block_t tail[2]; +} lfs_mdir_t; + +// littlefs directory type +typedef struct lfs_dir { + struct lfs_dir *next; + uint16_t id; + uint8_t type; + lfs_mdir_t m; + + lfs_off_t pos; + lfs_block_t head[2]; +} lfs_dir_t; + +// littlefs file type +typedef struct lfs_file { + struct lfs_file *next; + uint16_t id; + uint8_t type; + lfs_mdir_t m; + + struct lfs_ctz { + lfs_block_t head; + lfs_size_t size; + } ctz; + + uint32_t flags; + lfs_off_t pos; + lfs_block_t block; + lfs_off_t off; + lfs_cache_t cache; + + const struct lfs_file_config *cfg; +} lfs_file_t; + +typedef struct lfs_superblock { + uint32_t version; + lfs_size_t block_size; + lfs_size_t block_count; + lfs_size_t name_max; + lfs_size_t file_max; + lfs_size_t attr_max; +} lfs_superblock_t; + +typedef struct lfs_gstate { + uint32_t tag; + lfs_block_t pair[2]; +} lfs_gstate_t; + +// The littlefs filesystem type +typedef struct lfs { + lfs_cache_t rcache; + lfs_cache_t pcache; + + lfs_block_t root[2]; + struct lfs_mlist { + struct lfs_mlist *next; + uint16_t id; + uint8_t type; + lfs_mdir_t m; + } *mlist; + uint32_t seed; + + lfs_gstate_t gstate; + lfs_gstate_t gdisk; + lfs_gstate_t gdelta; + + struct lfs_free { + lfs_block_t off; + lfs_block_t size; + lfs_block_t i; + lfs_block_t ack; + uint32_t *buffer; + } free; + + const struct lfs_config *cfg; + lfs_size_t name_max; + lfs_size_t file_max; + lfs_size_t attr_max; + +#ifdef LFS_MIGRATE + struct lfs1 *lfs1; +#endif +} lfs_t; + + +/// Filesystem functions /// + +// Format a block device with the littlefs +// +// Requires a littlefs object and config struct. This clobbers the littlefs +// object, and does not leave the filesystem mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs_format(lfs_t *lfs, const struct lfs_config *config); + +// Mounts a littlefs +// +// Requires a littlefs object and config struct. Multiple filesystems +// may be mounted simultaneously with multiple littlefs objects. Both +// lfs and config must be allocated while mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs_mount(lfs_t *lfs, const struct lfs_config *config); + +// Unmounts a littlefs +// +// Does nothing besides releasing any allocated resources. +// Returns a negative error code on failure. +int lfs_unmount(lfs_t *lfs); + +/// General operations /// + +// Removes a file or directory +// +// If removing a directory, the directory must be empty. +// Returns a negative error code on failure. +int lfs_remove(lfs_t *lfs, const char *path); + +// Rename or move a file or directory +// +// If the destination exists, it must match the source in type. +// If the destination is a directory, the directory must be empty. +// +// Returns a negative error code on failure. +int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); + +// Find info about a file or directory +// +// Fills out the info structure, based on the specified file or directory. +// Returns a negative error code on failure. +int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); + +// Get a custom attribute +// +// Custom attributes are uniquely identified by an 8-bit type and limited +// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than +// the buffer, it will be padded with zeros. If the stored attribute is larger, +// then it will be silently truncated. If no attribute is found, the error +// LFS_ERR_NOATTR is returned and the buffer is filled with zeros. +// +// Returns the size of the attribute, or a negative error code on failure. +// Note, the returned size is the size of the attribute on disk, irrespective +// of the size of the buffer. This can be used to dynamically allocate a buffer +// or check for existance. +lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, + uint8_t type, void *buffer, lfs_size_t size); + +// Set custom attributes +// +// Custom attributes are uniquely identified by an 8-bit type and limited +// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be +// implicitly created. +// +// Returns a negative error code on failure. +int lfs_setattr(lfs_t *lfs, const char *path, + uint8_t type, const void *buffer, lfs_size_t size); + +// Removes a custom attribute +// +// If an attribute is not found, nothing happens. +// +// Returns a negative error code on failure. +int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); + + +/// File operations /// + +// Open a file +// +// The mode that the file is opened in is determined by the flags, which +// are values from the enum lfs_open_flags that are bitwise-ored together. +// +// Returns a negative error code on failure. +int lfs_file_open(lfs_t *lfs, lfs_file_t *file, + const char *path, int flags); + +// Open a file with extra configuration +// +// The mode that the file is opened in is determined by the flags, which +// are values from the enum lfs_open_flags that are bitwise-ored together. +// +// The config struct provides additional config options per file as described +// above. The config struct must be allocated while the file is open, and the +// config struct must be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, + const char *path, int flags, + const struct lfs_file_config *config); + +// Close a file +// +// Any pending writes are written out to storage as though +// sync had been called and releases any allocated resources. +// +// Returns a negative error code on failure. +int lfs_file_close(lfs_t *lfs, lfs_file_t *file); + +// Synchronize a file on storage +// +// Any pending writes are written out to storage. +// Returns a negative error code on failure. +int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); + +// Read data from file +// +// Takes a buffer and size indicating where to store the read data. +// Returns the number of bytes read, or a negative error code on failure. +lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size); + +// Write data to file +// +// Takes a buffer and size indicating the data to write. The file will not +// actually be updated on the storage until either sync or close is called. +// +// Returns the number of bytes written, or a negative error code on failure. +lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size); + +// Change the position of the file +// +// The change in position is determined by the offset and whence flag. +// Returns the new position of the file, or a negative error code on failure. +lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, + lfs_soff_t off, int whence); + +// Truncates the size of the file to the specified size +// +// Returns a negative error code on failure. +int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); + +// Return the position of the file +// +// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) +// Returns the position of the file, or a negative error code on failure. +lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); + +// Change the position of the file to the beginning of the file +// +// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET) +// Returns a negative error code on failure. +int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); + +// Return the size of the file +// +// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END) +// Returns the size of the file, or a negative error code on failure. +lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); + + +/// Directory operations /// + +// Create a directory +// +// Returns a negative error code on failure. +int lfs_mkdir(lfs_t *lfs, const char *path); + +// Open a directory +// +// Once open a directory can be used with read to iterate over files. +// Returns a negative error code on failure. +int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); + +// Close a directory +// +// Releases any allocated resources. +// Returns a negative error code on failure. +int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); + +// Read an entry in the directory +// +// Fills out the info structure, based on the specified file or directory. +// Returns a positive value on success, 0 at the end of directory, +// or a negative error code on failure. +int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); + +// Change the position of the directory +// +// The new off must be a value previous returned from tell and specifies +// an absolute offset in the directory seek. +// +// Returns a negative error code on failure. +int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); + +// Return the position of the directory +// +// The returned offset is only meant to be consumed by seek and may not make +// sense, but does indicate the current position in the directory iteration. +// +// Returns the position of the directory, or a negative error code on failure. +lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); + +// Change the position of the directory to the beginning of the directory +// +// Returns a negative error code on failure. +int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); + + +/// Filesystem-level filesystem operations + +// Finds the current size of the filesystem +// +// Note: Result is best effort. If files share COW structures, the returned +// size may be larger than the filesystem actually is. +// +// Returns the number of allocated blocks, or a negative error code on failure. +lfs_ssize_t lfs_fs_size(lfs_t *lfs); + +// Traverse through all blocks in use by the filesystem +// +// The provided callback will be called with each block address that is +// currently in use by the filesystem. This can be used to determine which +// blocks are in use or how much of the storage is available. +// +// Returns a negative error code on failure. +int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); + +#ifdef LFS_MIGRATE +// Attempts to migrate a previous version of littlefs +// +// Behaves similarly to the lfs_format function. Attempts to mount +// the previous version of littlefs and update the filesystem so it can be +// mounted with the current version of littlefs. +// +// Requires a littlefs object and config struct. This clobbers the littlefs +// object, and does not leave the filesystem mounted. The config struct must +// be zeroed for defaults and backwards compatibility. +// +// Returns a negative error code on failure. +int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/lib/libesp32/LITTLEFS/src/lfs_util.c b/lib/libesp32/LITTLEFS/src/lfs_util.c new file mode 100755 index 000000000..0b60e3b49 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/lfs_util.c @@ -0,0 +1,33 @@ +/* + * lfs util functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs_util.h" + +// Only compile if user does not provide custom config +#ifndef LFS_CONFIG + + +// Software CRC implementation with small lookup table +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { + static const uint32_t rtable[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, + }; + + const uint8_t *data = buffer; + + for (size_t i = 0; i < size; i++) { + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; + } + + return crc; +} + + +#endif diff --git a/lib/libesp32/LITTLEFS/src/lfs_util.h b/lib/libesp32/LITTLEFS/src/lfs_util.h new file mode 100755 index 000000000..dbb4c5ba8 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/lfs_util.h @@ -0,0 +1,234 @@ +/* + * lfs utility functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS_UTIL_H +#define LFS_UTIL_H + +// Users can override lfs_util.h with their own configuration by defining +// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). +// +// If LFS_CONFIG is used, none of the default utils will be emitted and must be +// provided by the config file. To start, I would suggest copying lfs_util.h +// and modifying as needed. +#ifdef LFS_CONFIG +#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) +#define LFS_STRINGIZE2(x) #x +#include LFS_STRINGIZE(LFS_CONFIG) +#else + +// System includes +#include +#include +#include +#include + +#ifndef LFS_NO_MALLOC +#include +#endif +#ifndef LFS_NO_ASSERT +#include +#endif +#if !defined(LFS_NO_DEBUG) || \ + !defined(LFS_NO_WARN) || \ + !defined(LFS_NO_ERROR) || \ + defined(LFS_YES_TRACE) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + +// Macros, may be replaced by system specific wrappers. Arguments to these +// macros must not have side-effects as the macros can be removed for a smaller +// code footprint + +// Logging functions +#ifdef LFS_YES_TRACE +#define LFS_TRACE_(fmt, ...) \ + printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") +#else +#define LFS_TRACE(...) +#endif + +#ifndef LFS_NO_DEBUG +#define LFS_DEBUG_(fmt, ...) \ + printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") +#else +#define LFS_DEBUG(...) +#endif + +#ifndef LFS_NO_WARN +#define LFS_WARN_(fmt, ...) \ + printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") +#else +#define LFS_WARN(...) +#endif + +#ifndef LFS_NO_ERROR +#define LFS_ERROR_(fmt, ...) \ + printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") +#else +#define LFS_ERROR(...) +#endif + +// Runtime assertions +#ifndef LFS_NO_ASSERT +#define LFS_ASSERT(test) assert(test) +#else +#define LFS_ASSERT(test) +#endif + + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs_max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +static inline uint32_t lfs_min(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +// Align to nearest multiple of a size +static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { + return a - (a % alignment); +} + +static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { + return lfs_aligndown(a + alignment-1, alignment); +} + +// Find the smallest power of 2 greater than or equal to a +static inline uint32_t lfs_npw2(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a-1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; a >>= s; r |= s; + s = (a > 0xff ) << 3; a >>= s; r |= s; + s = (a > 0xf ) << 2; a >>= s; r |= s; + s = (a > 0x3 ) << 1; a >>= s; r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs_ctz(0) may be undefined +static inline uint32_t lfs_ctz(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs_popc(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs_scmp(uint32_t a, uint32_t b) { + return (int)(unsigned)(a - b); +} + +// Convert between 32-bit little-endian and native order +static inline uint32_t lfs_fromle32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t*)&a)[0] << 0) | + (((uint8_t*)&a)[1] << 8) | + (((uint8_t*)&a)[2] << 16) | + (((uint8_t*)&a)[3] << 24); +#endif +} + +static inline uint32_t lfs_tole32(uint32_t a) { + return lfs_fromle32(a); +} + +// Convert between 32-bit big-endian and native order +static inline uint32_t lfs_frombe32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return __builtin_bswap32(a); +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return a; +#else + return (((uint8_t*)&a)[0] << 24) | + (((uint8_t*)&a)[1] << 16) | + (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); +#endif +} + +static inline uint32_t lfs_tobe32(uint32_t a) { + return lfs_frombe32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +// Note, memory must be 64-bit aligned +static inline void *lfs_malloc(size_t size) { +#ifndef LFS_NO_MALLOC + return malloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs_free(void *p) { +#ifndef LFS_NO_MALLOC + free(p); +#else + (void)p; +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif +#endif diff --git a/lib/libesp32/LITTLEFS/src/littlefs_api.c b/lib/libesp32/LITTLEFS/src/littlefs_api.c new file mode 100755 index 000000000..4098487c6 --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/littlefs_api.c @@ -0,0 +1,58 @@ +/** + * @file littlefs_api.c + * @brief Maps the HAL of esp_partition <-> littlefs + * @author Brian Pugh + */ + +#define ESP_LOCAL_LOG_LEVEL ESP_LOG_INFO + +#include "esp_log.h" +#include "esp_partition.h" +#include "esp_vfs.h" +#include "lfs.h" +#include "esp_littlefs.h" +#include "littlefs_api.h" + +static const char TAG[] = "esp_littlefs_api"; + +int littlefs_api_read(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, void *buffer, lfs_size_t size) { + esp_littlefs_t * efs = c->context; + size_t part_off = (block * c->block_size) + off; + esp_err_t err = esp_partition_read(efs->partition, part_off, buffer, size); + if (err) { + ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", part_off, size, err); + return LFS_ERR_IO; + } + return 0; +} + +int littlefs_api_prog(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size) { + esp_littlefs_t * efs = c->context; + size_t part_off = (block * c->block_size) + off; + esp_err_t err = esp_partition_write(efs->partition, part_off, buffer, size); + if (err) { + ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", part_off, size, err); + return LFS_ERR_IO; + } + return 0; +} + +int littlefs_api_erase(const struct lfs_config *c, lfs_block_t block) { + esp_littlefs_t * efs = c->context; + size_t part_off = block * c->block_size; + esp_err_t err = esp_partition_erase_range(efs->partition, part_off, c->block_size); + if (err) { + ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", part_off, c->block_size, err); + return LFS_ERR_IO; + } + return 0; + +} + +int littlefs_api_sync(const struct lfs_config *c) { + /* Unnecessary for esp-idf */ + return 0; +} + diff --git a/lib/libesp32/LITTLEFS/src/littlefs_api.h b/lib/libesp32/LITTLEFS/src/littlefs_api.h new file mode 100755 index 000000000..c1b2adc9a --- /dev/null +++ b/lib/libesp32/LITTLEFS/src/littlefs_api.h @@ -0,0 +1,106 @@ +#ifndef ESP_LITTLEFS_API_H__ +#define ESP_LITTLEFS_API_H__ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_vfs.h" +#include "esp_partition.h" +#include "lfs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief a file descriptor + * That's also a singly linked list used for keeping tracks of all opened file descriptor + * + * Shortcomings/potential issues of 32-bit hash (when CONFIG_LITTLEFS_USE_ONLY_HASH) listed here: + * * unlink - If a different file is open that generates a hash collision, it will report an + * error that it cannot unlink an open file. + * * rename - If a different file is open that generates a hash collision with + * src or dst, it will report an error that it cannot rename an open file. + * Potential consequences: + * 1. A file cannot be deleted while a collision-geneating file is open. + * Worst-case, if the other file is always open during the lifecycle + * of your app, it's collision file cannot be deleted, which in the + * worst-case could cause storage-capacity issues. + * 2. Same as (1), but for renames + */ +typedef struct _vfs_littlefs_file_t { + lfs_file_t file; + uint32_t hash; + struct _vfs_littlefs_file_t * next; /*!< Pointer to next file in Singly Linked List */ +#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH + char * path; +#endif +} vfs_littlefs_file_t; + +/** + * @brief littlefs definition structure + */ +typedef struct { + lfs_t *fs; /*!< Handle to the underlying littlefs */ + SemaphoreHandle_t lock; /*!< FS lock */ + const esp_partition_t* partition; /*!< The partition on which littlefs is located */ + char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */ + + struct lfs_config cfg; /*!< littlefs Mount configuration */ + + vfs_littlefs_file_t *file; /*!< Singly Linked List of files */ + + vfs_littlefs_file_t **cache; /*!< A cache of pointers to the opened files */ + uint16_t cache_size; /*!< The cache allocated size (in pointers) */ + uint16_t fd_count; /*!< The count of opened file descriptor used to speed up computation */ +} esp_littlefs_t; + +/** + * @brief Read a region in a block. + * + * Negative error codes are propogated to the user. + * + * @return errorcode. 0 on success. + */ +int littlefs_api_read(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, void *buffer, lfs_size_t size); + +/** + * @brief Program a region in a block. + * + * The block must have previously been erased. + * Negative error codes are propogated to the user. + * May return LFS_ERR_CORRUPT if the block should be considered bad. + * + * @return errorcode. 0 on success. + */ +int littlefs_api_prog(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size); + +/** + * @brief Erase a block. + * + * A block must be erased before being programmed. + * The state of an erased block is undefined. + * Negative error codes are propogated to the user. + * May return LFS_ERR_CORRUPT if the block should be considered bad. + * @return errorcode. 0 on success. + */ +int littlefs_api_erase(const struct lfs_config *c, lfs_block_t block); + +/** + * @brief Sync the state of the underlying block device. + * + * Negative error codes are propogated to the user. + * + * @return errorcode. 0 on success. + */ +int littlefs_api_sync(const struct lfs_config *c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 3615ebbaa..36984a992 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -53,6 +53,7 @@ driver enabled by #include #include #else +#include #include #include "FFat.h" #include "FS.h" @@ -78,7 +79,8 @@ uint8_t ufs_type; #define UFS_TNONE 0 #define UFS_TSDC 1 #define UFS_TFAT 2 -#define UFS_TSPIFFS 3 +#define UFS_TLFS 3 +#define UFS_TSPIFFS 4 #ifndef UFS_SDCS #define UFS_SDCS 4 @@ -113,21 +115,24 @@ void UFSInit(void) { // if no success with sd card try flash fs #ifdef ESP8266 ufsp = &LittleFS; - if (!fsp->begin()) { + if (!LittleFS.begin()) { return; } #else ufsp = &FFat; if (!FFat.begin(true)) { - if (!SPIFFS.begin(true)) { + ufsp = &LITTLEFS; + if (!LITTLEFS.begin(true)) { + ufsp = &SPIFFS; + if (!SPIFFS.begin(true)) { + return; + } + ufs_type = UFS_TSPIFFS; return; } - ufsp = &SPIFFS; - ufs_type = UFS_TSPIFFS; + ufs_type = UFS_TLFS; return; } - - #endif ufs_type = UFS_TFAT; return; @@ -145,10 +150,11 @@ uint32_t result = 0; result = (SD.totalBytes() - SD.usedBytes()); } #else - // currently no support on esp8266 + // currently no size support on esp8266 sdcard #endif break; - case UFS_TFAT: + + case UFS_TLFS: #ifdef ESP8266 FSInfo64 fsinfo; ufsp->info64(fsinfo); @@ -158,6 +164,16 @@ uint32_t result = 0; result = (fsinfo.totalBytes - fsinfo.usedBytes); } #else + if (sel == 0) { + result = LITTLEFS.totalBytes(); + } else { + result = LITTLEFS.totalBytes() - LITTLEFS.usedBytes(); + } +#endif + break; + + case UFS_TFAT: +#ifdef ESP32 if (sel == 0) { result = FFat.totalBytes(); } else { @@ -165,6 +181,7 @@ uint32_t result = 0; } #endif break; + case UFS_TSPIFFS: if (sel == 0) { result = SPIFFS.totalBytes(); @@ -385,9 +402,7 @@ uint8_t UFS_DownloadFile(char *file) { File download_file; WiFiClient download_Client; - AddLog_P(LOG_LEVEL_INFO, PSTR("file not found %s"),file); - - if (*file == '/') file++; + //AddLog_P(LOG_LEVEL_INFO, PSTR("file not found %s"),file); if (!ufsp->exists(file)) { AddLog_P(LOG_LEVEL_INFO, PSTR("file not found")); From 55d0f9991011ef0b98d5573aab2c107d3284ea93 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Thu, 31 Dec 2020 20:22:54 +0100 Subject: [PATCH 05/78] little fs is default --- esp32_partition_app1572k_spiffs983k.csv | 6 ++++++ esp32_partition_app1984k_spiffs12M.csv | 6 ++++++ tasmota/xdrv_98_filesystem.ino | 15 +++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 esp32_partition_app1572k_spiffs983k.csv create mode 100644 esp32_partition_app1984k_spiffs12M.csv diff --git a/esp32_partition_app1572k_spiffs983k.csv b/esp32_partition_app1572k_spiffs983k.csv new file mode 100644 index 000000000..12ea02fda --- /dev/null +++ b/esp32_partition_app1572k_spiffs983k.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x180000, +app1, app, ota_1, 0x190000, 0x180000, +spiffs, data, spiffs, 0x310000,0x0F0000, diff --git a/esp32_partition_app1984k_spiffs12M.csv b/esp32_partition_app1984k_spiffs12M.csv new file mode 100644 index 000000000..3ffb831ba --- /dev/null +++ b/esp32_partition_app1984k_spiffs12M.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1F0000, +app1, app, ota_1, 0x200000, 0x1F0000, +spiffs, data, spiffs, 0x3F0000,0xC10000, diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 36984a992..78b79a2be 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -119,10 +119,13 @@ void UFSInit(void) { return; } #else - ufsp = &FFat; - if (!FFat.begin(true)) { - ufsp = &LITTLEFS; - if (!LITTLEFS.begin(true)) { + // try lfs first + ufsp = &LITTLEFS; + if (!LITTLEFS.begin(true)) { + // ffat is second + ufsp = &FFat; + if (!FFat.begin(true)) { + // spiffs is last ufsp = &SPIFFS; if (!SPIFFS.begin(true)) { return; @@ -130,11 +133,11 @@ void UFSInit(void) { ufs_type = UFS_TSPIFFS; return; } - ufs_type = UFS_TLFS; + ufs_type = UFS_TFAT; return; } #endif - ufs_type = UFS_TFAT; + ufs_type = UFS_TLFS; return; } From 03a9d5b71f809ce1b14c0a8a470e51c44295ed63 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 1 Jan 2021 08:41:36 +0100 Subject: [PATCH 06/78] Update xdrv_98_filesystem.ino --- tasmota/xdrv_98_filesystem.ino | 37 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 78b79a2be..90d36b51c 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -373,28 +373,28 @@ void UFS_ListDir(char *path, uint8_t depth) { if (!*(pp + 1)) pp++; char *cp = name; // osx formatted disks contain a lot of stuff we dont want - if (ufs_reject((char*)ep)) goto fclose; + if (!ufs_reject((char*)ep)) { - for (uint8_t cnt = 0; cnt1) { - strcat(path, "/"); + for (uint8_t cnt = 0; cnt1) { + strcat(path, "/"); + } + strcat(path, ep); + UFS_ListDir(path, depth + 4); + path[plen] = 0; + } else { snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp,ep); WSContentSend_P(UFS_FORM_SDC_DIRb, npath, ep, name, tstr, entry.size()); + } } - fclose: entry.close(); } dir.close(); @@ -405,8 +405,6 @@ uint8_t UFS_DownloadFile(char *file) { File download_file; WiFiClient download_Client; - //AddLog_P(LOG_LEVEL_INFO, PSTR("file not found %s"),file); - if (!ufsp->exists(file)) { AddLog_P(LOG_LEVEL_INFO, PSTR("file not found")); return 0; @@ -457,6 +455,7 @@ uint8_t UFS_DownloadFile(char *file) { // loop(); //} } + delay(0); } download_file.close(); download_Client.stop(); From f86bfbc298302f1860dac1dc99d75e0ddb18198b Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 1 Jan 2021 11:08:48 +0100 Subject: [PATCH 07/78] sdcrad optional compile (saves 7k) #define USE_SDCARD --- tasmota/xdrv_98_filesystem.ino | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 90d36b51c..f8633aba2 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -50,11 +50,15 @@ driver enabled by #ifdef ESP8266 #include #include +#ifdef USE_SDCARD #include #include +#endif #else #include +#ifdef USE_SDCARD #include +#endif #include "FFat.h" #include "FS.h" #include "SPIFFS.h" @@ -92,6 +96,8 @@ void UFSInit(void) { // 1. check for SD card // 2. check for littlefs or FAT // 3. check for SPIFFS obsolete + +#ifdef USE_SDCARD // if (TasmotaGlobal.spi_enabled) { if (1) { int8_t cs; @@ -111,6 +117,7 @@ void UFSInit(void) { return; } } +#endif // if no success with sd card try flash fs #ifdef ESP8266 @@ -146,6 +153,7 @@ uint32_t result = 0; switch (ufs_type) { case UFS_TSDC: +#ifdef USE_SDCARD #ifdef ESP32 if (sel == 0) { result = SD.totalBytes(); @@ -154,6 +162,7 @@ uint32_t result = 0; } #else // currently no size support on esp8266 sdcard +#endif #endif break; From ef8f1bf8102b892c3421ae8f6d198549622ce455 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 1 Jan 2021 11:15:48 +0100 Subject: [PATCH 08/78] remove spiffs (saves 27k!!!) leave ffat for backwards compatibility with old linker files --- tasmota/xdrv_98_filesystem.ino | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index f8633aba2..1d9da5d48 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -61,7 +61,6 @@ driver enabled by #endif #include "FFat.h" #include "FS.h" -#include "SPIFFS.h" #endif #define UFS_FILE_WRITE "w" @@ -84,7 +83,6 @@ uint8_t ufs_type; #define UFS_TSDC 1 #define UFS_TFAT 2 #define UFS_TLFS 3 -#define UFS_TSPIFFS 4 #ifndef UFS_SDCS #define UFS_SDCS 4 @@ -132,12 +130,6 @@ void UFSInit(void) { // ffat is second ufsp = &FFat; if (!FFat.begin(true)) { - // spiffs is last - ufsp = &SPIFFS; - if (!SPIFFS.begin(true)) { - return; - } - ufs_type = UFS_TSPIFFS; return; } ufs_type = UFS_TFAT; @@ -194,13 +186,6 @@ uint32_t result = 0; #endif break; - case UFS_TSPIFFS: - if (sel == 0) { - result = SPIFFS.totalBytes(); - } else { - result = SPIFFS.totalBytes() - SPIFFS.usedBytes(); - } - break; } return result / 1000; } From c61fb025db8df8c91ca0742c3602c4f1555c3c07 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 1 Jan 2021 11:38:01 +0100 Subject: [PATCH 09/78] Update xdrv_98_filesystem.ino --- tasmota/xdrv_98_filesystem.ino | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 1d9da5d48..379d81931 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -84,16 +84,12 @@ uint8_t ufs_type; #define UFS_TFAT 2 #define UFS_TLFS 3 -#ifndef UFS_SDCS -#define UFS_SDCS 4 -#endif - void UFSInit(void) { ufs_type = 0; // check for fs options, // 1. check for SD card // 2. check for littlefs or FAT - // 3. check for SPIFFS obsolete + #ifdef USE_SDCARD // if (TasmotaGlobal.spi_enabled) { @@ -115,7 +111,7 @@ void UFSInit(void) { return; } } -#endif +#endif // USE_SDCARD // if no success with sd card try flash fs #ifdef ESP8266 @@ -135,7 +131,7 @@ void UFSInit(void) { ufs_type = UFS_TFAT; return; } -#endif +#endif // ESP8266 ufs_type = UFS_TLFS; return; } @@ -155,7 +151,7 @@ uint32_t result = 0; #else // currently no size support on esp8266 sdcard #endif -#endif +#endif //USE_SDCARD break; case UFS_TLFS: @@ -173,7 +169,7 @@ uint32_t result = 0; } else { result = LITTLEFS.totalBytes() - LITTLEFS.usedBytes(); } -#endif +#endif // ESP8266 break; case UFS_TFAT: @@ -183,7 +179,7 @@ uint32_t result = 0; } else { result = FFat.freeBytes(); } -#endif +#endif // ESP32 break; } @@ -473,7 +469,7 @@ void UFS_Upload(void) { } } else { Web.upload_error=1; - Webserver->send(500, "text/plain", "500: couldn't create file"); + WSSend(500, CT_PLAIN, F("500: couldn't create file")); } } From 84334bc015dcfa84906783b35b5fe82d4a6006e9 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Fri, 1 Jan 2021 16:48:52 +0100 Subject: [PATCH 10/78] Update xdrv_98_filesystem.ino --- tasmota/xdrv_98_filesystem.ino | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 379d81931..932185c0c 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -22,7 +22,7 @@ this driver adds universal file system support for ESP8266 (sd card or littlfs on > 1 M devices with special linker file e.g. eagle.flash.4m2m.ld) (makes no sense on 1M devices without sd card) and -ESP32 (sd card or fatfile system) +ESP32 (sd card or little fs or sfatfile system) the sd card chip select is the standard SPI_CS or when not found SDCARD_CS_PIN initializes the FS System Pointer ufsp which can be used by all standard file system calls the only specific call is ufs_fsinfo() which gets the total size (0) and free size (1) @@ -76,7 +76,7 @@ File ufs_upload_file; #define SDCARD_CS_PIN 4 #endif -// 0 = none, 1 = SD, 2 = Flash +// 0 = none, 1 = SD, 2 = ffat, 3 = littlefs // spiffs should be obsolete uint8_t ufs_type; #define UFS_TNONE 0 @@ -94,10 +94,8 @@ void UFSInit(void) { #ifdef USE_SDCARD // if (TasmotaGlobal.spi_enabled) { if (1) { - int8_t cs; - if (!PinUsed(GPIO_SPI_CS)) { - cs = SDCARD_CS_PIN; - } else { + int8_t cs = SDCARD_CS_PIN; + if (PinUsed(GPIO_SPI_CS)) { cs = Pin(GPIO_SPI_CS); } @@ -138,6 +136,9 @@ void UFSInit(void) { uint32_t ufs_fsinfo(uint32_t sel) { uint32_t result = 0; +#ifdef ESP8266 +FSInfo64 fsinfo; +#endif switch (ufs_type) { case UFS_TSDC: @@ -149,14 +150,18 @@ uint32_t result = 0; result = (SD.totalBytes() - SD.usedBytes()); } #else - // currently no size support on esp8266 sdcard + ufsp->info64(fsinfo); + if (sel == 0) { + result = fsinfo.totalBytes; + } else { + result = (fsinfo.totalBytes - fsinfo.usedBytes); + } #endif #endif //USE_SDCARD break; case UFS_TLFS: #ifdef ESP8266 - FSInfo64 fsinfo; ufsp->info64(fsinfo); if (sel == 0) { result = fsinfo.totalBytes; From ca09594c24fa36a71399f68b6302615006733e69 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Fri, 1 Jan 2021 21:13:22 +0100 Subject: [PATCH 11/78] RuleTimer0 applies to all RuleTimers --- tasmota/xdrv_10_rules.ino | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 8d8fefc13..0142b9a09 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -2123,21 +2123,29 @@ void CmndRule(void) void CmndRuleTimer(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RULE_TIMERS)) { - if (XdrvMailbox.data_len > 0) { -#ifdef USE_EXPRESSION - float timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len); - Rules.timer[XdrvMailbox.index -1] = (timer_set > 0) ? millis() + (1000 * timer_set) : 0; -#else - Rules.timer[XdrvMailbox.index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; -#endif // USE_EXPRESSION - } - ResponseClear(); - for (uint32_t i = 0; i < MAX_RULE_TIMERS; i++) { - ResponseAppend_P(PSTR("%c\"T%d\":%d"), (i) ? ',' : '{', i +1, (Rules.timer[i]) ? (Rules.timer[i] - millis()) / 1000 : 0); - } - ResponseJsonEnd(); + if (XdrvMailbox.index > MAX_RULE_TIMERS) + return; + int i = XdrvMailbox.index, max_i = XdrvMailbox.index; + if (0 == i) { + i = 1; + max_i = MAX_RULE_TIMERS; } +#ifdef USE_EXPRESSION + float timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len); + timer_set = (timer_set > 0) ? millis() + (1000 * timer_set) : 0; +#else + unsigned long timer_set = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; +#endif // USE_EXPRESSION + if (XdrvMailbox.data_len > 0) { + for ( ; i <= max_i ; ++i ) { + Rules.timer[i -1] = timer_set; + } + } + ResponseClear(); + for (i = 0; i < MAX_RULE_TIMERS; i++) { + ResponseAppend_P(PSTR("%c\"T%d\":%d"), (i) ? ',' : '{', i +1, (Rules.timer[i]) ? (Rules.timer[i] - millis()) / 1000 : 0); + } + ResponseJsonEnd(); } void CmndEvent(void) From e1e413490e3b6806683dbeac2a7295769432e4f1 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 2 Jan 2021 11:07:50 +0100 Subject: [PATCH 12/78] move ft5206 lib --- lib/{lib_i2c => lib_display}/FT5206_Library/.gitignore | 0 lib/{lib_i2c => lib_display}/FT5206_Library/LICENSE | 0 lib/{lib_i2c => lib_display}/FT5206_Library/README.md | 0 lib/{lib_i2c => lib_display}/FT5206_Library/keywords.txt | 0 lib/{lib_i2c => lib_display}/FT5206_Library/library.properties | 0 lib/{lib_i2c => lib_display}/FT5206_Library/src/FT5206.cpp | 0 lib/{lib_i2c => lib_display}/FT5206_Library/src/FT5206.h | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename lib/{lib_i2c => lib_display}/FT5206_Library/.gitignore (100%) rename lib/{lib_i2c => lib_display}/FT5206_Library/LICENSE (100%) rename lib/{lib_i2c => lib_display}/FT5206_Library/README.md (100%) rename lib/{lib_i2c => lib_display}/FT5206_Library/keywords.txt (100%) rename lib/{lib_i2c => lib_display}/FT5206_Library/library.properties (100%) rename lib/{lib_i2c => lib_display}/FT5206_Library/src/FT5206.cpp (100%) rename lib/{lib_i2c => lib_display}/FT5206_Library/src/FT5206.h (100%) diff --git a/lib/lib_i2c/FT5206_Library/.gitignore b/lib/lib_display/FT5206_Library/.gitignore similarity index 100% rename from lib/lib_i2c/FT5206_Library/.gitignore rename to lib/lib_display/FT5206_Library/.gitignore diff --git a/lib/lib_i2c/FT5206_Library/LICENSE b/lib/lib_display/FT5206_Library/LICENSE similarity index 100% rename from lib/lib_i2c/FT5206_Library/LICENSE rename to lib/lib_display/FT5206_Library/LICENSE diff --git a/lib/lib_i2c/FT5206_Library/README.md b/lib/lib_display/FT5206_Library/README.md similarity index 100% rename from lib/lib_i2c/FT5206_Library/README.md rename to lib/lib_display/FT5206_Library/README.md diff --git a/lib/lib_i2c/FT5206_Library/keywords.txt b/lib/lib_display/FT5206_Library/keywords.txt similarity index 100% rename from lib/lib_i2c/FT5206_Library/keywords.txt rename to lib/lib_display/FT5206_Library/keywords.txt diff --git a/lib/lib_i2c/FT5206_Library/library.properties b/lib/lib_display/FT5206_Library/library.properties similarity index 100% rename from lib/lib_i2c/FT5206_Library/library.properties rename to lib/lib_display/FT5206_Library/library.properties diff --git a/lib/lib_i2c/FT5206_Library/src/FT5206.cpp b/lib/lib_display/FT5206_Library/src/FT5206.cpp similarity index 100% rename from lib/lib_i2c/FT5206_Library/src/FT5206.cpp rename to lib/lib_display/FT5206_Library/src/FT5206.cpp diff --git a/lib/lib_i2c/FT5206_Library/src/FT5206.h b/lib/lib_display/FT5206_Library/src/FT5206.h similarity index 100% rename from lib/lib_i2c/FT5206_Library/src/FT5206.h rename to lib/lib_display/FT5206_Library/src/FT5206.h From 5bb682b7e7b9f392a7b3482ee332c17c2e7f4474 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sat, 2 Jan 2021 18:47:03 +0100 Subject: [PATCH 13/78] insure ruletimers always stops at 0 --- tasmota/xdrv_10_rules.ino | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 0142b9a09..2d0caed1d 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -974,9 +974,8 @@ void RulesEvery100ms(void) void RulesEverySecond(void) { + char json_event[120]; if (Settings.rule_enabled && !Rules.busy) { // Any rule enabled - char json_event[120]; - if (RtcTime.valid) { if ((TasmotaGlobal.uptime > 60) && (RtcTime.minute != Rules.last_minute)) { // Execute from one minute after restart every minute only once Rules.last_minute = RtcTime.minute; @@ -984,10 +983,12 @@ void RulesEverySecond(void) RulesProcessEvent(json_event); } } - for (uint32_t i = 0; i < MAX_RULE_TIMERS; i++) { - if (Rules.timer[i] != 0L) { // Timer active? - if (TimeReached(Rules.timer[i])) { // Timer finished? - Rules.timer[i] = 0L; // Turn off this timer + } + for (uint32_t i = 0; i < MAX_RULE_TIMERS; i++) { + if (Rules.timer[i] != 0L) { // Timer active? + if (TimeReached(Rules.timer[i])) { // Timer finished? + Rules.timer[i] = 0L; // Turn off this timer + if (Settings.rule_enabled && !Rules.busy) { // Any rule enabled snprintf_P(json_event, sizeof(json_event), PSTR("{\"Rules\":{\"Timer\":%d}}"), i +1); RulesProcessEvent(json_event); } From 3d1db430bbc63020f2163bf6282a5aa39713bdaf Mon Sep 17 00:00:00 2001 From: Jeroen Vermeulen - MageHost Date: Sat, 2 Jan 2021 20:30:00 +0100 Subject: [PATCH 14/78] fixes compile error of SSD1331 with tasmota-display + improves layout of DisplayMode 1. --- .../Adafruit_SPITFT_Renderer.cpp | 119 +++++++++--------- .../Adafruit_SPITFT_Renderer.h | 23 ++-- .../Adafruit_SSD1331.cpp | 8 +- .../Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h | 2 +- tasmota/xdsp_14_SSD1331.ino | 6 +- 5 files changed, 85 insertions(+), 73 deletions(-) diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp index d49141a28..bf1d5cb1d 100644 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp @@ -1,5 +1,10 @@ +/* + * This class is basically the same as Adafruit_SPITFT. + * The only difference is: it extends Renderer which extends Adafruit_GFX. + * The original Adafruit_SPITFT class directly extends Adafruit_GFX. + */ /*! - * @file Adafruit_SPITFT.cpp + * @file Adafruit_SPITFT_Renderer.cpp * * @mainpage Adafruit SPI TFT Displays (and some others) * @@ -92,7 +97,7 @@ #endif // end USE_SPI_DMA -// Possible values for Adafruit_SPITFT.connection: +// Possible values for Adafruit_SPITFT_Renderer.connection: #define TFT_HARD_SPI 0 ///< Display interface = hardware SPI #define TFT_SOFT_SPI 1 ///< Display interface = software SPI #define TFT_PARALLEL 2 ///< Display interface = 8- or 16-bit parallel @@ -101,7 +106,7 @@ // CONSTRUCTORS ------------------------------------------------------------ /*! - @brief Adafruit_SPITFT constructor for software (bitbang) SPI. + @brief Adafruit_SPITFT_Renderer constructor for software (bitbang) SPI. @param w Display width in pixels at default rotation setting (0). @param h Display height in pixels at default rotation setting (0). @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). @@ -112,12 +117,12 @@ can be tied to MCU reset, default of -1 means unused). @param miso Arduino pin # for bitbang SPI MISO signal (optional, -1 default, many displays don't support SPI read). - @return Adafruit_SPITFT object. + @return Adafruit_SPITFT_Renderer object. @note Output pins are not initialized; application typically will need to call subclass' begin() function, which in turn calls this library's initSPI() function to initialize pins. */ -Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, +Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst, int8_t miso) : Renderer(w, h), connection(TFT_SOFT_SPI), _rst(rst), _cs(cs), _dc(dc) { swspi._sck = sck; @@ -223,7 +228,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, } /*! - @brief Adafruit_SPITFT constructor for hardware SPI using the board's + @brief Adafruit_SPITFT_Renderer constructor for hardware SPI using the board's default SPI peripheral. @param w Display width in pixels at default rotation setting (0). @param h Display height in pixels at default rotation setting (0). @@ -231,20 +236,20 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, @param dc Arduino pin # for data/command select (required). @param rst Arduino pin # for display reset (optional, display reset can be tied to MCU reset, default of -1 means unused). - @return Adafruit_SPITFT object. + @return Adafruit_SPITFT_Renderer object. @note Output pins are not initialized; application typically will need to call subclass' begin() function, which in turn calls this library's initSPI() function to initialize pins. */ #if defined(ESP8266) // See notes below -Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, +Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, int8_t dc, int8_t rst) : Renderer(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { hwspi._spi = &SPI; } #else // !ESP8266 -Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, - int8_t dc, int8_t rst) : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst) { +Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, + int8_t dc, int8_t rst) : Adafruit_SPITFT_Renderer(w, h, &SPI, cs, dc, rst) { // This just invokes the hardware SPI constructor below, // passing the default SPI device (&SPI). } @@ -258,7 +263,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, // but if there's any library out there that creates a 'virtual' SPIClass // peripheral and drives it with software bitbanging, that's not supported. /*! - @brief Adafruit_SPITFT constructor for hardware SPI using a specific + @brief Adafruit_SPITFT_Renderer constructor for hardware SPI using a specific SPI peripheral. @param w Display width in pixels at default rotation (0). @param h Display height in pixels at default rotation (0). @@ -267,7 +272,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, @param dc Arduino pin # for data/command select (required). @param rst Arduino pin # for display reset (optional, display reset can be tied to MCU reset, default of -1 means unused). - @return Adafruit_SPITFT object. + @return Adafruit_SPITFT_Renderer object. @note Output pins are not initialized in constructor; application typically will need to call subclass' begin() function, which in turn calls this library's initSPI() function to initialize @@ -279,7 +284,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, GPIO manually. Do this BEFORE calling the display-specific begin or init function. Unfortunate but unavoidable. */ -Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, +Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst) : Renderer(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { hwspi._spi = spiClass; @@ -344,13 +349,13 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, #endif // end !ESP8266 /*! - @brief Adafruit_SPITFT constructor for parallel display connection. + @brief Adafruit_SPITFT_Renderer constructor for parallel display connection. @param w Display width in pixels at default rotation (0). @param h Display height in pixels at default rotation (0). @param busWidth If tft16 (enumeration in header file), is a 16-bit parallel connection, else 8-bit. 16-bit isn't fully implemented or tested yet so - applications should pass "tft8bitbus" for now...needed to + applications should pass "tft8bitbus_Renderer" for now...needed to stick a required enum argument in there to disambiguate this constructor from the soft-SPI case. Argument is ignored on 8-bit architectures (no 'wide' @@ -367,7 +372,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, @param rst Arduino pin # for display reset (optional, display reset can be tied to MCU reset, default of -1 means unused). @param rd Arduino pin # for read strobe (optional, -1 if unused). - @return Adafruit_SPITFT object. + @return Adafruit_SPITFT_Renderer object. @note Output pins are not initialized; application typically will need to call subclass' begin() function, which in turn calls this library's initSPI() function to initialize pins. @@ -375,13 +380,13 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, only SPI displays, parallel being a recent addition (but not wanting to break existing code). */ -Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, +Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, tftBusWidth_Renderer busWidth, int8_t d0, int8_t wr, int8_t dc, int8_t cs, int8_t rst, int8_t rd) : Renderer(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), _dc(dc) { tft8._d0 = d0; tft8._wr = wr; tft8._rd = rd; - tft8.wide = (busWidth == tft16bitbus); + tft8.wide = (busWidth == tft16bitbus_Renderer); #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) #if defined(CORE_TEENSY) @@ -523,7 +528,7 @@ Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, could probably be made private...quite a few class functions were generously put in the public section. */ -void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) { +void Adafruit_SPITFT_Renderer::initSPI(uint32_t freq, uint8_t spiMode) { if(!freq) freq = DEFAULT_SPI_FREQ; // If no freq specified, use default @@ -893,7 +898,7 @@ void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) { using hardware SPI and transactions are supported). Required for all display types; not an SPI-specific function. */ -void Adafruit_SPITFT::startWrite(void) { +void Adafruit_SPITFT_Renderer::startWrite(void) { SPI_BEGIN_TRANSACTION(); if(_cs >= 0) SPI_CS_LOW(); } @@ -904,7 +909,7 @@ void Adafruit_SPITFT::startWrite(void) { using hardware SPI and transactions are supported). Required for all display types; not an SPI-specific function. */ -void Adafruit_SPITFT::endWrite(void) { +void Adafruit_SPITFT_Renderer::endWrite(void) { if(_cs >= 0) SPI_CS_HIGH(); SPI_END_TRANSACTION(); } @@ -925,7 +930,7 @@ void Adafruit_SPITFT::endWrite(void) { @param y Vertical position (0 = top). @param color 16-bit pixel color in '565' RGB format. */ -void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) { +void Adafruit_SPITFT_Renderer::writePixel(int16_t x, int16_t y, uint16_t color) { if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { setAddrWindow(x, y, 1, 1); SPI_WRITE16(color); @@ -960,7 +965,7 @@ void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) { covered...this is really here only for SAMD DMA and much forethought on the application side. */ -void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, +void Adafruit_SPITFT_Renderer::writePixels(uint16_t *colors, uint32_t len, bool block, bool bigEndian) { if(!len) return; // Avoid 0-byte transfers @@ -1069,7 +1074,7 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, is not enabled, and is not needed if blocking writePixels() was used (as is the default case). */ -void Adafruit_SPITFT::dmaWait(void) { +void Adafruit_SPITFT_Renderer::dmaWait(void) { #if defined(USE_SPI_DMA) while(dma_busy); #if defined(__SAMD51__) || defined(_SAMD21_) @@ -1089,7 +1094,7 @@ void Adafruit_SPITFT::dmaWait(void) { @param color 16-bit pixel color in '565' RGB format. @param len Number of pixels to draw. */ -void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) { +void Adafruit_SPITFT_Renderer::writeColor(uint16_t color, uint32_t len) { if(!len) return; // Avoid 0-byte transfers @@ -1342,7 +1347,7 @@ void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) { optimize for the 'if' case, not the 'else' -- avoids branches and rejects clipped rectangles at the least-work possibility. */ -void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, +void Adafruit_SPITFT_Renderer::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { if(w && h) { // Nonzero width and height? if(w < 0) { // If negative width... @@ -1384,7 +1389,7 @@ void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, negative = point of first corner). @param color 16-bit line color in '565' RGB format. */ -void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, +void inline Adafruit_SPITFT_Renderer::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width if(w < 0) { // If negative width... @@ -1415,7 +1420,7 @@ void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, negative = above first point). @param color 16-bit line color in '565' RGB format. */ -void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, +void inline Adafruit_SPITFT_Renderer::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height if(h < 0) { // If negative height... @@ -1454,7 +1459,7 @@ void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, @note This is a new function, no graphics primitives besides rects and horizontal/vertical lines are written to best use this yet. */ -inline void Adafruit_SPITFT::writeFillRectPreclipped(int16_t x, int16_t y, +inline void Adafruit_SPITFT_Renderer::writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { setAddrWindow(x, y, w, h); writeColor(color, (uint32_t)w * h); @@ -1478,7 +1483,7 @@ inline void Adafruit_SPITFT::writeFillRectPreclipped(int16_t x, int16_t y, @param y Vertical position (0 = top). @param color 16-bit pixel color in '565' RGB format. */ -void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color) { +void Adafruit_SPITFT_Renderer::drawPixel(int16_t x, int16_t y, uint16_t color) { // Clip first... if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { // THEN set up transaction (if needed) and draw... @@ -1508,7 +1513,7 @@ void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color) { performed at all if the rectangle is rejected. It's really not that much code. */ -void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, +void Adafruit_SPITFT_Renderer::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { if(w && h) { // Nonzero width and height? if(w < 0) { // If negative width... @@ -1556,7 +1561,7 @@ void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, writeFastHLine() to handle clipping and so forth) so that the transaction isn't performed at all if the line is rejected. */ -void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, int16_t w, +void Adafruit_SPITFT_Renderer::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width if(w < 0) { // If negative width... @@ -1592,7 +1597,7 @@ void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, int16_t w, writeFastVLine() to handle clipping and so forth) so that the transaction isn't performed at all if the line is rejected. */ -void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, int16_t h, +void Adafruit_SPITFT_Renderer::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height if(h < 0) { // If negative height... @@ -1620,7 +1625,7 @@ void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, int16_t h, any user code relies on it. Consider it DEPRECATED. @param color 16-bit pixel color in '565' RGB format. */ -void Adafruit_SPITFT::pushColor(uint16_t color) { +void Adafruit_SPITFT_Renderer::pushColor(uint16_t color) { startWrite(); SPI_WRITE16(color); endWrite(); @@ -1642,7 +1647,7 @@ void Adafruit_SPITFT::pushColor(uint16_t color) { @param w Width of bitmap in pixels. @param h Height of bitmap in pixels. */ -void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y, +void Adafruit_SPITFT_Renderer::drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w, int16_t h) { int16_t x2, y2; // Lower-right coord @@ -1685,7 +1690,7 @@ void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y, Self-contained, no transaction setup required. @param i true = inverted display, false = normal display. */ -void Adafruit_SPITFT::invertDisplay(bool i) { +void Adafruit_SPITFT_Renderer::invertDisplay(bool i) { startWrite(); writeCommand(i ? invertOnCommand : invertOffCommand); endWrite(); @@ -1701,17 +1706,17 @@ void Adafruit_SPITFT::invertDisplay(bool i) { @param blue 8-bit blue brightnesss (0 = off, 255 = max). @return 'Packed' 16-bit color value (565 format). */ -uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) { +uint16_t Adafruit_SPITFT_Renderer::color565(uint8_t red, uint8_t green, uint8_t blue) { return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); } /*! - @brief Adafruit_SPITFT Send Command handles complete sending of commands and data + @brief Adafruit_SPITFT_Renderer Send Command handles complete sending of commands and data @param commandByte The Command Byte @param dataBytes A pointer to the Data bytes to send @param numDataBytes The number of bytes we should send */ -void Adafruit_SPITFT::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8_t numDataBytes) { +void Adafruit_SPITFT_Renderer::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8_t numDataBytes) { SPI_BEGIN_TRANSACTION(); if(_cs >= 0) SPI_CS_LOW(); @@ -1729,12 +1734,12 @@ void Adafruit_SPITFT::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8 } /*! - @brief Adafruit_SPITFT Send Command handles complete sending of commands and const data + @brief Adafruit_SPITFT_Renderer Send Command handles complete sending of commands and const data @param commandByte The Command Byte @param dataBytes A pointer to the Data bytes to send @param numDataBytes The number of bytes we should send */ -void Adafruit_SPITFT::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) { +void Adafruit_SPITFT_Renderer::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) { SPI_BEGIN_TRANSACTION(); if(_cs >= 0) SPI_CS_LOW(); @@ -1761,7 +1766,7 @@ void Adafruit_SPITFT::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, @return Unsigned 8-bit data read from display register. */ /**************************************************************************/ -uint8_t Adafruit_SPITFT::readcommand8(uint8_t commandByte, uint8_t index) { +uint8_t Adafruit_SPITFT_Renderer::readcommand8(uint8_t commandByte, uint8_t index) { uint8_t result; startWrite(); SPI_DC_LOW(); // Command mode @@ -1788,7 +1793,7 @@ uint8_t Adafruit_SPITFT::readcommand8(uint8_t commandByte, uint8_t index) { chip-select operation -- see startWrite() for a function that encapsulated both actions. */ -inline void Adafruit_SPITFT::SPI_BEGIN_TRANSACTION(void) { +inline void Adafruit_SPITFT_Renderer::SPI_BEGIN_TRANSACTION(void) { if(connection == TFT_HARD_SPI) { #if defined(SPI_HAS_TRANSACTION) hwspi._spi->beginTransaction(hwspi.settings); @@ -1816,7 +1821,7 @@ inline void Adafruit_SPITFT::SPI_BEGIN_TRANSACTION(void) { NOT include a chip-deselect operation -- see endWrite() for a function that encapsulated both actions. */ -inline void Adafruit_SPITFT::SPI_END_TRANSACTION(void) { +inline void Adafruit_SPITFT_Renderer::SPI_END_TRANSACTION(void) { #if defined(SPI_HAS_TRANSACTION) if(connection == TFT_HARD_SPI) { hwspi._spi->endTransaction(); @@ -1833,7 +1838,7 @@ inline void Adafruit_SPITFT::SPI_END_TRANSACTION(void) { This function is used even if display connection is parallel. @param b 8-bit value to write. */ -void Adafruit_SPITFT::spiWrite(uint8_t b) { +void Adafruit_SPITFT_Renderer::spiWrite(uint8_t b) { if(connection == TFT_HARD_SPI) { #if defined(__AVR__) AVR_WRITESPI(b); @@ -1869,7 +1874,7 @@ void Adafruit_SPITFT::spiWrite(uint8_t b) { function -- just use spiWrite(). @param cmd 8-bit command to write. */ -void Adafruit_SPITFT::writeCommand(uint8_t cmd) { +void Adafruit_SPITFT_Renderer::writeCommand(uint8_t cmd) { SPI_DC_LOW(); spiWrite(cmd); SPI_DC_HIGH(); @@ -1885,7 +1890,7 @@ void Adafruit_SPITFT::writeCommand(uint8_t cmd) { @return Unsigned 8-bit value read (always zero if USE_FAST_PINIO is not supported by the MCU architecture). */ -uint8_t Adafruit_SPITFT::spiRead(void) { +uint8_t Adafruit_SPITFT_Renderer::spiRead(void) { uint8_t b = 0; uint16_t w = 0; if(connection == TFT_HARD_SPI) { @@ -1943,7 +1948,7 @@ uint8_t Adafruit_SPITFT::spiRead(void) { /*! @brief Set the software (bitbang) SPI MOSI line HIGH. */ -inline void Adafruit_SPITFT::SPI_MOSI_HIGH(void) { +inline void Adafruit_SPITFT_Renderer::SPI_MOSI_HIGH(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) #if defined(KINETISK) @@ -1965,7 +1970,7 @@ inline void Adafruit_SPITFT::SPI_MOSI_HIGH(void) { /*! @brief Set the software (bitbang) SPI MOSI line LOW. */ -inline void Adafruit_SPITFT::SPI_MOSI_LOW(void) { +inline void Adafruit_SPITFT_Renderer::SPI_MOSI_LOW(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) #if defined(KINETISK) @@ -1987,7 +1992,7 @@ inline void Adafruit_SPITFT::SPI_MOSI_LOW(void) { /*! @brief Set the software (bitbang) SPI SCK line HIGH. */ -inline void Adafruit_SPITFT::SPI_SCK_HIGH(void) { +inline void Adafruit_SPITFT_Renderer::SPI_SCK_HIGH(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) #if defined(KINETISK) @@ -2012,7 +2017,7 @@ inline void Adafruit_SPITFT::SPI_SCK_HIGH(void) { /*! @brief Set the software (bitbang) SPI SCK line LOW. */ -inline void Adafruit_SPITFT::SPI_SCK_LOW(void) { +inline void Adafruit_SPITFT_Renderer::SPI_SCK_LOW(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) #if defined(KINETISK) @@ -2038,7 +2043,7 @@ inline void Adafruit_SPITFT::SPI_SCK_LOW(void) { @brief Read the state of the software (bitbang) SPI MISO line. @return true if HIGH, false if LOW. */ -inline bool Adafruit_SPITFT::SPI_MISO_READ(void) { +inline bool Adafruit_SPITFT_Renderer::SPI_MISO_READ(void) { #if defined(USE_FAST_PINIO) #if defined(KINETISK) return *swspi.misoPort; @@ -2060,7 +2065,7 @@ inline bool Adafruit_SPITFT::SPI_MISO_READ(void) { that. Again, staying compatible with outside code. @param w 16-bit value to write. */ -void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) { +void Adafruit_SPITFT_Renderer::SPI_WRITE16(uint16_t w) { if(connection == TFT_HARD_SPI) { #if defined(__AVR__) AVR_WRITESPI(w >> 8); @@ -2107,7 +2112,7 @@ void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) { Sorry about that. Again, staying compatible with outside code. @param l 32-bit value to write. */ -void Adafruit_SPITFT::SPI_WRITE32(uint32_t l) { +void Adafruit_SPITFT_Renderer::SPI_WRITE32(uint32_t l) { if(connection == TFT_HARD_SPI) { #if defined(__AVR__) AVR_WRITESPI(l >> 24); @@ -2162,7 +2167,7 @@ void Adafruit_SPITFT::SPI_WRITE32(uint32_t l) { @brief Set the WR line LOW, then HIGH. Used for parallel-connected interfaces when writing data. */ -inline void Adafruit_SPITFT::TFT_WR_STROBE(void) { +inline void Adafruit_SPITFT_Renderer::TFT_WR_STROBE(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) #if defined(KINETISK) @@ -2186,7 +2191,7 @@ inline void Adafruit_SPITFT::TFT_WR_STROBE(void) { @brief Set the RD line HIGH. Used for parallel-connected interfaces when reading data. */ -inline void Adafruit_SPITFT::TFT_RD_HIGH(void) { +inline void Adafruit_SPITFT_Renderer::TFT_RD_HIGH(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) *tft8.rdPortSet = tft8.rdPinMask; @@ -2202,7 +2207,7 @@ inline void Adafruit_SPITFT::TFT_RD_HIGH(void) { @brief Set the RD line LOW. Used for parallel-connected interfaces when reading data. */ -inline void Adafruit_SPITFT::TFT_RD_LOW(void) { +inline void Adafruit_SPITFT_Renderer::TFT_RD_LOW(void) { #if defined(USE_FAST_PINIO) #if defined(HAS_PORT_SET_CLR) *tft8.rdPortClr = tft8.rdPinMask; diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h index dcfc1646b..ce8f26d73 100644 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h @@ -1,5 +1,10 @@ +/* + * This class is basically the same as Adafruit_SPITFT. + * The only difference is: it extends Renderer which extends Adafruit_GFX. + * The original Adafruit_SPITFT class directly extends Adafruit_GFX. + */ /*! - * @file Adafruit_SPITFT.h + * @file Adafruit_SPITFT_Renderer.h * * Part of Adafruit's GFX graphics library. Originally this class was * written to handle a range of color TFT displays connected via SPI, @@ -17,8 +22,8 @@ * BSD license, all text here must be included in any redistribution. */ -#ifndef _ADAFRUIT_SPITFT_H_ -#define _ADAFRUIT_SPITFT_H_ +#ifndef _ADAFRUIT_SPITFT_RENDERER_H_ +#define _ADAFRUIT_SPITFT_RENDERER_H_ #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all @@ -100,7 +105,7 @@ typedef volatile ADAGFX_PORT_t* PORTreg_t; ///< PORT register type // an enumerated type as the first argument: tft8 (for 8-bit parallel) or // tft16 (for 16-bit)...even though 16-bit isn't fully implemented or tested // and might never be, still needed that disambiguation from soft SPI. -enum tftBusWidth { tft8bitbus, tft16bitbus }; ///< For first arg to parallel constructor +enum tftBusWidth_Renderer { tft8bitbus_Renderer, tft16bitbus_Renderer }; ///< For first arg to parallel constructor // CLASS DEFINITION -------------------------------------------------------- @@ -117,7 +122,7 @@ enum tftBusWidth { tft8bitbus, tft16bitbus }; ///< For first arg to parallel con again to avoid breaking a lot of other code. If in doubt, read the comments. */ -class Adafruit_SPITFT : public Renderer { +class Adafruit_SPITFT_Renderer : public Renderer { public: @@ -128,7 +133,7 @@ class Adafruit_SPITFT : public Renderer { // (reset, miso). cs argument is required but can be -1 if unused -- // rather than moving it to the optional arguments, it was done this way // to avoid breaking existing code (-1 option was a later addition). - Adafruit_SPITFT(uint16_t w, uint16_t h, + Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst = -1, int8_t miso = -1); @@ -137,14 +142,14 @@ class Adafruit_SPITFT : public Renderer { // optional reset pin. cs is required but can be -1 if unused -- rather // than moving it to the optional arguments, it was done this way to // avoid breaking existing code (-1 option was a later addition). - Adafruit_SPITFT(uint16_t w, uint16_t h, + Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, int8_t dc, int8_t rst = -1); #if !defined(ESP8266) // See notes in .cpp // Hardware SPI constructor using an arbitrary SPI peripheral: expects // width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc) // and optional reset pin. cs is required but can be -1 if unused. - Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, + Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst = -1); #endif // end !ESP8266 @@ -153,7 +158,7 @@ class Adafruit_SPITFT : public Renderer { // pins (d0, wr, dc), 3 optional pins (cs, rst, rd). 16-bit parallel // isn't even fully implemented but the 'wide' flag was added as a // required argument to avoid ambiguity with other constructors. - Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, + Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, tftBusWidth_Renderer busWidth, int8_t d0, int8_t wr, int8_t dc, int8_t cs = -1, int8_t rst = -1, int8_t rd = -1); diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp index 78d9901d6..799d87a79 100644 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp @@ -146,7 +146,7 @@ void Adafruit_SSD1331::begin(uint32_t freq) { /**************************************************************************/ Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, int8_t sclk, int8_t rst) - : Adafruit_SPITFT(TFTWIDTH, TFTHEIGHT, cs, dc, mosi, sclk, rst, -1) {} + : Adafruit_SPITFT_Renderer(TFTWIDTH, TFTHEIGHT, cs, dc, mosi, sclk, rst, -1) {} /**************************************************************************/ /*! @@ -157,7 +157,7 @@ Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, */ /**************************************************************************/ Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst) - : Adafruit_SPITFT(TFTWIDTH, TFTHEIGHT, cs, dc, rst) {} + : Adafruit_SPITFT_Renderer(TFTWIDTH, TFTHEIGHT, cs, dc, rst) {} /**************************************************************************/ /*! @@ -173,9 +173,9 @@ Adafruit_SSD1331::Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, int8_t rst) : #if defined(ESP8266) - Adafruit_SPITFT(TFTWIDTH, TFTWIDTH, cs, dc, rst) { + Adafruit_SPITFT_Renderer(TFTWIDTH, TFTWIDTH, cs, dc, rst) { #else - Adafruit_SPITFT(TFTWIDTH, TFTWIDTH, spi, cs, dc, rst) { + Adafruit_SPITFT_Renderer(TFTWIDTH, TFTWIDTH, spi, cs, dc, rst) { #endif } diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h index 7d9bc85a0..e427615c3 100644 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h @@ -55,7 +55,7 @@ #define SSD1331_CMD_VCOMH 0xBE //!< Set Vcomh voltge /// Class to manage hardware interface with SSD1331 chipset -class Adafruit_SSD1331 : public Adafruit_SPITFT { +class Adafruit_SSD1331 : public Adafruit_SPITFT_Renderer { public: Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, int8_t sclk, int8_t rst); Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst); diff --git a/tasmota/xdsp_14_SSD1331.ino b/tasmota/xdsp_14_SSD1331.ino index be5417426..a7e48eae8 100644 --- a/tasmota/xdsp_14_SSD1331.ino +++ b/tasmota/xdsp_14_SSD1331.ino @@ -19,7 +19,7 @@ #ifdef USE_SPI #ifdef USE_DISPLAY -#ifdef USE_DISPLAY_SSD1331 +#ifdef USE_DISPLAY_SSD1331 // This driver eats 5.3 K flash #define XDSP_14 14 @@ -87,6 +87,7 @@ void SSD1331_InitDriver() { renderer->setTextFont(1); renderer->DrawStringAt(24, 27, "SSD1331", SSD1331_RED, 0); delay(1000); + renderer->clearDisplay(); #endif color_type = COLOR_COLOR; @@ -139,10 +140,11 @@ void SSD1331Time(void) { char line[12]; renderer->clearDisplay(); - renderer->setCursor(0, 0); snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ] + renderer->setCursor(17, 20); renderer->println(line); snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018] + renderer->setCursor(17, 35); renderer->println(line); renderer->Updateframe(); } From be5d9f90a8f415b2a301ac63be68978fe8be3b77 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 3 Jan 2021 15:09:20 +0100 Subject: [PATCH 15/78] Zigbee replace qsort with insertion sort --- tasmota/xdrv_23_zigbee_5__constants.ino | 1524 +++++++++++------------ tasmota/xdrv_23_zigbee_A_impl.ino | 74 +- 2 files changed, 803 insertions(+), 795 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_5__constants.ino b/tasmota/xdrv_23_zigbee_5__constants.ino index fdd161c50..a5c223b2b 100644 --- a/tasmota/xdrv_23_zigbee_5__constants.ino +++ b/tasmota/xdrv_23_zigbee_5__constants.ino @@ -75,844 +75,844 @@ def strings_to_pmem(arg): const char Z_strings[] PROGMEM = "\x00" - "ZCLVersion" "\x00" - "AppVersion" "\x00" - "StackVersion" "\x00" - "HWVersion" "\x00" - "Manufacturer" "\x00" - "ModelId" "\x00" - "DateCode" "\x00" - "PowerSource" "\x00" - "GenericDeviceClass" "\x00" - "GenericDeviceType" "\x00" - "ProductCode" "\x00" - "ProductURL" "\x00" - "SWBuildID" "\x00" - "MainsVoltage" "\x00" - "MainsFrequency" "\x00" - "BatteryVoltage" "\x00" - "BatteryPercentage" "\x00" - "CurrentTemperature" "\x00" - "MinTempExperienced" "\x00" - "MaxTempExperienced" "\x00" - "OverTempTotalDwell" "\x00" - "IdentifyTime" "\x00" - "GroupNameSupport" "\x00" - "SceneCount" "\x00" - "CurrentScene" "\x00" - "CurrentGroup" "\x00" - "SceneValid" "\x00" - "Power" "\x00" - "StartUpOnOff" "\x00" - "SwitchType" "\x00" - "Dimmer" "\x00" - "DimmerOptions" "\x00" - "DimmerRemainingTime" "\x00" - "OnOffTransitionTime" "\x00" + "00" "\x00" + "00190200" "\x00" + "00xx0A00" "\x00" + "00xxxx000000000000" "\x00" + "01" "\x00" + "01190200" "\x00" + "01xx0A00" "\x00" + "01xxxx" "\x00" + "01xxxx000000000000" "\x00" + "01xxxx0A0000000000" "\x00" + "03xx0A00" "\x00" + "03xxxx000000000000" "\x00" + "03xxxx0A0000000000" "\x00" + "AccelerationTimeLift" "\x00" + "ActivePower" "\x00" + "ActuatorEnabled" "\x00" + "AddGroup" "\x00" + "AddScene" "\x00" "AlarmCount" "\x00" - "Time" "\x00" - "TimeStatus" "\x00" - "TimeZone" "\x00" - "DstStart" "\x00" - "DstEnd" "\x00" - "DstShift" "\x00" - "StandardTime" "\x00" - "LocalTime" "\x00" - "LastSetTime" "\x00" - "ValidUntilTime" "\x00" - "TimeEpoch" "\x00" - "LocationType" "\x00" - "LocationMethod" "\x00" - "LocationAge" "\x00" - "QualityMeasure" "\x00" - "NumberOfDevices" "\x00" + "AnalogApplicationType" "\x00" + "AnalogDescription" "\x00" + "AnalogEngineeringUnits" "\x00" + "AnalogInApplicationType" "\x00" "AnalogInDescription" "\x00" + "AnalogInEngineeringUnits" "\x00" "AnalogInMaxValue" "\x00" "AnalogInMinValue" "\x00" "AnalogInOutOfService" "\x00" - "AnalogValue" "\x00" "AnalogInReliability" "\x00" "AnalogInResolution" "\x00" "AnalogInStatusFlags" "\x00" - "AnalogInEngineeringUnits" "\x00" - "AnalogInApplicationType" "\x00" - "AqaraRotate" "\x00" - "Aqara_FF05" "\x00" + "AnalogOutApplicationType" "\x00" "AnalogOutDescription" "\x00" + "AnalogOutEngineeringUnits" "\x00" "AnalogOutMaxValue" "\x00" "AnalogOutMinValue" "\x00" + "AnalogOutOfService" "\x00" "AnalogOutOutOfService" "\x00" - "AnalogOutValue" "\x00" "AnalogOutReliability" "\x00" "AnalogOutRelinquishDefault" "\x00" "AnalogOutResolution" "\x00" "AnalogOutStatusFlags" "\x00" - "AnalogOutEngineeringUnits" "\x00" - "AnalogOutApplicationType" "\x00" - "AnalogDescription" "\x00" - "AnalogOutOfService" "\x00" + "AnalogOutValue" "\x00" "AnalogPriorityArray" "\x00" "AnalogReliability" "\x00" "AnalogRelinquishDefault" "\x00" "AnalogStatusFlags" "\x00" - "AnalogEngineeringUnits" "\x00" - "AnalogApplicationType" "\x00" + "AnalogValue" "\x00" + "AppVersion" "\x00" + "ApparentPower" "\x00" + "AqaraAccelerometer" "\x00" + "AqaraRotate" "\x00" + "AqaraVibration505" "\x00" + "AqaraVibrationMode" "\x00" + "AqaraVibrationsOrAngle" "\x00" + "Aqara_FF05" "\x00" + "ArrowClick" "\x00" + "ArrowHold" "\x00" + "ArrowRelease" "\x00" + "AvailablePower" "\x00" + "BatteryPercentage" "\x00" + "BatteryVoltage" "\x00" + "BinaryActiveText" "\x00" + "BinaryApplicationType" "\x00" + "BinaryDescription" "\x00" "BinaryInActiveText" "\x00" + "BinaryInApplicationType" "\x00" "BinaryInDescription" "\x00" "BinaryInInactiveText" "\x00" "BinaryInOutOfService" "\x00" "BinaryInPolarity" "\x00" - "BinaryInValue" "\x00" "BinaryInReliability" "\x00" "BinaryInStatusFlags" "\x00" - "BinaryInApplicationType" "\x00" + "BinaryInValue" "\x00" + "BinaryInactiveText" "\x00" + "BinaryMinimumOffTime" "\x00" + "BinaryMinimumOnTime" "\x00" "BinaryOutActiveText" "\x00" + "BinaryOutApplicationType" "\x00" "BinaryOutDescription" "\x00" "BinaryOutInactiveText" "\x00" "BinaryOutMinimumOffTime" "\x00" "BinaryOutMinimumOnTime" "\x00" + "BinaryOutOfService" "\x00" "BinaryOutOutOfService" "\x00" "BinaryOutPolarity" "\x00" - "BinaryOutValue" "\x00" "BinaryOutReliability" "\x00" "BinaryOutRelinquishDefault" "\x00" "BinaryOutStatusFlags" "\x00" - "BinaryOutApplicationType" "\x00" - "BinaryActiveText" "\x00" - "BinaryDescription" "\x00" - "BinaryInactiveText" "\x00" - "BinaryMinimumOffTime" "\x00" - "BinaryMinimumOnTime" "\x00" - "BinaryOutOfService" "\x00" - "BinaryValue" "\x00" + "BinaryOutValue" "\x00" "BinaryReliability" "\x00" "BinaryRelinquishDefault" "\x00" "BinaryStatusFlags" "\x00" - "BinaryApplicationType" "\x00" + "BinaryValue" "\x00" + "CIE" "\x00" + "CO" "\x00" + "CT" "\x00" + "CheckinInterval" "\x00" + "CheckinIntervalMin" "\x00" + "ClosedLimit" "\x00" + "Color" "\x00" + "ColorMode" "\x00" + "ColorMove" "\x00" + "ColorPointBIntensity" "\x00" + "ColorPointBX" "\x00" + "ColorPointBY" "\x00" + "ColorPointGIntensity" "\x00" + "ColorPointGX" "\x00" + "ColorPointGY" "\x00" + "ColorPointRIntensity" "\x00" + "ColorPointRX" "\x00" + "ColorPointRY" "\x00" + "ColorStep" "\x00" + "ColorTempMove" "\x00" + "ColorTempMoveDown" "\x00" + "ColorTempMoveStop" "\x00" + "ColorTempMoveUp" "\x00" + "ColorTempStep" "\x00" + "ColorTempStepDown" "\x00" + "ColorTempStepUp" "\x00" + "CompanyName" "\x00" + "CompensationText" "\x00" + "ConfigStatus" "\x00" + "Contact" "\x00" + "ControlSequenceOfOperation" "\x00" + "CurrentGroup" "\x00" + "CurrentPositionLift" "\x00" + "CurrentPositionLiftPercentage" "\x00" + "CurrentPositionTilt" "\x00" + "CurrentPositionTiltPercentage" "\x00" + "CurrentScene" "\x00" + "CurrentTemperature" "\x00" + "CurrentTemperatureSetPoint" "\x00" + "CustomerName" "\x00" + "DataQualityID" "\x00" + "DateCode" "\x00" + "DecelerationTimeLift" "\x00" + "Dimmer" "\x00" + "DimmerDown" "\x00" + "DimmerMove" "\x00" + "DimmerOptions" "\x00" + "DimmerRemainingTime" "\x00" + "DimmerStep" "\x00" + "DimmerStepDown" "\x00" + "DimmerStepUp" "\x00" + "DimmerStop" "\x00" + "DimmerUp" "\x00" + "DoorClosedEvents" "\x00" + "DoorOpenEvents" "\x00" + "DoorState" "\x00" + "DriftCompensation" "\x00" + "DstEnd" "\x00" + "DstShift" "\x00" + "DstStart" "\x00" + "EnergyFormatting" "\x00" + "EnergyRemote" "\x00" + "EnergyTotal" "\x00" + "EurotronicErrors" "\x00" + "EurotronicHostFlags" "\x00" + "FastPollTimeout" "\x00" + "FastPollTimeoutMax" "\x00" + "Fire" "\x00" + "FlowMaxMeasuredValue" "\x00" + "FlowMinMeasuredValue" "\x00" + "FlowRate" "\x00" + "FlowTolerance" "\x00" + "GenericDeviceClass" "\x00" + "GenericDeviceType" "\x00" + "GetAllGroups" "\x00" + "GetGroup" "\x00" + "GetSceneMembership" "\x00" + "GlassBreak" "\x00" + "GroupNameSupport" "\x00" + "HWVersion" "\x00" + "Hue" "\x00" + "HueMove" "\x00" + "HueSat" "\x00" + "HueStep" "\x00" + "HueStepDown" "\x00" + "HueStepUp" "\x00" + "Humidity" "\x00" + "HumidityMaxMeasuredValue" "\x00" + "HumidityMinMeasuredValue" "\x00" + "HumidityTolerance" "\x00" + "Identify" "\x00" + "IdentifyQuery" "\x00" + "IdentifyTime" "\x00" + "Illuminance" "\x00" + "IlluminanceLevelStatus" "\x00" + "IlluminanceLightSensorType" "\x00" + "IlluminanceMaxMeasuredValue" "\x00" + "IlluminanceMinMeasuredValue" "\x00" + "IlluminanceTargetLevel" "\x00" + "IlluminanceTolerance" "\x00" + "InstalledClosedLimitLift" "\x00" + "InstalledClosedLimitTilt" "\x00" + "InstalledOpenLimitLift" "\x00" + "InstalledOpenLimitTilt" "\x00" + "IntermediateSetpointsLift" "\x00" + "IntermediateSetpointsTilt" "\x00" + "LastMessageLQI" "\x00" + "LastMessageRSSI" "\x00" + "LastSetTime" "\x00" + "LocalTemperature" "\x00" + "LocalTemperatureCalibration" "\x00" + "LocalTime" "\x00" + "LocationAge" "\x00" + "LocationMethod" "\x00" + "LocationType" "\x00" + "LockState" "\x00" + "LockType" "\x00" + "LongPollInterval" "\x00" + "LongPollIntervalMin" "\x00" + "MainsFrequency" "\x00" + "MainsVoltage" "\x00" + "Manufacturer" "\x00" + "MaxTempExperienced" "\x00" + "MeterTypeID" "\x00" + "MinTempExperienced" "\x00" + "Mode" "\x00" + "Model" "\x00" + "ModelId" "\x00" + "MotorStepSize" "\x00" + "Movement" "\x00" + "MultiApplicationType" "\x00" + "MultiDescription" "\x00" + "MultiInApplicationType" "\x00" "MultiInDescription" "\x00" "MultiInNumberOfStates" "\x00" "MultiInOutOfService" "\x00" - "MultiInValue" "\x00" "MultiInReliability" "\x00" "MultiInStatusFlags" "\x00" - "MultiInApplicationType" "\x00" + "MultiInValue" "\x00" + "MultiNumberOfStates" "\x00" + "MultiOutApplicationType" "\x00" "MultiOutDescription" "\x00" "MultiOutNumberOfStates" "\x00" + "MultiOutOfService" "\x00" "MultiOutOutOfService" "\x00" - "MultiOutValue" "\x00" "MultiOutReliability" "\x00" "MultiOutRelinquishDefault" "\x00" "MultiOutStatusFlags" "\x00" - "MultiOutApplicationType" "\x00" - "MultiDescription" "\x00" - "MultiNumberOfStates" "\x00" - "MultiOutOfService" "\x00" - "MultiValue" "\x00" + "MultiOutValue" "\x00" "MultiReliability" "\x00" "MultiRelinquishDefault" "\x00" "MultiStatusFlags" "\x00" - "MultiApplicationType" "\x00" - "TotalProfileNum" "\x00" + "MultiValue" "\x00" "MultipleScheduling" "\x00" - "EnergyFormatting" "\x00" - "EnergyRemote" "\x00" - "ScheduleMode" "\x00" - "CheckinInterval" "\x00" - "LongPollInterval" "\x00" - "ShortPollInterval" "\x00" - "FastPollTimeout" "\x00" - "CheckinIntervalMin" "\x00" - "LongPollIntervalMin" "\x00" - "FastPollTimeoutMax" "\x00" - "PhysicalClosedLimit" "\x00" - "MotorStepSize" "\x00" - "Status" "\x00" - "ClosedLimit" "\x00" - "Mode" "\x00" - "LockState" "\x00" - "LockType" "\x00" - "ActuatorEnabled" "\x00" - "DoorState" "\x00" - "DoorOpenEvents" "\x00" - "DoorClosedEvents" "\x00" - "OpenPeriod" "\x00" - "AqaraVibrationMode" "\x00" - "AqaraVibrationsOrAngle" "\x00" - "AqaraVibration505" "\x00" - "AqaraAccelerometer" "\x00" - "WindowCoveringType" "\x00" - "PhysicalClosedLimitLift" "\x00" - "PhysicalClosedLimitTilt" "\x00" - "CurrentPositionLift" "\x00" - "CurrentPositionTilt" "\x00" + "NumberOfDevices" "\x00" + "NumberOfPrimaries" "\x00" + "NumberOfResets" "\x00" "NumberofActuationsLift" "\x00" "NumberofActuationsTilt" "\x00" - "ConfigStatus" "\x00" - "CurrentPositionLiftPercentage" "\x00" - "CurrentPositionTiltPercentage" "\x00" - "InstalledOpenLimitLift" "\x00" - "InstalledClosedLimitLift" "\x00" - "InstalledOpenLimitTilt" "\x00" - "InstalledClosedLimitTilt" "\x00" - "VelocityLift" "\x00" - "AccelerationTimeLift" "\x00" - "DecelerationTimeLift" "\x00" - "IntermediateSetpointsLift" "\x00" - "IntermediateSetpointsTilt" "\x00" - "LocalTemperature" "\x00" - "OutdoorTemperature" "\x00" - "PICoolingDemand" "\x00" - "PIHeatingDemand" "\x00" - "LocalTemperatureCalibration" "\x00" - "OccupiedCoolingSetpoint" "\x00" - "OccupiedHeatingSetpoint" "\x00" - "UnoccupiedCoolingSetpoint" "\x00" - "UnoccupiedHeatingSetpoint" "\x00" - "RemoteSensing" "\x00" - "ControlSequenceOfOperation" "\x00" - "SystemMode" "\x00" - "TRVMode" "\x00" - "ValvePosition" "\x00" - "EurotronicErrors" "\x00" - "CurrentTemperatureSetPoint" "\x00" - "EurotronicHostFlags" "\x00" - "TRVMirrorDisplay" "\x00" - "TRVBoost" "\x00" - "TRVWindowOpen" "\x00" - "TRVChildProtection" "\x00" - "ThSetpoint" "\x00" - "TempTarget" "\x00" - "Hue" "\x00" - "Sat" "\x00" - "RemainingTime" "\x00" - "X" "\x00" - "Y" "\x00" - "DriftCompensation" "\x00" - "CompensationText" "\x00" - "CT" "\x00" - "ColorMode" "\x00" - "NumberOfPrimaries" "\x00" - "Primary1X" "\x00" - "Primary1Y" "\x00" - "Primary1Intensity" "\x00" - "Primary2X" "\x00" - "Primary2Y" "\x00" - "Primary2Intensity" "\x00" - "Primary3X" "\x00" - "Primary3Y" "\x00" - "Primary3Intensity" "\x00" - "WhitePointX" "\x00" - "WhitePointY" "\x00" - "ColorPointRX" "\x00" - "ColorPointRY" "\x00" - "ColorPointRIntensity" "\x00" - "ColorPointGX" "\x00" - "ColorPointGY" "\x00" - "ColorPointGIntensity" "\x00" - "ColorPointBX" "\x00" - "ColorPointBY" "\x00" - "ColorPointBIntensity" "\x00" - "Illuminance" "\x00" - "IlluminanceMinMeasuredValue" "\x00" - "IlluminanceMaxMeasuredValue" "\x00" - "IlluminanceTolerance" "\x00" - "IlluminanceLightSensorType" "\x00" - "IlluminanceLevelStatus" "\x00" - "IlluminanceTargetLevel" "\x00" - "Temperature" "\x00" - "TemperatureMinMeasuredValue" "\x00" - "TemperatureMaxMeasuredValue" "\x00" - "TemperatureTolerance" "\x00" - "Pressure" "\x00" - "PressureMinMeasuredValue" "\x00" - "PressureMaxMeasuredValue" "\x00" - "PressureTolerance" "\x00" - "PressureScaledValue" "\x00" - "PressureMinScaledValue" "\x00" - "PressureMaxScaledValue" "\x00" - "PressureScaledTolerance" "\x00" - "PressureScale" "\x00" - "SeaPressure" "\x00" - "FlowRate" "\x00" - "FlowMinMeasuredValue" "\x00" - "FlowMaxMeasuredValue" "\x00" - "FlowTolerance" "\x00" - "Humidity" "\x00" - "HumidityMinMeasuredValue" "\x00" - "HumidityMaxMeasuredValue" "\x00" - "HumidityTolerance" "\x00" "Occupancy" "\x00" "OccupancySensorType" "\x00" - "ZoneState" "\x00" - "ZoneType" "\x00" - "ZoneStatus" "\x00" - "CIE" "\x00" - "Contact" "\x00" - "Fire" "\x00" - "Water" "\x00" - "CO" "\x00" - "PersonalAlarm" "\x00" - "Movement" "\x00" - "Panic" "\x00" - "GlassBreak" "\x00" - "EnergyTotal" "\x00" - "CompanyName" "\x00" - "MeterTypeID" "\x00" - "DataQualityID" "\x00" - "CustomerName" "\x00" - "Model" "\x00" - "PartNumber" "\x00" - "ProductRevision" "\x00" - "SoftwareRevision" "\x00" - "UtilityName" "\x00" + "OccupiedCoolingSetpoint" "\x00" + "OccupiedHeatingSetpoint" "\x00" + "OnOffTransitionTime" "\x00" + "OpenPeriod" "\x00" + "OppleMode" "\x00" + "OutdoorTemperature" "\x00" + "OverTempTotalDwell" "\x00" + "PICoolingDemand" "\x00" + "PIHeatingDemand" "\x00" "POD" "\x00" - "AvailablePower" "\x00" - "PowerThreshold" "\x00" - "RMSVoltage" "\x00" - "RMSCurrent" "\x00" - "ActivePower" "\x00" - "ReactivePower" "\x00" - "ApparentPower" "\x00" - "NumberOfResets" "\x00" + "Panic" "\x00" + "PartNumber" "\x00" "PersistentMemoryWrites" "\x00" - "LastMessageLQI" "\x00" - "LastMessageRSSI" "\x00" - "TuyaScheduleWorkdays" "\x00" - "TuyaScheduleHolidays" "\x00" + "PersonalAlarm" "\x00" + "PhysicalClosedLimit" "\x00" + "PhysicalClosedLimitLift" "\x00" + "PhysicalClosedLimitTilt" "\x00" + "Power" "\x00" "Power2" "\x00" "Power3" "\x00" "Power4" "\x00" - "TuyaChildLock" "\x00" - "TuyaWindowDetection" "\x00" - "TuyaValveDetection" "\x00" - "TuyaAutoLock" "\x00" - "TuyaTempTarget" "\x00" - "TuyaBattery" "\x00" - "TuyaMinTemp" "\x00" - "TuyaMaxTemp" "\x00" - "TuyaBoostTime" "\x00" - "TuyaComfortTemp" "\x00" - "TuyaEcoTemp" "\x00" - "TuyaValvePosition" "\x00" - "TuyaAwayTemp" "\x00" - "TuyaAwayDays" "\x00" - "TuyaPreset" "\x00" - "TuyaFanMode" "\x00" - "TuyaForceMode" "\x00" - "TuyaWeekSelect" "\x00" - "OppleMode" "\x00" - "TerncyDuration" "\x00" - "TerncyRotate" "\x00" - "Identify" "\x00" - "xxxx" "\x00" - "IdentifyQuery" "\x00" - "AddGroup" "\x00" - "xxxx00" "\x00" - "ViewGroup" "\x00" - "GetGroup" "\x00" - "01xxxx" "\x00" - "GetAllGroups" "\x00" - "00" "\x00" - "RemoveGroup" "\x00" - "RemoveAllGroups" "\x00" - "ViewScene" "\x00" - "xxxxyy" "\x00" - "RemoveScene" "\x00" - "RemoveAllScenes" "\x00" - "RecallScene" "\x00" - "GetSceneMembership" "\x00" "PowerOffEffect" "\x00" - "xxyy" "\x00" "PowerOnRecall" "\x00" "PowerOnTimer" "\x00" - "xxyyyyzzzz" "\x00" - "xx0A00" "\x00" - "DimmerUp" "\x00" - "00190200" "\x00" - "DimmerDown" "\x00" - "01190200" "\x00" - "DimmerStop" "\x00" + "PowerSource" "\x00" + "PowerThreshold" "\x00" + "Pressure" "\x00" + "PressureMaxMeasuredValue" "\x00" + "PressureMaxScaledValue" "\x00" + "PressureMinMeasuredValue" "\x00" + "PressureMinScaledValue" "\x00" + "PressureScale" "\x00" + "PressureScaledTolerance" "\x00" + "PressureScaledValue" "\x00" + "PressureTolerance" "\x00" + "Primary1Intensity" "\x00" + "Primary1X" "\x00" + "Primary1Y" "\x00" + "Primary2Intensity" "\x00" + "Primary2X" "\x00" + "Primary2Y" "\x00" + "Primary3Intensity" "\x00" + "Primary3X" "\x00" + "Primary3Y" "\x00" + "ProductCode" "\x00" + "ProductRevision" "\x00" + "ProductURL" "\x00" + "QualityMeasure" "\x00" + "RMSCurrent" "\x00" + "RMSVoltage" "\x00" + "ReactivePower" "\x00" + "RecallScene" "\x00" + "RemainingTime" "\x00" + "RemoteSensing" "\x00" + "RemoveAllGroups" "\x00" + "RemoveAllScenes" "\x00" + "RemoveGroup" "\x00" + "RemoveScene" "\x00" "ResetAlarm" "\x00" - "xxyyyy" "\x00" "ResetAllAlarms" "\x00" - "xx000A00" "\x00" - "HueSat" "\x00" - "xxyy0A00" "\x00" - "Color" "\x00" - "xxxxyyyy0A00" "\x00" - "xxxx0A00" "\x00" - "ShutterOpen" "\x00" - "ShutterClose" "\x00" - "ShutterStop" "\x00" - "ShutterLift" "\x00" - "xx" "\x00" - "ShutterTilt" "\x00" - "Shutter" "\x00" - "DimmerMove" "\x00" - "xx0A" "\x00" - "DimmerStepUp" "\x00" - "00xx0A00" "\x00" - "DimmerStepDown" "\x00" - "01xx0A00" "\x00" - "DimmerStep" "\x00" - "xx190A00" "\x00" - "01" "\x00" - "HueMove" "\x00" - "xx19" "\x00" - "HueStepUp" "\x00" - "HueStepDown" "\x00" - "03xx0A00" "\x00" - "HueStep" "\x00" + "SWBuildID" "\x00" + "Sat" "\x00" "SatMove" "\x00" "SatStep" "\x00" - "xx190A" "\x00" - "ColorMove" "\x00" - "xxxxyyyy" "\x00" - "ColorStep" "\x00" - "ColorTempMoveUp" "\x00" - "01xxxx000000000000" "\x00" - "ColorTempMoveDown" "\x00" - "03xxxx000000000000" "\x00" - "ColorTempMoveStop" "\x00" - "00xxxx000000000000" "\x00" - "ColorTempMove" "\x00" - "xxyyyy000000000000" "\x00" - "ColorTempStepUp" "\x00" - "01xxxx0A0000000000" "\x00" - "ColorTempStepDown" "\x00" - "03xxxx0A0000000000" "\x00" - "ColorTempStep" "\x00" - "xxyyyy0A0000000000" "\x00" - "ArrowClick" "\x00" - "ArrowHold" "\x00" - "ArrowRelease" "\x00" - "ZoneStatusChange" "\x00" - "xxxxyyzz" "\x00" - "xxyyzzzz" "\x00" - "AddScene" "\x00" - "xxyyyyzz" "\x00" + "SceneCount" "\x00" + "SceneValid" "\x00" + "ScheduleMode" "\x00" + "SeaPressure" "\x00" + "ShortPollInterval" "\x00" + "Shutter" "\x00" + "ShutterClose" "\x00" + "ShutterLift" "\x00" + "ShutterOpen" "\x00" + "ShutterStop" "\x00" + "ShutterTilt" "\x00" + "SoftwareRevision" "\x00" + "StackVersion" "\x00" + "StandardTime" "\x00" + "StartUpOnOff" "\x00" + "Status" "\x00" "StoreScene" "\x00" + "SwitchType" "\x00" + "SystemMode" "\x00" + "TRVBoost" "\x00" + "TRVChildProtection" "\x00" + "TRVMirrorDisplay" "\x00" + "TRVMode" "\x00" + "TRVWindowOpen" "\x00" + "TempTarget" "\x00" + "Temperature" "\x00" + "TemperatureMaxMeasuredValue" "\x00" + "TemperatureMinMeasuredValue" "\x00" + "TemperatureTolerance" "\x00" + "TerncyDuration" "\x00" + "TerncyRotate" "\x00" + "ThSetpoint" "\x00" + "Time" "\x00" + "TimeEpoch" "\x00" + "TimeStatus" "\x00" + "TimeZone" "\x00" + "TotalProfileNum" "\x00" + "TuyaAutoLock" "\x00" + "TuyaAwayDays" "\x00" + "TuyaAwayTemp" "\x00" + "TuyaBattery" "\x00" + "TuyaBoostTime" "\x00" + "TuyaChildLock" "\x00" + "TuyaComfortTemp" "\x00" + "TuyaEcoTemp" "\x00" + "TuyaFanMode" "\x00" + "TuyaForceMode" "\x00" + "TuyaMaxTemp" "\x00" + "TuyaMinTemp" "\x00" + "TuyaPreset" "\x00" + "TuyaScheduleHolidays" "\x00" + "TuyaScheduleWorkdays" "\x00" + "TuyaTempTarget" "\x00" + "TuyaValveDetection" "\x00" + "TuyaValvePosition" "\x00" + "TuyaWeekSelect" "\x00" + "TuyaWindowDetection" "\x00" + "UnoccupiedCoolingSetpoint" "\x00" + "UnoccupiedHeatingSetpoint" "\x00" + "UtilityName" "\x00" + "ValidUntilTime" "\x00" + "ValvePosition" "\x00" + "VelocityLift" "\x00" + "ViewGroup" "\x00" + "ViewScene" "\x00" + "Water" "\x00" + "WhitePointX" "\x00" + "WhitePointY" "\x00" + "WindowCoveringType" "\x00" + "X" "\x00" + "Y" "\x00" + "ZCLVersion" "\x00" + "ZoneState" "\x00" + "ZoneStatus" "\x00" + "ZoneStatusChange" "\x00" + "ZoneType" "\x00" + "xx" "\x00" + "xx000A00" "\x00" + "xx0A" "\x00" + "xx0A00" "\x00" + "xx19" "\x00" + "xx190A" "\x00" + "xx190A00" "\x00" + "xxxx" "\x00" + "xxxx00" "\x00" + "xxxx0A00" "\x00" + "xxxxyy" "\x00" + "xxxxyyyy" "\x00" + "xxxxyyyy0A00" "\x00" + "xxxxyyzz" "\x00" + "xxyy" "\x00" + "xxyy0A00" "\x00" + "xxyyyy" "\x00" + "xxyyyy000000000000" "\x00" + "xxyyyy0A0000000000" "\x00" + "xxyyyyzz" "\x00" + "xxyyyyzzzz" "\x00" + "xxyyzzzz" "\x00" ; enum Z_offsets { Zo_ = 0, - Zo_ZCLVersion = 1, - Zo_AppVersion = 12, - Zo_StackVersion = 23, - Zo_HWVersion = 36, - Zo_Manufacturer = 46, - Zo_ModelId = 59, - Zo_DateCode = 67, - Zo_PowerSource = 76, - Zo_GenericDeviceClass = 88, - Zo_GenericDeviceType = 107, - Zo_ProductCode = 125, - Zo_ProductURL = 137, - Zo_SWBuildID = 148, - Zo_MainsVoltage = 158, - Zo_MainsFrequency = 171, - Zo_BatteryVoltage = 186, - Zo_BatteryPercentage = 201, - Zo_CurrentTemperature = 219, - Zo_MinTempExperienced = 238, - Zo_MaxTempExperienced = 257, - Zo_OverTempTotalDwell = 276, - Zo_IdentifyTime = 295, - Zo_GroupNameSupport = 308, - Zo_SceneCount = 325, - Zo_CurrentScene = 336, - Zo_CurrentGroup = 349, - Zo_SceneValid = 362, - Zo_Power = 373, - Zo_StartUpOnOff = 379, - Zo_SwitchType = 392, - Zo_Dimmer = 403, - Zo_DimmerOptions = 410, - Zo_DimmerRemainingTime = 424, - Zo_OnOffTransitionTime = 444, - Zo_AlarmCount = 464, - Zo_Time = 475, - Zo_TimeStatus = 480, - Zo_TimeZone = 491, - Zo_DstStart = 500, - Zo_DstEnd = 509, - Zo_DstShift = 516, - Zo_StandardTime = 525, - Zo_LocalTime = 538, - Zo_LastSetTime = 548, - Zo_ValidUntilTime = 560, - Zo_TimeEpoch = 575, - Zo_LocationType = 585, - Zo_LocationMethod = 598, - Zo_LocationAge = 613, - Zo_QualityMeasure = 625, - Zo_NumberOfDevices = 640, - Zo_AnalogInDescription = 656, - Zo_AnalogInMaxValue = 676, - Zo_AnalogInMinValue = 693, - Zo_AnalogInOutOfService = 710, - Zo_AnalogValue = 731, - Zo_AnalogInReliability = 743, - Zo_AnalogInResolution = 763, - Zo_AnalogInStatusFlags = 782, - Zo_AnalogInEngineeringUnits = 802, - Zo_AnalogInApplicationType = 827, - Zo_AqaraRotate = 851, - Zo_Aqara_FF05 = 863, - Zo_AnalogOutDescription = 874, - Zo_AnalogOutMaxValue = 895, - Zo_AnalogOutMinValue = 913, - Zo_AnalogOutOutOfService = 931, - Zo_AnalogOutValue = 953, - Zo_AnalogOutReliability = 968, - Zo_AnalogOutRelinquishDefault = 989, - Zo_AnalogOutResolution = 1016, - Zo_AnalogOutStatusFlags = 1036, - Zo_AnalogOutEngineeringUnits = 1057, - Zo_AnalogOutApplicationType = 1083, - Zo_AnalogDescription = 1108, - Zo_AnalogOutOfService = 1126, - Zo_AnalogPriorityArray = 1145, - Zo_AnalogReliability = 1165, - Zo_AnalogRelinquishDefault = 1183, - Zo_AnalogStatusFlags = 1207, - Zo_AnalogEngineeringUnits = 1225, - Zo_AnalogApplicationType = 1248, - Zo_BinaryInActiveText = 1270, - Zo_BinaryInDescription = 1289, - Zo_BinaryInInactiveText = 1309, - Zo_BinaryInOutOfService = 1330, - Zo_BinaryInPolarity = 1351, - Zo_BinaryInValue = 1368, - Zo_BinaryInReliability = 1382, - Zo_BinaryInStatusFlags = 1402, - Zo_BinaryInApplicationType = 1422, - Zo_BinaryOutActiveText = 1446, - Zo_BinaryOutDescription = 1466, - Zo_BinaryOutInactiveText = 1487, - Zo_BinaryOutMinimumOffTime = 1509, - Zo_BinaryOutMinimumOnTime = 1533, - Zo_BinaryOutOutOfService = 1556, - Zo_BinaryOutPolarity = 1578, - Zo_BinaryOutValue = 1596, - Zo_BinaryOutReliability = 1611, - Zo_BinaryOutRelinquishDefault = 1632, - Zo_BinaryOutStatusFlags = 1659, - Zo_BinaryOutApplicationType = 1680, - Zo_BinaryActiveText = 1705, - Zo_BinaryDescription = 1722, - Zo_BinaryInactiveText = 1740, - Zo_BinaryMinimumOffTime = 1759, - Zo_BinaryMinimumOnTime = 1780, - Zo_BinaryOutOfService = 1800, - Zo_BinaryValue = 1819, - Zo_BinaryReliability = 1831, - Zo_BinaryRelinquishDefault = 1849, - Zo_BinaryStatusFlags = 1873, - Zo_BinaryApplicationType = 1891, - Zo_MultiInDescription = 1913, - Zo_MultiInNumberOfStates = 1932, - Zo_MultiInOutOfService = 1954, - Zo_MultiInValue = 1974, - Zo_MultiInReliability = 1987, - Zo_MultiInStatusFlags = 2006, - Zo_MultiInApplicationType = 2025, - Zo_MultiOutDescription = 2048, - Zo_MultiOutNumberOfStates = 2068, - Zo_MultiOutOutOfService = 2091, - Zo_MultiOutValue = 2112, - Zo_MultiOutReliability = 2126, - Zo_MultiOutRelinquishDefault = 2146, - Zo_MultiOutStatusFlags = 2172, - Zo_MultiOutApplicationType = 2192, - Zo_MultiDescription = 2216, - Zo_MultiNumberOfStates = 2233, - Zo_MultiOutOfService = 2253, - Zo_MultiValue = 2271, - Zo_MultiReliability = 2282, - Zo_MultiRelinquishDefault = 2299, - Zo_MultiStatusFlags = 2322, - Zo_MultiApplicationType = 2339, - Zo_TotalProfileNum = 2360, - Zo_MultipleScheduling = 2376, - Zo_EnergyFormatting = 2395, - Zo_EnergyRemote = 2412, - Zo_ScheduleMode = 2425, - Zo_CheckinInterval = 2438, - Zo_LongPollInterval = 2454, - Zo_ShortPollInterval = 2471, - Zo_FastPollTimeout = 2489, - Zo_CheckinIntervalMin = 2505, - Zo_LongPollIntervalMin = 2524, - Zo_FastPollTimeoutMax = 2544, - Zo_PhysicalClosedLimit = 2563, - Zo_MotorStepSize = 2583, - Zo_Status = 2597, - Zo_ClosedLimit = 2604, - Zo_Mode = 2616, - Zo_LockState = 2621, - Zo_LockType = 2631, - Zo_ActuatorEnabled = 2640, - Zo_DoorState = 2656, - Zo_DoorOpenEvents = 2666, - Zo_DoorClosedEvents = 2681, - Zo_OpenPeriod = 2698, - Zo_AqaraVibrationMode = 2709, - Zo_AqaraVibrationsOrAngle = 2728, - Zo_AqaraVibration505 = 2751, - Zo_AqaraAccelerometer = 2769, - Zo_WindowCoveringType = 2788, - Zo_PhysicalClosedLimitLift = 2807, - Zo_PhysicalClosedLimitTilt = 2831, - Zo_CurrentPositionLift = 2855, - Zo_CurrentPositionTilt = 2875, - Zo_NumberofActuationsLift = 2895, - Zo_NumberofActuationsTilt = 2918, - Zo_ConfigStatus = 2941, - Zo_CurrentPositionLiftPercentage = 2954, - Zo_CurrentPositionTiltPercentage = 2984, - Zo_InstalledOpenLimitLift = 3014, - Zo_InstalledClosedLimitLift = 3037, - Zo_InstalledOpenLimitTilt = 3062, - Zo_InstalledClosedLimitTilt = 3085, - Zo_VelocityLift = 3110, - Zo_AccelerationTimeLift = 3123, - Zo_DecelerationTimeLift = 3144, - Zo_IntermediateSetpointsLift = 3165, - Zo_IntermediateSetpointsTilt = 3191, - Zo_LocalTemperature = 3217, - Zo_OutdoorTemperature = 3234, - Zo_PICoolingDemand = 3253, - Zo_PIHeatingDemand = 3269, - Zo_LocalTemperatureCalibration = 3285, - Zo_OccupiedCoolingSetpoint = 3313, - Zo_OccupiedHeatingSetpoint = 3337, - Zo_UnoccupiedCoolingSetpoint = 3361, - Zo_UnoccupiedHeatingSetpoint = 3387, - Zo_RemoteSensing = 3413, - Zo_ControlSequenceOfOperation = 3427, - Zo_SystemMode = 3454, - Zo_TRVMode = 3465, - Zo_ValvePosition = 3473, - Zo_EurotronicErrors = 3487, - Zo_CurrentTemperatureSetPoint = 3504, - Zo_EurotronicHostFlags = 3531, - Zo_TRVMirrorDisplay = 3551, - Zo_TRVBoost = 3568, - Zo_TRVWindowOpen = 3577, - Zo_TRVChildProtection = 3591, - Zo_ThSetpoint = 3610, - Zo_TempTarget = 3621, - Zo_Hue = 3632, - Zo_Sat = 3636, - Zo_RemainingTime = 3640, - Zo_X = 3654, - Zo_Y = 3656, - Zo_DriftCompensation = 3658, - Zo_CompensationText = 3676, - Zo_CT = 3693, - Zo_ColorMode = 3696, - Zo_NumberOfPrimaries = 3706, - Zo_Primary1X = 3724, - Zo_Primary1Y = 3734, - Zo_Primary1Intensity = 3744, - Zo_Primary2X = 3762, - Zo_Primary2Y = 3772, - Zo_Primary2Intensity = 3782, - Zo_Primary3X = 3800, - Zo_Primary3Y = 3810, - Zo_Primary3Intensity = 3820, - Zo_WhitePointX = 3838, - Zo_WhitePointY = 3850, - Zo_ColorPointRX = 3862, - Zo_ColorPointRY = 3875, - Zo_ColorPointRIntensity = 3888, - Zo_ColorPointGX = 3909, - Zo_ColorPointGY = 3922, - Zo_ColorPointGIntensity = 3935, - Zo_ColorPointBX = 3956, - Zo_ColorPointBY = 3969, - Zo_ColorPointBIntensity = 3982, - Zo_Illuminance = 4003, - Zo_IlluminanceMinMeasuredValue = 4015, - Zo_IlluminanceMaxMeasuredValue = 4043, - Zo_IlluminanceTolerance = 4071, - Zo_IlluminanceLightSensorType = 4092, - Zo_IlluminanceLevelStatus = 4119, - Zo_IlluminanceTargetLevel = 4142, - Zo_Temperature = 4165, - Zo_TemperatureMinMeasuredValue = 4177, - Zo_TemperatureMaxMeasuredValue = 4205, - Zo_TemperatureTolerance = 4233, - Zo_Pressure = 4254, - Zo_PressureMinMeasuredValue = 4263, - Zo_PressureMaxMeasuredValue = 4288, - Zo_PressureTolerance = 4313, - Zo_PressureScaledValue = 4331, - Zo_PressureMinScaledValue = 4351, - Zo_PressureMaxScaledValue = 4374, - Zo_PressureScaledTolerance = 4397, - Zo_PressureScale = 4421, - Zo_SeaPressure = 4435, - Zo_FlowRate = 4447, - Zo_FlowMinMeasuredValue = 4456, - Zo_FlowMaxMeasuredValue = 4477, - Zo_FlowTolerance = 4498, - Zo_Humidity = 4512, - Zo_HumidityMinMeasuredValue = 4521, - Zo_HumidityMaxMeasuredValue = 4546, - Zo_HumidityTolerance = 4571, - Zo_Occupancy = 4589, - Zo_OccupancySensorType = 4599, - Zo_ZoneState = 4619, - Zo_ZoneType = 4629, - Zo_ZoneStatus = 4638, - Zo_CIE = 4649, - Zo_Contact = 4653, - Zo_Fire = 4661, - Zo_Water = 4666, - Zo_CO = 4672, - Zo_PersonalAlarm = 4675, - Zo_Movement = 4689, - Zo_Panic = 4698, - Zo_GlassBreak = 4704, - Zo_EnergyTotal = 4715, - Zo_CompanyName = 4727, - Zo_MeterTypeID = 4739, - Zo_DataQualityID = 4751, - Zo_CustomerName = 4765, - Zo_Model = 4778, - Zo_PartNumber = 4784, - Zo_ProductRevision = 4795, - Zo_SoftwareRevision = 4811, - Zo_UtilityName = 4828, - Zo_POD = 4840, - Zo_AvailablePower = 4844, - Zo_PowerThreshold = 4859, - Zo_RMSVoltage = 4874, - Zo_RMSCurrent = 4885, - Zo_ActivePower = 4896, - Zo_ReactivePower = 4908, - Zo_ApparentPower = 4922, - Zo_NumberOfResets = 4936, - Zo_PersistentMemoryWrites = 4951, - Zo_LastMessageLQI = 4974, - Zo_LastMessageRSSI = 4989, - Zo_TuyaScheduleWorkdays = 5005, - Zo_TuyaScheduleHolidays = 5026, - Zo_Power2 = 5047, - Zo_Power3 = 5054, - Zo_Power4 = 5061, - Zo_TuyaChildLock = 5068, - Zo_TuyaWindowDetection = 5082, - Zo_TuyaValveDetection = 5102, - Zo_TuyaAutoLock = 5121, - Zo_TuyaTempTarget = 5134, - Zo_TuyaBattery = 5149, - Zo_TuyaMinTemp = 5161, - Zo_TuyaMaxTemp = 5173, - Zo_TuyaBoostTime = 5185, - Zo_TuyaComfortTemp = 5199, - Zo_TuyaEcoTemp = 5215, - Zo_TuyaValvePosition = 5227, - Zo_TuyaAwayTemp = 5245, - Zo_TuyaAwayDays = 5258, - Zo_TuyaPreset = 5271, - Zo_TuyaFanMode = 5282, - Zo_TuyaForceMode = 5294, - Zo_TuyaWeekSelect = 5308, - Zo_OppleMode = 5323, - Zo_TerncyDuration = 5333, - Zo_TerncyRotate = 5348, - Zo_Identify = 5361, - Zo_xxxx = 5370, - Zo_IdentifyQuery = 5375, - Zo_AddGroup = 5389, - Zo_xxxx00 = 5398, - Zo_ViewGroup = 5405, - Zo_GetGroup = 5415, - Zo_01xxxx = 5424, - Zo_GetAllGroups = 5431, - Zo_00 = 5444, - Zo_RemoveGroup = 5447, - Zo_RemoveAllGroups = 5459, - Zo_ViewScene = 5475, - Zo_xxxxyy = 5485, - Zo_RemoveScene = 5492, - Zo_RemoveAllScenes = 5504, - Zo_RecallScene = 5520, - Zo_GetSceneMembership = 5532, - Zo_PowerOffEffect = 5551, - Zo_xxyy = 5566, - Zo_PowerOnRecall = 5571, - Zo_PowerOnTimer = 5585, - Zo_xxyyyyzzzz = 5598, - Zo_xx0A00 = 5609, - Zo_DimmerUp = 5616, - Zo_00190200 = 5625, - Zo_DimmerDown = 5634, - Zo_01190200 = 5645, - Zo_DimmerStop = 5654, - Zo_ResetAlarm = 5665, - Zo_xxyyyy = 5676, - Zo_ResetAllAlarms = 5683, - Zo_xx000A00 = 5698, - Zo_HueSat = 5707, - Zo_xxyy0A00 = 5714, - Zo_Color = 5723, - Zo_xxxxyyyy0A00 = 5729, - Zo_xxxx0A00 = 5742, - Zo_ShutterOpen = 5751, - Zo_ShutterClose = 5763, - Zo_ShutterStop = 5776, - Zo_ShutterLift = 5788, - Zo_xx = 5800, - Zo_ShutterTilt = 5803, - Zo_Shutter = 5815, - Zo_DimmerMove = 5823, - Zo_xx0A = 5834, - Zo_DimmerStepUp = 5839, - Zo_00xx0A00 = 5852, - Zo_DimmerStepDown = 5861, - Zo_01xx0A00 = 5876, - Zo_DimmerStep = 5885, - Zo_xx190A00 = 5896, - Zo_01 = 5905, - Zo_HueMove = 5908, - Zo_xx19 = 5916, - Zo_HueStepUp = 5921, - Zo_HueStepDown = 5931, - Zo_03xx0A00 = 5943, - Zo_HueStep = 5952, - Zo_SatMove = 5960, - Zo_SatStep = 5968, - Zo_xx190A = 5976, - Zo_ColorMove = 5983, - Zo_xxxxyyyy = 5993, - Zo_ColorStep = 6002, - Zo_ColorTempMoveUp = 6012, - Zo_01xxxx000000000000 = 6028, - Zo_ColorTempMoveDown = 6047, - Zo_03xxxx000000000000 = 6065, - Zo_ColorTempMoveStop = 6084, - Zo_00xxxx000000000000 = 6102, - Zo_ColorTempMove = 6121, - Zo_xxyyyy000000000000 = 6135, - Zo_ColorTempStepUp = 6154, - Zo_01xxxx0A0000000000 = 6170, - Zo_ColorTempStepDown = 6189, - Zo_03xxxx0A0000000000 = 6207, - Zo_ColorTempStep = 6226, - Zo_xxyyyy0A0000000000 = 6240, - Zo_ArrowClick = 6259, - Zo_ArrowHold = 6270, - Zo_ArrowRelease = 6280, - Zo_ZoneStatusChange = 6293, - Zo_xxxxyyzz = 6310, - Zo_xxyyzzzz = 6319, - Zo_AddScene = 6328, - Zo_xxyyyyzz = 6337, - Zo_StoreScene = 6346, + Zo_00 = 1, + Zo_00190200 = 4, + Zo_00xx0A00 = 13, + Zo_00xxxx000000000000 = 22, + Zo_01 = 41, + Zo_01190200 = 44, + Zo_01xx0A00 = 53, + Zo_01xxxx = 62, + Zo_01xxxx000000000000 = 69, + Zo_01xxxx0A0000000000 = 88, + Zo_03xx0A00 = 107, + Zo_03xxxx000000000000 = 116, + Zo_03xxxx0A0000000000 = 135, + Zo_AccelerationTimeLift = 154, + Zo_ActivePower = 175, + Zo_ActuatorEnabled = 187, + Zo_AddGroup = 203, + Zo_AddScene = 212, + Zo_AlarmCount = 221, + Zo_AnalogApplicationType = 232, + Zo_AnalogDescription = 254, + Zo_AnalogEngineeringUnits = 272, + Zo_AnalogInApplicationType = 295, + Zo_AnalogInDescription = 319, + Zo_AnalogInEngineeringUnits = 339, + Zo_AnalogInMaxValue = 364, + Zo_AnalogInMinValue = 381, + Zo_AnalogInOutOfService = 398, + Zo_AnalogInReliability = 419, + Zo_AnalogInResolution = 439, + Zo_AnalogInStatusFlags = 458, + Zo_AnalogOutApplicationType = 478, + Zo_AnalogOutDescription = 503, + Zo_AnalogOutEngineeringUnits = 524, + Zo_AnalogOutMaxValue = 550, + Zo_AnalogOutMinValue = 568, + Zo_AnalogOutOfService = 586, + Zo_AnalogOutOutOfService = 605, + Zo_AnalogOutReliability = 627, + Zo_AnalogOutRelinquishDefault = 648, + Zo_AnalogOutResolution = 675, + Zo_AnalogOutStatusFlags = 695, + Zo_AnalogOutValue = 716, + Zo_AnalogPriorityArray = 731, + Zo_AnalogReliability = 751, + Zo_AnalogRelinquishDefault = 769, + Zo_AnalogStatusFlags = 793, + Zo_AnalogValue = 811, + Zo_AppVersion = 823, + Zo_ApparentPower = 834, + Zo_AqaraAccelerometer = 848, + Zo_AqaraRotate = 867, + Zo_AqaraVibration505 = 879, + Zo_AqaraVibrationMode = 897, + Zo_AqaraVibrationsOrAngle = 916, + Zo_Aqara_FF05 = 939, + Zo_ArrowClick = 950, + Zo_ArrowHold = 961, + Zo_ArrowRelease = 971, + Zo_AvailablePower = 984, + Zo_BatteryPercentage = 999, + Zo_BatteryVoltage = 1017, + Zo_BinaryActiveText = 1032, + Zo_BinaryApplicationType = 1049, + Zo_BinaryDescription = 1071, + Zo_BinaryInActiveText = 1089, + Zo_BinaryInApplicationType = 1108, + Zo_BinaryInDescription = 1132, + Zo_BinaryInInactiveText = 1152, + Zo_BinaryInOutOfService = 1173, + Zo_BinaryInPolarity = 1194, + Zo_BinaryInReliability = 1211, + Zo_BinaryInStatusFlags = 1231, + Zo_BinaryInValue = 1251, + Zo_BinaryInactiveText = 1265, + Zo_BinaryMinimumOffTime = 1284, + Zo_BinaryMinimumOnTime = 1305, + Zo_BinaryOutActiveText = 1325, + Zo_BinaryOutApplicationType = 1345, + Zo_BinaryOutDescription = 1370, + Zo_BinaryOutInactiveText = 1391, + Zo_BinaryOutMinimumOffTime = 1413, + Zo_BinaryOutMinimumOnTime = 1437, + Zo_BinaryOutOfService = 1460, + Zo_BinaryOutOutOfService = 1479, + Zo_BinaryOutPolarity = 1501, + Zo_BinaryOutReliability = 1519, + Zo_BinaryOutRelinquishDefault = 1540, + Zo_BinaryOutStatusFlags = 1567, + Zo_BinaryOutValue = 1588, + Zo_BinaryReliability = 1603, + Zo_BinaryRelinquishDefault = 1621, + Zo_BinaryStatusFlags = 1645, + Zo_BinaryValue = 1663, + Zo_CIE = 1675, + Zo_CO = 1679, + Zo_CT = 1682, + Zo_CheckinInterval = 1685, + Zo_CheckinIntervalMin = 1701, + Zo_ClosedLimit = 1720, + Zo_Color = 1732, + Zo_ColorMode = 1738, + Zo_ColorMove = 1748, + Zo_ColorPointBIntensity = 1758, + Zo_ColorPointBX = 1779, + Zo_ColorPointBY = 1792, + Zo_ColorPointGIntensity = 1805, + Zo_ColorPointGX = 1826, + Zo_ColorPointGY = 1839, + Zo_ColorPointRIntensity = 1852, + Zo_ColorPointRX = 1873, + Zo_ColorPointRY = 1886, + Zo_ColorStep = 1899, + Zo_ColorTempMove = 1909, + Zo_ColorTempMoveDown = 1923, + Zo_ColorTempMoveStop = 1941, + Zo_ColorTempMoveUp = 1959, + Zo_ColorTempStep = 1975, + Zo_ColorTempStepDown = 1989, + Zo_ColorTempStepUp = 2007, + Zo_CompanyName = 2023, + Zo_CompensationText = 2035, + Zo_ConfigStatus = 2052, + Zo_Contact = 2065, + Zo_ControlSequenceOfOperation = 2073, + Zo_CurrentGroup = 2100, + Zo_CurrentPositionLift = 2113, + Zo_CurrentPositionLiftPercentage = 2133, + Zo_CurrentPositionTilt = 2163, + Zo_CurrentPositionTiltPercentage = 2183, + Zo_CurrentScene = 2213, + Zo_CurrentTemperature = 2226, + Zo_CurrentTemperatureSetPoint = 2245, + Zo_CustomerName = 2272, + Zo_DataQualityID = 2285, + Zo_DateCode = 2299, + Zo_DecelerationTimeLift = 2308, + Zo_Dimmer = 2329, + Zo_DimmerDown = 2336, + Zo_DimmerMove = 2347, + Zo_DimmerOptions = 2358, + Zo_DimmerRemainingTime = 2372, + Zo_DimmerStep = 2392, + Zo_DimmerStepDown = 2403, + Zo_DimmerStepUp = 2418, + Zo_DimmerStop = 2431, + Zo_DimmerUp = 2442, + Zo_DoorClosedEvents = 2451, + Zo_DoorOpenEvents = 2468, + Zo_DoorState = 2483, + Zo_DriftCompensation = 2493, + Zo_DstEnd = 2511, + Zo_DstShift = 2518, + Zo_DstStart = 2527, + Zo_EnergyFormatting = 2536, + Zo_EnergyRemote = 2553, + Zo_EnergyTotal = 2566, + Zo_EurotronicErrors = 2578, + Zo_EurotronicHostFlags = 2595, + Zo_FastPollTimeout = 2615, + Zo_FastPollTimeoutMax = 2631, + Zo_Fire = 2650, + Zo_FlowMaxMeasuredValue = 2655, + Zo_FlowMinMeasuredValue = 2676, + Zo_FlowRate = 2697, + Zo_FlowTolerance = 2706, + Zo_GenericDeviceClass = 2720, + Zo_GenericDeviceType = 2739, + Zo_GetAllGroups = 2757, + Zo_GetGroup = 2770, + Zo_GetSceneMembership = 2779, + Zo_GlassBreak = 2798, + Zo_GroupNameSupport = 2809, + Zo_HWVersion = 2826, + Zo_Hue = 2836, + Zo_HueMove = 2840, + Zo_HueSat = 2848, + Zo_HueStep = 2855, + Zo_HueStepDown = 2863, + Zo_HueStepUp = 2875, + Zo_Humidity = 2885, + Zo_HumidityMaxMeasuredValue = 2894, + Zo_HumidityMinMeasuredValue = 2919, + Zo_HumidityTolerance = 2944, + Zo_Identify = 2962, + Zo_IdentifyQuery = 2971, + Zo_IdentifyTime = 2985, + Zo_Illuminance = 2998, + Zo_IlluminanceLevelStatus = 3010, + Zo_IlluminanceLightSensorType = 3033, + Zo_IlluminanceMaxMeasuredValue = 3060, + Zo_IlluminanceMinMeasuredValue = 3088, + Zo_IlluminanceTargetLevel = 3116, + Zo_IlluminanceTolerance = 3139, + Zo_InstalledClosedLimitLift = 3160, + Zo_InstalledClosedLimitTilt = 3185, + Zo_InstalledOpenLimitLift = 3210, + Zo_InstalledOpenLimitTilt = 3233, + Zo_IntermediateSetpointsLift = 3256, + Zo_IntermediateSetpointsTilt = 3282, + Zo_LastMessageLQI = 3308, + Zo_LastMessageRSSI = 3323, + Zo_LastSetTime = 3339, + Zo_LocalTemperature = 3351, + Zo_LocalTemperatureCalibration = 3368, + Zo_LocalTime = 3396, + Zo_LocationAge = 3406, + Zo_LocationMethod = 3418, + Zo_LocationType = 3433, + Zo_LockState = 3446, + Zo_LockType = 3456, + Zo_LongPollInterval = 3465, + Zo_LongPollIntervalMin = 3482, + Zo_MainsFrequency = 3502, + Zo_MainsVoltage = 3517, + Zo_Manufacturer = 3530, + Zo_MaxTempExperienced = 3543, + Zo_MeterTypeID = 3562, + Zo_MinTempExperienced = 3574, + Zo_Mode = 3593, + Zo_Model = 3598, + Zo_ModelId = 3604, + Zo_MotorStepSize = 3612, + Zo_Movement = 3626, + Zo_MultiApplicationType = 3635, + Zo_MultiDescription = 3656, + Zo_MultiInApplicationType = 3673, + Zo_MultiInDescription = 3696, + Zo_MultiInNumberOfStates = 3715, + Zo_MultiInOutOfService = 3737, + Zo_MultiInReliability = 3757, + Zo_MultiInStatusFlags = 3776, + Zo_MultiInValue = 3795, + Zo_MultiNumberOfStates = 3808, + Zo_MultiOutApplicationType = 3828, + Zo_MultiOutDescription = 3852, + Zo_MultiOutNumberOfStates = 3872, + Zo_MultiOutOfService = 3895, + Zo_MultiOutOutOfService = 3913, + Zo_MultiOutReliability = 3934, + Zo_MultiOutRelinquishDefault = 3954, + Zo_MultiOutStatusFlags = 3980, + Zo_MultiOutValue = 4000, + Zo_MultiReliability = 4014, + Zo_MultiRelinquishDefault = 4031, + Zo_MultiStatusFlags = 4054, + Zo_MultiValue = 4071, + Zo_MultipleScheduling = 4082, + Zo_NumberOfDevices = 4101, + Zo_NumberOfPrimaries = 4117, + Zo_NumberOfResets = 4135, + Zo_NumberofActuationsLift = 4150, + Zo_NumberofActuationsTilt = 4173, + Zo_Occupancy = 4196, + Zo_OccupancySensorType = 4206, + Zo_OccupiedCoolingSetpoint = 4226, + Zo_OccupiedHeatingSetpoint = 4250, + Zo_OnOffTransitionTime = 4274, + Zo_OpenPeriod = 4294, + Zo_OppleMode = 4305, + Zo_OutdoorTemperature = 4315, + Zo_OverTempTotalDwell = 4334, + Zo_PICoolingDemand = 4353, + Zo_PIHeatingDemand = 4369, + Zo_POD = 4385, + Zo_Panic = 4389, + Zo_PartNumber = 4395, + Zo_PersistentMemoryWrites = 4406, + Zo_PersonalAlarm = 4429, + Zo_PhysicalClosedLimit = 4443, + Zo_PhysicalClosedLimitLift = 4463, + Zo_PhysicalClosedLimitTilt = 4487, + Zo_Power = 4511, + Zo_Power2 = 4517, + Zo_Power3 = 4524, + Zo_Power4 = 4531, + Zo_PowerOffEffect = 4538, + Zo_PowerOnRecall = 4553, + Zo_PowerOnTimer = 4567, + Zo_PowerSource = 4580, + Zo_PowerThreshold = 4592, + Zo_Pressure = 4607, + Zo_PressureMaxMeasuredValue = 4616, + Zo_PressureMaxScaledValue = 4641, + Zo_PressureMinMeasuredValue = 4664, + Zo_PressureMinScaledValue = 4689, + Zo_PressureScale = 4712, + Zo_PressureScaledTolerance = 4726, + Zo_PressureScaledValue = 4750, + Zo_PressureTolerance = 4770, + Zo_Primary1Intensity = 4788, + Zo_Primary1X = 4806, + Zo_Primary1Y = 4816, + Zo_Primary2Intensity = 4826, + Zo_Primary2X = 4844, + Zo_Primary2Y = 4854, + Zo_Primary3Intensity = 4864, + Zo_Primary3X = 4882, + Zo_Primary3Y = 4892, + Zo_ProductCode = 4902, + Zo_ProductRevision = 4914, + Zo_ProductURL = 4930, + Zo_QualityMeasure = 4941, + Zo_RMSCurrent = 4956, + Zo_RMSVoltage = 4967, + Zo_ReactivePower = 4978, + Zo_RecallScene = 4992, + Zo_RemainingTime = 5004, + Zo_RemoteSensing = 5018, + Zo_RemoveAllGroups = 5032, + Zo_RemoveAllScenes = 5048, + Zo_RemoveGroup = 5064, + Zo_RemoveScene = 5076, + Zo_ResetAlarm = 5088, + Zo_ResetAllAlarms = 5099, + Zo_SWBuildID = 5114, + Zo_Sat = 5124, + Zo_SatMove = 5128, + Zo_SatStep = 5136, + Zo_SceneCount = 5144, + Zo_SceneValid = 5155, + Zo_ScheduleMode = 5166, + Zo_SeaPressure = 5179, + Zo_ShortPollInterval = 5191, + Zo_Shutter = 5209, + Zo_ShutterClose = 5217, + Zo_ShutterLift = 5230, + Zo_ShutterOpen = 5242, + Zo_ShutterStop = 5254, + Zo_ShutterTilt = 5266, + Zo_SoftwareRevision = 5278, + Zo_StackVersion = 5295, + Zo_StandardTime = 5308, + Zo_StartUpOnOff = 5321, + Zo_Status = 5334, + Zo_StoreScene = 5341, + Zo_SwitchType = 5352, + Zo_SystemMode = 5363, + Zo_TRVBoost = 5374, + Zo_TRVChildProtection = 5383, + Zo_TRVMirrorDisplay = 5402, + Zo_TRVMode = 5419, + Zo_TRVWindowOpen = 5427, + Zo_TempTarget = 5441, + Zo_Temperature = 5452, + Zo_TemperatureMaxMeasuredValue = 5464, + Zo_TemperatureMinMeasuredValue = 5492, + Zo_TemperatureTolerance = 5520, + Zo_TerncyDuration = 5541, + Zo_TerncyRotate = 5556, + Zo_ThSetpoint = 5569, + Zo_Time = 5580, + Zo_TimeEpoch = 5585, + Zo_TimeStatus = 5595, + Zo_TimeZone = 5606, + Zo_TotalProfileNum = 5615, + Zo_TuyaAutoLock = 5631, + Zo_TuyaAwayDays = 5644, + Zo_TuyaAwayTemp = 5657, + Zo_TuyaBattery = 5670, + Zo_TuyaBoostTime = 5682, + Zo_TuyaChildLock = 5696, + Zo_TuyaComfortTemp = 5710, + Zo_TuyaEcoTemp = 5726, + Zo_TuyaFanMode = 5738, + Zo_TuyaForceMode = 5750, + Zo_TuyaMaxTemp = 5764, + Zo_TuyaMinTemp = 5776, + Zo_TuyaPreset = 5788, + Zo_TuyaScheduleHolidays = 5799, + Zo_TuyaScheduleWorkdays = 5820, + Zo_TuyaTempTarget = 5841, + Zo_TuyaValveDetection = 5856, + Zo_TuyaValvePosition = 5875, + Zo_TuyaWeekSelect = 5893, + Zo_TuyaWindowDetection = 5908, + Zo_UnoccupiedCoolingSetpoint = 5928, + Zo_UnoccupiedHeatingSetpoint = 5954, + Zo_UtilityName = 5980, + Zo_ValidUntilTime = 5992, + Zo_ValvePosition = 6007, + Zo_VelocityLift = 6021, + Zo_ViewGroup = 6034, + Zo_ViewScene = 6044, + Zo_Water = 6054, + Zo_WhitePointX = 6060, + Zo_WhitePointY = 6072, + Zo_WindowCoveringType = 6084, + Zo_X = 6103, + Zo_Y = 6105, + Zo_ZCLVersion = 6107, + Zo_ZoneState = 6118, + Zo_ZoneStatus = 6128, + Zo_ZoneStatusChange = 6139, + Zo_ZoneType = 6156, + Zo_xx = 6165, + Zo_xx000A00 = 6168, + Zo_xx0A = 6177, + Zo_xx0A00 = 6182, + Zo_xx19 = 6189, + Zo_xx190A = 6194, + Zo_xx190A00 = 6201, + Zo_xxxx = 6210, + Zo_xxxx00 = 6215, + Zo_xxxx0A00 = 6222, + Zo_xxxxyy = 6231, + Zo_xxxxyyyy = 6238, + Zo_xxxxyyyy0A00 = 6247, + Zo_xxxxyyzz = 6260, + Zo_xxyy = 6269, + Zo_xxyy0A00 = 6274, + Zo_xxyyyy = 6283, + Zo_xxyyyy000000000000 = 6290, + Zo_xxyyyy0A0000000000 = 6309, + Zo_xxyyyyzz = 6328, + Zo_xxyyyyzzzz = 6337, + Zo_xxyyzzzz = 6348, }; diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 9bdf84175..35ae1b827 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -1856,24 +1856,23 @@ const char ZB_WEB[] PROGMEM = "\x00\x66\x3D\x0E\xCA\xB1\xC1\x33\xF0\xF6\xD1\xEE\ // ++++++++++++++++++++ DO NOT EDIT ABOVE ++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -extern "C" { - // comparator function used to sort Zigbee devices by alphabetical order (if friendlyname) - // then by shortaddr if they don't have friendlyname - int device_cmp(const void * a, const void * b) { - const Z_Device &dev_a = zigbee_devices.devicesAt(*(uint8_t*)a); - const Z_Device &dev_b = zigbee_devices.devicesAt(*(uint8_t*)b); - const char * fn_a = dev_a.friendlyName; - const char * fn_b = dev_b.friendlyName; +// comparator function used to sort Zigbee devices by alphabetical order (if friendlyname) +// then by shortaddr if they don't have friendlyname +int device_cmp(uint8_t a, uint8_t b) { + const Z_Device &dev_a = zigbee_devices.devicesAt(a); + const Z_Device &dev_b = zigbee_devices.devicesAt(b); + const char * fn_a = dev_a.friendlyName; + const char * fn_b = dev_b.friendlyName; - if (fn_a && fn_b) { - return strcasecmp(fn_a, fn_b); - } else if (!fn_a && !fn_b) { - return (int32_t)dev_a.shortaddr - (int32_t)dev_b.shortaddr; - } else { - if (fn_a) return -1; - else return 1; - } + if (fn_a && fn_b) { + return strcasecmp(fn_a, fn_b); + } else if (!fn_a && !fn_b) { + return (int32_t)dev_a.shortaddr - (int32_t)dev_b.shortaddr; + } else { + if (fn_a) return -1; + else return 1; } +} // Convert seconds to a string representing days, hours or minutes present in the n-value. @@ -1884,24 +1883,23 @@ extern "C" { // - char for unit (d for day, h for hour, m for minute) // - the hex color to be used to display the text // - uint32_t convert_seconds_to_dhm(uint32_t seconds, char *unit, uint8_t *color){ - static uint32_t conversions[3] = {24 * 3600, 3600, 60}; - static char units[3] = { 'd', 'h', 'm'}; // day, hour, minute - uint8_t color_text_8 = WebColor(COL_TEXT) & 0xFF; // color of text on 8 bits - uint8_t color_back_8 = WebColor(COL_BACKGROUND) & 0xFF; // color of background on 8 bits - uint8_t colors[3] = { (uint8_t) changeUIntScale(6, 0, 16, color_back_8, color_text_8), // 6/16 of text - (uint8_t) changeUIntScale(10, 0, 16, color_back_8, color_text_8), // 10/16 of text color - color_text_8}; - for(int i = 0; i < 3; ++i) { - *color = colors[i]; - *unit = units[i]; - if (seconds > conversions[i]) { // always pass even if 00m - return seconds / conversions[i]; - } +uint32_t convert_seconds_to_dhm(uint32_t seconds, char *unit, uint8_t *color){ + static uint32_t conversions[3] = {24 * 3600, 3600, 60}; + static char units[3] = { 'd', 'h', 'm'}; // day, hour, minute + uint8_t color_text_8 = WebColor(COL_TEXT) & 0xFF; // color of text on 8 bits + uint8_t color_back_8 = WebColor(COL_BACKGROUND) & 0xFF; // color of background on 8 bits + uint8_t colors[3] = { (uint8_t) changeUIntScale(6, 0, 16, color_back_8, color_text_8), // 6/16 of text + (uint8_t) changeUIntScale(10, 0, 16, color_back_8, color_text_8), // 10/16 of text color + color_text_8}; + for(int i = 0; i < 3; ++i) { + *color = colors[i]; + *unit = units[i]; + if (seconds > conversions[i]) { // always pass even if 00m + return seconds / conversions[i]; } - return 0; } -} // extern "C" + return 0; +} const char HTTP_BTN_ZB_BUTTONS[] PROGMEM = "" @@ -1927,7 +1925,17 @@ void ZigbeeShow(bool json) for (uint32_t i = 0; i < zigbee_num; i++) { sorted_idx[i] = i; } - qsort(sorted_idx, zigbee_num, sizeof(sorted_idx[0]), device_cmp); + + // insertion sort + for (uint32_t i = 1; i < zigbee_num; i++) { + uint8_t key = sorted_idx[i]; + uint8_t j = i; + while ((j > 0) && (device_cmp(sorted_idx[j - 1], key) > 0)) { + sorted_idx[j] = sorted_idx[j - 1]; + j--; + } + sorted_idx[j] = key; + } uint32_t now = Rtc.utc_time; From 7b5184c89b1f3e7af140a372589add3d135f30fa Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 3 Jan 2021 15:28:52 +0100 Subject: [PATCH 16/78] Optimize sleepdelay Optimize sleepdelay (#10379) --- tasmota/tasmota.ino | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index d8b95433e..84c2252b1 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -368,7 +368,11 @@ void BacklogLoop(void) { void SleepDelay(uint32_t mseconds) { if (mseconds) { for (uint32_t wait = 0; wait < mseconds; wait++) { + // ESP8266 does an optimistic_yield(1000) in Serial.available() + // ESP32 does not so needs delay here +#ifdef ESP32 delay(1); +#endif if (Serial.available()) { break; } // We need to service serial buffer ASAP as otherwise we get uart buffer overrun } } else { @@ -383,7 +387,6 @@ void loop(void) { XsnsCall(FUNC_LOOP); OsWatchLoop(); - ButtonLoop(); SwitchLoop(); #ifdef USE_DEVICE_GROUPS @@ -391,7 +394,7 @@ void loop(void) { #endif // USE_DEVICE_GROUPS BacklogLoop(); - static uint32_t state_50msecond = 0; // State 50msecond timer + static uint32_t state_50msecond = 0; // State 50msecond timer if (TimeReached(state_50msecond)) { SetNextTimeInterval(state_50msecond, 50); #ifdef ROTARY_V1 @@ -401,7 +404,7 @@ void loop(void) { XsnsCall(FUNC_EVERY_50_MSECOND); } - static uint32_t state_100msecond = 0; // State 100msecond timer + static uint32_t state_100msecond = 0; // State 100msecond timer if (TimeReached(state_100msecond)) { SetNextTimeInterval(state_100msecond, 100); Every100mSeconds(); @@ -409,7 +412,7 @@ void loop(void) { XsnsCall(FUNC_EVERY_100_MSECOND); } - static uint32_t state_250msecond = 0; // State 250msecond timer + static uint32_t state_250msecond = 0; // State 250msecond timer if (TimeReached(state_250msecond)) { SetNextTimeInterval(state_250msecond, 250); Every250mSeconds(); @@ -417,7 +420,7 @@ void loop(void) { XsnsCall(FUNC_EVERY_250_MSECOND); } - static uint32_t state_second = 0; // State second timer + static uint32_t state_second = 0; // State second timer if (TimeReached(state_second)) { SetNextTimeInterval(state_second, 1000); PerformEverySecond(); @@ -435,7 +438,7 @@ void loop(void) { if (Settings.flag3.sleep_normal) { // SetOption60 - Enable normal sleep instead of dynamic sleep // yield(); // yield == delay(0), delay contains yield, auto yield in loop - SleepDelay(TasmotaGlobal.sleep); // https://github.com/esp8266/Arduino/issues/2021 + SleepDelay(TasmotaGlobal.sleep); // https://github.com/esp8266/Arduino/issues/2021 } else { if (my_activity < (uint32_t)TasmotaGlobal.sleep) { SleepDelay((uint32_t)TasmotaGlobal.sleep - my_activity); // Provide time for background tasks like wifi From f9403c8489b7de69f99c7618e0082f53ac12b513 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 3 Jan 2021 16:30:45 +0100 Subject: [PATCH 17/78] Optimize sleepdelay Optimize sleepdelay (#10379) --- tasmota/tasmota.ino | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 84c2252b1..79e648200 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -367,13 +367,19 @@ void BacklogLoop(void) { void SleepDelay(uint32_t mseconds) { if (mseconds) { - for (uint32_t wait = 0; wait < mseconds; wait++) { - // ESP8266 does an optimistic_yield(1000) in Serial.available() - // ESP32 does not so needs delay here -#ifdef ESP32 - delay(1); + uint32_t wait = millis() + mseconds; + while (!TimeReached(wait)) { +#ifdef ESP8266 + if ((wait - millis()) > 10) { // ESP8266 does an optimistic_yield(10000) in Serial.available() #endif - if (Serial.available()) { break; } // We need to service serial buffer ASAP as otherwise we get uart buffer overrun + if (Serial.available()) { return; } // We need to service serial buffer ASAP as otherwise we get uart buffer overrun +#ifdef ESP8266 + } else { +#endif + delay(1); +#ifdef ESP8266 + } +#endif // ESP8266 } } else { delay(0); From 61c518d8138247076757dc1dc0aa02497c29ec83 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 3 Jan 2021 16:36:34 +0100 Subject: [PATCH 18/78] Zigbee fix display `Devices allowed to join` when zero device --- tasmota/xdrv_23_zigbee_A_impl.ino | 291 +++++++++++++++--------------- 1 file changed, 146 insertions(+), 145 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 35ae1b827..e5ca3d36c 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -1914,170 +1914,171 @@ void ZigbeeShow(bool json) } else { UnishoxStrings msg(ZB_WEB); uint32_t zigbee_num = zigbee_devices.devicesSize(); - if (!zigbee_num) { return; } - if (zigbee_num > 255) { zigbee_num = 255; } + if (zigbee_num > 0) { + if (zigbee_num > 255) { zigbee_num = 255; } - WSContentSend_P(msg[ZB_WEB_CSS], WebColor(COL_TEXT)); - // WSContentSend_compressed(ZB_WEB, 0); + WSContentSend_P(msg[ZB_WEB_CSS], WebColor(COL_TEXT)); + // WSContentSend_compressed(ZB_WEB, 0); - // sort elements by name, then by id - uint8_t sorted_idx[zigbee_num]; - for (uint32_t i = 0; i < zigbee_num; i++) { - sorted_idx[i] = i; - } - - // insertion sort - for (uint32_t i = 1; i < zigbee_num; i++) { - uint8_t key = sorted_idx[i]; - uint8_t j = i; - while ((j > 0) && (device_cmp(sorted_idx[j - 1], key) > 0)) { - sorted_idx[j] = sorted_idx[j - 1]; - j--; - } - sorted_idx[j] = key; - } - - uint32_t now = Rtc.utc_time; - - for (uint32_t i = 0; i < zigbee_num; i++) { - const Z_Device &device = zigbee_devices.devicesAt(sorted_idx[i]); - uint16_t shortaddr = device.shortaddr; - char *name = (char*) device.friendlyName; - - char sdevice[33]; - if (nullptr == name) { - snprintf_P(sdevice, sizeof(sdevice), PSTR(D_DEVICE " 0x%04X"), shortaddr); - name = sdevice; + // sort elements by name, then by id + uint8_t sorted_idx[zigbee_num]; + for (uint32_t i = 0; i < zigbee_num; i++) { + sorted_idx[i] = i; } - char sbatt[64]; - snprintf_P(sbatt, sizeof(sbatt), PSTR(" ")); - if (device.validBatteryPercent()) { - snprintf_P(sbatt, sizeof(sbatt), - msg[ZB_WEB_BATTERY], - device.batterypercent, changeUIntScale(device.batterypercent, 0, 100, 0, 14) - ); - } - - uint32_t num_bars = 0; - - char slqi[4]; - slqi[0] = '-'; - slqi[1] = '\0'; - if (device.validLqi()){ - num_bars = changeUIntScale(device.lqi, 0, 254, 0, 4); - snprintf_P(slqi, sizeof(slqi), PSTR("%d"), device.lqi); - } - - WSContentSend_PD(msg[ZB_WEB_STATUS_LINE], - shortaddr, - device.modelId ? device.modelId : "", - device.manufacturerId ? device.manufacturerId : "", - name, sbatt, slqi); - - if(device.validLqi()) { - for(uint32_t j = 0; j < 4; ++j) { - WSContentSend_PD(PSTR(""), j, (num_bars < j) ? PSTR(" o30") : PSTR("")); - } - } - char dhm[48]; - snprintf_P(dhm, sizeof(dhm), PSTR(" ")); - if (device.validLastSeen()) { - char unit; - uint8_t color; - uint16_t val = convert_seconds_to_dhm(now - device.last_seen, &unit, &color); - if (val < 100) { - snprintf_P(dhm, sizeof(dhm), msg[ZB_WEB_LAST_SEEN], - color, color, color, val, unit); + // insertion sort + for (uint32_t i = 1; i < zigbee_num; i++) { + uint8_t key = sorted_idx[i]; + uint8_t j = i; + while ((j > 0) && (device_cmp(sorted_idx[j - 1], key) > 0)) { + sorted_idx[j] = sorted_idx[j - 1]; + j--; } + sorted_idx[j] = key; } - WSContentSend_PD(msg[ZB_WEB_END_STATUS], dhm ); + uint32_t now = Rtc.utc_time; - // Sensors - const Z_Data_Thermo & thermo = device.data.find(); + for (uint32_t i = 0; i < zigbee_num; i++) { + const Z_Device &device = zigbee_devices.devicesAt(sorted_idx[i]); + uint16_t shortaddr = device.shortaddr; + char *name = (char*) device.friendlyName; - if (&thermo != nullptr) { - bool validTemp = thermo.validTemperature(); - bool validTempTarget = thermo.validTempTarget(); - bool validThSetpoint = thermo.validThSetpoint(); - bool validHumidity = thermo.validHumidity(); - bool validPressure = thermo.validPressure(); + char sdevice[33]; + if (nullptr == name) { + snprintf_P(sdevice, sizeof(sdevice), PSTR(D_DEVICE " 0x%04X"), shortaddr); + name = sdevice; + } - if (validTemp || validTempTarget || validThSetpoint || validHumidity || validPressure) { + char sbatt[64]; + snprintf_P(sbatt, sizeof(sbatt), PSTR(" ")); + if (device.validBatteryPercent()) { + snprintf_P(sbatt, sizeof(sbatt), + msg[ZB_WEB_BATTERY], + device.batterypercent, changeUIntScale(device.batterypercent, 0, 100, 0, 14) + ); + } + + uint32_t num_bars = 0; + + char slqi[4]; + slqi[0] = '-'; + slqi[1] = '\0'; + if (device.validLqi()){ + num_bars = changeUIntScale(device.lqi, 0, 254, 0, 4); + snprintf_P(slqi, sizeof(slqi), PSTR("%d"), device.lqi); + } + + WSContentSend_PD(msg[ZB_WEB_STATUS_LINE], + shortaddr, + device.modelId ? device.modelId : "", + device.manufacturerId ? device.manufacturerId : "", + name, sbatt, slqi); + + if(device.validLqi()) { + for(uint32_t j = 0; j < 4; ++j) { + WSContentSend_PD(PSTR(""), j, (num_bars < j) ? PSTR(" o30") : PSTR("")); + } + } + char dhm[48]; + snprintf_P(dhm, sizeof(dhm), PSTR(" ")); + if (device.validLastSeen()) { + char unit; + uint8_t color; + uint16_t val = convert_seconds_to_dhm(now - device.last_seen, &unit, &color); + if (val < 100) { + snprintf_P(dhm, sizeof(dhm), msg[ZB_WEB_LAST_SEEN], + color, color, color, val, unit); + } + } + + WSContentSend_PD(msg[ZB_WEB_END_STATUS], dhm ); + + // Sensors + const Z_Data_Thermo & thermo = device.data.find(); + + if (&thermo != nullptr) { + bool validTemp = thermo.validTemperature(); + bool validTempTarget = thermo.validTempTarget(); + bool validThSetpoint = thermo.validThSetpoint(); + bool validHumidity = thermo.validHumidity(); + bool validPressure = thermo.validPressure(); + + if (validTemp || validTempTarget || validThSetpoint || validHumidity || validPressure) { + WSContentSend_P(msg[ZB_WEB_LINE_START]); + if (validTemp) { + char buf[12]; + dtostrf(thermo.getTemperature() / 100.0f, 3, 1, buf); + WSContentSend_PD(PSTR(" ☀️ %s°C"), buf); + } + if (validTempTarget) { + char buf[12]; + dtostrf(thermo.getTempTarget() / 100.0f, 3, 1, buf); + WSContentSend_PD(PSTR(" 🎯 %s°C"), buf); + } + if (validThSetpoint) { + WSContentSend_PD(PSTR(" ⚙️ %d%%"), thermo.getThSetpoint()); + } + if (validHumidity) { + WSContentSend_P(PSTR(" 💧 %d%%"), (uint16_t)(thermo.getHumidity() / 100.0f + 0.5f)); + } + if (validPressure) { + WSContentSend_P(PSTR(" ⛅ %d hPa"), thermo.getPressure()); + } + + WSContentSend_P(PSTR("{e}")); + } + } + + // Light, switches and plugs + const Z_Data_OnOff & onoff = device.data.find(); + bool onoff_display = (&onoff != nullptr) ? onoff.validPower() : false; + const Z_Data_Light & light = device.data.find(); + bool light_display = (&light != nullptr) ? light.validDimmer() : false; + const Z_Data_Plug & plug = device.data.find(); + bool plug_voltage = (&plug != nullptr) ? plug.validMainsVoltage() : false; + bool plug_power = (&plug != nullptr) ? plug.validMainsPower() : false; + if (onoff_display || light_display || plug_voltage || plug_power) { + int8_t channels = device.getLightChannels(); + if (channels < 0) { channels = 5; } // if number of channel is unknown, display all known attributes WSContentSend_P(msg[ZB_WEB_LINE_START]); - if (validTemp) { - char buf[12]; - dtostrf(thermo.getTemperature() / 100.0f, 3, 1, buf); - WSContentSend_PD(PSTR(" ☀️ %s°C"), buf); + if (onoff_display) { + WSContentSend_P(PSTR(" %s"), onoff.getPower() ? PSTR(D_ON) : PSTR(D_OFF)); } - if (validTempTarget) { - char buf[12]; - dtostrf(thermo.getTempTarget() / 100.0f, 3, 1, buf); - WSContentSend_PD(PSTR(" 🎯 %s°C"), buf); + if (&light != nullptr) { + if (light.validDimmer() && (channels >= 1)) { + WSContentSend_P(PSTR(" 🔅 %d%%"), changeUIntScale(light.getDimmer(),0,254,0,100)); + } + if (light.validCT() && ((channels == 2) || (channels == 5))) { + uint32_t ct_k = (((1000000 / light.getCT()) + 25) / 50) * 50; + WSContentSend_P(msg[ZB_WEB_LIGHT_CT], light.getCT(), ct_k); + } + if (light.validHue() && light.validSat() && (channels >= 3)) { + uint8_t r,g,b; + uint8_t sat = changeUIntScale(light.getSat(), 0, 254, 0, 255); // scale to 0..255 + HsToRgb(light.getHue(), sat, &r, &g, &b); + WSContentSend_P(msg[ZB_WEB_COLOR_RGB], r,g,b,r,g,b); + } else if (light.validX() && light.validY() && (channels >= 3)) { + uint8_t r,g,b; + XyToRgb(light.getX() / 65535.0f, light.getY() / 65535.0f, &r, &g, &b); + WSContentSend_P(msg[ZB_WEB_COLOR_RGB], r,g,b,r,g,b); + } } - if (validThSetpoint) { - WSContentSend_PD(PSTR(" ⚙️ %d%%"), thermo.getThSetpoint()); + if (plug_voltage || plug_power) { + WSContentSend_P(PSTR(" ⚡ ")); + if (plug_voltage) { + WSContentSend_P(PSTR(" %dV"), plug.getMainsVoltage()); + } + if (plug_power) { + WSContentSend_P(PSTR(" %dW"), plug.getMainsPower()); + } } - if (validHumidity) { - WSContentSend_P(PSTR(" 💧 %d%%"), (uint16_t)(thermo.getHumidity() / 100.0f + 0.5f)); - } - if (validPressure) { - WSContentSend_P(PSTR(" ⛅ %d hPa"), thermo.getPressure()); - } - WSContentSend_P(PSTR("{e}")); } } - // Light, switches and plugs - const Z_Data_OnOff & onoff = device.data.find(); - bool onoff_display = (&onoff != nullptr) ? onoff.validPower() : false; - const Z_Data_Light & light = device.data.find(); - bool light_display = (&light != nullptr) ? light.validDimmer() : false; - const Z_Data_Plug & plug = device.data.find(); - bool plug_voltage = (&plug != nullptr) ? plug.validMainsVoltage() : false; - bool plug_power = (&plug != nullptr) ? plug.validMainsPower() : false; - if (onoff_display || light_display || plug_voltage || plug_power) { - int8_t channels = device.getLightChannels(); - if (channels < 0) { channels = 5; } // if number of channel is unknown, display all known attributes - WSContentSend_P(msg[ZB_WEB_LINE_START]); - if (onoff_display) { - WSContentSend_P(PSTR(" %s"), onoff.getPower() ? PSTR(D_ON) : PSTR(D_OFF)); - } - if (&light != nullptr) { - if (light.validDimmer() && (channels >= 1)) { - WSContentSend_P(PSTR(" 🔅 %d%%"), changeUIntScale(light.getDimmer(),0,254,0,100)); - } - if (light.validCT() && ((channels == 2) || (channels == 5))) { - uint32_t ct_k = (((1000000 / light.getCT()) + 25) / 50) * 50; - WSContentSend_P(msg[ZB_WEB_LIGHT_CT], light.getCT(), ct_k); - } - if (light.validHue() && light.validSat() && (channels >= 3)) { - uint8_t r,g,b; - uint8_t sat = changeUIntScale(light.getSat(), 0, 254, 0, 255); // scale to 0..255 - HsToRgb(light.getHue(), sat, &r, &g, &b); - WSContentSend_P(msg[ZB_WEB_COLOR_RGB], r,g,b,r,g,b); - } else if (light.validX() && light.validY() && (channels >= 3)) { - uint8_t r,g,b; - XyToRgb(light.getX() / 65535.0f, light.getY() / 65535.0f, &r, &g, &b); - WSContentSend_P(msg[ZB_WEB_COLOR_RGB], r,g,b,r,g,b); - } - } - if (plug_voltage || plug_power) { - WSContentSend_P(PSTR(" ⚡ ")); - if (plug_voltage) { - WSContentSend_P(PSTR(" %dV"), plug.getMainsVoltage()); - } - if (plug_power) { - WSContentSend_P(PSTR(" %dW"), plug.getMainsPower()); - } - } - WSContentSend_P(PSTR("{e}")); - } + WSContentSend_P(msg[ZB_WEB_LINE_END]); // Terminate current multi column table and open new table } - - WSContentSend_P(msg[ZB_WEB_LINE_END]); // Terminate current multi column table and open new table if (zigbee.permit_end_time) { // PermitJoin in progress From d028e5c847530b45422b948b3ae37a6e5fbde4d2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 3 Jan 2021 17:04:14 +0100 Subject: [PATCH 19/78] Update changelog --- CHANGELOG.md | 4 +++- RELEASENOTES.md | 3 +++ tasmota/settings.h | 2 +- tools/decode-status.py | 8 +++++--- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bb01ac2a..6637b3a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ All notable changes to this project will be documented in this file. - Basic support for ESP32 Odroid Go 16MB binary tasmota32-odroidgo.bin (#8630) - Command ``CTRange`` to specify the visible CT range the bulb is capable of (#10311) - Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels (#10311) -- Disable `USE_LIGHT`` light support for ZBBridge (saves 17.6kb) +- Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default (#10353) +- Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic (#10355) ### Breaking Changed - Replaced MFRC522 13.56MHz rfid card reader GPIO selection from ``SPI CS`` by ``RC522 CS`` @@ -23,6 +24,7 @@ All notable changes to this project will be documented in this file. ### Changed - Maximum chars in AddLog_P logging reduced from 700 to 128 (LOGSZ) to enhance stability +- Disabled ``USE_LIGHT`` light support for ZBBridge saving 17.6kB (#10374) ## [9.2.0.1] 20201229 ### Added diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 539323f9d..63b7466c3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -60,6 +60,8 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ### Added - Command ``CTRange`` to specify the visible CT range the bulb is capable of [#10311](https://github.com/arendst/Tasmota/issues/10311) - Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels [#10311](https://github.com/arendst/Tasmota/issues/10311) +- Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default [#10353](https://github.com/arendst/Tasmota/issues/10353) +- Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic [#10355](https://github.com/arendst/Tasmota/issues/10355) - Milliseconds to console output [#10152](https://github.com/arendst/Tasmota/issues/10152) - Gpio ``Option_a1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs [#10196](https://github.com/arendst/Tasmota/issues/10196) - BSSID and Signal Strength Indicator to GUI wifi scan result [#10253](https://github.com/arendst/Tasmota/issues/10253) @@ -86,6 +88,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ### Changed - Logging from heap to stack freeing 700 bytes RAM +- Disabled ``USE_LIGHT`` light support for ZBBridge saving 17.6kB (#10374) ### Fixed - Redesign syslog and mqttlog using log buffer [#10164](https://github.com/arendst/Tasmota/issues/10164) diff --git a/tasmota/settings.h b/tasmota/settings.h index 81a62c835..32d8b8871 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -143,7 +143,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t mi32_enable : 1; // bit 1 (v9.1.0.1) - SetOption115 - (ESP32 BLE) Enable ESP32 MI32 BLE (1) uint32_t zb_disable_autoquery : 1; // bit 2 (v9.1.0.1) - SetOption116 - (Zigbee) Disable auto-query of zigbee lights and devices (1) uint32_t fade_fixed_duration : 1; // bit 3 (v9.1.0.2) - SetOption117 - (Light) run fading at fixed duration instead of fixed slew rate - uint32_t zb_received_as_subtopic : 1; // bit 4 (v9.2.0.3) - SetOption118 - (Zigbee) Move ZbReceived form JSON message and into the subtopic replacing "SENSOR" default + uint32_t zb_received_as_subtopic : 1; // bit 4 (v9.2.0.3) - SetOption118 - (Zigbee) Move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default uint32_t zb_omit_json_addr : 1; // bit 5 (v9.2.0.3) - SetOption119 - (Zigbee) Remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic uint32_t spare06 : 1; // bit 6 uint32_t spare07 : 1; // bit 7 diff --git a/tools/decode-status.py b/tools/decode-status.py index ba5ead287..3e940d8ff 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -171,8 +171,10 @@ a_setoption = [[ "(Switch) Detach Switches from relays and enable MQTT action state for all the SwitchModes (1)", "(ESP32 BLE) Enable ESP32 MI32 BLE (1)", "(Zigbee) Disable auto-query of zigbee lights and devices (1)", - "", - "","","","", + "(Light) run fading at fixed duration instead of fixed slew rate", + "(Zigbee) Move ZbReceived from JSON message and into the subtopic replacing SENSOR default", + "(Zigbee) Remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic", + "","", "","","","", "","","","", "","","","", @@ -271,7 +273,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20201222 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20210103 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) From 619e4bbfb5791491befa66e55961812048df2087 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 3 Jan 2021 17:31:44 +0100 Subject: [PATCH 20/78] Add command ``RuleTimer0`` to access all RuleTimers at once Add command ``RuleTimer0`` to access all RuleTimers at once (#10352) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/xdrv_10_rules.ino | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6637b3a12..8b34c9ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels (#10311) - Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default (#10353) - Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic (#10355) +- Command ``RuleTimer0`` to access all RuleTimers at once (#10352) ### Breaking Changed - Replaced MFRC522 13.56MHz rfid card reader GPIO selection from ``SPI CS`` by ``RC522 CS`` diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 63b7466c3..814272bdf 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -59,6 +59,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ## Changelog v9.2.0.2 ### Added - Command ``CTRange`` to specify the visible CT range the bulb is capable of [#10311](https://github.com/arendst/Tasmota/issues/10311) +- Command ``RuleTimer0`` to access all RuleTimers at once [#10352](https://github.com/arendst/Tasmota/issues/10352) - Command ``VirtualCT`` to simulate or fine tune CT bulbs with 3,4,5 channels [#10311](https://github.com/arendst/Tasmota/issues/10311) - Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default [#10353](https://github.com/arendst/Tasmota/issues/10353) - Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic [#10355](https://github.com/arendst/Tasmota/issues/10355) diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 2d0caed1d..637a3b963 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -2124,9 +2124,10 @@ void CmndRule(void) void CmndRuleTimer(void) { - if (XdrvMailbox.index > MAX_RULE_TIMERS) - return; - int i = XdrvMailbox.index, max_i = XdrvMailbox.index; + if (XdrvMailbox.index > MAX_RULE_TIMERS) { return; } + + uint32_t i = XdrvMailbox.index; + uint32_t max_i = XdrvMailbox.index; if (0 == i) { i = 1; max_i = MAX_RULE_TIMERS; @@ -2135,7 +2136,7 @@ void CmndRuleTimer(void) float timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len); timer_set = (timer_set > 0) ? millis() + (1000 * timer_set) : 0; #else - unsigned long timer_set = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; + uint32_t timer_set = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0; #endif // USE_EXPRESSION if (XdrvMailbox.data_len > 0) { for ( ; i <= max_i ; ++i ) { From d8fbbdd5c9babc334b04debcbf1da737e62f9245 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 3 Jan 2021 18:41:03 +0100 Subject: [PATCH 21/78] Zugbee fix possible crash on Web UI --- tasmota/xdrv_23_zigbee_A_impl.ino | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index e5ca3d36c..7c17b5d31 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -1768,8 +1768,7 @@ const char ZB_WEB_U[] PROGMEM = "\0" // +++++++++++++++++++++++++++++++++++++++++++++++++++++++ //=ZB_WEB_LINE_END - "" // Close LQI - "%s{e}" // dhm (Last Seen) + "{t}

" "\0" ; // end of list @@ -1794,7 +1793,7 @@ enum { ZB_WEB_LINE_END=1608, }; -// Compressed from 1625 to 1111, -31.6% +// Compressed from 1627 to 1118, -31.3% const char ZB_WEB[] PROGMEM = "\x00\x66\x3D\x0E\xCA\xB1\xC1\x33\xF0\xF6\xD1\xEE\x3D\x3D\x46\x41\x33\xF0\xE8\x6D" "\xA1\x15\x08\x79\xF6\x51\xDD\x3C\xCC\x6F\xFD\x47\x58\x62\xB4\x21\x0E\xF1\xED\x1F" "\xD1\x28\x51\xE6\x72\x99\x0C\x36\x1E\x0C\x67\x51\xD7\xED\x36\xB3\xCC\xE7\x99\xF4" @@ -1850,7 +1849,7 @@ const char ZB_WEB[] PROGMEM = "\x00\x66\x3D\x0E\xCA\xB1\xC1\x33\xF0\xF6\xD1\xEE\ "\x30\xF6\x1F\x87\xE8\xF2\x59\xEF\x9E\x0A\x70\xBE\x08\x5D\x15\xA0\x42\xE0\x6C\x83" "\x2A\x2B\x47\xD0\x87\xB0\xFC\x3D\x3C\x36\xC2\x08\xFC\x3F\x47\x91\xC5\xF5\xF3\xC1" "\xDC\x3D\x0E\xC2\x04\x19\x87\xD0\x84\x68\x08\x5D\x16\xC9\xC2\xF8\x21\x74\x18\x4E" - "\xCA\x10\xFC\x3E\xBC\x7B\x59\xEE\x04\xC9\xB3\x85\xF3"; + "\xCA\x10\xFC\x3E\xBC\x7B\x59\xEE\x9C\x2F\x82\x3F\x4E\x90\x10\x79\x23\x9C\x2F\x9B"; // ++++++++++++++++++++^^^^^^^^^^^^^^^^^^^++++++++++++++++++++ // ++++++++++++++++++++ DO NOT EDIT ABOVE ++++++++++++++++++++ From d1ef1c3255247d317c193f3ea6be3fcd830433cc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 12:31:05 +0100 Subject: [PATCH 22/78] Optimize sleepdelay after profiling --- tasmota/tasmota.ino | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 79e648200..a4c39681a 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -369,17 +369,8 @@ void SleepDelay(uint32_t mseconds) { if (mseconds) { uint32_t wait = millis() + mseconds; while (!TimeReached(wait)) { -#ifdef ESP8266 - if ((wait - millis()) > 10) { // ESP8266 does an optimistic_yield(10000) in Serial.available() -#endif - if (Serial.available()) { return; } // We need to service serial buffer ASAP as otherwise we get uart buffer overrun -#ifdef ESP8266 - } else { -#endif - delay(1); -#ifdef ESP8266 - } -#endif // ESP8266 + if (Serial.available()) { return; } // We need to service serial buffer ASAP as otherwise we get uart buffer overrun + delay(1); } } else { delay(0); From 5c92c5a9a98c94a1f73f86d82bb13c927a7f1c54 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 12:47:00 +0100 Subject: [PATCH 23/78] Optimize sleepdelay --- tasmota/tasmota.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index a4c39681a..8eb7303fb 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -368,8 +368,7 @@ void BacklogLoop(void) { void SleepDelay(uint32_t mseconds) { if (mseconds) { uint32_t wait = millis() + mseconds; - while (!TimeReached(wait)) { - if (Serial.available()) { return; } // We need to service serial buffer ASAP as otherwise we get uart buffer overrun + while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun delay(1); } } else { From e551e6c0545e8edfc7359c0cf4adf9644ada9a0a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 14:18:47 +0100 Subject: [PATCH 24/78] Prep SSD1331 fix --- .../Adafruit_SPITFT_Renderer.cpp | 2217 +++++++++++++++++ .../Adafruit_SPITFT_Renderer.h | 520 ++++ .../Adafruit_SSD1331.cpp | 190 ++ .../Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h | 76 + .../Adafruit_SSD1331-1.2.0/README.md | 24 + .../Adafruit_SSD1331-1.2.0/library.properties | 10 + .../Adafruit_SSD1331-1.2.0/license.txt | 26 + 7 files changed, 3063 insertions(+) create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/README.md create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties create mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp new file mode 100644 index 000000000..d49141a28 --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp @@ -0,0 +1,2217 @@ +/*! + * @file Adafruit_SPITFT.cpp + * + * @mainpage Adafruit SPI TFT Displays (and some others) + * + * @section intro_sec Introduction + * + * Part of Adafruit's GFX graphics library. Originally this class was + * written to handle a range of color TFT displays connected via SPI, + * but over time this library and some display-specific subclasses have + * mutated to include some color OLEDs as well as parallel-interfaced + * displays. The name's been kept for the sake of older code. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + + * @section dependencies Dependencies + * + * This library depends on + * Adafruit_GFX being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * @section author Author + * + * Written by Limor "ladyada" Fried for Adafruit Industries, + * with contributions from the open source community. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + */ + +#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all + +#include "Adafruit_SPITFT_Renderer.h" + +#if defined(__AVR__) +#if defined(__AVR_XMEGA__) //only tested with __AVR_ATmega4809__ +#define AVR_WRITESPI(x) for(SPI0_DATA = (x); (!(SPI0_INTFLAGS & _BV(SPI_IF_bp))); ) +#else +#define AVR_WRITESPI(x) for(SPDR = (x); (!(SPSR & _BV(SPIF))); ) +#endif +#endif + +#if defined(PORT_IOBUS) +// On SAMD21, redefine digitalPinToPort() to use the slightly-faster +// PORT_IOBUS rather than PORT (not needed on SAMD51). +#undef digitalPinToPort +#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort])) +#endif // end PORT_IOBUS + +#if defined(USE_SPI_DMA) + #include + #include "wiring_private.h" // pinPeripheral() function + #include // memalign() function + #define tcNum 2 // Timer/Counter for parallel write strobe PWM + #define wrPeripheral PIO_CCL // Use CCL to invert write strobe + + // DMA transfer-in-progress indicator and callback + static volatile bool dma_busy = false; + static void dma_callback(Adafruit_ZeroDMA *dma) { + dma_busy = false; + } + + #if defined(__SAMD51__) + // Timer/counter info by index # + static const struct { + Tc *tc; // -> Timer/Counter base address + int gclk; // GCLK ID + int evu; // EVSYS user ID + } tcList[] = { + { TC0, TC0_GCLK_ID, EVSYS_ID_USER_TC0_EVU }, + { TC1, TC1_GCLK_ID, EVSYS_ID_USER_TC1_EVU }, + { TC2, TC2_GCLK_ID, EVSYS_ID_USER_TC2_EVU }, + { TC3, TC3_GCLK_ID, EVSYS_ID_USER_TC3_EVU }, + #if defined(TC4) + { TC4, TC4_GCLK_ID, EVSYS_ID_USER_TC4_EVU }, + #endif + #if defined(TC5) + { TC5, TC5_GCLK_ID, EVSYS_ID_USER_TC5_EVU }, + #endif + #if defined(TC6) + { TC6, TC6_GCLK_ID, EVSYS_ID_USER_TC6_EVU }, + #endif + #if defined(TC7) + { TC7, TC7_GCLK_ID, EVSYS_ID_USER_TC7_EVU } + #endif + }; + #define NUM_TIMERS (sizeof tcList / sizeof tcList[0]) ///< # timer/counters + #endif // end __SAMD51__ + +#endif // end USE_SPI_DMA + +// Possible values for Adafruit_SPITFT.connection: +#define TFT_HARD_SPI 0 ///< Display interface = hardware SPI +#define TFT_SOFT_SPI 1 ///< Display interface = software SPI +#define TFT_PARALLEL 2 ///< Display interface = 8- or 16-bit parallel + + +// CONSTRUCTORS ------------------------------------------------------------ + +/*! + @brief Adafruit_SPITFT constructor for software (bitbang) SPI. + @param w Display width in pixels at default rotation setting (0). + @param h Display height in pixels at default rotation setting (0). + @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). + @param dc Arduino pin # for data/command select (required). + @param mosi Arduino pin # for bitbang SPI MOSI signal (required). + @param sck Arduino pin # for bitbang SPI SCK signal (required). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @param miso Arduino pin # for bitbang SPI MISO signal (optional, + -1 default, many displays don't support SPI read). + @return Adafruit_SPITFT object. + @note Output pins are not initialized; application typically will + need to call subclass' begin() function, which in turn calls + this library's initSPI() function to initialize pins. +*/ +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, + int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst, int8_t miso) : + Renderer(w, h), connection(TFT_SOFT_SPI), _rst(rst), _cs(cs), _dc(dc) { + swspi._sck = sck; + swspi._mosi = mosi; + swspi._miso = miso; +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(CORE_TEENSY) + #if !defined(KINETISK) + dcPinMask = digitalPinToBitMask(dc); + swspi.sckPinMask = digitalPinToBitMask(sck); + swspi.mosiPinMask = digitalPinToBitMask(mosi); + #endif + dcPortSet = portSetRegister(dc); + dcPortClr = portClearRegister(dc); + swspi.sckPortSet = portSetRegister(sck); + swspi.sckPortClr = portClearRegister(sck); + swspi.mosiPortSet = portSetRegister(mosi); + swspi.mosiPortClr = portClearRegister(mosi); + if(cs >= 0) { + #if !defined(KINETISK) + csPinMask = digitalPinToBitMask(cs); + #endif + csPortSet = portSetRegister(cs); + csPortClr = portClearRegister(cs); + } else { + #if !defined(KINETISK) + csPinMask = 0; + #endif + csPortSet = dcPortSet; + csPortClr = dcPortClr; + } + if(miso >= 0) { + swspi.misoPort = portInputRegister(miso); + #if !defined(KINETISK) + swspi.misoPinMask = digitalPinToBitMask(miso); + #endif + } else { + swspi.misoPort = portInputRegister(dc); + } + #else // !CORE_TEENSY + dcPinMask =digitalPinToBitMask(dc); + swspi.sckPinMask =digitalPinToBitMask(sck); + swspi.mosiPinMask=digitalPinToBitMask(mosi); + dcPortSet =&(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); + dcPortClr =&(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); + swspi.sckPortSet =&(PORT->Group[g_APinDescription[sck].ulPort].OUTSET.reg); + swspi.sckPortClr =&(PORT->Group[g_APinDescription[sck].ulPort].OUTCLR.reg); + swspi.mosiPortSet=&(PORT->Group[g_APinDescription[mosi].ulPort].OUTSET.reg); + swspi.mosiPortClr=&(PORT->Group[g_APinDescription[mosi].ulPort].OUTCLR.reg); + if(cs >= 0) { + csPinMask = digitalPinToBitMask(cs); + csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); + csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPortSet = dcPortSet; + csPortClr = dcPortClr; + csPinMask = 0; + } + if(miso >= 0) { + swspi.misoPinMask=digitalPinToBitMask(miso); + swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso)); + } else { + swspi.misoPinMask=0; + swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc)); + } + #endif // end !CORE_TEENSY + #else // !HAS_PORT_SET_CLR + dcPort =(PORTreg_t)portOutputRegister(digitalPinToPort(dc)); + dcPinMaskSet =digitalPinToBitMask(dc); + swspi.sckPort =(PORTreg_t)portOutputRegister(digitalPinToPort(sck)); + swspi.sckPinMaskSet =digitalPinToBitMask(sck); + swspi.mosiPort =(PORTreg_t)portOutputRegister(digitalPinToPort(mosi)); + swspi.mosiPinMaskSet=digitalPinToBitMask(mosi); + if(cs >= 0) { + csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); + csPinMaskSet = digitalPinToBitMask(cs); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPort = dcPort; + csPinMaskSet = 0; + } + if(miso >= 0) { + swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso)); + swspi.misoPinMask=digitalPinToBitMask(miso); + } else { + swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc)); + swspi.misoPinMask=0; + } + csPinMaskClr = ~csPinMaskSet; + dcPinMaskClr = ~dcPinMaskSet; + swspi.sckPinMaskClr = ~swspi.sckPinMaskSet; + swspi.mosiPinMaskClr = ~swspi.mosiPinMaskSet; + #endif // !end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +} + +/*! + @brief Adafruit_SPITFT constructor for hardware SPI using the board's + default SPI peripheral. + @param w Display width in pixels at default rotation setting (0). + @param h Display height in pixels at default rotation setting (0). + @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). + @param dc Arduino pin # for data/command select (required). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @return Adafruit_SPITFT object. + @note Output pins are not initialized; application typically will + need to call subclass' begin() function, which in turn calls + this library's initSPI() function to initialize pins. +*/ +#if defined(ESP8266) // See notes below +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, + int8_t dc, int8_t rst) : Renderer(w, h), + connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { + hwspi._spi = &SPI; +} +#else // !ESP8266 +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, + int8_t dc, int8_t rst) : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst) { + // This just invokes the hardware SPI constructor below, + // passing the default SPI device (&SPI). +} +#endif // end !ESP8266 + +#if !defined(ESP8266) +// ESP8266 compiler freaks out at this constructor -- it can't disambiguate +// beteween the SPIClass pointer (argument #3) and a regular integer. +// Solution here it to just not offer this variant on the ESP8266. You can +// use the default hardware SPI peripheral, or you can use software SPI, +// but if there's any library out there that creates a 'virtual' SPIClass +// peripheral and drives it with software bitbanging, that's not supported. +/*! + @brief Adafruit_SPITFT constructor for hardware SPI using a specific + SPI peripheral. + @param w Display width in pixels at default rotation (0). + @param h Display height in pixels at default rotation (0). + @param spiClass Pointer to SPIClass type (e.g. &SPI or &SPI1). + @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). + @param dc Arduino pin # for data/command select (required). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @return Adafruit_SPITFT object. + @note Output pins are not initialized in constructor; application + typically will need to call subclass' begin() function, which + in turn calls this library's initSPI() function to initialize + pins. EXCEPT...if you have built your own SERCOM SPI peripheral + (calling the SPIClass constructor) rather than one of the + built-in SPI devices (e.g. &SPI, &SPI1 and so forth), you will + need to call the begin() function for your object as well as + pinPeripheral() for the MOSI, MISO and SCK pins to configure + GPIO manually. Do this BEFORE calling the display-specific + begin or init function. Unfortunate but unavoidable. +*/ +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, + int8_t cs, int8_t dc, int8_t rst) : Renderer(w, h), + connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { + hwspi._spi = spiClass; +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(CORE_TEENSY) + #if !defined(KINETISK) + dcPinMask = digitalPinToBitMask(dc); + #endif + dcPortSet = portSetRegister(dc); + dcPortClr = portClearRegister(dc); + if(cs >= 0) { + #if !defined(KINETISK) + csPinMask = digitalPinToBitMask(cs); + #endif + csPortSet = portSetRegister(cs); + csPortClr = portClearRegister(cs); + } else { // see comments below + #if !defined(KINETISK) + csPinMask = 0; + #endif + csPortSet = dcPortSet; + csPortClr = dcPortClr; + } + #else // !CORE_TEENSY + dcPinMask = digitalPinToBitMask(dc); + dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); + dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); + if(cs >= 0) { + csPinMask = digitalPinToBitMask(cs); + csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); + csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPortSet = dcPortSet; + csPortClr = dcPortClr; + csPinMask = 0; + } + #endif // end !CORE_TEENSY + #else // !HAS_PORT_SET_CLR + dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); + dcPinMaskSet = digitalPinToBitMask(dc); + if(cs >= 0) { + csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); + csPinMaskSet = digitalPinToBitMask(cs); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPort = dcPort; + csPinMaskSet = 0; + } + csPinMaskClr = ~csPinMaskSet; + dcPinMaskClr = ~dcPinMaskSet; + #endif // end !HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +} +#endif // end !ESP8266 + +/*! + @brief Adafruit_SPITFT constructor for parallel display connection. + @param w Display width in pixels at default rotation (0). + @param h Display height in pixels at default rotation (0). + @param busWidth If tft16 (enumeration in header file), is a 16-bit + parallel connection, else 8-bit. + 16-bit isn't fully implemented or tested yet so + applications should pass "tft8bitbus" for now...needed to + stick a required enum argument in there to + disambiguate this constructor from the soft-SPI case. + Argument is ignored on 8-bit architectures (no 'wide' + support there since PORTs are 8 bits anyway). + @param d0 Arduino pin # for data bit 0 (1+ are extrapolated). + The 8 (or 16) data bits MUST be contiguous and byte- + aligned (or word-aligned for wide interface) within + the same PORT register (might not correspond to + Arduino pin sequence). + @param wr Arduino pin # for write strobe (required). + @param dc Arduino pin # for data/command select (required). + @param cs Arduino pin # for chip-select (optional, -1 if unused, + tie CS low). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @param rd Arduino pin # for read strobe (optional, -1 if unused). + @return Adafruit_SPITFT object. + @note Output pins are not initialized; application typically will need + to call subclass' begin() function, which in turn calls this + library's initSPI() function to initialize pins. + Yes, the name is a misnomer...this library originally handled + only SPI displays, parallel being a recent addition (but not + wanting to break existing code). +*/ +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, + int8_t d0, int8_t wr, int8_t dc, int8_t cs, int8_t rst, int8_t rd) : + Renderer(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), _dc(dc) { + tft8._d0 = d0; + tft8._wr = wr; + tft8._rd = rd; + tft8.wide = (busWidth == tft16bitbus); +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(CORE_TEENSY) + tft8.wrPortSet = portSetRegister(wr); + tft8.wrPortClr = portClearRegister(wr); + #if !defined(KINETISK) + dcPinMask = digitalPinToBitMask(dc); + #endif + dcPortSet = portSetRegister(dc); + dcPortClr = portClearRegister(dc); + if(cs >= 0) { + #if !defined(KINETISK) + csPinMask = digitalPinToBitMask(cs); + #endif + csPortSet = portSetRegister(cs); + csPortClr = portClearRegister(cs); + } else { // see comments below + #if !defined(KINETISK) + csPinMask = 0; + #endif + csPortSet = dcPortSet; + csPortClr = dcPortClr; + } + if(rd >= 0) { // if read-strobe pin specified... + #if defined(KINETISK) + tft8.rdPinMask = 1; + #else // !KINETISK + tft8.rdPinMask = digitalPinToBitMask(rd); + #endif + tft8.rdPortSet = portSetRegister(rd); + tft8.rdPortClr = portClearRegister(rd); + } else { + tft8.rdPinMask = 0; + tft8.rdPortSet = dcPortSet; + tft8.rdPortClr = dcPortClr; + } + // These are all uint8_t* pointers -- elsewhere they're recast + // as necessary if a 'wide' 16-bit interface is in use. + tft8.writePort = portOutputRegister(d0); + tft8.readPort = portInputRegister(d0); + tft8.dirSet = portModeRegister(d0); + tft8.dirClr = portModeRegister(d0); + #else // !CORE_TEENSY + tft8.wrPinMask = digitalPinToBitMask(wr); + tft8.wrPortSet = &(PORT->Group[g_APinDescription[wr].ulPort].OUTSET.reg); + tft8.wrPortClr = &(PORT->Group[g_APinDescription[wr].ulPort].OUTCLR.reg); + dcPinMask = digitalPinToBitMask(dc); + dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); + dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); + if(cs >= 0) { + csPinMask = digitalPinToBitMask(cs); + csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); + csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPortSet = dcPortSet; + csPortClr = dcPortClr; + csPinMask = 0; + } + if(rd >= 0) { // if read-strobe pin specified... + tft8.rdPinMask =digitalPinToBitMask(rd); + tft8.rdPortSet =&(PORT->Group[g_APinDescription[rd].ulPort].OUTSET.reg); + tft8.rdPortClr =&(PORT->Group[g_APinDescription[rd].ulPort].OUTCLR.reg); + } else { + tft8.rdPinMask = 0; + tft8.rdPortSet = dcPortSet; + tft8.rdPortClr = dcPortClr; + } + // Get pointers to PORT write/read/dir bytes within 32-bit PORT + uint8_t dBit = g_APinDescription[d0].ulPin; // d0 bit # in PORT + PortGroup *p = (&(PORT->Group[g_APinDescription[d0].ulPort])); + uint8_t offset = dBit / 8; // d[7:0] byte # within PORT + if(tft8.wide) offset &= ~1; // d[15:8] byte # within PORT + // These are all uint8_t* pointers -- elsewhere they're recast + // as necessary if a 'wide' 16-bit interface is in use. + tft8.writePort = (volatile uint8_t *)&(p->OUT.reg) + offset; + tft8.readPort = (volatile uint8_t *)&(p->IN.reg) + offset; + tft8.dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset; + tft8.dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset; + #endif // end !CORE_TEENSY + #else // !HAS_PORT_SET_CLR + tft8.wrPort = (PORTreg_t)portOutputRegister(digitalPinToPort(wr)); + tft8.wrPinMaskSet = digitalPinToBitMask(wr); + dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); + dcPinMaskSet = digitalPinToBitMask(dc); + if(cs >= 0) { + csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); + csPinMaskSet = digitalPinToBitMask(cs); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPort = dcPort; + csPinMaskSet = 0; + } + if(rd >= 0) { // if read-strobe pin specified... + tft8.rdPort =(PORTreg_t)portOutputRegister(digitalPinToPort(rd)); + tft8.rdPinMaskSet =digitalPinToBitMask(rd); + } else { + tft8.rdPort = dcPort; + tft8.rdPinMaskSet = 0; + } + csPinMaskClr = ~csPinMaskSet; + dcPinMaskClr = ~dcPinMaskSet; + tft8.wrPinMaskClr = ~tft8.wrPinMaskSet; + tft8.rdPinMaskClr = ~tft8.rdPinMaskSet; + tft8.writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(d0)); + tft8.readPort = (PORTreg_t)portInputRegister(digitalPinToPort(d0)); + tft8.portDir = (PORTreg_t)portModeRegister(digitalPinToPort(d0)); + #endif // end !HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +} + +// end constructors ------- + + +// CLASS MEMBER FUNCTIONS -------------------------------------------------- + +// begin() and setAddrWindow() MUST be declared by any subclass. + +/*! + @brief Configure microcontroller pins for TFT interfacing. Typically + called by a subclass' begin() function. + @param freq SPI frequency when using hardware SPI. If default (0) + is passed, will fall back on a device-specific value. + Value is ignored when using software SPI or parallel + connection. + @param spiMode SPI mode when using hardware SPI. MUST be one of the + values SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 + defined in SPI.h. Do NOT attempt to pass '0' for + SPI_MODE0 and so forth...the values are NOT the same! + Use ONLY the defines! (Pity it's not an enum.) + @note Another anachronistically-named function; this is called even + when the display connection is parallel (not SPI). Also, this + could probably be made private...quite a few class functions + were generously put in the public section. +*/ +void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) { + + if(!freq) freq = DEFAULT_SPI_FREQ; // If no freq specified, use default + + // Init basic control pins common to all connection types + if(_cs >= 0) { + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); // Deselect + } + pinMode(_dc, OUTPUT); + digitalWrite(_dc, HIGH); // Data mode + + if(connection == TFT_HARD_SPI) { + +#if defined(SPI_HAS_TRANSACTION) + hwspi.settings = SPISettings(freq, MSBFIRST, spiMode); +#else + hwspi._freq = freq; // Save freq value for later +#endif + hwspi._mode = spiMode; // Save spiMode value for later + // Call hwspi._spi->begin() ONLY if this is among the 'established' + // SPI interfaces in variant.h. For DIY roll-your-own SERCOM SPIs, + // begin() and pinPeripheral() calls MUST be made in one's calling + // code, BEFORE the screen-specific begin/init function is called. + // Reason for this is that SPI::begin() makes its own calls to + // pinPeripheral() based on g_APinDescription[n].ulPinType, which + // on non-established SPI interface pins will always be PIO_DIGITAL + // or similar, while we need PIO_SERCOM or PIO_SERCOM_ALT...it's + // highly unique between devices and variants for each pin or + // SERCOM so we can't make those calls ourselves here. And the SPI + // device needs to be set up before calling this because it's + // immediately followed with initialization commands. Blargh. + if( +#if !defined(SPI_INTERFACES_COUNT) + 1 +#endif +#if SPI_INTERFACES_COUNT > 0 + (hwspi._spi == &SPI) +#endif +#if SPI_INTERFACES_COUNT > 1 + || (hwspi._spi == &SPI1) +#endif +#if SPI_INTERFACES_COUNT > 2 + || (hwspi._spi == &SPI2) +#endif +#if SPI_INTERFACES_COUNT > 3 + || (hwspi._spi == &SPI3) +#endif +#if SPI_INTERFACES_COUNT > 4 + || (hwspi._spi == &SPI4) +#endif +#if SPI_INTERFACES_COUNT > 5 + || (hwspi._spi == &SPI5) +#endif + ) { + hwspi._spi->begin(); + } + } else if(connection == TFT_SOFT_SPI) { + + pinMode(swspi._mosi, OUTPUT); + digitalWrite(swspi._mosi, LOW); + pinMode(swspi._sck, OUTPUT); + digitalWrite(swspi._sck, LOW); + if(swspi._miso >= 0) { + pinMode(swspi._miso, INPUT); + } + + } else { // TFT_PARALLEL + + // Initialize data pins. We were only passed d0, so scan + // the pin description list looking for the other pins. + // They'll be on the same PORT, and within the next 7 (or 15) bits + // (because we need to write to a contiguous PORT byte or word). +#if defined(__AVR__) + // PORT registers are 8 bits wide, so just need a register match... + for(uint8_t i=0; i= dBit ) && + (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) { + pinMode(i, OUTPUT); + digitalWrite(i, LOW); + } + } + #endif // end !CORE_TEENSY +#endif + pinMode(tft8._wr, OUTPUT); + digitalWrite(tft8._wr, HIGH); + if(tft8._rd >= 0) { + pinMode(tft8._rd, OUTPUT); + digitalWrite(tft8._rd, HIGH); + } + } + + if(_rst >= 0) { + // Toggle _rst low to reset + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + +#if defined(USE_SPI_DMA) + if(((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && + (dma.allocate() == DMA_STATUS_OK)) { // Allocate channel + // The DMA library needs to alloc at least one valid descriptor, + // so we do that here. It's not used in the usual sense though, + // just before a transfer we copy descriptor[0] to this address. + if(dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE, + false, false)) { + // Alloc 2 scanlines worth of pixels on display's major axis, + // whichever that is, rounding each up to 2-pixel boundary. + int major = (WIDTH > HEIGHT) ? WIDTH : HEIGHT; + major += (major & 1); // -> next 2-pixel bound, if needed. + maxFillLen = major * 2; // 2 scanlines + // Note to future self: if you decide to make the pixel buffer + // much larger, remember that DMA transfer descriptors can't + // exceed 65,535 bytes (not 65,536), meaning 32,767 pixels max. + // Not that we have that kind of RAM to throw around right now. + if((pixelBuf[0] = + (uint16_t *)malloc(maxFillLen * sizeof(uint16_t)))) { + // Alloc OK. Get pointer to start of second scanline. + pixelBuf[1] = &pixelBuf[0][major]; + // Determine number of DMA descriptors needed to cover + // entire screen when entire 2-line pixelBuf is used + // (round up for fractional last descriptor). + int numDescriptors = (WIDTH * HEIGHT + (maxFillLen - 1)) / + maxFillLen; + // DMA descriptors MUST be 128-bit (16 byte) aligned. + // memalign() is considered obsolete but it's replacements + // (aligned_alloc() or posix_memalign()) are not currently + // available in the version of ARM GCC in use, but this + // is, so here we are. + if((descriptor = (DmacDescriptor *)memalign(16, + numDescriptors * sizeof(DmacDescriptor)))) { + int dmac_id; + volatile uint32_t *data_reg; + + if(connection == TFT_HARD_SPI) { + // THIS IS AN AFFRONT TO NATURE, but I don't know + // any "clean" way to get the sercom number from the + // the SPIClass pointer (e.g. &SPI or &SPI1), which + // is all we have to work with. SPIClass does contain + // a SERCOM pointer but it is a PRIVATE member! + // Doing an UNSPEAKABLY HORRIBLE THING here, directly + // accessing the first 32-bit value in the SPIClass + // structure, knowing that's (currently) where the + // SERCOM pointer lives, but this ENTIRELY DEPENDS on + // that structure not changing nor the compiler + // rearranging things. Oh the humanity! + + if(*(SERCOM **)hwspi._spi == &sercom0) { + dmac_id = SERCOM0_DMAC_ID_TX; + data_reg = &SERCOM0->SPI.DATA.reg; +#if defined SERCOM1 + } else if(*(SERCOM **)hwspi._spi == &sercom1) { + dmac_id = SERCOM1_DMAC_ID_TX; + data_reg = &SERCOM1->SPI.DATA.reg; +#endif +#if defined SERCOM2 + } else if(*(SERCOM **)hwspi._spi == &sercom2) { + dmac_id = SERCOM2_DMAC_ID_TX; + data_reg = &SERCOM2->SPI.DATA.reg; +#endif +#if defined SERCOM3 + } else if(*(SERCOM **)hwspi._spi == &sercom3) { + dmac_id = SERCOM3_DMAC_ID_TX; + data_reg = &SERCOM3->SPI.DATA.reg; +#endif +#if defined SERCOM4 + } else if(*(SERCOM **)hwspi._spi == &sercom4) { + dmac_id = SERCOM4_DMAC_ID_TX; + data_reg = &SERCOM4->SPI.DATA.reg; +#endif +#if defined SERCOM5 + } else if(*(SERCOM **)hwspi._spi == &sercom5) { + dmac_id = SERCOM5_DMAC_ID_TX; + data_reg = &SERCOM5->SPI.DATA.reg; +#endif +#if defined SERCOM6 + } else if(*(SERCOM **)hwspi._spi == &sercom6) { + dmac_id = SERCOM6_DMAC_ID_TX; + data_reg = &SERCOM6->SPI.DATA.reg; +#endif +#if defined SERCOM7 + } else if(*(SERCOM **)hwspi._spi == &sercom7) { + dmac_id = SERCOM7_DMAC_ID_TX; + data_reg = &SERCOM7->SPI.DATA.reg; +#endif + } + dma.setPriority(DMA_PRIORITY_3); + dma.setTrigger(dmac_id); + dma.setAction(DMA_TRIGGER_ACTON_BEAT); + + // Initialize descriptor list. + for(int d=0; dChannel[dmaChannel].CHEVCTRL.bit.EVOE = 1; + DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOMODE = 0; + + // CONFIGURE TIMER/COUNTER (for write strobe) + + Tc *timer = tcList[tcNum].tc; // -> Timer struct + int id = tcList[tcNum].gclk; // Timer GCLK ID + GCLK_PCHCTRL_Type pchctrl; + + // Set up timer clock source from GCLK + GCLK->PCHCTRL[id].bit.CHEN = 0; // Stop timer + while(GCLK->PCHCTRL[id].bit.CHEN); // Wait for it + pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; + pchctrl.bit.CHEN = 1; // Enable + GCLK->PCHCTRL[id].reg = pchctrl.reg; + while(!GCLK->PCHCTRL[id].bit.CHEN); // Wait for it + + // Disable timer/counter before configuring it + timer->COUNT8.CTRLA.bit.ENABLE = 0; + while(timer->COUNT8.SYNCBUSY.bit.STATUS); + + timer->COUNT8.WAVE.bit.WAVEGEN = 2; // NPWM + timer->COUNT8.CTRLA.bit.MODE = 1; // 8-bit + timer->COUNT8.CTRLA.bit.PRESCALER = 0; // 1:1 + while(timer->COUNT8.SYNCBUSY.bit.STATUS); + + timer->COUNT8.CTRLBCLR.bit.DIR = 1; // Count UP + while(timer->COUNT8.SYNCBUSY.bit.CTRLB); + timer->COUNT8.CTRLBSET.bit.ONESHOT = 1; // One-shot + while(timer->COUNT8.SYNCBUSY.bit.CTRLB); + timer->COUNT8.PER.reg = 6; // PWM top + while(timer->COUNT8.SYNCBUSY.bit.PER); + timer->COUNT8.CC[0].reg = 2; // Compare + while(timer->COUNT8.SYNCBUSY.bit.CC0); + // Enable async input events, + // event action = restart. + timer->COUNT8.EVCTRL.bit.TCEI = 1; + timer->COUNT8.EVCTRL.bit.EVACT = 1; + + // Enable timer + timer->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE; + while(timer->COUNT8.SYNCBUSY.bit.STATUS); + +#if(wrPeripheral == PIO_CCL) + // CONFIGURE CCL (inverts timer/counter output) + + MCLK->APBCMASK.bit.CCL_ = 1; // Enable CCL clock + CCL->CTRL.bit.ENABLE = 0; // Disable to config + CCL->CTRL.bit.SWRST = 1; // Reset CCL registers + CCL->LUTCTRL[tcNum].bit.ENABLE = 0; // Disable LUT + CCL->LUTCTRL[tcNum].bit.FILTSEL = 0; // No filter + CCL->LUTCTRL[tcNum].bit.INSEL0 = 6; // TC input + CCL->LUTCTRL[tcNum].bit.INSEL1 = 0; // MASK + CCL->LUTCTRL[tcNum].bit.INSEL2 = 0; // MASK + CCL->LUTCTRL[tcNum].bit.TRUTH = 1; // Invert in 0 + CCL->LUTCTRL[tcNum].bit.ENABLE = 1; // Enable LUT + CCL->CTRL.bit.ENABLE = 1; // Enable CCL +#endif + + // CONFIGURE EVENT SYSTEM + + // Set up event system clock source from GCLK... + // Disable EVSYS, wait for disable + GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 0; + while(GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); + pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; + pchctrl.bit.CHEN = 1; // Re-enable + GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg = pchctrl.reg; + // Wait for it, then enable EVSYS clock + while(!GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); + MCLK->APBBMASK.bit.EVSYS_ = 1; + + // Connect Timer EVU to ch 0 + EVSYS->USER[tcList[tcNum].evu].reg = 1; + // Datasheet recommends single write operation; + // reg instead of bit. Also datasheet: PATH bits + // must be zero when using async! + EVSYS_CHANNEL_Type ev; + ev.reg = 0; + ev.bit.PATH = 2; // Asynchronous + ev.bit.EVGEN = 0x22 + dmaChannel; // DMA channel 0+ + EVSYS->Channel[0].CHANNEL.reg = ev.reg; + + // Initialize descriptor list. + for(int d=0; d= 0) SPI_CS_LOW(); +} + +/*! + @brief Call after issuing command(s) or data to display. Performs + chip-deselect (if required) and ends an SPI transaction (if + using hardware SPI and transactions are supported). Required + for all display types; not an SPI-specific function. +*/ +void Adafruit_SPITFT::endWrite(void) { + if(_cs >= 0) SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + + +// ------------------------------------------------------------------------- +// Lower-level graphics operations. These functions require a chip-select +// and/or SPI transaction around them (via startWrite(), endWrite() above). +// Higher-level graphics primitives might start a single transaction and +// then make multiple calls to these functions (e.g. circle or text +// rendering might make repeated lines or rects) before ending the +// transaction. It's more efficient than starting a transaction every time. + +/*! + @brief Draw a single pixel to the display at requested coordinates. + Not self-contained; should follow a startWrite() call. + @param x Horizontal position (0 = left). + @param y Vertical position (0 = top). + @param color 16-bit pixel color in '565' RGB format. +*/ +void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) { + if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { + setAddrWindow(x, y, 1, 1); + SPI_WRITE16(color); + } +} + +/*! + @brief Issue a series of pixels from memory to the display. Not self- + contained; should follow startWrite() and setAddrWindow() calls. + @param colors Pointer to array of 16-bit pixel values in '565' RGB + format. + @param len Number of elements in 'colors' array. + @param block If true (default case if unspecified), function blocks + until DMA transfer is complete. This is simply IGNORED + if DMA is not enabled. If false, the function returns + immediately after the last DMA transfer is started, + and one should use the dmaWait() function before + doing ANY other display-related activities (or even + any SPI-related activities, if using an SPI display + that shares the bus with other devices). + @param bigEndian If using DMA, and if set true, bitmap in memory is in + big-endian order (most significant byte first). By + default this is false, as most microcontrollers seem + to be little-endian and 16-bit pixel values must be + byte-swapped before issuing to the display (which tend + to be big-endian when using SPI or 8-bit parallel). + If an application can optimize around this -- for + example, a bitmap in a uint16_t array having the byte + values already reordered big-endian, this can save + some processing time here, ESPECIALLY if using this + function's non-blocking DMA mode. Not all cases are + covered...this is really here only for SAMD DMA and + much forethought on the application side. +*/ +void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, + bool block, bool bigEndian) { + + if(!len) return; // Avoid 0-byte transfers + +#if defined(ESP32) // ESP32 has a special SPI pixel-writing function... + if(connection == TFT_HARD_SPI) { + hwspi._spi->writePixels(colors, len * 2); + return; + } +#elif defined(USE_SPI_DMA) + if((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) { + int maxSpan = maxFillLen / 2; // One scanline max + uint8_t pixelBufIdx = 0; // Active pixel buffer number + #if defined(__SAMD51__) + if(connection == TFT_PARALLEL) { + // Switch WR pin to PWM or CCL + pinPeripheral(tft8._wr, wrPeripheral); + } + #endif // end __SAMD51__ + if(!bigEndian) { // Normal little-endian situation... + while(len) { + int count = (len < maxSpan) ? len : maxSpan; + + // Because TFT and SAMD endianisms are different, must swap + // bytes from the 'colors' array passed into a DMA working + // buffer. This can take place while the prior DMA transfer + // is in progress, hence the need for two pixelBufs. + for(int i=0; isetDataMode(hwspi._mode); + } else { + pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO + } + #endif // end __SAMD51__ || _SAMD21_ + } + return; + } +#endif // end USE_SPI_DMA + + // All other cases (bitbang SPI or non-DMA hard SPI or parallel), + // use a loop with the normal 16-bit data write function: + while(len--) { + SPI_WRITE16(*colors++); + } +} + +/*! + @brief Wait for the last DMA transfer in a prior non-blocking + writePixels() call to complete. This does nothing if DMA + is not enabled, and is not needed if blocking writePixels() + was used (as is the default case). +*/ +void Adafruit_SPITFT::dmaWait(void) { +#if defined(USE_SPI_DMA) + while(dma_busy); + #if defined(__SAMD51__) || defined(_SAMD21_) + if(connection == TFT_HARD_SPI) { + // See SAMD51/21 note in writeColor() + hwspi._spi->setDataMode(hwspi._mode); + } else { + pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO + } + #endif // end __SAMD51__ || _SAMD21_ +#endif +} + +/*! + @brief Issue a series of pixels, all the same color. Not self- + contained; should follow startWrite() and setAddrWindow() calls. + @param color 16-bit pixel color in '565' RGB format. + @param len Number of pixels to draw. +*/ +void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) { + + if(!len) return; // Avoid 0-byte transfers + + uint8_t hi = color >> 8, lo = color; + +#if defined(ESP32) // ESP32 has a special SPI pixel-writing function... + if(connection == TFT_HARD_SPI) { + #define SPI_MAX_PIXELS_AT_ONCE 32 + #define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1) / 2 + #define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2) + static uint32_t temp[TMPBUF_LONGWORDS]; + uint32_t c32 = color * 0x00010001; + uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS, + xferLen, fillLen; + // Fill temp buffer 32 bits at a time + fillLen = (bufLen + 1) / 2; // Round up to next 32-bit boundary + for(uint32_t t=0; t= 16)) { // Don't bother with DMA on short pixel runs + int i, d, numDescriptors; + if(hi == lo) { // If high & low bytes are same... + onePixelBuf = color; + // Can do this with a relatively short descriptor list, + // each transferring a max of 32,767 (not 32,768) pixels. + // This won't run off the end of the allocated descriptor list, + // since we're using much larger chunks per descriptor here. + numDescriptors = (len + 32766) / 32767; + for(d=0; d lastFillLen) { + int fillStart = lastFillLen / 2, + fillEnd = (((len < maxFillLen) ? + len : maxFillLen) + 1) / 2; + for(i=fillStart; isetDataMode(hwspi._mode); + } else { + pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO + } + #endif // end __SAMD51__ + return; + } + #endif // end USE_SPI_DMA +#endif // end !ESP32 + + // All other cases (non-DMA hard SPI, bitbang SPI, parallel)... + + if(connection == TFT_HARD_SPI) { +#if defined(ESP8266) + do { + uint32_t pixelsThisPass = len; + if(pixelsThisPass > 50000) pixelsThisPass = 50000; + len -= pixelsThisPass; + yield(); // Periodic yield() on long fills + while(pixelsThisPass--) { + hwspi._spi->write(hi); + hwspi._spi->write(lo); + } + } while(len); +#else // !ESP8266 + while(len--) { + #if defined(__AVR__) + AVR_WRITESPI(hi); + AVR_WRITESPI(lo); + #elif defined(ESP32) + hwspi._spi->write(hi); + hwspi._spi->write(lo); + #else + hwspi._spi->transfer(hi); + hwspi._spi->transfer(lo); + #endif + } +#endif // end !ESP8266 + } else if(connection == TFT_SOFT_SPI) { +#if defined(ESP8266) + do { + uint32_t pixelsThisPass = len; + if(pixelsThisPass > 20000) pixelsThisPass = 20000; + len -= pixelsThisPass; + yield(); // Periodic yield() on long fills + while(pixelsThisPass--) { + for(uint16_t bit=0, x=color; bit<16; bit++) { + if(x & 0x8000) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + x <<= 1; + } + } + } while(len); +#else // !ESP8266 + while(len--) { + #if defined(__AVR__) + for(uint8_t bit=0, x=hi; bit<8; bit++) { + if(x & 0x80) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + x <<= 1; + } + for(uint8_t bit=0, x=lo; bit<8; bit++) { + if(x & 0x80) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + x <<= 1; + } + #else // !__AVR__ + for(uint16_t bit=0, x=color; bit<16; bit++) { + if(x & 0x8000) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + x <<= 1; + SPI_SCK_LOW(); + } + #endif // end !__AVR__ + } +#endif // end !ESP8266 + } else { // PARALLEL + if(hi == lo) { +#if defined(__AVR__) + len *= 2; + *tft8.writePort = hi; + while(len--) { + TFT_WR_STROBE(); + } +#elif defined(USE_FAST_PINIO) + if(!tft8.wide) { + len *= 2; + *tft8.writePort = hi; + } else { + *(volatile uint16_t *)tft8.writePort = color; + } + while(len--) { + TFT_WR_STROBE(); + } +#endif + } else { + while(len--) { +#if defined(__AVR__) + *tft8.writePort = hi; + TFT_WR_STROBE(); + *tft8.writePort = lo; +#elif defined(USE_FAST_PINIO) + if(!tft8.wide) { + *tft8.writePort = hi; + TFT_WR_STROBE(); + *tft8.writePort = lo; + } else { + *(volatile uint16_t *)tft8.writePort = color; + } +#endif + TFT_WR_STROBE(); + } + } + } +} + +/*! + @brief Draw a filled rectangle to the display. Not self-contained; + should follow startWrite(). Typically used by higher-level + graphics primitives; user code shouldn't need to call this and + is likely to use the self-contained fillRect() instead. + writeFillRect() performs its own edge clipping and rejection; + see writeFillRectPreclipped() for a more 'raw' implementation. + @param x Horizontal position of first corner. + @param y Vertical position of first corner. + @param w Rectangle width in pixels (positive = right of first + corner, negative = left of first corner). + @param h Rectangle height in pixels (positive = below first + corner, negative = above first corner). + @param color 16-bit fill color in '565' RGB format. + @note Written in this deep-nested way because C by definition will + optimize for the 'if' case, not the 'else' -- avoids branches + and rejects clipped rectangles at the least-work possibility. +*/ +void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, + int16_t w, int16_t h, uint16_t color) { + if(w && h) { // Nonzero width and height? + if(w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if(x < _width) { // Not off right + if(h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if(y < _height) { // Not off bottom + int16_t x2 = x + w - 1; + if(x2 >= 0) { // Not off left + int16_t y2 = y + h - 1; + if(y2 >= 0) { // Not off top + // Rectangle partly or fully overlaps screen + if(x < 0) { x = 0; w = x2 + 1; } // Clip left + if(y < 0) { y = 0; h = y2 + 1; } // Clip top + if(x2 >= _width) { w = _width - x; } // Clip right + if(y2 >= _height) { h = _height - y; } // Clip bottom + writeFillRectPreclipped(x, y, w, h, color); + } + } + } + } + } +} + +/*! + @brief Draw a horizontal line on the display. Performs edge clipping + and rejection. Not self-contained; should follow startWrite(). + Typically used by higher-level graphics primitives; user code + shouldn't need to call this and is likely to use the self- + contained drawFastHLine() instead. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param w Line width in pixels (positive = right of first point, + negative = point of first corner). + @param color 16-bit line color in '565' RGB format. +*/ +void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width + if(w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if(x < _width) { // Not off right + int16_t x2 = x + w - 1; + if(x2 >= 0) { // Not off left + // Line partly or fully overlaps screen + if(x < 0) { x = 0; w = x2 + 1; } // Clip left + if(x2 >= _width) { w = _width - x; } // Clip right + writeFillRectPreclipped(x, y, w, 1, color); + } + } + } +} + +/*! + @brief Draw a vertical line on the display. Performs edge clipping and + rejection. Not self-contained; should follow startWrite(). + Typically used by higher-level graphics primitives; user code + shouldn't need to call this and is likely to use the self- + contained drawFastVLine() instead. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param h Line height in pixels (positive = below first point, + negative = above first point). + @param color 16-bit line color in '565' RGB format. +*/ +void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height + if(h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if(y < _height) { // Not off bottom + int16_t y2 = y + h - 1; + if(y2 >= 0) { // Not off top + // Line partly or fully overlaps screen + if(y < 0) { y = 0; h = y2 + 1; } // Clip top + if(y2 >= _height) { h = _height - y; } // Clip bottom + writeFillRectPreclipped(x, y, 1, h, color); + } + } + } +} + +/*! + @brief A lower-level version of writeFillRect(). This version requires + all inputs are in-bounds, that width and height are positive, + and no part extends offscreen. NO EDGE CLIPPING OR REJECTION IS + PERFORMED. If higher-level graphics primitives are written to + handle their own clipping earlier in the drawing process, this + can avoid unnecessary function calls and repeated clipping + operations in the lower-level functions. + @param x Horizontal position of first corner. MUST BE WITHIN + SCREEN BOUNDS. + @param y Vertical position of first corner. MUST BE WITHIN SCREEN + BOUNDS. + @param w Rectangle width in pixels. MUST BE POSITIVE AND NOT + EXTEND OFF SCREEN. + @param h Rectangle height in pixels. MUST BE POSITIVE AND NOT + EXTEND OFF SCREEN. + @param color 16-bit fill color in '565' RGB format. + @note This is a new function, no graphics primitives besides rects + and horizontal/vertical lines are written to best use this yet. +*/ +inline void Adafruit_SPITFT::writeFillRectPreclipped(int16_t x, int16_t y, + int16_t w, int16_t h, uint16_t color) { + setAddrWindow(x, y, w, h); + writeColor(color, (uint32_t)w * h); +} + + +// ------------------------------------------------------------------------- +// Ever-so-slightly higher-level graphics operations. Similar to the 'write' +// functions above, but these contain their own chip-select and SPI +// transactions as needed (via startWrite(), endWrite()). They're typically +// used solo -- as graphics primitives in themselves, not invoked by higher- +// level primitives (which should use the functions above for better +// performance). + +/*! + @brief Draw a single pixel to the display at requested coordinates. + Self-contained and provides its own transaction as needed + (see writePixel(x,y,color) for a lower-level variant). + Edge clipping is performed here. + @param x Horizontal position (0 = left). + @param y Vertical position (0 = top). + @param color 16-bit pixel color in '565' RGB format. +*/ +void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color) { + // Clip first... + if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { + // THEN set up transaction (if needed) and draw... + startWrite(); + setAddrWindow(x, y, 1, 1); + SPI_WRITE16(color); + endWrite(); + } +} + +/*! + @brief Draw a filled rectangle to the display. Self-contained and + provides its own transaction as needed (see writeFillRect() or + writeFillRectPreclipped() for lower-level variants). Edge + clipping and rejection is performed here. + @param x Horizontal position of first corner. + @param y Vertical position of first corner. + @param w Rectangle width in pixels (positive = right of first + corner, negative = left of first corner). + @param h Rectangle height in pixels (positive = below first + corner, negative = above first corner). + @param color 16-bit fill color in '565' RGB format. + @note This repeats the writeFillRect() function almost in its entirety, + with the addition of a transaction start/end. It's done this way + (rather than starting the transaction and calling writeFillRect() + to handle clipping and so forth) so that the transaction isn't + performed at all if the rectangle is rejected. It's really not + that much code. +*/ +void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + if(w && h) { // Nonzero width and height? + if(w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if(x < _width) { // Not off right + if(h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if(y < _height) { // Not off bottom + int16_t x2 = x + w - 1; + if(x2 >= 0) { // Not off left + int16_t y2 = y + h - 1; + if(y2 >= 0) { // Not off top + // Rectangle partly or fully overlaps screen + if(x < 0) { x = 0; w = x2 + 1; } // Clip left + if(y < 0) { y = 0; h = y2 + 1; } // Clip top + if(x2 >= _width) { w = _width - x; } // Clip right + if(y2 >= _height) { h = _height - y; } // Clip bottom + startWrite(); + writeFillRectPreclipped(x, y, w, h, color); + endWrite(); + } + } + } + } + } +} + +/*! + @brief Draw a horizontal line on the display. Self-contained and + provides its own transaction as needed (see writeFastHLine() for + a lower-level variant). Edge clipping and rejection is performed + here. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param w Line width in pixels (positive = right of first point, + negative = point of first corner). + @param color 16-bit line color in '565' RGB format. + @note This repeats the writeFastHLine() function almost in its + entirety, with the addition of a transaction start/end. It's + done this way (rather than starting the transaction and calling + writeFastHLine() to handle clipping and so forth) so that the + transaction isn't performed at all if the line is rejected. +*/ +void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width + if(w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if(x < _width) { // Not off right + int16_t x2 = x + w - 1; + if(x2 >= 0) { // Not off left + // Line partly or fully overlaps screen + if(x < 0) { x = 0; w = x2 + 1; } // Clip left + if(x2 >= _width) { w = _width - x; } // Clip right + startWrite(); + writeFillRectPreclipped(x, y, w, 1, color); + endWrite(); + } + } + } +} + +/*! + @brief Draw a vertical line on the display. Self-contained and provides + its own transaction as needed (see writeFastHLine() for a lower- + level variant). Edge clipping and rejection is performed here. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param h Line height in pixels (positive = below first point, + negative = above first point). + @param color 16-bit line color in '565' RGB format. + @note This repeats the writeFastVLine() function almost in its + entirety, with the addition of a transaction start/end. It's + done this way (rather than starting the transaction and calling + writeFastVLine() to handle clipping and so forth) so that the + transaction isn't performed at all if the line is rejected. +*/ +void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height + if(h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if(y < _height) { // Not off bottom + int16_t y2 = y + h - 1; + if(y2 >= 0) { // Not off top + // Line partly or fully overlaps screen + if(y < 0) { y = 0; h = y2 + 1; } // Clip top + if(y2 >= _height) { h = _height - y; } // Clip bottom + startWrite(); + writeFillRectPreclipped(x, y, 1, h, color); + endWrite(); + } + } + } +} + +/*! + @brief Essentially writePixel() with a transaction around it. I don't + think this is in use by any of our code anymore (believe it was + for some older BMP-reading examples), but is kept here in case + any user code relies on it. Consider it DEPRECATED. + @param color 16-bit pixel color in '565' RGB format. +*/ +void Adafruit_SPITFT::pushColor(uint16_t color) { + startWrite(); + SPI_WRITE16(color); + endWrite(); +} + +/*! + @brief Draw a 16-bit image (565 RGB) at the specified (x,y) position. + For 16-bit display devices; no color reduction performed. + Adapted from https://github.com/PaulStoffregen/ILI9341_t3 + by Marc MERLIN. See examples/pictureEmbed to use this. + 5/6/2017: function name and arguments have changed for + compatibility with current GFX library and to avoid naming + problems in prior implementation. Formerly drawBitmap() with + arguments in different order. Handles its own transaction and + edge clipping/rejection. + @param x Top left corner horizontal coordinate. + @param y Top left corner vertical coordinate. + @param pcolors Pointer to 16-bit array of pixel values. + @param w Width of bitmap in pixels. + @param h Height of bitmap in pixels. +*/ +void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y, + uint16_t *pcolors, int16_t w, int16_t h) { + + int16_t x2, y2; // Lower-right coord + if(( x >= _width ) || // Off-edge right + ( y >= _height) || // " top + ((x2 = (x+w-1)) < 0 ) || // " left + ((y2 = (y+h-1)) < 0) ) return; // " bottom + + int16_t bx1=0, by1=0, // Clipped top-left within bitmap + saveW=w; // Save original bitmap width value + if(x < 0) { // Clip left + w += x; + bx1 = -x; + x = 0; + } + if(y < 0) { // Clip top + h += y; + by1 = -y; + y = 0; + } + if(x2 >= _width ) w = _width - x; // Clip right + if(y2 >= _height) h = _height - y; // Clip bottom + + pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left + startWrite(); + setAddrWindow(x, y, w, h); // Clipped area + while(h--) { // For each (clipped) scanline... + writePixels(pcolors, w); // Push one (clipped) row + pcolors += saveW; // Advance pointer by one full (unclipped) line + } + endWrite(); +} + + +// ------------------------------------------------------------------------- +// Miscellaneous class member functions that don't draw anything. + +/*! + @brief Invert the colors of the display (if supported by hardware). + Self-contained, no transaction setup required. + @param i true = inverted display, false = normal display. +*/ +void Adafruit_SPITFT::invertDisplay(bool i) { + startWrite(); + writeCommand(i ? invertOnCommand : invertOffCommand); + endWrite(); +} + +/*! + @brief Given 8-bit red, green and blue values, return a 'packed' + 16-bit color value in '565' RGB format (5 bits red, 6 bits + green, 5 bits blue). This is just a mathematical operation, + no hardware is touched. + @param red 8-bit red brightnesss (0 = off, 255 = max). + @param green 8-bit green brightnesss (0 = off, 255 = max). + @param blue 8-bit blue brightnesss (0 = off, 255 = max). + @return 'Packed' 16-bit color value (565 format). +*/ +uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) { + return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); +} + +/*! + @brief Adafruit_SPITFT Send Command handles complete sending of commands and data + @param commandByte The Command Byte + @param dataBytes A pointer to the Data bytes to send + @param numDataBytes The number of bytes we should send + */ +void Adafruit_SPITFT::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8_t numDataBytes) { + SPI_BEGIN_TRANSACTION(); + if(_cs >= 0) SPI_CS_LOW(); + + SPI_DC_LOW(); // Command mode + spiWrite(commandByte); // Send the command byte + + SPI_DC_HIGH(); + for (int i=0; i= 0) SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +/*! + @brief Adafruit_SPITFT Send Command handles complete sending of commands and const data + @param commandByte The Command Byte + @param dataBytes A pointer to the Data bytes to send + @param numDataBytes The number of bytes we should send + */ +void Adafruit_SPITFT::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) { + SPI_BEGIN_TRANSACTION(); + if(_cs >= 0) SPI_CS_LOW(); + + SPI_DC_LOW(); // Command mode + spiWrite(commandByte); // Send the command byte + + SPI_DC_HIGH(); + for (int i=0; i= 0) SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +/*! + @brief Read 8 bits of data from display configuration memory (not RAM). + This is highly undocumented/supported and should be avoided, + function is only included because some of the examples use it. + @param commandByte + The command register to read data from. + @param index + The byte index into the command to read from. + @return Unsigned 8-bit data read from display register. + */ +/**************************************************************************/ +uint8_t Adafruit_SPITFT::readcommand8(uint8_t commandByte, uint8_t index) { + uint8_t result; + startWrite(); + SPI_DC_LOW(); // Command mode + spiWrite(commandByte); + SPI_DC_HIGH(); // Data mode + do { + result = spiRead(); + } while(index--); // Discard bytes up to index'th + endWrite(); + return result; +} + +// ------------------------------------------------------------------------- +// Lowest-level hardware-interfacing functions. Many of these are inline and +// compile to different things based on #defines -- typically just a few +// instructions. Others, not so much, those are not inlined. + +/*! + @brief Start an SPI transaction if using the hardware SPI interface to + the display. If using an earlier version of the Arduino platform + (before the addition of SPI transactions), this instead attempts + to set up the SPI clock and mode. No action is taken if the + connection is not hardware SPI-based. This does NOT include a + chip-select operation -- see startWrite() for a function that + encapsulated both actions. +*/ +inline void Adafruit_SPITFT::SPI_BEGIN_TRANSACTION(void) { + if(connection == TFT_HARD_SPI) { +#if defined(SPI_HAS_TRANSACTION) + hwspi._spi->beginTransaction(hwspi.settings); +#else // No transactions, configure SPI manually... + #if defined(__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1) + hwspi._spi->setClockDivider(SPI_CLOCK_DIV2); + #elif defined(__arm__) + hwspi._spi->setClockDivider(11); + #elif defined(ESP8266) || defined(ESP32) + hwspi._spi->setFrequency(hwspi._freq); + #elif defined(RASPI) || defined(ARDUINO_ARCH_STM32F1) + hwspi._spi->setClock(hwspi._freq); + #endif + hwspi._spi->setBitOrder(MSBFIRST); + hwspi._spi->setDataMode(hwspi._mode); +#endif // end !SPI_HAS_TRANSACTION + } +} + +/*! + @brief End an SPI transaction if using the hardware SPI interface to + the display. No action is taken if the connection is not + hardware SPI-based or if using an earlier version of the Arduino + platform (before the addition of SPI transactions). This does + NOT include a chip-deselect operation -- see endWrite() for a + function that encapsulated both actions. +*/ +inline void Adafruit_SPITFT::SPI_END_TRANSACTION(void) { +#if defined(SPI_HAS_TRANSACTION) + if(connection == TFT_HARD_SPI) { + hwspi._spi->endTransaction(); + } +#endif +} + +/*! + @brief Issue a single 8-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the byte. This is another of + those functions in the library with a now-not-accurate name + that's being maintained for compatibility with outside code. + This function is used even if display connection is parallel. + @param b 8-bit value to write. +*/ +void Adafruit_SPITFT::spiWrite(uint8_t b) { + if(connection == TFT_HARD_SPI) { +#if defined(__AVR__) + AVR_WRITESPI(b); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->write(b); +#else + hwspi._spi->transfer(b); +#endif + } else if(connection == TFT_SOFT_SPI) { + for(uint8_t bit=0; bit<8; bit++) { + if(b & 0x80) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + b <<= 1; + SPI_SCK_LOW(); + } + } else { // TFT_PARALLEL +#if defined(__AVR__) + *tft8.writePort = b; +#elif defined(USE_FAST_PINIO) + if(!tft8.wide) *tft8.writePort = b; + else *(volatile uint16_t *)tft8.writePort = b; +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Write a single command byte to the display. Chip-select and + transaction must have been previously set -- this ONLY sets + the device to COMMAND mode, issues the byte and then restores + DATA mode. There is no corresponding explicit writeData() + function -- just use spiWrite(). + @param cmd 8-bit command to write. +*/ +void Adafruit_SPITFT::writeCommand(uint8_t cmd) { + SPI_DC_LOW(); + spiWrite(cmd); + SPI_DC_HIGH(); +} + +/*! + @brief Read a single 8-bit value from the display. Chip-select and + transaction must have been previously set -- this ONLY reads + the byte. This is another of those functions in the library + with a now-not-accurate name that's being maintained for + compatibility with outside code. This function is used even if + display connection is parallel. + @return Unsigned 8-bit value read (always zero if USE_FAST_PINIO is + not supported by the MCU architecture). +*/ +uint8_t Adafruit_SPITFT::spiRead(void) { + uint8_t b = 0; + uint16_t w = 0; + if(connection == TFT_HARD_SPI) { + return hwspi._spi->transfer((uint8_t)0); + } else if(connection == TFT_SOFT_SPI) { + if(swspi._miso >= 0) { + for(uint8_t i=0; i<8; i++) { + SPI_SCK_HIGH(); + b <<= 1; + if(SPI_MISO_READ()) b++; + SPI_SCK_LOW(); + } + } + return b; + } else { // TFT_PARALLEL + if(tft8._rd >= 0) { +#if defined(USE_FAST_PINIO) + TFT_RD_LOW(); // Read line LOW + #if defined(__AVR__) + *tft8.portDir = 0x00; // Set port to input state + w = *tft8.readPort; // Read value from port + *tft8.portDir = 0xFF; // Restore port to output + #else // !__AVR__ + if(!tft8.wide) { // 8-bit TFT connection + #if defined(HAS_PORT_SET_CLR) + *tft8.dirClr = 0xFF; // Set port to input state + w = *tft8.readPort; // Read value from port + *tft8.dirSet = 0xFF; // Restore port to output + #else // !HAS_PORT_SET_CLR + *tft8.portDir = 0x00; // Set port to input state + w = *tft8.readPort; // Read value from port + *tft8.portDir = 0xFF; // Restore port to output + #endif // end HAS_PORT_SET_CLR + } else { // 16-bit TFT connection + #if defined(HAS_PORT_SET_CLR) + *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state + w = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state + #else // !HAS_PORT_SET_CLR + *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state + w = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state + #endif // end !HAS_PORT_SET_CLR + } + TFT_RD_HIGH(); // Read line HIGH + #endif // end !__AVR__ +#else // !USE_FAST_PINIO + w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO +#endif // end !USE_FAST_PINIO + } + return w; + } +} + +/*! + @brief Set the software (bitbang) SPI MOSI line HIGH. +*/ +inline void Adafruit_SPITFT::SPI_MOSI_HIGH(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *swspi.mosiPortSet = 1; + #else // !KINETISK + *swspi.mosiPortSet = swspi.mosiPinMask; + #endif + #else // !HAS_PORT_SET_CLR + *swspi.mosiPort |= swspi.mosiPinMaskSet; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._mosi, HIGH); + #if defined(ESP32) + for(volatile uint8_t i=0; i<1; i++); + #endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the software (bitbang) SPI MOSI line LOW. +*/ +inline void Adafruit_SPITFT::SPI_MOSI_LOW(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *swspi.mosiPortClr = 1; + #else // !KINETISK + *swspi.mosiPortClr = swspi.mosiPinMask; + #endif + #else // !HAS_PORT_SET_CLR + *swspi.mosiPort &= swspi.mosiPinMaskClr; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._mosi, LOW); + #if defined(ESP32) + for(volatile uint8_t i=0; i<1; i++); + #endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the software (bitbang) SPI SCK line HIGH. +*/ +inline void Adafruit_SPITFT::SPI_SCK_HIGH(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *swspi.sckPortSet = 1; + #else // !KINETISK + *swspi.sckPortSet = swspi.sckPinMask; + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + for(volatile uint8_t i=0; i<1; i++); + #endif + #endif + #else // !HAS_PORT_SET_CLR + *swspi.sckPort |= swspi.sckPinMaskSet; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._sck, HIGH); + #if defined(ESP32) + for(volatile uint8_t i=0; i<1; i++); + #endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the software (bitbang) SPI SCK line LOW. +*/ +inline void Adafruit_SPITFT::SPI_SCK_LOW(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *swspi.sckPortClr = 1; + #else // !KINETISK + *swspi.sckPortClr = swspi.sckPinMask; + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + for(volatile uint8_t i=0; i<1; i++); + #endif + #endif + #else // !HAS_PORT_SET_CLR + *swspi.sckPort &= swspi.sckPinMaskClr; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._sck, LOW); + #if defined(ESP32) + for(volatile uint8_t i=0; i<1; i++); + #endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Read the state of the software (bitbang) SPI MISO line. + @return true if HIGH, false if LOW. +*/ +inline bool Adafruit_SPITFT::SPI_MISO_READ(void) { +#if defined(USE_FAST_PINIO) + #if defined(KINETISK) + return *swspi.misoPort; + #else // !KINETISK + return *swspi.misoPort & swspi.misoPinMask; + #endif // end !KINETISK +#else // !USE_FAST_PINIO + return digitalRead(swspi._miso); +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Issue a single 16-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the word. Despite the name, + this function is used even if display connection is parallel; + name was maintaned for backward compatibility. Naming is also + not consistent with the 8-bit version, spiWrite(). Sorry about + that. Again, staying compatible with outside code. + @param w 16-bit value to write. +*/ +void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) { + if(connection == TFT_HARD_SPI) { +#if defined(__AVR__) + AVR_WRITESPI(w >> 8); + AVR_WRITESPI(w); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->write16(w); +#else + hwspi._spi->transfer(w >> 8); + hwspi._spi->transfer(w); +#endif + } else if(connection == TFT_SOFT_SPI) { + for(uint8_t bit=0; bit<16; bit++) { + if(w & 0x8000) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + w <<= 1; + } + } else { // TFT_PARALLEL +#if defined(__AVR__) + *tft8.writePort = w >> 8; + TFT_WR_STROBE(); + *tft8.writePort = w; +#elif defined(USE_FAST_PINIO) + if(!tft8.wide) { + *tft8.writePort = w >> 8; + TFT_WR_STROBE(); + *tft8.writePort = w; + } else { + *(volatile uint16_t *)tft8.writePort = w; + } +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Issue a single 32-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the longword. Despite the + name, this function is used even if display connection is + parallel; name was maintaned for backward compatibility. Naming + is also not consistent with the 8-bit version, spiWrite(). + Sorry about that. Again, staying compatible with outside code. + @param l 32-bit value to write. +*/ +void Adafruit_SPITFT::SPI_WRITE32(uint32_t l) { + if(connection == TFT_HARD_SPI) { +#if defined(__AVR__) + AVR_WRITESPI(l >> 24); + AVR_WRITESPI(l >> 16); + AVR_WRITESPI(l >> 8); + AVR_WRITESPI(l ); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->write32(l); +#else + hwspi._spi->transfer(l >> 24); + hwspi._spi->transfer(l >> 16); + hwspi._spi->transfer(l >> 8); + hwspi._spi->transfer(l); +#endif + } else if(connection == TFT_SOFT_SPI) { + for(uint8_t bit=0; bit<32; bit++) { + if(l & 0x80000000) SPI_MOSI_HIGH(); + else SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + l <<= 1; + } + } else { // TFT_PARALLEL +#if defined(__AVR__) + *tft8.writePort = l >> 24; + TFT_WR_STROBE(); + *tft8.writePort = l >> 16; + TFT_WR_STROBE(); + *tft8.writePort = l >> 8; + TFT_WR_STROBE(); + *tft8.writePort = l; +#elif defined(USE_FAST_PINIO) + if(!tft8.wide) { + *tft8.writePort = l >> 24; + TFT_WR_STROBE(); + *tft8.writePort = l >> 16; + TFT_WR_STROBE(); + *tft8.writePort = l >> 8; + TFT_WR_STROBE(); + *tft8.writePort = l; + } else { + *(volatile uint16_t *)tft8.writePort = l >> 16; + TFT_WR_STROBE(); + *(volatile uint16_t *)tft8.writePort = l; + } +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Set the WR line LOW, then HIGH. Used for parallel-connected + interfaces when writing data. +*/ +inline void Adafruit_SPITFT::TFT_WR_STROBE(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *tft8.wrPortClr = 1; + *tft8.wrPortSet = 1; + #else // !KINETISK + *tft8.wrPortClr = tft8.wrPinMask; + *tft8.wrPortSet = tft8.wrPinMask; + #endif // end !KINETISK + #else // !HAS_PORT_SET_CLR + *tft8.wrPort &= tft8.wrPinMaskClr; + *tft8.wrPort |= tft8.wrPinMaskSet; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(tft8._wr, LOW); + digitalWrite(tft8._wr, HIGH); +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the RD line HIGH. Used for parallel-connected interfaces + when reading data. +*/ +inline void Adafruit_SPITFT::TFT_RD_HIGH(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + *tft8.rdPortSet = tft8.rdPinMask; + #else // !HAS_PORT_SET_CLR + *tft8.rdPort |= tft8.rdPinMaskSet; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(tft8._rd, HIGH); +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the RD line LOW. Used for parallel-connected interfaces + when reading data. +*/ +inline void Adafruit_SPITFT::TFT_RD_LOW(void) { +#if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + *tft8.rdPortClr = tft8.rdPinMask; + #else // !HAS_PORT_SET_CLR + *tft8.rdPort &= tft8.rdPinMaskClr; + #endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(tft8._rd, LOW); +#endif // end !USE_FAST_PINIO +} + +#endif // end __AVR_ATtiny85__ diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h new file mode 100644 index 000000000..dcfc1646b --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h @@ -0,0 +1,520 @@ +/*! + * @file Adafruit_SPITFT.h + * + * Part of Adafruit's GFX graphics library. Originally this class was + * written to handle a range of color TFT displays connected via SPI, + * but over time this library and some display-specific subclasses have + * mutated to include some color OLEDs as well as parallel-interfaced + * displays. The name's been kept for the sake of older code. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Limor "ladyada" Fried for Adafruit Industries, + * with contributions from the open source community. + * + * BSD license, all text here must be included in any redistribution. + */ + +#ifndef _ADAFRUIT_SPITFT_H_ +#define _ADAFRUIT_SPITFT_H_ + +#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all + +#include +#include "Adafruit_GFX.h" +#include "renderer.h" + +// HARDWARE CONFIG --------------------------------------------------------- + +#if defined(__AVR__) + typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit + #define USE_FAST_PINIO ///< Use direct PORT register access +#elif defined(ARDUINO_STM32_FEATHER) // WICED + typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED + typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit +#elif defined(__arm__) + #if defined(ARDUINO_ARCH_SAMD) + // Adafruit M0, M4 + typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit + #define USE_FAST_PINIO ///< Use direct PORT register access + #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers + #elif defined(CORE_TEENSY) + // PJRC Teensy 4.x + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit + // PJRC Teensy 3.x + #else + typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit + #endif + #define USE_FAST_PINIO ///< Use direct PORT register access + #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers + #else + // Arduino Due? + typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit + // USE_FAST_PINIO not available here (yet)...Due has a totally different + // GPIO register set and will require some changes elsewhere (e.g. in + // constructors especially). + #endif +#else // !ARM + // Probably ESP8266 or ESP32. USE_FAST_PINIO is not available here (yet) + // but don't worry about it too much...the digitalWrite() implementation + // on these platforms is reasonably efficient and already RAM-resident, + // only gotcha then is no parallel connection support for now. + typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit +#endif // end !ARM +typedef volatile ADAGFX_PORT_t* PORTreg_t; ///< PORT register type + +#if defined(__AVR__) + #define DEFAULT_SPI_FREQ 8000000L ///< Hardware SPI default speed +#else + #define DEFAULT_SPI_FREQ 16000000L ///< Hardware SPI default speed +#endif + +#if defined(ADAFRUIT_PYPORTAL) || defined(ADAFRUIT_PYBADGE_M4_EXPRESS) || defined(ADAFRUIT_PYGAMER_M4_EXPRESS) + #define USE_SPI_DMA ///< Auto DMA if using PyPortal +#else + //#define USE_SPI_DMA ///< If set, use DMA if available +#endif +// Another "oops" name -- this now also handles parallel DMA. +// If DMA is enabled, Arduino sketch MUST #include +// Estimated RAM usage: +// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis, +// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes. + +#if !defined(ARDUINO_ARCH_SAMD) + #undef USE_SPI_DMA ///< DMA currently for SAMD chips only +#endif + +#if defined(USE_SPI_DMA) + #pragma message ("GFX DMA IS ENABLED. HIGHLY EXPERIMENTAL.") + #include +#endif + +// This is kind of a kludge. Needed a way to disambiguate the software SPI +// and parallel constructors via their argument lists. Originally tried a +// bool as the first argument to the parallel constructor (specifying 8-bit +// vs 16-bit interface) but the compiler regards this as equivalent to an +// integer and thus still ambiguous. SO...the parallel constructor requires +// an enumerated type as the first argument: tft8 (for 8-bit parallel) or +// tft16 (for 16-bit)...even though 16-bit isn't fully implemented or tested +// and might never be, still needed that disambiguation from soft SPI. +enum tftBusWidth { tft8bitbus, tft16bitbus }; ///< For first arg to parallel constructor + +// CLASS DEFINITION -------------------------------------------------------- + +/*! + @brief Adafruit_SPITFT is an intermediary class between Adafruit_GFX + and various hardware-specific subclasses for different displays. + It handles certain operations that are common to a range of + displays (address window, area fills, etc.). Originally these were + all color TFT displays interfaced via SPI, but it's since expanded + to include color OLEDs and parallel-interfaced TFTs. THE NAME HAS + BEEN KEPT TO AVOID BREAKING A LOT OF SUBCLASSES AND EXAMPLE CODE. + Many of the class member functions similarly live on with names + that don't necessarily accurately describe what they're doing, + again to avoid breaking a lot of other code. If in doubt, read + the comments. +*/ +class Adafruit_SPITFT : public Renderer { + + public: + + // CONSTRUCTORS -------------------------------------------------------- + + // Software SPI constructor: expects width & height (at default rotation + // setting 0), 4 signal pins (cs, dc, mosi, sclk), 2 optional pins + // (reset, miso). cs argument is required but can be -1 if unused -- + // rather than moving it to the optional arguments, it was done this way + // to avoid breaking existing code (-1 option was a later addition). + Adafruit_SPITFT(uint16_t w, uint16_t h, + int8_t cs, int8_t dc, int8_t mosi, int8_t sck, + int8_t rst = -1, int8_t miso = -1); + + // Hardware SPI constructor using the default SPI port: expects width & + // height (at default rotation setting 0), 2 signal pins (cs, dc), + // optional reset pin. cs is required but can be -1 if unused -- rather + // than moving it to the optional arguments, it was done this way to + // avoid breaking existing code (-1 option was a later addition). + Adafruit_SPITFT(uint16_t w, uint16_t h, + int8_t cs, int8_t dc, int8_t rst = -1); + +#if !defined(ESP8266) // See notes in .cpp + // Hardware SPI constructor using an arbitrary SPI peripheral: expects + // width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc) + // and optional reset pin. cs is required but can be -1 if unused. + Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, + int8_t cs, int8_t dc, int8_t rst = -1); +#endif // end !ESP8266 + + // Parallel constructor: expects width & height (rotation 0), flag + // indicating whether 16-bit (true) or 8-bit (false) interface, 3 signal + // pins (d0, wr, dc), 3 optional pins (cs, rst, rd). 16-bit parallel + // isn't even fully implemented but the 'wide' flag was added as a + // required argument to avoid ambiguity with other constructors. + Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, + int8_t d0, int8_t wr, int8_t dc, + int8_t cs = -1, int8_t rst = -1, int8_t rd = -1); + + // CLASS MEMBER FUNCTIONS ---------------------------------------------- + + // These first two functions MUST be declared by subclasses: + + /*! + @brief Display-specific initialization function. + @param freq SPI frequency, in hz (or 0 for default or unused). + */ + virtual void begin(uint32_t freq) = 0; + + /*! + @brief Set up the specific display hardware's "address window" + for subsequent pixel-pushing operations. + @param x Leftmost pixel of area to be drawn (MUST be within + display bounds at current rotation setting). + @param y Topmost pixel of area to be drawn (MUST be within + display bounds at current rotation setting). + @param w Width of area to be drawn, in pixels (MUST be >0 and, + added to x, within display bounds at current rotation). + @param h Height of area to be drawn, in pixels (MUST be >0 and, + added to x, within display bounds at current rotation). + */ + virtual void setAddrWindow( + uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0; + + // Remaining functions do not need to be declared in subclasses + // unless they wish to provide hardware-specific optimizations. + // Brief comments here...documented more thoroughly in .cpp file. + + // Subclass' begin() function invokes this to initialize hardware. + // freq=0 to use default SPI speed. spiMode must be one of the SPI_MODEn + // values defined in SPI.h, which are NOT the same as 0 for SPI_MODE0, + // 1 for SPI_MODE1, etc...use ONLY the SPI_MODEn defines! Only! + // Name is outdated (interface may be parallel) but for compatibility: + void initSPI(uint32_t freq = 0, uint8_t spiMode = SPI_MODE0); + // Chip select and/or hardware SPI transaction start as needed: + void startWrite(void); + // Chip deselect and/or hardware SPI transaction end as needed: + void endWrite(void); + void sendCommand(uint8_t commandByte, uint8_t *dataBytes = NULL, uint8_t numDataBytes = 0); + void sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes); + uint8_t readcommand8(uint8_t commandByte, uint8_t index = 0); + + // These functions require a chip-select and/or SPI transaction + // around them. Higher-level graphics primitives might start a + // single transaction and then make multiple calls to these functions + // (e.g. circle or text rendering might make repeated lines or rects) + // before ending the transaction. It's more efficient than starting a + // transaction every time. + void writePixel(int16_t x, int16_t y, uint16_t color); + void writePixels(uint16_t *colors, uint32_t len, + bool block=true, bool bigEndian=false); + void writeColor(uint16_t color, uint32_t len); + void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color); + void writeFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color); + void writeFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color); + // This is a new function, similar to writeFillRect() except that + // all arguments MUST be onscreen, sorted and clipped. If higher-level + // primitives can handle their own sorting/clipping, it avoids repeating + // such operations in the low-level code, making it potentially faster. + // CALLING THIS WITH UNCLIPPED OR NEGATIVE VALUES COULD BE DISASTROUS. + inline void writeFillRectPreclipped(int16_t x, int16_t y, + int16_t w, int16_t h, uint16_t color); + // Another new function, companion to the new non-blocking + // writePixels() variant. + void dmaWait(void); + + + // These functions are similar to the 'write' functions above, but with + // a chip-select and/or SPI transaction built-in. They're typically used + // solo -- that is, as graphics primitives in themselves, not invoked by + // higher-level primitives (which should use the functions above). + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color); + // A single-pixel push encapsulated in a transaction. I don't think + // this is used anymore (BMP demos might've used it?) but is provided + // for backward compatibility, consider it deprecated: + void pushColor(uint16_t color); + + using Adafruit_GFX::drawRGBBitmap; // Check base class first + void drawRGBBitmap(int16_t x, int16_t y, + uint16_t *pcolors, int16_t w, int16_t h); + + void invertDisplay(bool i); + uint16_t color565(uint8_t r, uint8_t g, uint8_t b); + + // Despite parallel additions, function names kept for compatibility: + void spiWrite(uint8_t b); // Write single byte as DATA + void writeCommand(uint8_t cmd); // Write single byte as COMMAND + uint8_t spiRead(void); // Read single byte of data + + // Most of these low-level functions were formerly macros in + // Adafruit_SPITFT_Macros.h. Some have been made into inline functions + // to avoid macro mishaps. Despite the addition of code for a parallel + // display interface, the names have been kept for backward + // compatibility (some subclasses may be invoking these): + void SPI_WRITE16(uint16_t w); // Not inline + void SPI_WRITE32(uint32_t l); // Not inline + // Old code had both a spiWrite16() function and SPI_WRITE16 macro + // in addition to the SPI_WRITE32 macro. The latter two have been + // made into functions here, and spiWrite16() removed (use SPI_WRITE16() + // instead). It looks like most subclasses had gotten comfortable with + // SPI_WRITE16 and SPI_WRITE32 anyway so those names were kept rather + // than the less-obnoxious camelcase variants, oh well. + + // Placing these functions entirely in the class definition inlines + // them implicitly them while allowing their use in other code: + + /*! + @brief Set the chip-select line HIGH. Does NOT check whether CS pin + is set (>=0), that should be handled in calling function. + Despite function name, this is used even if the display + connection is parallel. + */ + void SPI_CS_HIGH(void) { + #if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *csPortSet = 1; + #else // !KINETISK + *csPortSet = csPinMask; + #endif // end !KINETISK + #else // !HAS_PORT_SET_CLR + *csPort |= csPinMaskSet; + #endif // end !HAS_PORT_SET_CLR + #else // !USE_FAST_PINIO + digitalWrite(_cs, HIGH); + #endif // end !USE_FAST_PINIO + } + + /*! + @brief Set the chip-select line LOW. Does NOT check whether CS pin + is set (>=0), that should be handled in calling function. + Despite function name, this is used even if the display + connection is parallel. + */ + void SPI_CS_LOW(void) { + #if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *csPortClr = 1; + #else // !KINETISK + *csPortClr = csPinMask; + #endif // end !KINETISK + #else // !HAS_PORT_SET_CLR + *csPort &= csPinMaskClr; + #endif // end !HAS_PORT_SET_CLR + #else // !USE_FAST_PINIO + digitalWrite(_cs, LOW); + #endif // end !USE_FAST_PINIO + } + + /*! + @brief Set the data/command line HIGH (data mode). + */ + void SPI_DC_HIGH(void) { + #if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *dcPortSet = 1; + #else // !KINETISK + *dcPortSet = dcPinMask; + #endif // end !KINETISK + #else // !HAS_PORT_SET_CLR + *dcPort |= dcPinMaskSet; + #endif // end !HAS_PORT_SET_CLR + #else // !USE_FAST_PINIO + digitalWrite(_dc, HIGH); + #endif // end !USE_FAST_PINIO + } + + /*! + @brief Set the data/command line LOW (command mode). + */ + void SPI_DC_LOW(void) { + #if defined(USE_FAST_PINIO) + #if defined(HAS_PORT_SET_CLR) + #if defined(KINETISK) + *dcPortClr = 1; + #else // !KINETISK + *dcPortClr = dcPinMask; + #endif // end !KINETISK + #else // !HAS_PORT_SET_CLR + *dcPort &= dcPinMaskClr; + #endif // end !HAS_PORT_SET_CLR + #else // !USE_FAST_PINIO + digitalWrite(_dc, LOW); + #endif // end !USE_FAST_PINIO + } + + protected: + + // A few more low-level member functions -- some may have previously + // been macros. Shouldn't have a need to access these externally, so + // they've been moved to the protected section. Additionally, they're + // declared inline here and the code is in the .cpp file, since outside + // code doesn't need to see these. + inline void SPI_MOSI_HIGH(void); + inline void SPI_MOSI_LOW(void); + inline void SPI_SCK_HIGH(void); + inline void SPI_SCK_LOW(void); + inline bool SPI_MISO_READ(void); + inline void SPI_BEGIN_TRANSACTION(void); + inline void SPI_END_TRANSACTION(void); + inline void TFT_WR_STROBE(void); // Parallel interface write strobe + inline void TFT_RD_HIGH(void); // Parallel interface read high + inline void TFT_RD_LOW(void); // Parallel interface read low + + // CLASS INSTANCE VARIABLES -------------------------------------------- + + // Here be dragons! There's a big union of three structures here -- + // one each for hardware SPI, software (bitbang) SPI, and parallel + // interfaces. This is to save some memory, since a display's connection + // will be only one of these. The order of some things is a little weird + // in an attempt to get values to align and pack better in RAM. + +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) + PORTreg_t csPortSet; ///< PORT register for chip select SET + PORTreg_t csPortClr; ///< PORT register for chip select CLEAR + PORTreg_t dcPortSet; ///< PORT register for data/command SET + PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR +#else // !HAS_PORT_SET_CLR + PORTreg_t csPort; ///< PORT register for chip select + PORTreg_t dcPort; ///< PORT register for data/command +#endif // end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +#if defined(__cplusplus) && (__cplusplus >= 201100) + union { +#endif + struct { // Values specific to HARDWARE SPI: + SPIClass *_spi; ///< SPI class pointer +#if defined(SPI_HAS_TRANSACTION) + SPISettings settings; ///< SPI transaction settings +#else + uint32_t _freq; ///< SPI bitrate (if no SPI transactions) +#endif + uint32_t _mode; ///< SPI data mode (transactions or no) + } hwspi; ///< Hardware SPI values + struct { // Values specific to SOFTWARE SPI: +#if defined(USE_FAST_PINIO) + PORTreg_t misoPort; ///< PORT (PIN) register for MISO +#if defined(HAS_PORT_SET_CLR) + PORTreg_t mosiPortSet; ///< PORT register for MOSI SET + PORTreg_t mosiPortClr; ///< PORT register for MOSI CLEAR + PORTreg_t sckPortSet; ///< PORT register for SCK SET + PORTreg_t sckPortClr; ///< PORT register for SCK CLEAR + #if !defined(KINETISK) + ADAGFX_PORT_t mosiPinMask; ///< Bitmask for MOSI + ADAGFX_PORT_t sckPinMask; ///< Bitmask for SCK + #endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + PORTreg_t mosiPort; ///< PORT register for MOSI + PORTreg_t sckPort; ///< PORT register for SCK + ADAGFX_PORT_t mosiPinMaskSet; ///< Bitmask for MOSI SET (OR) + ADAGFX_PORT_t mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND) + ADAGFX_PORT_t sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask) + ADAGFX_PORT_t sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND) +#endif // end HAS_PORT_SET_CLR + #if !defined(KINETISK) + ADAGFX_PORT_t misoPinMask; ///< Bitmask for MISO + #endif // end !KINETISK +#endif // end USE_FAST_PINIO + int8_t _mosi; ///< MOSI pin # + int8_t _miso; ///< MISO pin # + int8_t _sck; ///< SCK pin # + } swspi; ///< Software SPI values + struct { // Values specific to 8-bit parallel: +#if defined(USE_FAST_PINIO) + + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + volatile uint32_t *writePort; ///< PORT register for DATA WRITE + volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ + #else + volatile uint8_t *writePort; ///< PORT register for DATA WRITE + volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ + #endif +#if defined(HAS_PORT_SET_CLR) + // Port direction register pointers are always 8-bit regardless of + // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits. + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + volatile uint32_t *dirSet; ///< PORT byte data direction SET + volatile uint32_t *dirClr; ///< PORT byte data direction CLEAR + #else + volatile uint8_t *dirSet; ///< PORT byte data direction SET + volatile uint8_t *dirClr; ///< PORT byte data direction CLEAR + #endif + PORTreg_t wrPortSet; ///< PORT register for write strobe SET + PORTreg_t wrPortClr; ///< PORT register for write strobe CLEAR + PORTreg_t rdPortSet; ///< PORT register for read strobe SET + PORTreg_t rdPortClr; ///< PORT register for read strobe CLEAR + #if !defined(KINETISK) + ADAGFX_PORT_t wrPinMask; ///< Bitmask for write strobe + #endif // end !KINETISK + ADAGFX_PORT_t rdPinMask; ///< Bitmask for read strobe +#else // !HAS_PORT_SET_CLR + // Port direction register pointer is always 8-bit regardless of + // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits. + volatile uint8_t *portDir; ///< PORT direction register + PORTreg_t wrPort; ///< PORT register for write strobe + PORTreg_t rdPort; ///< PORT register for read strobe + ADAGFX_PORT_t wrPinMaskSet; ///< Bitmask for write strobe SET (OR) + ADAGFX_PORT_t wrPinMaskClr; ///< Bitmask for write strobe CLEAR (AND) + ADAGFX_PORT_t rdPinMaskSet; ///< Bitmask for read strobe SET (OR) + ADAGFX_PORT_t rdPinMaskClr; ///< Bitmask for read strobe CLEAR (AND) +#endif // end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO + int8_t _d0; ///< Data pin 0 # + int8_t _wr; ///< Write strobe pin # + int8_t _rd; ///< Read strobe pin # (or -1) + bool wide = 0; ///< If true, is 16-bit interface + } tft8; ///< Parallel interface settings +#if defined(__cplusplus) && (__cplusplus >= 201100) + }; ///< Only one interface is active +#endif +#if defined(USE_SPI_DMA) // Used by hardware SPI and tft8 + Adafruit_ZeroDMA dma; ///< DMA instance + DmacDescriptor *dptr = NULL; ///< 1st descriptor + DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list + uint16_t *pixelBuf[2]; ///< Working buffers + uint16_t maxFillLen; ///< Max pixels per DMA xfer + uint16_t lastFillColor = 0; ///< Last color used w/fill + uint32_t lastFillLen = 0; ///< # of pixels w/last fill + uint8_t onePixelBuf; ///< For hi==lo fill +#endif +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) + #if !defined(KINETISK) + ADAGFX_PORT_t csPinMask; ///< Bitmask for chip select + ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command + #endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR) + ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND) + ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR) + ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND) +#endif // end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO + uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc. + int8_t _rst; ///< Reset pin # (or -1) + int8_t _cs; ///< Chip select pin # (or -1) + int8_t _dc; ///< Data/command pin # + + int16_t _xstart = 0; ///< Internal framebuffer X offset + int16_t _ystart = 0; ///< Internal framebuffer Y offset + uint8_t invertOnCommand = 0; ///< Command to enable invert mode + uint8_t invertOffCommand = 0; ///< Command to disable invert mode + + uint32_t _freq = 0; ///< Dummy var to keep subclasses happy +}; + +#endif // end __AVR_ATtiny85__ +#endif // end _ADAFRUIT_SPITFT_H_ diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp new file mode 100644 index 000000000..78d9901d6 --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp @@ -0,0 +1,190 @@ +/*! + * @file Adafruit_SSD1331.cpp + * + * @mainpage Adafruit SSD1331 Arduino Library + * + * @section intro_sec Introduction + * + * This is a library for the 0.96" 16-bit Color OLED with SSD1331 driver chip + * + * Pick one up today in the adafruit shop! + * ------> http://www.adafruit.com/products/684 + * + * These displays use SPI to communicate, 4 or 5 pins are required to + * interface + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section author Author + * + * Written by Limor Fried/Ladyada for Adafruit Industries. + * + * @section license License + * + * BSD license, all text above must be included in any redistribution + */ + +#include "Adafruit_SSD1331.h" +#include "pins_arduino.h" +#include "wiring_private.h" + +/***********************************/ + +/*! + @brief SPI displays set an address window rectangle for blitting pixels + @param x Top left corner x coordinate + @param y Top left corner x coordinate + @param w Width of window + @param h Height of window +*/ +void Adafruit_SSD1331::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, + uint16_t h) { + + uint8_t x1 = x; + uint8_t y1 = y; + if (x1 > 95) + x1 = 95; + if (y1 > 63) + y1 = 63; + + uint8_t x2 = (x + w - 1); + uint8_t y2 = (y + h - 1); + if (x2 > 95) + x2 = 95; + if (y2 > 63) + y2 = 63; + + if (x1 > x2) { + uint8_t t = x2; + x2 = x1; + x1 = t; + } + if (y1 > y2) { + uint8_t t = y2; + y2 = y1; + y1 = t; + } + + sendCommand(0x15); // Column addr set + sendCommand(x1); + sendCommand(x2); + + sendCommand(0x75); // Column addr set + sendCommand(y1); + sendCommand(y2); + + startWrite(); +} + +/**************************************************************************/ +/*! + @brief Initialize SSD1331 chip + Connects to the SSD1331 over SPI and sends initialization procedure commands + @param freq Desired SPI clock frequency +*/ +/**************************************************************************/ +void Adafruit_SSD1331::begin(uint32_t freq) { + initSPI(freq); + + // Initialization Sequence + sendCommand(SSD1331_CMD_DISPLAYOFF); // 0xAE + sendCommand(SSD1331_CMD_SETREMAP); // 0xA0 +#if defined SSD1331_COLORORDER_RGB + sendCommand(0x72); // RGB Color +#else + sendCommand(0x76); // BGR Color +#endif + sendCommand(SSD1331_CMD_STARTLINE); // 0xA1 + sendCommand(0x0); + sendCommand(SSD1331_CMD_DISPLAYOFFSET); // 0xA2 + sendCommand(0x0); + sendCommand(SSD1331_CMD_NORMALDISPLAY); // 0xA4 + sendCommand(SSD1331_CMD_SETMULTIPLEX); // 0xA8 + sendCommand(0x3F); // 0x3F 1/64 duty + sendCommand(SSD1331_CMD_SETMASTER); // 0xAD + sendCommand(0x8E); + sendCommand(SSD1331_CMD_POWERMODE); // 0xB0 + sendCommand(0x0B); + sendCommand(SSD1331_CMD_PRECHARGE); // 0xB1 + sendCommand(0x31); + sendCommand(SSD1331_CMD_CLOCKDIV); // 0xB3 + sendCommand(0xF0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio + // (A[3:0]+1 = 1..16) + sendCommand(SSD1331_CMD_PRECHARGEA); // 0x8A + sendCommand(0x64); + sendCommand(SSD1331_CMD_PRECHARGEB); // 0x8B + sendCommand(0x78); + sendCommand(SSD1331_CMD_PRECHARGEC); // 0x8C + sendCommand(0x64); + sendCommand(SSD1331_CMD_PRECHARGELEVEL); // 0xBB + sendCommand(0x3A); + sendCommand(SSD1331_CMD_VCOMH); // 0xBE + sendCommand(0x3E); + sendCommand(SSD1331_CMD_MASTERCURRENT); // 0x87 + sendCommand(0x06); + sendCommand(SSD1331_CMD_CONTRASTA); // 0x81 + sendCommand(0x91); + sendCommand(SSD1331_CMD_CONTRASTB); // 0x82 + sendCommand(0x50); + sendCommand(SSD1331_CMD_CONTRASTC); // 0x83 + sendCommand(0x7D); + sendCommand(SSD1331_CMD_DISPLAYON); //--turn on oled panel + _width = TFTWIDTH; + _height = TFTHEIGHT; +} + +/**************************************************************************/ +/*! + @brief Instantiate Adafruit SSD1331 driver with software SPI + @param cs Chip select pin # + @param dc Data/Command pin # + @param mosi SPI MOSI pin # + @param sclk SPI Clock pin # + @param rst Reset pin # (optional, pass -1 if unused) +*/ +/**************************************************************************/ +Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, + int8_t sclk, int8_t rst) + : Adafruit_SPITFT(TFTWIDTH, TFTHEIGHT, cs, dc, mosi, sclk, rst, -1) {} + +/**************************************************************************/ +/*! + @brief Instantiate Adafruit SSD1331 driver with hardware SPI + @param cs Chip select pin # + @param dc Data/Command pin # + @param rst Reset pin # (optional, pass -1 if unused) +*/ +/**************************************************************************/ +Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst) + : Adafruit_SPITFT(TFTWIDTH, TFTHEIGHT, cs, dc, rst) {} + +/**************************************************************************/ +/*! + @brief Instantiate Adafruit SSD1331 driver with hardware SPI + @param spi Pointer to an existing SPIClass instance (e.g. &SPI, the + microcontroller's primary SPI bus). + @param cs Chip select pin # + @param dc Data/Command pin # + @param rst Reset pin # (optional, pass -1 if unused) +*/ +/**************************************************************************/ +Adafruit_SSD1331::Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, + int8_t rst) + : +#if defined(ESP8266) + Adafruit_SPITFT(TFTWIDTH, TFTWIDTH, cs, dc, rst) { +#else + Adafruit_SPITFT(TFTWIDTH, TFTWIDTH, spi, cs, dc, rst) { +#endif +} + +/**************************************************************************/ +/*! + @brief Change whether display is on or off + @param enable True if you want the display ON, false OFF +*/ +/**************************************************************************/ +void Adafruit_SSD1331::enableDisplay(boolean enable) { + sendCommand(enable ? SSD1331_CMD_DISPLAYON : SSD1331_CMD_DISPLAYOFF); +} diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h new file mode 100644 index 000000000..7d9bc85a0 --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h @@ -0,0 +1,76 @@ +/*! + * @file Adafruit_SSD1331.h + */ + +#include "Arduino.h" +#include +// Tasmota change: use custom version of Adafruit_SPITFT which extends Renderer instead of Adafruit_GFX +#include +#include +#include + +/*! + * @brief Select one of these defines to set the pixel color order + */ +#define SSD1331_COLORORDER_RGB +// #define SSD1331_COLORORDER_BGR + +#if defined SSD1331_COLORORDER_RGB && defined SSD1331_COLORORDER_BGR +#error "RGB and BGR can not both be defined for SSD1331_COLORODER." +#endif + +// Timing Delays +#define SSD1331_DELAYS_HWFILL (3) //!< Fill delay +#define SSD1331_DELAYS_HWLINE (1) //!< Line delay + +// SSD1331 Commands +#define SSD1331_CMD_DRAWLINE 0x21 //!< Draw line +#define SSD1331_CMD_DRAWRECT 0x22 //!< Draw rectangle +#define SSD1331_CMD_FILL 0x26 //!< Fill enable/disable +#define SSD1331_CMD_SETCOLUMN 0x15 //!< Set column address +#define SSD1331_CMD_SETROW 0x75 //!< Set row adress +#define SSD1331_CMD_CONTRASTA 0x81 //!< Set contrast for color A +#define SSD1331_CMD_CONTRASTB 0x82 //!< Set contrast for color B +#define SSD1331_CMD_CONTRASTC 0x83 //!< Set contrast for color C +#define SSD1331_CMD_MASTERCURRENT 0x87 //!< Master current control +#define SSD1331_CMD_SETREMAP 0xA0 //!< Set re-map & data format +#define SSD1331_CMD_STARTLINE 0xA1 //!< Set display start line +#define SSD1331_CMD_DISPLAYOFFSET 0xA2 //!< Set display offset +#define SSD1331_CMD_NORMALDISPLAY 0xA4 //!< Set display to normal mode +#define SSD1331_CMD_DISPLAYALLON 0xA5 //!< Set entire display ON +#define SSD1331_CMD_DISPLAYALLOFF 0xA6 //!< Set entire display OFF +#define SSD1331_CMD_INVERTDISPLAY 0xA7 //!< Invert display +#define SSD1331_CMD_SETMULTIPLEX 0xA8 //!< Set multiplex ratio +#define SSD1331_CMD_SETMASTER 0xAD //!< Set master configuration +#define SSD1331_CMD_DISPLAYOFF 0xAE //!< Display OFF (sleep mode) +#define SSD1331_CMD_DISPLAYON 0xAF //!< Normal Brightness Display ON +#define SSD1331_CMD_POWERMODE 0xB0 //!< Power save mode +#define SSD1331_CMD_PRECHARGE 0xB1 //!< Phase 1 and 2 period adjustment +#define SSD1331_CMD_CLOCKDIV \ + 0xB3 //!< Set display clock divide ratio/oscillator frequency +#define SSD1331_CMD_PRECHARGEA 0x8A //!< Set second pre-charge speed for color A +#define SSD1331_CMD_PRECHARGEB 0x8B //!< Set second pre-charge speed for color B +#define SSD1331_CMD_PRECHARGEC 0x8C //!< Set second pre-charge speed for color C +#define SSD1331_CMD_PRECHARGELEVEL 0xBB //!< Set pre-charge voltage +#define SSD1331_CMD_VCOMH 0xBE //!< Set Vcomh voltge + +/// Class to manage hardware interface with SSD1331 chipset +class Adafruit_SSD1331 : public Adafruit_SPITFT { +public: + Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, int8_t sclk, int8_t rst); + Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst); + // 3-4 args using hardware SPI (must specify peripheral) (reset optional) + Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, int8_t rst = -1); + + // commands + void begin(uint32_t begin = 8000000); + + void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + + void enableDisplay(boolean enable); + + static const int16_t TFTWIDTH = 96; ///< The width of the display + static const int16_t TFTHEIGHT = 64; ///< The height of the display + +private: +}; diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md b/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md new file mode 100644 index 000000000..24c404c59 --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md @@ -0,0 +1,24 @@ +# Adafruit SSD1331 Arduino Library [![Build Status](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/html/index.html) +This is a library for the 0.96" 16-bit Color OLED with SSD1331 driver chip + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/products/684 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution + +To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1131. Check that the Adafruit_SSD1331 folder contains Adafruit_SSD1331.cpp and Adafruit_SSD1331.h + +Place the Adafruit_SSD1331 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. + +You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from +https://github.com/adafruit/Adafruit-GFX-Library +and download/install that library as well diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties b/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties new file mode 100644 index 000000000..931f1aa38 --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties @@ -0,0 +1,10 @@ +name=Adafruit SSD1331 OLED Driver Library for Arduino +version=1.2.0 +author=Adafruit +maintainer=Adafruit +sentence=For 0.96" OLEDs in the Adafruit shop +paragraph=For 0.96" OLEDs in the Adafruit shop +category=Display +url=https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino +architectures=* +depends=Adafruit GFX Library diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt b/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt new file mode 100644 index 000000000..f6a0f22b8 --- /dev/null +++ b/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt @@ -0,0 +1,26 @@ +Software License Agreement (BSD License) + +Copyright (c) 2012, Adafruit Industries +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holders nor the +names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From fb2c10cb97ca7644d9962b057dc9b0084bbb027f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 14:26:27 +0100 Subject: [PATCH 25/78] Add SPI display driver SSD1331 Color oled Add SPI display driver SSD1331 Color oled by Jeroen Vermeulen (#10376) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/tasmota_configurations.h | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b34c9ca0..1836bee70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. - Command ``SetOption118 1`` to move ZbReceived from JSON message and into the subtopic replacing "SENSOR" default (#10353) - Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic (#10355) - Command ``RuleTimer0`` to access all RuleTimers at once (#10352) +- SPI display driver SSD1331 Color oled by Jeroen Vermeulen (#10376) ### Breaking Changed - Replaced MFRC522 13.56MHz rfid card reader GPIO selection from ``SPI CS`` by ``RC522 CS`` diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 814272bdf..01f4cc1fc 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -75,6 +75,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Support for disabling 38kHz IR modulation using ``#define IR_SEND_USE_MODULATION false`` [#10301](https://github.com/arendst/Tasmota/issues/10301) - Support for SPI display driver for ST7789 TFT by Gerhard Mutz [#9037](https://github.com/arendst/Tasmota/issues/9037) - Basic support for ESP32 Odroid Go 16MB binary tasmota32-odroidgo.bin [#8630](https://github.com/arendst/Tasmota/issues/8630) +- SPI display driver SSD1331 Color oled by Jeroen Vermeulen [#10376](https://github.com/arendst/Tasmota/issues/10376) ### Breaking Changed - Replaced MFRC522 13.56MHz rfid card reader GPIO selection from ``SPI CS`` by ``RC522 CS`` diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 87022257c..5dcce7502 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -310,7 +310,7 @@ #define USE_DISPLAY_SSD1351 // [DisplayModel 9] #define USE_DISPLAY_RA8876 // [DisplayModel 10] #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module -// #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module + #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code From 24cbad3257d3d26826766fd587f81fe9fa9d2453 Mon Sep 17 00:00:00 2001 From: Vic Date: Mon, 4 Jan 2021 14:57:32 +0100 Subject: [PATCH 26/78] more diagnostics --- tasmota/.xdrv_47_ftc532.ino.kate-swp | Bin 0 -> 710 bytes tasmota/xdrv_47_ftc532.ino | 99 ++++++++++++++++----------- 2 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 tasmota/.xdrv_47_ftc532.ino.kate-swp diff --git a/tasmota/.xdrv_47_ftc532.ino.kate-swp b/tasmota/.xdrv_47_ftc532.ino.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..46ab3cc1996b17b4471ee761f28e803930b1f42e GIT binary patch literal 710 zcmZ9}J4*vW5C`zx_zGx@im&)$F~)R~J2i#cNZ5$@Bzq`UN5B&f!eMbi?X2?|Y%Kj6 zehO1D(@2@8_M>XXok;mRH6g_OZ|~Kse7v9B^nQ}J zueE+Y3XyuY(lA?I(Kz6mUo}#>r*#$UZPs1s@2z%@qxUT@fyVw0kZ8Vgw)41~)R@|nE_(}rk1q(JjFnk{TI>^8&wW?!4ztiGbnVDb?q@X4~9 zk;vS0MGlVGBk%)z6wWRW6UX4}^5AjU>7RfV_vgulX3*H*^+OXJ2Rh`n1=Kd!i|`eD x3BF)2!`JK*e9m5hHG35f*lR=U>#%dy4RTI72{oL+%h<=j-@A_i_a9?V{{fF>QeprA literal 0 HcmV?d00001 diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index 5c076faa4..e88a80312 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -54,105 +54,122 @@ #define XDRV_47 47 #define FTC532_KEYS_MAX 8 +#define FTC532_RETRY 8 // number of reads before discarding #define FTC532_STATE_WAITING false #define FTC532_STATE_READING true // Rising edge timing in microseconds #define FTC532_BIT 377 +#define FTC532_NOISE (FTC532_BIT * 3 / 2) #define FTC532_SHORT (FTC532_BIT * 2) #define FTC532_LONG (FTC532_BIT * 4) #define FTC532_IDLE (FTC532_BIT * 10) #define FTC532_MAX (FTC532_BIT * 58) +#define DEBUG_FTC532 //@@@@@@@@@@@@@@@@ + struct FTC532 { volatile uint32_t rxtime; // ISR timer memory - volatile uint16_t sample = 0xF0F0; // buffer for bit-coded time samples + volatile uint16_t tsmp = 0xF0F0; // buffer for bit-coded time samples + volatile uint16_t sample = 0xF0F0; // complete samples volatile uint16_t rxbit; // ISR bit counter uint8_t keys = 0; // bitmap of active keys uint8_t old_keys = 0; // previously active keys volatile bool state; // ISR state - bool present = false; -#ifdef DEBUG_TASMOTA_DRIVER - volatile uint16_t errors; // error counter - volatile bool valid; // did we ever receive valid data? -#endif // DEBUG_TASMOTA_DRIVER + bool present = false; // driver active +#ifdef DEBUG_FTC532 + volatile uint16_t errors = 0; // inv. key error counter + volatile uint16_t frame = 0; // frame error counter + volatile uint16_t noise = 0; // noise detection counter + volatile bool valid = 0; // did we ever receive valid data? +#endif // DEBUG_FTC532 } Ftc532; const char ftc532_json[] PROGMEM = "\"FTC532\":{\"KEYS\":\""; -void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, triggers on rising edge +void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, triggers on rising edge uint32_t time = micros(); uint32_t time_diff = time - Ftc532.rxtime; Ftc532.rxtime = time; if (Ftc532.state == FTC532_STATE_WAITING) { - if (time_diff > FTC532_LONG + FTC532_SHORT) { // new frame + if (time_diff > FTC532_LONG + FTC532_SHORT) { // new frame Ftc532.rxbit = 0; Ftc532.state = FTC532_STATE_READING; } return; } // FTC532_STATE_READING starts here if (time_diff > FTC532_LONG + FTC532_BIT) { -#ifdef DEBUG_TASMOTA_DRIVER - ++Ftc532.errors; // frame error -#endif // DEBUG_TASMOTA_DRIVER +#ifdef DEBUG_FTC532 + ++Ftc532.frame; // frame error +#endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; } if (time_diff > FTC532_SHORT + FTC532_BIT) { - Ftc532.sample |= (1 << Ftc532.rxbit); // LONG + Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG + } else if (time_diff < FTC532_NOISE) { // noise detector +#ifdef DEBUG_FTC532 + ++Ftc532.noise; +#endif // DEBUG_FTC532 + Ftc532.state = FTC532_STATE_WAITING; + return; } else { - Ftc532.sample &= ~(1 << Ftc532.rxbit); // SHORT + Ftc532.tsmp &= ~(1 << Ftc532.rxbit); // SHORT } ++Ftc532.rxbit; - if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete + if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete + Ftc532.sample = Ftc532.tsmp; // copy frame Ftc532.rxbit = 0; -#ifdef DEBUG_TASMOTA_DRIVER - Ftc532.valid = true; -#endif // DEBUG_TASMOTA_DRIVER Ftc532.state = FTC532_STATE_WAITING; +#ifdef DEBUG_FTC532 + Ftc532.valid = true; +#endif // DEBUG_FTC532 } } -void ftc532_init(void) { // Initialize +void ftc532_init(void) { // Initialize if (!PinUsed(GPIO_FTC532)) { return; } -#ifdef DEBUG_TASMOTA_DRIVER - Ftc532.errors = 0; - Ftc532.valid = false; -#endif // DEBUG_TASMOTA_DRIVER Ftc532.state = FTC532_STATE_WAITING; - Ftc532.rxtime = micros(); pinMode(Pin(GPIO_FTC532), INPUT_PULLUP); + Ftc532.rxtime = micros(); attachInterrupt(Pin(GPIO_FTC532), ftc532_ISR, RISING); Ftc532.present = true; } -void ftc532_update(void) { // Usually called every 50 ms -#ifdef DEBUG_TASMOTA_DRIVER -// WARNING: Reduce callback frequency if this code is enabled -// if ((Ftc532.sample & 0xF) != ((~Ftc532.sample >> 4) & 0xF) || ((Ftc532.sample >> 8) & 0xF) != ((~Ftc532.sample >> 12) & 0xF)) { -// AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: inverted sample does not match %x %x %x %x"), -// Ftc532.sample & 0xF, (~Ftc532.sample >> 4) & 0xF, (Ftc532.sample >> 8) & 0xF, (~Ftc532.sample >> 12) & 0xF); -// } -#endif // DEBUG_TASMOTA_DRIVER - Ftc532.keys = (Ftc532.sample & 0xF) | ((Ftc532.sample >> 4) & 0xF0); - if (Ftc532.keys != Ftc532.old_keys) { -#ifdef DEBUG_TASMOTA_DRIVER - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%02X OLD=%02X ERR=%u OK=%u TIME=%lu Pin=%u"), - Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.errors, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); -#endif // DEBUG_TASMOTA_DRIVER - ftc532_publish(); - Ftc532.old_keys = Ftc532.keys; +void ftc532_update(void) { // Usually called every 50 ms + uint16_t smp; + uint16_t i; + + while (i++ < FTC532_RETRY) { // fix 'ghost' keys from bad hardware + smp = Ftc532.sample; + if ((smp & 0xF0F0) != ((~smp & 0x0F0F) << 4)) { // inverted keys don't match + ++Ftc532.errors; +#ifdef DEBUG_FTC532 + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), smp); +#endif // DEBUG_FTC532 + } else { + Ftc532.keys = (smp & 0xF) | ((smp >> 4) & 0xF0); + if (Ftc532.keys != Ftc532.old_keys) { +#ifdef DEBUG_FTC532 + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%02X OLD=%02X ERR=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), + Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.errors, Ftc532.noise, Ftc532.frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); +#endif // DEBUG_FTC532 + ftc532_publish(); + Ftc532.old_keys = Ftc532.keys; + } + break; + } } } void ftc532_show() { - ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes + ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); } void ftc532_publish(void) { - Response_P(PSTR("{%s%02X\"}}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes + Response_P(PSTR("{%s%02X\"}}"), ftc532_json, Ftc532.keys); MqttPublishTeleSensor(); } From 928f6f94477dab4777f236e189641ed48482f010 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:03:56 +0100 Subject: [PATCH 27/78] Prep SPI SDCard support --- tasmota/language/af_AF.h | 1 + tasmota/language/bg_BG.h | 1 + tasmota/language/cs_CZ.h | 1 + tasmota/language/de_DE.h | 1 + tasmota/language/el_GR.h | 1 + tasmota/language/en_GB.h | 1 + tasmota/language/es_ES.h | 1 + tasmota/language/fr_FR.h | 1 + tasmota/language/he_HE.h | 1 + tasmota/language/hu_HU.h | 1 + tasmota/language/it_IT.h | 1 + tasmota/language/ko_KO.h | 1 + tasmota/language/nl_NL.h | 1 + tasmota/language/pl_PL.h | 1 + tasmota/language/pt_BR.h | 1 + tasmota/language/pt_PT.h | 1 + tasmota/language/ro_RO.h | 1 + tasmota/language/ru_RU.h | 1 + tasmota/language/sk_SK.h | 1 + tasmota/language/sv_SE.h | 1 + tasmota/language/tr_TR.h | 1 + tasmota/language/uk_UA.h | 1 + tasmota/language/vi_VN.h | 1 + tasmota/language/zh_CN.h | 1 + tasmota/language/zh_TW.h | 1 + tasmota/tasmota_template.h | 15 +++++++++------ 26 files changed, 34 insertions(+), 6 deletions(-) diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 4eab30241..476726bfb 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index e9003a386..51a355887 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -777,6 +777,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 159d00878..571cdc769 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index cdbc1f994..e05128033 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 8e2e3f093..cfe86a0bb 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 2d6a47f43..fa8ab091d 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 31640385e..716048851 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 7bb645751..61e494c29 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -774,6 +774,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index ab7ff6d77..c69b67765 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index e2d335ce6..71271e34e 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 9aa08db46..04e295d97 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 - DC" #define D_SENSOR_SSD1331_CS "SSD1331 - CS" #define D_SENSOR_SSD1331_DC "SSD1331 - DC" +#define D_SENSOR_SDCARD_CS "SDCard - CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 0d9f91af4..d535c6f38 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 8087a8770..d7f11bd99 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 5919b35b5..b5fac0432 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 8069a265f..feb940b36 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index af9ee37a0..31d3b4a27 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index bf23a7c8d..0b8d26d20 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 965f5f5d7..7191969b7 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 20a691be6..787d841cb 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 18822f2b8..db6e9fc48 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index f307a9e73..5014afcd6 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 2626572ae..b027a95ac 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index d8d9d5124..0fb6cd6a4 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 1895fc690..05ca75c7b 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "安" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 2f2ec544e..384103e01 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -778,6 +778,7 @@ #define D_SENSOR_ST7789_DC "ST7789 DC" #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" +#define D_SENSOR_SDCARD_CS "SDCard CS" // Units #define D_UNIT_AMPERE "安培" diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 874f5ab2f..8e8de6142 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -142,6 +142,7 @@ enum UserSelectablePins { GPIO_RA8876_CS, GPIO_ST7789_CS, GPIO_ST7789_DC, GPIO_SSD1331_CS, GPIO_SSD1331_DC, + GPIO_SDCARD_CS, GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -304,6 +305,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_RA8876_CS "|" D_SENSOR_ST7789_CS "|" D_SENSOR_ST7789_DC "|" D_SENSOR_SSD1331_CS "|" D_SENSOR_SSD1331_DC "|" + D_SENSOR_SDCARD_CS "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -374,12 +376,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_RC522_CS), // RC522 Rfid Chip Select AGPIO(GPIO_RC522_RST), // RC522 Rfid Reset #endif -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_ILI9341 - AGPIO(GPIO_ILI9341_CS), - AGPIO(GPIO_ILI9341_DC), -#endif // USE_DISPLAY_ILI9341 -#endif // USE_DISPLAY +#ifdef USE_SDCARD + AGPIO(GPIO_SDCARD_CS), +#endif // USE_SDCARD #endif // USE_SPI AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Client Output AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Client Input @@ -387,6 +386,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_SSPI_CS), // Software SPI Chip Select AGPIO(GPIO_SSPI_DC), // Software SPI Data or Command #ifdef USE_DISPLAY +#ifdef USE_DISPLAY_ILI9341 + AGPIO(GPIO_ILI9341_CS), + AGPIO(GPIO_ILI9341_DC), +#endif // USE_DISPLAY_ILI9341 #ifdef USE_DISPLAY_ILI9488 AGPIO(GPIO_ILI9488_CS), #endif // USE_DISPLAY_ILI9488 From 0a882f53baa301229fc3c7379102c772c7eaea06 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:52:32 +0100 Subject: [PATCH 28/78] Update xdrv_98_filesystem.ino --- tasmota/xdrv_98_filesystem.ino | 338 +++++++++++++++++---------------- 1 file changed, 174 insertions(+), 164 deletions(-) diff --git a/tasmota/xdrv_98_filesystem.ino b/tasmota/xdrv_98_filesystem.ino index 932185c0c..1fadd6427 100644 --- a/tasmota/xdrv_98_filesystem.ino +++ b/tasmota/xdrv_98_filesystem.ino @@ -17,17 +17,19 @@ along with this program. If not, see . */ -/* -this driver adds universal file system support for -ESP8266 (sd card or littlfs on > 1 M devices with special linker file e.g. eagle.flash.4m2m.ld) -(makes no sense on 1M devices without sd card) -and -ESP32 (sd card or little fs or sfatfile system) -the sd card chip select is the standard SPI_CS or when not found SDCARD_CS_PIN -initializes the FS System Pointer ufsp which can be used by all standard file system calls -the only specific call is ufs_fsinfo() which gets the total size (0) and free size (1) -a button is created in the setup section to show up the file directory to download and upload files -subdirectories are supported +#ifdef USE_UFILESYS +/*********************************************************************************************\ +This driver adds universal file system support for ESP8266 (sd card or littlfs on > 1 M devices +with special linker file e.g. eagle.flash.4m2m.ld) (makes no sense on 1M devices without sd card) +and ESP32 (sd card or little fs or sfatfile system). + +The sd card chip select is the standard SDCARD_CS or when not found SDCARD_CS_PIN and initializes +the FS System Pointer ufsp which can be used by all standard file system calls. + +The only specific call is ufs_fsinfo() which gets the total size (0) and free size (1). + +A button is created in the setup section to show up the file directory to download and upload files +subdirectories are supported. console calls : @@ -36,16 +38,14 @@ ufstype get filesytem type 0=none 1=SD 2=Flashfile ufssize total size in kB ufsfree free size in kB -driver enabled by +The driver enabled by #define USE_UFILESYS +\*********************************************************************************************/ -#define USE_UFILESYS +#define XDRV_98 98 -*/ - - -#ifdef USE_UFILESYS - -#define XDRV_98 98 +#ifndef SDCARD_CS_PIN +#define SDCARD_CS_PIN 4 +#endif #ifdef ESP8266 #include @@ -53,15 +53,17 @@ driver enabled by #ifdef USE_SDCARD #include #include -#endif -#else +#endif // USE_SDCARD +#endif // ESP8266 + +#ifdef ESP32 #include #ifdef USE_SDCARD #include -#endif +#endif // USE_SDCARD #include "FFat.h" #include "FS.h" -#endif +#endif // ESP32 #define UFS_FILE_WRITE "w" #define UFS_FILE_READ "r" @@ -71,11 +73,6 @@ FS *ufsp; char ufs_path[48]; File ufs_upload_file; - -#ifndef SDCARD_CS_PIN -#define SDCARD_CS_PIN 4 -#endif - // 0 = none, 1 = SD, 2 = ffat, 3 = littlefs // spiffs should be obsolete uint8_t ufs_type; @@ -92,19 +89,20 @@ void UFSInit(void) { #ifdef USE_SDCARD -// if (TasmotaGlobal.spi_enabled) { - if (1) { + if (TasmotaGlobal.spi_enabled) { +// if (1) { int8_t cs = SDCARD_CS_PIN; - if (PinUsed(GPIO_SPI_CS)) { - cs = Pin(GPIO_SPI_CS); + if (PinUsed(GPIO_SDCARD_CS)) { + cs = Pin(GPIO_SDCARD_CS); } if (SD.begin(cs)) { #ifdef ESP8266 ufsp = (FS*)&SD; -#else +#endif // ESP8266 +#ifdef ESP32 ufsp = &SD; -#endif +#endif // ESP32 ufs_type = UFS_TSDC; return; } @@ -117,7 +115,8 @@ void UFSInit(void) { if (!LittleFS.begin()) { return; } -#else +#endif // ESP8266 +#ifdef ESP32 // try lfs first ufsp = &LITTLEFS; if (!LITTLEFS.begin(true)) { @@ -129,33 +128,35 @@ void UFSInit(void) { ufs_type = UFS_TFAT; return; } -#endif // ESP8266 +#endif // ESP32 ufs_type = UFS_TLFS; return; } uint32_t ufs_fsinfo(uint32_t sel) { -uint32_t result = 0; + uint32_t result = 0; + #ifdef ESP8266 -FSInfo64 fsinfo; -#endif + FSInfo64 fsinfo; +#endif // ESP8266 switch (ufs_type) { case UFS_TSDC: #ifdef USE_SDCARD -#ifdef ESP32 - if (sel == 0) { - result = SD.totalBytes(); - } else { - result = (SD.totalBytes() - SD.usedBytes()); - } -#else +#ifdef ESP8266 ufsp->info64(fsinfo); if (sel == 0) { result = fsinfo.totalBytes; } else { result = (fsinfo.totalBytes - fsinfo.usedBytes); } +#endif // ESP8266 +#ifdef ESP32 + if (sel == 0) { + result = SD.totalBytes(); + } else { + result = (SD.totalBytes() - SD.usedBytes()); + } #endif #endif //USE_SDCARD break; @@ -168,13 +169,14 @@ FSInfo64 fsinfo; } else { result = (fsinfo.totalBytes - fsinfo.usedBytes); } -#else +#endif // ESP8266 +#ifdef ESP32 if (sel == 0) { result = LITTLEFS.totalBytes(); } else { result = LITTLEFS.totalBytes() - LITTLEFS.usedBytes(); } -#endif // ESP8266 +#endif // ESP32 break; case UFS_TFAT: @@ -200,21 +202,20 @@ FSInfo64 fsinfo; #endif uint8_t ufs_reject(char *name) { - char *lcp = strrchr(name,'/'); if (lcp) { name = lcp + 1; } - while (*name=='/') name++; - if (*name=='_') return 1; - if (*name=='.') return 1; + while (*name=='/') { name++; } + if (*name=='_') { return 1; } + if (*name=='.') { return 1; } - if (!strncasecmp(name, "SPOTLI~1", REJCMPL)) return 1; - if (!strncasecmp(name, "TRASHE~1", REJCMPL)) return 1; - if (!strncasecmp(name, "FSEVEN~1", REJCMPL)) return 1; - if (!strncasecmp(name, "SYSTEM~1", REJCMPL)) return 1; - if (!strncasecmp(name, "System Volume", 13)) return 1; + if (!strncasecmp(name, "SPOTLI~1", REJCMPL)) { return 1; } + if (!strncasecmp(name, "TRASHE~1", REJCMPL)) { return 1; } + if (!strncasecmp(name, "FSEVEN~1", REJCMPL)) { return 1; } + if (!strncasecmp(name, "SYSTEM~1", REJCMPL)) { return 1; } + if (!strncasecmp(name, "System Volume", 13)) { return 1; } return 0; } @@ -225,35 +226,35 @@ void UFS_form1000(uint32_t number, char *dp, char sc) { char *sp = str; uint32_t inum = strlen(sp)/3; uint32_t fnum = strlen(sp)%3; - if (!fnum) inum--; - for (uint32_t count=0; count<=inum; count++) { - if (fnum){ - memcpy(dp,sp,fnum); - dp+=fnum; - sp+=fnum; - fnum=0; + if (!fnum) { inum--; } + for (uint32_t count = 0; count <= inum; count++) { + if (fnum) { + memcpy(dp, sp, fnum); + dp += fnum; + sp += fnum; + fnum = 0; } else { - memcpy(dp,sp,3); - dp+=3; - sp+=3; + memcpy(dp, sp, 3); + dp += 3; + sp += 3; } - if (count!=inum) { - *dp++=sc; + if (count != inum) { + *dp++ = sc; } } - *dp=0; + *dp = 0; } - -const char kUFSCommands[] PROGMEM = "UFS" "|" // Prefix - "|" "TYPE" "|" "SIZE" "|" "FREE"; +const char kUFSCommands[] PROGMEM = "Ufs" "|" // Prefix + "|" "Type" "|" "Size" "|" "Free"; void (* const kUFSCommand[])(void) PROGMEM = { &UFS_info, &UFS_type, &UFS_size, &UFS_free}; void UFS_info(void) { - Response_P(PSTR("{\"UFS\":{\"TYPE\":%d,\"SIZE\":%d,\"FREE\":%d}}"),ufs_type,ufs_fsinfo(0),ufs_fsinfo(1)); + Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}}"), ufs_type, ufs_fsinfo(0), ufs_fsinfo(1)); } + void UFS_type(void) { ResponseCmndNumber(ufs_type); } @@ -268,28 +269,28 @@ const char UFS_WEB_DIR[] PROGMEM = "

"; const char UFS_FILE_UPLOAD[] PROGMEM = D_SDCARD_DIR; const char UFS_FORM_FILE_UPLOAD[] PROGMEM = -"
" -"
 %s" " "; + "
" + "
 %s" " "; const char UFS_FORM_FILE_UPG[] PROGMEM = -"
" -"

" -"
"; + "
" + "

" + "
"; const char UFS_FORM_FILE_UPGc[] PROGMEM = -"
total size: %s kB - free: %s kB
"; + "
total size: %s kB - free: %s kB
"; const char UFS_FORM_SDC_DIRa[] PROGMEM = -"
"; + "
"; const char UFS_FORM_SDC_DIRc[] PROGMEM = -"
"; + "
"; const char UFS_FORM_FILE_UPGb[] PROGMEM = -"
" -"
" -""; + "
" + "
" + ""; const char UFS_FORM_SDC_DIRd[] PROGMEM = -"
%s
"; + "
%s
"; const char UFS_FORM_SDC_DIRb[] PROGMEM = - "
%s     %s : %8d
"; + "
%s     %s : %8d
"; const char UFS_FORM_SDC_HREF[] PROGMEM = - "http://%s/ufsd?download=%s/%s"; + "http://%s/ufsd?download=%s/%s"; void UFSdirectory(void) { uint8_t depth = 0; @@ -324,7 +325,6 @@ void UFSdirectory(void) { WSContentSpaceButton(BUTTON_CONFIGURATION); WSContentStop(); Web.upload_error = 0; - } void UFS_ListDir(char *path, uint8_t depth) { @@ -337,15 +337,18 @@ void UFS_ListDir(char *path, uint8_t depth) { if (dir) { dir.rewindDirectory(); if (strlen(path)>1) { - snprintf_P(npath, sizeof(npath), PSTR("http://%s/ufsd?download=%s"), WiFi.localIP().toString().c_str(),path); - for (uint8_t cnt = strlen(npath) - 1; cnt>0; cnt--) { - if (npath[cnt]=='/') { - if (npath[cnt - 1]=='=') npath[cnt + 1] = 0; - else npath[cnt] = 0; + snprintf_P(npath, sizeof(npath), PSTR("http://%s/ufsd?download=%s"), WiFi.localIP().toString().c_str(), path); + for (uint32_t cnt = strlen(npath) - 1; cnt > 0; cnt--) { + if (npath[cnt] == '/') { + if (npath[cnt - 1] == '=') { + npath[cnt + 1] = 0; + } else { + npath[cnt] = 0; + } break; } } - WSContentSend_P(UFS_FORM_SDC_DIRd, npath,path, ".."); + WSContentSend_P(UFS_FORM_SDC_DIRd, npath, path, ".."); } char *ep; while (true) { @@ -355,17 +358,17 @@ void UFS_ListDir(char *path, uint8_t depth) { } // esp32 returns path here, shorten to filename ep = (char*)entry.name(); - if (*ep=='/') ep++; + if (*ep == '/') { ep++; } char *lcp = strrchr(ep,'/'); if (lcp) { ep = lcp + 1; } time_t tm = entry.getLastWrite(); char tstr[24]; - strftime(tstr, 22, "%d-%m-%Y - %H:%M:%S ", localtime(&tm)); + strftime(tstr, 22, "%d-%m-%Y - %H:%M:%S ", localtime(&tm)); // Theo note to me. Isn't strftime expensive? SHould use ISO Date/Time char *pp = path; - if (!*(pp + 1)) pp++; + if (!*(pp + 1)) { pp++; } char *cp = name; // osx formatted disks contain a lot of stuff we dont want if (!ufs_reject((char*)ep)) { @@ -376,17 +379,17 @@ void UFS_ListDir(char *path, uint8_t depth) { sprintf(cp, format, ep); if (entry.isDirectory()) { - snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp,ep); - WSContentSend_P(UFS_FORM_SDC_DIRd, npath,ep,name); + snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp, ep); + WSContentSend_P(UFS_FORM_SDC_DIRd, npath, ep, name); uint8_t plen = strlen(path); - if (plen>1) { + if (plen > 1) { strcat(path, "/"); } strcat(path, ep); UFS_ListDir(path, depth + 4); path[plen] = 0; } else { - snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp,ep); + snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, WiFi.localIP().toString().c_str(), pp, ep); WSContentSend_P(UFS_FORM_SDC_DIRb, npath, ep, name, tstr, entry.size()); } } @@ -400,61 +403,61 @@ uint8_t UFS_DownloadFile(char *file) { File download_file; WiFiClient download_Client; - if (!ufsp->exists(file)) { - AddLog_P(LOG_LEVEL_INFO, PSTR("file not found")); - return 0; - } - - download_file = ufsp->open(file, UFS_FILE_READ); - if (!download_file) { - AddLog_P(LOG_LEVEL_INFO, PSTR("could not open file")); - return 0; - } - - if (download_file.isDirectory()) { - download_file.close(); - return 1; - } - - uint32_t flen = download_file.size(); - - download_Client = Webserver->client(); - Webserver->setContentLength(flen); - - char attachment[100]; - char *cp; - for (uint8_t cnt = strlen(file); cnt>=0; cnt--) { - if (file[cnt]=='/') { - cp = &file[cnt + 1]; - break; - } - } - snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), cp); - Webserver->sendHeader(F("Content-Disposition"), attachment); - WSSend(200, CT_STREAM, ""); - - uint8_t buff[512]; - uint16_t bread; - - // transfer is about 150kb/s - uint8_t cnt = 0; - while (download_file.available()) { - bread = download_file.read(buff, sizeof(buff)); - uint16_t bw = download_Client.write((const char*)buff, bread); - if (!bw) break; - cnt++; - if (cnt>7) { - cnt = 0; - //if (glob_script_mem.script_loglevel & 0x80) { - // this indeed multitasks, but is slower 50 kB/s - // loop(); - //} - } - delay(0); - } - download_file.close(); - download_Client.stop(); + if (!ufsp->exists(file)) { + AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: File not found")); return 0; + } + + download_file = ufsp->open(file, UFS_FILE_READ); + if (!download_file) { + AddLog_P(LOG_LEVEL_INFO, PSTR("UFS: Could not open file")); + return 0; + } + + if (download_file.isDirectory()) { + download_file.close(); + return 1; + } + + uint32_t flen = download_file.size(); + + download_Client = Webserver->client(); + Webserver->setContentLength(flen); + + char attachment[100]; + char *cp; + for (uint32_t cnt = strlen(file); cnt >= 0; cnt--) { + if (file[cnt] == '/') { + cp = &file[cnt + 1]; + break; + } + } + snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), cp); + Webserver->sendHeader(F("Content-Disposition"), attachment); + WSSend(200, CT_STREAM, ""); + + uint8_t buff[512]; + uint32_t bread; + + // transfer is about 150kb/s + uint32_t cnt = 0; + while (download_file.available()) { + bread = download_file.read(buff, sizeof(buff)); + uint32_t bw = download_Client.write((const char*)buff, bread); + if (!bw) { break; } + cnt++; + if (cnt > 7) { + cnt = 0; + //if (glob_script_mem.script_loglevel & 0x80) { + // this indeed multitasks, but is slower 50 kB/s + // loop(); + //} + } + delay(0); + } + download_file.close(); + download_Client.stop(); + return 0; } void UFS_Upload(void) { @@ -464,16 +467,20 @@ void UFS_Upload(void) { sprintf(npath, "%s/%s", ufs_path, upload.filename.c_str()); ufsp->remove(npath); ufs_upload_file = ufsp->open(npath, UFS_FILE_WRITE); - if (!ufs_upload_file) Web.upload_error = 1; - } else if(upload.status == UPLOAD_FILE_WRITE) { - if (ufs_upload_file) ufs_upload_file.write(upload.buf, upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END) { - if (ufs_upload_file) ufs_upload_file.close(); + if (!ufs_upload_file) { Web.upload_error = 1; } + } + else if (upload.status == UPLOAD_FILE_WRITE) { + if (ufs_upload_file) { + ufs_upload_file.write(upload.buf, upload.currentSize); + } + } + else if (upload.status == UPLOAD_FILE_END) { + if (ufs_upload_file) { ufs_upload_file.close(); } if (Web.upload_error) { AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: upload error")); } } else { - Web.upload_error=1; + Web.upload_error = 1; WSSend(500, CT_PLAIN, F("500: couldn't create file")); } } @@ -484,7 +491,7 @@ void UFSFileUploadSuccess(void) { WSContentSend_P(PSTR("
" D_UPLOAD " " D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS)); WSContentSend_P(PSTR("

")); - WSContentSend_P(PSTR("

"),"/ufsd",D_UPL_DONE); + WSContentSend_P(PSTR("

"), "/ufsd", D_UPL_DONE); WSContentStop(); } @@ -513,7 +520,10 @@ bool Xdrv98(uint8_t function) { case FUNC_WEB_ADD_HANDLER: Webserver->on("/ufsd", UFSdirectory); Webserver->on("/ufsu", HTTP_GET, UFSFileUploadSuccess); - Webserver->on("/ufsu", HTTP_POST,[]() { Webserver->sendHeader("Location","/ufsu");Webserver->send(303);}, UFS_Upload); + Webserver->on("/ufsu", HTTP_POST,[]() { + Webserver->sendHeader("Location","/ufsu"); + Webserver->send(303); + }, UFS_Upload); break; #endif // USE_WEBSERVER } From aa943fc696802ecb5946f78f0f5ecce0641dd365 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 16:10:22 +0100 Subject: [PATCH 29/78] Add ESP32 RTOS timesync --- tasmota/support_rtc.ino | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tasmota/support_rtc.ino b/tasmota/support_rtc.ino index fc8a14042..9884b337f 100644 --- a/tasmota/support_rtc.ino +++ b/tasmota/support_rtc.ino @@ -400,6 +400,15 @@ void RtcSecond(void) } else { TasmotaGlobal.rules_flag.time_set = 1; } + +#ifdef ESP32 + // Sync RTOS time to be used by SD Card time stamps + struct timeval tv; + tv.tv_sec = Rtc.local_time; + tv.tv_usec = 0; + settimeofday(&tv, nullptr); +#endif // ESP32 + } else { Rtc.utc_time++; // Increment every second } From 448daed0d10cdfdfe0b175880f145ff58d0fbad7 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 4 Jan 2021 16:29:34 +0100 Subject: [PATCH 30/78] picture buttons part 1 --- .../Adafruit_GFX.cpp | 24 +++++++----- .../ILI9341-gemu-1.0/ILI9341_2.cpp | 6 +++ lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h | 26 +------------ .../JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp | 32 +++++++++++++--- .../JaretBurkett_ILI9488-gemu-1.0/ILI9488.h | 1 + .../src/renderer.cpp | 38 +++++++++++++------ .../src/renderer.h | 1 + 7 files changed, 77 insertions(+), 51 deletions(-) diff --git a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp index 8741e6247..a40702660 100644 --- a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp +++ b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp @@ -1579,6 +1579,8 @@ void Adafruit_GFX_Button::initButtonUL( strncpy(_label, label, 9); } +void draw_picture(char *path, uint32_t xp, uint32_t yp, uint32_t xs, uint32_t ys, bool inverted); + /**************************************************************************/ /*! @brief Draw the button on the screen @@ -1598,16 +1600,20 @@ void Adafruit_GFX_Button::drawButton(boolean inverted) { text = _fillcolor; } - uint8_t r = min(_w, _h) / 4; // Corner radius - _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill); - _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline); - - _gfx->setCursor(_x1 + (_w/2) - (strlen(_label) * 3 * _textsize_x), - _y1 + (_h/2) - (4 * _textsize_y)); - _gfx->setTextColor(text); - _gfx->setTextSize(_textsize_x, _textsize_y); - _gfx->print(_label); + if (_label[0]=='/') { + // picture path + draw_picture(_label, _x1, _y1, _w, _h, inverted); + _gfx->drawRect(_x1, _y1, _w, _h, text); + } else { + uint8_t r = min(_w, _h) / 4; // Corner radius + _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill); + _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline); + _gfx->setCursor(_x1 + (_w/2) - (strlen(_label) * 3 * _textsize_x), _y1 + (_h/2) - (4 * _textsize_y)); + _gfx->setTextColor(text); + _gfx->setTextSize(_textsize_x, _textsize_y); + _gfx->print(_label); + } } /**************************************************************************/ diff --git a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp index a4391f10e..d590cdc14 100644 --- a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp +++ b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.cpp @@ -545,6 +545,12 @@ void ILI9341_2::DisplayOnff(int8_t on) { } } +void ILI9341_2::invertDisplay(boolean i) { + ILI9341_2_CS_LOW + writecmd(i ? ILI9341_2_INVOFF : ILI9341_2_INVON); + ILI9341_2_CS_HIGH +} + void ili9342_dimm(uint8_t dim); // dimmer 0-100 diff --git a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h index 27ff00e5d..a4608e6ba 100644 --- a/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h +++ b/lib/lib_display/ILI9341-gemu-1.0/ILI9341_2.h @@ -119,30 +119,6 @@ class ILI9341_2 : public Renderer { ILI9341_2(int8_t cs, int8_t res, int8_t dc, int8_t bp); void init(uint16_t width, uint16_t height); - /* - void begin(void); - void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - void setScrollArea(uint16_t topFixedArea, uint16_t bottomFixedArea); - void scroll(uint16_t pixels); - void pushColor(uint16_t color); - void pushColors(uint16_t *data, uint8_t len, boolean first); - //void drawImage(const uint8_t* img, uint16_t x, uint16_t y, uint16_t w, uint16_t h); - void fillScreen(uint16_t color); - void drawPixel(int16_t x, int16_t y, uint16_t color); - void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); - void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,uint16_t color); - void setRotation(uint8_t r); - void invertDisplay(boolean i); - uint16_t color565(uint8_t r, uint8_t g, uint8_t b); - void DisplayOnff(int8_t on); - void writecommand(uint8_t c); - void writedata(uint8_t d); - void write16BitColor(uint16_t color); - void commandList(uint8_t *addr); - void hw_spi_init(); - void dim(uint8_t contrast);*/ uint16_t GetColorFromIndex(uint8_t index); private: @@ -161,7 +137,7 @@ class ILI9341_2 : public Renderer { void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); void dim(uint8_t dim); void pushColors(uint16_t *data, uint8_t len, boolean first); - + void invertDisplay(boolean i); void spiwrite(uint8_t c); void spiwrite16(uint16_t c); void spiwrite32(uint32_t c); diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp index 357000a69..61dea05c1 100644 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp +++ b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp @@ -503,6 +503,16 @@ void ILI9488::scroll(uint16_t pixels){ }*/ void ILI9488::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + if (!x0 && !y0 && !x1 && !y1) { + x0=0; + y0=0; + x1=_width; + y1=_height; + } + setAddrWindow_int(x0, y0, x1-1, y1-1); +} + +void ILI9488::setAddrWindow_int(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { uint8_t flag=0; if (!x0 && !y0 && !x1 && !y1) { @@ -594,6 +604,7 @@ void ILI9488::pushColor(uint16_t color) { ILI9488_STOP } +#if 1 void ILI9488::pushColors(uint16_t *data, uint8_t len, boolean first) { uint16_t color; uint8_t buff[len*3+1]; @@ -616,6 +627,17 @@ void ILI9488::pushColors(uint16_t *data, uint8_t len, boolean first) { ILI9488_STOP } +#else + +void ILI9488::pushColors(uint16_t *data, uint8_t len, boolean first) { + uint16_t color; + + while (len--) { + write16BitColor(*data++); + } + ILI9488_STOP +} +#endif void ILI9488::write16BitColor(uint16_t color){ // #if (__STM32F1__) @@ -688,7 +710,7 @@ void ILI9488::drawPixel(int16_t x, int16_t y, uint16_t color) { if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - setAddrWindow(x,y,x+1,y+1); + setAddrWindow_int(x,y,x+1,y+1); write16BitColor(color); ILI9488_STOP } @@ -702,7 +724,7 @@ void ILI9488::drawFastVLine(int16_t x, int16_t y, int16_t h, if((y+h-1) >= _height) h = _height-y; - setAddrWindow(x, y, x, y+h-1); + setAddrWindow_int(x, y, x, y+h-1); uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; @@ -770,7 +792,7 @@ void ILI9488::drawFastHLine(int16_t x, int16_t y, int16_t w, if((x >= _width) || (y >= _height)) return; if((x+w-1) >= _width) w = _width-x; - setAddrWindow(x, y, x+w-1, y); + setAddrWindow_int(x, y, x+w-1, y); uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; @@ -905,7 +927,7 @@ void ILI9488::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t colo if((x + w - 1) >= _width) w = _width - x; if((y + h - 1) >= _height) h = _height - y; - setAddrWindow(x, y, x+w-1, y+h-1); + setAddrWindow_int(x, y, x+w-1, y+h-1); //ILI9488_START uint8_t r = (color & 0xF800) >> 11; @@ -1050,7 +1072,7 @@ void ILI9488::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t colo if((x + w - 1) >= _width) w = _width - x; if((y + h - 1) >= _height) h = _height - y; - setAddrWindow(x, y, x+w-1, y+h-1); + setAddrWindow_int(x, y, x+w-1, y+h-1); uint8_t r = (color & 0xF800) >> 11; uint8_t g = (color & 0x07E0) >> 5; diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h index 5fd2e39e5..50557822e 100644 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h +++ b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h @@ -136,6 +136,7 @@ class ILI9488 : public Renderer { void begin(void); void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); + void setAddrWindow_int(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void setScrollArea(uint16_t topFixedArea, uint16_t bottomFixedArea); void scroll(uint16_t pixels); diff --git a/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp b/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp index a8f0f9e57..1b78aaa9a 100644 --- a/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp +++ b/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.cpp @@ -32,6 +32,10 @@ //#define USE_GFX_FONTS #define USE_TINY_FONT +#ifdef ESP32 +#define USE_ICON_FONT +#endif + uint8_t wr_redir=0; uint8_t *buffer; @@ -223,27 +227,32 @@ void Renderer::setTextFont(uint8_t f) { break; case 7: selected_font = &RAFont; + break; default: - font=0; + selected_font = &Font12; + break; } #else #ifdef USE_EPD_FONTS - if (1 == font) { + switch (font) { selected_font = &Font12; - } else { - #ifdef USE_TINY_FONT - if (2 == font) { - selected_font = &Font24; - } else { - selected_font = &Font8; - } - #else + break; + case 2: selected_font = &Font24; - #endif + break; + case 3: +#ifdef USE_TINY_FONT + selected_font = &Font8; +#else + selected_font = &Font24; +#endif + break; + default: + selected_font = &Font12; + break; } #endif #endif - } @@ -513,6 +522,9 @@ void Renderer::setDrawMode(uint8_t mode) { drawmode=mode; } +void Renderer::invertDisplay(boolean i) { +} + void VButton::xdrawButton(bool inverted) { wr_redir=1; drawButton(inverted); @@ -520,4 +532,6 @@ void VButton::xdrawButton(bool inverted) { } + + /* END OF FILE */ diff --git a/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h b/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h index 27ff56efe..0685b9bb1 100644 --- a/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h +++ b/lib/lib_display/esp-epaper-29-ws-20171230-gemu-1.1/src/renderer.h @@ -35,6 +35,7 @@ public: virtual void dim(uint8_t contrast); virtual void pushColors(uint16_t *data, uint8_t len, boolean first); virtual void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + virtual void invertDisplay(boolean i); void setDrawMode(uint8_t mode); uint8_t drawmode; virtual void FastString(uint16_t x,uint16_t y,uint16_t tcolor, const char* str); From 5d8b10141a8d9b48ec35788752e1d07b11754e57 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 4 Jan 2021 16:34:44 +0100 Subject: [PATCH 31/78] picture buttons part 2 --- tasmota/support_jpeg.ino | 22 ++++++++- tasmota/xdrv_13_display.ino | 88 +++++++++++++++++++++++------------ tasmota/xdsp_05_epaper_29.ino | 1 + tasmota/xdsp_12_ST7789.ino | 12 ++--- tasmota/xdsp_13_ILI9341-2.ino | 5 +- 5 files changed, 83 insertions(+), 45 deletions(-) diff --git a/tasmota/support_jpeg.ino b/tasmota/support_jpeg.ino index 4669b9ad7..2ebce0e4c 100644 --- a/tasmota/support_jpeg.ino +++ b/tasmota/support_jpeg.ino @@ -29,9 +29,27 @@ uint8_t red, grn, blu; uint16_t b , g, r; for (uint32_t cnt=0; cnt> 3) & 0x1f; + g = ((grn >> 2) & 0x3f) << 5; + r = ((red >> 3) & 0x1f) << 11; + *out++ = (r | g | b); + } + +} + +void rgb888_to_565i(uint8_t *in, uint16_t *out, uint32_t len) { +uint8_t red, grn, blu; +uint16_t b , g, r; + + for (uint32_t cnt=0; cnt> 3) & 0x1f; g = ((grn >> 2) & 0x3f) << 5; r = ((red >> 3) & 0x1f) << 11; diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 6bdab9d03..3a1abe6d2 100644 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -503,7 +503,7 @@ void DisplayText(void) if (ep) { *ep=0; ep++; - Draw_RGB_Bitmap(cp,disp_xpos,disp_ypos); + Draw_RGB_Bitmap(cp,disp_xpos,disp_ypos, false); cp=ep; } } @@ -1423,7 +1423,7 @@ void CmndDisplayDimmer(void) void CmndDisplayBlinkrate(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) { - + if (!renderer) XdspCall(FUNC_DISPLAY_BLINKRATE); } @@ -1540,20 +1540,39 @@ void CmndDisplayRows(void) /*********************************************************************************************\ * optional drivers \*********************************************************************************************/ + +#ifdef USE_TOUCH_BUTTONS +// very limited path size, so, add .jpg +void draw_picture(char *path, uint32_t xp, uint32_t yp, uint32_t xs, uint32_t ys, bool inverted) { +char ppath[16]; + strcpy(ppath, path); + uint8_t plen = strlen(path) -1; + if (ppath[plen]=='1') { + // index mode + if (inverted) { + ppath[plen] = '2'; + } + inverted = false; + } + strcat(ppath, ".jpg"); + Draw_RGB_Bitmap(ppath, xp, yp, inverted); +} +#endif + + #ifdef ESP32 #ifdef JPEG_PICTS #include "img_converters.h" #include "esp_jpg_decode.h" bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale); char get_jpeg_size(unsigned char* data, unsigned int data_size, unsigned short *width, unsigned short *height); -void rgb888_to_565(uint8_t *in, uint16_t *out, uint32_t len); #endif // JPEG_PICTS #endif // ESP32 -#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) +#if defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT) && defined(USE_DISPLAY) extern FS *fsp; #define XBUFF_LEN 128 -void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp) { +void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp, bool inverted ) { if (!renderer) return; File fp; char *ending = strrchr(file,'.'); @@ -1602,34 +1621,41 @@ void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp) { // jpeg files on ESP32 with more memory #ifdef ESP32 #ifdef JPEG_PICTS - if (psramFound()) { - fp=fsp->open(file,FILE_READ); - if (!fp) return; - uint32_t size = fp.size(); - uint8_t *mem = (uint8_t *)heap_caps_malloc(size+4, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - if (mem) { - uint8_t res=fp.read(mem, size); - if (res) { - uint16_t xsize; - uint16_t ysize; - if (mem[0]==0xff && mem[1]==0xd8) { - get_jpeg_size(mem, size, &xsize, &ysize); - //Serial.printf(" x,y %d - %d\n",xsize, ysize ); - if (xsize && ysize) { - uint8_t *out_buf = (uint8_t *)heap_caps_malloc((xsize*ysize*3)+4, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - if (out_buf) { + fp=fsp->open(file,FILE_READ); + if (!fp) return; + uint32_t size = fp.size(); + uint8_t *mem = (uint8_t *)special_malloc(size+4); + if (mem) { + uint8_t res=fp.read(mem, size); + if (res) { + uint16_t xsize; + uint16_t ysize; + if (mem[0]==0xff && mem[1]==0xd8) { + get_jpeg_size(mem, size, &xsize, &ysize); + //Serial.printf(" x,y,fs %d - %d - %d\n",xsize, ysize, size ); + if (xsize && ysize) { + uint8_t *out_buf = (uint8_t *)special_malloc((xsize*ysize*3)+4); + if (out_buf) { + uint16_t *pixb = (uint16_t *)special_malloc((xsize*2)+4); + if (pixb) { uint8_t *ob=out_buf; - jpg2rgb888(mem, size, out_buf, (jpg_scale_t)JPG_SCALE_NONE); - uint16_t pixels=xsize*ysize/XBUFF_LEN; - renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize); - for(int32_t j=0; jpushColors(rbuff,XBUFF_LEN,true); - OsWatchLoop(); + if (jpg2rgb888(mem, size, out_buf, (jpg_scale_t)JPG_SCALE_NONE)) { + renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize); + for(int32_t j=0; jpushColors(pixb, xsize, true); + OsWatchLoop(); + } + renderer->setAddrWindow(0,0,0,0); } - renderer->setAddrWindow(0,0,0,0); + free(out_buf); + free(pixb); + } else { free(out_buf); } } diff --git a/tasmota/xdsp_05_epaper_29.ino b/tasmota/xdsp_05_epaper_29.ino index a607bd937..d9c35435f 100644 --- a/tasmota/xdsp_05_epaper_29.ino +++ b/tasmota/xdsp_05_epaper_29.ino @@ -83,6 +83,7 @@ void EpdInitDriver29(void) { #ifdef SHOW_SPLASH // Welcome text + delay(100); renderer->setTextFont(1); renderer->DrawStringAt(50, 50, "Waveshare E-Paper Display!", COLORED,0); renderer->Updateframe(); diff --git a/tasmota/xdsp_12_ST7789.ino b/tasmota/xdsp_12_ST7789.ino index 80cf4d6e5..be3a40da9 100644 --- a/tasmota/xdsp_12_ST7789.ino +++ b/tasmota/xdsp_12_ST7789.ino @@ -112,14 +112,8 @@ void ST7789_InitDriver(void) { #ifdef SHOW_SPLASH // Welcome text renderer->setTextColor(ST7789_WHITE,ST7789_BLACK); - int fontSize = 2; renderer->setTextFont(2); - if (Settings.display_width<240) { - fontSize = 1; - } - renderer->setTextFont(fontSize); - int fontHeight = 12 * fontSize; - renderer->DrawStringAt(30, (Settings.display_height-fontHeight)/2, "ST7789 TFT!", ST7789_WHITE,0); + renderer->DrawStringAt(30, (Settings.display_height-12)/2, "ST7789 TFT!", ST7789_WHITE,0); delay(1000); #endif @@ -131,8 +125,8 @@ void ST7789_InitDriver(void) { #define SDA_2 23 #define SCL_2 32 #ifdef USE_LANBON_L8 - #undef SDA_2 - #undef SCL_2 + #undef SDA_2 + #undef SCL_2 #define SDA_2 4 #define SCL_2 0 #endif // USE_LANBON_L8 diff --git a/tasmota/xdsp_13_ILI9341-2.ino b/tasmota/xdsp_13_ILI9341-2.ino index 6095b5c53..cb0e4616e 100644 --- a/tasmota/xdsp_13_ILI9341-2.ino +++ b/tasmota/xdsp_13_ILI9341-2.ino @@ -94,10 +94,9 @@ void ILI9341_2_InitDriver() #ifdef SHOW_SPLASH // Welcome text renderer->setTextFont(2); - renderer->setTextColor(ILI9341_2_WHITE,ILI9341_2_BLACK); - renderer->DrawStringAt(20, 140, "ILI9341 TFT!", ILI9341_2_RED,0); + renderer->setTextColor(ILI9341_2_WHITE, ILI9341_2_BLACK); + renderer->DrawStringAt(30, (Settings.display_height/2)-12, "ILI9341 TFT!", ILI9341_2_WHITE, 0); delay(1000); - renderer->clearDisplay(); #endif color_type = COLOR_COLOR; From 1d572ea304a97fcff7b68a80f8f3605037b72c6f Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 4 Jan 2021 16:39:00 +0100 Subject: [PATCH 32/78] special malloc --- tasmota/support_esp32.ino | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tasmota/support_esp32.ino b/tasmota/support_esp32.ino index 0554129e8..79821806b 100644 --- a/tasmota/support_esp32.ino +++ b/tasmota/support_esp32.ino @@ -86,6 +86,11 @@ uint32_t FlashWriteMaxSector(void) { uint8_t* FlashDirectAccess(void) { return (uint8_t*)(0x40200000 + (FlashWriteStartSector() * SPI_FLASH_SEC_SIZE)); } + +void *special_malloc(uint32_t size) { + return malloc(size); +} + #endif /*********************************************************************************************\ @@ -414,4 +419,13 @@ uint8_t* FlashDirectAccess(void) { return data; } -#endif // ESP32 \ No newline at end of file + +void *special_malloc(uint32_t size) { + if (psramFound()) { + return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + } else { + return malloc(size); + } +} + +#endif // ESP32 From 97da3c7034a5464df3daa359fdf58437764910d1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 4 Jan 2021 16:45:46 +0100 Subject: [PATCH 33/78] Add SDCard detection --- tasmota/support_tasmota.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 84bc2dd53..d58447337 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1615,7 +1615,8 @@ void GpioInit(void) ValidSpiPinUsed(GPIO_RA8876_CS) || ValidSpiPinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too ValidSpiPinUsed(GPIO_ST7789_CS) || - ValidSpiPinUsed(GPIO_SSD1331_CS) + ValidSpiPinUsed(GPIO_SSD1331_CS) || + ValidSpiPinUsed(GPIO_SDCARD_CS) ); bool valid_dc = (ValidSpiPinUsed(GPIO_SPI_DC) || ValidSpiPinUsed(GPIO_NRF24_DC) || @@ -1647,7 +1648,8 @@ void GpioInit(void) PinUsed(GPIO_RA8876_CS) || PinUsed(GPIO_ST7789_DC) || // ST7789 CS may be omitted so chk DC too PinUsed(GPIO_ST7789_CS) || - PinUsed(GPIO_SSD1331_CS) + PinUsed(GPIO_SSD1331_CS) || + PinUsed(GPIO_SDCARD_CS) ) { uint32_t spi_mosi = (PinUsed(GPIO_SPI_CLK) && PinUsed(GPIO_SPI_MOSI)) ? SPI_MOSI : SPI_NONE; uint32_t spi_miso = (PinUsed(GPIO_SPI_CLK) && PinUsed(GPIO_SPI_MISO)) ? SPI_MISO : SPI_NONE; From 8acb06515c982b2e675fe299cab00c044a84e25b Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Mon, 4 Jan 2021 18:43:58 +0100 Subject: [PATCH 34/78] IRremoteESP8266 library from v2.7.13 to v2.7.14 --- CHANGELOG.md | 1 + .../html/classIRNeoclimaAc__coll__graph.map | 4 - .../html/classIRNeoclimaAc__coll__graph.md5 | 1 - .../html/classIRNeoclimaAc__coll__graph.png | Bin 3405 -> 0 bytes .../html/classIRSamsungAc__coll__graph.map | 4 - .../html/classIRSamsungAc__coll__graph.md5 | 1 - .../html/classIRSamsungAc__coll__graph.png | Bin 3730 -> 0 bytes .../html/classIRSanyoAc__coll__graph.map | 4 - .../html/classIRSanyoAc__coll__graph.md5 | 1 - .../html/classIRSanyoAc__coll__graph.png | Bin 3485 -> 0 bytes .../html/classIRSharpAc__coll__graph.map | 4 - .../html/classIRSharpAc__coll__graph.md5 | 1 - .../html/classIRSharpAc__coll__graph.png | Bin 3360 -> 0 bytes .../docs/doxygen/html/search/all_10.js | 27 - .../docs/doxygen/html/search/all_15.js | 14 - .../docs/doxygen/html/search/all_17.js | 12 - .../docs/doxygen/html/search/all_1a.js | 7 - .../docs/doxygen/html/search/all_1b.js | 4 - .../docs/doxygen/html/search/all_4.js | 135 - .../docs/doxygen/html/search/all_5.js | 39 - .../docs/doxygen/html/search/all_8.js | 34 - .../docs/doxygen/html/search/all_9.js | 198 - .../docs/doxygen/html/search/all_c.js | 19 - .../docs/doxygen/html/search/all_d.js | 50 - .../docs/doxygen/html/search/classes_0.js | 6 - .../docs/doxygen/html/search/classes_1.js | 7 - .../docs/doxygen/html/search/classes_2.js | 13 - .../docs/doxygen/html/search/classes_3.js | 4 - .../docs/doxygen/html/search/classes_4.js | 5 - .../docs/doxygen/html/search/classes_5.js | 8 - .../docs/doxygen/html/search/classes_6.js | 56 - .../docs/doxygen/html/search/classes_7.js | 4 - .../docs/doxygen/html/search/classes_8.js | 4 - .../docs/doxygen/html/search/classes_9.js | 11 - .../docs/doxygen/html/search/classes_a.js | 4 - .../docs/doxygen/html/search/classes_b.js | 4 - .../docs/doxygen/html/search/classes_c.js | 4 - .../docs/doxygen/html/search/enums_5.js | 4 - .../docs/doxygen/html/search/enums_7.js | 6 - .../docs/doxygen/html/search/files_0.js | 7 - .../docs/doxygen/html/search/files_1.js | 8 - .../docs/doxygen/html/search/files_2.js | 4 - .../docs/doxygen/html/search/files_3.js | 115 - .../docs/doxygen/html/search/files_4.js | 4 - .../docs/doxygen/html/search/files_5.js | 4 - .../docs/doxygen/html/search/files_6.js | 4 - .../docs/doxygen/html/search/functions_0.js | 21 - .../docs/doxygen/html/search/functions_1.js | 15 - .../docs/doxygen/html/search/functions_15.js | 4 - .../docs/doxygen/html/search/functions_17.js | 4 - .../docs/doxygen/html/search/functions_4.js | 103 - .../docs/doxygen/html/search/functions_a.js | 4 - .../docs/doxygen/html/search/functions_b.js | 7 - .../docs/doxygen/html/search/functions_d.js | 4 - .../docs/doxygen/html/search/functions_f.js | 4 - .../docs/doxygen/html/search/namespaces_0.js | 5 - .../docs/doxygen/html/search/namespaces_1.js | 4 - .../docs/doxygen/html/search/pages_0.js | 4 - .../docs/doxygen/html/search/pages_1.js | 5 - .../docs/doxygen/html/search/pages_2.js | 4 - .../docs/doxygen/html/search/variables_1.js | 6 - .../docs/doxygen/html/search/variables_11.js | 38 - .../docs/doxygen/html/search/variables_13.js | 9 - .../docs/doxygen/html/search/variables_14.js | 8 - .../docs/doxygen/html/search/variables_15.js | 8 - .../docs/doxygen/html/search/variables_2.js | 12 - .../docs/doxygen/html/search/variables_4.js | 13 - .../docs/doxygen/html/search/variables_5.js | 6 - .../docs/doxygen/html/search/variables_7.js | 8 - .../docs/doxygen/html/search/variables_8.js | 9 - .../docs/doxygen/html/search/variables_a.js | 9 - .../docs/doxygen/html/search/variables_b.js | 11 - .../docs/doxygen/html/search/variables_e.js | 20 - .../.github/CONTRIBUTING.md | 0 .../.github/Contributors.md | 0 .../.github/issue_template.md | 0 .../.gitignore | 0 .../.gitmodules | 0 .../.style.yapf | 0 .../.travis.yml | 0 .../CPPLINT.cfg | 0 .../Doxyfile | 0 .../LICENSE.txt | 0 .../README.md | 4 +- .../README_de.md | 4 +- .../README_fr.md | 4 +- .../ReleaseNotes.md | 25 + .../SupportedProtocols.md | 8 +- .../docs/README.md | 0 .../docs/README_de.md | 0 .../docs/README_fr.md | 0 .../docs/_config.yml | 0 .../docs/doxygen/html/IRac_8cpp.html | 0 .../docs/doxygen/html/IRac_8h.html | 0 .../docs/doxygen/html/IRac_8h_source.html | 342 +- .../docs/doxygen/html/IRrecv_8cpp.html | 119 + .../docs/doxygen/html/IRrecv_8h.html | 0 .../docs/doxygen/html/IRrecv_8h_source.html | 78 +- .../docs/doxygen/html/IRremoteESP8266_8h.html | 0 .../html/IRremoteESP8266_8h_source.html | 2 +- .../docs/doxygen/html/IRsend_8cpp.html | 0 .../docs/doxygen/html/IRsend_8h.html | 0 .../docs/doxygen/html/IRsend_8h_source.html | 28 +- .../docs/doxygen/html/IRtext_8cpp.html | 0 .../docs/doxygen/html/IRtext_8h.html | 0 .../docs/doxygen/html/IRtext_8h_source.html | 2 +- .../docs/doxygen/html/IRtimer_8cpp.html | 0 .../docs/doxygen/html/IRtimer_8h.html | 0 .../docs/doxygen/html/IRtimer_8h_source.html | 0 .../docs/doxygen/html/IRutils_8cpp.html | 6 +- .../docs/doxygen/html/IRutils_8h.html | 6 +- .../docs/doxygen/html/IRutils_8h_source.html | 131 +- .../docs/doxygen/html/README_8md.html | 0 .../docs/doxygen/html/annotated.html | 62 +- .../docs/doxygen/html/bc_s.png | Bin .../docs/doxygen/html/bdwn.png | Bin .../html/classIRAirwellAc-members.html | 0 .../docs/doxygen/html/classIRAirwellAc.html | 0 .../html/classIRAirwellAc__coll__graph.map | 0 .../html/classIRAirwellAc__coll__graph.md5 | 0 .../html/classIRAirwellAc__coll__graph.png | Bin .../doxygen/html/classIRAmcorAc-members.html | 0 .../docs/doxygen/html/classIRAmcorAc.html | 0 .../html/classIRAmcorAc__coll__graph.map | 0 .../html/classIRAmcorAc__coll__graph.md5 | 0 .../html/classIRAmcorAc__coll__graph.png | Bin .../doxygen/html/classIRArgoAC-members.html | 0 .../docs/doxygen/html/classIRArgoAC.html | 0 .../html/classIRArgoAC__coll__graph.map | 0 .../html/classIRArgoAC__coll__graph.md5 | 0 .../html/classIRArgoAC__coll__graph.png | Bin .../html/classIRCarrierAc64-members.html | 0 .../docs/doxygen/html/classIRCarrierAc64.html | 0 .../html/classIRCarrierAc64__coll__graph.map | 0 .../html/classIRCarrierAc64__coll__graph.md5 | 0 .../html/classIRCarrierAc64__coll__graph.png | Bin .../doxygen/html/classIRCoolixAC-members.html | 0 .../docs/doxygen/html/classIRCoolixAC.html | 0 .../html/classIRCoolixAC__coll__graph.map | 0 .../html/classIRCoolixAC__coll__graph.md5 | 0 .../html/classIRCoolixAC__coll__graph.png | Bin .../doxygen/html/classIRCoronaAc-members.html | 0 .../docs/doxygen/html/classIRCoronaAc.html | 0 .../html/classIRCoronaAc__coll__graph.map | 0 .../html/classIRCoronaAc__coll__graph.md5 | 0 .../html/classIRCoronaAc__coll__graph.png | Bin .../html/classIRDaikin128-members.html | 0 .../docs/doxygen/html/classIRDaikin128.html | 0 .../html/classIRDaikin128__coll__graph.map | 0 .../html/classIRDaikin128__coll__graph.md5 | 0 .../html/classIRDaikin128__coll__graph.png | Bin .../html/classIRDaikin152-members.html | 0 .../docs/doxygen/html/classIRDaikin152.html | 0 .../html/classIRDaikin152__coll__graph.map | 0 .../html/classIRDaikin152__coll__graph.md5 | 0 .../html/classIRDaikin152__coll__graph.png | Bin .../html/classIRDaikin160-members.html | 0 .../docs/doxygen/html/classIRDaikin160.html | 0 .../html/classIRDaikin160__coll__graph.map | 0 .../html/classIRDaikin160__coll__graph.md5 | 0 .../html/classIRDaikin160__coll__graph.png | Bin .../html/classIRDaikin176-members.html | 0 .../docs/doxygen/html/classIRDaikin176.html | 0 .../html/classIRDaikin176__coll__graph.map | 0 .../html/classIRDaikin176__coll__graph.md5 | 0 .../html/classIRDaikin176__coll__graph.png | Bin .../doxygen/html/classIRDaikin2-members.html | 0 .../docs/doxygen/html/classIRDaikin2.html | 0 .../html/classIRDaikin216-members.html | 0 .../docs/doxygen/html/classIRDaikin216.html | 0 .../html/classIRDaikin216__coll__graph.map | 0 .../html/classIRDaikin216__coll__graph.md5 | 0 .../html/classIRDaikin216__coll__graph.png | Bin .../html/classIRDaikin2__coll__graph.map | 0 .../html/classIRDaikin2__coll__graph.md5 | 0 .../html/classIRDaikin2__coll__graph.png | Bin .../doxygen/html/classIRDaikin64-members.html | 0 .../docs/doxygen/html/classIRDaikin64.html | 0 .../html/classIRDaikin64__coll__graph.map | 0 .../html/classIRDaikin64__coll__graph.md5 | 0 .../html/classIRDaikin64__coll__graph.png | Bin .../html/classIRDaikinESP-members.html | 0 .../docs/doxygen/html/classIRDaikinESP.html | 0 .../html/classIRDaikinESP__coll__graph.map | 0 .../html/classIRDaikinESP__coll__graph.md5 | 0 .../html/classIRDaikinESP__coll__graph.png | Bin .../html/classIRDelonghiAc-members.html | 0 .../docs/doxygen/html/classIRDelonghiAc.html | 0 .../html/classIRDelonghiAc__coll__graph.map | 0 .../html/classIRDelonghiAc__coll__graph.md5 | 0 .../html/classIRDelonghiAc__coll__graph.png | Bin .../html/classIRElectraAc-members.html | 0 .../docs/doxygen/html/classIRElectraAc.html | 0 .../html/classIRElectraAc__coll__graph.map | 0 .../html/classIRElectraAc__coll__graph.md5 | 0 .../html/classIRElectraAc__coll__graph.png | Bin .../html/classIRFujitsuAC-members.html | 0 .../docs/doxygen/html/classIRFujitsuAC.html | 0 .../html/classIRFujitsuAC__coll__graph.map | 0 .../html/classIRFujitsuAC__coll__graph.md5 | 0 .../html/classIRFujitsuAC__coll__graph.png | Bin .../html/classIRGoodweatherAc-members.html | 0 .../doxygen/html/classIRGoodweatherAc.html | 0 .../classIRGoodweatherAc__coll__graph.map | 0 .../classIRGoodweatherAc__coll__graph.md5 | 0 .../classIRGoodweatherAc__coll__graph.png | Bin .../doxygen/html/classIRGreeAC-members.html | 0 .../docs/doxygen/html/classIRGreeAC.html | 0 .../html/classIRGreeAC__coll__graph.map | 0 .../html/classIRGreeAC__coll__graph.md5 | 0 .../html/classIRGreeAC__coll__graph.png | Bin .../doxygen/html/classIRHaierAC-members.html | 0 .../docs/doxygen/html/classIRHaierAC.html | 0 .../html/classIRHaierACYRW02-members.html | 0 .../doxygen/html/classIRHaierACYRW02.html | 0 .../html/classIRHaierACYRW02__coll__graph.map | 0 .../html/classIRHaierACYRW02__coll__graph.md5 | 0 .../html/classIRHaierACYRW02__coll__graph.png | Bin .../html/classIRHaierAC__coll__graph.map | 0 .../html/classIRHaierAC__coll__graph.md5 | 0 .../html/classIRHaierAC__coll__graph.png | Bin .../html/classIRHitachiAc-members.html | 0 .../docs/doxygen/html/classIRHitachiAc.html | 0 .../html/classIRHitachiAc1-members.html | 0 .../docs/doxygen/html/classIRHitachiAc1.html | 0 .../html/classIRHitachiAc1__coll__graph.map | 0 .../html/classIRHitachiAc1__coll__graph.md5 | 0 .../html/classIRHitachiAc1__coll__graph.png | Bin .../html/classIRHitachiAc3-members.html | 0 .../docs/doxygen/html/classIRHitachiAc3.html | 0 .../html/classIRHitachiAc344-members.html | 0 .../doxygen/html/classIRHitachiAc344.html | 0 .../html/classIRHitachiAc344__coll__graph.map | 0 .../html/classIRHitachiAc344__coll__graph.md5 | 0 .../html/classIRHitachiAc344__coll__graph.png | Bin .../classIRHitachiAc344__inherit__graph.map | 0 .../classIRHitachiAc344__inherit__graph.md5 | 0 .../classIRHitachiAc344__inherit__graph.png | Bin .../html/classIRHitachiAc3__coll__graph.map | 0 .../html/classIRHitachiAc3__coll__graph.md5 | 0 .../html/classIRHitachiAc3__coll__graph.png | Bin .../html/classIRHitachiAc424-members.html | 0 .../doxygen/html/classIRHitachiAc424.html | 0 .../html/classIRHitachiAc424__coll__graph.map | 0 .../html/classIRHitachiAc424__coll__graph.md5 | 0 .../html/classIRHitachiAc424__coll__graph.png | Bin .../classIRHitachiAc424__inherit__graph.map | 0 .../classIRHitachiAc424__inherit__graph.md5 | 0 .../classIRHitachiAc424__inherit__graph.png | Bin .../html/classIRHitachiAc__coll__graph.map | 0 .../html/classIRHitachiAc__coll__graph.md5 | 0 .../html/classIRHitachiAc__coll__graph.png | Bin .../html/classIRKelvinatorAC-members.html | 0 .../doxygen/html/classIRKelvinatorAC.html | 0 .../html/classIRKelvinatorAC__coll__graph.map | 0 .../html/classIRKelvinatorAC__coll__graph.md5 | 0 .../html/classIRKelvinatorAC__coll__graph.png | Bin .../doxygen/html/classIRLgAc-members.html | 0 .../docs/doxygen/html/classIRLgAc.html | 0 .../doxygen/html/classIRLgAc__coll__graph.map | 0 .../doxygen/html/classIRLgAc__coll__graph.md5 | 0 .../doxygen/html/classIRLgAc__coll__graph.png | Bin .../doxygen/html/classIRMideaAC-members.html | 0 .../docs/doxygen/html/classIRMideaAC.html | 0 .../html/classIRMideaAC__coll__graph.map | 0 .../html/classIRMideaAC__coll__graph.md5 | 0 .../html/classIRMideaAC__coll__graph.png | Bin .../html/classIRMitsubishi112-members.html | 0 .../doxygen/html/classIRMitsubishi112.html | 0 .../classIRMitsubishi112__coll__graph.map | 0 .../classIRMitsubishi112__coll__graph.md5 | 0 .../classIRMitsubishi112__coll__graph.png | Bin .../html/classIRMitsubishi136-members.html | 0 .../doxygen/html/classIRMitsubishi136.html | 0 .../classIRMitsubishi136__coll__graph.map | 0 .../classIRMitsubishi136__coll__graph.md5 | 0 .../classIRMitsubishi136__coll__graph.png | Bin .../html/classIRMitsubishiAC-members.html | 0 .../doxygen/html/classIRMitsubishiAC.html | 0 .../html/classIRMitsubishiAC__coll__graph.map | 0 .../html/classIRMitsubishiAC__coll__graph.md5 | 0 .../html/classIRMitsubishiAC__coll__graph.png | Bin .../classIRMitsubishiHeavy152Ac-members.html | 0 .../html/classIRMitsubishiHeavy152Ac.html | 0 ...assIRMitsubishiHeavy152Ac__coll__graph.map | 0 ...assIRMitsubishiHeavy152Ac__coll__graph.md5 | 0 ...assIRMitsubishiHeavy152Ac__coll__graph.png | Bin .../classIRMitsubishiHeavy88Ac-members.html | 0 .../html/classIRMitsubishiHeavy88Ac.html | 0 ...lassIRMitsubishiHeavy88Ac__coll__graph.map | 0 ...lassIRMitsubishiHeavy88Ac__coll__graph.md5 | 0 ...lassIRMitsubishiHeavy88Ac__coll__graph.png | Bin .../html/classIRNeoclimaAc-members.html | 64 +- .../docs/doxygen/html/classIRNeoclimaAc.html | 326 +- .../html/classIRNeoclimaAc__coll__graph.map | 5 + .../html/classIRNeoclimaAc__coll__graph.md5 | 1 + .../html/classIRNeoclimaAc__coll__graph.png | Bin 0 -> 6475 bytes .../html/classIRPanasonicAc-members.html | 0 .../docs/doxygen/html/classIRPanasonicAc.html | 0 .../html/classIRPanasonicAc32-members.html | 108 + .../doxygen/html/classIRPanasonicAc32.html | 986 ++++ .../classIRPanasonicAc32__coll__graph.map | 5 + .../classIRPanasonicAc32__coll__graph.md5 | 1 + .../classIRPanasonicAc32__coll__graph.png | Bin 0 -> 7290 bytes .../html/classIRPanasonicAc__coll__graph.map | 0 .../html/classIRPanasonicAc__coll__graph.md5 | 0 .../html/classIRPanasonicAc__coll__graph.png | Bin .../html/classIRSamsungAc-members.html | 56 +- .../docs/doxygen/html/classIRSamsungAc.html | 256 +- .../html/classIRSamsungAc__coll__graph.map | 5 + .../html/classIRSamsungAc__coll__graph.md5 | 1 + .../html/classIRSamsungAc__coll__graph.png | Bin 0 -> 7008 bytes .../doxygen/html/classIRSanyoAc-members.html | 50 +- .../docs/doxygen/html/classIRSanyoAc.html | 328 +- .../html/classIRSanyoAc__coll__graph.map | 5 + .../html/classIRSanyoAc__coll__graph.md5 | 1 + .../html/classIRSanyoAc__coll__graph.png | Bin 0 -> 6451 bytes .../doxygen/html/classIRSharpAc-members.html | 82 +- .../docs/doxygen/html/classIRSharpAc.html | 322 +- .../html/classIRSharpAc__coll__graph.map | 5 + .../html/classIRSharpAc__coll__graph.md5 | 1 + .../html/classIRSharpAc__coll__graph.png | Bin 0 -> 6284 bytes .../doxygen/html/classIRTcl112Ac-members.html | 0 .../docs/doxygen/html/classIRTcl112Ac.html | 0 .../html/classIRTcl112Ac__coll__graph.map | 0 .../html/classIRTcl112Ac__coll__graph.md5 | 0 .../html/classIRTcl112Ac__coll__graph.png | Bin .../html/classIRTechnibelAc-members.html | 0 .../docs/doxygen/html/classIRTechnibelAc.html | 0 .../html/classIRTechnibelAc__coll__graph.map | 0 .../html/classIRTechnibelAc__coll__graph.md5 | 0 .../html/classIRTechnibelAc__coll__graph.png | Bin .../doxygen/html/classIRTecoAc-members.html | 0 .../docs/doxygen/html/classIRTecoAc.html | 0 .../html/classIRTecoAc__coll__graph.map | 0 .../html/classIRTecoAc__coll__graph.md5 | 0 .../html/classIRTecoAc__coll__graph.png | Bin .../html/classIRToshibaAC-members.html | 0 .../docs/doxygen/html/classIRToshibaAC.html | 0 .../html/classIRToshibaAC__coll__graph.map | 0 .../html/classIRToshibaAC__coll__graph.md5 | 0 .../html/classIRToshibaAC__coll__graph.png | Bin .../html/classIRTranscoldAc-members.html | 0 .../docs/doxygen/html/classIRTranscoldAc.html | 0 .../html/classIRTranscoldAc__coll__graph.map | 0 .../html/classIRTranscoldAc__coll__graph.md5 | 0 .../html/classIRTranscoldAc__coll__graph.png | Bin .../html/classIRTrotecESP-members.html | 0 .../docs/doxygen/html/classIRTrotecESP.html | 0 .../html/classIRTrotecESP__coll__graph.map | 0 .../html/classIRTrotecESP__coll__graph.md5 | 0 .../html/classIRTrotecESP__coll__graph.png | Bin .../doxygen/html/classIRVestelAc-members.html | 0 .../docs/doxygen/html/classIRVestelAc.html | 0 .../html/classIRVestelAc__coll__graph.map | 0 .../html/classIRVestelAc__coll__graph.md5 | 0 .../html/classIRVestelAc__coll__graph.png | Bin .../doxygen/html/classIRVoltas-members.html | 0 .../docs/doxygen/html/classIRVoltas.html | 0 .../html/classIRVoltas__coll__graph.map | 0 .../html/classIRVoltas__coll__graph.md5 | 0 .../html/classIRVoltas__coll__graph.png | Bin .../html/classIRWhirlpoolAc-members.html | 0 .../docs/doxygen/html/classIRWhirlpoolAc.html | 0 .../html/classIRWhirlpoolAc__coll__graph.map | 0 .../html/classIRWhirlpoolAc__coll__graph.md5 | 0 .../html/classIRWhirlpoolAc__coll__graph.png | Bin .../docs/doxygen/html/classIRac-members.html | 47 +- .../docs/doxygen/html/classIRac.html | 83 + .../doxygen/html/classIRac__coll__graph.map | 0 .../doxygen/html/classIRac__coll__graph.md5 | 0 .../doxygen/html/classIRac__coll__graph.png | Bin .../doxygen/html/classIRrecv-members.html | 0 .../docs/doxygen/html/classIRrecv.html | 8 +- .../doxygen/html/classIRrecv__coll__graph.map | 0 .../doxygen/html/classIRrecv__coll__graph.md5 | 0 .../doxygen/html/classIRrecv__coll__graph.png | Bin .../doxygen/html/classIRsend-members.html | 0 .../docs/doxygen/html/classIRsend.html | 4 +- .../doxygen/html/classIRtimer-members.html | 0 .../docs/doxygen/html/classIRtimer.html | 0 .../doxygen/html/classTimerMs-members.html | 0 .../docs/doxygen/html/classTimerMs.html | 0 .../html/classdecode__results-members.html | 0 .../doxygen/html/classdecode__results.html | 32 +- .../docs/doxygen/html/classes.html | 156 +- .../docs/doxygen/html/closed.png | Bin .../docs/doxygen/html/de-CH_8h.html | 0 .../docs/doxygen/html/de-CH_8h_source.html | 0 .../docs/doxygen/html/de-DE_8h.html | 0 .../docs/doxygen/html/de-DE_8h_source.html | 0 .../docs/doxygen/html/defaults_8h.html | 0 .../docs/doxygen/html/defaults_8h_source.html | 0 .../docs/doxygen/html/deprecated.html | 0 .../dir_49e56c817e5e54854c35e136979f97ca.html | 0 .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 0 .../dir_84fe998d1eb06414cc389ad334e77e63.html | 0 .../docs/doxygen/html/doc.png | Bin .../docs/doxygen/html/doxygen.css | 0 .../docs/doxygen/html/doxygen.png | Bin .../docs/doxygen/html/doxygen__index_8md.html | 0 .../docs/doxygen/html/dynsections.js | 0 .../docs/doxygen/html/en-AU_8h.html | 0 .../docs/doxygen/html/en-AU_8h_source.html | 0 .../docs/doxygen/html/en-IE_8h.html | 0 .../docs/doxygen/html/en-IE_8h_source.html | 0 .../docs/doxygen/html/en-UK_8h.html | 0 .../docs/doxygen/html/en-UK_8h_source.html | 0 .../docs/doxygen/html/en-US_8h.html | 0 .../docs/doxygen/html/en-US_8h_source.html | 0 .../docs/doxygen/html/es-ES_8h.html | 0 .../docs/doxygen/html/es-ES_8h_source.html | 0 .../docs/doxygen/html/files.html | 0 .../docs/doxygen/html/folderclosed.png | Bin .../docs/doxygen/html/folderopen.png | Bin .../docs/doxygen/html/fr-FR_8h.html | 0 .../docs/doxygen/html/fr-FR_8h_source.html | 0 .../docs/doxygen/html/functions.html | 67 +- .../docs/doxygen/html/functions_a.html | 3 + .../docs/doxygen/html/functions_b.html | 7 + .../docs/doxygen/html/functions_c.html | 14 + .../docs/doxygen/html/functions_d.html | 3 + .../docs/doxygen/html/functions_e.html | 2 + .../docs/doxygen/html/functions_f.html | 11 + .../docs/doxygen/html/functions_func.html | 6 +- .../docs/doxygen/html/functions_func_a.html | 0 .../docs/doxygen/html/functions_func_b.html | 1 + .../docs/doxygen/html/functions_func_c.html | 4 + .../docs/doxygen/html/functions_func_d.html | 0 .../docs/doxygen/html/functions_func_e.html | 0 .../docs/doxygen/html/functions_func_f.html | 0 .../docs/doxygen/html/functions_func_g.html | 119 +- .../docs/doxygen/html/functions_func_h.html | 0 .../docs/doxygen/html/functions_func_i.html | 5 +- .../docs/doxygen/html/functions_func_k.html | 0 .../docs/doxygen/html/functions_func_l.html | 0 .../docs/doxygen/html/functions_func_m.html | 0 .../docs/doxygen/html/functions_func_n.html | 0 .../docs/doxygen/html/functions_func_o.html | 0 .../docs/doxygen/html/functions_func_p.html | 3 + .../docs/doxygen/html/functions_func_r.html | 0 .../docs/doxygen/html/functions_func_s.html | 9 + .../docs/doxygen/html/functions_func_t.html | 25 +- .../docs/doxygen/html/functions_func_u.html | 0 .../docs/doxygen/html/functions_func_v.html | 0 .../docs/doxygen/html/functions_func_w.html | 0 .../docs/doxygen/html/functions_func_~.html | 0 .../docs/doxygen/html/functions_g.html | 119 +- .../docs/doxygen/html/functions_h.html | 3 + .../docs/doxygen/html/functions_i.html | 12 +- .../docs/doxygen/html/functions_k.html | 0 .../docs/doxygen/html/functions_l.html | 1 + .../docs/doxygen/html/functions_m.html | 6 + .../docs/doxygen/html/functions_n.html | 0 .../docs/doxygen/html/functions_o.html | 4 + .../docs/doxygen/html/functions_p.html | 24 + .../docs/doxygen/html/functions_q.html | 6 + .../docs/doxygen/html/functions_r.html | 11 +- .../docs/doxygen/html/functions_rela.html | 0 .../docs/doxygen/html/functions_s.html | 30 +- .../docs/doxygen/html/functions_t.html | 36 +- .../docs/doxygen/html/functions_u.html | 3 + .../docs/doxygen/html/functions_v.html | 0 .../docs/doxygen/html/functions_vars.html | 59 + .../docs/doxygen/html/functions_vars_a.html | 3 + .../docs/doxygen/html/functions_vars_b.html | 6 + .../docs/doxygen/html/functions_vars_c.html | 10 + .../docs/doxygen/html/functions_vars_d.html | 3 + .../docs/doxygen/html/functions_vars_e.html | 2 + .../docs/doxygen/html/functions_vars_f.html | 11 + .../docs/doxygen/html/functions_vars_h.html | 3 + .../docs/doxygen/html/functions_vars_i.html | 5 + .../docs/doxygen/html/functions_vars_l.html | 1 + .../docs/doxygen/html/functions_vars_m.html | 6 + .../docs/doxygen/html/functions_vars_n.html | 0 .../docs/doxygen/html/functions_vars_o.html | 4 + .../docs/doxygen/html/functions_vars_p.html | 21 + .../docs/doxygen/html/functions_vars_q.html | 6 + .../docs/doxygen/html/functions_vars_r.html | 11 +- .../docs/doxygen/html/functions_vars_s.html | 19 + .../docs/doxygen/html/functions_vars_t.html | 11 + .../docs/doxygen/html/functions_vars_u.html | 3 + .../docs/doxygen/html/functions_vars_v.html | 0 .../docs/doxygen/html/functions_vars_w.html | 0 .../docs/doxygen/html/functions_vars_x.html | 0 .../docs/doxygen/html/functions_vars_z.html | 0 .../docs/doxygen/html/functions_w.html | 0 .../docs/doxygen/html/functions_x.html | 0 .../docs/doxygen/html/functions_z.html | 0 .../docs/doxygen/html/functions_~.html | 0 .../docs/doxygen/html/globals.html | 0 .../docs/doxygen/html/globals_a.html | 0 .../docs/doxygen/html/globals_c.html | 0 .../docs/doxygen/html/globals_d.html | 0 .../docs/doxygen/html/globals_e.html | 0 .../docs/doxygen/html/globals_enum.html | 0 .../docs/doxygen/html/globals_eval.html | 0 .../docs/doxygen/html/globals_f.html | 0 .../docs/doxygen/html/globals_func.html | 0 .../docs/doxygen/html/globals_g.html | 0 .../docs/doxygen/html/globals_h.html | 3 + .../docs/doxygen/html/globals_i.html | 13 +- .../docs/doxygen/html/globals_j.html | 0 .../docs/doxygen/html/globals_k.html | 427 +- .../docs/doxygen/html/globals_l.html | 0 .../docs/doxygen/html/globals_m.html | 0 .../docs/doxygen/html/globals_n.html | 0 .../docs/doxygen/html/globals_p.html | 0 .../docs/doxygen/html/globals_r.html | 0 .../docs/doxygen/html/globals_s.html | 0 .../docs/doxygen/html/globals_t.html | 0 .../docs/doxygen/html/globals_type.html | 3 + .../docs/doxygen/html/globals_u.html | 0 .../docs/doxygen/html/globals_v.html | 0 .../docs/doxygen/html/globals_vars.html | 0 .../docs/doxygen/html/globals_vars_i.html | 0 .../docs/doxygen/html/globals_vars_k.html | 443 +- .../docs/doxygen/html/globals_w.html | 0 .../docs/doxygen/html/globals_x.html | 0 .../docs/doxygen/html/globals_y.html | 0 .../docs/doxygen/html/globals_z.html | 0 .../docs/doxygen/html/graph_legend.html | 0 .../docs/doxygen/html/graph_legend.md5 | 0 .../docs/doxygen/html/graph_legend.png | Bin .../docs/doxygen/html/hierarchy.html | 64 +- .../docs/doxygen/html/i18n_8h.html | 0 .../docs/doxygen/html/i18n_8h_source.html | 0 .../docs/doxygen/html/index.html | 0 .../docs/doxygen/html/inherit_graph_0.map | 0 .../docs/doxygen/html/inherit_graph_0.md5 | 0 .../docs/doxygen/html/inherit_graph_0.png | Bin .../docs/doxygen/html/inherit_graph_1.map | 0 .../docs/doxygen/html/inherit_graph_1.md5 | 0 .../docs/doxygen/html/inherit_graph_1.png | Bin .../docs/doxygen/html/inherit_graph_10.map | 0 .../docs/doxygen/html/inherit_graph_10.md5 | 0 .../docs/doxygen/html/inherit_graph_10.png | Bin .../docs/doxygen/html/inherit_graph_11.map | 0 .../docs/doxygen/html/inherit_graph_11.md5 | 0 .../docs/doxygen/html/inherit_graph_11.png | Bin .../docs/doxygen/html/inherit_graph_12.map | 0 .../docs/doxygen/html/inherit_graph_12.md5 | 0 .../docs/doxygen/html/inherit_graph_12.png | Bin .../docs/doxygen/html/inherit_graph_13.map | 0 .../docs/doxygen/html/inherit_graph_13.md5 | 0 .../docs/doxygen/html/inherit_graph_13.png | Bin .../docs/doxygen/html/inherit_graph_14.map | 0 .../docs/doxygen/html/inherit_graph_14.md5 | 0 .../docs/doxygen/html/inherit_graph_14.png | Bin .../docs/doxygen/html/inherit_graph_15.map | 0 .../docs/doxygen/html/inherit_graph_15.md5 | 0 .../docs/doxygen/html/inherit_graph_15.png | Bin .../docs/doxygen/html/inherit_graph_16.map | 0 .../docs/doxygen/html/inherit_graph_16.md5 | 0 .../docs/doxygen/html/inherit_graph_16.png | Bin .../docs/doxygen/html/inherit_graph_17.map | 0 .../docs/doxygen/html/inherit_graph_17.md5 | 0 .../docs/doxygen/html/inherit_graph_17.png | Bin .../docs/doxygen/html/inherit_graph_18.map | 0 .../docs/doxygen/html/inherit_graph_18.md5 | 0 .../docs/doxygen/html/inherit_graph_18.png | Bin .../docs/doxygen/html/inherit_graph_19.map | 0 .../docs/doxygen/html/inherit_graph_19.md5 | 0 .../docs/doxygen/html/inherit_graph_19.png | Bin .../docs/doxygen/html/inherit_graph_2.map | 0 .../docs/doxygen/html/inherit_graph_2.md5 | 0 .../docs/doxygen/html/inherit_graph_2.png | Bin .../docs/doxygen/html/inherit_graph_20.map | 0 .../docs/doxygen/html/inherit_graph_20.md5 | 0 .../docs/doxygen/html/inherit_graph_20.png | Bin .../docs/doxygen/html/inherit_graph_21.map | 0 .../docs/doxygen/html/inherit_graph_21.md5 | 0 .../docs/doxygen/html/inherit_graph_21.png | Bin .../docs/doxygen/html/inherit_graph_22.map | 0 .../docs/doxygen/html/inherit_graph_22.md5 | 0 .../docs/doxygen/html/inherit_graph_22.png | Bin .../docs/doxygen/html/inherit_graph_23.map | 0 .../docs/doxygen/html/inherit_graph_23.md5 | 0 .../docs/doxygen/html/inherit_graph_23.png | Bin .../docs/doxygen/html/inherit_graph_24.map | 0 .../docs/doxygen/html/inherit_graph_24.md5 | 0 .../docs/doxygen/html/inherit_graph_24.png | Bin .../docs/doxygen/html/inherit_graph_25.map | 0 .../docs/doxygen/html/inherit_graph_25.md5 | 0 .../docs/doxygen/html/inherit_graph_25.png | Bin .../docs/doxygen/html/inherit_graph_26.map | 0 .../docs/doxygen/html/inherit_graph_26.md5 | 0 .../docs/doxygen/html/inherit_graph_26.png | Bin .../docs/doxygen/html/inherit_graph_27.map | 0 .../docs/doxygen/html/inherit_graph_27.md5 | 0 .../docs/doxygen/html/inherit_graph_27.png | Bin .../docs/doxygen/html/inherit_graph_28.map | 0 .../docs/doxygen/html/inherit_graph_28.md5 | 0 .../docs/doxygen/html/inherit_graph_28.png | Bin .../docs/doxygen/html/inherit_graph_29.map | 0 .../docs/doxygen/html/inherit_graph_29.md5 | 0 .../docs/doxygen/html/inherit_graph_29.png | Bin .../docs/doxygen/html/inherit_graph_3.map | 0 .../docs/doxygen/html/inherit_graph_3.md5 | 0 .../docs/doxygen/html/inherit_graph_3.png | Bin .../docs/doxygen/html/inherit_graph_30.map | 0 .../docs/doxygen/html/inherit_graph_30.md5 | 0 .../docs/doxygen/html/inherit_graph_30.png | Bin .../docs/doxygen/html/inherit_graph_31.map | 0 .../docs/doxygen/html/inherit_graph_31.md5 | 0 .../docs/doxygen/html/inherit_graph_31.png | Bin .../docs/doxygen/html/inherit_graph_32.map | 0 .../docs/doxygen/html/inherit_graph_32.md5 | 0 .../docs/doxygen/html/inherit_graph_32.png | Bin .../docs/doxygen/html/inherit_graph_33.map | 0 .../docs/doxygen/html/inherit_graph_33.md5 | 0 .../docs/doxygen/html/inherit_graph_33.png | Bin .../docs/doxygen/html/inherit_graph_34.map | 0 .../docs/doxygen/html/inherit_graph_34.md5 | 0 .../docs/doxygen/html/inherit_graph_34.png | Bin .../docs/doxygen/html/inherit_graph_35.map | 0 .../docs/doxygen/html/inherit_graph_35.md5 | 0 .../docs/doxygen/html/inherit_graph_35.png | Bin .../docs/doxygen/html/inherit_graph_36.map | 0 .../docs/doxygen/html/inherit_graph_36.md5 | 0 .../docs/doxygen/html/inherit_graph_36.png | Bin .../docs/doxygen/html/inherit_graph_37.map | 0 .../docs/doxygen/html/inherit_graph_37.md5 | 0 .../docs/doxygen/html/inherit_graph_37.png | Bin .../docs/doxygen/html/inherit_graph_38.map | 0 .../docs/doxygen/html/inherit_graph_38.md5 | 0 .../docs/doxygen/html/inherit_graph_38.png | Bin .../docs/doxygen/html/inherit_graph_39.map | 0 .../docs/doxygen/html/inherit_graph_39.md5 | 0 .../docs/doxygen/html/inherit_graph_39.png | Bin .../docs/doxygen/html/inherit_graph_4.map | 0 .../docs/doxygen/html/inherit_graph_4.md5 | 0 .../docs/doxygen/html/inherit_graph_4.png | Bin .../docs/doxygen/html/inherit_graph_40.map | 0 .../docs/doxygen/html/inherit_graph_40.md5 | 0 .../docs/doxygen/html/inherit_graph_40.png | Bin .../docs/doxygen/html/inherit_graph_41.map | 0 .../docs/doxygen/html/inherit_graph_41.md5 | 0 .../docs/doxygen/html/inherit_graph_41.png | Bin .../docs/doxygen/html/inherit_graph_42.map | 0 .../docs/doxygen/html/inherit_graph_42.md5 | 0 .../docs/doxygen/html/inherit_graph_42.png | Bin .../docs/doxygen/html/inherit_graph_43.map | 0 .../docs/doxygen/html/inherit_graph_43.md5 | 0 .../docs/doxygen/html/inherit_graph_43.png | Bin .../docs/doxygen/html/inherit_graph_44.map | 0 .../docs/doxygen/html/inherit_graph_44.md5 | 0 .../docs/doxygen/html/inherit_graph_44.png | Bin .../docs/doxygen/html/inherit_graph_45.map | 0 .../docs/doxygen/html/inherit_graph_45.md5 | 0 .../docs/doxygen/html/inherit_graph_45.png | Bin .../docs/doxygen/html/inherit_graph_46.map | 0 .../docs/doxygen/html/inherit_graph_46.md5 | 0 .../docs/doxygen/html/inherit_graph_46.png | Bin .../docs/doxygen/html/inherit_graph_47.map | 0 .../docs/doxygen/html/inherit_graph_47.md5 | 0 .../docs/doxygen/html/inherit_graph_47.png | Bin .../docs/doxygen/html/inherit_graph_48.map | 0 .../docs/doxygen/html/inherit_graph_48.md5 | 0 .../docs/doxygen/html/inherit_graph_48.png | Bin .../docs/doxygen/html/inherit_graph_49.map | 0 .../docs/doxygen/html/inherit_graph_49.md5 | 0 .../docs/doxygen/html/inherit_graph_49.png | Bin .../docs/doxygen/html/inherit_graph_5.map | 0 .../docs/doxygen/html/inherit_graph_5.md5 | 0 .../docs/doxygen/html/inherit_graph_5.png | Bin .../docs/doxygen/html/inherit_graph_50.map | 0 .../docs/doxygen/html/inherit_graph_50.md5 | 0 .../docs/doxygen/html/inherit_graph_50.png | Bin .../docs/doxygen/html/inherit_graph_51.map | 0 .../docs/doxygen/html/inherit_graph_51.md5 | 0 .../docs/doxygen/html/inherit_graph_51.png | Bin .../docs/doxygen/html/inherit_graph_52.map | 0 .../docs/doxygen/html/inherit_graph_52.md5 | 0 .../docs/doxygen/html/inherit_graph_52.png | Bin .../docs/doxygen/html/inherit_graph_53.map | 0 .../docs/doxygen/html/inherit_graph_53.md5 | 0 .../docs/doxygen/html/inherit_graph_53.png | Bin .../docs/doxygen/html/inherit_graph_54.map | 0 .../docs/doxygen/html/inherit_graph_54.md5 | 0 .../docs/doxygen/html/inherit_graph_54.png | Bin .../docs/doxygen/html/inherit_graph_55.map | 0 .../docs/doxygen/html/inherit_graph_55.md5 | 0 .../docs/doxygen/html/inherit_graph_55.png | Bin .../docs/doxygen/html/inherit_graph_56.map | 0 .../docs/doxygen/html/inherit_graph_56.md5 | 0 .../docs/doxygen/html/inherit_graph_56.png | Bin .../docs/doxygen/html/inherit_graph_57.map | 0 .../docs/doxygen/html/inherit_graph_57.md5 | 0 .../docs/doxygen/html/inherit_graph_57.png | Bin .../docs/doxygen/html/inherit_graph_58.map | 0 .../docs/doxygen/html/inherit_graph_58.md5 | 0 .../docs/doxygen/html/inherit_graph_58.png | Bin .../docs/doxygen/html/inherit_graph_59.map | 0 .../docs/doxygen/html/inherit_graph_59.md5 | 0 .../docs/doxygen/html/inherit_graph_59.png | Bin .../docs/doxygen/html/inherit_graph_6.map | 0 .../docs/doxygen/html/inherit_graph_6.md5 | 0 .../docs/doxygen/html/inherit_graph_6.png | Bin .../docs/doxygen/html/inherit_graph_60.map | 0 .../docs/doxygen/html/inherit_graph_60.md5 | 0 .../docs/doxygen/html/inherit_graph_60.png | Bin .../docs/doxygen/html/inherit_graph_61.map | 3 + .../docs/doxygen/html/inherit_graph_61.md5 | 1 + .../docs/doxygen/html/inherit_graph_61.png | Bin 0 -> 1882 bytes .../docs/doxygen/html/inherit_graph_62.map} | 0 .../docs/doxygen/html/inherit_graph_62.md5} | 0 .../docs/doxygen/html/inherit_graph_62.png} | Bin .../docs/doxygen/html/inherit_graph_63.map} | 0 .../docs/doxygen/html/inherit_graph_63.md5} | 0 .../docs/doxygen/html/inherit_graph_63.png} | Bin .../docs/doxygen/html/inherit_graph_64.map} | 0 .../docs/doxygen/html/inherit_graph_64.md5} | 0 .../docs/doxygen/html/inherit_graph_64.png} | Bin .../docs/doxygen/html/inherit_graph_65.map} | 0 .../docs/doxygen/html/inherit_graph_65.md5} | 0 .../docs/doxygen/html/inherit_graph_65.png} | Bin .../docs/doxygen/html/inherit_graph_66.map} | 0 .../docs/doxygen/html/inherit_graph_66.md5} | 0 .../docs/doxygen/html/inherit_graph_66.png} | Bin .../docs/doxygen/html/inherit_graph_67.map} | 0 .../docs/doxygen/html/inherit_graph_67.md5} | 0 .../docs/doxygen/html/inherit_graph_67.png} | Bin .../docs/doxygen/html/inherit_graph_68.map} | 0 .../docs/doxygen/html/inherit_graph_68.md5} | 0 .../docs/doxygen/html/inherit_graph_68.png} | Bin .../docs/doxygen/html/inherit_graph_69.map} | 0 .../docs/doxygen/html/inherit_graph_69.md5} | 0 .../docs/doxygen/html/inherit_graph_69.png} | Bin .../docs/doxygen/html/inherit_graph_7.map | 0 .../docs/doxygen/html/inherit_graph_7.md5 | 0 .../docs/doxygen/html/inherit_graph_7.png | Bin .../docs/doxygen/html/inherit_graph_70.map} | 0 .../docs/doxygen/html/inherit_graph_70.md5} | 0 .../docs/doxygen/html/inherit_graph_70.png} | Bin .../docs/doxygen/html/inherit_graph_71.map} | 0 .../docs/doxygen/html/inherit_graph_71.md5} | 0 .../docs/doxygen/html/inherit_graph_71.png} | Bin .../docs/doxygen/html/inherit_graph_72.map} | 0 .../docs/doxygen/html/inherit_graph_72.md5} | 0 .../docs/doxygen/html/inherit_graph_72.png} | Bin .../docs/doxygen/html/inherit_graph_73.map} | 0 .../docs/doxygen/html/inherit_graph_73.md5} | 0 .../docs/doxygen/html/inherit_graph_73.png} | Bin .../docs/doxygen/html/inherit_graph_74.map} | 0 .../docs/doxygen/html/inherit_graph_74.md5} | 0 .../docs/doxygen/html/inherit_graph_74.png} | Bin .../docs/doxygen/html/inherit_graph_75.map} | 0 .../docs/doxygen/html/inherit_graph_75.md5} | 0 .../docs/doxygen/html/inherit_graph_75.png} | Bin .../docs/doxygen/html/inherit_graph_76.map} | 0 .../docs/doxygen/html/inherit_graph_76.md5} | 0 .../docs/doxygen/html/inherit_graph_76.png} | Bin .../docs/doxygen/html/inherit_graph_77.map} | 0 .../docs/doxygen/html/inherit_graph_77.md5} | 0 .../docs/doxygen/html/inherit_graph_77.png} | Bin .../docs/doxygen/html/inherit_graph_78.map} | 0 .../docs/doxygen/html/inherit_graph_78.md5} | 0 .../docs/doxygen/html/inherit_graph_78.png} | Bin .../docs/doxygen/html/inherit_graph_79.map} | 0 .../docs/doxygen/html/inherit_graph_79.md5} | 0 .../docs/doxygen/html/inherit_graph_79.png} | Bin .../docs/doxygen/html/inherit_graph_8.map | 0 .../docs/doxygen/html/inherit_graph_8.md5 | 0 .../docs/doxygen/html/inherit_graph_8.png | Bin .../docs/doxygen/html/inherit_graph_80.map} | 0 .../docs/doxygen/html/inherit_graph_80.md5} | 0 .../docs/doxygen/html/inherit_graph_80.png} | Bin .../docs/doxygen/html/inherit_graph_81.map} | 0 .../docs/doxygen/html/inherit_graph_81.md5} | 0 .../docs/doxygen/html/inherit_graph_81.png} | Bin .../docs/doxygen/html/inherit_graph_82.map} | 0 .../docs/doxygen/html/inherit_graph_82.md5} | 0 .../docs/doxygen/html/inherit_graph_82.png} | Bin .../docs/doxygen/html/inherit_graph_83.map} | 0 .../docs/doxygen/html/inherit_graph_83.md5} | 0 .../docs/doxygen/html/inherit_graph_83.png} | Bin .../docs/doxygen/html/inherit_graph_84.map} | 0 .../docs/doxygen/html/inherit_graph_84.md5} | 0 .../docs/doxygen/html/inherit_graph_84.png} | Bin .../docs/doxygen/html/inherit_graph_85.map} | 0 .../docs/doxygen/html/inherit_graph_85.md5} | 0 .../docs/doxygen/html/inherit_graph_85.png} | Bin .../docs/doxygen/html/inherit_graph_86.map} | 0 .../docs/doxygen/html/inherit_graph_86.md5} | 0 .../docs/doxygen/html/inherit_graph_86.png} | Bin .../docs/doxygen/html/inherit_graph_87.map} | 0 .../docs/doxygen/html/inherit_graph_87.md5} | 0 .../docs/doxygen/html/inherit_graph_87.png} | Bin .../docs/doxygen/html/inherit_graph_88.map | 3 + .../docs/doxygen/html/inherit_graph_88.md5 | 1 + .../docs/doxygen/html/inherit_graph_88.png | Bin 0 -> 1434 bytes .../docs/doxygen/html/inherit_graph_89.map | 3 + .../docs/doxygen/html/inherit_graph_89.md5 | 1 + .../docs/doxygen/html/inherit_graph_89.png | Bin 0 -> 1936 bytes .../docs/doxygen/html/inherit_graph_9.map | 0 .../docs/doxygen/html/inherit_graph_9.md5 | 0 .../docs/doxygen/html/inherit_graph_9.png | Bin .../docs/doxygen/html/inherit_graph_90.map | 3 + .../docs/doxygen/html/inherit_graph_90.md5 | 1 + .../docs/doxygen/html/inherit_graph_90.png | Bin 0 -> 1790 bytes .../docs/doxygen/html/inherit_graph_91.map | 3 + .../docs/doxygen/html/inherit_graph_91.md5 | 1 + .../docs/doxygen/html/inherit_graph_91.png | Bin 0 -> 1449 bytes .../docs/doxygen/html/inherit_graph_92.map | 3 + .../docs/doxygen/html/inherit_graph_92.md5 | 1 + .../docs/doxygen/html/inherit_graph_92.png | Bin 0 -> 1530 bytes .../docs/doxygen/html/inherit_graph_93.map} | 0 .../docs/doxygen/html/inherit_graph_93.md5} | 0 .../docs/doxygen/html/inherit_graph_93.png} | Bin .../docs/doxygen/html/inherit_graph_94.map} | 0 .../docs/doxygen/html/inherit_graph_94.md5} | 0 .../docs/doxygen/html/inherit_graph_94.png} | Bin .../docs/doxygen/html/inherit_graph_95.map} | 0 .../docs/doxygen/html/inherit_graph_95.md5} | 0 .../docs/doxygen/html/inherit_graph_95.png} | Bin .../docs/doxygen/html/inherits.html | 88 +- .../docs/doxygen/html/ir__Airwell_8cpp.html | 0 .../docs/doxygen/html/ir__Airwell_8h.html | 0 .../doxygen/html/ir__Airwell_8h_source.html | 0 .../docs/doxygen/html/ir__Aiwa_8cpp.html | 0 .../docs/doxygen/html/ir__Amcor_8cpp.html | 0 .../docs/doxygen/html/ir__Amcor_8h.html | 0 .../doxygen/html/ir__Amcor_8h_source.html | 0 .../docs/doxygen/html/ir__Argo_8cpp.html | 0 .../docs/doxygen/html/ir__Argo_8h.html | 0 .../docs/doxygen/html/ir__Argo_8h_source.html | 0 .../docs/doxygen/html/ir__Carrier_8cpp.html | 0 .../docs/doxygen/html/ir__Carrier_8h.html | 0 .../doxygen/html/ir__Carrier_8h_source.html | 0 .../docs/doxygen/html/ir__Coolix_8cpp.html | 0 .../docs/doxygen/html/ir__Coolix_8h.html | 0 .../doxygen/html/ir__Coolix_8h_source.html | 0 .../docs/doxygen/html/ir__Corona_8cpp.html | 0 .../docs/doxygen/html/ir__Corona_8h.html | 0 .../doxygen/html/ir__Corona_8h_source.html | 0 .../docs/doxygen/html/ir__Daikin_8cpp.html | 0 .../docs/doxygen/html/ir__Daikin_8h.html | 0 .../doxygen/html/ir__Daikin_8h_source.html | 0 .../docs/doxygen/html/ir__Delonghi_8cpp.html | 0 .../docs/doxygen/html/ir__Delonghi_8h.html | 0 .../doxygen/html/ir__Delonghi_8h_source.html | 0 .../docs/doxygen/html/ir__Denon_8cpp.html | 0 .../docs/doxygen/html/ir__Dish_8cpp.html | 0 .../docs/doxygen/html/ir__Doshisha_8cpp.html | 0 .../docs/doxygen/html/ir__Electra_8cpp.html | 0 .../docs/doxygen/html/ir__Electra_8h.html | 0 .../doxygen/html/ir__Electra_8h_source.html | 0 .../doxygen/html/ir__EliteScreens_8cpp.html | 0 .../docs/doxygen/html/ir__Epson_8cpp.html | 0 .../docs/doxygen/html/ir__Fujitsu_8cpp.html | 0 .../docs/doxygen/html/ir__Fujitsu_8h.html | 0 .../doxygen/html/ir__Fujitsu_8h_source.html | 0 .../docs/doxygen/html/ir__GICable_8cpp.html | 0 .../doxygen/html/ir__GlobalCache_8cpp.html | 0 .../doxygen/html/ir__Goodweather_8cpp.html | 0 .../docs/doxygen/html/ir__Goodweather_8h.html | 0 .../html/ir__Goodweather_8h_source.html | 0 .../docs/doxygen/html/ir__Gree_8cpp.html | 0 .../docs/doxygen/html/ir__Gree_8h.html | 0 .../docs/doxygen/html/ir__Gree_8h_source.html | 488 +- .../docs/doxygen/html/ir__Haier_8cpp.html | 0 .../docs/doxygen/html/ir__Haier_8h.html | 0 .../doxygen/html/ir__Haier_8h_source.html | 0 .../docs/doxygen/html/ir__Hitachi_8cpp.html | 0 .../docs/doxygen/html/ir__Hitachi_8h.html | 0 .../doxygen/html/ir__Hitachi_8h_source.html | 0 .../docs/doxygen/html/ir__Inax_8cpp.html | 0 .../docs/doxygen/html/ir__JVC_8cpp.html | 0 .../doxygen/html/ir__Kelvinator_8cpp.html | 0 .../docs/doxygen/html/ir__Kelvinator_8h.html | 0 .../html/ir__Kelvinator_8h_source.html | 387 +- .../docs/doxygen/html/ir__LG_8cpp.html | 0 .../docs/doxygen/html/ir__LG_8h.html | 0 .../docs/doxygen/html/ir__LG_8h_source.html | 0 .../docs/doxygen/html/ir__Lasertag_8cpp.html | 4 +- .../docs/doxygen/html/ir__Lego_8cpp.html | 0 .../docs/doxygen/html/ir__Lutron_8cpp.html | 0 .../docs/doxygen/html/ir__MWM_8cpp.html | 0 .../docs/doxygen/html/ir__Magiquest_8cpp.html | 0 .../docs/doxygen/html/ir__Magiquest_8h.html | 0 .../doxygen/html/ir__Magiquest_8h_source.html | 0 .../docs/doxygen/html/ir__Metz_8cpp.html | 0 .../docs/doxygen/html/ir__Midea_8cpp.html | 0 .../docs/doxygen/html/ir__Midea_8h.html | 4 +- .../doxygen/html/ir__Midea_8h_source.html | 524 +- .../docs/doxygen/html/ir__Mirage_8cpp.html | 0 .../html/ir__MitsubishiHeavy_8cpp.html | 0 .../doxygen/html/ir__MitsubishiHeavy_8h.html | 0 .../html/ir__MitsubishiHeavy_8h_source.html | 0 .../doxygen/html/ir__Mitsubishi_8cpp.html | 0 .../docs/doxygen/html/ir__Mitsubishi_8h.html | 0 .../html/ir__Mitsubishi_8h_source.html | 0 .../doxygen/html/ir__Multibrackets_8cpp.html | 0 .../docs/doxygen/html/ir__NEC_8cpp.html | 0 .../docs/doxygen/html/ir__NEC_8h.html | 0 .../docs/doxygen/html/ir__NEC_8h_source.html | 0 .../docs/doxygen/html/ir__Neoclima_8cpp.html | 0 .../docs/doxygen/html/ir__Neoclima_8h.html | 363 +- .../doxygen/html/ir__Neoclima_8h_source.html | 519 +- .../docs/doxygen/html/ir__Nikai_8cpp.html | 0 .../docs/doxygen/html/ir__Panasonic_8cpp.html | 0 .../docs/doxygen/html/ir__Panasonic_8h.html | 217 + .../doxygen/html/ir__Panasonic_8h_source.html | 134 +- .../docs/doxygen/html/ir__Pioneer_8cpp.html | 0 .../docs/doxygen/html/ir__Pronto_8cpp.html | 0 .../docs/doxygen/html/ir__RC5__RC6_8cpp.html | 0 .../docs/doxygen/html/ir__RCMM_8cpp.html | 0 .../docs/doxygen/html/ir__Samsung_8cpp.html | 0 .../docs/doxygen/html/ir__Samsung_8h.html | 307 +- .../doxygen/html/ir__Samsung_8h_source.html | 467 +- .../docs/doxygen/html/ir__Sanyo_8cpp.html | 12 +- .../docs/doxygen/html/ir__Sanyo_8h.html | 421 +- .../doxygen/html/ir__Sanyo_8h_source.html | 411 +- .../docs/doxygen/html/ir__Sharp_8cpp.html | 0 .../docs/doxygen/html/ir__Sharp_8h.html | 355 +- .../doxygen/html/ir__Sharp_8h_source.html | 563 +- .../docs/doxygen/html/ir__Sherwood_8cpp.html | 0 .../docs/doxygen/html/ir__Sony_8cpp.html | 0 .../docs/doxygen/html/ir__Symphony_8cpp.html | 0 .../docs/doxygen/html/ir__Tcl_8cpp.html | 0 .../docs/doxygen/html/ir__Tcl_8h.html | 0 .../docs/doxygen/html/ir__Tcl_8h_source.html | 0 .../docs/doxygen/html/ir__Technibel_8cpp.html | 0 .../docs/doxygen/html/ir__Technibel_8h.html | 0 .../doxygen/html/ir__Technibel_8h_source.html | 0 .../docs/doxygen/html/ir__Teco_8cpp.html | 0 .../docs/doxygen/html/ir__Teco_8h.html | 0 .../docs/doxygen/html/ir__Teco_8h_source.html | 0 .../docs/doxygen/html/ir__Toshiba_8cpp.html | 0 .../docs/doxygen/html/ir__Toshiba_8h.html | 0 .../doxygen/html/ir__Toshiba_8h_source.html | 0 .../docs/doxygen/html/ir__Transcold_8cpp.html | 0 .../docs/doxygen/html/ir__Transcold_8h.html | 0 .../doxygen/html/ir__Transcold_8h_source.html | 0 .../docs/doxygen/html/ir__Trotec_8cpp.html | 0 .../docs/doxygen/html/ir__Trotec_8h.html | 0 .../doxygen/html/ir__Trotec_8h_source.html | 0 .../docs/doxygen/html/ir__Vestel_8cpp.html | 0 .../docs/doxygen/html/ir__Vestel_8h.html | 0 .../doxygen/html/ir__Vestel_8h_source.html | 0 .../docs/doxygen/html/ir__Voltas_8cpp.html | 0 .../docs/doxygen/html/ir__Voltas_8h.html | 0 .../doxygen/html/ir__Voltas_8h_source.html | 0 .../docs/doxygen/html/ir__Whirlpool_8cpp.html | 0 .../docs/doxygen/html/ir__Whirlpool_8h.html | 0 .../doxygen/html/ir__Whirlpool_8h_source.html | 0 .../docs/doxygen/html/ir__Whynter_8cpp.html | 0 .../docs/doxygen/html/ir__Zepeal_8cpp.html | 0 .../docs/doxygen/html/it-IT_8h.html | 0 .../docs/doxygen/html/it-IT_8h_source.html | 0 .../docs/doxygen/html/jquery.js | 0 .../doxygen/html/md_src_locale_README.html | 0 .../docs/doxygen/html/menu.js | 0 .../docs/doxygen/html/menudata.js | 3 +- .../docs/doxygen/html/namespaceIRAcUtils.html | 0 .../docs/doxygen/html/namespace__IRrecv.html} | 38 +- .../docs/doxygen/html/namespaceirutils.html | 19 +- .../docs/doxygen/html/namespacemembers.html | 19 +- .../doxygen/html/namespacemembers_enum.html | 0 .../doxygen/html/namespacemembers_func.html | 2 +- .../doxygen/html/namespacemembers_vars.html | 83 + .../docs/doxygen/html/namespaces.html | 7 +- .../docs/doxygen/html/namespacestdAc.html | 0 .../docs/doxygen/html/nav_f.png | Bin .../docs/doxygen/html/nav_g.png | Bin .../docs/doxygen/html/nav_h.png | Bin .../docs/doxygen/html/open.png | Bin .../docs/doxygen/html/pages.html | 0 .../docs/doxygen/html/pt-BR_8h.html | 0 .../docs/doxygen/html/pt-BR_8h_source.html | 0 .../docs/doxygen/html/search/all_0.html | 0 .../docs/doxygen/html/search/all_0.js | 50 +- .../docs/doxygen/html/search/all_1.html | 0 .../docs/doxygen/html/search/all_1.js | 4 +- .../docs/doxygen/html/search/all_10.html | 0 .../docs/doxygen/html/search/all_10.js | 36 + .../docs/doxygen/html/search/all_11.html | 0 .../docs/doxygen/html/search/all_11.js | 4 +- .../docs/doxygen/html/search/all_12.html | 0 .../docs/doxygen/html/search/all_12.js | 53 +- .../docs/doxygen/html/search/all_13.html | 0 .../docs/doxygen/html/search/all_13.js | 570 +- .../docs/doxygen/html/search/all_14.html | 0 .../docs/doxygen/html/search/all_14.js | 77 +- .../docs/doxygen/html/search/all_15.html | 0 .../docs/doxygen/html/search/all_15.js | 15 + .../docs/doxygen/html/search/all_16.html | 0 .../docs/doxygen/html/search/all_16.js | 24 +- .../docs/doxygen/html/search/all_17.html | 0 .../docs/doxygen/html/search/all_17.js | 12 + .../docs/doxygen/html/search/all_18.html | 0 .../docs/doxygen/html/search/all_18.js | 4 +- .../docs/doxygen/html/search/all_19.html | 0 .../docs/doxygen/html/search/all_19.js | 4 +- .../docs/doxygen/html/search/all_1a.html | 0 .../docs/doxygen/html/search/all_1a.js | 7 + .../docs/doxygen/html/search/all_1b.html | 0 .../docs/doxygen/html/search/all_1b.js | 4 + .../docs/doxygen/html/search/all_2.html | 0 .../docs/doxygen/html/search/all_2.js | 15 +- .../docs/doxygen/html/search/all_3.html | 0 .../docs/doxygen/html/search/all_3.js | 115 +- .../docs/doxygen/html/search/all_4.html | 0 .../docs/doxygen/html/search/all_4.js | 136 + .../docs/doxygen/html/search/all_5.html | 0 .../docs/doxygen/html/search/all_5.js | 39 + .../docs/doxygen/html/search/all_6.html | 0 .../docs/doxygen/html/search/all_6.js | 38 +- .../docs/doxygen/html/search/all_7.html | 0 .../docs/doxygen/html/search/all_7.js | 250 +- .../docs/doxygen/html/search/all_8.html | 0 .../docs/doxygen/html/search/all_8.js | 36 + .../docs/doxygen/html/search/all_9.html | 0 .../docs/doxygen/html/search/all_9.js | 198 + .../docs/doxygen/html/search/all_a.html | 0 .../docs/doxygen/html/search/all_a.js | 2 +- .../docs/doxygen/html/search/all_b.html | 0 .../docs/doxygen/html/search/all_b.js | 4589 ++++++++--------- .../docs/doxygen/html/search/all_c.html | 0 .../docs/doxygen/html/search/all_c.js | 19 + .../docs/doxygen/html/search/all_d.html | 0 .../docs/doxygen/html/search/all_d.js | 51 + .../docs/doxygen/html/search/all_e.html | 0 .../docs/doxygen/html/search/all_e.js | 13 +- .../docs/doxygen/html/search/all_f.html | 0 .../docs/doxygen/html/search/all_f.js | 63 +- .../docs/doxygen/html/search/classes_0.html | 0 .../docs/doxygen/html/search/classes_0.js | 6 + .../docs/doxygen/html/search/classes_1.html | 0 .../docs/doxygen/html/search/classes_1.js | 7 + .../docs/doxygen/html/search/classes_2.html | 0 .../docs/doxygen/html/search/classes_2.js | 13 + .../docs/doxygen/html/search/classes_3.html | 0 .../docs/doxygen/html/search/classes_3.js | 4 + .../docs/doxygen/html/search/classes_4.html | 0 .../docs/doxygen/html/search/classes_4.js | 5 + .../docs/doxygen/html/search/classes_5.html | 0 .../docs/doxygen/html/search/classes_5.js | 8 + .../docs/doxygen/html/search/classes_6.html | 0 .../docs/doxygen/html/search/classes_6.js | 57 + .../docs/doxygen/html/search/classes_7.html | 0 .../docs/doxygen/html/search/classes_7.js | 4 + .../docs/doxygen/html/search/classes_8.html | 0 .../docs/doxygen/html/search/classes_8.js | 4 + .../docs/doxygen/html/search/classes_9.html | 0 .../docs/doxygen/html/search/classes_9.js | 11 + .../docs/doxygen/html/search/classes_a.html | 0 .../docs/doxygen/html/search/classes_a.js | 4 + .../docs/doxygen/html/search/classes_b.html | 0 .../docs/doxygen/html/search/classes_b.js | 4 + .../docs/doxygen/html/search/classes_c.html | 0 .../docs/doxygen/html/search/classes_c.js | 7 + .../docs/doxygen/html/search/classes_d.html | 30 + .../docs/doxygen/html/search/classes_d.js | 4 + .../docs/doxygen/html/search/classes_e.html | 30 + .../docs/doxygen/html/search/classes_e.js | 4 + .../docs/doxygen/html/search/close.png | Bin .../docs/doxygen/html/search/enums_0.html | 0 .../docs/doxygen/html/search/enums_0.js | 2 +- .../docs/doxygen/html/search/enums_1.html | 0 .../docs/doxygen/html/search/enums_1.js | 4 +- .../docs/doxygen/html/search/enums_2.html | 0 .../docs/doxygen/html/search/enums_2.js | 2 +- .../docs/doxygen/html/search/enums_3.html | 0 .../docs/doxygen/html/search/enums_3.js | 2 +- .../docs/doxygen/html/search/enums_4.html | 0 .../docs/doxygen/html/search/enums_4.js | 2 +- .../docs/doxygen/html/search/enums_5.html | 0 .../docs/doxygen/html/search/enums_5.js | 4 + .../docs/doxygen/html/search/enums_6.html | 0 .../docs/doxygen/html/search/enums_6.js | 2 +- .../docs/doxygen/html/search/enums_7.html | 0 .../docs/doxygen/html/search/enums_7.js | 6 + .../docs/doxygen/html/search/enums_8.html | 0 .../docs/doxygen/html/search/enums_8.js | 2 +- .../docs/doxygen/html/search/enums_9.html | 0 .../docs/doxygen/html/search/enums_9.js | 2 +- .../doxygen/html/search/enumvalues_0.html | 0 .../docs/doxygen/html/search/enumvalues_0.js | 24 +- .../doxygen/html/search/enumvalues_1.html | 0 .../docs/doxygen/html/search/enumvalues_1.js | 10 +- .../doxygen/html/search/enumvalues_10.html | 0 .../docs/doxygen/html/search/enumvalues_10.js | 12 +- .../doxygen/html/search/enumvalues_11.html | 0 .../docs/doxygen/html/search/enumvalues_11.js | 4 +- .../doxygen/html/search/enumvalues_12.html | 0 .../docs/doxygen/html/search/enumvalues_12.js | 4 +- .../doxygen/html/search/enumvalues_13.html | 0 .../docs/doxygen/html/search/enumvalues_13.js | 4 +- .../doxygen/html/search/enumvalues_14.html | 0 .../docs/doxygen/html/search/enumvalues_14.js | 4 +- .../doxygen/html/search/enumvalues_15.html | 0 .../docs/doxygen/html/search/enumvalues_15.js | 2 +- .../doxygen/html/search/enumvalues_2.html | 0 .../docs/doxygen/html/search/enumvalues_2.js | 28 +- .../doxygen/html/search/enumvalues_3.html | 0 .../docs/doxygen/html/search/enumvalues_3.js | 6 +- .../doxygen/html/search/enumvalues_4.html | 0 .../docs/doxygen/html/search/enumvalues_4.js | 2 +- .../doxygen/html/search/enumvalues_5.html | 0 .../docs/doxygen/html/search/enumvalues_5.js | 10 +- .../doxygen/html/search/enumvalues_6.html | 0 .../docs/doxygen/html/search/enumvalues_6.js | 16 +- .../doxygen/html/search/enumvalues_7.html | 0 .../docs/doxygen/html/search/enumvalues_7.js | 2 +- .../doxygen/html/search/enumvalues_8.html | 0 .../docs/doxygen/html/search/enumvalues_8.js | 2 +- .../doxygen/html/search/enumvalues_9.html | 0 .../docs/doxygen/html/search/enumvalues_9.js | 68 +- .../doxygen/html/search/enumvalues_a.html | 0 .../docs/doxygen/html/search/enumvalues_a.js | 10 +- .../doxygen/html/search/enumvalues_b.html | 0 .../docs/doxygen/html/search/enumvalues_b.js | 28 +- .../doxygen/html/search/enumvalues_c.html | 0 .../docs/doxygen/html/search/enumvalues_c.js | 8 +- .../doxygen/html/search/enumvalues_d.html | 0 .../docs/doxygen/html/search/enumvalues_d.js | 10 +- .../doxygen/html/search/enumvalues_e.html | 0 .../docs/doxygen/html/search/enumvalues_e.js | 14 +- .../doxygen/html/search/enumvalues_f.html | 0 .../docs/doxygen/html/search/enumvalues_f.js | 24 +- .../docs/doxygen/html/search/files_0.html | 0 .../docs/doxygen/html/search/files_0.js | 7 + .../docs/doxygen/html/search/files_1.html | 0 .../docs/doxygen/html/search/files_1.js | 8 + .../docs/doxygen/html/search/files_2.html | 0 .../docs/doxygen/html/search/files_2.js | 4 + .../docs/doxygen/html/search/files_3.html | 0 .../docs/doxygen/html/search/files_3.js | 115 + .../docs/doxygen/html/search/files_4.html | 0 .../docs/doxygen/html/search/files_4.js | 4 + .../docs/doxygen/html/search/files_5.html | 0 .../docs/doxygen/html/search/files_5.js | 4 + .../docs/doxygen/html/search/files_6.html | 0 .../docs/doxygen/html/search/files_6.js | 4 + .../docs/doxygen/html/search/functions_0.html | 0 .../docs/doxygen/html/search/functions_0.js | 20 + .../docs/doxygen/html/search/functions_1.html | 0 .../docs/doxygen/html/search/functions_1.js | 15 + .../doxygen/html/search/functions_10.html | 0 .../docs/doxygen/html/search/functions_10.js | 20 +- .../doxygen/html/search/functions_11.html | 0 .../docs/doxygen/html/search/functions_11.js | 466 +- .../doxygen/html/search/functions_12.html | 0 .../docs/doxygen/html/search/functions_12.js | 42 +- .../doxygen/html/search/functions_13.html | 0 .../docs/doxygen/html/search/functions_13.js | 8 +- .../doxygen/html/search/functions_14.html | 0 .../docs/doxygen/html/search/functions_14.js | 8 +- .../doxygen/html/search/functions_15.html | 0 .../docs/doxygen/html/search/functions_15.js | 4 + .../doxygen/html/search/functions_16.html | 0 .../docs/doxygen/html/search/functions_16.js | 2 +- .../doxygen/html/search/functions_17.html | 0 .../docs/doxygen/html/search/functions_17.js | 4 + .../docs/doxygen/html/search/functions_2.html | 0 .../docs/doxygen/html/search/functions_2.js | 10 +- .../docs/doxygen/html/search/functions_3.html | 0 .../docs/doxygen/html/search/functions_3.js | 66 +- .../docs/doxygen/html/search/functions_4.html | 0 .../docs/doxygen/html/search/functions_4.js | 103 + .../docs/doxygen/html/search/functions_5.html | 0 .../docs/doxygen/html/search/functions_5.js | 48 +- .../docs/doxygen/html/search/functions_6.html | 0 .../docs/doxygen/html/search/functions_6.js | 10 +- .../docs/doxygen/html/search/functions_7.html | 0 .../docs/doxygen/html/search/functions_7.js | 238 +- .../docs/doxygen/html/search/functions_8.html | 0 .../docs/doxygen/html/search/functions_8.js | 24 +- .../docs/doxygen/html/search/functions_9.html | 0 .../docs/doxygen/html/search/functions_9.js | 143 +- .../docs/doxygen/html/search/functions_a.html | 0 .../docs/doxygen/html/search/functions_a.js | 4 + .../docs/doxygen/html/search/functions_b.html | 0 .../docs/doxygen/html/search/functions_b.js | 7 + .../docs/doxygen/html/search/functions_c.html | 0 .../docs/doxygen/html/search/functions_c.js | 44 +- .../docs/doxygen/html/search/functions_d.html | 0 .../docs/doxygen/html/search/functions_d.js | 4 + .../docs/doxygen/html/search/functions_e.html | 0 .../docs/doxygen/html/search/functions_e.js | 6 +- .../docs/doxygen/html/search/functions_f.html | 0 .../docs/doxygen/html/search/functions_f.js | 5 + .../docs/doxygen/html/search/mag_sel.png | Bin .../doxygen/html/search/namespaces_0.html | 0 .../docs/doxygen/html/search/namespaces_0.js | 4 + .../doxygen/html/search/namespaces_1.html | 0 .../docs/doxygen/html/search/namespaces_1.js | 5 + .../doxygen/html/search/namespaces_2.html | 30 + .../docs/doxygen/html/search/namespaces_2.js | 4 + .../docs/doxygen/html/search/nomatches.html | 0 .../docs/doxygen/html/search/pages_0.html | 0 .../docs/doxygen/html/search/pages_0.js | 4 + .../docs/doxygen/html/search/pages_1.html | 0 .../docs/doxygen/html/search/pages_1.js | 5 + .../docs/doxygen/html/search/pages_2.html | 0 .../docs/doxygen/html/search/pages_2.js | 4 + .../docs/doxygen/html/search/related_0.html | 0 .../docs/doxygen/html/search/related_0.js | 2 +- .../docs/doxygen/html/search/search.css | 0 .../docs/doxygen/html/search/search.js | 0 .../docs/doxygen/html/search/search_l.png | Bin .../docs/doxygen/html/search/search_m.png | Bin .../docs/doxygen/html/search/search_r.png | Bin .../docs/doxygen/html/search/searchdata.js | 6 +- .../docs/doxygen/html/search/typedefs_0.html | 0 .../docs/doxygen/html/search/typedefs_0.js | 4 + .../docs/doxygen/html/search/typedefs_1.html | 30 + .../docs/doxygen/html/search/typedefs_1.js} | 2 +- .../docs/doxygen/html/search/variables_0.html | 0 .../docs/doxygen/html/search/variables_0.js | 138 +- .../docs/doxygen/html/search/variables_1.html | 0 .../docs/doxygen/html/search/variables_1.js | 7 + .../doxygen/html/search/variables_10.html | 0 .../docs/doxygen/html/search/variables_10.js | 19 +- .../doxygen/html/search/variables_11.html | 0 .../docs/doxygen/html/search/variables_11.js | 39 + .../doxygen/html/search/variables_12.html | 0 .../docs/doxygen/html/search/variables_12.js | 27 +- .../doxygen/html/search/variables_13.html | 0 .../docs/doxygen/html/search/variables_13.js | 10 + .../doxygen/html/search/variables_14.html | 0 .../docs/doxygen/html/search/variables_14.js | 8 + .../doxygen/html/search/variables_15.html | 0 .../docs/doxygen/html/search/variables_15.js | 8 + .../doxygen/html/search/variables_16.html | 0 .../docs/doxygen/html/search/variables_16.js | 2 +- .../doxygen/html/search/variables_17.html | 0 .../docs/doxygen/html/search/variables_17.js | 4 +- .../docs/doxygen/html/search/variables_2.html | 0 .../docs/doxygen/html/search/variables_2.js | 13 + .../docs/doxygen/html/search/variables_3.html | 0 .../docs/doxygen/html/search/variables_3.js | 35 +- .../docs/doxygen/html/search/variables_4.html | 0 .../docs/doxygen/html/search/variables_4.js | 14 + .../docs/doxygen/html/search/variables_5.html | 0 .../docs/doxygen/html/search/variables_5.js | 6 + .../docs/doxygen/html/search/variables_6.html | 0 .../docs/doxygen/html/search/variables_6.js | 20 +- .../docs/doxygen/html/search/variables_7.html | 0 .../docs/doxygen/html/search/variables_7.js | 9 + .../docs/doxygen/html/search/variables_8.html | 0 .../docs/doxygen/html/search/variables_8.js | 8 + .../docs/doxygen/html/search/variables_9.html | 0 .../docs/doxygen/html/search/variables_9.js | 4529 ++++++++-------- .../docs/doxygen/html/search/variables_a.html | 0 .../docs/doxygen/html/search/variables_a.js | 9 + .../docs/doxygen/html/search/variables_b.html | 0 .../docs/doxygen/html/search/variables_b.js | 12 + .../docs/doxygen/html/search/variables_c.html | 0 .../docs/doxygen/html/search/variables_c.js | 4 +- .../docs/doxygen/html/search/variables_d.html | 0 .../docs/doxygen/html/search/variables_d.js | 55 +- .../docs/doxygen/html/search/variables_e.html | 0 .../docs/doxygen/html/search/variables_e.js | 27 + .../docs/doxygen/html/search/variables_f.html | 0 .../docs/doxygen/html/search/variables_f.js | 4 +- .../docs/doxygen/html/splitbar.png | Bin .../html/structCoronaSection-members.html | 0 .../doxygen/html/structCoronaSection.html | 0 .../html/structirparams__t-members.html | 0 .../docs/doxygen/html/structirparams__t.html | 0 .../html/structmatch__result__t-members.html | 0 .../doxygen/html/structmatch__result__t.html | 0 .../html/structstdAc_1_1state__t-members.html | 0 .../doxygen/html/structstdAc_1_1state__t.html | 0 .../docs/doxygen/html/sync_off.png | Bin .../docs/doxygen/html/sync_on.png | Bin .../docs/doxygen/html/tab_a.png | Bin .../docs/doxygen/html/tab_b.png | Bin .../docs/doxygen/html/tab_h.png | Bin .../docs/doxygen/html/tab_s.png | Bin .../docs/doxygen/html/tabs.css | 0 .../docs/doxygen/html/todo.html | 20 +- .../html/unionAirwellProtocol-members.html | 0 .../doxygen/html/unionAirwellProtocol.html | 0 .../html/unionAmcorProtocol-members.html | 0 .../docs/doxygen/html/unionAmcorProtocol.html | 0 .../html/unionArgoProtocol-members.html | 0 .../docs/doxygen/html/unionArgoProtocol.html | 0 .../html/unionCarrierProtocol-members.html | 0 .../doxygen/html/unionCarrierProtocol.html | 0 .../html/unionCoolixProtocol-members.html | 0 .../doxygen/html/unionCoolixProtocol.html | 0 .../html/unionCoronaProtocol-members.html | 0 .../doxygen/html/unionCoronaProtocol.html | 0 .../html/unionCoronaProtocol__coll__graph.map | 0 .../html/unionCoronaProtocol__coll__graph.md5 | 0 .../html/unionCoronaProtocol__coll__graph.png | Bin .../html/unionDaikin128Protocol-members.html | 0 .../doxygen/html/unionDaikin128Protocol.html | 0 .../html/unionDaikin152Protocol-members.html | 0 .../doxygen/html/unionDaikin152Protocol.html | 0 .../html/unionDaikin160Protocol-members.html | 0 .../doxygen/html/unionDaikin160Protocol.html | 0 .../html/unionDaikin176Protocol-members.html | 0 .../doxygen/html/unionDaikin176Protocol.html | 0 .../html/unionDaikin216Protocol-members.html | 0 .../doxygen/html/unionDaikin216Protocol.html | 0 .../html/unionDaikin2Protocol-members.html | 0 .../doxygen/html/unionDaikin2Protocol.html | 0 .../html/unionDaikin64Protocol-members.html | 0 .../doxygen/html/unionDaikin64Protocol.html | 0 .../html/unionDaikinESPProtocol-members.html | 0 .../doxygen/html/unionDaikinESPProtocol.html | 0 .../html/unionDelonghiProtocol-members.html | 0 .../doxygen/html/unionDelonghiProtocol.html | 0 .../html/unionElectraProtocol-members.html | 0 .../doxygen/html/unionElectraProtocol.html | 0 .../unionGoodweatherProtocol-members.html | 0 .../html/unionGoodweatherProtocol.html | 0 .../html/unionGreeProtocol-members.html | 0 .../docs/doxygen/html/unionGreeProtocol.html | 0 .../html/unionHaierProtocol-members.html | 0 .../docs/doxygen/html/unionHaierProtocol.html | 0 .../html/unionHaierYRW02Protocol-members.html | 0 .../doxygen/html/unionHaierYRW02Protocol.html | 0 .../html/unionHitachi1Protocol-members.html | 0 .../doxygen/html/unionHitachi1Protocol.html | 0 .../html/unionHitachi424Protocol-members.html | 0 .../doxygen/html/unionHitachi424Protocol.html | 0 .../html/unionHitachiProtocol-members.html | 0 .../doxygen/html/unionHitachiProtocol.html | 0 .../html/unionKelvinatorProtocol-members.html | 0 .../doxygen/html/unionKelvinatorProtocol.html | 0 .../doxygen/html/unionLGProtocol-members.html | 0 .../docs/doxygen/html/unionLGProtocol.html | 0 .../html/unionMideaProtocol-members.html | 0 .../docs/doxygen/html/unionMideaProtocol.html | 9 + .../unionMitsubishi112Protocol-members.html | 0 .../html/unionMitsubishi112Protocol.html | 0 .../unionMitsubishi136Protocol-members.html | 0 .../html/unionMitsubishi136Protocol.html | 0 .../unionMitsubishi144Protocol-members.html | 0 .../html/unionMitsubishi144Protocol.html | 0 .../unionMitsubishi152Protocol-members.html | 0 .../html/unionMitsubishi152Protocol.html | 0 .../unionMitsubishi88Protocol-members.html | 0 .../html/unionMitsubishi88Protocol.html | 0 .../html/unionNeoclimaProtocol-members.html | 110 + .../doxygen/html/unionNeoclimaProtocol.html | 610 +++ .../unionPanasonicAc32Protocol-members.html | 90 + .../html/unionPanasonicAc32Protocol.html | 293 ++ .../html/unionSamsungProtocol-members.html | 117 + .../doxygen/html/unionSamsungProtocol.html | 751 +++ .../html/unionSanyoProtocol-members.html | 102 + .../docs/doxygen/html/unionSanyoProtocol.html | 485 ++ .../html/unionSharpProtocol-members.html | 106 + .../docs/doxygen/html/unionSharpProtocol.html | 546 ++ .../html/unionVoltasProtocol-members.html | 0 .../doxygen/html/unionVoltasProtocol.html | 126 +- .../doxygen/html/unionmagiquest-members.html | 0 .../docs/doxygen/html/unionmagiquest.html | 0 .../docs/doxygen/html/zh-CN_8h.html | 0 .../docs/doxygen/html/zh-CN_8h_source.html | 0 .../docs/doxygen_index.md | 0 .../examples/BlynkIrRemote/BlynkIrRemote.ino | 0 .../examples/BlynkIrRemote/platformio.ini | 0 .../CommonAcControl/CommonAcControl.ino | 0 .../examples/CommonAcControl/platformio.ini | 0 .../ControlSamsungAC/ControlSamsungAC.ino | 0 .../examples/ControlSamsungAC/platformio.ini | 0 .../DumbIRRepeater/DumbIRRepeater.ino | 0 .../examples/DumbIRRepeater/platformio.ini | 0 .../examples/IRGCSendDemo/IRGCSendDemo.ino | 0 .../examples/IRGCSendDemo/platformio.ini | 0 .../examples/IRGCTCPServer/IRGCTCPServer.ino | 0 .../examples/IRGCTCPServer/platformio.ini | 0 .../examples/IRMQTTServer/IRMQTTServer.h | 1 + .../examples/IRMQTTServer/IRMQTTServer.ino | 16 +- .../examples/IRMQTTServer/platformio.ini | 0 .../examples/IRServer/IRServer.ino | 0 .../examples/IRServer/platformio.ini | 0 .../examples/IRrecvDemo/IRrecvDemo.ino | 0 .../examples/IRrecvDemo/platformio.ini | 0 .../examples/IRrecvDump/IRrecvDump.ino | 0 .../examples/IRrecvDump/platformio.ini | 0 .../examples/IRrecvDumpV2/IRrecvDumpV2.ino | 0 .../examples/IRrecvDumpV2/platformio.ini | 0 .../examples/IRrecvDumpV3/BaseOTA.h | 0 .../examples/IRrecvDumpV3/IRrecvDumpV3.ino | 0 .../examples/IRrecvDumpV3/platformio.ini | 0 .../examples/IRsendDemo/IRsendDemo.ino | 0 .../examples/IRsendDemo/platformio.ini | 0 .../IRsendProntoDemo/IRsendProntoDemo.ino | 0 .../examples/IRsendProntoDemo/platformio.ini | 0 .../JVCPanasonicSendDemo.ino | 0 .../JVCPanasonicSendDemo/platformio.ini | 0 .../examples/LGACSend/LGACSend.ino | 0 .../examples/LGACSend/platformio.ini | 0 .../SmartIRRepeater/SmartIRRepeater.ino | 0 .../examples/SmartIRRepeater/platformio.ini | 0 .../examples/TurnOnArgoAC/TurnOnArgoAC.ino | 0 .../examples/TurnOnArgoAC/platformio.ini | 0 .../TurnOnDaikinAC/TurnOnDaikinAC.ino | 0 .../examples/TurnOnDaikinAC/platformio.ini | 0 .../TurnOnFujitsuAC/TurnOnFujitsuAC.ino | 0 .../examples/TurnOnFujitsuAC/platformio.ini | 0 .../examples/TurnOnGreeAC/TurnOnGreeAC.ino | 0 .../examples/TurnOnGreeAC/platformio.ini | 0 .../TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino | 0 .../TurnOnKelvinatorAC/platformio.ini | 0 .../TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino | 0 .../TurnOnMitsubishiAC/platformio.ini | 0 .../TurnOnMitsubishiHeavyAc.ino | 0 .../TurnOnMitsubishiHeavyAc/platformio.ini | 0 .../TurnOnPanasonicAC/TurnOnPanasonicAC.ino | 0 .../examples/TurnOnPanasonicAC/platformio.ini | 0 .../TurnOnToshibaAC/TurnOnToshibaAC.ino | 0 .../examples/TurnOnToshibaAC/platformio.ini | 0 .../TurnOnTrotecAC/TurnOnTrotecAC.ino | 0 .../examples/TurnOnTrotecAC/platformio.ini | 0 .../examples/Web-AC-control/README.md | 0 .../examples/Web-AC-control/Web-AC-control.h | 0 .../Web-AC-control/Web-AC-control.ino | 0 .../examples/Web-AC-control/data/favicon.ico | Bin .../Web-AC-control/data/level_1_off.svg | 0 .../Web-AC-control/data/level_1_on.svg | 0 .../Web-AC-control/data/level_2_off.svg | 0 .../Web-AC-control/data/level_2_on.svg | 0 .../Web-AC-control/data/level_3_off.svg | 0 .../Web-AC-control/data/level_3_on.svg | 0 .../Web-AC-control/data/level_4_off.svg | 0 .../Web-AC-control/data/level_4_on.svg | 0 .../examples/Web-AC-control/data/ui.html | 0 .../examples/Web-AC-control/data/ui.js | 0 .../examples/Web-AC-control/platformio.ini | 0 .../examples/Web-AC-control/printscreen.png | Bin .../keywords.txt | 101 +- .../library.json | 2 +- .../library.properties | 2 +- .../platformio.ini | 0 .../pylintrc | 0 .../src/CPPLINT.cfg | 0 .../src/IRac.cpp | 73 + .../src/IRac.h | 6 + .../src/IRrecv.cpp | 198 +- .../src/IRrecv.h | 0 .../src/IRremoteESP8266.h | 2 +- .../src/IRsend.cpp | 0 .../src/IRsend.h | 0 .../src/IRtext.cpp | 0 .../src/IRtext.h | 0 .../src/IRtimer.cpp | 0 .../src/IRtimer.h | 0 .../src/IRutils.cpp | 15 +- .../src/IRutils.h | 3 +- .../src/i18n.h | 0 .../src/ir_Airwell.cpp | 0 .../src/ir_Airwell.h | 0 .../src/ir_Aiwa.cpp | 0 .../src/ir_Amcor.cpp | 0 .../src/ir_Amcor.h | 0 .../src/ir_Argo.cpp | 0 .../src/ir_Argo.h | 0 .../src/ir_Carrier.cpp | 0 .../src/ir_Carrier.h | 0 .../src/ir_Coolix.cpp | 0 .../src/ir_Coolix.h | 0 .../src/ir_Corona.cpp | 0 .../src/ir_Corona.h | 0 .../src/ir_Daikin.cpp | 0 .../src/ir_Daikin.h | 0 .../src/ir_Delonghi.cpp | 0 .../src/ir_Delonghi.h | 0 .../src/ir_Denon.cpp | 0 .../src/ir_Dish.cpp | 0 .../src/ir_Doshisha.cpp | 0 .../src/ir_Electra.cpp | 0 .../src/ir_Electra.h | 0 .../src/ir_EliteScreens.cpp | 8 + .../src/ir_Epson.cpp | 0 .../src/ir_Fujitsu.cpp | 0 .../src/ir_Fujitsu.h | 0 .../src/ir_GICable.cpp | 0 .../src/ir_GlobalCache.cpp | 0 .../src/ir_Goodweather.cpp | 0 .../src/ir_Goodweather.h | 0 .../src/ir_Gree.cpp | 0 .../src/ir_Gree.h | 2 + .../src/ir_Haier.cpp | 0 .../src/ir_Haier.h | 0 .../src/ir_Hitachi.cpp | 0 .../src/ir_Hitachi.h | 0 .../src/ir_Inax.cpp | 0 .../src/ir_JVC.cpp | 0 .../src/ir_Kelvinator.cpp | 0 .../src/ir_Kelvinator.h | 1 + .../src/ir_LG.cpp | 0 .../src/ir_LG.h | 0 .../src/ir_Lasertag.cpp | 2 +- .../src/ir_Lego.cpp | 0 .../src/ir_Lutron.cpp | 0 .../src/ir_MWM.cpp | 0 .../src/ir_Magiquest.cpp | 0 .../src/ir_Magiquest.h | 0 .../src/ir_Metz.cpp | 0 .../src/ir_Midea.cpp | 0 .../src/ir_Midea.h | 21 +- .../src/ir_Mirage.cpp | 0 .../src/ir_Mitsubishi.cpp | 0 .../src/ir_Mitsubishi.h | 0 .../src/ir_MitsubishiHeavy.cpp | 0 .../src/ir_MitsubishiHeavy.h | 0 .../src/ir_Multibrackets.cpp | 0 .../src/ir_NEC.cpp | 0 .../src/ir_NEC.h | 0 .../src/ir_Neoclima.cpp | 215 +- .../src/ir_Neoclima.h | 126 +- .../src/ir_Nikai.cpp | 0 .../src/ir_Panasonic.cpp | 338 +- .../src/ir_Panasonic.h | 89 +- .../src/ir_Pioneer.cpp | 0 .../src/ir_Pronto.cpp | 0 .../src/ir_RC5_RC6.cpp | 0 .../src/ir_RCMM.cpp | 0 .../src/ir_Samsung.cpp | 205 +- .../src/ir_Samsung.h | 135 +- .../src/ir_Sanyo.cpp | 138 +- .../src/ir_Sanyo.h | 110 +- .../src/ir_Sharp.cpp | 214 +- .../src/ir_Sharp.h | 124 +- .../src/ir_Sherwood.cpp | 0 .../src/ir_Sony.cpp | 0 .../src/ir_Symphony.cpp | 0 .../src/ir_Tcl.cpp | 0 .../src/ir_Tcl.h | 0 .../src/ir_Technibel.cpp | 0 .../src/ir_Technibel.h | 0 .../src/ir_Teco.cpp | 0 .../src/ir_Teco.h | 0 .../src/ir_Toshiba.cpp | 0 .../src/ir_Toshiba.h | 0 .../src/ir_Transcold.cpp | 0 .../src/ir_Transcold.h | 0 .../src/ir_Trotec.cpp | 0 .../src/ir_Trotec.h | 0 .../src/ir_Vestel.cpp | 0 .../src/ir_Vestel.h | 0 .../src/ir_Voltas.cpp | 0 .../src/ir_Voltas.h | 0 .../src/ir_Whirlpool.cpp | 0 .../src/ir_Whirlpool.h | 0 .../src/ir_Whynter.cpp | 0 .../src/ir_Zepeal.cpp | 0 .../src/locale/README.md | 0 .../src/locale/de-CH.h | 0 .../src/locale/de-DE.h | 0 .../src/locale/defaults.h | 0 .../src/locale/en-AU.h | 0 .../src/locale/en-IE.h | 0 .../src/locale/en-UK.h | 0 .../src/locale/en-US.h | 0 .../src/locale/es-ES.h | 0 .../src/locale/fr-FR.h | 0 .../src/locale/it-IT.h | 0 .../src/locale/pt-BR.h | 0 .../src/locale/zh-CN.h | 0 .../test/IRac_test.cpp | 28 +- .../test/IRrecv_test.cpp | 0 .../test/IRrecv_test.h | 0 .../test/IRsend_test.cpp | 0 .../test/IRsend_test.h | 0 .../test/IRutils_test.cpp | 0 .../test/Makefile | 0 .../test/ir_Airwell_test.cpp | 0 .../test/ir_Aiwa_test.cpp | 0 .../test/ir_Amcor_test.cpp | 0 .../test/ir_Argo_test.cpp | 0 .../test/ir_Carrier_test.cpp | 0 .../test/ir_Coolix_test.cpp | 0 .../test/ir_Corona_test.cpp | 0 .../test/ir_Daikin_test.cpp | 0 .../test/ir_Delonghi_test.cpp | 0 .../test/ir_Denon_test.cpp | 0 .../test/ir_Dish_test.cpp | 0 .../test/ir_Doshisha_test.cpp | 0 .../test/ir_Electra_test.cpp | 0 .../test/ir_EliteScreens_test.cpp | 0 .../test/ir_Epson_test.cpp | 0 .../test/ir_Fujitsu_test.cpp | 0 .../test/ir_GICable_test.cpp | 0 .../test/ir_GlobalCache_test.cpp | 0 .../test/ir_Goodweather_test.cpp | 0 .../test/ir_Gree_test.cpp | 0 .../test/ir_Haier_test.cpp | 0 .../test/ir_Hitachi_test.cpp | 0 .../test/ir_Inax_test.cpp | 0 .../test/ir_JVC_test.cpp | 0 .../test/ir_Kelvinator_test.cpp | 0 .../test/ir_LG_test.cpp | 0 .../test/ir_Lasertag_test.cpp | 0 .../test/ir_Lego_test.cpp | 0 .../test/ir_Lutron_test.cpp | 0 .../test/ir_MWM_test.cpp | 0 .../test/ir_Magiquest_test.cpp | 0 .../test/ir_Metz_test.cpp | 0 .../test/ir_Midea_test.cpp | 36 + .../test/ir_Mirage_test.cpp | 0 .../test/ir_MitsubishiHeavy_test.cpp | 0 .../test/ir_Mitsubishi_test.cpp | 0 .../test/ir_Multibrackets_test.cpp | 0 .../test/ir_NEC_test.cpp | 0 .../test/ir_Neoclima_test.cpp | 0 .../test/ir_Nikai_test.cpp | 0 .../test/ir_Panasonic_test.cpp | 565 +- .../test/ir_Pioneer_test.cpp | 0 .../test/ir_Pronto_test.cpp | 0 .../test/ir_RC5_RC6_test.cpp | 0 .../test/ir_RCMM_test.cpp | 0 .../test/ir_Samsung_test.cpp | 0 .../test/ir_Sanyo_test.cpp | 6 +- .../test/ir_Sharp_test.cpp | 0 .../test/ir_Sherwood_test.cpp | 0 .../test/ir_Sony_test.cpp | 0 .../test/ir_Symphony_test.cpp | 0 .../test/ir_Tcl_test.cpp | 0 .../test/ir_Technibel_test.cpp | 0 .../test/ir_Teco_test.cpp | 0 .../test/ir_Toshiba_test.cpp | 0 .../test/ir_Transcold_test.cpp | 0 .../test/ir_Trotec_test.cpp | 0 .../test/ir_Vestel_test.cpp | 0 .../test/ir_Voltas_test.cpp | 0 .../test/ir_Whirlpool_test.cpp | 0 .../test/ir_Whynter_test.cpp | 0 .../test/ir_Zepeal_test.cpp | 0 .../tools/Makefile | 0 .../tools/RawToGlobalCache.sh | 0 .../tools/auto_analyse_raw_data.py | 0 .../tools/auto_analyse_raw_data_test.py | 0 .../tools/gc_decode.cpp | 0 .../tools/generate_irtext_h.sh | 0 .../tools/mkkeywords | 0 .../tools/mode2_decode.cpp | 0 .../tools/raw_to_pronto_code.py | 0 .../tools/raw_to_pronto_code_test.py | 0 .../tools/scrape_supported_devices.py | 0 1639 files changed, 18048 insertions(+), 13683 deletions(-) delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.map delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.png delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.map delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.md5 delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.png delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.map delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.md5 delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.png delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_10.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_15.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_17.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_1a.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_1b.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_4.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_5.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_8.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_9.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_c.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/all_d.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_0.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_1.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_2.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_3.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_4.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_5.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_6.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_7.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_8.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_9.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_a.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_b.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/classes_c.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/enums_5.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/enums_7.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_0.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_1.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_2.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_3.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_4.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_5.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/files_6.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_0.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_1.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_15.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_17.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_4.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_a.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_b.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_d.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/functions_f.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/namespaces_0.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/namespaces_1.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/pages_0.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/pages_1.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/pages_2.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_1.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_11.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_13.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_14.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_15.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_2.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_4.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_5.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_7.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_8.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_a.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_b.js delete mode 100644 lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/search/variables_e.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.github/CONTRIBUTING.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.github/Contributors.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.github/issue_template.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.gitignore (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.gitmodules (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.style.yapf (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/.travis.yml (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/CPPLINT.cfg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/Doxyfile (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/LICENSE.txt (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/README.md (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/README_de.md (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/README_fr.md (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/ReleaseNotes.md (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/SupportedProtocols.md (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/README.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/README_de.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/README_fr.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/_config.yml (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRac_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRac_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRac_8h_source.html (94%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRrecv_8cpp.html rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRrecv_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRrecv_8h_source.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRremoteESP8266_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRremoteESP8266_8h_source.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRsend_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRsend_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRsend_8h_source.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRtext_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRtext_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRtext_8h_source.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRtimer_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRtimer_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRtimer_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRutils_8cpp.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRutils_8h.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/IRutils_8h_source.html (91%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/README_8md.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/annotated.html (80%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/bc_s.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/bdwn.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAirwellAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAirwellAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAirwellAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAirwellAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAirwellAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAmcorAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAmcorAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAmcorAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAmcorAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRAmcorAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRArgoAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRArgoAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRArgoAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRArgoAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRArgoAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCarrierAc64-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCarrierAc64.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCarrierAc64__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCarrierAc64__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCarrierAc64__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoolixAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoolixAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoolixAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoolixAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoolixAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoronaAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoronaAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoronaAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoronaAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRCoronaAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin128-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin128.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin128__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin128__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin128__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin152-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin152.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin152__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin152__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin152__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin160-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin160.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin160__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin160__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin160__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin176-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin176.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin176__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin176__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin176__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin2-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin2.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin216-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin216.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin216__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin216__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin216__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin2__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin2__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin2__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin64-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin64.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin64__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin64__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikin64__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikinESP-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikinESP.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikinESP__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikinESP__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDaikinESP__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDelonghiAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDelonghiAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDelonghiAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDelonghiAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRDelonghiAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRElectraAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRElectraAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRElectraAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRElectraAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRElectraAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRFujitsuAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRFujitsuAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRFujitsuAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRFujitsuAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRFujitsuAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGoodweatherAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGoodweatherAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGoodweatherAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGoodweatherAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGoodweatherAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGreeAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGreeAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGreeAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGreeAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRGreeAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierACYRW02-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierACYRW02.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierACYRW02__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierACYRW02__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierACYRW02__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHaierAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc1-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc1.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc1__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc1__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc1__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc3-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc3.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344__inherit__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344__inherit__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc344__inherit__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc3__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc3__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc3__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424__inherit__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424__inherit__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc424__inherit__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRHitachiAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRKelvinatorAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRKelvinatorAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRKelvinatorAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRKelvinatorAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRKelvinatorAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRLgAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRLgAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRLgAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRLgAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRLgAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMideaAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMideaAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMideaAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMideaAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMideaAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi112-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi112.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi112__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi112__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi112__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi136-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi136.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi136__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi136__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishi136__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy152Ac-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy152Ac.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy88Ac-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy88Ac.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRNeoclimaAc-members.html (67%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRNeoclimaAc.html (85%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRPanasonicAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRPanasonicAc.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRPanasonicAc32-members.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRPanasonicAc32.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRPanasonicAc32__coll__graph.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRPanasonicAc32__coll__graph.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRPanasonicAc32__coll__graph.png rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRPanasonicAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRPanasonicAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRPanasonicAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRSamsungAc-members.html (68%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRSamsungAc.html (88%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSamsungAc__coll__graph.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSamsungAc__coll__graph.png rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRSanyoAc-members.html (66%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRSanyoAc.html (83%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSanyoAc__coll__graph.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSanyoAc__coll__graph.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSanyoAc__coll__graph.png rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRSharpAc-members.html (65%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRSharpAc.html (86%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSharpAc__coll__graph.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSharpAc__coll__graph.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/classIRSharpAc__coll__graph.png rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTcl112Ac-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTcl112Ac.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTcl112Ac__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTcl112Ac__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTcl112Ac__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTechnibelAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTechnibelAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTechnibelAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTechnibelAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTechnibelAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTecoAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTecoAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTecoAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTecoAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTecoAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRToshibaAC-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRToshibaAC.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRToshibaAC__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRToshibaAC__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRToshibaAC__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTranscoldAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTranscoldAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTranscoldAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTranscoldAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTranscoldAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTrotecESP-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTrotecESP.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTrotecESP__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTrotecESP__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRTrotecESP__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVestelAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVestelAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVestelAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVestelAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVestelAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVoltas-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVoltas.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVoltas__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVoltas__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRVoltas__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRWhirlpoolAc-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRWhirlpoolAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRac-members.html (78%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRac.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRac__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRac__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRac__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRrecv-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRrecv.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRrecv__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRrecv__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRrecv__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRsend-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRsend.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRtimer-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classIRtimer.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classTimerMs-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classTimerMs.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classdecode__results-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classdecode__results.html (91%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/classes.html (88%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/closed.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/de-CH_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/de-CH_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/de-DE_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/de-DE_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/defaults_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/defaults_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/deprecated.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/dir_49e56c817e5e54854c35e136979f97ca.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/dir_84fe998d1eb06414cc389ad334e77e63.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/doc.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/doxygen.css (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/doxygen.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/doxygen__index_8md.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/dynsections.js (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-AU_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-AU_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-IE_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-IE_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-UK_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-UK_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-US_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/en-US_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/es-ES_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/es-ES_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/files.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/folderclosed.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/folderopen.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/fr-FR_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/fr-FR_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions.html (87%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_a.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_b.html (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_c.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_d.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_e.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_f.html (91%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func.html (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_a.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_b.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_c.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_d.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_e.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_f.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_g.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_i.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_k.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_l.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_m.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_n.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_o.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_p.html (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_r.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_s.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_t.html (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_u.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_v.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_w.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_func_~.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_g.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_h.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_i.html (95%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_k.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_l.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_m.html (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_n.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_o.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_p.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_q.html (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_r.html (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_rela.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_s.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_t.html (92%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_u.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_v.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars.html (87%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_a.html (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_b.html (90%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_c.html (92%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_d.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_e.html (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_f.html (90%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_h.html (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_i.html (91%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_l.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_m.html (92%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_n.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_o.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_p.html (90%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_q.html (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_r.html (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_s.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_t.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_u.html (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_v.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_w.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_x.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_vars_z.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_w.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_x.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_z.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/functions_~.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_a.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_c.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_d.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_e.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_enum.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_eval.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_f.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_func.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_g.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_h.html (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_i.html (87%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_j.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_k.html (95%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_l.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_m.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_n.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_p.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_r.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_s.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_t.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_type.html (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_u.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_v.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_vars.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_vars_i.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_vars_k.html (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_w.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_x.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_y.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/globals_z.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/graph_legend.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/graph_legend.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/graph_legend.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/hierarchy.html (80%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/i18n_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/i18n_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/index.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_0.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_0.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_0.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_1.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_1.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_1.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_10.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_10.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_10.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_11.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_11.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_11.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_12.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_12.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_12.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_13.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_13.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_13.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_14.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_14.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_14.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_15.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_15.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_15.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_16.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_16.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_16.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_17.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_17.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_17.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_18.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_18.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_18.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_19.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_19.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_19.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_2.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_2.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_2.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_20.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_20.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_20.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_21.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_21.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_21.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_22.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_22.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_22.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_23.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_23.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_23.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_24.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_24.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_24.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_25.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_25.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_25.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_26.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_26.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_26.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_27.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_27.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_27.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_28.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_28.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_28.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_29.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_29.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_29.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_3.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_3.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_3.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_30.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_30.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_30.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_31.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_31.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_31.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_32.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_32.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_32.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_33.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_33.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_33.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_34.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_34.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_34.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_35.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_35.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_35.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_36.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_36.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_36.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_37.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_37.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_37.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_38.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_38.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_38.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_39.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_39.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_39.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_4.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_4.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_4.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_40.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_40.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_40.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_41.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_41.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_41.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_42.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_42.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_42.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_43.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_43.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_43.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_44.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_44.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_44.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_45.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_45.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_45.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_46.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_46.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_46.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_47.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_47.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_47.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_48.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_48.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_48.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_49.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_49.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_49.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_5.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_5.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_5.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_50.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_50.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_50.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_51.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_51.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_51.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_52.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_52.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_52.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_53.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_53.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_53.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_54.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_54.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_54.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_55.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_55.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_55.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_56.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_56.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_56.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_57.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_57.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_57.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_58.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_58.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_58.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_59.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_59.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_59.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_6.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_6.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_6.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_60.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_60.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_60.png (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_61.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_61.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_61.png rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_61.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_62.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_61.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_62.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_61.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_62.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_62.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_63.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_62.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_63.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_62.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_63.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_63.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_64.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_63.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_64.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_63.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_64.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_64.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_65.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_64.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_65.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_64.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_65.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_65.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_66.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_65.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_66.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_65.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_66.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_66.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_67.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_66.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_67.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_66.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_67.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_67.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_68.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_67.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_68.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_67.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_68.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_68.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_69.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_68.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_69.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_68.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_69.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_7.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_7.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_7.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_69.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_70.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_69.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_70.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_69.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_70.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_70.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_71.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_70.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_71.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_70.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_71.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_71.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_72.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_71.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_72.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_71.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_72.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_72.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_73.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_72.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_73.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_72.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_73.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_73.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_74.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_73.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_74.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_73.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_74.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_74.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_75.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_74.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_75.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_74.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_75.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_75.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_76.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_75.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_76.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_75.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_76.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_76.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_77.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_76.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_77.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_76.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_77.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_77.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_78.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_77.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_78.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_77.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_78.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_78.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_79.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_78.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_79.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_78.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_79.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_8.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_8.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_8.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_79.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_80.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_79.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_80.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_79.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_80.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_80.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_81.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_80.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_81.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_80.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_81.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_81.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_82.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_81.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_82.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_81.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_82.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_82.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_83.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_82.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_83.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_82.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_83.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_83.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_84.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_83.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_84.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_83.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_84.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_84.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_85.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_84.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_85.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_84.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_85.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_85.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_86.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_85.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_86.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_85.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_86.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_86.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_87.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_86.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_87.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_86.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_87.png} (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_88.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_88.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_88.png create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_89.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_89.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_89.png rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_9.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_9.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherit_graph_9.png (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_90.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_90.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_90.png create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_91.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_91.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_91.png create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_92.map create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_92.md5 create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_92.png rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_87.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_93.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_87.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_93.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_87.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_93.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_88.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_94.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_88.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_94.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_88.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_94.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_89.map => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_95.map} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_89.md5 => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_95.md5} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/inherit_graph_89.png => IRremoteESP8266-2.7.14/docs/doxygen/html/inherit_graph_95.png} (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/inherits.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Airwell_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Airwell_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Airwell_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Aiwa_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Amcor_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Amcor_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Amcor_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Argo_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Argo_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Argo_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Carrier_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Carrier_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Carrier_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Coolix_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Coolix_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Coolix_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Corona_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Corona_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Corona_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Daikin_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Daikin_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Daikin_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Delonghi_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Delonghi_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Delonghi_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Denon_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Dish_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Doshisha_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Electra_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Electra_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Electra_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__EliteScreens_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Epson_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Fujitsu_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Fujitsu_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Fujitsu_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__GICable_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__GlobalCache_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Goodweather_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Goodweather_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Goodweather_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Gree_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Gree_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Gree_8h_source.html (83%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Haier_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Haier_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Haier_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Hitachi_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Hitachi_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Hitachi_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Inax_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__JVC_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Kelvinator_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Kelvinator_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Kelvinator_8h_source.html (82%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__LG_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__LG_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__LG_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Lasertag_8cpp.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Lego_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Lutron_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__MWM_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Magiquest_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Magiquest_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Magiquest_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Metz_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Midea_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Midea_8h.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Midea_8h_source.html (80%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Mirage_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__MitsubishiHeavy_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__MitsubishiHeavy_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__MitsubishiHeavy_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Mitsubishi_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Mitsubishi_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Mitsubishi_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Multibrackets_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__NEC_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__NEC_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__NEC_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Neoclima_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Neoclima_8h.html (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Neoclima_8h_source.html (56%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Nikai_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Panasonic_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Panasonic_8h.html (78%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Panasonic_8h_source.html (69%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Pioneer_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Pronto_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__RC5__RC6_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__RCMM_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Samsung_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Samsung_8h.html (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Samsung_8h_source.html (55%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sanyo_8cpp.html (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sanyo_8h.html (54%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sanyo_8h_source.html (57%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sharp_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sharp_8h.html (67%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sharp_8h_source.html (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sherwood_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Sony_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Symphony_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Tcl_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Tcl_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Tcl_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Technibel_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Technibel_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Technibel_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Teco_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Teco_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Teco_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Toshiba_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Toshiba_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Toshiba_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Transcold_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Transcold_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Transcold_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Trotec_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Trotec_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Trotec_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Vestel_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Vestel_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Vestel_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Voltas_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Voltas_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Voltas_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Whirlpool_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Whirlpool_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Whirlpool_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Whynter_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/ir__Zepeal_8cpp.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/it-IT_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/it-IT_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/jquery.js (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/md_src_locale_README.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/menu.js (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/menudata.js (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespaceIRAcUtils.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/IRrecv_8cpp.html => IRremoteESP8266-2.7.14/docs/doxygen/html/namespace__IRrecv.html} (69%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespaceirutils.html (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespacemembers.html (90%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespacemembers_enum.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespacemembers_func.html (98%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/namespacemembers_vars.html rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespaces.html (77%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/namespacestdAc.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/nav_f.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/nav_g.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/nav_h.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/open.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/pages.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/pt-BR_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/pt-BR_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_0.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_0.js (81%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_1.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_1.js (92%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_10.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_10.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_11.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_11.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_12.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_12.js (65%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_13.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_13.js (67%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_14.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_14.js (68%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_15.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_15.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_16.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_16.js (85%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_17.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_17.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_18.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_18.js (78%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_19.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_19.js (54%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_1a.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_1a.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_1b.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_1b.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_2.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_2.js (68%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_3.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_3.js (72%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_4.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_4.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_5.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_5.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_6.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_6.js (67%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_7.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_7.js (69%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_8.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_8.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_9.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_9.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_a.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_a.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_b.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_b.js (52%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_c.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_c.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_d.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/all_d.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_e.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_e.js (57%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_f.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/all_f.js (83%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_0.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_0.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_1.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_1.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_2.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_2.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_3.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_3.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_4.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_4.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_5.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_5.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_6.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_6.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_7.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_7.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_8.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_8.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_9.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_9.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_a.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_a.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_b.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_b.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/classes_c.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_c.js create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_d.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_d.js create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_e.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/classes_e.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/close.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_0.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_0.js (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_1.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_1.js (53%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_2.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_2.js (59%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_3.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_3.js (61%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_4.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_4.js (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_5.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/enums_5.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_6.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_6.js (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_7.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/enums_7.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_8.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_8.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_9.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enums_9.js (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_0.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_0.js (54%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_1.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_1.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_10.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_10.js (59%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_11.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_11.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_12.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_12.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_13.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_13.js (61%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_14.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_14.js (54%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_15.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_15.js (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_2.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_2.js (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_3.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_3.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_4.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_4.js (64%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_5.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_5.js (59%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_6.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_6.js (61%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_7.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_7.js (61%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_8.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_8.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_9.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_9.js (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_a.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_a.js (57%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_b.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_b.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_c.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_c.js (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_d.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_d.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_e.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_e.js (57%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_f.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/enumvalues_f.js (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_0.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_0.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_1.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_1.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_2.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_2.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_3.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_3.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_4.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_4.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_5.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_5.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/files_6.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/files_6.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_0.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_0.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_1.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_1.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_10.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_10.js (75%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_11.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_11.js (71%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_12.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_12.js (68%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_13.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_13.js (63%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_14.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_14.js (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_15.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_15.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_16.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_16.js (82%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_17.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_17.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_2.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_2.js (67%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_3.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_3.js (75%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_4.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_4.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_5.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_5.js (52%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_6.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_6.js (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_7.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_7.js (69%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_8.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_8.js (52%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_9.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_9.js (54%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_a.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_a.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_b.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_b.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_c.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_c.js (58%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_d.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_d.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_e.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_e.js (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/functions_f.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/functions_f.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/mag_sel.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/namespaces_0.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/namespaces_0.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/namespaces_1.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/namespaces_1.js create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/namespaces_2.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/namespaces_2.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/nomatches.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/pages_0.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/pages_0.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/pages_1.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/pages_1.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/pages_2.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/pages_2.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/related_0.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/related_0.js (57%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/search.css (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/search.js (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/search_l.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/search_m.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/search_r.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/searchdata.js (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/typedefs_0.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/typedefs_0.js create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/typedefs_1.html rename lib/lib_basic/{IRremoteESP8266-2.7.13/docs/doxygen/html/search/typedefs_0.js => IRremoteESP8266-2.7.14/docs/doxygen/html/search/typedefs_1.js} (53%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_0.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_0.js (71%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_1.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_1.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_10.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_10.js (64%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_11.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_11.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_12.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_12.js (65%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_13.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_13.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_14.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_14.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_15.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_15.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_16.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_16.js (72%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_17.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_17.js (52%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_2.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_2.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_3.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_3.js (51%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_4.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_4.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_5.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_5.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_6.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_6.js (70%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_7.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_7.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_8.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_8.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_9.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_9.js (52%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_a.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_a.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_b.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_b.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_c.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_c.js (62%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_d.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_d.js (69%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_e.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/search/variables_e.js rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_f.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/search/variables_f.js (60%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/splitbar.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structCoronaSection-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structCoronaSection.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structirparams__t-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structirparams__t.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structmatch__result__t-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structmatch__result__t.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structstdAc_1_1state__t-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/structstdAc_1_1state__t.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/sync_off.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/sync_on.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/tab_a.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/tab_b.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/tab_h.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/tab_s.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/tabs.css (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/todo.html (89%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionAirwellProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionAirwellProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionAmcorProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionAmcorProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionArgoProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionArgoProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCarrierProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCarrierProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoolixProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoolixProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoronaProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoronaProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoronaProtocol__coll__graph.map (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoronaProtocol__coll__graph.md5 (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionCoronaProtocol__coll__graph.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin128Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin128Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin152Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin152Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin160Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin160Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin176Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin176Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin216Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin216Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin2Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin2Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin64Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikin64Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikinESPProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDaikinESPProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDelonghiProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionDelonghiProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionElectraProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionElectraProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionGoodweatherProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionGoodweatherProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionGreeProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionGreeProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHaierProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHaierProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHaierYRW02Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHaierYRW02Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHitachi1Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHitachi1Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHitachi424Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHitachi424Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHitachiProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionHitachiProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionKelvinatorProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionKelvinatorProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionLGProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionLGProtocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMideaProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMideaProtocol.html (93%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi112Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi112Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi136Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi136Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi144Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi144Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi152Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi152Protocol.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi88Protocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionMitsubishi88Protocol.html (100%) create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionNeoclimaProtocol-members.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionNeoclimaProtocol.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionPanasonicAc32Protocol-members.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionPanasonicAc32Protocol.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionSamsungProtocol-members.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionSamsungProtocol.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionSanyoProtocol-members.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionSanyoProtocol.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionSharpProtocol-members.html create mode 100644 lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/unionSharpProtocol.html rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionVoltasProtocol-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionVoltasProtocol.html (85%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionmagiquest-members.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/unionmagiquest.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/zh-CN_8h.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen/html/zh-CN_8h_source.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/docs/doxygen_index.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/BlynkIrRemote/BlynkIrRemote.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/BlynkIrRemote/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/CommonAcControl/CommonAcControl.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/CommonAcControl/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/ControlSamsungAC/ControlSamsungAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/ControlSamsungAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/DumbIRRepeater/DumbIRRepeater.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/DumbIRRepeater/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRGCSendDemo/IRGCSendDemo.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRGCSendDemo/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRGCTCPServer/IRGCTCPServer.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRGCTCPServer/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRMQTTServer/IRMQTTServer.h (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRMQTTServer/IRMQTTServer.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRMQTTServer/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRServer/IRServer.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRServer/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDemo/IRrecvDemo.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDemo/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDump/IRrecvDump.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDump/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDumpV2/IRrecvDumpV2.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDumpV2/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDumpV3/BaseOTA.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDumpV3/IRrecvDumpV3.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRrecvDumpV3/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRsendDemo/IRsendDemo.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRsendDemo/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRsendProntoDemo/IRsendProntoDemo.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/IRsendProntoDemo/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/JVCPanasonicSendDemo/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/LGACSend/LGACSend.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/LGACSend/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/SmartIRRepeater/SmartIRRepeater.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/SmartIRRepeater/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnArgoAC/TurnOnArgoAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnArgoAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnDaikinAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnFujitsuAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnGreeAC/TurnOnGreeAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnGreeAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnKelvinatorAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnMitsubishiAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnMitsubishiHeavyAc/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnPanasonicAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnToshibaAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/TurnOnTrotecAC/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/README.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/Web-AC-control.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/Web-AC-control.ino (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/favicon.ico (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_1_off.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_1_on.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_2_off.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_2_on.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_3_off.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_3_on.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_4_off.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/level_4_on.svg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/ui.html (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/data/ui.js (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/examples/Web-AC-control/printscreen.png (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/keywords.txt (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/library.json (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/library.properties (96%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/platformio.ini (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/pylintrc (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/CPPLINT.cfg (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRac.cpp (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRac.h (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRrecv.cpp (92%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRrecv.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRremoteESP8266.h (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRsend.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRsend.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRtext.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRtext.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRtimer.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRtimer.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRutils.cpp (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/IRutils.h (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/i18n.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Airwell.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Airwell.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Aiwa.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Amcor.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Amcor.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Argo.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Argo.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Carrier.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Carrier.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Coolix.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Coolix.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Corona.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Corona.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Daikin.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Daikin.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Delonghi.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Delonghi.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Denon.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Dish.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Doshisha.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Electra.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Electra.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_EliteScreens.cpp (94%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Epson.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Fujitsu.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Fujitsu.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_GICable.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_GlobalCache.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Goodweather.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Goodweather.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Gree.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Gree.h (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Haier.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Haier.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Hitachi.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Hitachi.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Inax.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_JVC.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Kelvinator.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Kelvinator.h (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_LG.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_LG.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Lasertag.cpp (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Lego.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Lutron.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_MWM.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Magiquest.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Magiquest.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Metz.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Midea.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Midea.h (87%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Mirage.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Mitsubishi.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Mitsubishi.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_MitsubishiHeavy.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_MitsubishiHeavy.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Multibrackets.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_NEC.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_NEC.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Neoclima.cpp (77%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Neoclima.h (69%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Nikai.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Panasonic.cpp (78%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Panasonic.h (70%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Pioneer.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Pronto.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_RC5_RC6.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_RCMM.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Samsung.cpp (83%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Samsung.h (71%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Sanyo.cpp (86%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Sanyo.h (65%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Sharp.cpp (84%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Sharp.h (74%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Sherwood.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Sony.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Symphony.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Tcl.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Tcl.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Technibel.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Technibel.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Teco.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Teco.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Toshiba.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Toshiba.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Transcold.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Transcold.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Trotec.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Trotec.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Vestel.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Vestel.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Voltas.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Voltas.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Whirlpool.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Whirlpool.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Whynter.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/ir_Zepeal.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/README.md (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/de-CH.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/de-DE.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/defaults.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/en-AU.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/en-IE.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/en-UK.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/en-US.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/es-ES.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/fr-FR.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/it-IT.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/pt-BR.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/src/locale/zh-CN.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/IRac_test.cpp (98%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/IRrecv_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/IRrecv_test.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/IRsend_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/IRsend_test.h (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/IRutils_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/Makefile (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Airwell_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Aiwa_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Amcor_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Argo_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Carrier_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Coolix_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Corona_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Daikin_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Delonghi_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Denon_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Dish_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Doshisha_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Electra_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_EliteScreens_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Epson_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Fujitsu_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_GICable_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_GlobalCache_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Goodweather_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Gree_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Haier_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Hitachi_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Inax_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_JVC_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Kelvinator_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_LG_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Lasertag_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Lego_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Lutron_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_MWM_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Magiquest_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Metz_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Midea_test.cpp (97%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Mirage_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_MitsubishiHeavy_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Mitsubishi_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Multibrackets_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_NEC_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Neoclima_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Nikai_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Panasonic_test.cpp (80%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Pioneer_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Pronto_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_RC5_RC6_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_RCMM_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Samsung_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Sanyo_test.cpp (99%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Sharp_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Sherwood_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Sony_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Symphony_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Tcl_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Technibel_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Teco_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Toshiba_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Transcold_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Trotec_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Vestel_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Voltas_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Whirlpool_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Whynter_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/test/ir_Zepeal_test.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/Makefile (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/RawToGlobalCache.sh (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/auto_analyse_raw_data.py (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/auto_analyse_raw_data_test.py (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/gc_decode.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/generate_irtext_h.sh (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/mkkeywords (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/mode2_decode.cpp (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/raw_to_pronto_code.py (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/raw_to_pronto_code_test.py (100%) rename lib/lib_basic/{IRremoteESP8266-2.7.13 => IRremoteESP8266-2.7.14}/tools/scrape_supported_devices.py (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1836bee70..b5176046c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - Command ``SetOption119 1`` to remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic (#10355) - Command ``RuleTimer0`` to access all RuleTimers at once (#10352) - SPI display driver SSD1331 Color oled by Jeroen Vermeulen (#10376) +- IRremoteESP8266 library from v2.7.13 to v2.7.14 ### Breaking Changed - Replaced MFRC522 13.56MHz rfid card reader GPIO selection from ``SPI CS`` by ``RC522 CS`` diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map deleted file mode 100644 index 57358d833..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 deleted file mode 100644 index fe697a810..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 +++ /dev/null @@ -1 +0,0 @@ -1e6ee18f808b645d10f6652b3a78aca2 \ No newline at end of file diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png deleted file mode 100644 index 9515ee73a64712d49d10e556d7f305e6ba48bf2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3405 zcmZu!cQhRB8Xt9cwUA)-nh2sLL|r7TPLzmlk*HsY5~BA`5G{xvEkunF5}j3}C3@M7 zs2{t!AXs;DzjNOD}SreL7}0DxLU9ccir0pJ-7B?o8W zxKdhhA%Co;h6FDE90jdqsbD0r2J*h4PYyoUUz>iKqp!XDA&RwSg{W_4g{zHD5=JfwCyp-Y$g$`U!y&R}elGHa2B$PM znVq}4%^um8>RSJ8PKz?jPRQU$Q_g{gq|Mq_+-dFwE+x_&<+j!f&z&I>i-?4k zQSs&6$#ffZqy5~Ke#@A`a+Oy{MJ2M}$X&^*fgiiVXHr*vX>M@Ps^;Q}1IhuH73 zyTk0^;UV-|CXuAi-ObAj9Y#jEdvT17XDW2r>!-|*!Qq@~mBhrvLOyHak1Ja|Hnb0X@NV>3|b4 z5sRjf=I84?+}uR=^;y`pdDnIo4Gq}u-@jj_q=ZRf15!EZv>rU@eaS37HaiBKkIBwvJ;i^*_O=@9>Rutb z=jZQ#>cy8DtA71z(Ale3wEJkd)$VF|csMDb|9-N#zCIP;$`G;qIkdI82?f4kvB6ju zo`{5xI&tRfZdFE<%@&DXTT`93cZdLD5)yqQqo|e^L_~D-a@8kHSNX#-0I;;Q1OO{5 zD?-;O2E#F3ZK>?-Epw1d27~bEPcw9_m|Yv z(sJKkkipH=gdF=6_mlfuhJxvj=In)?&7=VzKR+HRDL5L9Zt^|g3%WQm4%qF4Y~XM`{rymFzH3zE zBwy{t&o3_O0!}@OOH1Dt6_NP0a`Yu}swpWEzf@h8-=d(P=t{Yv^(s9*l0XQ0XDCQd zPY)d%Ebm^6B>Y(!#dAy$$q=^skNN z#%E?S`S|+U9Bodj>*z$**B=BRcyC($2{E;SFl>U&wr7?t7YnP&SJV+4tj92@av2xV>3 zvE0e!%}9U69%=RhB_9Vo7Y?_BD1N%rv9!P~o9H1MF-?Uz+Rk)JyVsl#%V*peVR36% z$1EN-pm;qUsELu+McyuOFr;j?sv=HDvlzETycYrBD^au>UAfT4%(+<;ajA#EN5Mwf4pBd_R*qM(PRV*qda4GS!r@ zU!W0~wR>he{#J!wSeQZXWwiYq7Lg?gDjb@|M$=mDkCGh^;4Oc5MN-ziz?%t~H&StM zaLjyi&3Cze#DH*};JtVDE511J46T8`#>}kI=!zW?jgE+*<>ch_INZ>`BP**pk|(dl z#?C&F%&QjDY0U+K;JTDl23CQaJG7^#hc;bPr5e?$i3z?8yvo9&3Bvp`h(I8$%+x)x z_3_E1XJDWc6%~CfnGNHP5VHK7cKybUWUUO52@Tr(<9sOHl2;c{KS~ zL+0J5Q^i}SPYtl<-#8`8MdiB6pynEzLlL@kjVTiugV{H6+^Xbv^#l+S!;nHJg>w&3 z9)gbo&Tiek`>5q!6_9QzJFMp$@tx{_%1@!FU(p$BkT7EtL!9nCBy!6&hCR&j|HooD z><+q_CptcR4*nl5;et-A^xjW8K6}Q<%h)+Kous3*ktPw#7VG8vYt~_DechpX{}*hT zA~FofoDz*)euDgYlDXk-at1QD_XcUx@-<>7er_ z^zXw%Pk#Eia_G}<&WoQJ+}+*7CK?<@Il%CE=XfRS23~}K01SNW$?1AN9ULC5t8f}I zYW#vS78zF4PGGUGpEa{Vq|hq4{pcX->Fs@dNw^4`ayiPnIWjV$uCCqz+EIZ)IW5zP z0}p$ac2sY#>crF(X0QJa6BUSAGzcm&1mflC!8-5Fn-B~J1BBc%uC@kU&C%5r0w9q{ zu3NV#LCgX`D=LXy?nOa!GqbX?vPq*e^Br;V+fRC5x_jB#+H#4ABqptbmZNH7!Zea2 zLsDV@b9HsCG_5BG{Z>^)h3wEz9@N`CjQ`G_%seQwV{>y9iOWCm_=K4mla{?+Rz{h{ zxw*L?OG}}kVZv+LehYs7{8>mLW1t6NS{Xzm#gcHc*T>oE&IX#W@F3`RuU@~7%9Zo( zvd%o=Yz_MTci9FWkM2!i)kmRdf`fzU85w_0rJ8aE9@0fcMd_KD#ktHk7Phx@g8pz$ z04LCd`2_^-o0>BJvGx6xfwRQ+@^YA|sp-j5G^dy=2C=fX_O`4HBImu`)95lkwy^LL ztY5qjD+`OBv2k>gB7q5Vg##HF*oyWydi2OS=)1W@-L}gV~ z^8NjNu8bk!L5VkYa%Q6K=le~^J6l`fVDo{)ES^*US1wQFRAMi;Ty zL-MKn`}fq#`GEl#2vJ7M_o=C=Dw62#=qpclFs&PZ|J|9u`XrSx-*=60bldvS@}|7_VvtgQPfI1bZTXPb;zVWNPeoy zJi4}4tf{G~;KPTMoo_Jicje`s+lyc5XlXlkrZJdA%P%kP^QCt7_4QTUrreiXSX^Wu z7#NtTcetXergn3IPhOt==;-KNpZcX89QDB#rm3k}VD#Qbg2jF9D>I16$F{bl&)2?o zg1u|4`?6{q<>mg6C>=BNfcIWJT(s9AKQIbR;)#zB)8yo&qmxserd)z5FO(Z>Rl|#l zcnK%VR}2jecUN6pTmWlsRzOKf2_!f;Dmm({Nkn5~W5rk!-c?oQ)-Fs>!$n&UuU1>N zKdWmiC;&iP=pP;J1Mykw^qmisBWYP#VnE@1R~gLLda~k?x~^{Da+2b+WS*?vqB_S~(=yJHXci+!XcB;lI38d{G$%=UoPjBT;DSIP5m8ZZ zD=G#zZzpBP=%G-FD=W4y{3m)r#na=b_gPIh7MiLreDuEp{g0AvOTP{(TYtmcINX#h z$x_NP-i3UaV3G(Qv|e}n&mIWCaJ&$A+vS9FN+~w=P2#nW;QtYzq4EG(tz;ecFPxZV A2><{9 diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.map b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.map deleted file mode 100644 index 7b65cd5e6..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.map +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 deleted file mode 100644 index c11ced0ba..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 +++ /dev/null @@ -1 +0,0 @@ -383f10b4ef1888fea2358fde261598f6 \ No newline at end of file diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.png b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSamsungAc__coll__graph.png deleted file mode 100644 index 9ce17f8b0db4b36a22dca1acb89858aca964d6ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3730 zcmZ9Pc{o(>`^QHM5-k)VCXqdR$(G6>WH%W5mVF3e?4+_ZgBXJhLqea7CHodpWMm6t zU$XD}zJH&tPrvK?y?)oZ&bhDi$2re^?)%*D*ZYak(om+OVWELQAap8^VLBlCfHR1i z5?p^~AoW0?v{F-sK~DZ0XR~D=9Wc|I{=q8-qVqorLNNRi?WH zOFc*Runn?d!B}7cYh&&>QkPY$Mzz^-NWN) zj%F!mMa1Uj^NO5BcbK9g$%x>qp%3|Fb2d#Cgh?+g9i10S8R)3L5@Z#Vw>^)@Z-hLBk`?-aSa`w|oyoshs} zl#7drx#TiZ%{O&$a8P9b>*kBlP&Y5Hte}(Q>r(EpW?>;AZZ57fc6N6D0RjDGt^`>O zk|#RXCbaHrBZl>ty~G(x%2Us_=Hc}8^tVy(SX8y87%1cU*BRlevH0JUNGtkB@_!`*qof@0%=+o!MFY#l^*@_I4gl&QLZP zucm?NAaqQ`7r&jzQhiC^P5aAG=%_PW3?nNm>)WIxzNv*R-?7@%m(iNrQ&1VNCy?>B6d9zW zfsM_Fa5UOkH)(sdkBy{0Guhdx^GHDfQR>XBlyMp2>guYatD7X_Eff+GQhl^NcnCfd zVp1E(7JNTo|1py*4u?Bj`vDy)cT*UsO-@eU>>n9n53a0~ra6D!?fG+O+{(m6SAXl$ zr9ZtXudFQeT+q)mt!gYq4u06|=+L^rCjEVHW9Hn23%0wfW7lXYtE;OE3JTJQL|P75 z(Jcvy&GaoF6iUn3Sk1xVA8c0df=niot<_q9`9TgjHYVnQySo@29o=;~U+mfQj4=d4 z`_aLUC<~^WOtutDTHV~_5)?%Lqnqsxx zy_bg`=J&>7v0MrQgYDM0nJs#V2$0PElS28kE;D;G9@)4nADfft_A`fq4ZaUn{|`DeJiUW}g1%FHC0 zJ{6yjswG<1l~aj(I78d6eYwxwPQ&$%MD+uH0H=zx7*>E2^cg z)s?4uqYd1gQ&a8C7D%-Qe#tV|`?b2Iq)xQXrj1Si!@tam^>EQgPrf$dJe!?E5%O94 z*@j+xg+eS{!{Zva_cR%6bxA6ruMded;>ujm$hUX`Jmf43R4#!6HDv$cv;>@ z>tC9cT#ocYNt-9Vi7aP&qXja4>c5hnH?G zhzW??Ic`nxJ;k3#*8ZoK$5l(LEBBUxX{|CDb0XMLZxniLzq4FeRWf}2oU;%VuGDoXItr#4D2Hg$lg0j`u(5Apx+W%q z>O)3GM$NjKa^z{>V_7$+xYDZBHwHh$8Lu${SM z!Q*fQ1hx~tVx9nI_nmOZ1(@4#3BC5vTO#Z)i2f(I#a=uviy9|5wy?b>@@lyMs;KIQ z4@r7oD|~;Cqzd~ly#79OMY8*24S@*Ot8)4mM1OhoZ-|T|eqWnpbiKpK$QTLT-8Sy4@)p+C)&~8_E~=lSr{=haTD>vRh?)2r za=MT_IJbf79~hu#XK(vMw}mZ~pPw!QLCQ5QGXyxu%gciR-qByX#v8AusyYtdVlTns zyEWfX?lytiXqC*|E6P$&ZcKX^y1P_1+A;ThbDsR>`*)a-X(i0pSDG?36RqU z`2N};`MJ3{J$?Pod~v5d7=QMgxB`Xv$K21yq>> zQ?>GChuyV$jj}i2{Kw#+v13u4g~ebga&mG~OIP-YT=LDP$ZP6Cyp+0_Bh)HOA48<)~5D=T}gjI@4&=iCGQf3wca%nU4)<%_wQf~hOVZjrUfrmq>hY4qiwzhQ}hiC ztOGNs3x_NE_(&-#Do##KiTZ6j1CjzyW4pgO*V>FrNXY1#yC&t%1+lcW#7ldszAMNr zF2>^V*XbD;*4EeSNu-FFm>Ars!pUjr+^VSX@EbxxQJ+5X_vD+m1OMW)*1+_+0JR!4 zH9r0bc*51RWNG(FYBijo<#46v?!ke_`lQPCV!y(}hZH-@a=UbsOlGKb1e;N={=T!d zb!cubvM8^$u~BKCb9;F>S@8|yXP*t*PdPbjfZR84zE|JSJFck7is+eNSl|;7_%D#gu(Yh}(v&}HT9f5Z88LM#F`8~mQPbAG zOm&gn*^`xuii-P5VsKTJjE|2G`1cF__uQ?ltoq7ap*$M+8+Y$AX8h{QGX##c@!cJ# zzG@$F3JQvrR5{~)o`RARdNY{Cs8Vkc57gSQ*w#8y^eG1Jg83hWD1>;zj69}*h{Mq9t zPq-u`uwe6n6GYrpmyxw@qygr8<5xvty|ug+S=L#&8qu`EQ=$hX)^zB|MeGP$J_Ij4#lvkwVPsM zg^EURfYUp05*tqGF^kilq1A@WOCcye#$FBPM^G42EU{t?=GG6PoF~6IbJ6LGV3P?^ MQPhCtJ+gT5ACE<600000 diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.map b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.map deleted file mode 100644 index c97e33523..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.map +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.md5 b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.md5 deleted file mode 100644 index e2e3cbfec..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.md5 +++ /dev/null @@ -1 +0,0 @@ -f6001a30fa104f98434d740081ebee62 \ No newline at end of file diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.png b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSanyoAc__coll__graph.png deleted file mode 100644 index 8e567d014b79f7a0f85ce7b815d63bd3060996a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3485 zcmZvf2Q*x3zs3th?@Avu5_JckTU_e|dh-j@H#yyH3SMMMOk&9j>md53a7@8%jwI zeyQ&8{{|OwyT@wEM3;X)d02E3xKkgltY{dJwVjR9W%9l3wf;_Yo8^3|lb0&&c4+(> z6v3H3bXQ!MiHw@m0iyP@X8icP3#TdK%O<3luCd);+9Nt42p_tSpdM02GvaD%`W#7Q zoo|xTn5^)1NG*J)eHp9-m1|$hlG}1YIu7srI+_a3{o&YlIyX1+A%c#CY${Kpftac% zpOR0E5$EudJ8h_%!4@hYu{|f7;RuN9mr}U$6c5%@wHH1Q;X*2JL z|BPcOnK?O!H}GYr6=jA3h5}6S@$sajq`T|r+>B1>>t4GcQ)g!ZB}z6nwt%Hb7Ih7c zg7WgAS)|!bW*$>6aC14Li9T7QyQ=L%z%BH2yJ7F=&(8k-XjU<#$5IE`-HM8exX+&r zp9cqfdV1a#6-{*cQVCyIR8(x;AGjA087cB?R+3LEqib)ax9A`vgN>VqhZXkhra`gh z(%RU29t}q5!VqfxoHq&=X+uMr;OuY>4ZHR6qJudqO?7pfp)?UgW8=ik z%)yKEQ#GI5I3?MpDL6k}CI(LOTr2ApNG!a_}5opLZmXl1$k zH4&o8i;U>Og9lF+?d_g>YMmX_WUax;vFr>E`3*>NnFLXKsNUqW_v90nscDwDVS z>z5-K4+sdTcE$@NCMDH0G_+OK({RaaT3E0%@M+!x1y)#i$6#mrt?pHkI&^U@1_K9~ zeuXzB3vMvc3@q!nL#1_O>yak0#@L8Hy78apuoVwG^kLn}?x%v(_s)XHqRKufjvZ&S z+atvbYQ+~0^Nh>7XJ%&V;;4O(8r|#XvtDPP5bssBPjK&sBGc!X4Mrwu1B*N98}}`* z@sC4gr5$B4V&_9{@$i}$Z__7=40+4b>&(qE<);Wf6z`?7C@Zs{i8R3Z zRF1+d<)*@{7B=xlB_%`dq8OE8FlMw0%U30PAxv3UR59ziE`l*Cel!_2=eo0WqT>dk zzT|+F(jktAgXRj#$yyKuS({8c-Gl`vau-!{vunl)3xu*!YdZ3h)1vJ93=3rKKwY14 zHTd`WvSq~&OQbtfGMWV;oR$+$Q5lv_Cmw0bQ4^%->ZP3gf9{K-|r_uNiy#H zkC!(|)vCr3)iRcU8_+VZyud=7WtcMDD@KF{^s5KlceZz^=fYxSH`#?~X10?Plox~o z4$}9|>+uLD`_=_WPwbDj#~jz^B%7z=3IqAN1(2J>@@YZ;no17=!8*f=4MNPCyT)RH z?CJjR^pvqqnxxk4zlpZ@_#JhK@SeL`cEhzUuTdFD8d7mqN4Hi_h`^vDi<`%y{&st* z*XOnG-ze$7lhvdpoS`?@`L(ZvdCM;q!pPWFtd$vXvW{kz@e|AqK1%;a#w)g7#>}IB zahd#jQ=y*C2svH%bUB<>{_W(ID_0`XXtbpFYV6wj`i-{Bi>P5NPMtd z&feYIO9-*B11FW!Xk`#Ex>WmKP*CtHCZ@wi*kf(n_zvjF5|AYynb7MR zll;@?q`U?}gaw;u#ePQI1v!`wDW23e@JN!1IT}w{zc?2y3&oq6w*?)3fCjY$!?m>~ za`PW`IU|;xaLz#lC&hm{yt4-vPBGQs&c!a_YO^!jv?|f-BPS>!ky22={psSwg`1n3Q16z>I74D{ zesU-&DY<)b`osJ8uI=*5ij>dV+tMLcMkUI44w;@XvTJ?){UQxg?UaqmC=?1%O1IQd z|7OhUDzehLZ5SxNr@w#i*jU2bw{)UnVntqH$y-q9yXtCTuu-Xi-CLnpsf)9pBN+Du z`N?v#N6N~ik5lh|>*We1y~WQT^<*&R5c8-EFN!*H-PqV5a(epowwzoxs8g^M;Zv{- zVDkCEyOb1Bzb#X%=X)vujHl;IL;wc_ED9DK9j&aQQe)ps^K2fv&62En-_*o}#X97e zS0FhCp2SDIxV#+J&;X;Lxw$xA^mw*eeAgvtrokOuQu2y{Uwe1jrAp7#w68yj|Mc5k zK|zP({cq3rx><%YVQ*q%sUzry(#4`c;SUT96t*@sHAO^3>@J4Wl3-aX+}zx@=2}w! zWWd^5M^#m|?Zn&L8~B*s$;p(pH77vflOjh42VFfqMI@5X%*;$P0~!r@7-$+lGbfyG zqxOcA7X)f|*JB>_Lk=|1-q8_x(EGo)raxYT!C>`nGpZm~ckkYPetG`u%5}rCbV*O{ z*UUo8U{B}c0L=g}z4P-qj=8}pDJjfs?ChQ%9)Gf($iBI=Q=FIgqOVUq4;C}s{hGxL z8zf#?S*afzmzYS;#*S)x^_f6WS5YC$&(A0NL%|8O&SOObA88K9k(?)>CVrosEN^XT zIye-1{tOFmcgTMYXby+N^NWfi0p&aw+le_t&pbbG%wN9B%w#VuEqz$!A{BBbnF(`8 zejm;zB_s3P_iiM-_4TB%2h&*z5me4+M2qL4>Tty=UsC0*zD{Ouqc4!%fO>$$p$7S-!m!r zviYOM(%RaZPbWtc*bFHtsfeg3dzYEh%Y)tBhgDzRPplW7;qiE)#+DYIh+7H@x#y?9 z3=9qL2)TbcF8<0aCnqNYp+>ZY1Xo8Pbz}Q{(*X3ZUcGu#HsEbe4ks|6gho#umivgj zj~|ndj{Lm5y-O=9p6q|^_wn_;9ns$3e^o|C=DuZfR|1b(>@%3ObOx|eA*b6g(3^$Z zv~mY@#Kgp{hm#gi35kM<^*^;fQLNR8$0v`E>*tvqw9!K#uTCe_+54Xoa9vYg%io ztX0VIlVa`c7&Myyo^iR&=46GSY4r>Lh2Ye5F-Nw!RRbNlNb?H5zy4D93Ji9gZ)K&R zpvXb(NEw%#{wp&xlQHWaXyd07#n($lK;+3P)mvBWwoQQ0`FTy Na20LkN+p}H{{l6C&FcUF diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.map b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.map deleted file mode 100644 index bd52394a1..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.map +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.md5 b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.md5 deleted file mode 100644 index 4e92a3fe3..000000000 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.md5 +++ /dev/null @@ -1 +0,0 @@ -a87b7a535dbb4358d51525a2278a117d \ No newline at end of file diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.png b/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/classIRSharpAc__coll__graph.png deleted file mode 100644 index 397be3abbff42fdcb1c2c648081cee364eaea847..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3360 zcmZWs2{cr1{~xjosW61Hq-2mivXpiF$R37lld)tg%h*X{2~i9o`;sMO8B4}i)*8#0 z$}%y=F5B3*i2wEe-*evgocG@I+~=I<-1FS;^ZkC7?~OGw&|zWXVFH0bEV@ul6JT}& zMmPf<@cezC905#pa6KJO(COKo*II%GfzA)>YTh>s$Xd$|HR6~*`K(4ScliyuEb=z^ z9rQ}QDXe!R&ukW~8ds!_B?mRaeI+-AYy)+MZH z-lV&%_s14qvwKPVG^~PI+Y@S^+_?y1UNJuWM122XwR5iXe)CZVDKsF5wEiUW0yPKs z*IEpc=GHl#)a&dYAhAXW-L8Xavq`L6d=(Awy{>K;)GdDCeT5r#G*(iqbBe-Y17!gq_Zz4LA1odI*H1CZ9#` z<)5Mmn6>ql&CSh#z`*?BCydO@vmH^)IPdWA@X6498+CQ{r%0sJuR2#=ZAPx~42SYxhJztCSTkVw8u=~Yb0vX;AN8NZ`HtH7$4*QUVdV1YbybIHjm># z98Pz}&|X_!S)s4Ddp@+Xi~1k~mG+qFUv70C9v;sBu>>_R=y8;$np#_Xpsh{kHu~}U zwQJAk`_g>=?6`t%iHT7?_4l{n5uNQxm|Y$&&r%Dwg|(NLmv8MC>7qfufB(+IVtI6Q zdR6;ELqZ^}%^E!-j=M86GwN1WJRBSxs}oJ8hc+cYHh&nZJ)7xb1QO4{#MI#;J2O8Y zm7UGU!otEJ@JC-Mo6<18y|Izk+M12UD$OgPzSt*)USV|qhx564`E>z-h@U^rKH9Yp z=4-@QwuhQ&Uru^7buUmPavgOPHOV9Vp@?(pptj zRrzoZ-PPS~Y-jiSi~TiGQP<0R-Y#QVkmtkY7LR3l4!8Ow1OF_Q5T4XWMn`+^ll(Cr zg%UxXEiJ>!BSFEZzt*< z@(=e1oWY~C7bAq#0k-)^R!|JK*O*CE=Z}o* zfVu(S)De7}@9_QU+G2197#`fYAv92p;NarA#K)&{vF1Eu`)T02dA1hAjzo*!(sqqj zyoFz?gKoP=bjGHd@p~>1*-q2w)$2xBdy~JCPy~dm&*r-L^XS^Y3Bb|}RD4DKKJ&uI zoM(OU;qACxd33!-?M;)uTYYZS%{k8fQLv|NdEGd67^f@3&vvbN!BMPZXH>iqQuQs4 z9mem9;AU;uQLf+gisY6!Elfx(mRO-hI25HmY^Y+tPmZq8J{PUwPkC?j4{Xiiqp5!} z-!qNgC?e!$U$c*OlnL&`ouOAwygR|65AOYi302DZFR1mJ;BF0gbcDp4V@Y>dIASRM z(b2xOR)cnhO$FyX3F~kQXUcqOt^13(+;=rsPRV5Q!^lYo=#6rBJD~;2xWBVGuM2;a zi*}mBKK8XpPqf6N;=41_B;&(1D<6e{)Y0@mrKY*H#S&#lC0=nmt(0huf#cJ=sTIe& z#%?ii*Ex#cRkzaGe--2Zr7sfDrXnw_zpNj@49T)jL|5{~z5kYMI|5e!tELB(Q2z5h zbZ~+$EFvPJ=>2=x-BToXc`W{sJ#=|J*n9;oi8H zhfGu2bu>!?UD^rZ*49ZCz;q{kjyQ64EWiKg@Q_hKLE+izm=u9T5+BUIdqYG&{aPZw z$}J@&B~4@FBq$VWgwxT~d^t2^}p#0a%c-8yFN6H{1I)yT3_qMbU|45e4*rN}Q33l`k7oBQN zOiWS&uRNe2uEaLDQyCf>&U;xupvZ|>qZDR)g#RdIvt}E_5Zy&oRI>B(u1VOnRS55Y zC@-I#3|{BkL7vDoSyWX=i0qr-D>CiNzqOjd6uy|FgLTPC<*K&};b^F&+wx-r$niJ| zcYL_Lm}>qj!PMQoVwakas;K>ZqQK9-JpKPILYm*!njn>aiNCx0xXNCL^;eZez3C_F0@kLndyN(WZw=QX6?8#E( z=BG@*_Gvkq=pB{WE95bN(<*lGB*)suOyNhXq)Pr?`x1dSfqna!t?g~EdME;X`SRsA zSy{?O*zaUa&&7XZW&meZ1E-B)<*P-4<)a30CQJC2EtTz_Bqe1PmDu=r(*?sEWya^N zttu1>1!CRs$~h-cyUf(aX23Z&R9jbzflkc-UQD+W2f(Qc}{~;^Ow~YqeSzf}p&|ucEm(AgI2+8$m@yZZ0k^ z5H&S50|Ucv)5Z@U;^f>$o>C?hDNT#~fFGqw>+0%W=HesrczAal z2Mrw^03mf(S5Zbr#-fsvOJML<;2fo;rJqTpY=y}Hln#HOCUF69zI5e4X|L8@PRX_d z!PL~$fZ$-Uz65QdyZ)4->gqQQ4e~EgC|Layj!QQT>UQ$$j#bJr81&V!1F8h=&N|m0 zprI%A0RaKk!TX+rIVyd-D+;G~h!N-L19pck4o{BOGt|OW%gV}jRHLc`x1E5ZDTW-} zUT;5DrDx@x`kEvZy1Y(q&rKDxNY2dEgF+cVKx!a%ZCMo+kcELv9XMQ2Ts%B9==O~p zF{Pz9dtP6~&veIs8yHx_3<3^>!{Nqi5zO4&-1?dF31onPU5TUNo$%T{3aPIpaNDxl zo+>x&k0@{fL4s6>j~YD2ds0MA$Ld@!#dC@aN=PKyg&n@fE4`JliL0uT+}qnzK0V&9 ztE(Ft8{3zOKq8UK2U92rtTys-Z{jYDlb!ubC!5-@nDvsQ1FIlM7IPA zfDmAXgzw)wfY`=bgB4z@oqY11D%Q_X4+&8o@^MuR*toXdy3cRj=-EvsU;V9kE_mqy z!}s7RCMG5TStS58fG&Y*rzz_``B=AAKU=Au91iK26J@j!o9 zT3OjWIGA{}-X88kk4U#XmM$HB0&7N!%gM>DjyJ9sBY1gvEn5PlJUu;AQc@<6*#iRu z?h~Jq($m3bIZYDMu>`;%VoLU6o=ktu807tzbZ32L=Ea2c_AD;vDGn%~@<868bGQe}rPGc9rP@OTe28d+Jq zKyQ|z8v4g$bd*Spy+Ey_qXP)~T>OD6i|1quccr-=5-E>y##1c9jt@5b-^s-TX8}k`tadne7rAOr z!ut98`kuMZN>#gR(PL@LKPqz>85z31zB_!1nzit5rh>x4BNAF0Jt>eZpln^PIwyJw z5Hql8hB89G + Last generated: Sun 03 Jan 2021 09:04:41 +0000 ---> # IR Protocols supported by this library | Protocol | Brand | Model | A/C Model | Detailed A/C Support | @@ -25,12 +25,14 @@ | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C
YKR-T/011 remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | Classic INV 17 / AXW12DCS A/C
YKR-M/003E remote | | Yes | | [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Elite Screens** | CineTension2 / CineTension3 series
Home2 / Home3 series
Spectrum series
VMAX Plus4 series
VMAX2 / VMAX2 Plus series
ZSP-IR-B / ZSP-IR-W remote | | - | +| [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Lumene Screens** | Embassy | | - | | [Epson](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Epson.cpp) | **Epson** | EN-TW9100W Projector | | - | | [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C (ARRAH2E)
AR-DB1 remote (ARDB1)
AR-DL10 remote (ARDB1)
AR-RAC1E remote (ARRAH2E)
AR-RAE1E remote (ARRAH2E)
AR-RAH2E remote (ARRAH2E)
AR-REB1E remote (ARREB1E)
AR-RY4 remote (ARRY4)
AST9RSGCW A/C (ARDB1)
ASTB09LBC A/C (ARRY4)
ASU30C1 A/C (ARDB1)
ASYG30LFCA A/C (ARRAH2E)
ASYG7LMCA A/C (ARREB1E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARRY4 | Yes | | [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AOHG09LLC A/C (ARRAH2E)
AR-JW2 remote (ARJW2)
AR-RCE1E remote (ARRAH2E)
ASHG09LLCA A/C (ARRAH2E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARRY4 | Yes | | [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **G.I. Cable** | XRC-200 remote | | - | | [GlobalCache](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Global Cache** | Control Tower IR DB | | - | | [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Amana](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | PBC093G00CC A/C
YX1FF remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YAA1FBF remote
YB1F2F remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | YAW1F
YBOFB | Yes | @@ -42,7 +44,7 @@ | [JVC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_JVC.cpp) | **JVC** | PTU94023B remote | | - | | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | YAPOF3 remote | | Yes | | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | KSV26CRC A/C
KSV26HRC A/C
KSV35CRC A/C
KSV35HRC A/C
KSV53HRC A/C
KSV62HRC A/C
KSV70CRC A/C
KSV70HRC A/C
KSV80HRC A/C
YALIF Remote | | Yes | -| [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | YB1FA remote | | Yes | +| [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | A5VEY A/C
YB1FA remote | | Yes | | [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[General Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711AR2853M A/C Remote
AG1BH09AW101 Split A/C | | Yes | | [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote (LG)
AKB74395308 remote (LG2)
AKB75215403 remote (LG2)
S4-W12JA3AA A/C (LG2) | | Yes | | [Lasertag](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lasertag.cpp) | **Lasertag** | Phaser emitters | | - | @@ -57,7 +59,7 @@ | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Keystone](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H4(B)BGEF remote (MIDEA) | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | FS40-7AR Stand Fan (MIDEA24) | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[MrCool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57A6/BGEFU1 remote (MIDEA) | | Yes | -| [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RUBO18GMFILCAD A/C (18K BTU) (MIDEA)
RYBO12GMFILCAD A/C (12K BTU) (MIDEA) | | Yes | +| [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG66B6(B)/BGEFU1 remote (MIDEA)
RUBO18GMFILCAD A/C (18K BTU) (MIDEA)
RYBO12GMFILCAD A/C (12K BTU) (MIDEA)
UB018GMFILCFHD A/C (12K BTU) (MIDEA)
WS012GMFI22HLD A/C (12K BTU) (MIDEA)
WS018GMFI22HLD A/C (12K BTU) (MIDEA) | | Yes | | [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **Mirage** | VLU series A/C | | - | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | HC3000 Projector (MITSUBISHI2)
KM14A 0179213 remote
MS-GK24VA A/C
TV (MITSUBISHI) | | Yes | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | 001CP T7WE10714 remote (MITSUBISHI136)
KPOA remote (MITSUBISHI112)
MSH-A24WV A/C (MITSUBISHI112)
MUH-A24WV A/C (MITSUBISHI112)
PEAD-RP71JAA Ducted A/C (MITSUBISHI136) | | Yes | diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/README.md b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/README.md similarity index 100% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/README.md rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/README.md diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/README_de.md b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/README_de.md similarity index 100% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/README_de.md rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/README_de.md diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/README_fr.md b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/README_fr.md similarity index 100% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/README_fr.md rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/README_fr.md diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/_config.yml b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/_config.yml similarity index 100% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/_config.yml rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/_config.yml diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8cpp.html b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8cpp.html similarity index 100% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8cpp.html rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8cpp.html diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8h.html b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8h.html similarity index 100% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8h.html rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8h.html diff --git a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8h_source.html b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8h_source.html similarity index 94% rename from lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8h_source.html rename to lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8h_source.html index bb7c6a469..051b58a17 100644 --- a/lib/lib_basic/IRremoteESP8266-2.7.13/docs/doxygen/html/IRac_8h_source.html +++ b/lib/lib_basic/IRremoteESP8266-2.7.14/docs/doxygen/html/IRac_8h_source.html @@ -424,215 +424,221 @@ $(function() {
354  const bool quiet, const bool turbo, const bool filter,
355  const int16_t clock = -1);
356 #endif // SEND_PANASONIC_AC
-
357 #if SEND_SAMSUNG_AC
-
358  void samsung(IRSamsungAc *ac,
-
359  const bool on, const stdAc::opmode_t mode, const float degrees,
-
360  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
-
361  const bool quiet, const bool turbo, const bool light,
-
362  const bool filter, const bool clean,
-
363  const bool beep, const bool prevpower = true,
-
364  const bool forcepower = true);
-
365 #endif // SEND_SAMSUNG_AC
-
366 #if SEND_SANYO_AC
-
367  void sanyo(IRSanyoAc *ac,
-
368  const bool on, const stdAc::opmode_t mode, const float degrees,
-
369  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
-
370  const bool beep, const int16_t sleep = -1);
-
371 #endif // SEND_SANYO_AC
-
372 #if SEND_SHARP_AC
-
373  void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model,
-
374  const bool on, const bool prev_power, const stdAc::opmode_t mode,
-
375  const float degrees, const stdAc::fanspeed_t fan,
-
376  const stdAc::swingv_t swingv, const bool turbo, const bool light,
-
377  const bool filter, const bool clean);
-
378 #endif // SEND_SHARP_AC
-
379 #if SEND_TCL112AC
-
380  void tcl112(IRTcl112Ac *ac,
-
381  const bool on, const stdAc::opmode_t mode, const float degrees,
-
382  const stdAc::fanspeed_t fan,
-
383  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
-
384  const bool turbo, const bool light, const bool econo,
-
385  const bool filter);
-
386 #endif // SEND_TCL112AC
-
387 #if SEND_TECHNIBEL_AC
-
388  void technibel(IRTechnibelAc *ac,
-
389  const bool on, const stdAc::opmode_t mode, const bool celsius,
-
390  const float degrees, const stdAc::fanspeed_t fan,
-
391  const stdAc::swingv_t swingv, const int16_t sleep = -1);
-
392 #endif // SEND_TECHNIBEL_AC
-
393 #if SEND_TECO
-
394  void teco(IRTecoAc *ac,
-
395  const bool on, const stdAc::opmode_t mode, const float degrees,
-
396  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
-
397  const bool light, const int16_t sleep = -1);
-
398 #endif // SEND_TECO
-
399 #if SEND_TOSHIBA_AC
-
400  void toshiba(IRToshibaAC *ac,
-
401  const bool on, const stdAc::opmode_t mode, const float degrees,
-
402  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
-
403  const bool turbo, const bool econo);
-
404 #endif // SEND_TOSHIBA_AC
-
405 #if SEND_TROTEC
-
406  void trotec(IRTrotecESP *ac,
-
407  const bool on, const stdAc::opmode_t mode, const float degrees,
-
408  const stdAc::fanspeed_t fan, const int16_t sleep = -1);
-
409 #endif // SEND_TROTEC
-
410 #if SEND_VESTEL_AC
-
411  void vestel(IRVestelAc *ac,
-
412  const bool on, const stdAc::opmode_t mode, const float degrees,
-
413  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
-
414  const bool turbo, const bool filter,
-
415  const int16_t sleep = -1, const int16_t clock = -1,
-
416  const bool sendNormal = true);
-
417 #endif // SEND_VESTEL_AC
-
418 #if SEND_VOLTAS
-
419  void voltas(IRVoltas *ac, const voltas_ac_remote_model_t model,
-
420  const bool on, const stdAc::opmode_t mode,
-
421  const float degrees, const stdAc::fanspeed_t fan,
-
422  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
-
423  const bool turbo, const bool econo, const bool light,
-
424  const int16_t sleep = -1);
-
425 #endif // SEND_VOLTAS
-
426 #if SEND_WHIRLPOOL_AC
- -
428  const bool on, const stdAc::opmode_t mode, const float degrees,
-
429  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
-
430  const bool turbo, const bool light,
-
431  const int16_t sleep = -1, const int16_t clock = -1);
-
432 #endif // SEND_WHIRLPOOL_AC
-
433 #if SEND_TRANSCOLD
-
434  void transcold(IRTranscoldAc *ac,
-
435  const bool on, const stdAc::opmode_t mode, const float degrees,
-
436  const stdAc::fanspeed_t fan,
-
437  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
-
438 #endif // SEND_TRANSCOLD
-
439 static stdAc::state_t cleanState(const stdAc::state_t state);
-
440 static stdAc::state_t handleToggles(const stdAc::state_t desired,
-
441  const stdAc::state_t *prev = NULL);
-
442 }; // IRac class
-
443 
-
445 namespace IRAcUtils {
-
446  String resultAcToString(const decode_results * const results);
-
447  bool decodeToState(const decode_results *decode, stdAc::state_t *result,
-
448  const stdAc::state_t *prev = NULL);
-
449 } // namespace IRAcUtils
-
450 #endif // IRAC_H_
+
357 #if SEND_PANASONIC_AC32
+
358  void panasonic32(IRPanasonicAc32 *ac,
+
359  const bool on, const stdAc::opmode_t mode,
+
360  const float degrees, const stdAc::fanspeed_t fan,
+
361  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
+
362 #endif // SEND_PANASONIC_AC32
+
363 #if SEND_SAMSUNG_AC
+
364  void samsung(IRSamsungAc *ac,
+
365  const bool on, const stdAc::opmode_t mode, const float degrees,
+
366  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+
367  const bool quiet, const bool turbo, const bool light,
+
368  const bool filter, const bool clean,
+
369  const bool beep, const bool prevpower = true,
+
370  const bool forcepower = true);
+
371 #endif // SEND_SAMSUNG_AC
+
372 #if SEND_SANYO_AC
+
373  void sanyo(IRSanyoAc *ac,
+
374  const bool on, const stdAc::opmode_t mode, const float degrees,
+
375  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+
376  const bool beep, const int16_t sleep = -1);
+
377 #endif // SEND_SANYO_AC
+
378 #if SEND_SHARP_AC
+
379  void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model,
+
380  const bool on, const bool prev_power, const stdAc::opmode_t mode,
+
381  const float degrees, const stdAc::fanspeed_t fan,
+
382  const stdAc::swingv_t swingv, const bool turbo, const bool light,
+
383  const bool filter, const bool clean);
+
384 #endif // SEND_SHARP_AC
+
385 #if SEND_TCL112AC
+
386  void tcl112(IRTcl112Ac *ac,
+
387  const bool on, const stdAc::opmode_t mode, const float degrees,
+
388  const stdAc::fanspeed_t fan,
+
389  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+
390  const bool turbo, const bool light, const bool econo,
+
391  const bool filter);
+
392 #endif // SEND_TCL112AC
+
393 #if SEND_TECHNIBEL_AC
+
394  void technibel(IRTechnibelAc *ac,
+
395  const bool on, const stdAc::opmode_t mode, const bool celsius,
+
396  const float degrees, const stdAc::fanspeed_t fan,
+
397  const stdAc::swingv_t swingv, const int16_t sleep = -1);
+
398 #endif // SEND_TECHNIBEL_AC
+
399 #if SEND_TECO
+
400  void teco(IRTecoAc *ac,
+
401  const bool on, const stdAc::opmode_t mode, const float degrees,
+
402  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+
403  const bool light, const int16_t sleep = -1);
+
404 #endif // SEND_TECO
+
405 #if SEND_TOSHIBA_AC
+
406  void toshiba(IRToshibaAC *ac,
+
407  const bool on, const stdAc::opmode_t mode, const float degrees,
+
408  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+
409  const bool turbo, const bool econo);
+
410 #endif // SEND_TOSHIBA_AC
+
411 #if SEND_TROTEC
+
412  void trotec(IRTrotecESP *ac,
+
413  const bool on, const stdAc::opmode_t mode, const float degrees,
+
414  const stdAc::fanspeed_t fan, const int16_t sleep = -1);
+
415 #endif // SEND_TROTEC
+
416 #if SEND_VESTEL_AC
+
417  void vestel(IRVestelAc *ac,
+
418  const bool on, const stdAc::opmode_t mode, const float degrees,
+
419  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+
420  const bool turbo, const bool filter,
+
421  const int16_t sleep = -1, const int16_t clock = -1,
+
422  const bool sendNormal = true);
+
423 #endif // SEND_VESTEL_AC
+
424 #if SEND_VOLTAS
+
425  void voltas(IRVoltas *ac, const voltas_ac_remote_model_t model,
+
426  const bool on, const stdAc::opmode_t mode,
+
427  const float degrees, const stdAc::fanspeed_t fan,
+
428  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
+
429  const bool turbo, const bool econo, const bool light,
+
430  const int16_t sleep = -1);
+
431 #endif // SEND_VOLTAS
+
432 #if SEND_WHIRLPOOL_AC
+ +
434  const bool on, const stdAc::opmode_t mode, const float degrees,
+
435  const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
+
436  const bool turbo, const bool light,
+
437  const int16_t sleep = -1, const int16_t clock = -1);
+
438 #endif // SEND_WHIRLPOOL_AC
+
439 #if SEND_TRANSCOLD
+
440  void transcold(IRTranscoldAc *ac,
+
441  const bool on, const stdAc::opmode_t mode, const float degrees,
+
442  const stdAc::fanspeed_t fan,
+
443  const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
+
444 #endif // SEND_TRANSCOLD
+
445 static stdAc::state_t cleanState(const stdAc::state_t state);
+
446 static stdAc::state_t handleToggles(const stdAc::state_t desired,
+
447  const stdAc::state_t *prev = NULL);
+
448 }; // IRac class
+
449 
+
451 namespace IRAcUtils {
+
452  String resultAcToString(const decode_results * const results);
+
453  bool decodeToState(const decode_results *decode, stdAc::state_t *result,
+
454  const stdAc::state_t *prev = NULL);
+
455 } // namespace IRAcUtils
+
456 #endif // IRAC_H_
Class for handling detailed Panasonic A/C messages.
Definition: ir_Panasonic.h:100
-
void airwell(IRAirwellAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan)
Send an Airwell A/C message with the supplied settings.
Definition: IRac.cpp:299
+
void airwell(IRAirwellAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan)
Send an Airwell A/C message with the supplied settings.
Definition: IRac.cpp:302
Support for Kelvinator A/C protocols.
-
Class for handling detailed Samsung A/C messages.
Definition: ir_Samsung.h:97
-
void hitachi(IRHitachiAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Hitachi A/C message with the supplied settings.
Definition: IRac.cpp:1070
+
Class for handling detailed Samsung A/C messages.
Definition: ir_Samsung.h:130
+
void hitachi(IRHitachiAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Hitachi A/C message with the supplied settings.
Definition: IRac.cpp:1073
Class for handling detailed Toshiba A/C messages.
Definition: ir_Toshiba.h:100
decode_type_t
Enumerator for defining and numbering of supported IR protocol.
Definition: IRremoteESP8266.h:771
stdAc::state_t getStatePrev(void)
Get the previous internal A/C climate state that should have already been sent to the device....
Definition: IRac.cpp:133
stdAc::state_t getState(void)
Get the current internal A/C climate state.
Definition: IRac.cpp:128
Class for handling detailed Mitsubishi Heavy 152-bit A/C messages.
Definition: ir_MitsubishiHeavy.h:184
-
static stdAc::swingh_t strToSwingH(const char *str, const stdAc::swingh_t def=stdAc::swingh_t::kOff)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2791
-
void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model, const bool on, const bool prev_power, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const bool filter, const bool clean)
Send a Sharp A/C message with the supplied settings.
Definition: IRac.cpp:1688
-
void hitachi344(IRHitachiAc344 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Hitachi 344-bit A/C message with the supplied settings.
Definition: IRac.cpp:1146
+
static stdAc::swingh_t strToSwingH(const char *str, const stdAc::swingh_t def=stdAc::swingh_t::kOff)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2842
+
void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model, const bool on, const bool prev_power, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const bool filter, const bool clean)
Send a Sharp A/C message with the supplied settings.
Definition: IRac.cpp:1725
+
void hitachi344(IRHitachiAc344 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Hitachi 344-bit A/C message with the supplied settings.
Definition: IRac.cpp:1149
Support for Electra A/C protocols.
-
void markAsSent(void)
Update the previous state to the current one.
Definition: IRac.cpp:2654
+
void markAsSent(void)
Update the previous state to the current one.
Definition: IRac.cpp:2705
swingv_t
Common A/C settings for Vertical Swing.
Definition: IRsend.h:70
Airwell "Manchester code" based protocol. Some other Airwell products use the COOLIX protocol.
-
void daikin2(IRDaikin2 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool light, const bool econo, const bool filter, const bool clean, const bool beep, const int16_t sleep=-1, const int16_t clock=-1)
Send a Daikin2 A/C message with the supplied settings.
Definition: IRac.cpp:688
+
void daikin2(IRDaikin2 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool light, const bool econo, const bool filter, const bool clean, const bool beep, const int16_t sleep=-1, const int16_t clock=-1)
Send a Daikin2 A/C message with the supplied settings.
Definition: IRac.cpp:691
Support for Trotec protocols.
-
void sanyo(IRSanyoAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool beep, const int16_t sleep=-1)
Send a Toshiba A/C message with the supplied settings.
Definition: IRac.cpp:1644
+
void sanyo(IRSanyoAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool beep, const int16_t sleep=-1)
Send a Toshiba A/C message with the supplied settings.
Definition: IRac.cpp:1681
Class for handling detailed Daikin 280-bit A/C messages.
Definition: ir_Daikin.h:651
-
void lg(IRLgAc *ac, const lg_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan)
Send a LG A/C message with the supplied settings.
Definition: IRac.cpp:1252
+
void lg(IRLgAc *ac, const lg_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan)
Send a LG A/C message with the supplied settings.
Definition: IRac.cpp:1255
Class for handling detailed Delonghi A/C messages.
Definition: ir_Delonghi.h:73
Class for handling detailed Corona A/C messages.
Definition: ir_Corona.h:107
-
void kelvinator(IRKelvinatorAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool light, const bool filter, const bool clean)
Send a Kelvinator A/C message with the supplied settings.
Definition: IRac.cpp:1218
+
void kelvinator(IRKelvinatorAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool light, const bool filter, const bool clean)
Send a Kelvinator A/C message with the supplied settings.
Definition: IRac.cpp:1221
Class for handling detailed Daikin 312-bit A/C messages.
Definition: ir_Daikin.h:733
Support for Neoclima protocols. Analysis by crankyoldgit & AndreyShpilevoy.
Class for handling detailed Daikin 128-bit A/C messages.
Definition: ir_Daikin.h:994
fanspeed_t
Common A/C settings for Fan Speeds.
Definition: IRsend.h:58
Support for Sharp protocols.
-
static String fanspeedToString(const stdAc::fanspeed_t speed)
Convert the supplied fan speed enum into the appropriate String.
Definition: IRac.cpp:2941
+
static String fanspeedToString(const stdAc::fanspeed_t speed)
Convert the supplied fan speed enum into the appropriate String.
Definition: IRac.cpp:2992
whirlpool_ac_remote_model_t
Whirlpool A/C model numbers.
Definition: IRsend.h:164
Carrier A/C.
-
void whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const int16_t sleep=-1, const int16_t clock=-1)
Send a Whirlpool A/C message with the supplied settings.
Definition: IRac.cpp:1999
+
void whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const int16_t sleep=-1, const int16_t clock=-1)
Send a Whirlpool A/C message with the supplied settings.
Definition: IRac.cpp:2036
Results returned from the decoder.
Definition: IRrecv.h:92
-
void daikin64(IRDaikin64 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const int16_t sleep=-1, const int16_t clock=-1)
Send a Daikin 64-bit A/C message with the supplied settings.
Definition: IRac.cpp:757
-
void voltas(IRVoltas *ac, const voltas_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool light, const int16_t sleep=-1)
Send a Voltas A/C message with the supplied settings.
Definition: IRac.cpp:1958
-
void tcl112(IRTcl112Ac *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool econo, const bool filter)
Send a TCL 112-bit A/C message with the supplied settings.
Definition: IRac.cpp:1741
-
void transcold(IRTranscoldAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Transcold A/C message with the supplied settings.
Definition: IRac.cpp:2036
-
bool sendAc(void)
Send an A/C message based soley on our internal state.
Definition: IRac.cpp:2660
-
static bool cmpStates(const stdAc::state_t a, const stdAc::state_t b)
Compare two AirCon states.
Definition: IRac.cpp:2671
+
void daikin64(IRDaikin64 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const int16_t sleep=-1, const int16_t clock=-1)
Send a Daikin 64-bit A/C message with the supplied settings.
Definition: IRac.cpp:760
+
void voltas(IRVoltas *ac, const voltas_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool light, const int16_t sleep=-1)
Send a Voltas A/C message with the supplied settings.
Definition: IRac.cpp:1995
+
void tcl112(IRTcl112Ac *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool econo, const bool filter)
Send a TCL 112-bit A/C message with the supplied settings.
Definition: IRac.cpp:1778
+
void transcold(IRTranscoldAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Transcold A/C message with the supplied settings.
Definition: IRac.cpp:2073
+
bool sendAc(void)
Send an A/C message based soley on our internal state.
Definition: IRac.cpp:2711
+
static bool cmpStates(const stdAc::state_t a, const stdAc::state_t b)
Compare two AirCon states.
Definition: IRac.cpp:2722
Support for Midea protocols. Midea added by crankyoldgit & bwze.
Support for Daikin A/C protocols.
gree_ac_remote_model_t
Gree A/C model numbers.
Definition: IRsend.h:129
Class for handling detailed Daikin 64-bit A/C messages.
Definition: ir_Daikin.h:1124
Support for Coolix A/C protocols.
-
void vestel(IRVestelAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool filter, const int16_t sleep=-1, const int16_t clock=-1, const bool sendNormal=true)
Send a Vestel A/C message with the supplied settings.
Definition: IRac.cpp:1916
+
void vestel(IRVestelAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool filter, const int16_t sleep=-1, const int16_t clock=-1, const bool sendNormal=true)
Send a Vestel A/C message with the supplied settings.
Definition: IRac.cpp:1953
Class for handling detailed Hitachi 53-byte/424-bit A/C messages.
Definition: ir_Hitachi.h:371
-
void daikin(IRDaikinESP *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool clean)
Send a Daikin A/C message with the supplied settings.
Definition: IRac.cpp:524
+
void daikin(IRDaikinESP *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool clean)
Send a Daikin A/C message with the supplied settings.
Definition: IRac.cpp:527
IRac(const uint16_t pin, const bool inverted=false, const bool use_modulation=true)
Class constructor.
Definition: IRac.cpp:54
Class for handling detailed Daikin 216-bit A/C messages.
Definition: ir_Daikin.h:829
Class for handling detailed Voltas A/C messages.
Definition: ir_Voltas.h:90
hitachi_ac1_remote_model_t
HITACHI_AC1 A/C model numbers.
Definition: IRsend.h:135
-
void samsung(IRSamsungAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool light, const bool filter, const bool clean, const bool beep, const bool prevpower=true, const bool forcepower=true)
Send a Samsung A/C message with the supplied settings.
Definition: IRac.cpp:1603
-
void daikin128(IRDaikin128 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool light, const bool econo, const int16_t sleep=-1, const int16_t clock=-1)
Send a Daikin 128-bit A/C message with the supplied settings.
Definition: IRac.cpp:564
+
void samsung(IRSamsungAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool light, const bool filter, const bool clean, const bool beep, const bool prevpower=true, const bool forcepower=true)
Send a Samsung A/C message with the supplied settings.
Definition: IRac.cpp:1640
+
void daikin128(IRDaikin128 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool light, const bool econo, const int16_t sleep=-1, const int16_t clock=-1)
Send a Daikin 128-bit A/C message with the supplied settings.
Definition: IRac.cpp:567
Class for handling detailed Hitachi 224-bit A/C messages.
Definition: ir_Hitachi.h:246
const int8_t kGpioUnused
A placeholder for not using an actual GPIO.
Definition: IRac.h:45
-
Common functions for use with all A/Cs supported by the IRac class.
Definition: IRac.cpp:3010
-
Class for handling detailed Sanyo A/C messages.
Definition: ir_Sanyo.h:98
-
void haier(IRHaierAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool filter, const int16_t sleep=-1, const int16_t clock=-1)
Send a Haier A/C message with the supplied settings.
Definition: IRac.cpp:1001
+
Common functions for use with all A/Cs supported by the IRac class.
Definition: IRac.cpp:3061
+
Class for handling detailed Sanyo A/C messages.
Definition: ir_Sanyo.h:106
+
void haier(IRHaierAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool filter, const int16_t sleep=-1, const int16_t clock=-1)
Send a Haier A/C message with the supplied settings.
Definition: IRac.cpp:1004
Class for handling detailed Whirlpool A/C messages.
Definition: ir_Whirlpool.h:91
Class for handling detailed Hitachi 344-bit A/C messages.
Definition: ir_Hitachi.h:459
-
static String boolToString(const bool value)
Convert the supplied boolean into the appropriate String.
Definition: IRac.cpp:2912
+
static String boolToString(const bool value)
Convert the supplied boolean into the appropriate String.
Definition: IRac.cpp:2963
stdAc::state_t next
The state we want the device to be in after we send.
Definition: IRac.h:97
std::string String
Definition: IRremoteESP8266.h:1178
Class for handling detailed Mitsubishi 144-bit A/C messages.
Definition: ir_Mitsubishi.h:221
-
void trotec(IRTrotecESP *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const int16_t sleep=-1)
Send a Trotec A/C message with the supplied settings.
Definition: IRac.cpp:1879
-
static int16_t strToModel(const char *str, const int16_t def=-1)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2831
+
void trotec(IRTrotecESP *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const int16_t sleep=-1)
Send a Trotec A/C message with the supplied settings.
Definition: IRac.cpp:1916
+
static int16_t strToModel(const char *str, const int16_t def=-1)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2882
Class for handling detailed Amcor A/C messages.
Definition: ir_Amcor.h:90
Class for handling detailed Mitsubishi 122-bit A/C messages.
Definition: ir_Mitsubishi.h:339
Class for handling detailed TCL A/C messages.
Definition: ir_Tcl.h:63
-
void daikin176(IRDaikin176 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingh_t swingh)
Send a Daikin 176-bit A/C message with the supplied settings.
Definition: IRac.cpp:656
+
void daikin176(IRDaikin176 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingh_t swingh)
Send a Daikin 176-bit A/C message with the supplied settings.
Definition: IRac.cpp:659
Class for handling detailed Electra A/C messages.
Definition: ir_Electra.h:98
Support for TCL protocols.
-
bool hasStateChanged(void)
Check if the internal state has changed from what was previously sent.
Definition: IRac.cpp:2683
-
void haierYrwo2(IRHaierACYRW02 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool filter, const int16_t sleep=-1)
Send a Haier YRWO2 A/C message with the supplied settings.
Definition: IRac.cpp:1038
-
void daikin216(IRDaikin216 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo)
Send a Daikin 216-bit A/C message with the supplied settings.
Definition: IRac.cpp:727
+
bool hasStateChanged(void)
Check if the internal state has changed from what was previously sent.
Definition: IRac.cpp:2734
+
void haierYrwo2(IRHaierACYRW02 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool filter, const int16_t sleep=-1)
Send a Haier YRWO2 A/C message with the supplied settings.
Definition: IRac.cpp:1041
+
void daikin216(IRDaikin216 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo)
Send a Daikin 216-bit A/C message with the supplied settings.
Definition: IRac.cpp:730
Support for Transcold A/C protocols.
Support for Hitachi A/C protocols.
Support for Panasonic protocols.
-
static stdAc::state_t handleToggles(const stdAc::state_t desired, const stdAc::state_t *prev=NULL)
Create a new state base on desired & previous states but handle any state changes for options that ne...
Definition: IRac.cpp:2085
+
static stdAc::state_t handleToggles(const stdAc::state_t desired, const stdAc::state_t *prev=NULL)
Create a new state base on desired & previous states but handle any state changes for options that ne...
Definition: IRac.cpp:2122
Class for handling detailed Mitsubishi 136-bit A/C messages.
Definition: ir_Mitsubishi.h:285
panasonic_ac_remote_model_t
Panasonic A/C model numbers.
Definition: IRsend.h:141
swingh_t
Common A/C settings for Horizontal Swing.
Definition: IRsend.h:83
-
void mitsubishi112(IRMitsubishi112 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet)
Send a Mitsubishi 112-bit A/C message with the supplied settings.
Definition: IRac.cpp:1362
-
bool decodeToState(const decode_results *decode, stdAc::state_t *result, const stdAc::state_t *prev)
Convert a valid IR A/C remote message that we understand enough into a Common A/C state.
Definition: IRac.cpp:3369
+
void mitsubishi112(IRMitsubishi112 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet)
Send a Mitsubishi 112-bit A/C message with the supplied settings.
Definition: IRac.cpp:1365
+
bool decodeToState(const decode_results *decode, stdAc::state_t *result, const stdAc::state_t *prev)
Convert a valid IR A/C remote message that we understand enough into a Common A/C state.
Definition: IRac.cpp:3430
Class for handling detailed Hitachi 104-bit A/C messages.
Definition: ir_Hitachi.h:303
-
void hitachi424(IRHitachiAc424 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv)
Send a Hitachi 424-bit A/C message with the supplied settings.
Definition: IRac.cpp:1180
+
void hitachi424(IRHitachiAc424 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv)
Send a Hitachi 424-bit A/C message with the supplied settings.
Definition: IRac.cpp:1183
Support for Samsung protocols. Samsung originally added from https://github.com/shirriff/Arduino-IRre...
-
String resultAcToString(const decode_results *const result)
Display the human readable state of an A/C message if we can.
Definition: IRac.cpp:3016
-
void daikin152(IRDaikin152 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool econo)
Send a Daikin 152-bit A/C message with the supplied settings.
Definition: IRac.cpp:601
+
String resultAcToString(const decode_results *const result)
Display the human readable state of an A/C message if we can.
Definition: IRac.cpp:3067
+
void daikin152(IRDaikin152 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool econo)
Send a Daikin 152-bit A/C message with the supplied settings.
Definition: IRac.cpp:604
fujitsu_ac_remote_model_t
Fujitsu A/C model numbers.
Definition: IRsend.h:120
Support for Gree A/C protocols.
Class for handling detailed Carrier 64 bit A/C messages.
Definition: ir_Carrier.h:84
-
Class for handling detailed Midea A/C messages.
Definition: ir_Midea.h:138
-
Class for handling detailed Kelvinator A/C messages.
Definition: ir_Kelvinator.h:120
+
Class for handling detailed Midea A/C messages.
Definition: ir_Midea.h:151
+
Class for handling detailed Kelvinator A/C messages.
Definition: ir_Kelvinator.h:121
bool _inverted
IR LED is lit when GPIO is LOW (true) or HIGH (false)?
Definition: IRac.h:103
Class for handling detailed Fujitsu A/C messages.
Definition: ir_Fujitsu.h:113
Support for Mitsubishi Heavy Industry protocols. Code to emulate Mitsubishi Heavy Industries A/C IR r...
Class for handling detailed Coolix A/C messages.
Definition: ir_Coolix.h:112
-
void midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool econo, const bool light, const int16_t sleep=-1)
Send a Midea A/C message with the supplied settings.
Definition: IRac.cpp:1289
-
void panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool filter, const int16_t clock=-1)
Send a Panasonic A/C message with the supplied settings.
Definition: IRac.cpp:1559
-
static String swingvToString(const stdAc::swingv_t swingv)
Convert the supplied enum into the appropriate String.
Definition: IRac.cpp:2963
+
void midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool econo, const bool light, const int16_t sleep=-1)
Send a Midea A/C message with the supplied settings.
Definition: IRac.cpp:1292
+
void panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool filter, const int16_t clock=-1)
Send a Panasonic A/C message with the supplied settings.
Definition: IRac.cpp:1562
+
static String swingvToString(const stdAc::swingv_t swingv)
Convert the supplied enum into the appropriate String.
Definition: IRac.cpp:3014
Support for Mitsubishi protocols. Mitsubishi (TV) decoding added from https://github....
A universal/common/generic interface for controling supported A/Cs.
Definition: IRac.h:49
Support for Teco protocols.
-
void gree(IRGreeAC *ac, const gree_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const bool clean, const int16_t sleep=-1)
Send a Gree A/C message with the supplied settings.
Definition: IRac.cpp:963
+
void gree(IRGreeAC *ac, const gree_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const bool clean, const int16_t sleep=-1)
Send a Gree A/C message with the supplied settings.
Definition: IRac.cpp:966
Delonghi A/C.
-
void electra(IRElectraAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool lighttoggle, const bool clean)
Send an Electra A/C message with the supplied settings.
Definition: IRac.cpp:814
-
static stdAc::state_t cleanState(const stdAc::state_t state)
Create a new state base on the provided state that has been suitably fixed.
Definition: IRac.cpp:2072
+
void electra(IRElectraAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool lighttoggle, const bool clean)
Send an Electra A/C message with the supplied settings.
Definition: IRac.cpp:817
+
static stdAc::state_t cleanState(const stdAc::state_t state)
Create a new state base on the provided state that has been suitably fixed.
Definition: IRac.cpp:2109
Support for Argo Ulisse 13 DCI Mobile Split ACs.
-
void mitsubishi(IRMitsubishiAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const int16_t clock=-1)
Send a Mitsubishi A/C message with the supplied settings.
Definition: IRac.cpp:1327
-
void amcor(IRAmcorAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan)
Send an Amcor A/C message with the supplied settings.
Definition: IRac.cpp:327
+
void mitsubishi(IRMitsubishiAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const int16_t clock=-1)
Send a Mitsubishi A/C message with the supplied settings.
Definition: IRac.cpp:1330
+
void amcor(IRAmcorAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan)
Send an Amcor A/C message with the supplied settings.
Definition: IRac.cpp:330
Class for handling detailed Technibel A/C messages.
Definition: ir_Technibel.h:108
Class for handling detailed Airwell A/C messages.
Definition: ir_Airwell.h:60
Support for Voltas A/C protocol.
@@ -640,63 +646,65 @@ $(function() {
Class for handling detailed LG A/C messages.
Definition: ir_LG.h:67
Support for Fujitsu A/C protocols. Fujitsu A/C support added by Jonny Graham.
Class for handling detailed Haier A/C messages.
Definition: ir_Haier.h:244
-
void neoclima(IRNeoclimaAc *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool light, const bool filter, const int16_t sleep=-1)
Send a Neoclima A/C message with the supplied settings.
Definition: IRac.cpp:1518
+
void neoclima(IRNeoclimaAc *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool light, const bool filter, const int16_t sleep=-1)
Send a Neoclima A/C message with the supplied settings.
Definition: IRac.cpp:1521
Class for handling detailed Daikin 160-bit A/C messages.
Definition: ir_Daikin.h:885
-
static String opmodeToString(const stdAc::opmode_t mode)
Convert the supplied operation mode into the appropriate String.
Definition: IRac.cpp:2919
-
Class for handling detailed Sharp A/C messages.
Definition: ir_Sharp.h:113
-
void toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool econo)
Send a Toshiba A/C message with the supplied settings.
Definition: IRac.cpp:1843
+
static String opmodeToString(const stdAc::opmode_t mode)
Convert the supplied operation mode into the appropriate String.
Definition: IRac.cpp:2970
+
Class for handling detailed Sharp A/C messages.
Definition: ir_Sharp.h:131
+
void toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool econo)
Send a Toshiba A/C message with the supplied settings.
Definition: IRac.cpp:1880
Support for Goodweather compatible HVAC protocols.
-
void argo(IRArgoAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const int16_t sleep=-1)
Send an Argo A/C message with the supplied settings.
Definition: IRac.cpp:359
+
void argo(IRArgoAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const int16_t sleep=-1)
Send an Argo A/C message with the supplied settings.
Definition: IRac.cpp:362
lg_ac_remote_model_t
LG A/C model numbers.
Definition: IRsend.h:170
-
void mitsubishi136(IRMitsubishi136 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet)
Send a Mitsubishi 136-bit A/C message with the supplied settings.
Definition: IRac.cpp:1398
+
void mitsubishi136(IRMitsubishi136 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet)
Send a Mitsubishi 136-bit A/C message with the supplied settings.
Definition: IRac.cpp:1401
bool _modulation
Is frequency modulation to be used?
Definition: IRac.h:104
-
void teco(IRTecoAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool light, const int16_t sleep=-1)
Send a Teco A/C message with the supplied settings.
Definition: IRac.cpp:1810
-
static stdAc::opmode_t strToOpmode(const char *str, const stdAc::opmode_t def=stdAc::opmode_t::kAuto)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2689
+
void teco(IRTecoAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool light, const int16_t sleep=-1)
Send a Teco A/C message with the supplied settings.
Definition: IRac.cpp:1847
+
static stdAc::opmode_t strToOpmode(const char *str, const stdAc::opmode_t def=stdAc::opmode_t::kAuto)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2740
Support for Sanyo protocols. Sanyo LC7461 support originally by marcosamarinho Sanyo SA 8650B origina...
-
void hitachi1(IRHitachiAc1 *ac, const hitachi_ac1_remote_model_t model, const bool on, const bool power_toggle, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool swing_toggle, const int16_t sleep=-1)
Send a Hitachi1 A/C message with the supplied settings.
Definition: IRac.cpp:1107
+
void hitachi1(IRHitachiAc1 *ac, const hitachi_ac1_remote_model_t model, const bool on, const bool power_toggle, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool swing_toggle, const int16_t sleep=-1)
Send a Hitachi1 A/C message with the supplied settings.
Definition: IRac.cpp:1110
Class for handling detailed Transcold A/C messages.
Definition: ir_Transcold.h:111
+
void panasonic32(IRPanasonicAc32 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh)
Send a Panasonic A/C message with the supplied settings.
Definition: IRac.cpp:1598
Support for Whirlpool protocols. Decoding help from: @redmusicxd, @josh929800, @raducostea.
-
static bool strToBool(const char *str, const bool def=false)
Convert the supplied str into the appropriate boolean value.
Definition: IRac.cpp:2894
-
void mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool clean)
Send a Mitsubishi Heavy 88-bit A/C message with the supplied settings.
Definition: IRac.cpp:1433
-
static stdAc::swingv_t strToSwingV(const char *str, const stdAc::swingv_t def=stdAc::swingv_t::kOff)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2750
+
static bool strToBool(const char *str, const bool def=false)
Convert the supplied str into the appropriate boolean value.
Definition: IRac.cpp:2945
+
void mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool clean)
Send a Mitsubishi Heavy 88-bit A/C message with the supplied settings.
Definition: IRac.cpp:1436
+
static stdAc::swingv_t strToSwingV(const char *str, const stdAc::swingv_t def=stdAc::swingv_t::kOff)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2801
Class for handling detailed Vestel A/C messages.
Definition: ir_Vestel.h:116
+
Class for handling detailed Panasonic 32bit A/C messages.
Definition: ir_Panasonic.h:219
Class for handling detailed Trotec A/C messages.
Definition: ir_Trotec.h:76
Class for handling detailed Teco A/C messages.
Definition: ir_Teco.h:107
-
static String swinghToString(const stdAc::swingh_t swingh)
Convert the supplied enum into the appropriate String.
Definition: IRac.cpp:2987
-
void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool filter, const bool clean, const int16_t sleep=-1)
Send a Fujitsu A/C message with the supplied settings.
Definition: IRac.cpp:857
+
static String swinghToString(const stdAc::swingh_t swingh)
Convert the supplied enum into the appropriate String.
Definition: IRac.cpp:3038
+
void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool filter, const bool clean, const int16_t sleep=-1)
Send a Fujitsu A/C message with the supplied settings.
Definition: IRac.cpp:860
Support for Technibel protocol.
-
void delonghiac(IRDelonghiAc *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const bool turbo, const int16_t sleep=-1)
Send a Delonghi A/C message with the supplied settings.
Definition: IRac.cpp:787
+
void delonghiac(IRDelonghiAc *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const bool turbo, const int16_t sleep=-1)
Send a Delonghi A/C message with the supplied settings.
Definition: IRac.cpp:790
stdAc::state_t _prev
The state we expect the device to currently be in.
Definition: IRac.h:105
Class for handling detailed Haier ACYRW02 A/C messages.
Definition: ir_Haier.h:314
-
void daikin160(IRDaikin160 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv)
Send a Daikin 160-bit A/C message with the supplied settings.
Definition: IRac.cpp:634
-
void corona(IRCoronaAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool econo)
Send a Corona A/C message with the supplied settings.
Definition: IRac.cpp:489
+
void daikin160(IRDaikin160 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv)
Send a Daikin 160-bit A/C message with the supplied settings.
Definition: IRac.cpp:637
+
void corona(IRCoronaAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool econo)
Send a Corona A/C message with the supplied settings.
Definition: IRac.cpp:492
static void initState(stdAc::state_t *state, const decode_type_t vendor, const int16_t model, const bool power, const stdAc::opmode_t mode, const float degrees, const bool celsius, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool light, const bool filter, const bool clean, const bool beep, const int16_t sleep, const int16_t clock)
Initialise the given state with the supplied settings.
Definition: IRac.cpp:85
-
void mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool filter, const bool clean, const int16_t sleep=-1)
Send a Mitsubishi Heavy 152-bit A/C message with the supplied settings.
Definition: IRac.cpp:1474
+
void mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool filter, const bool clean, const int16_t sleep=-1)
Send a Mitsubishi Heavy 152-bit A/C message with the supplied settings.
Definition: IRac.cpp:1477
Support for Haier A/C protocols. The specifics of reverse engineering the protocols details:
Class for handling detailed Mitsubishi Heavy 88-bit A/C messages.
Definition: ir_MitsubishiHeavy.h:271
-
Class for handling detailed Gree A/C messages.
Definition: ir_Gree.h:131
-
void coolix(IRCoolixAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool clean, const int16_t sleep=-1)
Send a Coolix A/C message with the supplied settings.
Definition: IRac.cpp:428
-
static stdAc::fanspeed_t strToFanspeed(const char *str, const stdAc::fanspeed_t def=stdAc::fanspeed_t::kAuto)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2719
+
Class for handling detailed Gree A/C messages.
Definition: ir_Gree.h:133
+
void coolix(IRCoolixAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool clean, const int16_t sleep=-1)
Send a Coolix A/C message with the supplied settings.
Definition: IRac.cpp:431
+
static stdAc::fanspeed_t strToFanspeed(const char *str, const stdAc::fanspeed_t def=stdAc::fanspeed_t::kAuto)
Convert the supplied str into the appropriate enum.
Definition: IRac.cpp:2770
Support for Toshiba protocols.
-
void goodweather(IRGoodweatherAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const int16_t sleep=-1)
Send a Goodweather A/C message with the supplied settings.
Definition: IRac.cpp:921
+
void goodweather(IRGoodweatherAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const int16_t sleep=-1)
Send a Goodweather A/C message with the supplied settings.
Definition: IRac.cpp:924
Structure to hold a common A/C state.
Definition: IRsend.h:97
Class for handling detailed Goodweather A/C messages.
Definition: ir_Goodweather.h:100
Support for Vestel protocols. Vestel added by Erdem U. Altinyurt.
Class for handling detailed Argo A/C messages.
Definition: ir_Argo.h:127
-
Class for handling detailed Neoclima A/C messages.
Definition: ir_Neoclima.h:94
+
Class for handling detailed Neoclima A/C messages.
Definition: ir_Neoclima.h:120
static bool isProtocolSupported(const decode_type_t protocol)
Is the given protocol supported by the IRac class?
Definition: IRac.cpp:138
Class for handling detailed Daikin 176-bit A/C messages.
Definition: ir_Daikin.h:937
Amcor A/C protocol.
uint16_t _pin
The GPIO to use to transmit messages from.
Definition: IRac.h:102
-
void technibel(IRTechnibelAc *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const int16_t sleep=-1)
Send a Technibel A/C message with the supplied settings.
Definition: IRac.cpp:1777
+
void technibel(IRTechnibelAc *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const int16_t sleep=-1)
Send a Technibel A/C message with the supplied settings.
Definition: IRac.cpp:1814
voltas_ac_remote_model_t
Voltas A/C model numbers.
Definition: IRsend.h:158
sharp_ac_remote_model_t
Sharp A/C model numbers.
Definition: IRsend.h:152
Support for LG protocols.
-
void carrier64(IRCarrierAc64 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const int16_t sleep=-1)
Send a Carrier 64-bit A/C message with the supplied settings.
Definition: IRac.cpp:391
+
void carrier64(IRCarrierAc64 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const int16_t sleep=-1)
Send a Carrier 64-bit A/C message with the supplied settings.
Definition: IRac.cpp:394
opmode_t
Common A/C settings for A/C operating modes.
Definition: IRsend.h:46