diff --git a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h index b56afc08c..56428cfa2 100644 --- a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h +++ b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h @@ -31,6 +31,21 @@ #ifndef FLD_PIN_SDA #define FLD_PIN_SDA 21 #endif + #ifndef FLD_PIN_CLOCKSPI + #define FLD_PIN_CLOCKSPI 18 + #endif + #ifndef FLD_PIN_DATASPI + #define FLD_PIN_DATASPI 23 + #endif + #ifndef FLD_PIN_DC + #define FLD_PIN_DC 19 + #endif + #ifndef FLD_PIN_CS + #define FLD_PIN_CS 5 + #endif + #ifndef FLD_PIN_RESET + #define FLD_PIN_RESET 26 + #endif #else #ifndef FLD_PIN_SCL #define FLD_PIN_SCL 5 @@ -38,6 +53,21 @@ #ifndef FLD_PIN_SDA #define FLD_PIN_SDA 4 #endif + #ifndef FLD_PIN_CLOCKSPI + #define FLD_PIN_CLOCKSPI 14 + #endif + #ifndef FLD_PIN_DATASPI + #define FLD_PIN_DATASPI 13 + #endif + #ifndef FLD_PIN_DC + #define FLD_PIN_DC 12 + #endif + #ifndef FLD_PIN_CS + #define FLD_PIN_CS 15 + #endif + #ifndef FLD_PIN_RESET + #define FLD_PIN_RESET 16 + #endif #endif // When to time out to the clock or blank the screen @@ -64,11 +94,13 @@ typedef enum { typedef enum { NONE = 0, - SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C - SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C - SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C - SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C - SSD1305_64 // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C + SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C + SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C + SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C + SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C + SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C + SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI + SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI } DisplayType; class FourLineDisplayUsermod : public Usermod { @@ -80,8 +112,13 @@ class FourLineDisplayUsermod : public Usermod { // HW interface & configuration U8X8 *u8x8 = nullptr; // pointer to U8X8 display object - int8_t sclPin=FLD_PIN_SCL, sdaPin=FLD_PIN_SDA; // I2C pins for interfacing, get initialised in readFromConfig() + #ifndef FLD_SPI_DEFAULT + int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA DisplayType type = SSD1306; // display type + #else + int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST + DisplayType type = SSD1306_SPI; // display type + #endif bool flip = false; // flip display 180° uint8_t contrast = 10; // screen contrast uint8_t lineHeight = 1; // 1 row or 2 rows @@ -131,53 +168,74 @@ class FourLineDisplayUsermod : public Usermod { // network here void setup() { if (type == NONE) return; - if (!pinManager.allocatePin(sclPin)) { sclPin = -1; type = NONE; return;} - if (!pinManager.allocatePin(sdaPin)) { pinManager.deallocatePin(sclPin); sclPin = sdaPin = -1; type = NONE; return; } + bool allocated = false; + byte i; + if (type == SSD1306_SPI || type == SSD1306_SPI64) { + for (i=0; i<5; i++) if (!pinManager.allocatePin(ioPin[i])) { allocated=true; break; } + if (i<5 && allocated) { for (byte i=0; i<5; i++) pinManager.deallocatePin(ioPin[i]); type=NONE; return; } + } else { + for (i=0; i<2; i++) if (!pinManager.allocatePin(ioPin[i])) { allocated=true; break; } + if (i<2 && allocated) { for (byte i=0; i<5; i++) pinManager.deallocatePin(ioPin[i]); type=NONE; return; } + } DEBUG_PRINTLN(F("Allocating display.")); switch (type) { case SSD1306: #ifdef ESP8266 - if (!(sclPin==5 && sdaPin==4)) - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset + if (!(ioPin[0]==5 && ioPin[1]==4)) + u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset else #endif - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA + u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 1; break; case SH1106: #ifdef ESP8266 - if (!(sclPin==5 && sdaPin==4)) - u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset + if (!(ioPin[0]==5 && ioPin[1]==4)) + u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset else #endif - u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA + u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 2; break; case SSD1306_64: #ifdef ESP8266 - if (!(sclPin==5 && sdaPin==4)) - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset + if (!(ioPin[0]==5 && ioPin[1]==4)) + u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset else #endif - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA + u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 2; break; case SSD1305: #ifdef ESP8266 - if (!(sclPin==5 && sdaPin==4)) - u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset + if (!(ioPin[0]==5 && ioPin[1]==4)) + u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset else #endif - u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA + u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 1; break; case SSD1305_64: #ifdef ESP8266 - if (!(sclPin==5 && sdaPin==4)) - u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(sclPin, sdaPin); // SCL, SDA, reset + if (!(ioPin[0]==5 && ioPin[1]==4)) + u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset else #endif - u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, sclPin, sdaPin); // Pins are Reset, SCL, SDA + u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + lineHeight = 2; + break; + case SSD1306_SPI: + if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated + u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else + u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset + lineHeight = 1; + break; + case SSD1306_SPI64: + if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated + u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else + u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset lineHeight = 2; break; default: @@ -605,10 +663,10 @@ class FourLineDisplayUsermod : public Usermod { * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! */ void addToConfig(JsonObject& root) { - JsonObject top = root.createNestedObject(FPSTR(_name)); - JsonArray i2c_pin = top.createNestedArray("pin"); - i2c_pin.add(sclPin); - i2c_pin.add(sdaPin); + JsonObject top = root.createNestedObject(FPSTR(_name)); + JsonArray io_pin = top.createNestedArray("pin"); + for (byte i=0; i<5; i++) io_pin.add(ioPin[i]); + top["help4PinTypes"] = F("Clk,Data,CS,DC,RST"); // help for Settings page top["type"] = type; top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_contrast)] = contrast; @@ -630,8 +688,7 @@ class FourLineDisplayUsermod : public Usermod { bool readFromConfig(JsonObject& root) { bool needsRedraw = false; DisplayType newType = type; - int8_t newScl = sclPin; - int8_t newSda = sdaPin; + int8_t newPin[5]; for (byte i=0; i<5; i++) newPin[i] = ioPin[i]; JsonObject top = root[FPSTR(_name)]; if (top.isNull()) { @@ -640,9 +697,8 @@ class FourLineDisplayUsermod : public Usermod { return false; } - newScl = top["pin"][0] | newScl; - newSda = top["pin"][1] | newSda; newType = top["type"] | newType; + for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i]; flip = top[FPSTR(_flip)] | flip; contrast = top[FPSTR(_contrast)] | contrast; refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/1000) * 1000; @@ -653,20 +709,21 @@ class FourLineDisplayUsermod : public Usermod { DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // first run: reading from cfg.json - sclPin = newScl; - sdaPin = newSda; + for (byte i=0; i<5; i++) ioPin[i] = newPin[i]; type = newType; DEBUG_PRINTLN(F(" config loaded.")); } else { DEBUG_PRINTLN(F(" config (re)loaded.")); // changing parameters from settings page - if (sclPin!=newScl || sdaPin!=newSda || type!=newType) { + bool pinsChanged = false; + for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } + if (pinsChanged || type!=newType) { if (type != NONE) delete (static_cast(u8x8)); - pinManager.deallocatePin(sclPin); - pinManager.deallocatePin(sdaPin); - sclPin = newScl; - sdaPin = newSda; - if (newScl<0 || newSda<0) { + for (byte i=0; i<5; i++) { + if (ioPin[i]>=0) pinManager.deallocatePin(ioPin[i]); + ioPin[i] = newPin[i]; + } + if (ioPin[0]<0 || ioPin[1]<0) { // data & clock must be > -1 type = NONE; return true; } else type = newType; @@ -678,7 +735,7 @@ class FourLineDisplayUsermod : public Usermod { if (needsRedraw && !wakeDisplay()) redraw(true); } // use "return !top["newestParameter"].isNull();" when updating Usermod with new features - return true; + return !(top["pin"][2]).isNull(); } /*