2020-11-30 23:33:47 +00:00
# ifndef BusManager_h
# define BusManager_h
/*
* Class for addressing various light types
*/
2021-01-15 14:43:11 +00:00
# include "const.h"
2021-09-21 20:18:55 +00:00
2021-02-27 17:46:35 +00:00
# define GET_BIT(var,bit) (((var)>>(bit))&0x01)
# define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
# define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
2021-02-26 15:05:05 +00:00
2023-02-14 00:33:06 +00:00
# define NUM_ICS_WS2812_1CH_3X(len) (((len)+2) / 3) // 1 WS2811 IC controls 3 zones (each zone has 1 LED, W)
# define IC_INDEX_WS2812_1CH_3X(i) ((i) / 3)
# define NUM_ICS_WS2812_2CH_3X(len) (((len)+1)*2 / 3) // 2 WS2811 ICs control 3 zones (each zone has 2 LEDs, CW and WW)
# define IC_INDEX_WS2812_2CH_3X(i) ((i)*2 / 3)
# define WS2812_2CH_3X_SPANS_2_ICS(i) ((i)&0x01) // every other LED zone is on two different ICs
2023-06-30 19:12:59 +00:00
// flag for using double buffering in BusDigital
extern bool useGlobalLedBuffer ;
2021-01-30 19:51:36 +00:00
//temporary struct for passing bus configuration to bus
struct BusConfig {
2022-03-09 12:39:51 +00:00
uint8_t type ;
2021-04-01 10:53:01 +00:00
uint16_t count ;
uint16_t start ;
uint8_t colorOrder ;
bool reversed ;
uint8_t skipAmount ;
2021-10-07 20:57:07 +00:00
bool refreshReq ;
2022-03-09 12:39:51 +00:00
uint8_t autoWhite ;
2021-01-30 19:51:36 +00:00
uint8_t pins [ 5 ] = { LEDPIN , 255 , 255 , 255 , 255 } ;
2023-04-27 22:27:19 +00:00
uint16_t frequency ;
2023-07-05 21:57:46 +00:00
bool doubleBuffer ;
2023-11-15 18:37:07 +00:00
uint8_t milliAmpsPerLed ;
uint16_t milliAmpsMax ;
2023-07-06 19:16:29 +00:00
2023-11-15 18:37:07 +00:00
BusConfig ( uint8_t busType , uint8_t * ppins , uint16_t pstart , uint16_t len = 1 , uint8_t pcolorOrder = COL_ORDER_GRB , bool rev = false , uint8_t skip = 0 , byte aw = RGBW_MODE_MANUAL_ONLY , uint16_t clock_kHz = 0U , bool dblBfr = false , uint8_t maPerLed = 55 , uint16_t maMax = ABL_MILLIAMPS_DEFAULT )
2023-07-06 19:16:29 +00:00
: count ( len )
, start ( pstart )
, colorOrder ( pcolorOrder )
, reversed ( rev )
, skipAmount ( skip )
, autoWhite ( aw )
, frequency ( clock_kHz )
, doubleBuffer ( dblBfr )
2023-11-15 18:37:07 +00:00
, milliAmpsPerLed ( maPerLed )
, milliAmpsMax ( maMax )
2023-07-06 19:16:29 +00:00
{
2021-10-07 20:57:07 +00:00
refreshReq = ( bool ) GET_BIT ( busType , 7 ) ;
type = busType & 0x7F ; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
2023-07-06 19:16:29 +00:00
size_t nPins = 1 ;
2021-10-06 12:30:41 +00:00
if ( type > = TYPE_NET_DDP_RGB & & type < 96 ) nPins = 4 ; //virtual network bus. 4 "pins" store IP address
2021-09-21 20:18:55 +00:00
else if ( type > 47 ) nPins = 2 ;
2021-05-21 22:13:49 +00:00
else if ( type > 40 & & type < 46 ) nPins = NUM_PWM_PINS ( type ) ;
2023-07-06 19:16:29 +00:00
for ( size_t i = 0 ; i < nPins ; i + + ) pins [ i ] = ppins [ i ] ;
2021-01-30 19:51:36 +00:00
}
2021-07-09 14:25:23 +00:00
//validates start and length and extends total if needed
bool adjustBounds ( uint16_t & total ) {
if ( ! count ) count = 1 ;
if ( count > MAX_LEDS_PER_BUS ) count = MAX_LEDS_PER_BUS ;
if ( start > = MAX_LEDS ) return false ;
//limit length of strip if it would exceed total permissible LEDs
if ( start + count > MAX_LEDS ) count = MAX_LEDS - start ;
//extend total count accordingly
if ( start + count > total ) total = start + count ;
return true ;
}
2021-01-30 19:51:36 +00:00
} ;
2023-06-30 19:12:59 +00:00
2021-12-31 20:35:27 +00:00
// Defines an LED Strip and its color ordering.
struct ColorOrderMapEntry {
uint16_t start ;
uint16_t len ;
uint8_t colorOrder ;
} ;
struct ColorOrderMap {
2023-02-05 22:48:43 +00:00
void add ( uint16_t start , uint16_t len , uint8_t colorOrder ) ;
2021-12-31 20:35:27 +00:00
2023-07-06 19:16:29 +00:00
uint8_t count ( ) const { return _count ; }
2021-12-31 20:35:27 +00:00
2023-02-05 22:48:43 +00:00
void reset ( ) {
_count = 0 ;
memset ( _mappings , 0 , sizeof ( _mappings ) ) ;
2021-12-31 20:35:27 +00:00
}
2023-02-05 22:48:43 +00:00
const ColorOrderMapEntry * get ( uint8_t n ) const {
if ( n > _count ) {
return nullptr ;
2021-12-31 20:35:27 +00:00
}
2023-02-05 22:48:43 +00:00
return & ( _mappings [ n ] ) ;
2021-12-31 20:35:27 +00:00
}
2023-02-05 22:48:43 +00:00
uint8_t getPixelColorOrder ( uint16_t pix , uint8_t defaultColorOrder ) const ;
2021-12-31 20:35:27 +00:00
private :
2023-02-05 22:48:43 +00:00
uint8_t _count ;
ColorOrderMapEntry _mappings [ WLED_MAX_COLOR_ORDER_MAPPINGS ] ;
2021-12-31 20:35:27 +00:00
} ;
2023-06-30 19:12:59 +00:00
2021-11-24 10:02:25 +00:00
//parent class of BusDigital, BusPwm, and BusNetwork
2020-11-30 23:33:47 +00:00
class Bus {
public :
2023-07-06 19:16:29 +00:00
Bus ( uint8_t type , uint16_t start , uint8_t aw , uint16_t len = 1 , bool reversed = false , bool refresh = false )
: _type ( type )
, _bri ( 255 )
, _start ( start )
, _len ( len )
, _reversed ( reversed )
2022-08-21 18:50:24 +00:00
, _valid ( false )
2023-07-06 19:16:29 +00:00
, _needsRefresh ( refresh )
, _data ( nullptr ) // keep data access consistent across all types of buses
2022-08-21 18:50:24 +00:00
{
2023-12-09 18:03:33 +00:00
_autoWhiteMode = Bus : : hasWhite ( type ) ? aw : RGBW_MODE_MANUAL_ONLY ;
2021-10-16 13:13:30 +00:00
} ;
2021-04-07 19:04:54 +00:00
2021-10-16 13:13:30 +00:00
virtual ~ Bus ( ) { } //throw the bus under the bus
2022-08-21 18:50:24 +00:00
virtual void show ( ) = 0 ;
2023-07-06 19:16:29 +00:00
virtual bool canShow ( ) { return true ; }
virtual void setStatusPixel ( uint32_t c ) { }
2022-08-21 18:50:24 +00:00
virtual void setPixelColor ( uint16_t pix , uint32_t c ) = 0 ;
2021-11-30 15:28:26 +00:00
virtual uint32_t getPixelColor ( uint16_t pix ) { return 0 ; }
2023-07-19 15:25:25 +00:00
virtual void setBrightness ( uint8_t b ) { _bri = b ; } ;
2022-08-21 18:50:24 +00:00
virtual void cleanup ( ) = 0 ;
2023-07-06 19:16:29 +00:00
virtual uint8_t getPins ( uint8_t * pinArray ) { return 0 ; }
virtual uint16_t getLength ( ) { return _len ; }
virtual void setColorOrder ( ) { }
virtual uint8_t getColorOrder ( ) { return COL_ORDER_RGB ; }
virtual uint8_t skippedLeds ( ) { return 0 ; }
virtual uint16_t getFrequency ( ) { return 0U ; }
2023-11-15 18:37:07 +00:00
virtual uint16_t getLEDCurrent ( ) { return 0 ; }
2023-12-29 22:07:29 +00:00
virtual uint16_t getUsedCurrent ( ) { return 0 ; }
2023-11-15 18:37:07 +00:00
virtual uint16_t getMaxCurrent ( ) { return 0 ; }
2023-07-06 19:16:29 +00:00
inline void setReversed ( bool reversed ) { _reversed = reversed ; }
inline uint16_t getStart ( ) { return _start ; }
inline void setStart ( uint16_t start ) { _start = start ; }
inline uint8_t getType ( ) { return _type ; }
inline bool isOk ( ) { return _valid ; }
inline bool isReversed ( ) { return _reversed ; }
inline bool isOffRefreshRequired ( ) { return _needsRefresh ; }
2021-10-23 13:41:35 +00:00
bool containsPixel ( uint16_t pix ) { return pix > = _start & & pix < _start + _len ; }
2021-10-16 13:13:30 +00:00
2023-07-03 19:13:01 +00:00
virtual bool hasRGB ( void ) { return Bus : : hasRGB ( _type ) ; }
static bool hasRGB ( uint8_t type ) {
if ( ( type > = TYPE_WS2812_1CH & & type < = TYPE_WS2812_WWA ) | | type = = TYPE_ANALOG_1CH | | type = = TYPE_ANALOG_2CH | | type = = TYPE_ONOFF ) return false ;
2022-03-11 11:20:48 +00:00
return true ;
}
2023-07-03 19:13:01 +00:00
virtual bool hasWhite ( void ) { return Bus : : hasWhite ( _type ) ; }
2023-02-14 00:33:06 +00:00
static bool hasWhite ( uint8_t type ) {
2023-12-09 18:03:33 +00:00
if ( ( type > = TYPE_WS2812_1CH & & type < = TYPE_WS2812_WWA ) | | type = = TYPE_SK6812_RGBW | | type = = TYPE_TM1814 | | type = = TYPE_UCS8904 ) return true ; // digital types with white channel
2023-02-14 00:33:06 +00:00
if ( type > TYPE_ONOFF & & type < = TYPE_ANALOG_5CH & & type ! = TYPE_ANALOG_3CH ) return true ; // analog types with white channel
if ( type = = TYPE_NET_DDP_RGBW ) return true ; // network types with white channel
return false ;
}
2023-07-03 19:13:01 +00:00
virtual bool hasCCT ( void ) { return Bus : : hasCCT ( _type ) ; }
static bool hasCCT ( uint8_t type ) {
if ( type = = TYPE_WS2812_2CH_X3 | | type = = TYPE_WS2812_WWA | |
type = = TYPE_ANALOG_2CH | | type = = TYPE_ANALOG_5CH ) return true ;
2022-03-11 11:20:48 +00:00
return false ;
}
2021-11-28 00:21:17 +00:00
static void setCCT ( uint16_t cct ) {
2021-11-24 10:02:25 +00:00
_cct = cct ;
}
2023-02-14 13:28:10 +00:00
static void setCCTBlend ( uint8_t b ) {
if ( b > 100 ) b = 100 ;
_cctBlend = ( b * 127 ) / 100 ;
//compile-time limiter for hardware that can't power both white channels at max
# ifdef WLED_MAX_CCT_BLEND
if ( _cctBlend > WLED_MAX_CCT_BLEND ) _cctBlend = WLED_MAX_CCT_BLEND ;
# endif
}
inline void setAutoWhiteMode ( uint8_t m ) { if ( m < 5 ) _autoWhiteMode = m ; }
inline uint8_t getAutoWhiteMode ( ) { return _autoWhiteMode ; }
2023-02-14 00:33:06 +00:00
inline static void setGlobalAWMode ( uint8_t m ) { if ( m < 5 ) _gAWM = m ; else _gAWM = AW_GLOBAL_DISABLED ; }
inline static uint8_t getGlobalAWMode ( ) { return _gAWM ; }
2021-10-07 20:57:07 +00:00
2020-11-30 23:33:47 +00:00
protected :
2022-08-21 18:50:24 +00:00
uint8_t _type ;
uint8_t _bri ;
uint16_t _start ;
uint16_t _len ;
2023-07-06 19:16:29 +00:00
bool _reversed ;
2022-08-21 18:50:24 +00:00
bool _valid ;
bool _needsRefresh ;
2022-03-26 22:20:14 +00:00
uint8_t _autoWhiteMode ;
2023-07-06 19:16:29 +00:00
uint8_t * _data ;
2023-02-05 22:48:43 +00:00
static uint8_t _gAWM ;
static int16_t _cct ;
static uint8_t _cctBlend ;
uint32_t autoWhiteCalc ( uint32_t c ) ;
2023-06-30 19:12:59 +00:00
uint8_t * allocData ( size_t size = 1 ) ;
2023-07-05 21:57:46 +00:00
void freeData ( ) { if ( _data ! = nullptr ) free ( _data ) ; _data = nullptr ; }
2020-11-30 23:33:47 +00:00
} ;
2020-12-07 00:39:42 +00:00
2020-11-30 23:33:47 +00:00
class BusDigital : public Bus {
public :
2023-02-05 22:48:43 +00:00
BusDigital ( BusConfig & bc , uint8_t nr , const ColorOrderMap & com ) ;
2023-07-06 19:16:29 +00:00
~ BusDigital ( ) { cleanup ( ) ; }
2020-12-07 00:39:42 +00:00
2023-07-06 19:16:29 +00:00
void show ( ) ;
2023-02-05 22:48:43 +00:00
bool canShow ( ) ;
2023-07-19 15:25:25 +00:00
void setBrightness ( uint8_t b ) ;
2023-02-05 22:48:43 +00:00
void setStatusPixel ( uint32_t c ) ;
void setPixelColor ( uint16_t pix , uint32_t c ) ;
void setColorOrder ( uint8_t colorOrder ) ;
2023-07-06 19:16:29 +00:00
uint32_t getPixelColor ( uint16_t pix ) ;
uint8_t getColorOrder ( ) { return _colorOrder ; }
uint8_t getPins ( uint8_t * pinArray ) ;
uint8_t skippedLeds ( ) { return _skip ; }
uint16_t getFrequency ( ) { return _frequencykHz ; }
2023-11-15 18:37:07 +00:00
uint8_t estimateCurrentAndLimitBri ( ) ;
uint16_t getLEDCurrent ( ) { return _milliAmpsPerLed ; }
2023-12-29 22:07:29 +00:00
uint16_t getUsedCurrent ( ) { return _milliAmpsTotal ; }
2023-11-15 18:37:07 +00:00
uint16_t getMaxCurrent ( ) { return _milliAmpsMax ; }
2023-02-05 22:48:43 +00:00
void reinit ( ) ;
void cleanup ( ) ;
2023-01-06 08:24:29 +00:00
private :
2023-07-06 19:16:29 +00:00
uint8_t _skip ;
uint8_t _colorOrder ;
uint8_t _pins [ 2 ] ;
uint8_t _iType ;
uint16_t _frequencykHz ;
2023-11-15 18:37:07 +00:00
uint8_t _milliAmpsPerLed ;
uint16_t _milliAmpsMax ;
2023-07-06 19:16:29 +00:00
void * _busPtr ;
2023-02-05 22:48:43 +00:00
const ColorOrderMap & _colorOrderMap ;
2023-12-29 22:07:29 +00:00
static uint16_t _milliAmpsTotal ; // is overwitten/recalculated on each show()
2023-06-26 20:12:32 +00:00
2023-07-19 11:50:09 +00:00
inline uint32_t restoreColorLossy ( uint32_t c , uint8_t restoreBri ) {
2023-07-18 21:33:28 +00:00
if ( restoreBri < 255 ) {
2023-07-17 15:06:04 +00:00
uint8_t * chan = ( uint8_t * ) & c ;
for ( uint_fast8_t i = 0 ; i < 4 ; i + + ) {
uint_fast16_t val = chan [ i ] ;
2023-07-18 21:33:28 +00:00
chan [ i ] = ( ( val < < 8 ) + restoreBri ) / ( restoreBri + 1 ) ; //adding _bri slighly improves recovery / stops degradation on re-scale
2023-07-17 15:06:04 +00:00
}
2023-06-26 20:12:32 +00:00
}
return c ;
}
2020-11-30 23:33:47 +00:00
} ;
2020-12-07 00:39:42 +00:00
2020-11-30 23:33:47 +00:00
class BusPwm : public Bus {
public :
2023-02-05 22:48:43 +00:00
BusPwm ( BusConfig & bc ) ;
2023-07-06 19:16:29 +00:00
~ BusPwm ( ) { cleanup ( ) ; }
2020-12-07 00:39:42 +00:00
2023-02-05 22:48:43 +00:00
void setPixelColor ( uint16_t pix , uint32_t c ) ;
2023-07-06 19:16:29 +00:00
uint32_t getPixelColor ( uint16_t pix ) ; //does no index check
uint8_t getPins ( uint8_t * pinArray ) ;
2023-04-27 22:27:19 +00:00
uint16_t getFrequency ( ) { return _frequency ; }
2023-07-06 19:16:29 +00:00
void show ( ) ;
void cleanup ( ) { deallocatePins ( ) ; }
2021-03-04 21:17:25 +00:00
2023-01-06 08:24:29 +00:00
private :
2023-07-06 19:16:29 +00:00
uint8_t _pins [ 5 ] ;
uint8_t _pwmdata [ 5 ] ;
2020-12-07 00:39:42 +00:00
# ifdef ARDUINO_ARCH_ESP32
2023-07-06 19:16:29 +00:00
uint8_t _ledcStart ;
2020-12-07 00:39:42 +00:00
# endif
2023-07-06 19:16:29 +00:00
uint16_t _frequency ;
2023-02-05 22:48:43 +00:00
void deallocatePins ( ) ;
2020-11-30 23:33:47 +00:00
} ;
2021-09-20 20:24:58 +00:00
2022-06-20 20:17:01 +00:00
class BusOnOff : public Bus {
public :
2023-02-05 22:48:43 +00:00
BusOnOff ( BusConfig & bc ) ;
2023-07-06 19:16:29 +00:00
~ BusOnOff ( ) { cleanup ( ) ; }
2022-06-20 20:17:01 +00:00
2023-02-05 22:48:43 +00:00
void setPixelColor ( uint16_t pix , uint32_t c ) ;
uint32_t getPixelColor ( uint16_t pix ) ;
2023-07-06 19:16:29 +00:00
uint8_t getPins ( uint8_t * pinArray ) ;
2023-02-05 22:48:43 +00:00
void show ( ) ;
2023-07-06 19:16:29 +00:00
void cleanup ( ) { pinManager . deallocatePin ( _pin , PinOwner : : BusOnOff ) ; }
2022-06-20 20:17:01 +00:00
2023-01-06 08:24:29 +00:00
private :
2023-07-06 19:16:29 +00:00
uint8_t _pin ;
uint8_t _onoffdata ;
2022-06-20 20:17:01 +00:00
} ;
2021-09-22 11:20:36 +00:00
class BusNetwork : public Bus {
2021-09-20 20:24:58 +00:00
public :
2023-02-05 22:48:43 +00:00
BusNetwork ( BusConfig & bc ) ;
2023-07-06 19:16:29 +00:00
~ BusNetwork ( ) { cleanup ( ) ; }
2021-09-20 20:24:58 +00:00
2023-07-06 19:16:29 +00:00
bool hasRGB ( ) { return true ; }
2023-02-05 22:48:43 +00:00
bool hasWhite ( ) { return _rgbw ; }
2023-07-06 19:16:29 +00:00
bool canShow ( ) { return ! _broadcastLock ; } // this should be a return value from UDP routine if it is still sending data out
2023-02-05 22:48:43 +00:00
void setPixelColor ( uint16_t pix , uint32_t c ) ;
uint32_t getPixelColor ( uint16_t pix ) ;
2023-07-06 19:16:29 +00:00
uint8_t getPins ( uint8_t * pinArray ) ;
2023-02-05 22:48:43 +00:00
void show ( ) ;
void cleanup ( ) ;
2021-09-20 20:24:58 +00:00
private :
IPAddress _client ;
2021-09-27 14:29:38 +00:00
uint8_t _UDPtype ;
uint8_t _UDPchannels ;
2021-09-20 20:24:58 +00:00
bool _rgbw ;
bool _broadcastLock ;
} ;
2021-01-15 14:43:11 +00:00
class BusManager {
public :
2023-12-29 22:07:29 +00:00
BusManager ( ) { } ;
2022-12-31 16:06:18 +00:00
2023-02-05 22:48:43 +00:00
//utility to get the approx. memory usage of a given BusConfig
static uint32_t memUsage ( BusConfig & bc ) ;
2023-12-29 22:07:29 +00:00
static uint16_t currentMilliamps ( void ) { return _milliAmpsUsed ; }
static uint16_t ablMilliampsMax ( void ) { return _milliAmpsMax ; }
2021-01-15 14:43:11 +00:00
2023-12-29 22:07:29 +00:00
static int add ( BusConfig & bc ) ;
2021-01-15 14:43:11 +00:00
2023-02-05 22:48:43 +00:00
//do not call this method from system context (network callback)
2023-12-29 22:07:29 +00:00
static void removeAll ( ) ;
2021-01-15 14:43:11 +00:00
2023-12-29 22:07:29 +00:00
static void show ( ) ;
static bool canAllShow ( ) ;
static void setStatusPixel ( uint32_t c ) ;
static void setPixelColor ( uint16_t pix , uint32_t c ) ;
static void setBrightness ( uint8_t b ) ;
static void setSegmentCCT ( int16_t cct , bool allowWBCorrection = false ) ;
static void setMilliampsMax ( uint16_t max ) { _milliAmpsMax = max ; }
static uint32_t getPixelColor ( uint16_t pix ) ;
2021-01-15 14:43:11 +00:00
2023-12-29 22:07:29 +00:00
static Bus * getBus ( uint8_t busNr ) ;
2021-02-27 11:06:14 +00:00
2023-02-05 22:48:43 +00:00
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
2023-12-29 22:07:29 +00:00
static uint16_t getTotalLength ( ) ;
static uint8_t getNumBusses ( ) { return numBusses ; }
2021-12-31 20:35:27 +00:00
2023-12-29 22:07:29 +00:00
static void updateColorOrderMap ( const ColorOrderMap & com ) { memcpy ( & colorOrderMap , & com , sizeof ( ColorOrderMap ) ) ; }
static const ColorOrderMap & getColorOrderMap ( ) { return colorOrderMap ; }
2022-12-31 16:06:18 +00:00
2021-01-15 14:43:11 +00:00
private :
2023-12-29 22:07:29 +00:00
static uint8_t numBusses ;
static Bus * busses [ WLED_MAX_BUSSES + WLED_MIN_VIRTUAL_BUSSES ] ;
static ColorOrderMap colorOrderMap ;
static uint16_t _milliAmpsUsed ;
static uint16_t _milliAmpsMax ;
2023-02-05 22:48:43 +00:00
2023-12-29 22:07:29 +00:00
static uint8_t getNumVirtualBusses ( ) {
2023-02-05 22:48:43 +00:00
int j = 0 ;
for ( int i = 0 ; i < numBusses ; i + + ) if ( busses [ i ] - > getType ( ) > = TYPE_NET_DDP_RGB & & busses [ i ] - > getType ( ) < 96 ) j + + ;
return j ;
}
2021-01-15 14:43:11 +00:00
} ;
2023-07-05 12:26:09 +00:00
# endif