Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usermod bus type #4123

Draft
wants to merge 5 commits into
base: 0_15
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ AR_lib_deps = kosme/arduinoFFT @ 2.0.1
;;
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
platform = espressif32@ ~6.3.2
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
build_flags = -g
Expand Down
83 changes: 83 additions & 0 deletions usermods/AT8870_I2C_PSPWM_v2/usermod.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#pragma once

#include "wled.h"
#include "bus_usermod.h"


class UMB_AT8870_I2C_PSPWM : public UsermodBus
{
public:

uint16_t getId() override { return USERMOD_ID_BUS; }
void loop() override {}

void initBus(BusUsermod* bus) override
{
allocateBusData(bus, bus->getLength() * 4);
setBusRGB(bus, true);
setBusWhite(bus, true);
}

void setBusPixelColor(BusUsermod* bus, uint16_t pix, uint32_t c) override
{
uint8_t* data = getBusData(bus);
uint16_t i = pix * 4;
data[i++] = R(c);
data[i++] = G(c);
data[i++] = B(c);
data[i++] = W(c);
}

uint32_t getBusPixelColor(const BusUsermod* bus, uint16_t pix) const override
{
uint8_t* data = getBusData(bus);
uint16_t i = pix * 4;
return RGBW32(data[i], data[i+1], data[i+2], data[i+3]);
}

void showBus(BusUsermod* bus) override
{
const uint8_t* pins = getBusPins(bus);
uint32_t c = getBusPixelColor(bus, 0);
if ( bus->hasWhite() ) {
c = autoWhiteCalc(bus, c);
}

uint8_t pwm_duty;
uint16_t pwm_delay;
uint8_t bri = getBusBrightness(bus);


Wire.beginTransmission(pins[0]);

Wire.write(16); // 16 == start of PWM addresses

pwm_delay = 0; // PWM delay for red = 0
pwm_duty = (R(c) * bri) / 255; // PWM duty for red, scaled by brightness
Wire.write(pwm_duty);
Wire.write(pwm_delay);

pwm_delay += pwm_duty; // PWM delay for green, start after red
if ( pwm_delay > 254 ) pwm_delay -= 255;
pwm_duty = (G(c) * bri) / 255; // PWM duty for green, scaled by brightness
Wire.write(pwm_duty);
Wire.write(pwm_delay);

pwm_delay += pwm_duty; // PWM delay for blue, start after green
if ( pwm_delay > 254 ) pwm_delay -= 255;
pwm_duty = (B(c) * bri) / 255; // PWM duty for blue, scaled by brightness
Wire.write(pwm_duty);
Wire.write(pwm_delay);

pwm_delay += pwm_duty; // PWM delay for white, start after blue
if ( pwm_delay > 254 ) pwm_delay -= 255;
pwm_duty = (W(c) * bri) / 255; // PWM duty for white, scaled by brightness
Wire.write(pwm_duty);
Wire.write(pwm_delay);

Wire.endTransmission();

}

};

12 changes: 7 additions & 5 deletions wled00/bus_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "pin_manager.h"
#include "bus_wrapper.h"
#include "bus_manager.h"
#include "bus_usermod.h"

extern bool cctICused;

Expand Down Expand Up @@ -699,7 +700,9 @@ uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned

int BusManager::add(BusConfig &bc) {
if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1;
if (Bus::isVirtual(bc.type)) {
if (bc.type == TYPE_USERMOD) {
busses[numBusses] = new BusUsermod(bc);
} else if (Bus::isVirtual(bc.type)) {
busses[numBusses] = new BusNetwork(bc);
} else if (Bus::isDigital(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
Expand Down Expand Up @@ -749,13 +752,12 @@ String BusManager::getLEDTypesJSONString(void) {
{TYPE_NET_ARTNET_RGB, "N", PSTR("Art-Net RGB (network)")},
{TYPE_NET_DDP_RGBW, "N", PSTR("DDP RGBW (network)")},
{TYPE_NET_ARTNET_RGBW, "N", PSTR("Art-Net RGBW (network)")},
// hypothetical extensions
//{TYPE_VIRTUAL_I2C_W, "V", PSTR("I2C White (virtual)")}, // allows setting I2C address in _pin[0]
//{TYPE_VIRTUAL_I2C_CCT, "V", PSTR("I2C CCT (virtual)")}, // allows setting I2C address in _pin[0]
//{TYPE_VIRTUAL_I2C_RGB, "V", PSTR("I2C RGB (virtual)")}, // allows setting I2C address in _pin[0]
{TYPE_USERMOD, "V", PSTR("Usermod (virtual)")}, // virtual bus for usermods
};
String json = "[";
for (const auto &type : types) {
extern UsermodManager usermods;
if ( (type.id == TYPE_USERMOD) && (!usermods.lookup(USERMOD_ID_BUS))) continue;
String id = String(type.id);
// capabilities follows similar pattern as JSON API
int capabilities = Bus::hasRGB(type.id) | Bus::hasWhite(type.id)<<1 | Bus::hasCCT(type.id)<<2 | Bus::is16bit(type.id)<<4;
Expand Down
5 changes: 3 additions & 2 deletions wled00/bus_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ class Bus {
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
type == TYPE_NET_DDP_RGBW || type == TYPE_NET_ARTNET_RGBW ||
type == TYPE_USERMOD; // network types with white channel
}
static constexpr bool hasCCT(uint8_t type) {
return type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA ||
Expand All @@ -132,7 +133,7 @@ class Bus {
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 isVirtual(uint8_t type) { return ((type >= TYPE_VIRTUAL_MIN && type <= TYPE_VIRTUAL_MAX) || type == TYPE_USERMOD); }
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); }

Expand Down
75 changes: 75 additions & 0 deletions wled00/bus_usermod.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

#include <Arduino.h>
#include <IPAddress.h>

#include "pin_manager.h"
#include "bus_wrapper.h"
#include "bus_manager.h"
#include "bus_usermod.h"

#include "Wire.h"

extern BusManager busses;
extern UsermodManager usermods;

void BusUsermod::setPixelColor(uint16_t pix, uint32_t c) {
if (!_valid || !_usermod || pix >= _len) return;
return _usermod->setBusPixelColor(this, pix, c);
}

uint32_t BusUsermod::getPixelColor(uint16_t pix) const {
if (!_valid || !_usermod || pix >= _len) return 0;
return _usermod->getBusPixelColor(this, pix);
}

void BusUsermod::show() {
if (!_valid || !_usermod) return;
return _usermod->showBus(this);
}

BusUsermod::BusUsermod(BusConfig &bc)
: Bus(bc.type, bc.start, bc.autoWhite, bc.count)
{
// safe pin configuration for the actual Usermod
_pins[0] = bc.pins[0];
_pins[1] = bc.pins[1];
_pins[2] = bc.pins[2];
_pins[3] = bc.pins[3];
_pins[4] = bc.pins[4];

_valid = 1;
// error: 'dynamic_cast' not permitted with '-fno-rtti'
// _usermod = dynamic_cast<UsermodBus*> (usermods.lookup(USERMOD_ID_BUS));
_usermod = static_cast<UsermodBus*> (usermods.lookup(USERMOD_ID_BUS));

if ( _usermod ) {
_usermod->initBus(this);
}
}

void BusUsermod::cleanup(void) {
_type = I_NONE;
_valid = false;
freeData();
}

uint8_t BusUsermod::getPins(uint8_t* pinArray) const {
if (!_valid) return 0;
unsigned numPins = 5;
for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i];
return numPins;
}


void UsermodBus::setup() {
uint8_t busNr;
for ( busNr = 0; busNr < busses.getNumBusses(); busNr++ ) {
BusUsermod* bus = static_cast<BusUsermod*> (busses.getBus(busNr));
if ( bus->getType() == TYPE_USERMOD ) {
if ( bus->_usermod ) continue;
bus->_usermod = this;
initBus(bus);
}
}
}

59 changes: 59 additions & 0 deletions wled00/bus_usermod.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef BusUsermod_h
#define BusUsermod_h

class JsonObject;

#include "usermod.h"

class UsermodBus;

class BusUsermod : public Bus {
public:
BusUsermod(BusConfig &bc);
~BusUsermod() { cleanup(); }

void setPixelColor(uint16_t pix, uint32_t c) override;
uint32_t getPixelColor(uint16_t pix) const override;
void show(void) override;
void cleanup(void);

uint8_t getPins(uint8_t* pinArray) const override;

protected:
UsermodBus* _usermod;
uint8 _pins[5]; // used as configuration hints for the Usermod

friend class UsermodBus;
};



class UsermodBus : public Usermod {
public:

void setup() override;

protected:
virtual void showBus(BusUsermod* bus) = 0;
virtual void setBusPixelColor(BusUsermod* bus, uint16_t pix, uint32_t c) = 0;
virtual uint32_t getBusPixelColor(const BusUsermod* bus, uint16_t pix) const = 0;
virtual void initBus(BusUsermod* bus) = 0;

// helper functions, as C++ classes do not inherit friend class permissions
inline uint8_t* allocateBusData(BusUsermod* bus, size_t size = 1) { return bus->allocateData(size); }
inline uint8_t* getBusData(const BusUsermod* bus) const { return bus->_data; }
inline const uint8_t* getBusPins(const BusUsermod* bus) const { return bus->_pins; }
inline void setBusRGB(BusUsermod* bus, const bool hasRgb) { bus->_hasRgb = hasRgb; }
inline void setBusWhite(BusUsermod* bus, const bool hasWhite) { bus->_hasWhite = hasWhite; }
inline void setBusCCT(BusUsermod* bus, const bool hasCCT) { bus->_hasCCT = hasCCT; }
inline uint8_t getBusBrightness(const BusUsermod* bus) const { return bus->_bri; }
inline uint32_t autoWhiteCalc(const BusUsermod* bus, uint32_t c) const { return bus->autoWhiteCalc(c); }

friend class BusUsermod;
};





#endif
5 changes: 5 additions & 0 deletions wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@
#define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h"
#define USERMOD_ID_PIXELS_DICE_TRAY 54 //Usermod "pixels_dice_tray.h"

#define USERMOD_ID_BUS 127 //Special ID to be used by UsermodBus instances (only one may be used at once)



//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
Expand Down Expand Up @@ -327,6 +331,7 @@
#define TYPE_NET_DDP_RGBW 88 //network DDP RGBW bus (master broadcast bus)
#define TYPE_NET_ARTNET_RGBW 89 //network ArtNet RGB bus (master broadcast bus, unused)
#define TYPE_VIRTUAL_MAX 95
#define TYPE_USERMOD 127 //virtual type for usermods

/*
// old macros that have been moved to Bus class
Expand Down
6 changes: 3 additions & 3 deletions wled00/data/settings_leds.htm
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@
let nm = LC.name.substring(0,2);
let n = LC.name.substring(2);
let t = parseInt(d.Sf["LT"+n].value, 10); // LED type SELECT
// ignore IP address
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3") {
// ignore IP address and virtual usermod
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4") {
if (t>=80) return;
}
//check for pin conflicts
Expand Down Expand Up @@ -259,7 +259,7 @@
gId("p1d"+n).innerText = p1d;
gId("off"+n).innerText = off;
// secondary pins show/hide (type string length is equivalent to number of pins used; except for network and on/off)
let pins = Math.min(gT(t).t.length,1) + 3*isNet(t); // fixes network pins to 4
let pins = Math.min(gT(t).t.length,1) + 4*isVir(t) - 1*isNet(t); // fixes network pins to 4, other virtual to 5
for (let p=1; p<5; p++) {
var LK = d.Sf["L"+p+n];
if (!LK) continue;
Expand Down
Loading