Merge branch '0_15' into HUB75-AC

This commit is contained in:
Will Tatam
2024-09-22 15:12:37 +01:00
89 changed files with 1837 additions and 2091 deletions

View File

@@ -1,34 +1,28 @@
#include "pin_manager.h"
#include "wled.h"
#ifdef WLED_DEBUG
static void DebugPrintOwnerTag(PinOwner tag)
{
uint32_t q = static_cast<uint8_t>(tag);
if (q) {
DEBUG_PRINTF_P(PSTR("0x%02x (%d)"), q, q);
} else {
DEBUG_PRINT(F("(no owner)"));
}
}
#ifdef ARDUINO_ARCH_ESP32
#ifdef bitRead
// Arduino variants assume 32 bit values
#undef bitRead
#undef bitSet
#undef bitClear
#define bitRead(var,bit) (((unsigned long long)(var)>>(bit))&0x1ULL)
#define bitSet(var,bit) ((var)|=(1ULL<<(bit)))
#define bitClear(var,bit) ((var)&=(~(1ULL<<(bit))))
#endif
#endif
/// Actual allocation/deallocation routines
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
bool PinManager::deallocatePin(byte gpio, PinOwner tag)
{
if (gpio == 0xFF) return true; // explicitly allow clients to free -1 as a no-op
if (!isPinOk(gpio, false)) return false; // but return false for any other invalid pin
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN DEALLOC: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINT(F(", but attempted de-allocation by "));
DebugPrintOwnerTag(tag);
#endif
DEBUG_PRINTF_P(PSTR("PIN DEALLOC: FAIL GPIO %d allocated by 0x%02X, but attempted de-allocation by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]), static_cast<int>(tag));
return false;
}
@@ -38,7 +32,7 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
}
// support function for deallocating multiple pins
bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag)
bool PinManager::deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag)
{
bool shouldFail = false;
DEBUG_PRINTLN(F("MULTIPIN DEALLOC"));
@@ -54,14 +48,7 @@ bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte array
// if the current pin is allocated by selected owner it is possible to release it
continue;
}
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN DEALLOC: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINT(F(", but attempted de-allocation by "));
DebugPrintOwnerTag(tag);
#endif
DEBUG_PRINTF_P(PSTR("PIN DEALLOC: FAIL GPIO %d allocated by 0x%02X, but attempted de-allocation by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]), static_cast<int>(tag));
shouldFail = true;
}
if (shouldFail) {
@@ -85,14 +72,14 @@ bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte array
return true;
}
bool PinManagerClass::deallocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
bool PinManager::deallocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
{
uint8_t pins[arrayElementCount];
for (int i=0; i<arrayElementCount; i++) pins[i] = mptArray[i].pin;
return deallocateMultiplePins(pins, arrayElementCount, tag);
}
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
bool PinManager::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
{
bool shouldFail = false;
// first verify the pins are OK and not already allocated
@@ -104,25 +91,14 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
continue;
}
if (!isPinOk(gpio, mptArray[i].isOutput)) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: GPIO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" as ")); DEBUG_PRINT(mptArray[i].isOutput ? F("output"): F("input"));
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL Invalid pin attempted to be allocated: GPIO %d as %s\n."), gpio, mptArray[i].isOutput ? PSTR("output"): PSTR("input"));
shouldFail = true;
}
if ((tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) && isPinAllocated(gpio, tag)) {
// allow multiple "allocations" of HW I2C & SPI bus pins
continue;
} else if (isPinAllocated(gpio)) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" already allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d already allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
shouldFail = true;
}
}
@@ -146,70 +122,51 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
bitWrite(pinAlloc, gpio, true);
ownerTag[gpio] = tag;
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" allocated by "));
DebugPrintOwnerTag(tag);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: Pin %d allocated by 0x%02X.\n"), gpio, static_cast<int>(tag));
}
DEBUG_PRINTF_P(PSTR("PIN ALLOC: 0x%014llX.\n"), (unsigned long long)pinAlloc);
return true;
}
bool PinManagerClass::allocateMultiplePins(const int8_t * mptArray, byte arrayElementCount, PinOwner tag, boolean output) {
bool PinManager::allocateMultiplePins(const int8_t * mptArray, byte arrayElementCount, PinOwner tag, boolean output) {
PinManagerPinType pins[arrayElementCount];
for (int i=0; i<arrayElementCount; i++) pins[i] = {mptArray[i], output};
return allocateMultiplePins(pins, arrayElementCount, tag);
}
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
bool PinManager::allocatePin(byte gpio, bool output, PinOwner tag)
{
// HW I2C & SPI pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair
if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) {
#ifdef WLED_DEBUG
if (gpio < 255) { // 255 (-1) is the "not defined GPIO"
if (!isPinOk(gpio, output)) {
DEBUG_PRINT(F("PIN ALLOC: FAIL for owner "));
DebugPrintOwnerTag(tag);
DEBUG_PRINT(F(": GPIO ")); DEBUG_PRINT(gpio);
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL for owner 0x%02X: GPIO %d "), static_cast<int>(tag), gpio);
if (output) DEBUG_PRINTLN(F(" cannot be used for i/o on this MCU."));
else DEBUG_PRINTLN(F(" cannot be used as input on this MCU."));
} else {
DEBUG_PRINT(F("PIN ALLOC: FAIL: GPIO ")); DEBUG_PRINT(gpio);
DEBUG_PRINTLN(F(" - HW I2C & SPI pins have to be allocated using allocateMultiplePins()"));
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d - HW I2C & SPI pins have to be allocated using allocateMultiplePins.\n"), gpio);
}
}
#endif
return false;
}
if (isPinAllocated(gpio)) {
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" already allocated by "));
DebugPrintOwnerTag(ownerTag[gpio]);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL Pin %d already allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
return false;
}
bitWrite(pinAlloc, gpio, true);
ownerTag[gpio] = tag;
#ifdef WLED_DEBUG
DEBUG_PRINT(F("PIN ALLOC: Pin "));
DEBUG_PRINT(gpio);
DEBUG_PRINT(F(" successfully allocated by "));
DebugPrintOwnerTag(tag);
DEBUG_PRINTLN(F(""));
#endif
DEBUG_PRINTF_P(PSTR("PIN ALLOC: Pin %d successfully allocated by 0x%02X.\n"), gpio, static_cast<int>(ownerTag[gpio]));
DEBUG_PRINTF_P(PSTR("PIN ALLOC: 0x%014llX.\n"), (unsigned long long)pinAlloc);
return true;
}
// if tag is set to PinOwner::None, checks for ANY owner of the pin.
// if tag is set to any other value, checks if that tag is the current owner of the pin.
bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) const
bool PinManager::isPinAllocated(byte gpio, PinOwner tag)
{
if (!isPinOk(gpio, false)) return true;
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
@@ -233,7 +190,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) const
*/
// Check if supplied GPIO is ok to use
bool PinManagerClass::isPinOk(byte gpio, bool output) const
bool PinManager::isPinOk(byte gpio, bool output)
{
if (gpio >= WLED_NUM_PINS) return false; // catch error case, to avoid array out-of-bounds access
#ifdef ARDUINO_ARCH_ESP32
@@ -273,14 +230,22 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const
return false;
}
PinOwner PinManagerClass::getPinOwner(byte gpio) const
bool PinManager::isReadOnlyPin(byte gpio)
{
#ifdef ARDUINO_ARCH_ESP32
if (gpio < WLED_NUM_PINS) return (digitalPinIsValid(gpio) && !digitalPinCanOutput(gpio));
#endif
return false;
}
PinOwner PinManager::getPinOwner(byte gpio)
{
if (!isPinOk(gpio, false)) return PinOwner::None;
return ownerTag[gpio];
}
#ifdef ARDUINO_ARCH_ESP32
byte PinManagerClass::allocateLedc(byte channels)
byte PinManager::allocateLedc(byte channels)
{
if (channels > WLED_MAX_ANALOG_CHANNELS || channels == 0) return 255;
unsigned ca = 0;
@@ -307,7 +272,7 @@ byte PinManagerClass::allocateLedc(byte channels)
return 255; //not enough consecutive free LEDC channels
}
void PinManagerClass::deallocateLedc(byte pos, byte channels)
void PinManager::deallocateLedc(byte pos, byte channels)
{
for (unsigned j = pos; j < pos + channels && j < WLED_MAX_ANALOG_CHANNELS; j++) {
bitWrite(ledcAlloc, j, false);
@@ -315,4 +280,12 @@ void PinManagerClass::deallocateLedc(byte pos, byte channels)
}
#endif
PinManagerClass pinManager = PinManagerClass();
#ifdef ESP8266
uint32_t PinManager::pinAlloc = 0UL;
#else
uint64_t PinManager::pinAlloc = 0ULL;
uint16_t PinManager::ledcAlloc = 0;
#endif
uint8_t PinManager::i2cAllocCount = 0;
uint8_t PinManager::spiAllocCount = 0;
PinOwner PinManager::ownerTag[WLED_NUM_PINS] = { PinOwner::None };