Fixed pin reservations. (#2214)

* Fixed pin reservations.
Added ethernet pin reservations.
Minor tweaks in usermods.

* Optional ADA compile (not default, free GPIO3 use)

* Move ethernet definitions

Remove pin 3 used check

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
This commit is contained in:
Blaž Kristan 2021-09-30 16:30:44 +02:00 committed by GitHub
parent 7d929dcde6
commit dc9dedf220
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 593 additions and 523 deletions

View File

@ -81,7 +81,9 @@ class UsermodTemperature : public Usermod {
temperature = readDallas(); temperature = readDallas();
lastMeasurement = millis(); lastMeasurement = millis();
waitingForConversion = false; waitingForConversion = false;
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature); //DEBUG_PRINTF("Read temperature %2.1f.\n", temperature); // does not work properly on 8266
DEBUG_PRINT(F("Read temperature "));
DEBUG_PRINTLN(temperature);
} }
bool findSensor() { bool findSensor() {

View File

@ -317,15 +317,15 @@ class MultiRelay : public Usermod {
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients * Values in the state object may be modified by connected clients
*/ */
void addToJsonState(JsonObject &root) { //void addToJsonState(JsonObject &root) {
} //}
/** /**
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients * Values in the state object may be modified by connected clients
*/ */
void readFromJsonState(JsonObject &root) { //void readFromJsonState(JsonObject &root) {
} //}
/** /**
* provide the changeable values * provide the changeable values
@ -335,11 +335,12 @@ class MultiRelay : public Usermod {
top[FPSTR(_enabled)] = enabled; top[FPSTR(_enabled)] = enabled;
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) { for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-"; String parName = FPSTR(_relay_str); parName += '-'; parName += i;
top[parName+"pin"] = _relay[i].pin; JsonObject relay = top.createNestedObject(parName);
top[parName+FPSTR(_activeHigh)] = _relay[i].mode; relay["pin"] = _relay[i].pin;
top[parName+FPSTR(_delay_str)] = _relay[i].delay; relay[FPSTR(_activeHigh)] = _relay[i].mode;
top[parName+FPSTR(_external)] = _relay[i].external; relay[FPSTR(_delay_str)] = _relay[i].delay;
relay[FPSTR(_external)] = _relay[i].external;
} }
DEBUG_PRINTLN(F("MultiRelay config saved.")); DEBUG_PRINTLN(F("MultiRelay config saved."));
} }
@ -363,12 +364,19 @@ class MultiRelay : public Usermod {
enabled = top[FPSTR(_enabled)] | enabled; enabled = top[FPSTR(_enabled)] | enabled;
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) { for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-"; String parName = FPSTR(_relay_str); parName += '-'; parName += i;
oldPin[i] = _relay[i].pin; oldPin[i] = _relay[i].pin;
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
// begin backwards compatibility (beta) remove when 0.13 is released
parName += '-';
_relay[i].pin = top[parName+"pin"] | _relay[i].pin; _relay[i].pin = top[parName+"pin"] | _relay[i].pin;
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode; _relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external; _relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay; _relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
// end compatibility
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min _relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
} }
@ -396,7 +404,7 @@ class MultiRelay : public Usermod {
DEBUG_PRINTLN(F(" config (re)loaded.")); DEBUG_PRINTLN(F(" config (re)loaded."));
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return true; return !top[F("relay-0")]["pin"].isNull();
} }
/** /**

View File

@ -114,6 +114,7 @@ class FourLineDisplayUsermod : public Usermod {
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
#ifndef FLD_SPI_DEFAULT #ifndef FLD_SPI_DEFAULT
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
DisplayType type = SSD1306; // display type DisplayType type = SSD1306; // display type
#else #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 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
@ -155,6 +156,7 @@ class FourLineDisplayUsermod : public Usermod {
static const char _flip[]; static const char _flip[];
static const char _sleepMode[]; static const char _sleepMode[];
static const char _clockMode[]; static const char _clockMode[];
static const char _busClkFrequency[];
// If display does not work or looks corrupted check the // If display does not work or looks corrupted check the
// constructor reference: // constructor reference:
@ -248,6 +250,7 @@ class FourLineDisplayUsermod : public Usermod {
initDone = true; initDone = true;
DEBUG_PRINTLN(F("Starting display.")); DEBUG_PRINTLN(F("Starting display."));
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
u8x8->begin(); u8x8->begin();
setFlipMode(flip); setFlipMode(flip);
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
@ -683,6 +686,7 @@ class FourLineDisplayUsermod : public Usermod {
top[FPSTR(_screenTimeOut)] = screenTimeout/1000; top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
top[FPSTR(_sleepMode)] = (bool) sleepMode; top[FPSTR(_sleepMode)] = (bool) sleepMode;
top[FPSTR(_clockMode)] = (bool) clockMode; top[FPSTR(_clockMode)] = (bool) clockMode;
top[FPSTR(_busClkFrequency)] = ioFrequency/1000;
DEBUG_PRINTLN(F("4 Line Display config saved.")); DEBUG_PRINTLN(F("4 Line Display config saved."));
} }
@ -714,6 +718,7 @@ class FourLineDisplayUsermod : public Usermod {
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000; screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
sleepMode = top[FPSTR(_sleepMode)] | sleepMode; sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
clockMode = top[FPSTR(_clockMode)] | clockMode; clockMode = top[FPSTR(_clockMode)] | clockMode;
ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINT(FPSTR(_name));
if (!initDone) { if (!initDone) {
@ -739,12 +744,13 @@ class FourLineDisplayUsermod : public Usermod {
setup(); setup();
needsRedraw |= true; needsRedraw |= true;
} }
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
setContrast(contrast); setContrast(contrast);
setFlipMode(flip); setFlipMode(flip);
if (needsRedraw && !wakeDisplay()) redraw(true); if (needsRedraw && !wakeDisplay()) redraw(true);
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return !(top["pin"][2]).isNull(); return !(top[_busClkFrequency]).isNull();
} }
/* /*
@ -764,3 +770,4 @@ const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip"; const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode"; const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode"; const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";

View File

@ -4,18 +4,6 @@
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
#include "pin_manager.h" #include "pin_manager.h"
// The following six pins are neither configurable nor
// can they be re-assigned through IOMUX / GPIO matrix.
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
const managed_pin_type esp32_nonconfigurable_ethernet_pins[6] = {
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
};
// For ESP32, the remaining five pins are at least somewhat configurable. // For ESP32, the remaining five pins are at least somewhat configurable.
// eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface // eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface
// eth_power is an output GPIO pin used to enable/disable the ethernet port (and/or external oscillator) // eth_power is an output GPIO pin used to enable/disable the ethernet port (and/or external oscillator)
@ -37,15 +25,16 @@ typedef struct EthernetSettings {
eth_clock_mode_t eth_clk_mode; eth_clock_mode_t eth_clk_mode;
} ethernet_settings; } ethernet_settings;
ethernet_settings ethernetBoards[] = { const ethernet_settings ethernetBoards[] = {
// None // None
{ {
}, },
// WT32-EHT01 // WT32-EHT01
// (*) NOTE: silkscreen on board revision v1.2 may be wrong: // Please note, from my testing only these pins work for LED outputs:
// silkscreen on v1.2 says IO35, but appears to be IO5 // IO2, IO4, IO12, IO14, IO15
// silkscreen on v1.2 says RXD, and appears to be IO35 // These pins do not appear to work from my testing:
// IO35, IO36, IO39
{ {
1, // eth_address, 1, // eth_address,
16, // eth_power, 16, // eth_power,
@ -107,4 +96,17 @@ ethernet_settings ethernetBoards[] = {
}; };
#endif #endif
#define WLED_ETH_RSVD_PINS_COUNT 6
// The following six pins are neither configurable nor
// can they be re-assigned through IOMUX / GPIO matrix.
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT] = {
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
};
#endif #endif

View File

@ -1,4 +1,5 @@
#include "wled.h" #include "wled.h"
#include "wled_ethernet.h"
/* /*
* Sending XML status files to client * Sending XML status files to client
@ -186,6 +187,52 @@ void sappends(char stype, const char* key, char* val)
} }
} }
void extractPin(JsonObject &obj, const char *key) {
if (obj[key].is<JsonArray>()) {
JsonArray pins = obj[key].as<JsonArray>();
for (JsonVariant pv : pins) {
if (pv.as<int>() > -1) { oappend(","); oappendi(pv.as<int>()); }
}
} else {
if (obj[key].as<int>() > -1) { oappend(","); oappendi(obj[key].as<int>()); }
}
}
// oappens used pins by scanning JsonObject (1 level deep)
void fillUMPins(JsonObject &mods)
{
for (JsonPair kv : mods) {
// kv.key() is usermod name or subobject key
// kv.value() is object itself
JsonObject obj = kv.value();
if (!obj.isNull()) {
// element is an JsonObject
if (!obj["pin"].isNull()) {
extractPin(obj, "pin");
} else {
// scan keys (just one level deep as is possible with usermods)
for (JsonPair so : obj) {
const char *key = so.key().c_str();
if (strstr(key, "pin")) {
// we found a key containing "pin" substring
if (strlen(strstr(key, "pin")) == 3) {
// and it is at the end, we found another pin
extractPin(obj, key);
continue;
}
}
if (!obj[so.key()].is<JsonObject>()) continue;
JsonObject subObj = obj[so.key()];
if (!subObj["pin"].isNull()) {
// get pins from subobject
extractPin(subObj, "pin");
}
}
}
}
}
}
//get values for settings form in javascript //get values for settings form in javascript
void getSettingsJS(byte subPage, char* dest) void getSettingsJS(byte subPage, char* dest)
@ -198,7 +245,8 @@ void getSettingsJS(byte subPage, char* dest)
if (subPage <1 || subPage >8) return; if (subPage <1 || subPage >8) return;
if (subPage == 1) { if (subPage == 1)
{
sappends('s',SET_F("CS"),clientSSID); sappends('s',SET_F("CS"),clientSSID);
byte l = strlen(clientPass); byte l = strlen(clientPass);
@ -264,50 +312,53 @@ void getSettingsJS(byte subPage, char* dest)
} }
} }
if (subPage == 2) { if (subPage == 2)
{
char nS[8]; char nS[8];
// add reserved and usermod pins as d.um_p array // add reserved and usermod pins as d.um_p array
oappend(SET_F("d.um_p=[6,7,8,9,10,11"));
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2); DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
JsonObject mods = doc.createNestedObject(F("um")); JsonObject mods = doc.createNestedObject(F("um"));
usermods.addToConfig(mods); usermods.addToConfig(mods);
oappend(SET_F("d.um_p=[")); if (!mods.isNull()) fillUMPins(mods);
if (!mods.isNull()) {
uint8_t i=0;
for (JsonPair kv : mods) {
if (!kv.value().isNull()) {
// element is an JsonObject
JsonObject obj = kv.value();
if (obj["pin"] != nullptr) {
if (obj["pin"].is<JsonArray>()) {
JsonArray pins = obj["pin"].as<JsonArray>();
for (JsonVariant pv : pins) {
if (i++) oappend(SET_F(","));
oappendi(pv.as<int>());
}
} else {
if (i++) oappend(SET_F(","));
oappendi(obj["pin"].as<int>());
}
}
}
}
if (i) oappend(SET_F(","));
oappend(SET_F("6,7,8,9,10,11")); // flash memory pins
#ifdef WLED_ENABLE_DMX #ifdef WLED_ENABLE_DMX
oappend(SET_F(",2")); // DMX hardcoded pin oappend(SET_F(",2")); // DMX hardcoded pin
#endif #endif
//Adalight / Serial in requires pin 3 to be unused. However, Serial input can not be prevented by WLED
//Note: Using pin 3 (RX) disables Adalight / Serial JSON
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
oappend(SET_F(",1")); // debug output (TX) pin oappend(SET_F(",1")); // debug output (TX) pin
#endif #endif
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
#endif #endif
//TODO: add reservations for Ethernet shield pins
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
#endif if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { oappend(","); oappend(itoa(esp32_nonconfigurable_ethernet_pins[p].pin,nS,10)); }
if (ethernetBoards[ethernetType].eth_power>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); }
if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); }
if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); }
switch (ethernetBoards[ethernetType].eth_clk_mode) {
case ETH_CLOCK_GPIO0_IN:
case ETH_CLOCK_GPIO0_OUT:
oappend(SET_F(",0"));
break;
case ETH_CLOCK_GPIO16_OUT:
oappend(SET_F(",16"));
break;
case ETH_CLOCK_GPIO17_OUT:
oappend(SET_F(",17"));
break;
} }
}
#endif
oappend(SET_F("];")); oappend(SET_F("];"));
// set limits // set limits
@ -338,9 +389,9 @@ void getSettingsJS(byte subPage, char* dest)
uint8_t nPins = bus->getPins(pins); uint8_t nPins = bus->getPins(pins);
for (uint8_t i = 0; i < nPins; i++) { for (uint8_t i = 0; i < nPins; i++) {
lp[1] = 48+i; lp[1] = 48+i;
if (pinManager.isPinOk(pins[i])) sappend('v', lp, pins[i]); if (pinManager.isPinOk(pins[i])) sappend('v',lp,pins[i]);
} }
sappend('v', lc, bus->getLength()); sappend('v',lc,bus->getLength());
sappend('v',lt,bus->getType()); sappend('v',lt,bus->getType());
sappend('v',co,bus->getColorOrder()); sappend('v',co,bus->getColorOrder());
sappend('v',ls,bus->getStart()); sappend('v',ls,bus->getStart());