mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 10:46:31 +00:00
Command 'PixelType' to change the WS2812 color order and channel number (#22876)
This commit is contained in:
parent
a91771e0cf
commit
beb967ccd4
@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Berry `serial.read()` read only `n` bytes (#22835)
|
||||
- Display template for Waveshare ESP32-C6 LCD 1.47 (#22863)
|
||||
- Berry `tasmota.global.tele_period` and `tasmota.settings.tele_period` (#22865)
|
||||
- Command `PixelType` to change the WS2812 color order and channel number
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
|
@ -24,13 +24,15 @@
|
||||
#include "TasmotaLED.h"
|
||||
|
||||
// DRAM_ATTR to force in IRAM because we use this in show loop
|
||||
static const DRAM_ATTR uint8_t TASMOTALED_CHANNEL_ORDERS[6][3] = {
|
||||
{1, 0, 2}, // GRB (0)
|
||||
{2, 0, 1}, // GBR (1)
|
||||
static const DRAM_ATTR uint8_t TASMOTALED_CHANNEL_ORDERS[8][3] = {
|
||||
{1, 0, 2}, // Def=GRB (0)
|
||||
{1, 0, 2}, // GRB (1)
|
||||
{0, 1, 2}, // RGB (2)
|
||||
{0, 2, 1}, // RBG (3)
|
||||
{2, 1, 0}, // BRG (4)
|
||||
{1, 2, 0} // BGR (5)
|
||||
{1, 2, 0}, // BGR (5)
|
||||
{2, 0, 1}, // GBR (6)
|
||||
{1, 0, 2} // GRB (7) // fallback if erroneous value
|
||||
};
|
||||
|
||||
static const TasmotaLED_Timing TasmotaLED_Timings[] = {
|
||||
@ -61,8 +63,6 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D
|
||||
|
||||
TasmotaLED::TasmotaLED(uint16_t type, uint16_t num_leds) :
|
||||
_type(type),
|
||||
_pixel_order((type >> 4) & 0x07),
|
||||
_w_before(type & 0x08),
|
||||
_timing((type >> 8) & 0xFF),
|
||||
_started(false),
|
||||
_dirty(true),
|
||||
@ -70,19 +70,17 @@ TasmotaLED::TasmotaLED(uint16_t type, uint16_t num_leds) :
|
||||
_pixel_count(num_leds),
|
||||
_buf_work(nullptr),
|
||||
_buf_show(nullptr),
|
||||
_pixel_matrix(&TASMOTALED_CHANNEL_ORDERS[0]),
|
||||
_pusher(nullptr)
|
||||
{
|
||||
_adjustSubType(); // compute values for _pixel_order, _w_before, _pixel_matrix
|
||||
if (_timing > (TasmotaLed_TimingEnd >> 8)) {
|
||||
_timing = 0;
|
||||
}
|
||||
switch (_type & 0x0F) {
|
||||
// case TasmotaLed_1_W:
|
||||
// _pixel_size = 1;
|
||||
// break;
|
||||
case TasmotaLed_4_WRGB:
|
||||
_pixel_size = 4;
|
||||
break;
|
||||
case TasmotaLed_1_Def:
|
||||
case TasmotaLed_3_RGB:
|
||||
default: // fallback
|
||||
_pixel_size = 3;
|
||||
@ -109,6 +107,13 @@ TasmotaLED::~TasmotaLED() {
|
||||
_buf_show = nullptr;
|
||||
}
|
||||
|
||||
// Adjust all internal parameters accouring to sub-type
|
||||
void TasmotaLED::_adjustSubType(void) {
|
||||
_pixel_order = (_type >> 4) & 0x07;
|
||||
_pixel_matrix = &TASMOTALED_CHANNEL_ORDERS[_pixel_order];
|
||||
_w_before = _type & 0x08;
|
||||
}
|
||||
|
||||
void TasmotaLED::SetPixelCount(uint16_t num_leds) {
|
||||
if (num_leds != _pixel_count) {
|
||||
_pixel_count = num_leds;
|
||||
@ -124,6 +129,12 @@ void TasmotaLED::SetPixelCount(uint16_t num_leds) {
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaLED::SetPixelSubType(uint8_t subtype) {
|
||||
// subtype is only the 8 lower bits of _type
|
||||
_type = (_type & 0xFF00) | (subtype & 0xFF);
|
||||
_adjustSubType();
|
||||
}
|
||||
|
||||
|
||||
// Color is passed as 0xWWRRGGBB and copied as WWRRGGBB in _buf_work
|
||||
void TasmotaLED::ClearTo(uint32_t wrgb, int32_t first, int32_t last) {
|
||||
|
@ -22,16 +22,17 @@
|
||||
|
||||
enum TasmotaLEDTypesEncoding : uint16_t {
|
||||
// bits 0..3 encode for number of bytes per pixel
|
||||
TasmotaLed_1_W = 0x0, // 1 byte per pixel (not used yet)
|
||||
TasmotaLed_1_Def = 0x0, // Default value - identical to TasmotaLed_3_RGB
|
||||
TasmotaLed_3_RGB = 0x1, // 3 bytes per pixel
|
||||
TasmotaLed_4_WRGB = 0x2, // 4 bytes per pixel
|
||||
// bits 4..6 encode for pixel order
|
||||
TasmotaLed_GRB = 0b000 << 4,
|
||||
TasmotaLed_GBR = 0b001 << 4,
|
||||
TasmotaLed_Def = 0b000 << 4, // Default value - identical to TasmotaLed_GRB
|
||||
TasmotaLed_GRB = 0b001 << 4,
|
||||
TasmotaLed_RGB = 0b010 << 4,
|
||||
TasmotaLed_RBG = 0b011 << 4,
|
||||
TasmotaLed_BRG = 0b100 << 4,
|
||||
TasmotaLed_BGR = 0b101 << 4,
|
||||
TasmotaLed_GBR = 0b110 << 4,
|
||||
// bit 7 sets the position for W channel
|
||||
TasmotaLed_xxxW = 0b0 << 7, // W channel after color
|
||||
TasmotaLed_Wxxx = 0b1 << 7, // W channel before color
|
||||
@ -92,6 +93,8 @@ public:
|
||||
~TasmotaLED();
|
||||
|
||||
void SetPixelCount(uint16_t num_leds);
|
||||
void SetPixelSubType(uint8_t type); // change only Pixel order and pixel size
|
||||
void _adjustSubType(void);
|
||||
|
||||
bool Begin(void);
|
||||
void SetPusher(TasmotaLEDPusher *pusher); // needs to be called before `Begin()`, sets the hardware implementation
|
||||
|
@ -532,6 +532,7 @@
|
||||
#define D_CMND_PALETTE "Palette"
|
||||
#define D_CMND_PIXELS "Pixels"
|
||||
#define D_CMND_STEPPIXELS "StepPixels"
|
||||
#define D_CMND_PIXELTYPE "PixelType"
|
||||
#define D_CMND_ARTNET "ArtNet"
|
||||
#define D_CMND_ARTNET_CONFIG "ArtNetConfig"
|
||||
#define D_SO_ARTNET_AUTORUN "ArtNetAutorun"
|
||||
|
@ -242,11 +242,9 @@ typedef union {
|
||||
uint32_t data; // Allow bit manipulation
|
||||
struct {
|
||||
uint32_t log_file_idx : 4; // bit 0.3 (v14.4.1.2) - FileLog log rotate index
|
||||
uint32_t spare04 : 1; // bit 4
|
||||
uint32_t spare05 : 1; // bit 5
|
||||
uint32_t spare06 : 1; // bit 6
|
||||
uint32_t spare07 : 1; // bit 7
|
||||
uint32_t spare08 : 1; // bit 8
|
||||
uint32_t light_pixels_order : 3; // bit 4.6 (v14.4.1.3) - LED light order <Compile>/GRB/RGB/RBG/BRG/BGR/GBR, high bit indicates W before (for RGBW)
|
||||
uint32_t light_pixels_rgbw : 1; // bit 7 (v14.4.1.3) - LED true is 4 channels RGBW, false is 3 channels RGB
|
||||
uint32_t light_pixels_w_first : 1; // bit 8 (v14.4.1.3) - LED true if W channel comes first, default is <RGB>W
|
||||
uint32_t spare09 : 1; // bit 9
|
||||
uint32_t spare10 : 1; // bit 10
|
||||
uint32_t spare11 : 1; // bit 11
|
||||
|
@ -44,10 +44,10 @@
|
||||
const uint8_t WS2812_SCHEMES = 10; // Number of WS2812 schemes
|
||||
|
||||
const char kWs2812Commands[] PROGMEM = "|" // No prefix
|
||||
D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH "|" D_CMND_STEPPIXELS ;
|
||||
D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH "|" D_CMND_STEPPIXELS "|" D_CMND_PIXELTYPE ;
|
||||
|
||||
void (* const Ws2812Command[])(void) PROGMEM = {
|
||||
&CmndLed, &CmndPixels, &CmndRotation, &CmndWidth, &CmndStepPixels };
|
||||
&CmndLed, &CmndPixels, &CmndRotation, &CmndWidth, &CmndStepPixels, &CmndPixelType };
|
||||
|
||||
#include <TasmotaLED.h>
|
||||
|
||||
@ -610,6 +610,17 @@ void Ws2812ShowScheme(void)
|
||||
}
|
||||
}
|
||||
|
||||
// convert the Settings to a Led type compatible with TasmotaLED
|
||||
uint16_t Ws2812SettingsToLedType(void) {
|
||||
uint16_t led_type = kTasLed_Type; // default value from compile options
|
||||
if (Settings->mbflag2.light_pixels_order != 0) {
|
||||
led_type = (led_type & 0xFF00) | (Settings->mbflag2.light_pixels_order << 4)
|
||||
| (Settings->mbflag2.light_pixels_w_first ? TasmotaLed_Wxxx : 0)
|
||||
| (Settings->mbflag2.light_pixels_rgbw ? TasmotaLed_4_WRGB : TasmotaLed_3_RGB);
|
||||
}
|
||||
return led_type;
|
||||
}
|
||||
|
||||
bool Ws2812InitStrip(void)
|
||||
{
|
||||
if (strip != nullptr) {
|
||||
@ -623,7 +634,8 @@ bool Ws2812InitStrip(void)
|
||||
AddLog(LOG_LEVEL_ERROR, "LED: No hardware supported");
|
||||
return false;
|
||||
}
|
||||
strip = new TasmotaLED(kTasLed_Type, Settings->light_pixels);
|
||||
uint16_t led_type = Ws2812SettingsToLedType();
|
||||
strip = new TasmotaLED(led_type, Settings->light_pixels);
|
||||
strip->SetPusher(pusher);
|
||||
strip->Begin();
|
||||
|
||||
@ -643,6 +655,21 @@ bool Ws2812ChangePixelCount(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ws2812ChangePixelType(bool clear)
|
||||
{
|
||||
if (strip == nullptr) {
|
||||
return true;
|
||||
}
|
||||
uint16_t led_type = Ws2812SettingsToLedType();
|
||||
strip->SetPixelSubType(led_type & 0xFF); // just submit the lower part
|
||||
if (clear) {
|
||||
Ws2812Clear();
|
||||
} else {
|
||||
Ws2812LibStripShow();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Ws2812ModuleSelected(void)
|
||||
{
|
||||
if (Ws2812InitStrip()) {
|
||||
@ -809,6 +836,37 @@ void CmndPixels(void)
|
||||
Settings->light_pixels, Settings->light_pixels_reverse, Settings->light_pixels_height_1 + 1, Settings->light_pixels_alternate);
|
||||
}
|
||||
|
||||
void CmndPixelType(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32)) {
|
||||
// Value is:
|
||||
// 0 = use compile-time option (default value)
|
||||
// 1..6 = Pixel Order: 1=GRB 2=RGB 3=RBG 4=BRG 5=BGR 6=GBR
|
||||
// Modifiers:
|
||||
// +8 = 4 channels RGBW strip - default is 3 channels RGB
|
||||
// +16 = W channel is sent first - default W channel is sent last
|
||||
uint32_t pixels_order = XdrvMailbox.payload & 0x07;
|
||||
uint32_t pixels_w_first = (XdrvMailbox.payload & 0x08) ? 1 : 0;
|
||||
uint32_t pixels_rgbw = (XdrvMailbox.payload & 0x10) ? 1 : 0;
|
||||
// changing number of channels requires a reboot
|
||||
bool reboot = pixels_rgbw != Settings->mbflag2.light_pixels_rgbw;
|
||||
if (reboot) {
|
||||
TasmotaGlobal.restart_flag = 2; // force restart if number of channels changed
|
||||
}
|
||||
|
||||
Settings->mbflag2.light_pixels_order = pixels_order;
|
||||
Settings->mbflag2.light_pixels_w_first = pixels_w_first;
|
||||
Settings->mbflag2.light_pixels_rgbw = (XdrvMailbox.payload & 0x10) ? 1 : 0;
|
||||
Ws2812ChangePixelType(reboot);
|
||||
}
|
||||
uint32_t pixel_type = 0;
|
||||
if (Settings->mbflag2.light_pixels_order != 0) {
|
||||
pixel_type = Settings->mbflag2.light_pixels_order | (Settings->mbflag2.light_pixels_w_first ? 0x08 : 0)
|
||||
| (Settings->mbflag2.light_pixels_rgbw ? 0x10 : 0);
|
||||
}
|
||||
ResponseCmndNumber(pixel_type);
|
||||
}
|
||||
|
||||
void CmndStepPixels(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user