diff --git a/docs/source/Plugin/P000_commands.repl b/docs/source/Plugin/P000_commands.repl index cd10de3b6..3491d5d0a 100644 --- a/docs/source/Plugin/P000_commands.repl +++ b/docs/source/Plugin/P000_commands.repl @@ -1104,9 +1104,9 @@ ``WriteEE,,`` for writing a value to a slot. - ``WriteRTC,erase,erase`` for erasing all data from the module. + ``WriteEE,erase,erase`` for erasing all data from the module. - ``WriteRTC,check,wp`` for re-checking the write-protect status of the module. + ``WriteEE,check,wp`` for re-checking the write-protect status of the module. " " WriteRTC"," diff --git a/lib/AT24Cx/AT24CX.cpp b/lib/AT24Cx/AT24CX.cpp deleted file mode 100644 index bca40187c..000000000 --- a/lib/AT24Cx/AT24CX.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/** - -AT24CX.cpp -Library for using the EEPROM AT24C32/64 - -Copyright (c) 2014 Christian Paul - -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. - - */ -#include "AT24CX.h" -#include - -/** - * Constructor with AT24Cx EEPROM at index 0 - */ -AT24CX::AT24CX() { - init(0, 32, 4096); -} - -/** - * Constructor with AT24Cx EEPROM at given index, size of page and max size in bytes - */ -AT24CX::AT24CX(uint8_t index, uint8_t pageSize, uint32_t maxSize) { - init(index, pageSize, maxSize); -} - -/** - * Constructor with AT24C32 EEPROM at index 0 - */ -AT24C32::AT24C32() { - init(0, 32, 4096); -} -/** - * Constructor with AT24Cx EEPROM at given index - */ -AT24C32::AT24C32(uint8_t index) { - init(index, 32, 4096); -} - -/** - * Constructor with AT24C64 EEPROM at index 0 - */ -AT24C64::AT24C64() { - init(0, 32, 8192); -} -/** - * Constructor with AT24C64 EEPROM at given index - */ -AT24C64::AT24C64(uint8_t index) { - init(index, 32, 8192); -} - -/** - * Constructor with AT24C128 EEPROM at index 0 - */ -AT24C128::AT24C128() { - init(0, 64, 16384); -} -/** - * Constructor with AT24C128 EEPROM at given index - */ -AT24C128::AT24C128(uint8_t index) { - init(index, 64, 16384); -} - -/** - * Constructor with AT24C256 EEPROM at index 0 - */ -AT24C256::AT24C256() { - init(0, 64, 32768); -} -/** - * Constructor with AT24C128 EEPROM at given index - */ -AT24C256::AT24C256(uint8_t index) { - init(index, 64, 32768); -} - -/** - * Constructor with AT24C512 EEPROM at index 0 - */ -AT24C512::AT24C512() { - init(0, 128, 65536); -} -/** - * Constructor with AT24C512 EEPROM at given index - */ -AT24C512::AT24C512(uint8_t index) { - init(index, 128, 65536); -} - -/** - * Init - */ -void AT24CX::init(uint8_t index, uint8_t pageSize, uint32_t maxSize) { - _id = AT24CX_ID | (index & 0x7); - _pageSize = pageSize; - _maxSize = maxSize; - // Wire.begin(); -} - -/** - * Check address not reached - */ -bool AT24CX::checkSize(uint32_t address, uint32_t size) { - return (address + size - 1) <= _maxSize; -} - -/** - * Write byte - */ -void AT24CX::write(uint32_t address, uint8_t data) { - if (!checkSize(address, 1)) { - return; - } - Wire.beginTransmission(_id); - if(Wire.endTransmission()==0) { - Wire.beginTransmission(_id); - Wire.write(address >> 8); - Wire.write(address & 0xFF); - Wire.write(data); - Wire.endTransmission(); - delay(20); - } -} - -/** - * Write integer - */ -void AT24CX::writeInt(uint32_t address, uint16_t data) { - write(address, (uint8_t*)&data, 2); -} - -/** - * Write long - */ -void AT24CX::writeLong(uint32_t address, uint32_t data) { - write(address, (uint8_t*)&data, 4); -} - -/** - * Write float - */ -void AT24CX::writeFloat(uint32_t address, float data) { - write(address, (uint8_t*)&data, 4); -} - -/** - * Write double - */ -void AT24CX::writeDouble(uint32_t address, double data) { - write(address, (uint8_t*)&data, 8); -} - -/** - * Write chars - */ -void AT24CX::writeChars(uint32_t address, char *data, int length) { - write(address, (uint8_t*)data, length); -} - -/** - * Write bytes - */ -void AT24CX::writeBytes(uint32_t address, uint8_t *data, int length) { - write(address, data, length); -} - -/** - * Read integer - */ -uint16_t AT24CX::readInt(uint32_t address) { - memset(_b, 0, sizeof(_b)); - read(address, _b, 2); - return *(uint32_t*)&_b[0]; -} - -/** - * Read long - */ -uint32_t AT24CX::readLong(uint32_t address) { - read(address, _b, 4); - return *(unsigned long*)&_b[0]; -} - -/** - * Read float - */ -float AT24CX::readFloat(uint32_t address) { - read(address, _b, 4); - return *(float*)&_b[0]; -} - -/** - * Read double - */ -double AT24CX::readDouble(uint32_t address) { - read(address, _b, 8); - return *(double*)&_b[0]; -} - -/** - * Read chars - */ -void AT24CX::readChars(uint32_t address, char *data, int n) { - read(address, (uint8_t*)data, n); -} - -/** - * Read bytes - */ -void AT24CX::readBytes(uint32_t address, uint8_t *data, int n) { - read(address, data, n); -} - -/** - * Write sequence of n bytes - */ -void AT24CX::write(uint32_t address, uint8_t *data, int n) { - if (!checkSize(address, n)) { - return; - } - // status quo - int c = n; // bytes left to write - int offD = 0; // current offset in data pointer - int offP; // current offset in page - int nc = 0; // next n bytes to write - - // write alle bytes in multiple steps - while (c > 0) { - // calc offset in page - offP = address % _pageSize; - // maximal 30 bytes to write - nc = min(min(c, 30), _pageSize - offP); - write(address, data, offD, nc); - c-=nc; - offD+=nc; - address+=nc; - } -} - -/** - * Write sequence of n bytes from offset - */ -void AT24CX::write(uint32_t address, uint8_t *data, int offset, int n) { - if (!checkSize(address, n)) { - return; - } - Wire.beginTransmission(_id); - if (Wire.endTransmission()==0) { - Wire.beginTransmission(_id); - Wire.write(address >> 8); - Wire.write(address & 0xFF); - uint8_t *adr = data+offset; - Wire.write(adr, n); - Wire.endTransmission(); - delay(20); - } -} - -/** - * Read byte - */ -uint8_t AT24CX::read(uint32_t address) { - if (!checkSize(address, 1)) { - return 0; - } - uint8_t b = 0; - int r = 0; - Wire.beginTransmission(_id); - if (Wire.endTransmission()==0) { - Wire.beginTransmission(_id); - Wire.write(address >> 8); - Wire.write(address & 0xFF); - if (Wire.endTransmission()==0) { - Wire.requestFrom(_id, 1); - while (Wire.available() > 0 && r<1) { - b = (uint8_t)Wire.read(); - r++; - } - } - } - return b; -} - -/** - * Read sequence of n bytes - */ -void AT24CX::read(uint32_t address, uint8_t *data, int n) { - if (!checkSize(address, n)) { - return; - } - int c = n; - int offD = 0; - // read until are n bytes read - while (c > 0) { - // read maximal 32 bytes - int nc = c; - if (nc > 32) - nc = 32; - read(address, data, offD, nc); - address+=nc; - offD+=nc; - c-=nc; - } -} - - -/** - * Read sequence of n bytes to offset - */ -void AT24CX::read(uint32_t address, uint8_t *data, int offset, int n) { - Wire.beginTransmission(_id); - if (Wire.endTransmission()==0) { - Wire.beginTransmission(_id); - Wire.write(address >> 8); - Wire.write(address & 0xFF); - if (Wire.endTransmission()==0) { - int r = 0; - Wire.requestFrom(_id, n); - while (Wire.available() > 0 && r -#include - -// // byte -// typedef uint8_t byte; - -// AT24Cx I2C adress -// 80 -// 0x50 -#define AT24CX_ID 0b01010000 - -// general class definition -class AT24CX { -public: - AT24CX(); - AT24CX(uint8_t index, uint8_t pageSize, uint32_t maxSize); - void write(uint32_t address, uint8_t data); - void write(uint32_t address, uint8_t *data, int n); - void writeInt(uint32_t address, uint16_t data); - void writeLong(uint32_t address, uint32_t data); - void writeFloat(uint32_t address, float data); - void writeDouble(uint32_t address, double data); - void writeChars(uint32_t address, char *data, int length); - void writeBytes(uint32_t address, uint8_t *data, int length); - uint8_t read(uint32_t address); - void read(uint32_t address, uint8_t *data, int n); - uint16_t readInt(uint32_t address); - uint32_t readLong(uint32_t address); - float readFloat(uint32_t address); - double readDouble(uint32_t address); - void readChars(uint32_t address, char *data, int n); - void readBytes(uint32_t address, uint8_t *data, int n); -protected: - void init(uint8_t index, uint8_t pageSize, uint32_t maxSize); -private: - void read(uint32_t address, uint8_t *data, int offset, int n); - void write(uint32_t address, uint8_t *data, int offset, int n); - bool checkSize(uint32_t address, uint32_t size); - int _id; - uint8_t _b[8]; - uint8_t _pageSize; - uint32_t _maxSize{}; -}; - -// AT24C32 class definiton -class AT24C32 : public AT24CX { -public: - AT24C32(); - AT24C32(uint8_t index); -}; - -// AT24C64 class definiton -class AT24C64 : public AT24CX { -public: - AT24C64(); - AT24C64(uint8_t index); -}; - -// AT24C128 class definiton -class AT24C128 : public AT24CX { -public: - AT24C128(); - AT24C128(uint8_t index); -}; - -// AT24C256 class definiton -class AT24C256 : public AT24CX { -public: - AT24C256(); - AT24C256(uint8_t index); -}; - -// AT24C512 class definiton -class AT24C512 : public AT24CX { -public: - AT24C512(); - AT24C512(uint8_t index); -}; - - - -#endif diff --git a/lib/AT24Cx/AT24CX_demo/AT24CX_demo.ino b/lib/AT24Cx/AT24CX_demo/AT24CX_demo.ino deleted file mode 100644 index b49cadab5..000000000 --- a/lib/AT24Cx/AT24CX_demo/AT24CX_demo.ino +++ /dev/null @@ -1,128 +0,0 @@ -/* -* -* Read and write demo of the AT24CX library -* Written by Christian Paul, 2014-11-24 -* -* -*/ - -// include libraries -#include -#include - -// EEPROM object -AT24CX mem; - -// setup -void setup() { - // serial init - Serial.begin(115200); - Serial.println("AT24CX read/write demo"); - Serial.println("----------------------"); -} - -// main loop -void loop() { - // read and write byte - Serial.println("Write 42 to address 12"); - mem.write(12, 42); - Serial.println("Read byte from address 12 ..."); - byte b = mem.read(12); - Serial.print("... read: "); - Serial.println(b, DEC); - Serial.println(); - - // read and write integer - Serial.println("Write 65000 to address 15"); - mem.writeInt(15, 65000); - Serial.println("Read integer from address 15 ..."); - unsigned int i = mem.readInt(15); - Serial.print("... read: "); - Serial.println(i, DEC); - Serial.println(); - - // read and write long - Serial.println("Write 3293732729 to address 20"); - mem.writeLong(20, 3293732729UL); - Serial.println("Read long from address 20 ..."); - unsigned long l = mem.readLong(20); - Serial.print("... read: "); - Serial.println(l, DEC); - Serial.println(); - - // read and write long - Serial.println("Write 1111111111 to address 31"); - mem.writeLong(31, 1111111111); - Serial.println("Read long from address 31 ..."); - unsigned long l2 = mem.readLong(31); - Serial.print("... read: "); - Serial.println(l2, DEC); - Serial.println(); - - // read and write float - Serial.println("Write 3.14 to address 40"); - mem.writeFloat(40, 3.14); - Serial.println("Read float from address 40 ..."); - float f = mem.readFloat(40); - Serial.print("... read: "); - Serial.println(f, DEC); - Serial.println(); - - // read and write double - Serial.println("Write 3.14159265359 to address 50"); - mem.writeDouble(50, 3.14159265359); - Serial.println("Read double from address 50 ..."); - double d = mem.readDouble(50); - Serial.print("... read: "); - Serial.println(d, DEC); - Serial.println(); - - // read and write char - Serial.print("Write chars: '"); - char msg[] = "This is a message"; - Serial.print(msg); - Serial.println("' to address 200"); - mem.writeChars(200, msg, sizeof(msg)); - Serial.println("Read chars from address 200 ..."); - char msg2[30]; - mem.readChars(200, msg2, sizeof(msg2)); - Serial.print("... read: '"); - Serial.print(msg2); - Serial.println("'"); - Serial.println(); - - // write array of bytes - Serial.println("Write array of 80 bytes at address 1000"); - byte xy[] = {0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9, // 10 x 3 = 30 - 10,11,12,13,14,15,16,17,18,19, // 10 - 120,121,122,123,124,125,126,127,128,129, // 10 - 130,131,132,133,134,135,136,137,138,139, // 10 - 200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219}; // 20 - mem.write(1000, (byte*)xy, sizeof(xy)); - - // read bytes with multiple steps - Serial.println("Read 80 single bytes starting at address 1000"); - for (int i=0; i for definitons and differences. - -Written by Christian Paul, 2014 - 2015. -This software is released under the terms of the MIT license. -See the file LICENSE or LIZENZ for details, please. - -You can use any of the eight possibles EEPROM devices on the I2C bus. - -Constructor - - AT24CX(byte pageSize); - -uses the device with index 0 and given page size. You can select a device with given index between 0 and 8 with constructor - - AT24CX(byte index, byte pageSize); - -Than, you can single write or read single bytes from the EEPROM with - - void write(unsigned int address, byte data); - byte read(unsigned int address); - -or write and read an array of bytes with - - void write(unsigned int address, byte *data, int n); - void read(unsigned int address, byte *data, int n); - -For writing integers, long, float, double or sequences of chars you can use the comfort functions - - void writeInt(unsigned int address, unsigned int data); - void writeLong(unsigned int address, unsigned long data); - void writeFloat(unsigned int address, float data); - void writeDouble(unsigned int address, double data); - void writeChars(unsigned int address, char *data, int length); - -Reading the values is done by using - - unsigned int readInt(unsigned int address); - unsigned long readLong(unsigned int address); - float readFloat(unsigned int address); - double readDouble(unsigned int address); - void readChars(unsigned int address, char *data, int n); - -Alternative you can use the individual classes with predefined page sizes: - - AT24C32(); - AT24C64(); - AT24C128(); - AT24C256(); - AT24C512(); - -or with different index than 0: - - AT24C32(byte index); - AT24C64(byte index); - AT24C128(byte index); - AT24C256(byte index); - AT24C512(byte index); - diff --git a/lib/AT24Cx/library.properties b/lib/AT24Cx/library.properties deleted file mode 100644 index 24d962201..000000000 --- a/lib/AT24Cx/library.properties +++ /dev/null @@ -1,11 +0,0 @@ -name=AT24CX -version=0.0.1 -author=Christian Paul -maintainer=Christian Paul -sentence=Arduino library for AT24Cx EEPROM storage devices. -paragraph= -category=Sensors -url=https://github.com/cyberp/AT24Cx -architectures=* -includes=AT24CX.h -depends= diff --git a/lib/Adafruit_RTClib/src/RTClib.h b/lib/Adafruit_RTClib/src/RTClib.h index fb7d78103..e89d1da3a 100644 --- a/lib/Adafruit_RTClib/src/RTClib.h +++ b/lib/Adafruit_RTClib/src/RTClib.h @@ -300,7 +300,7 @@ public: void writenvram(uint8_t address, uint8_t *buf, uint8_t size); protected: - TwoWire *RTCWireBus; + TwoWire *RTCWireBus = nullptr; }; /** DS3231 SQW pin mode settings */ @@ -362,7 +362,7 @@ public: void writenvram(uint8_t address, uint8_t *buf, uint8_t size); protected: - TwoWire *RTCWireBus; + TwoWire *RTCWireBus = nullptr; }; /** PCF8523 INT/SQW pin mode settings */ @@ -433,7 +433,7 @@ public: void calibrate(Pcf8523OffsetMode mode, int8_t offset); protected: - TwoWire *RTCWireBus; + TwoWire *RTCWireBus = nullptr; }; /** PCF8563 CLKOUT pin mode settings */ @@ -464,7 +464,7 @@ public: void writeSqwPinMode(Pcf8563SqwPinMode mode); protected: - TwoWire *RTCWireBus; + TwoWire *RTCWireBus = nullptr; }; /**************************************************************************/ @@ -487,7 +487,7 @@ public: void writenvram(uint8_t address, uint8_t *buf, uint8_t size); protected: - TwoWire *RTCWireBus; + TwoWire *RTCWireBus = nullptr; uint8_t _addr = PCF8583_ADDRESS; }; diff --git a/lib/arduino-library-at24cxxx/LICENSE b/lib/arduino-library-at24cxxx/LICENSE new file mode 100644 index 000000000..29f81d812 --- /dev/null +++ b/lib/arduino-library-at24cxxx/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/lib/arduino-library-at24cxxx/README.md b/lib/arduino-library-at24cxxx/README.md new file mode 100644 index 000000000..1f3373ce9 --- /dev/null +++ b/lib/arduino-library-at24cxxx/README.md @@ -0,0 +1,137 @@ +# AT24C Two-wire Serial EEPROM Library +This is an Arduino library for using the AT24C-series serial persistant memory chips. The library supports the following chips: +* AT24C01 - 128 bytes +* AT24C02 - 256 bytes +* AT24C04 - 512 bytes +* AT24C08 - 1024 bytes +* AT24C16 - 2048 bytes +* AT24C32 - 4096 bytes +* AT24C64 - 8192 bytes +* AT24C128 - 16384 bytes +* AT24C256 - 32768 bytes + +The library interface is drop in compatible with the Arduino built in EEPROM API, so code written for the internal EEPROM will work with this library without modification. + +The library has the following features: +* Uses the page write feature of the AT24C chips which is up to 64 times faster than doing single byte writes and reduces wear on the memory cells. +* Keeps track of page sizes for the different chips and adjusts writes to page borders +* Handles the Write Cycle Time of the chips, avoiding the risk of trying to access the chip while it is busy processing an earlier write +* Can read and write arbitrarily long buffers, managing limitations of buffer sizes in I2C libraries +* Transparent error handling making it easy to detect errors in the communication with the chip (very useful in early stages of a project) +* Can read and write basic types and structs directly + +# Examples + +## Setting up +You need to include the .h file for the chip type you are using and create a chip-object with the address it is configured at. There are constants defined for all eight possible addresses of the chip, AT24C_ADDRESS_0 - AT24C_ADDRESS_7. Since the I2C-bus is used, you also have to start the Wire-interface: +```C++ +#include + +AT24C256 eprom(AT24C_ADDRESS_0); + +void setup() { + Wire.begin(); + + uint8_t byte = eprom.read(0); +} +``` + +## Reading and writing basic types +All basic types, such as int, long, double can be read or written with the `put` and `get` methods. You just specify the memory address and the variable to read or write: +```C++ +int foo = 42; +eprom.put(0, foo); // Write the integer value 42 to address 0 +int foo_in; +eprom.get(0, foo_in); // Read the integer value at address 0 into variable foo_in +``` +## Reading and writing complex types +Also complex types, such as structs can be read or written with the `put` and `get` methods: +```C++ +struct Coordinate { + int x; + int y; +}; + +Coordinate point = {17, 42}; +eprom.put(0, point); // Write the struct point to address 0 +Coordinate point_in; +eprom.get(0, point_in); // Read the values of the struct point_in from address 0 +``` +## Reading and writing byte buffers +Byte buffers of any length (that fits the memory) can be read and written. The library handles limitations in the underlying I2C libraris so the reads and writes are partitioned in small enough chunks: +```C++ +uint8_t out[15] = "Test of buffer"; +eprom.writeBuffer(0, out, 15); +uint8_t in[15]; +eprom.readBuffer(0, in, 15); +``` +## Reading raw bytes +The library can also read write and update single bytes: +```C++ +eprom.write(0, 77); // Writes the value 77 to byte at address 0 +eprom.update(0, 77); // In this case `update` does nothing, since it only writes if the value differs from the current +uint8_t value = eprom.read(0); // Reads the value of the byte at address 0 +``` +## Connecting multiple chips +The libray allows you to create multiple chips (also of different types). You just have to create an object for each chip of the right type: +```C++ +#include +#include + +AT24C256 eprom0(AT24C_ADDRESS_0); +AT24C256 eprom1(AT24C_ADDRESS_1); +AT24C02 eprom2(AT24C_ADDRESS_2); + +void setup() { + Wire.begin(); + + uint8_t byte = eprom0.read(0); +} +``` +## Error handling +Since this is an external memory chip that is connected through the I2C-bus, there is always a risk that the communication failes, due to physical errors in the setup. You can always check if the latest operation succeeded via the `getLastError()` method: +```C++ +uint8_t data = eprom.read(0); +if (eprom.getLastError() != 0) { + Serial.print("Error reading from eeprom"); +} +``` +Value 0 means no error, 1 means internal buffer overflow, 2 means NACK when addressing the chip and this is the error you will get if a chip is not connected to the specified address. + +It is good practice to check for error at least once in setup so you get early feedback if there is a bad connection to the chip. +## Specifying TwoWire interface +Some Arduino boards have multiple I2C busses. The library allows you to specify which TwoWire bus to use for each chip object: +```C++ +#include + +AT24C256 eprom0(AT24C_ADDRESS_0, Wire); +``` +## Specifying Write Cycle Time +The library waits for the chip to process a write (write cycle time). The default time is 6 mS, which with some margin covers the standard 5 mS specified for the chips. However some old versions of AT24C256A may have up to 20 mS write cycle time, and in that case you can specify a higher time for a chip: +```C++ +#include + +AT24C256 eprom0(AT24C_ADDRESS_0, Wire, 20); +``` +If your application is really time critical and you only write single bytes, you can also set the write cycle time to 0 to avoid the internal wait. I that case you have to keep track on that your application does not try to access the chip too fast after a write operation. +## Getting the size of a chip +To be compatible with the built in EEPROM library, this library can also return the size of the memory chip. This makes it possible for your code automatically to adapt to different chip types: +```C++ +int size = eprom.length()); +``` +## Limitations on chips +Some of the at24c chips have limitations in how many i2c addresses are available for the chips: +* AT24C04 has 4 addresses +* AT24C08 has 2 addresses +* AT24C16 has only 1 hardcoded address + +Because of this, AT24C04 and AT24C08 have their own address enums and the AT24C16 does not have an address parameter in the constructor. +```C++ +#include +#include +#include + +AT24C04 eprom0(AT24C04_ADDRESS_1); +AT24C08 eprom1(AT24C08_ADDRESS_1); +AT24C16 eprom2(); +``` diff --git a/lib/arduino-library-at24cxxx/arduino-library-at24cxxx.ino b/lib/arduino-library-at24cxxx/arduino-library-at24cxxx.ino new file mode 100644 index 000000000..f35fad497 --- /dev/null +++ b/lib/arduino-library-at24cxxx/arduino-library-at24cxxx.ino @@ -0,0 +1,161 @@ +/** + * These are the test cases to verify the functions of the API. + * They are made to run on the target device with a at24c250 on address 0 + * + * Because of the Arduino IDEs limitations in including and placing files + * This file has to be placed here. + */ + +#include +#include "src/at24c256.h" // trigger compilation of the source directory + +AT24C256 eprom(AT24C_ADDRESS_0); +AT24C256 badEprom(AT24C_ADDRESS_7); + +#define NO_ERROR (0) +#define ADDRESS_NACK (2) +#define AT24C256_LENGTH ((uint16_t)32768) + +int memoryPosition = 0; +int8_t buffer[1024]; + +// Spread out the test values a bit in memory to spread out ware +int getNextMemoryPosition() { + memoryPosition += 2; + return memoryPosition; +} + +test(writeAndReadByte) { + int pos = getNextMemoryPosition(); + uint8_t in = 19; + eprom.write(pos, in); + assertEqual(eprom.getLastError(), NO_ERROR); + uint8_t out = eprom.read(pos); + assertEqual(eprom.getLastError(), NO_ERROR); + assertEqual(in, out); +} + +test(updateAndReadByte) { + int pos = getNextMemoryPosition(); + uint8_t in = 42; + eprom.update(pos, in); + assertEqual(eprom.getLastError(), NO_ERROR); + uint8_t out = eprom.read(pos); + assertEqual(eprom.getLastError(), NO_ERROR); + assertEqual(in, out); +} + +test(putIntAndGetBack) { + int pos = getNextMemoryPosition(); + int in = 17; + eprom.put(pos, in); + assertEqual(eprom.getLastError(), NO_ERROR); + int out; + eprom.get(pos, out); + assertEqual(eprom.getLastError(), NO_ERROR); + assertEqual(in, out); +} + +test(putDoubleAndGetBack) { + int pos = getNextMemoryPosition(); + double pi = 3.141593; + eprom.put(pos, pi); + assertEqual(eprom.getLastError(), NO_ERROR); + double pi_in; + eprom.get(pos, pi_in); + assertEqual(eprom.getLastError(), NO_ERROR); + assertEqual(pi_in, pi); +} + +test(getLength) { + assertEqual(eprom.length(), AT24C256_LENGTH); +} + +test(badAddressErrorBusWorksAfter) { + int pos = getNextMemoryPosition(); + uint8_t in = 19; + assertEqual(badEprom.getLastError(), NO_ERROR); + badEprom.write(pos, in); + assertEqual(badEprom.getLastError(), ADDRESS_NACK); + // Verify bus is still ok after error + eprom.write(pos, in); + assertEqual(eprom.getLastError(), NO_ERROR); +} + + +test(writeAndReadSmallBuffer) { + int8_t out[15] = "Test of buffer"; + int lenw = eprom.writeBuffer(0, out, 15); + assertEqual(lenw, 15); + assertEqual(eprom.getLastError(), NO_ERROR); + + uint8_t in[15]; + int lenr = eprom.readBuffer(0, in, 15); + assertEqual(lenr, 15); + assertEqual(eprom.getLastError(), NO_ERROR); + + assertEqual((char*)in, (char*)out); +} + +test(writeBufferAtBadAddress) { + int8_t out[15] = "Test of buffer"; + int lenw = badEprom.writeBuffer(0, out, 15); + assertEqual(lenw, 0); + assertEqual(badEprom.getLastError(), ADDRESS_NACK); +} + +test(writeAndRead256Buffer) { + for (int i = 0; i < 255; i++) { + buffer[i] = 'a' + (i % 26); + } + buffer[255] = 0; + int lenw = eprom.writeBuffer(0, buffer, 256); + assertEqual(lenw, 256); + assertEqual(eprom.getLastError(), NO_ERROR); + + for (int i = 0; i < 255; i++) { + buffer[i] = '0'; + } + + int lenr = eprom.readBuffer(0, buffer, 256); + assertEqual(lenr, 256); + assertEqual(eprom.getLastError(), NO_ERROR); + + for (int i = 0; i < 255; i++) { + assertEqual(buffer[i], (uint8_t)('a' + (i % 26))); + } +} + +test(writeAndRead1024Buffer) { + for (int i = 0; i < 1023; i++) { + buffer[i] = 'a' + (i % 26); + } + buffer[1023] = 0; + int lenw = eprom.writeBuffer(0, buffer, 1024); + assertEqual(lenw, 1024); + assertEqual(eprom.getLastError(), NO_ERROR); + + for (int i = 0; i < 1023; i++) { + buffer[i] = '0'; + } + + int lenr = eprom.readBuffer(0, buffer, 1024); + assertEqual(lenr, 1024); + assertEqual(eprom.getLastError(), NO_ERROR); + + for (int i = 0; i < 1023; i++) { + assertEqual(buffer[i], (uint8_t)('a' + (i % 26))); + } +} + +void setup() { + Serial.begin(115200); + Wire.begin(); + Serial.println(F("\n\nModule test for eeprom driver\n")); +} + +void loop() { + aunit::TestRunner::run(); +} + + diff --git a/lib/arduino-library-at24cxxx/examples/example/example.ino b/lib/arduino-library-at24cxxx/examples/example/example.ino new file mode 100644 index 000000000..611b13070 --- /dev/null +++ b/lib/arduino-library-at24cxxx/examples/example/example.ino @@ -0,0 +1,125 @@ +/** + * This sketch shows examples on how to use all the features of this library + * + * It can also be used as a test to verify that you have your eprom configured + * propery to your Arduino as it prints out the results so you can see if everything works + */ + +#include + +// Create a eprom object configured at address 0 +// Sketch assumes that there is an eprom present at this address +AT24C256 eprom(AT24C_ADDRESS_0); +// Create another eprom object configured att address 2 +// Sketch assumes that there is NO eprom present at this address +AT24C256 badEprom(AT24C_ADDRESS_2); + +void setup() { + Serial.begin(115200); + Serial.println("Starting up"); + + // Initialize the i2c library + Wire.begin(); + + /** Write and read an integer */ + int foo = 42; + // Write the integer foo to the eprom starting at address 0 + eprom.put(0, foo); + int foo_in; + // Read the integer foo_in from eprom starting at address 0 + eprom.get(0, foo_in); + Serial.println(foo_in); + + /** Write and read a double */ + double pi = 3.141593; + // Write the double pi to the eprom starting at address 0 + eprom.put(0, pi); + double pi_in; + // Read the double pi_in from eprom starting at address 0 + eprom.get(0, pi_in); + // Create a buffer and convert pi_in to a string to be able to print it + char buffer[10]; + dtostrf(pi_in, 9, 6, buffer); // Converts a double to a string + Serial.println(buffer); + + /** Write and read a struct */ + // Declare the struct "Point" + struct Point { + int x; + int y; + }; + Point point = {17, 42}; + // Write the struct point to the eprom starting at address 0 + eprom.put(0, point); + Point point_in; + // Read the struct point_in from eprom starting at address 0 + eprom.get(0, point_in); + Serial.println(point_in.x); + Serial.println(point_in.y); + + /** Write and read a single byte */ + // Write the value 77 to the eprom byte at address 0 + eprom.write(0, 77); + // Read the value of the byte at address 0 + int value = eprom.read(0); + Serial.println(value); + + /** Write and read a byte buffer */ + uint8_t out[15] = "Test of buffer"; + // Write the 15 bytes long buffer "out" to eprom starting at address 0 + eprom.writeBuffer(0, out, 15); + uint8_t in[15]; + // Read 15 bytes from eprom starting at address 0 into the buffer "in". + eprom.readBuffer(0, in, 15); + Serial.println((char*)in); + + /** Error handling on write, no error */ + // Read a byte from address 0, this should not result in an error + eprom.write(0, 77); + // Get the last error code, it should be 0 since there was no error + int lastError = eprom.getLastError(); + Serial.print("last status on write: "); + Serial.println(lastError); + + /** Error handling on write, using a eprom address without eprom */ + // Write the value 77 to an eprom that is not connected - this will fail + badEprom.write(0, 77); + // Get the last error code, it should not be zero, but 2 which means that there were no response from the eprom + int lastError2 = badEprom.getLastError(); + Serial.print("last error on write: "); + Serial.println(lastError2); + + /** Error handling on read, using a eprom address without eprom */ + // Read the value from address 0 from an eprom that is not connected (and print it) + badEprom.read(0); + // Get the last error code, it should not be zero, but 2 which means that there were no response from the eprom + int lastError3 = badEprom.getLastError(); + Serial.print("last error on read: "); + Serial.println(lastError3); + + // Read the size of the eprom and print it + Serial.println(eprom.length()); + + /** Write and read a long byte buffer, >32 which is TwoWire's internal buffer size and + * >64 which is the at24c256 page size) */ + uint8_t out2[80] = "Writing a really long message, testing some of several buffer limits on the way"; + // Write the long buffer to the eprom starting at address 0 and check how many bytes were actually written + int written = eprom.writeBuffer(0, out2, 80); + Serial.print(written); + Serial.print(" bytes written, last error on write: "); + // Get the last error and print it + Serial.println(eprom.getLastError()); + uint8_t in2[80]; + // Read 80 bytes from eprom starting at address 0 and store it in the in2 buffer. Check how many bytes were actually read + int readBytes = eprom.readBuffer(0, in2, 80); + Serial.print(readBytes); + Serial.print(" bytes read, last error on read: "); + // Get the last error and print it + Serial.println(eprom.getLastError()); + in2[79] = '\0'; + Serial.println((char*)in2); +} + +// This test program has no loop, it just runs once +void loop() { +} diff --git a/lib/arduino-library-at24cxxx/keywords.txt b/lib/arduino-library-at24cxxx/keywords.txt new file mode 100644 index 000000000..5a5b07351 --- /dev/null +++ b/lib/arduino-library-at24cxxx/keywords.txt @@ -0,0 +1,40 @@ +####################################### +# Syntax Coloring Map For AT24C +####################################### +# Class +####################################### + +AT24C01 KEYWORD3 +AT24C02 KEYWORD3 +AT24C04 KEYWORD3 +AT24C08 KEYWORD3 +AT24C16 KEYWORD3 +AT24C32 KEYWORD3 +AT24C64 KEYWORD3 +AT24C128 KEYWORD3 +AT24C256 KEYWORD3 + +####################################### +# Methods and Functions +####################################### + +read KEYWORD2 +write KEYWORD2 +update KEYWORD2 +length KEYWORD2 +writeBuffer KEYWORD2 +readBuffer KEYWORD2 +getLastError KEYWORD2 + +####################################### +# Constants +####################################### + +AT24C_ADDRESS_0 LITERAL1 +AT24C_ADDRESS_1 LITERAL1 +AT24C_ADDRESS_2 LITERAL1 +AT24C_ADDRESS_3 LITERAL1 +AT24C_ADDRESS_4 LITERAL1 +AT24C_ADDRESS_5 LITERAL1 +AT24C_ADDRESS_6 LITERAL1 +AT24C_ADDRESS_7 LITERAL1 diff --git a/lib/arduino-library-at24cxxx/library.properties b/lib/arduino-library-at24cxxx/library.properties new file mode 100644 index 000000000..d46a567f2 --- /dev/null +++ b/lib/arduino-library-at24cxxx/library.properties @@ -0,0 +1,10 @@ +name=AT24C +version=1.2.2 +author=Stefan Stromberg +maintainer=Stefan Stromberg +sentence=A library for using the AT24C series i2c serial eeproms. +paragraph=Supports the chips AT24C01, AT24C02, AT24C04, AT24C08, AT24C16, AT24C32, AT24C64, AT24C128 and AT24C256. The interface is compatible with the Arduino built in eeprom interface and supports fast page writes, handles write cycle timing and error reporting. The library has simple read/write methods for built in types and structs and cn also read and write large byte buffers efficiently. +category=Data Storage +url=https://github.com/stefangs/arduino-library-at24cxxx +architectures=* +includes=at24cxxx.h,at24c01.h,at24c02.h,at24c04.h,at24c08.h,at24c16.h,at24c32.h,at24c64.h,at24c128.h,at24c256.h diff --git a/lib/arduino-library-at24cxxx/src/at24c01.h b/lib/arduino-library-at24cxxx/src/at24c01.h new file mode 100644 index 000000000..91a71230c --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c01.h @@ -0,0 +1,19 @@ +#ifndef AT24C01_H +#define AT24C01_H + +#include "at24cxxx.h" + +class AT24C01 : public AT24Cxxx { + + public: + AT24C01(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 128, 8) {} + + protected: + virtual void writeAddress(uint16_t address) override { + twoWire->beginTransmission(i2cAddress); + twoWire->write((uint8_t)(address & 0xFF)); + } +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c02.h b/lib/arduino-library-at24cxxx/src/at24c02.h new file mode 100644 index 000000000..d18f7f9bc --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c02.h @@ -0,0 +1,20 @@ +#ifndef AT24C02_H +#define AT24C02_H + +#include "at24cxxx.h" + +class AT24C02 : public AT24Cxxx { + + public: + AT24C02(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 256, 8) {} + + protected: + virtual void writeAddress(uint16_t address) override { + twoWire->beginTransmission(i2cAddress); + twoWire->write((uint8_t)(address & 0xFF)); + } + +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c04.h b/lib/arduino-library-at24cxxx/src/at24c04.h new file mode 100644 index 000000000..e9e7776f7 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c04.h @@ -0,0 +1,30 @@ +#ifndef AT24C04_H +#define AT24C04_H + +#include "at24cxxx.h" + +// Valid addresses for AT24C04 +#define AT24C04_ADDRESS_0 (0x50) +#define AT24C04_ADDRESS_1 (0x52) +#define AT24C04_ADDRESS_2 (0x54) +#define AT24C04_ADDRESS_3 (0x56) + +class AT24C04 : public AT24Cxxx { + + public: + AT24C04(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 512, 16) { + } + + protected: + virtual void writeAddress(uint16_t address) override { + // AT24C04 has 512 bytes, but only an 8-bit address parameter + // The 9th bit is sent in the lsb of the chip i2c address leaving + // only 2 bits (four addresses) to address chips. + twoWire->beginTransmission((uint8_t)((i2cAddress & 0xFE) | ((address >> 8) & 0x1))); + twoWire->write((uint8_t)(address & 0xFF)); + } + +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c08.h b/lib/arduino-library-at24cxxx/src/at24c08.h new file mode 100644 index 000000000..6ebb39f7a --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c08.h @@ -0,0 +1,27 @@ +#ifndef AT24C08_H +#define AT24C08_H + +#include "at24cxxx.h" + +// Valid addresses for AT24C08 +#define AT24C08_ADDRESS_0 (0x50) +#define AT24C08_ADDRESS_1 (0x54) + + +class AT24C08 : public AT24Cxxx { + + public: + AT24C08(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 1024, 16) {} + + protected: + virtual void writeAddress(uint16_t address) override { + // AT24C08 has 1024 bytes, but only an 8-bit address parameter + // The 9th and 01th bits are sent in the lsb of the chip i2c address leaving + // only 1 bit (two addresses) to address chips. + twoWire->beginTransmission((uint8_t)((i2cAddress & 0xFC) | ((address >> 8) & 0x03))); + twoWire->write((uint8_t)(address & 0xFF)); + } +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c128.h b/lib/arduino-library-at24cxxx/src/at24c128.h new file mode 100644 index 000000000..a14a658a0 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c128.h @@ -0,0 +1,13 @@ +#ifndef AT24C128_H +#define AT24C128_H + +#include "at24cxxx.h" + +class AT24C128 : public AT24Cxxx { + + public: + AT24C128(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 16384, 64) {} +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c16.h b/lib/arduino-library-at24cxxx/src/at24c16.h new file mode 100644 index 000000000..a4223d305 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c16.h @@ -0,0 +1,25 @@ +#ifndef AT24C16_H +#define AT24C16_H + +#include "at24cxxx.h" + +// Note that the at24c16 has one fixed i2c address which cannot be altered +// so it does not have an address parameter +class AT24C16 : public AT24Cxxx { + + public: + AT24C16(TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(AT24C_ADDRESS_0, i2c, writeDelay, 2048, 16) {} + + protected: + virtual void writeAddress(uint16_t address) override { + // AT24C16 has 2048 bytes, but only an 8-bit address parameter + // The three most significant bits are sent in the chip's i2c address. + // Because of this the i2c address is hard-coded and only one chip can + // be used on an i2c bus + twoWire->beginTransmission((uint8_t)((i2cAddress & 0xF8) | ((address >> 8) & 0x07))); + twoWire->write((uint8_t)(address & 0xFF)); + } +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c256.h b/lib/arduino-library-at24cxxx/src/at24c256.h new file mode 100644 index 000000000..3e6c9ccc9 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c256.h @@ -0,0 +1,13 @@ +#ifndef AT24C256_H +#define AT24C256_H + +#include "at24cxxx.h" + +class AT24C256 : public AT24Cxxx { + + public: + AT24C256(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 32768, 64) {} +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c32.h b/lib/arduino-library-at24cxxx/src/at24c32.h new file mode 100644 index 000000000..5e48ba634 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c32.h @@ -0,0 +1,13 @@ +#ifndef AT24C32_H +#define AT24C32_H + +#include "at24cxxx.h" + +class AT24C32 : public AT24Cxxx { + + public: + AT24C32(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 4096, 32) {} +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24c64.h b/lib/arduino-library-at24cxxx/src/at24c64.h new file mode 100644 index 000000000..6a505976b --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24c64.h @@ -0,0 +1,13 @@ +#ifndef AT24C64_H +#define AT24C64_H + +#include "at24cxxx.h" + +class AT24C64 : public AT24Cxxx { + + public: + AT24C64(uint8_t address, TwoWire& i2c = Wire, uint8_t writeDelay = 6) : + AT24Cxxx(address, i2c, writeDelay, 8192, 32) {} +}; + +#endif diff --git a/lib/arduino-library-at24cxxx/src/at24cxxx.cpp b/lib/arduino-library-at24cxxx/src/at24cxxx.cpp new file mode 100644 index 000000000..4d4d80d81 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24cxxx.cpp @@ -0,0 +1,142 @@ + +#include "at24cxxx.h" +#include "Arduino.h" + +constexpr size_t MAX_ALLOWED_LEN_IN_REQUESTFROM = 255; + +AT24Cxxx::AT24Cxxx(uint8_t address, TwoWire& i2c, int writeDelay, size_t size, uint8_t pageSize) : + i2cAddress(address), twoWire(&i2c), size(size), writeDelay(writeDelay), pageSize(pageSize) { +} + +uint8_t +AT24Cxxx::read( int idx ){ + uint8_t result; + readBuffer(idx, &result, 1); + return result; +} + +void +AT24Cxxx::write( int idx, uint8_t val){ + uint8_t data = val; + writeBuffer(idx, &data, 1); +} + +void +AT24Cxxx::update( int idx, uint8_t val){ + if (val != read(idx)) { + write(idx, val); + } +} + +size_t +AT24Cxxx::length() { + return size; +} + + uint8_t + AT24Cxxx::getLastError() { + return lastError; + } + +// Writes both the chip address and the memory address to the I2C bus. +// Since the way this is done varies between the different chips, this +// function is extracted as a virtual template method which can be overridden +// by the different chips. +void +AT24Cxxx::writeAddress(uint16_t address){ + twoWire->beginTransmission(i2cAddress); + twoWire->write((uint8_t)((address >> 8) & 0xFF)); + twoWire->write((uint8_t)(address & 0xFF)); +} + +int +AT24Cxxx::rawWriteBuffer(size_t address, const uint8_t* data, size_t len) { + lastError = 0; + writeAddress(address); + size_t written = 0; + for (written = 0; written < len; written++) { + // Not using twoWire's built in buffer write since it hides errors from write. + if (twoWire->write(data[written]) != 1) { + // An error here (not 1) indicates that we have reached the end of the + // internal write buffer, so no more data can be written. + // Stop filling the buffer, write what we got and return the number written + break; + } + } + lastError = twoWire->endTransmission(); + // The AT24Cxxx chips needs 5-20 ms time after write (tWR Write Cycle Time) + // to become available again for new operations. + // It is possible to poll the chip to ask if it is ready, but this is hard to + // do through the TwoWire-API, so instead we just do a hard wait to ensure + // that the chip is available again before we finish the operation. + delay(writeDelay); + return lastError == 0 ? written : 0; +} + +int +AT24Cxxx::writeBuffer(size_t address, const uint8_t* data, size_t len){ + const uint8_t* dataToWrite = data; + size_t lenRemaining = len; + size_t nextAddress = address; + int totalWritten = 0; + size_t numberOfWrites = 0; + do { + // Since page write to the AT24Cxxx chips only works within the pages + // we must make sure to split our writes on page borders. + // Therefore we start by finding out how far it is to the next page + // border and only write as many bytes in one write operation. + uint16_t locationOnPage = nextAddress % pageSize; + size_t maxBytesToWrite = pageSize - locationOnPage; + size_t bytesToWrite = min(maxBytesToWrite, lenRemaining); + // Note, due to other internal buffer sizes in the TwoWire libraries + // we may not be able to write the whole message. Therefore we keep track + // on how many bytes were actually written and use that number when + // calculating what to write next + size_t written = rawWriteBuffer(nextAddress, dataToWrite, bytesToWrite); + if (getLastError() != 0) { + // If we got a hard error from the TwoWire bus, there is no point to continue + break; + } + totalWritten += written; + lenRemaining -= written; + dataToWrite += written; + nextAddress += written; + } while ((lenRemaining > 0) && (++numberOfWrites < len)); + return totalWritten; +} + +int +AT24Cxxx::readBuffer(size_t address, uint8_t* data, size_t len){ + lastError = 0; + uint8_t* dataPointer = data; + size_t lenRemaining = len; + size_t nextAddress = address; + int totalread = 0; + uint8_t numberOfReads = 0; + if (len == 0) { + return 0; + } + do { + // Since underlying layers will limit how many bytes we can actually read + // in one go, we will try to read as many as possible, but see from the + // result how many were actually read, and make multiple reads until + // we have all data. + writeAddress(nextAddress); + lastError = twoWire->endTransmission(); + if (lastError != 0) { + // If we got a hard error from the TwoWire bus, there is no point to continue + break; + } + size_t bytesToRead = min(lenRemaining, MAX_ALLOWED_LEN_IN_REQUESTFROM); + size_t readBytes = twoWire->requestFrom(i2cAddress, bytesToRead); + size_t byteNumber; + for(byteNumber = 0; (byteNumber < readBytes) && twoWire->available(); byteNumber++){ + dataPointer[byteNumber] = twoWire->read(); + } + totalread += byteNumber; + lenRemaining -= byteNumber; + dataPointer += byteNumber; + nextAddress += byteNumber; + } while ((lenRemaining > 0) && (++numberOfReads < len)); + return totalread; +} diff --git a/lib/arduino-library-at24cxxx/src/at24cxxx.h b/lib/arduino-library-at24cxxx/src/at24cxxx.h new file mode 100644 index 000000000..18ef7b151 --- /dev/null +++ b/lib/arduino-library-at24cxxx/src/at24cxxx.h @@ -0,0 +1,63 @@ + +#ifndef AT24CXXX_H +#define AT24CXXX_H + +/** + * 2026-08-19 tonhuisman: Updated to allow use of AT24C512, AT24C1024 and AT24C2048 by changing uint16_t argments to size_t + */ +#include "Wire.h" + +#define AT24C_ADDRESS_0 (0x50) +#define AT24C_ADDRESS_1 (0x51) +#define AT24C_ADDRESS_2 (0x52) +#define AT24C_ADDRESS_3 (0x53) +#define AT24C_ADDRESS_4 (0x54) +#define AT24C_ADDRESS_5 (0x55) +#define AT24C_ADDRESS_6 (0x56) +#define AT24C_ADDRESS_7 (0x57) + +class AT24Cxxx { + + public: + AT24Cxxx(uint8_t address, TwoWire& i2c, int writeDelay, size_t size, uint8_t pageSize); + uint8_t read( int idx ); + void write( int idx, uint8_t val); + void update( int idx, uint8_t val); + size_t length(); + int writeBuffer(size_t address, const uint8_t* data, size_t len); + int readBuffer(size_t address, uint8_t* data, size_t len); + /** + * Returns result from the last performed operation. + * The meaning of the values are: + * 0 .. success + * 1 .. length to long for buffer + * 2 .. address send, NACK received - typically means no device at the address + * 3 .. data send, NACK received + * 4 .. other twi error (lost bus arbitration, bus error, ..) + */ + uint8_t getLastError(); + + template< typename T > T &get( int idx, T &t ){ + readBuffer(idx, (uint8_t*)&t, sizeof(T)); + return t; + } + + template< typename T > const T &put( int idx, const T &t ){ + writeBuffer(idx, (uint8_t*)&t, sizeof(T)); + return t; + } + + protected: + virtual void writeAddress(uint16_t address); + uint8_t i2cAddress; + TwoWire* twoWire; + + private: + int rawWriteBuffer(size_t address, const uint8_t* data, size_t len); + size_t size; + uint8_t writeDelay; + uint8_t lastError; + uint8_t pageSize; +}; + +#endif diff --git a/platformio_esp82xx_base.ini b/platformio_esp82xx_base.ini index 0df18db4f..629cfd0ab 100644 --- a/platformio_esp82xx_base.ini +++ b/platformio_esp82xx_base.ini @@ -410,7 +410,7 @@ lib_ignore = ESP32_ping htcw_ip5306 ld2410 supertinycron - AT24CX + AT24C ;lib_ignore = ${esp82xx_1M.lib_ignore} ; Adding the libs below to the lib_ignore will even increase build size ; Adafruit TCS34725 diff --git a/src/ESPEasy/eeprom/Helpers/EEPROMExternal.cpp b/src/ESPEasy/eeprom/Helpers/EEPROMExternal.cpp index 6fd2bf331..cb6ae6dc5 100644 --- a/src/ESPEasy/eeprom/Helpers/EEPROMExternal.cpp +++ b/src/ESPEasy/eeprom/Helpers/EEPROMExternal.cpp @@ -10,7 +10,7 @@ namespace ESPEasy { namespace eeprom { -AT24CX *EEPROMExternal = nullptr; +AT24Cxxx *EEPROMExternal = nullptr; EEPROMExternal_WriteProtect_e EEPROMExternalWriteProtect = EEPROMExternal_WriteProtect_e::Undefined; bool EEPROMParamsOkState{}; LongTermTimer EEPROMParamsOkTimer; @@ -35,9 +35,10 @@ void initializeEEPROMExternal() { if (ESPEasy::eeprom::selectEEPROMI2CBusAndMultiplexer()) { // Switch to I2C Bus and multiplexer channel of External EEPROM // We have an I2C device at this address, let's assume it's an EEPROM... - uint8_t pageSize = 0; - const uint32_t eepromSize = ESPEasy::eeprom::getEEPROMSize(eepromType, pageSize); - ESPEasy::eeprom::EEPROMExternal = new (std::nothrow) AT24CX(eepromAddress, pageSize, eepromSize); + uint8_t pageSize = 0; + uint8_t delay = 0; + const size_t eepromSize = ESPEasy::eeprom::getEEPROMSize(eepromType, pageSize, delay); + ESPEasy::eeprom::EEPROMExternal = new (std::nothrow) AT24Cxxx(eepromAddress, Wire, delay, eepromSize, pageSize); if (nullptr != ESPEasy::eeprom::EEPROMExternal) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -91,7 +92,8 @@ bool validateEEPROMExternalParameters(bool force) { // result return EEPROMParamsOkState; } - const uint16_t eepromVersionParam = EEPROMExternal->readInt(EEPROM_PARAMS_VERSION_ADDRESS); + const uint16_t eepromVersionParam{}; + EEPROMExternal->get(EEPROM_PARAMS_VERSION_ADDRESS, eepromVersionParam); EEPROMParamsOkTimer.setNow(); EEPROMParamsOkState = false; @@ -108,10 +110,12 @@ bool validateEEPROMExternalParameters(bool force) { * - Version */ void updateEEPROMExternalParameters() { - const uint16_t eepromVersionParam = EEPROMExternal->readInt(EEPROM_PARAMS_VERSION_ADDRESS); + const uint16_t eepromVersionParam{}; + + EEPROMExternal->get(EEPROM_PARAMS_VERSION_ADDRESS, eepromVersionParam); if (EEPROM_PARAMS_CURRENT_VERSION != eepromVersionParam) { - EEPROMExternal->writeInt(EEPROM_PARAMS_VERSION_ADDRESS, EEPROM_PARAMS_CURRENT_VERSION); + EEPROMExternal->put(EEPROM_PARAMS_VERSION_ADDRESS, (uint16_t)EEPROM_PARAMS_CURRENT_VERSION); } } @@ -205,7 +209,7 @@ uint8_t selectEEPROMI2CBusAndMultiplexer() { /** * EEPROM size in bytes */ -uint32_t getEEPROMSize(EEPROMExternal_Type_e type) { +size_t getEEPROMSize(EEPROMExternal_Type_e type) { switch (type) { case EEPROMExternal_Type_e::AT24C256: @@ -240,33 +244,40 @@ uint32_t getEEPROMSize(EEPROMExternal_Type_e type) { /** * EEPROM pagesize in bytes */ -uint32_t getEEPROMSize(EEPROMExternal_Type_e type, - uint8_t & pageSize) { +size_t getEEPROMSize(EEPROMExternal_Type_e type, + uint8_t & pageSize, + uint8_t & delay) { pageSize = (uint8_t)0; + delay = (uint8_t)0; // ms switch (type) { case EEPROMExternal_Type_e::AT24C256: - case EEPROMExternal_Type_e::MB85RC256: case EEPROMExternal_Type_e::AT24C128: + delay = (uint8_t)6; // fall through + case EEPROMExternal_Type_e::MB85RC256: case EEPROMExternal_Type_e::MB85RC128: pageSize = (uint8_t)64; break; # if EEPROM_SUPPORT_AT24C1024 case EEPROMExternal_Type_e::AT24C1024: + delay = (uint8_t)6; // fall through case EEPROMExternal_Type_e::MB85RC1M: # endif // if EEPROM_SUPPORT_AT24C1024 # if EEPROM_SUPPORT_AT24C2048 case EEPROMExternal_Type_e::AT24C2048: + delay = (uint8_t)6; // fall through case EEPROMExternal_Type_e::MB85RC2M: # endif // if EEPROM_SUPPORT_AT24C2048 case EEPROMExternal_Type_e::AT24C512: + delay = (uint8_t)6; // fall through case EEPROMExternal_Type_e::MB85RC512: pageSize = (uint8_t)128; break; case EEPROMExternal_Type_e::AT24C32: - case EEPROMExternal_Type_e::MB85RC32: case EEPROMExternal_Type_e::AT24C64: + delay = (uint8_t)10; // fall through + case EEPROMExternal_Type_e::MB85RC32: case EEPROMExternal_Type_e::MB85RC64: pageSize = (uint8_t)32; break; @@ -363,16 +374,17 @@ bool writeEEPROMSlot(uint32_t slot, const uint32_t addr = getEEPROMAddressForSlot(slot); if ((addr != std::numeric_limits::max()) && !isEEPROMExternalWriteProtected()) { - ESPEASY_RULES_FLOAT_TYPE oldData{}; + double oldData{}; { START_TIMER; - oldData = EEPROMExternal->readDouble(addr); + EEPROMExternal->get(addr, oldData); STOP_TIMER(READ_EEPROM_SLOT); } if (!essentiallyEqual(oldData, data)) { START_TIMER; - EEPROMExternal->writeDouble(addr, data); // Always write double size! + const double _wrdata = data; + EEPROMExternal->put(addr, _wrdata); // Always write double size! STOP_TIMER(WRITE_EEPROM_SLOT); } return true; @@ -385,11 +397,11 @@ bool writeEEPROMSlot(uint32_t slot, */ ESPEASY_RULES_FLOAT_TYPE readEEPROMSlot(uint32_t slot) { const uint32_t addr = getEEPROMAddressForSlot(slot); - ESPEASY_RULES_FLOAT_TYPE res{}; + double res{}; if (addr != std::numeric_limits::max()) { START_TIMER; - res = EEPROMExternal->readDouble(addr); + EEPROMExternal->get(addr, res); STOP_TIMER(READ_EEPROM_SLOT); } return res; diff --git a/src/ESPEasy/eeprom/Helpers/EEPROMExternal.h b/src/ESPEasy/eeprom/Helpers/EEPROMExternal.h index 7c8dd371e..1d1147626 100644 --- a/src/ESPEasy/eeprom/Helpers/EEPROMExternal.h +++ b/src/ESPEasy/eeprom/Helpers/EEPROMExternal.h @@ -6,7 +6,7 @@ # include "../../../src/DataTypes/TaskIndex.h" # include "../../../src/Helpers/LongTermTimer.h" -# include +# include namespace ESPEasy { namespace eeprom { @@ -17,7 +17,7 @@ enum class EEPROMExternal_WriteProtect_e : uint8_t { }; -extern AT24CX *EEPROMExternal; +extern AT24Cxxx *EEPROMExternal; extern EEPROMExternal_WriteProtect_e EEPROMExternalWriteProtect; extern bool EEPROMParamsOkState; extern LongTermTimer EEPROMParamsOkTimer; @@ -78,9 +78,10 @@ bool isEEPROMExternalWriteProtected(); uint8_t selectEEPROMI2CBusAndMultiplexer(); -uint32_t getEEPROMSize(EEPROMExternal_Type_e type); -uint32_t getEEPROMSize(EEPROMExternal_Type_e type, - uint8_t & pageSize); +size_t getEEPROMSize(EEPROMExternal_Type_e type); +size_t getEEPROMSize(EEPROMExternal_Type_e type, + uint8_t & pageSize, + uint8_t & delay); const __FlashStringHelper* getEEPROMName(EEPROMExternal_Type_e type); uint32_t getEEPROMAddressForSlot(uint32_t slot); diff --git a/src/ESPEasy/eeprom/Helpers/RTCSRAMStorage.cpp b/src/ESPEasy/eeprom/Helpers/RTCSRAMStorage.cpp index 8f88aa528..54b4bc4dc 100644 --- a/src/ESPEasy/eeprom/Helpers/RTCSRAMStorage.cpp +++ b/src/ESPEasy/eeprom/Helpers/RTCSRAMStorage.cpp @@ -179,11 +179,13 @@ bool writeRTCSRAMSlot(uint32_t slot, case ExtTimeSource_e::DS1307: { RTC_DS1307 rtc; + + if (!rtc.begin()) { return false; } rtc.readnvram(_b, sizeof_rtcsram_slot, addr); STOP_TIMER(READ_RTC_SLOT); const SRAM_STORAGE_FLOAT_TYPE oldData = *(SRAM_STORAGE_FLOAT_TYPE *)&_b[0]; - if (!essentiallyEqual(oldData, data)) { + if (isnan(oldData) || !essentiallyEqual(oldData, data)) { rtc.writenvram(addr, (uint8_t *)&data, sizeof_rtcsram_slot); STOP_TIMER(WRITE_RTC_SLOT); } @@ -192,11 +194,13 @@ bool writeRTCSRAMSlot(uint32_t slot, case ExtTimeSource_e::DS3232: { RTC_DS3231 rtc; + + if (!rtc.begin()) { return false; } rtc.readnvram(_b, sizeof_rtcsram_slot, addr); STOP_TIMER(READ_RTC_SLOT); const SRAM_STORAGE_FLOAT_TYPE oldData = *(SRAM_STORAGE_FLOAT_TYPE *)&_b[0]; - if (!essentiallyEqual(oldData, data)) { + if (isnan(oldData) || !essentiallyEqual(oldData, data)) { rtc.writenvram(addr, (uint8_t *)&data, sizeof_rtcsram_slot); STOP_TIMER(WRITE_RTC_SLOT); } @@ -212,11 +216,12 @@ bool writeRTCSRAMSlot(uint32_t slot, rtc.altAddress(); // Set alternative address (0x51) } + if (!rtc.begin()) { return false; } rtc.readnvram(_b, sizeof_rtcsram_slot, addr); STOP_TIMER(READ_RTC_SLOT); const SRAM_STORAGE_FLOAT_TYPE oldData = *(SRAM_STORAGE_FLOAT_TYPE *)&_b[0]; - if (!essentiallyEqual(oldData, data)) { + if (isnan(oldData) || !essentiallyEqual(oldData, data)) { rtc.writenvram(addr, (uint8_t *)&data, sizeof_rtcsram_slot); STOP_TIMER(WRITE_RTC_SLOT); } @@ -250,14 +255,20 @@ SRAM_STORAGE_FLOAT_TYPE readRTCSRAMSlot(uint32_t slot) { case ExtTimeSource_e::DS1307: { RTC_DS1307 rtc; - rtc.readnvram(_b, sizeof_rtcsram_slot, addr); + + if (rtc.begin()) { + rtc.readnvram(_b, sizeof_rtcsram_slot, addr); + } STOP_TIMER(READ_RTC_SLOT); return *(SRAM_STORAGE_FLOAT_TYPE *)&_b[0]; } case ExtTimeSource_e::DS3232: { RTC_DS3231 rtc; - rtc.readnvram(_b, sizeof_rtcsram_slot, addr); + + if (rtc.begin()) { + rtc.readnvram(_b, sizeof_rtcsram_slot, addr); + } STOP_TIMER(READ_RTC_SLOT); return *(SRAM_STORAGE_FLOAT_TYPE *)&_b[0]; } @@ -271,7 +282,9 @@ SRAM_STORAGE_FLOAT_TYPE readRTCSRAMSlot(uint32_t slot) { rtc.altAddress(); // Set alternative address (0x51) } - rtc.readnvram(_b, sizeof_rtcsram_slot, addr); + if (rtc.begin()) { + rtc.readnvram(_b, sizeof_rtcsram_slot, addr); + } STOP_TIMER(READ_RTC_SLOT); return *(SRAM_STORAGE_FLOAT_TYPE *)&_b[0]; } diff --git a/src/src/Commands/EEPROMExternal.cpp b/src/src/Commands/EEPROMExternal.cpp index 8a7af2697..5e176f6cb 100644 --- a/src/src/Commands/EEPROMExternal.cpp +++ b/src/src/Commands/EEPROMExternal.cpp @@ -8,6 +8,7 @@ # include "../DataStructs/ESPEasy_EventStruct.h" +# include "../Helpers/ESPEasy_time_calc.h" # include "../Helpers/Misc.h" # include "../Helpers/Numerical.h" # include "../Helpers/StringConverter.h" @@ -29,7 +30,9 @@ const __FlashStringHelper* Command_writeEE(struct EventStruct *event, const char if (validUIntFromString(parseString(Line, 2), slot) && validValue) { return return_command_boolean_result_flashstr(ESPEasy::eeprom::writeEEPROMSlot(slot, value)); - } else if (equals(parseString(Line, 2), F("erase")) && equals(parseString(Line, 3), F("erase"))) { + } else if (equals(parseString(Line, 2), F("erase")) && equals(parseString(Line, 3), F("erase"))) { + uint32_t start = millis(); + for (uint32_t slot = 0; slot < ESPEasy::eeprom::getEEPROMMaxSlots(); ++slot) { # if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE ESPEasy::eeprom::writeEEPROMSlot(slot, 0.0); @@ -37,11 +40,14 @@ const __FlashStringHelper* Command_writeEE(struct EventStruct *event, const char ESPEasy::eeprom::writeEEPROMSlot(slot, 0.0f); # endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE - if (slot % 50 == 0) { delay(0); } + if ((slot % 50 == 0) || (timePassedSince(start) > 50)) { + delay(0); + start = millis(); + } } addLog(LOG_LEVEL_INFO, F("EEPROM: All slot-values erased.")); return return_command_success_flashstr(); - } else if (equals(parseString(Line, 2), F("check")) && equals(parseString(Line, 3), F("wp"))) { + } else if (equals(parseString(Line, 2), F("check")) && equals(parseString(Line, 3), F("wp"))) { addLog(LOG_LEVEL_INFO, F("EEPROM: Check write-protect.")); ESPEasy::eeprom::checkEEPROMExternalWriteProtected(true); diff --git a/src/src/Commands/RTCSRAMStorage.cpp b/src/src/Commands/RTCSRAMStorage.cpp index 3924aa80a..34b8961b7 100644 --- a/src/src/Commands/RTCSRAMStorage.cpp +++ b/src/src/Commands/RTCSRAMStorage.cpp @@ -8,6 +8,7 @@ # include "../DataStructs/ESPEasy_EventStruct.h" +# include "../Helpers/ESPEasy_time_calc.h" # include "../Helpers/Misc.h" # include "../Helpers/Numerical.h" # include "../Helpers/StringConverter.h" @@ -28,7 +29,9 @@ const __FlashStringHelper* Command_writeRTC(struct EventStruct *event, const cha if (validUIntFromString(parseString(Line, 2), slot) && validValue) { return return_command_boolean_result_flashstr(ESPEasy::eeprom::writeRTCSRAMSlot(slot, value)); - } else if (equals(parseString(Line, 2), F("erase")) && equals(parseString(Line, 3), F("erase"))) { + } else if (equals(parseString(Line, 2), F("erase")) && equals(parseString(Line, 3), F("erase"))) { + uint32_t start = millis(); + for (uint32_t slot = 0; slot < ESPEasy::eeprom::getRTCSRAMMaxSlots(); ++slot) { # if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE ESPEasy::eeprom::writeRTCSRAMSlot(slot, 0.0); @@ -36,7 +39,10 @@ const __FlashStringHelper* Command_writeRTC(struct EventStruct *event, const cha ESPEasy::eeprom::writeRTCSRAMSlot(slot, 0.0f); # endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE - if (slot % 50 == 0) { delay(0); } + if ((slot % 50 == 0) || (timePassedSince(start) > 50)) { + delay(0); + start = millis(); + } } addLog(LOG_LEVEL_INFO, F("RTC SRAM: All slot-values erased.")); return return_command_success_flashstr(); diff --git a/src/src/PluginStructs/P129_data_struct.cpp b/src/src/PluginStructs/P129_data_struct.cpp index 66e6dcdfd..387102528 100644 --- a/src/src/PluginStructs/P129_data_struct.cpp +++ b/src/src/PluginStructs/P129_data_struct.cpp @@ -28,7 +28,7 @@ bool P129_data_struct::plugin_init(struct EventStruct *event) { if (validGpio(_enablePin)) { DIRECT_pinWrite(_enablePin, HIGH); } - plugin_read(event); // Prime data + plugin_readData(event); // Initial read, next PLUGIN_READ takes care of filling the UserVars return true; } return false; diff --git a/src/src/WebServer/EepromVarPage.cpp b/src/src/WebServer/EepromVarPage.cpp index 27d45bb19..651db043c 100644 --- a/src/src/WebServer/EepromVarPage.cpp +++ b/src/src/WebServer/EepromVarPage.cpp @@ -96,7 +96,7 @@ void handle_eepromvars() { html_end_table(); } else { - addHtml(F("External EEPROM not enabled.
")); + addHtml(F("
External EEPROM not enabled.
")); } # endif // if FEATURE_EEPROM_EXTERNAL # if FEATURE_RTC_SRAM_STORAGE @@ -168,8 +168,6 @@ void handle_eepromvars() { html_TD(); html_end_table(); - } else { - addHtml(F("External RTC SRAM not available.")); } # endif // if FEATURE_RTC_SRAM_STORAGE html_end_form(); diff --git a/src/src/WebServer/HardwarePage.cpp b/src/src/WebServer/HardwarePage.cpp index cb08f8a0e..d0a7cae29 100644 --- a/src/src/WebServer/HardwarePage.cpp +++ b/src/src/WebServer/HardwarePage.cpp @@ -50,13 +50,19 @@ void handle_hardware() { // EEPROM settings #if FEATURE_EEPROM_EXTERNAL + bool eepromChanged = false; + int tmp = getFormItemInt(F("eepromtype"), + static_cast(ESPEasy::eeprom::EEPROMExternal_Type_e::AT24C256)); + eepromChanged |= tmp != Settings.EEPROMExternalType(); - Settings.EEPROMExternalType(getFormItemInt(F("eepromtype"), - static_cast(ESPEasy::eeprom::EEPROMExternal_Type_e::AT24C256))); - Settings.EEPROMExternalI2CAddress(getFormItemInt(F("i2c_eeprom"), 0)); + Settings.EEPROMExternalType(tmp); + tmp = getFormItemInt(F("i2c_eeprom"), 0); + eepromChanged |= tmp != Settings.EEPROMExternalI2CAddress(); + Settings.EEPROMExternalI2CAddress(tmp); # if FEATURE_I2C_MULTIPLE const uint8_t i2cBus = getFormItemInt(F("pi2cbuseeprom"), 0); + eepromChanged |= i2cBus != Settings.getI2CInterfaceEEPROM(); set3BitToUL(Settings.I2C_peripheral_bus, I2C_PERIPHERAL_BUS_EEPROM, i2cBus); #endif // if FEATURE_I2C_MULTIPLE @@ -71,6 +77,7 @@ void handle_hardware() { uint16_t muxFlags{}; bitWrite(muxFlags, EEPROM_MUX_FLAGS_MULTI, muxPortsOption); set8BitToUL(muxFlags, EEPROM_MUX_FLAGS_PORT, selectedPorts); + eepromChanged |= muxFlags != Settings.EEPROMExternalI2CMultiplexerFlags(); Settings.EEPROMExternalI2CMultiplexerFlags(muxFlags); # endif // if FEATURE_I2CMULTIPLEXER @@ -96,6 +103,11 @@ void handle_hardware() { } error += SaveSettings(); addHtmlError(error); + #if FEATURE_EEPROM_EXTERNAL + if (error.isEmpty() && eepromChanged) { + ESPEasy::eeprom::initializeEEPROMExternal(); + } + #endif // if FEATURE_EEPROM_EXTERNAL } html_add_form();