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"
|
2024-08-22 15:15:12 +00:00
|
|
|
#include <array>
|
|
|
|
#include <vector>
|
2021-09-21 20:18:55 +00:00
|
|
|
|
2023-07-17 18:54:24 +00:00
|
|
|
//colors.cpp
|
|
|
|
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
|
|
|
|
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
|
|
|
|
|
2024-08-24 09:35:32 +00:00
|
|
|
struct BusConfig; // forward declaration
|
2023-06-30 19:12:59 +00:00
|
|
|
|
2021-12-31 20:35:27 +00:00
|
|
|
// Defines an LED Strip and its color ordering.
|
2024-08-22 15:15:12 +00:00
|
|
|
typedef struct {
|
2021-12-31 20:35:27 +00:00
|
|
|
uint16_t start;
|
|
|
|
uint16_t len;
|
|
|
|
uint8_t colorOrder;
|
2024-08-22 15:15:12 +00:00
|
|
|
} ColorOrderMapEntry;
|
2021-12-31 20:35:27 +00:00
|
|
|
|
|
|
|
struct ColorOrderMap {
|
2024-08-22 15:15:12 +00:00
|
|
|
bool add(uint16_t start, uint16_t len, uint8_t colorOrder);
|
2021-12-31 20:35:27 +00:00
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
inline uint8_t count() const { return _mappings.size(); }
|
2021-12-31 20:35:27 +00:00
|
|
|
|
2023-02-05 22:48:43 +00:00
|
|
|
void reset() {
|
2024-08-22 15:15:12 +00:00
|
|
|
_mappings.clear();
|
|
|
|
_mappings.shrink_to_fit();
|
2021-12-31 20:35:27 +00:00
|
|
|
}
|
|
|
|
|
2023-02-05 22:48:43 +00:00
|
|
|
const ColorOrderMapEntry* get(uint8_t n) const {
|
2024-08-22 15:15:12 +00:00
|
|
|
if (n >= count()) return nullptr;
|
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:
|
2024-08-22 15:15:12 +00:00
|
|
|
std::vector<ColorOrderMapEntry> _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
|
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
virtual void show(void) = 0;
|
|
|
|
virtual bool canShow(void) const { 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;
|
2024-08-22 15:15:12 +00:00
|
|
|
virtual void setBrightness(uint8_t b) { _bri = b; };
|
|
|
|
virtual void setColorOrder(uint8_t co) {}
|
|
|
|
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
|
|
|
|
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
|
|
|
|
virtual uint16_t getLength(void) const { return isOk() ? _len : 0; }
|
|
|
|
virtual uint8_t getColorOrder(void) const { return COL_ORDER_RGB; }
|
|
|
|
virtual uint8_t skippedLeds(void) const { return 0; }
|
|
|
|
virtual uint16_t getFrequency(void) const { return 0U; }
|
|
|
|
virtual uint16_t getLEDCurrent(void) const { return 0; }
|
|
|
|
virtual uint16_t getUsedCurrent(void) const { return 0; }
|
|
|
|
virtual uint16_t getMaxCurrent(void) const { return 0; }
|
|
|
|
|
2024-08-24 09:35:32 +00:00
|
|
|
inline bool hasRGB(void) const { return _hasRgb; }
|
|
|
|
inline bool hasWhite(void) const { return _hasWhite; }
|
|
|
|
inline bool hasCCT(void) const { return _hasCCT; }
|
|
|
|
inline bool isDigital(void) const { return isDigital(_type); }
|
|
|
|
inline bool is2Pin(void) const { return is2Pin(_type); }
|
|
|
|
inline bool isOnOff(void) const { return isOnOff(_type); }
|
|
|
|
inline bool isPWM(void) const { return isPWM(_type); }
|
|
|
|
inline bool isVirtual(void) const { return isVirtual(_type); }
|
|
|
|
inline bool is16bit(void) const { return is16bit(_type); }
|
2024-08-22 15:15:12 +00:00
|
|
|
inline void setReversed(bool reversed) { _reversed = reversed; }
|
2024-08-24 09:35:32 +00:00
|
|
|
inline void setStart(uint16_t start) { _start = start; }
|
2024-08-22 15:15:12 +00:00
|
|
|
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
|
|
|
inline uint8_t getAutoWhiteMode(void) const { return _autoWhiteMode; }
|
2024-08-24 09:35:32 +00:00
|
|
|
inline uint8_t getNumberOfChannels(void) const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
2024-08-22 15:15:12 +00:00
|
|
|
inline uint16_t getStart(void) const { return _start; }
|
|
|
|
inline uint8_t getType(void) const { return _type; }
|
|
|
|
inline bool isOk(void) const { return _valid; }
|
|
|
|
inline bool isReversed(void) const { return _reversed; }
|
|
|
|
inline bool isOffRefreshRequired(void) const { return _needsRefresh; }
|
|
|
|
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
|
|
|
|
|
2024-08-25 10:53:23 +00:00
|
|
|
static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
2024-08-24 09:35:32 +00:00
|
|
|
static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
2024-08-22 15:15:12 +00:00
|
|
|
static constexpr bool hasRGB(uint8_t type) {
|
|
|
|
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
|
2022-03-11 11:20:48 +00:00
|
|
|
}
|
2024-08-22 15:15:12 +00:00
|
|
|
static constexpr bool hasWhite(uint8_t type) {
|
|
|
|
return (type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) ||
|
|
|
|
type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904 ||
|
|
|
|
type == TYPE_FW1906 || type == TYPE_WS2805 || type == TYPE_SM16825 || // digital types with white channel
|
|
|
|
(type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) || // analog types with white channel
|
|
|
|
type == TYPE_NET_DDP_RGBW || type == TYPE_NET_ARTNET_RGBW; // network types with white channel
|
2023-02-14 00:33:06 +00:00
|
|
|
}
|
2024-08-22 15:15:12 +00:00
|
|
|
static constexpr bool hasCCT(uint8_t type) {
|
|
|
|
return type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA ||
|
|
|
|
type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH ||
|
|
|
|
type == TYPE_FW1906 || type == TYPE_WS2805 ||
|
|
|
|
type == TYPE_SM16825;
|
2022-03-11 11:20:48 +00:00
|
|
|
}
|
2024-08-24 09:35:32 +00:00
|
|
|
static constexpr bool isTypeValid(uint8_t type) { return (type > 15 && type < 128); }
|
|
|
|
static constexpr bool isDigital(uint8_t type) { return (type >= TYPE_DIGITAL_MIN && type <= TYPE_DIGITAL_MAX) || is2Pin(type); }
|
|
|
|
static constexpr bool is2Pin(uint8_t type) { return (type >= TYPE_2PIN_MIN && type <= TYPE_2PIN_MAX); }
|
|
|
|
static constexpr bool isOnOff(uint8_t type) { return (type == TYPE_ONOFF); }
|
|
|
|
static constexpr bool isPWM(uint8_t type) { return (type >= TYPE_ANALOG_MIN && type <= TYPE_ANALOG_MAX); }
|
|
|
|
static constexpr bool isVirtual(uint8_t type) { return (type >= TYPE_VIRTUAL_MIN && type <= TYPE_VIRTUAL_MAX); }
|
|
|
|
static constexpr bool is16bit(uint8_t type) { return type == TYPE_UCS8903 || type == TYPE_UCS8904 || type == TYPE_SM16825; }
|
|
|
|
static constexpr int numPWMPins(uint8_t type) { return (type - 40); }
|
|
|
|
|
|
|
|
static inline int16_t getCCT(void) { return _cct; }
|
|
|
|
static inline void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
|
|
|
|
static inline uint8_t getGlobalAWMode(void) { return _gAWM; }
|
|
|
|
static inline void setCCT(int16_t cct) { _cct = cct; }
|
|
|
|
static inline uint8_t getCCTBlend(void) { return _cctBlend; }
|
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
|
|
|
|
}
|
2023-07-17 18:54:24 +00:00
|
|
|
static void calculateCCT(uint32_t c, uint8_t &ww, uint8_t &cw) {
|
|
|
|
uint8_t cct = 0; //0 - full warm white, 255 - full cold white
|
|
|
|
uint8_t w = byte(c >> 24);
|
|
|
|
|
|
|
|
if (_cct > -1) {
|
|
|
|
if (_cct >= 1900) cct = (_cct - 1900) >> 5;
|
|
|
|
else if (_cct < 256) cct = _cct;
|
|
|
|
} else {
|
|
|
|
cct = (approximateKelvinFromRGB(c) - 1900) >> 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
//0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
|
|
|
|
if (cct < _cctBlend) ww = 255;
|
2024-03-16 11:36:05 +00:00
|
|
|
else ww = ((255-cct) * 255) / (255 - _cctBlend);
|
2023-07-17 18:54:24 +00:00
|
|
|
if ((255-cct) < _cctBlend) cw = 255;
|
|
|
|
else cw = (cct * 255) / (255 - _cctBlend);
|
|
|
|
|
|
|
|
ww = (w * ww) / 255; //brightness scaling
|
|
|
|
cw = (w * cw) / 255;
|
|
|
|
}
|
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;
|
2024-08-24 09:35:32 +00:00
|
|
|
//struct { //using bitfield struct adds abour 250 bytes to binary size
|
|
|
|
bool _reversed;// : 1;
|
|
|
|
bool _valid;// : 1;
|
|
|
|
bool _needsRefresh;// : 1;
|
|
|
|
bool _hasRgb;// : 1;
|
|
|
|
bool _hasWhite;// : 1;
|
|
|
|
bool _hasCCT;// : 1;
|
|
|
|
//} __attribute__ ((packed));
|
2022-03-26 22:20:14 +00:00
|
|
|
uint8_t _autoWhiteMode;
|
2023-07-06 19:16:29 +00:00
|
|
|
uint8_t *_data;
|
2024-03-16 11:36:05 +00:00
|
|
|
// global Auto White Calculation override
|
2023-02-05 22:48:43 +00:00
|
|
|
static uint8_t _gAWM;
|
2024-03-16 11:36:05 +00:00
|
|
|
// _cct has the following menaings (see calculateCCT() & BusManager::setSegmentCCT()):
|
|
|
|
// -1 means to extract approximate CCT value in K from RGB (in calcualteCCT())
|
|
|
|
// [0,255] is the exact CCT value where 0 means warm and 255 cold
|
|
|
|
// [1900,10060] only for color correction expressed in K (colorBalanceFromKelvin())
|
2023-02-05 22:48:43 +00:00
|
|
|
static int16_t _cct;
|
2024-03-16 11:36:05 +00:00
|
|
|
// _cctBlend determines WW/CW blending:
|
|
|
|
// 0 - linear (CCT 127 => 50% warm, 50% cold)
|
|
|
|
// 63 - semi additive/nonlinear (CCT 127 => 66% warm, 66% cold)
|
|
|
|
// 127 - additive CCT blending (CCT 127 => 100% warm, 100% cold)
|
2023-02-05 22:48:43 +00:00
|
|
|
static uint8_t _cctBlend;
|
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
uint32_t autoWhiteCalc(uint32_t c) const;
|
|
|
|
uint8_t *allocateData(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
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
void show(void) override;
|
|
|
|
bool canShow(void) const override;
|
2024-01-14 16:38:29 +00:00
|
|
|
void setBrightness(uint8_t b) override;
|
|
|
|
void setStatusPixel(uint32_t c) override;
|
|
|
|
void setPixelColor(uint16_t pix, uint32_t c) override;
|
|
|
|
void setColorOrder(uint8_t colorOrder) override;
|
2024-08-22 15:15:12 +00:00
|
|
|
uint32_t getPixelColor(uint16_t pix) const override;
|
|
|
|
uint8_t getColorOrder(void) const override { return _colorOrder; }
|
2024-08-24 09:35:32 +00:00
|
|
|
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
2024-08-22 15:15:12 +00:00
|
|
|
uint8_t skippedLeds(void) const override { return _skip; }
|
|
|
|
uint16_t getFrequency(void) const override { return _frequencykHz; }
|
|
|
|
uint16_t getLEDCurrent(void) const override { return _milliAmpsPerLed; }
|
|
|
|
uint16_t getUsedCurrent(void) const override { return _milliAmpsTotal; }
|
|
|
|
uint16_t getMaxCurrent(void) const override { return _milliAmpsMax; }
|
|
|
|
void reinit(void);
|
|
|
|
void cleanup(void);
|
2023-02-05 22:48:43 +00:00
|
|
|
|
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
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
inline uint32_t restoreColorLossy(uint32_t c, uint8_t restoreBri) const {
|
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];
|
2024-02-06 13:47:20 +00:00
|
|
|
chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slightly 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;
|
|
|
|
}
|
2024-08-22 15:15:12 +00:00
|
|
|
|
|
|
|
uint8_t estimateCurrentAndLimitBri(void);
|
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
|
|
|
|
2024-01-14 16:38:29 +00:00
|
|
|
void setPixelColor(uint16_t pix, uint32_t c) override;
|
2024-08-22 15:15:12 +00:00
|
|
|
uint32_t getPixelColor(uint16_t pix) const override; //does no index check
|
2024-08-24 09:35:32 +00:00
|
|
|
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
2024-08-22 15:15:12 +00:00
|
|
|
uint16_t getFrequency(void) const override { return _frequency; }
|
|
|
|
void show(void) override;
|
|
|
|
void cleanup(void) { 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
|
2024-03-07 19:21:56 +00:00
|
|
|
uint8_t _depth;
|
2023-07-06 19:16:29 +00:00
|
|
|
uint16_t _frequency;
|
2023-02-05 22:48:43 +00:00
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
void deallocatePins(void);
|
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
|
|
|
|
2024-01-14 20:04:18 +00:00
|
|
|
void setPixelColor(uint16_t pix, uint32_t c) override;
|
2024-08-22 15:15:12 +00:00
|
|
|
uint32_t getPixelColor(uint16_t pix) const override;
|
|
|
|
uint8_t getPins(uint8_t* pinArray) const override;
|
|
|
|
void show(void) override;
|
|
|
|
void cleanup(void) { 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
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
bool canShow(void) const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
2024-01-14 16:38:29 +00:00
|
|
|
void setPixelColor(uint16_t pix, uint32_t c) override;
|
2024-08-22 15:15:12 +00:00
|
|
|
uint32_t getPixelColor(uint16_t pix) const override;
|
2024-08-24 09:35:32 +00:00
|
|
|
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
2024-08-22 15:15:12 +00:00
|
|
|
void show(void) override;
|
|
|
|
void cleanup(void);
|
2023-02-05 22:48:43 +00:00
|
|
|
|
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 _broadcastLock;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2024-08-24 09:35:32 +00:00
|
|
|
//temporary struct for passing bus configuration to bus
|
|
|
|
struct BusConfig {
|
|
|
|
uint8_t type;
|
|
|
|
uint16_t count;
|
|
|
|
uint16_t start;
|
|
|
|
uint8_t colorOrder;
|
|
|
|
bool reversed;
|
|
|
|
uint8_t skipAmount;
|
|
|
|
bool refreshReq;
|
|
|
|
uint8_t autoWhite;
|
|
|
|
uint8_t pins[5] = {255, 255, 255, 255, 255};
|
|
|
|
uint16_t frequency;
|
|
|
|
bool doubleBuffer;
|
|
|
|
uint8_t milliAmpsPerLed;
|
|
|
|
uint16_t milliAmpsMax;
|
|
|
|
|
|
|
|
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=LED_MILLIAMPS_DEFAULT, uint16_t maMax=ABL_MILLIAMPS_DEFAULT)
|
|
|
|
: count(len)
|
|
|
|
, start(pstart)
|
|
|
|
, colorOrder(pcolorOrder)
|
|
|
|
, reversed(rev)
|
|
|
|
, skipAmount(skip)
|
|
|
|
, autoWhite(aw)
|
|
|
|
, frequency(clock_kHz)
|
|
|
|
, doubleBuffer(dblBfr)
|
|
|
|
, milliAmpsPerLed(maPerLed)
|
|
|
|
, milliAmpsMax(maMax)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
size_t nPins = 1;
|
|
|
|
if (Bus::isVirtual(type)) nPins = 4; //virtual network bus. 4 "pins" store IP address
|
|
|
|
else if (Bus::is2Pin(type)) nPins = 2;
|
|
|
|
else if (Bus::isPWM(type)) nPins = Bus::numPWMPins(type);
|
|
|
|
for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
//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-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);
|
2024-07-07 12:18:51 +00:00
|
|
|
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
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);
|
2024-06-12 16:00:00 +00:00
|
|
|
static void useParallelOutput(void); // workaround for inaccessible PolyBus
|
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)
|
2024-08-22 15:15:12 +00:00
|
|
|
static void removeAll(void);
|
2021-01-15 14:43:11 +00:00
|
|
|
|
2024-06-23 12:09:18 +00:00
|
|
|
static void on(void);
|
|
|
|
static void off(void);
|
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
static void show(void);
|
|
|
|
static bool canAllShow(void);
|
2023-12-29 22:07:29 +00:00
|
|
|
static void setStatusPixel(uint32_t c);
|
|
|
|
static void setPixelColor(uint16_t pix, uint32_t c);
|
|
|
|
static void setBrightness(uint8_t b);
|
2024-03-16 11:36:05 +00:00
|
|
|
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
|
|
|
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
2023-12-29 22:07:29 +00:00
|
|
|
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
2024-08-22 15:15:12 +00:00
|
|
|
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
2023-12-29 22:07:29 +00:00
|
|
|
static uint32_t getPixelColor(uint16_t pix);
|
2024-08-22 15:15:12 +00:00
|
|
|
static inline int16_t getSegmentCCT(void) { return Bus::getCCT(); }
|
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())
|
2024-08-22 15:15:12 +00:00
|
|
|
static uint16_t getTotalLength(void);
|
|
|
|
static inline uint8_t getNumBusses(void) { return numBusses; }
|
|
|
|
static String getLEDTypesJSONString(void);
|
2021-12-31 20:35:27 +00:00
|
|
|
|
2024-08-22 15:15:12 +00:00
|
|
|
static inline ColorOrderMap& getColorOrderMap(void) { 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;
|
2024-06-23 12:09:18 +00:00
|
|
|
static uint8_t _parallelOutputs;
|
2023-02-05 22:48:43 +00:00
|
|
|
|
2024-06-23 12:09:18 +00:00
|
|
|
#ifdef ESP32_DATA_IDLE_HIGH
|
2024-08-24 09:35:32 +00:00
|
|
|
static void esp32RMTInvertIdle(void) ;
|
2024-06-23 12:09:18 +00:00
|
|
|
#endif
|
2024-08-22 15:15:12 +00:00
|
|
|
static uint8_t getNumVirtualBusses(void) {
|
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
|