Merge pull request #2415 from Aircoookie/i2c-sharing
Pin manager support for sharing multipin buses.
This commit is contained in:
commit
c27117e99e
@ -1,6 +1,7 @@
|
|||||||
#include "pin_manager.h"
|
#include "pin_manager.h"
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
static void DebugPrintOwnerTag(PinOwner tag)
|
static void DebugPrintOwnerTag(PinOwner tag)
|
||||||
{
|
{
|
||||||
uint32_t q = static_cast<uint8_t>(tag);
|
uint32_t q = static_cast<uint8_t>(tag);
|
||||||
@ -10,6 +11,7 @@ static void DebugPrintOwnerTag(PinOwner tag)
|
|||||||
DEBUG_PRINT(F("(no owner)"));
|
DEBUG_PRINT(F("(no owner)"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Actual allocation/deallocation routines
|
/// Actual allocation/deallocation routines
|
||||||
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
||||||
@ -19,12 +21,14 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
|||||||
|
|
||||||
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
|
// if a non-zero ownerTag, only allow de-allocation if the owner's tag is provided
|
||||||
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
|
if ((ownerTag[gpio] != PinOwner::None) && (ownerTag[gpio] != tag)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN DEALLOC: IO "));
|
DEBUG_PRINT(F("PIN DEALLOC: IO "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINT(F(" allocated by "));
|
DEBUG_PRINT(F(" allocated by "));
|
||||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||||
DEBUG_PRINT(F(", but attempted de-allocation by "));
|
DEBUG_PRINT(F(", but attempted de-allocation by "));
|
||||||
DebugPrintOwnerTag(tag);
|
DebugPrintOwnerTag(tag);
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +38,49 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag)
|
|||||||
ownerTag[gpio] = PinOwner::None;
|
ownerTag[gpio] = PinOwner::None;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// support function for deallocating multiple pins
|
||||||
|
bool PinManagerClass::deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag)
|
||||||
|
{
|
||||||
|
bool shouldFail = false;
|
||||||
|
DEBUG_PRINTLN(F("MULTIPIN DEALLOC"));
|
||||||
|
// first verify the pins are OK and allocated by selected owner
|
||||||
|
for (int i = 0; i < arrayElementCount; i++) {
|
||||||
|
byte gpio = pinArray[i];
|
||||||
|
if (gpio == 0xFF) {
|
||||||
|
// explicit support for io -1 as a no-op (no allocation of pin),
|
||||||
|
// as this can greatly simplify configuration arrays
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isPinAllocated(gpio, tag)) {
|
||||||
|
// 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
|
||||||
|
shouldFail = true;
|
||||||
|
}
|
||||||
|
if (shouldFail) {
|
||||||
|
return false; // no pins deallocated
|
||||||
|
}
|
||||||
|
if (tag==PinOwner::HW_I2C) {
|
||||||
|
if (i2cAllocCount && --i2cAllocCount>0) {
|
||||||
|
// no deallocation done until last owner releases pins
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < arrayElementCount; i++) {
|
||||||
|
deallocatePin(pinArray[i], tag);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
|
bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag)
|
||||||
{
|
{
|
||||||
bool shouldFail = false;
|
bool shouldFail = false;
|
||||||
@ -46,17 +93,24 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isPinOk(gpio, mptArray[i].isOutput)) {
|
if (!isPinOk(gpio, mptArray[i].isOutput)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: "));
|
DEBUG_PRINT(F("PIN ALLOC: Invalid pin attempted to be allocated: "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
#endif
|
||||||
shouldFail = true;
|
shouldFail = true;
|
||||||
}
|
}
|
||||||
if (isPinAllocated(gpio)) {
|
if (tag==PinOwner::HW_I2C && isPinAllocated(gpio, tag)) {
|
||||||
|
// allow multiple "allocations" of HW I2C bus pins
|
||||||
|
continue;
|
||||||
|
} else if (isPinAllocated(gpio)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
|
DEBUG_PRINT(F("PIN ALLOC: FAIL: IO "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINT(F(" already allocated by "));
|
DEBUG_PRINT(F(" already allocated by "));
|
||||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
#endif
|
||||||
shouldFail = true;
|
shouldFail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,6 +118,8 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag==PinOwner::HW_I2C) i2cAllocCount++;
|
||||||
|
|
||||||
// all pins are available .. track each one
|
// all pins are available .. track each one
|
||||||
for (int i = 0; i < arrayElementCount; i++) {
|
for (int i = 0; i < arrayElementCount; i++) {
|
||||||
byte gpio = mptArray[i].pin;
|
byte gpio = mptArray[i].pin;
|
||||||
@ -79,15 +135,19 @@ bool PinManagerClass::allocateMultiplePins(const managed_pin_type * mptArray, by
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
|
bool PinManagerClass::allocatePin(byte gpio, bool output, PinOwner tag)
|
||||||
{
|
{
|
||||||
if (!isPinOk(gpio, output)) return false;
|
// HW I2C pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair
|
||||||
|
if (!isPinOk(gpio, output) || tag==PinOwner::HW_I2C) return false;
|
||||||
if (isPinAllocated(gpio)) {
|
if (isPinAllocated(gpio)) {
|
||||||
|
#ifdef WLED_DEBUG
|
||||||
DEBUG_PRINT(F("PIN ALLOC: Pin "));
|
DEBUG_PRINT(F("PIN ALLOC: Pin "));
|
||||||
DEBUG_PRINT(gpio);
|
DEBUG_PRINT(gpio);
|
||||||
DEBUG_PRINT(F(" already allocated by "));
|
DEBUG_PRINT(F(" already allocated by "));
|
||||||
DebugPrintOwnerTag(ownerTag[gpio]);
|
DebugPrintOwnerTag(ownerTag[gpio]);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +166,7 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag)
|
|||||||
if (!isPinOk(gpio, false)) return true;
|
if (!isPinOk(gpio, false)) return true;
|
||||||
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
|
if ((tag != PinOwner::None) && (ownerTag[gpio] != tag)) return false;
|
||||||
byte by = gpio >> 3;
|
byte by = gpio >> 3;
|
||||||
byte bi = gpio - 8*by;
|
byte bi = gpio - (by<<3);
|
||||||
return bitRead(pinAlloc[by], bi);
|
return bitRead(pinAlloc[by], bi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
#include "const.h" // for USERMOD_* values
|
#include "const.h" // for USERMOD_* values
|
||||||
|
|
||||||
typedef struct PinManagerPinType {
|
typedef struct PinManagerPinType {
|
||||||
int8_t pin;
|
int8_t pin;
|
||||||
uint8_t isOutput;
|
bool isOutput;
|
||||||
} managed_pin_type;
|
} managed_pin_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -21,9 +21,8 @@ typedef struct PinManagerPinType {
|
|||||||
* 40 bytes on ESP32
|
* 40 bytes on ESP32
|
||||||
*/
|
*/
|
||||||
enum struct PinOwner : uint8_t {
|
enum struct PinOwner : uint8_t {
|
||||||
None = 0, // default == legacy == unspecified owner
|
None = 0, // default == legacy == unspecified owner
|
||||||
// High bit is set for all built-in pin owners
|
// High bit is set for all built-in pin owners
|
||||||
// StatusLED -- THIS SHOULD NEVER BE ALLOCATED -- see handleStatusLED()
|
|
||||||
Ethernet = 0x81,
|
Ethernet = 0x81,
|
||||||
BusDigital = 0x82,
|
BusDigital = 0x82,
|
||||||
BusDigital2 = 0x83,
|
BusDigital2 = 0x83,
|
||||||
@ -34,26 +33,27 @@ enum struct PinOwner : uint8_t {
|
|||||||
SPI_RAM = 0x88, // 'SpiR' == SPI RAM
|
SPI_RAM = 0x88, // 'SpiR' == SPI RAM
|
||||||
DebugOut = 0x89, // 'Dbg' == debug output always IO1
|
DebugOut = 0x89, // 'Dbg' == debug output always IO1
|
||||||
DMX = 0x8A, // 'DMX' == hard-coded to IO2
|
DMX = 0x8A, // 'DMX' == hard-coded to IO2
|
||||||
|
HW_I2C = 0x8B, // 'I2C' == hardware I2C pins (4&5 on ESP8266, 21&22 on ESP32)
|
||||||
// Use UserMod IDs from const.h here
|
// Use UserMod IDs from const.h here
|
||||||
UM_Unspecified = USERMOD_ID_UNSPECIFIED, // 0x01
|
UM_Unspecified = USERMOD_ID_UNSPECIFIED, // 0x01
|
||||||
UM_Example = USERMOD_ID_EXAMPLE, // 0x02 // Usermod "usermod_v2_example.h"
|
UM_Example = USERMOD_ID_EXAMPLE, // 0x02 // Usermod "usermod_v2_example.h"
|
||||||
UM_Temperature = USERMOD_ID_TEMPERATURE, // 0x03 // Usermod "usermod_temperature.h"
|
UM_Temperature = USERMOD_ID_TEMPERATURE, // 0x03 // Usermod "usermod_temperature.h"
|
||||||
// #define USERMOD_ID_FIXNETSERVICES // 0x04 // Usermod "usermod_Fix_unreachable_netservices.h" -- Does not allocate pins
|
// #define USERMOD_ID_FIXNETSERVICES // 0x04 // Usermod "usermod_Fix_unreachable_netservices.h" -- Does not allocate pins
|
||||||
UM_PIR = USERMOD_ID_PIRSWITCH, // 0x05 // Usermod "usermod_PIR_sensor_switch.h"
|
UM_PIR = USERMOD_ID_PIRSWITCH, // 0x05 // Usermod "usermod_PIR_sensor_switch.h"
|
||||||
// #define USERMOD_ID_IMU // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" I2C pins ... TODO -- enable shared I2C bus use
|
// #define USERMOD_ID_IMU // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" HW_I2C pins
|
||||||
UM_FourLineDisplay = USERMOD_ID_FOUR_LINE_DISP, // 0x07 // Usermod "usermod_v2_four_line_display.h
|
UM_FourLineDisplay = USERMOD_ID_FOUR_LINE_DISP, // 0x07 // Usermod "usermod_v2_four_line_display.h -- May use "standard" HW_I2C pins
|
||||||
UM_RotaryEncoderUI = USERMOD_ID_ROTARY_ENC_UI, // 0x08 // Usermod "usermod_v2_rotary_encoder_ui.h"
|
UM_RotaryEncoderUI = USERMOD_ID_ROTARY_ENC_UI, // 0x08 // Usermod "usermod_v2_rotary_encoder_ui.h"
|
||||||
// #define USERMOD_ID_AUTO_SAVE // 0x09 // Usermod "usermod_v2_auto_save.h" -- Does not allocate pins
|
// #define USERMOD_ID_AUTO_SAVE // 0x09 // Usermod "usermod_v2_auto_save.h" -- Does not allocate pins
|
||||||
// #define USERMOD_ID_DHT // 0x0A // Usermod "usermod_dht.h" -- Statically allocates pins, not compatible with pinManager?
|
// #define USERMOD_ID_DHT // 0x0A // Usermod "usermod_dht.h" -- Statically allocates pins, not compatible with pinManager?
|
||||||
// #define USERMOD_ID_MODE_SORT // 0x0B // Usermod "usermod_v2_mode_sort.h" -- Does not allocate pins
|
// #define USERMOD_ID_MODE_SORT // 0x0B // Usermod "usermod_v2_mode_sort.h" -- Does not allocate pins
|
||||||
// #define USERMOD_ID_VL53L0X // 0x0C // Usermod "usermod_vl53l0x_gestures.h" -- Uses "standard" I2C pins ... TODO -- enable shared I2C bus use
|
// #define USERMOD_ID_VL53L0X // 0x0C // Usermod "usermod_vl53l0x_gestures.h" -- Uses "standard" HW_I2C pins
|
||||||
UM_MultiRelay = USERMOD_ID_MULTI_RELAY, // 0x0D // Usermod "usermod_multi_relay.h"
|
UM_MultiRelay = USERMOD_ID_MULTI_RELAY, // 0x0D // Usermod "usermod_multi_relay.h"
|
||||||
UM_AnimatedStaircase = USERMOD_ID_ANIMATED_STAIRCASE, // 0x0E // Usermod "Animated_Staircase.h"
|
UM_AnimatedStaircase = USERMOD_ID_ANIMATED_STAIRCASE, // 0x0E // Usermod "Animated_Staircase.h"
|
||||||
// #define USERMOD_ID_RTC // 0x0F // Usermod "usermod_rtc.h" -- Uses "standard" I2C pins ... TODO -- enable shared I2C bus use
|
// #define USERMOD_ID_RTC // 0x0F // Usermod "usermod_rtc.h" -- Uses "standard" HW_I2C pins
|
||||||
// #define USERMOD_ID_ELEKSTUBE_IPS // 0x10 // Usermod "usermod_elekstube_ips.h" -- Uses quite a few pins ... see Hardware.h and User_Setup.h
|
// #define USERMOD_ID_ELEKSTUBE_IPS // 0x10 // Usermod "usermod_elekstube_ips.h" -- Uses quite a few pins ... see Hardware.h and User_Setup.h
|
||||||
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
||||||
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
||||||
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA // 0x17 // Usermod "quinled-an-penta.h"
|
||||||
};
|
};
|
||||||
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
||||||
|
|
||||||
@ -67,10 +67,13 @@ class PinManagerClass {
|
|||||||
uint8_t ledcAlloc[2] = {0x00, 0x00}; //16 LEDC channels
|
uint8_t ledcAlloc[2] = {0x00, 0x00}; //16 LEDC channels
|
||||||
PinOwner ownerTag[40] = { PinOwner::None };
|
PinOwner ownerTag[40] = { PinOwner::None };
|
||||||
#endif
|
#endif
|
||||||
|
uint8_t i2cAllocCount = 0; // allow multiple allocation of I2C bus pins but keep track of allocations
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// De-allocates a single pin
|
// De-allocates a single pin
|
||||||
bool deallocatePin(byte gpio, PinOwner tag);
|
bool deallocatePin(byte gpio, PinOwner tag);
|
||||||
|
// De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified)
|
||||||
|
bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag);
|
||||||
// Allocates a single pin, with an owner tag.
|
// Allocates a single pin, with an owner tag.
|
||||||
// De-allocation requires the same owner tag (or override)
|
// De-allocation requires the same owner tag (or override)
|
||||||
bool allocatePin(byte gpio, bool output, PinOwner tag);
|
bool allocatePin(byte gpio, bool output, PinOwner tag);
|
||||||
@ -85,11 +88,13 @@ class PinManagerClass {
|
|||||||
#endif
|
#endif
|
||||||
inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); }
|
inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); }
|
||||||
#if !defined(ESP8266) // ESP8266 compiler doesn't understand deprecated attribute
|
#if !defined(ESP8266) // ESP8266 compiler doesn't understand deprecated attribute
|
||||||
[[deprecated("Replaced by three-parameter deallocatePin(gpio, output, ownerTag), for improved debugging")]]
|
[[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]]
|
||||||
#endif
|
#endif
|
||||||
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); }
|
||||||
|
|
||||||
|
// will return true for reserved pins
|
||||||
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
||||||
|
// will return false for reserved pins
|
||||||
bool isPinOk(byte gpio, bool output = true);
|
bool isPinOk(byte gpio, bool output = true);
|
||||||
|
|
||||||
PinOwner getPinOwner(byte gpio);
|
PinOwner getPinOwner(byte gpio);
|
||||||
|
Loading…
Reference in New Issue
Block a user