Merge branch 'MoonModules:mdev' into downsample4x

This commit is contained in:
Troy
2023-09-20 12:19:26 -04:00
committed by GitHub
6 changed files with 141 additions and 111 deletions

View File

@@ -60,9 +60,9 @@ class UsermodBattery : public Usermod
bool initializing = true; bool initializing = true;
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; // static const char _name[];
static const char _readInterval[]; static const char _readInterval[];
static const char _enabled[]; // static const char _enabled[];
static const char _threshold[]; static const char _threshold[];
static const char _preset[]; static const char _preset[];
static const char _duration[]; static const char _duration[];
@@ -117,6 +117,7 @@ class UsermodBattery : public Usermod
float readVoltage() float readVoltage()
{ {
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
if ((batteryPin <0) || !pinManager.isPinAnalog(batteryPin)) return(-1.0f); // WLEDMM avoid reading from invalid pin
// use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value
return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration; return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration;
#else #else
@@ -127,6 +128,7 @@ class UsermodBattery : public Usermod
public: public:
//Functions called by WLED //Functions called by WLED
UsermodBattery(const char *name, bool enabled):Usermod(name, enabled) {} //WLEDMM: this shouldn't be necessary (passthrough of constructor), maybe because Usermod is an abstract class
/* /*
* setup() is called once at boot. WiFi is not yet connected at this point. * setup() is called once at boot. WiFi is not yet connected at this point.
@@ -134,10 +136,11 @@ class UsermodBattery : public Usermod
*/ */
void setup() void setup()
{ {
if (!enabled) return; // WLEDMM
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
bool success = false; bool success = false;
DEBUG_PRINTLN(F("Allocating battery pin...")); DEBUG_PRINTLN(F("Allocating battery pin..."));
if (batteryPin >= 0 && digitalPinToAnalogChannel(batteryPin) >= 0) if ((batteryPin >= 0) && (digitalPinToAnalogChannel(batteryPin) >= 0))
if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) { if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) {
DEBUG_PRINTLN(F("Battery pin allocation succeeded.")); DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
success = true; success = true;
@@ -145,8 +148,9 @@ class UsermodBattery : public Usermod
} }
if (!success) { if (!success) {
DEBUG_PRINTLN(F("Battery pin allocation failed.")); USER_PRINTLN(F("Battery pin allocation failed."));
batteryPin = -1; // allocation failed batteryPin = -1; // allocation failed
enabled = false;
} else { } else {
pinMode(batteryPin, INPUT); pinMode(batteryPin, INPUT);
} }
@@ -178,7 +182,13 @@ class UsermodBattery : public Usermod
*/ */
void loop() void loop()
{ {
if(strip.isUpdating()) return; // WLEDMM begin
if (!enabled) return;
if (batteryPin < 0) return;
unsigned long currentTime = millis(); // get the current elapsed time
if (strip.isUpdating() && (currentTime - lastTime < 30000)) return; // WLEDMM: be nice
lastTime = currentTime;
// WLEDMM end
lowPowerIndicator(); lowPowerIndicator();
@@ -252,6 +262,7 @@ class UsermodBattery : public Usermod
JsonObject user = root["u"]; JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u"); if (user.isNull()) user = root.createNestedObject("u");
if (!enabled) return; // WLEDMM
if (batteryPin < 0) { if (batteryPin < 0) {
JsonArray infoVoltage = user.createNestedArray(F("Battery voltage")); JsonArray infoVoltage = user.createNestedArray(F("Battery voltage"));
infoVoltage.add(F("n/a")); infoVoltage.add(F("n/a"));
@@ -360,6 +371,8 @@ class UsermodBattery : public Usermod
void addToConfig(JsonObject& root) void addToConfig(JsonObject& root)
{ {
JsonObject battery = root.createNestedObject(FPSTR(_name)); // usermodname JsonObject battery = root.createNestedObject(FPSTR(_name)); // usermodname
battery[F("enabled")] = enabled; // WLEDMM
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
battery[F("pin")] = batteryPin; battery[F("pin")] = batteryPin;
#endif #endif
@@ -373,11 +386,11 @@ class UsermodBattery : public Usermod
battery[FPSTR(_readInterval)] = readingInterval; battery[FPSTR(_readInterval)] = readingInterval;
JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section
ao[FPSTR(_enabled)] = autoOffEnabled; ao[F("auto-off-enabled")] = autoOffEnabled;
ao[FPSTR(_threshold)] = autoOffThreshold; ao[FPSTR(_threshold)] = autoOffThreshold;
JsonObject lp = battery.createNestedObject(F("indicator")); // low power section JsonObject lp = battery.createNestedObject(F("indicator")); // low power section
lp[FPSTR(_enabled)] = lowPowerIndicatorEnabled; lp[F("indicator-enabled")] = lowPowerIndicatorEnabled;
lp[FPSTR(_preset)] = lowPowerIndicatorPreset; // dropdown trickery (String)lowPowerIndicatorPreset; lp[FPSTR(_preset)] = lowPowerIndicatorPreset; // dropdown trickery (String)lowPowerIndicatorPreset;
lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold; lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold;
lp[FPSTR(_duration)] = lowPowerIndicatorDuration; lp[FPSTR(_duration)] = lowPowerIndicatorDuration;
@@ -436,6 +449,10 @@ class UsermodBattery : public Usermod
#endif #endif
JsonObject battery = root[FPSTR(_name)]; JsonObject battery = root[FPSTR(_name)];
bool configComplete = !battery.isNull(); // WLEDMM
configComplete &= getJsonValue(battery[F("enabled")], enabled, true); // WLEDMM
if (battery.isNull()) if (battery.isNull())
{ {
DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINT(FPSTR(_name));
@@ -455,11 +472,11 @@ class UsermodBattery : public Usermod
setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval);
JsonObject ao = battery[F("auto-off")]; JsonObject ao = battery[F("auto-off")];
setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled); setAutoOffEnabled(ao[F("auto-off-enabled")] | autoOffEnabled); // WLEDMM
setAutoOffThreshold(ao[FPSTR(_threshold)] | autoOffThreshold); setAutoOffThreshold(ao[FPSTR(_threshold)] | autoOffThreshold);
JsonObject lp = battery[F("indicator")]; JsonObject lp = battery[F("indicator")];
setLowPowerIndicatorEnabled(lp[FPSTR(_enabled)] | lowPowerIndicatorEnabled); setLowPowerIndicatorEnabled(lp[F("indicator-enabled")] | lowPowerIndicatorEnabled); // WLEDMM
setLowPowerIndicatorPreset(lp[FPSTR(_preset)] | lowPowerIndicatorPreset); // dropdown trickery (int)lp["preset"] setLowPowerIndicatorPreset(lp[FPSTR(_preset)] | lowPowerIndicatorPreset); // dropdown trickery (int)lp["preset"]
setLowPowerIndicatorThreshold(lp[FPSTR(_threshold)] | lowPowerIndicatorThreshold); setLowPowerIndicatorThreshold(lp[FPSTR(_threshold)] | lowPowerIndicatorThreshold);
lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10; lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10;
@@ -490,7 +507,7 @@ class UsermodBattery : public Usermod
} }
#endif #endif
return !battery[FPSTR(_readInterval)].isNull(); return configComplete && (!battery[FPSTR(_readInterval)].isNull()); // WLEDMM
} }
/* /*
@@ -780,9 +797,9 @@ class UsermodBattery : public Usermod
}; };
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
const char UsermodBattery::_name[] PROGMEM = "Battery"; // const char UsermodBattery::_name[] PROGMEM = "Battery";
const char UsermodBattery::_readInterval[] PROGMEM = "interval"; const char UsermodBattery::_readInterval[] PROGMEM = "interval";
const char UsermodBattery::_enabled[] PROGMEM = "enabled"; //const char UsermodBattery::_enabled[] PROGMEM = "enabled";
const char UsermodBattery::_threshold[] PROGMEM = "threshold"; const char UsermodBattery::_threshold[] PROGMEM = "threshold";
const char UsermodBattery::_preset[] PROGMEM = "preset"; const char UsermodBattery::_preset[] PROGMEM = "preset";
const char UsermodBattery::_duration[] PROGMEM = "duration"; const char UsermodBattery::_duration[] PROGMEM = "duration";

View File

@@ -8,21 +8,25 @@
#define RTC_DELTA 2 // only modify RTC time if delta exceeds this number of seconds #define RTC_DELTA 2 // only modify RTC time if delta exceeds this number of seconds
//Connect DS1307 to standard I2C pins (ESP32: GPIO 21 (SDA)/GPIO 22 (SCL)) //Connect DS1307 or DS3231 to standard I2C pins (ESP32: GPIO 21 (SDA)/GPIO 22 (SCL))
class RTCUsermod : public Usermod { class RTCUsermod : public Usermod {
private: private:
unsigned long lastTime = 0; unsigned long lastTime = 0;
bool disabled = false; bool RTCfound = false; // WLEDMM to prevent errors after anabling the usermod (Wire.cpp:526] write(): NULL TX buffer pointer)
public: public:
RTCUsermod(const char *name, bool enabled):Usermod(name, enabled) {} //WLEDMM: this shouldn't be necessary (passthrough of constructor), maybe because Usermod is an abstract class
void setup() { void setup() {
RTCfound = false; // WLEDMM
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } }; PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if (pins[1].pin < 0 || pins[0].pin < 0) { disabled=true; return; } //WLEDMM bugfix - ensure that "final" GPIO are valid and no "-1" sneaks trough if (pins[1].pin < 0 || pins[0].pin < 0) { enabled=false; return; } //WLEDMM bugfix - ensure that "final" GPIO are valid and no "-1" sneaks trough
if (!enabled) { DEBUG_PRINTLN(F("RTC usermod not enabled.")); return; }
// WLEDMM join hardware I2C // WLEDMM join hardware I2C
if (!pinManager.joinWire()) { // WLEDMM - this allocates global I2C pins, then starts Wire - if not started previously if (!pinManager.joinWire()) { // WLEDMM - this allocates global I2C pins, then starts Wire - if not started previously
disabled = true; enabled = false;
return; return;
} }
@@ -40,20 +44,31 @@ class RTCUsermod : public Usermod {
updateLocalTime(); updateLocalTime();
USER_PRINTLN(F("Localtime updated from RTC.")); USER_PRINTLN(F("Localtime updated from RTC."));
} else { } else {
if (!RTC.chipPresent()) disabled = true; //don't waste time if H/W error if (!RTC.chipPresent()) {
enabled = false; //don't waste time if H/W error
USER_PRINTLN(F("RTC board not present."));
}
} }
if (enabled) RTCfound = true; // WLEDMM
} }
void loop() { void loop() {
if (strip.isUpdating()) return; // WLEDMM begin
if (!disabled && toki.isTick()) { if (!enabled) return;
if (!RTCfound) return; // WLEDMM
unsigned long currentTime = millis(); // get the current elapsed time
if (strip.isUpdating() && (currentTime - lastTime < 10000)) return; // WLEDMM: be nice
// WLEDMM end
if (enabled && toki.isTick()) { // WLEDMM
time_t t = toki.second(); time_t t = toki.second();
lastTime = millis(); // WLEDMM
if (abs(t - RTC.get())> RTC_DELTA) { // WLEDMM only consider time diffs > 2 seconds if (abs(t - RTC.get())> RTC_DELTA) { // WLEDMM only consider time diffs > 2 seconds
if ( (toki.getTimeSource() == TOKI_TS_NTP) if ( (toki.getTimeSource() == TOKI_TS_NTP)
||( (toki.getTimeSource() != TOKI_TS_NONE) && (toki.getTimeSource() != TOKI_TS_RTC) ||( (toki.getTimeSource() != TOKI_TS_NONE) && (toki.getTimeSource() != TOKI_TS_RTC)
&& (toki.getTimeSource() != TOKI_TS_BAD) && (toki.getTimeSource() != TOKI_TS_UDP_SEC) && (toki.getTimeSource() != TOKI_TS_UDP))) && (toki.getTimeSource() != TOKI_TS_BAD) && (toki.getTimeSource() != TOKI_TS_UDP_SEC) && (toki.getTimeSource() != TOKI_TS_UDP)))
{ // WLEMM update RTC if we have a reliable time source { // WLEDMM update RTC if we have a reliable time source
RTC.set(t); //set RTC to NTP/UI-provided value - WLEDMM allow up to 3 sec deviation RTC.set(t); //set RTC to NTP/UI-provided value - WLEDMM allow up to 3 sec deviation
USER_PRINTLN(F("RTC updated using localtime.")); USER_PRINTLN(F("RTC updated using localtime."));
} else { } else {

View File

@@ -449,9 +449,9 @@ void FFTcode(void * parameter)
} }
#if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS) #if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS)
// timing
uint64_t start = esp_timer_get_time(); uint64_t start = esp_timer_get_time();
bool haveDoneFFT = false; // indicates if second measurement (FFT time) is valid bool haveDoneFFT = false; // indicates if second measurement (FFT time) is valid
static uint64_t lastCycleStart = 0; static uint64_t lastCycleStart = 0;
static uint64_t lastLastTime = 0; static uint64_t lastLastTime = 0;
if ((lastCycleStart > 0) && (lastCycleStart < start)) { // filter out overflows if ((lastCycleStart > 0) && (lastCycleStart < start)) { // filter out overflows
@@ -466,6 +466,14 @@ void FFTcode(void * parameter)
if (audioSource) audioSource->getSamples(vReal, samplesFFT); if (audioSource) audioSource->getSamples(vReal, samplesFFT);
#if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS) #if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS)
// debug info in case that stack usage changes
static unsigned int minStackFree = UINT32_MAX;
unsigned int stackFree = uxTaskGetStackHighWaterMark(NULL);
if (minStackFree > stackFree) {
minStackFree = stackFree;
DEBUGSR_PRINTF("|| %-9s min free stack %d\n", pcTaskGetTaskName(NULL), minStackFree); //WLEDMM
}
// timing
if (start < esp_timer_get_time()) { // filter out overflows if (start < esp_timer_get_time()) { // filter out overflows
uint64_t sampleTimeInMillis = (esp_timer_get_time() - start +5ULL) / 10ULL; // "+5" to ensure proper rounding uint64_t sampleTimeInMillis = (esp_timer_get_time() - start +5ULL) / 10ULL; // "+5" to ensure proper rounding
sampleTime = (sampleTimeInMillis*3 + sampleTime*7)/10.0; // smooth sampleTime = (sampleTimeInMillis*3 + sampleTime*7)/10.0; // smooth
@@ -715,6 +723,7 @@ void FFTcode(void * parameter)
postProcessFFTResults((fabsf(volumeSmth)>0.25f)? true : false , NUM_GEQ_CHANNELS); // this function modifies fftCalc, fftAvg and fftResult postProcessFFTResults((fabsf(volumeSmth)>0.25f)? true : false , NUM_GEQ_CHANNELS); // this function modifies fftCalc, fftAvg and fftResult
#if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS) #if defined(WLED_DEBUG) || defined(SR_DEBUG)|| defined(SR_STATS)
// timing
static uint64_t lastLastFFT = 0; static uint64_t lastLastFFT = 0;
if (haveDoneFFT && (start < esp_timer_get_time())) { // filter out overflows if (haveDoneFFT && (start < esp_timer_get_time())) { // filter out overflows
uint64_t fftTimeInMillis = ((esp_timer_get_time() - start) +5ULL) / 10ULL; // "+5" to ensure proper rounding uint64_t fftTimeInMillis = ((esp_timer_get_time() - start) +5ULL) / 10ULL; // "+5" to ensure proper rounding
@@ -1678,7 +1687,13 @@ class AudioReactive : public Usermod {
//useInputFilter = 0; // in case you need to disable low-cut software filtering //useInputFilter = 0; // in case you need to disable low-cut software filtering
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE); audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
delay(100); delay(100);
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin); // WLEDMM align global pins
if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined)
if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin;
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
if (i2c_scl >= 0) sclPin = -1;
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break; break;
case 3: case 3:
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT)); DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
@@ -1710,11 +1725,21 @@ class AudioReactive : public Usermod {
break; break;
#endif #endif
case 6: case 6:
DEBUGSR_PRINTLN(F("AR: ES8388 Source")); #ifdef use_es8388_mic
DEBUGSR_PRINTLN(F("AR: ES8388 Source (Mic)"));
#else
DEBUGSR_PRINTLN(F("AR: ES8388 Source (Line-In)"));
#endif
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f); audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f);
//useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour //useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour
delay(100); delay(100);
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin); // WLEDMM align global pins
if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined)
if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin;
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
if (i2c_scl >= 0) sclPin = -1;
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break; break;
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
@@ -1758,6 +1783,10 @@ class AudioReactive : public Usermod {
DEBUGSR_PRINT(F("AR: init done, enabled = ")); DEBUGSR_PRINT(F("AR: init done, enabled = "));
DEBUGSR_PRINTLN(enabled ? F("true.") : F("false.")); DEBUGSR_PRINTLN(enabled ? F("true.") : F("false."));
USER_FLUSH(); USER_FLUSH();
#if defined(ARDUINO_ARCH_ESP32) && defined(SR_DEBUG)
DEBUGSR_PRINTF("|| %-9s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM
#endif
} }
@@ -1788,6 +1817,10 @@ class AudioReactive : public Usermod {
DEBUGSR_PRINTLN(udpSyncConnected ? F("AR connected(): UDP: connected to WIFI.") : F("AR connected(): UDP is disconnected (Wifi).")); DEBUGSR_PRINTLN(udpSyncConnected ? F("AR connected(): UDP: connected to WIFI.") : F("AR connected(): UDP is disconnected (Wifi)."));
} }
} }
#if defined(ARDUINO_ARCH_ESP32) && defined(SR_DEBUG)
DEBUGSR_PRINTF("|| %-9s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM
#endif
} }
@@ -1844,6 +1877,15 @@ class AudioReactive : public Usermod {
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source
#ifdef SR_DEBUG
// debug info in case that task stack usage changes
static unsigned int minLoopStackFree = UINT32_MAX;
unsigned int stackFree = uxTaskGetStackHighWaterMark(NULL);
if (minLoopStackFree > stackFree) {
minLoopStackFree = stackFree;
DEBUGSR_PRINTF("|| %-9s min free stack %d\n", pcTaskGetTaskName(NULL), minLoopStackFree); //WLEDMM
}
#endif
// Only run the sampling code IF we're not in Receive mode or realtime mode // Only run the sampling code IF we're not in Receive mode or realtime mode
if (!(audioSyncEnabled & 0x02) && !disableSoundProcessing) { if (!(audioSyncEnabled & 0x02) && !disableSoundProcessing) {
@@ -2040,6 +2082,10 @@ class AudioReactive : public Usermod {
micDataReal = 0.0f; // just to be sure micDataReal = 0.0f; // just to be sure
if (enabled) disableSoundProcessing = false; if (enabled) disableSoundProcessing = false;
updateIsRunning = init; updateIsRunning = init;
#if defined(ARDUINO_ARCH_ESP32) && defined(SR_DEBUG)
DEBUGSR_PRINTF("|| %-9s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM
#endif
} }
#else // reduced function for 8266 #else // reduced function for 8266
@@ -2336,6 +2382,11 @@ class AudioReactive : public Usermod {
JsonObject dmic = top.createNestedObject(FPSTR(_digitalmic)); JsonObject dmic = top.createNestedObject(FPSTR(_digitalmic));
dmic[F("type")] = dmType; dmic[F("type")] = dmType;
// WLEDMM: align with globals I2C pins
if ((dmType == 2) || (dmType == 6)) { // only for ES7243 and ES8388
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
if (i2c_scl >= 0) sclPin = -1; // -1 = use global
}
JsonArray pinArray = dmic.createNestedArray("pin"); JsonArray pinArray = dmic.createNestedArray("pin");
pinArray.add(i2ssdPin); pinArray.add(i2ssdPin);
pinArray.add(i2swsPin); pinArray.add(i2swsPin);

View File

@@ -126,7 +126,7 @@ class AudioSource {
This function needs to take care of anything that needs to be done This function needs to take care of anything that needs to be done
before samples can be obtained from the microphone. before samples can be obtained from the microphone.
*/ */
virtual void initialize(int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) = 0; virtual void initialize(int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) = 0;
/* Deinitialize /* Deinitialize
Release all resources and deactivate any functionality that is used Release all resources and deactivate any functionality that is used
@@ -206,7 +206,8 @@ class I2SSource : public AudioSource {
}; };
} }
virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN("I2SSource:: initialize().");
if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) { if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) {
if (!pinManager.allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) || if (!pinManager.allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) ||
!pinManager.allocatePin(i2ssdPin, false, PinOwner::UM_Audioreactive)) { // #206 !pinManager.allocatePin(i2ssdPin, false, PinOwner::UM_Audioreactive)) { // #206
@@ -444,19 +445,14 @@ class ES7243 : public I2SSource {
private: private:
// I2C initialization functions for ES7243 // I2C initialization functions for ES7243
void _es7243I2cBegin() { void _es7243I2cBegin() {
bool i2c_initialized = Wire.begin(pin_ES7243_SDA, pin_ES7243_SCL, 100000U); Wire.setClock(100000);
if (i2c_initialized == false) {
ERRORSR_PRINTLN(F("AR: ES7243 failed to initialize I2C bus driver."));
}
} }
void _es7243I2cWrite(uint8_t reg, uint8_t val) { void _es7243I2cWrite(uint8_t reg, uint8_t val) {
#ifndef ES7243_ADDR #ifndef ES7243_ADDR
Wire.beginTransmission(0x13); #define ES7243_ADDR 0x13 // default address
#define ES7243_ADDR 0x13 // default address #endif
#else
Wire.beginTransmission(ES7243_ADDR); Wire.beginTransmission(ES7243_ADDR);
#endif
Wire.write((uint8_t)reg); Wire.write((uint8_t)reg);
Wire.write((uint8_t)val); Wire.write((uint8_t)val);
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
@@ -481,53 +477,30 @@ public:
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT; _config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
}; };
void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
// check that pins are valid DEBUGSR_PRINTLN("ES7243:: initialize();");
if ((sdaPin < 0) || (sclPin < 0)) {
ERRORSR_PRINTF("\nAR: invalid ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
return;
}
if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" // if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too
// ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
// return;
// }
if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined"
ERRORSR_PRINTF("\nAR: invalid ES7243 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); ERRORSR_PRINTF("\nAR: invalid ES7243 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
return; return;
} }
if (!pinManager.joinWire()) { // WLEDMM specific: start I2C with globally defined pins if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins
ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
return; return;
} }
if ((i2sckPin < 0) || (mclkPin < 0)) {
ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
return;
}
// Reserve SDA and SCL pins of the I2C interface
PinManagerPinType es7243Pins[2] = { { sdaPin, true }, { sclPin, true } };
if (!pinManager.allocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C)) {
pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C);
ERRORSR_PRINTF("\nAR: Failed to allocate ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
return;
}
pin_ES7243_SDA = sdaPin;
pin_ES7243_SCL = sclPin;
// First route mclk, then configure ADC over I2C, then configure I2S // First route mclk, then configure ADC over I2C, then configure I2S
_es7243InitAdc(); _es7243InitAdc();
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
} }
void deinitialize() { void deinitialize() {
// Release SDA and SCL pins of the I2C interface
PinManagerPinType es7243Pins[2] = { { pin_ES7243_SDA, true }, { pin_ES7243_SCL, true } };
pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C);
I2SSource::deinitialize(); I2SSource::deinitialize();
} }
private:
int8_t pin_ES7243_SDA;
int8_t pin_ES7243_SCL;
}; };
/* ES8388 Sound Modude /* ES8388 Sound Modude
@@ -538,19 +511,14 @@ class ES8388Source : public I2SSource {
private: private:
// I2C initialization functions for ES8388 // I2C initialization functions for ES8388
void _es8388I2cBegin() { void _es8388I2cBegin() {
bool i2c_initialized = Wire.begin(pin_ES8388_SDA, pin_ES8388_SCL, 100000U); Wire.setClock(100000);
if (i2c_initialized == false) {
ERRORSR_PRINTLN(F("AR: ES8388 failed to initialize I2C bus driver."));
}
} }
void _es8388I2cWrite(uint8_t reg, uint8_t val) { void _es8388I2cWrite(uint8_t reg, uint8_t val) {
#ifndef ES8388_ADDR #ifndef ES8388_ADDR
Wire.beginTransmission(0x10); #define ES8388_ADDR 0x10 // default address
#define ES8388_ADDR 0x10 // default address #endif
#else
Wire.beginTransmission(ES8388_ADDR); Wire.beginTransmission(ES8388_ADDR);
#endif
Wire.write((uint8_t)reg); Wire.write((uint8_t)reg);
Wire.write((uint8_t)val); Wire.write((uint8_t)val);
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
@@ -637,58 +605,34 @@ class ES8388Source : public I2SSource {
_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT; _config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
}; };
void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
DEBUGSR_PRINTLN("ES8388Source:: initialize();");
// if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too
// ERRORSR_PRINTF("\nAR: invalid I2S ES8388 pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
// return;
// }
// BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here. // BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here.
// Workaround: Set I2C pins here, which will also set them globally. // Workaround: Set I2C pins here, which will also set them globally.
// Bug also exists in ES7243. // Bug also exists in ES7243.
// check that pins are valid
if ((sdaPin < 0) || (sclPin < 0)) {
ERRORSR_PRINTF("\nAR: invalid ES8388 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
return;
}
if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined"
ERRORSR_PRINTF("\nAR: invalid ES8388 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); ERRORSR_PRINTF("\nAR: invalid ES8388 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
return; return;
} }
if (!pinManager.joinWire()) { // WLEDMM specific: start I2C with globally defined pins if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins
ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
return; return;
} }
if ((i2sckPin < 0) || (mclkPin < 0)) {
ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
return;
}
// Reserve SDA and SCL pins of the I2C interface
PinManagerPinType es8388Pins[2] = { { sdaPin, true }, { sclPin, true } };
if (!pinManager.allocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C)) {
pinManager.deallocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C);
ERRORSR_PRINTF("\nAR: Failed to allocate ES8388 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
return;
}
pin_ES8388_SDA = sdaPin;
pin_ES8388_SCL = sclPin;
// First route mclk, then configure ADC over I2C, then configure I2S // First route mclk, then configure ADC over I2C, then configure I2S
_es8388InitAdc(); _es8388InitAdc();
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
} }
void deinitialize() { void deinitialize() {
// Release SDA and SCL pins of the I2C interface
PinManagerPinType es8388Pins[2] = { { pin_ES8388_SDA, true }, { pin_ES8388_SCL, true } };
pinManager.deallocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C);
I2SSource::deinitialize(); I2SSource::deinitialize();
} }
private:
int8_t pin_ES8388_SDA;
int8_t pin_ES8388_SCL;
}; };
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
@@ -731,7 +675,8 @@ class I2SAdcSource : public I2SSource {
/* identify Audiosource type - I2S-ADC*/ /* identify Audiosource type - I2S-ADC*/
AudioSourceType getType(void) {return(Type_I2SAdc);} AudioSourceType getType(void) {return(Type_I2SAdc);}
void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN("I2SAdcSource:: initialize().");
_myADCchannel = 0x0F; _myADCchannel = 0x0F;
if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) { if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) {
ERRORSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin); ERRORSR_PRINTF("failed to allocate GPIO for audio analog input: %d\n", audioPin);
@@ -902,7 +847,8 @@ class SPH0654 : public I2SSource {
I2SSource(sampleRate, blockSize, sampleScale, i2sMaster) I2SSource(sampleRate, blockSize, sampleScale, i2sMaster)
{} {}
void initialize(uint8_t i2swsPin, uint8_t i2ssdPin, uint8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTLN("SPH0654:: initialize();");
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin);
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// these registers are only existing in "classic" ESP32 // these registers are only existing in "classic" ESP32

View File

@@ -5303,6 +5303,7 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
oldSpawnColor = SEGMENT.getPixelColorXY(SEGENV.aux0, SEGENV.aux1); // find color of previous spawns oldSpawnColor = SEGMENT.getPixelColorXY(SEGENV.aux0, SEGENV.aux1); // find color of previous spawns
SEGENV.aux1 ++; // our sample pixel will be one row down the next time SEGENV.aux1 ++; // our sample pixel will be one row down the next time
} }
if ((oldSpawnColor == CRGB::Black) || (oldSpawnColor == trailColor)) oldSpawnColor = spawnColor; // reject "black", as it would mean that ALL pixels create trails
// move pixels one row down. Falling codes keep color and add trail pixels; all others pixels are faded // move pixels one row down. Falling codes keep color and add trail pixels; all others pixels are faded
for (int row=rows-1; row>=0; row--) { for (int row=rows-1; row>=0; row--) {
@@ -5313,7 +5314,7 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
if (row < rows-1) SEGMENT.setPixelColorXY(col, row+1, spawnColor); if (row < rows-1) SEGMENT.setPixelColorXY(col, row+1, spawnColor);
} else { } else {
// fade other pixels // fade other pixels
SEGMENT.setPixelColorXY(col, row, pix.nscale8(fade)); if (pix != CRGB::Black) SEGMENT.setPixelColorXY(col, row, pix.nscale8(fade)); // optimization: don't fade black pixels
} }
} }
} }

View File

@@ -222,7 +222,7 @@ void registerUsermods()
*/ */
//usermods.add(new MyExampleUsermod()); //usermods.add(new MyExampleUsermod());
#ifdef USERMOD_BATTERY #ifdef USERMOD_BATTERY
usermods.add(new UsermodBattery()); usermods.add(new UsermodBattery("Battery", true));
#endif #endif
#ifdef USERMOD_DALLASTEMPERATURE #ifdef USERMOD_DALLASTEMPERATURE
@@ -290,7 +290,7 @@ void registerUsermods()
#endif #endif
#ifdef USERMOD_RTC #ifdef USERMOD_RTC
usermods.add(new RTCUsermod()); usermods.add(new RTCUsermod("RTC", true));
#endif #endif
#ifdef USERMOD_ELEKSTUBE_IPS #ifdef USERMOD_ELEKSTUBE_IPS