mirror of
https://github.com/openshwprojects/OpenBK7231T_App.git
synced 2026-02-20 00:32:37 +01:00
merge LED strip backend separation before DMX support
* stub * clear * clear upo * one more test * split * fx * Update drv_led_shared.c * step * split * Update drv_leds_shared.c * Update selftest_ws2812b.c * port * dmx * DMX * s * with test * fix * fx * ChType_Ph test and RGBW test * ddp formats unfinished * Update selftest_ws2812b.c * Update selftest_hass_discovery_ext.c * fxes
This commit is contained in:
@@ -217,6 +217,7 @@
|
||||
<ClCompile Include="src\driver\drv_debouncer.c" />
|
||||
<ClCompile Include="src\driver\drv_dht.c" />
|
||||
<ClCompile Include="src\driver\drv_dht_internal.c" />
|
||||
<ClCompile Include="src\driver\drv_dmx512.c" />
|
||||
<ClCompile Include="src\driver\drv_ds1820_full.c" />
|
||||
<ClCompile Include="src\driver\drv_ds1820_common.c" />
|
||||
<ClCompile Include="src\driver\drv_doorSensorWithDeepSleep.c" />
|
||||
@@ -231,6 +232,7 @@
|
||||
<ClCompile Include="src\driver\drv_ir.cpp" />
|
||||
<ClCompile Include="src\driver\drv_kp18058.c" />
|
||||
<ClCompile Include="src\driver\drv_kp18068.c" />
|
||||
<ClCompile Include="src\driver\drv_leds_shared.c" />
|
||||
<ClCompile Include="src\driver\drv_main.c" />
|
||||
<ClCompile Include="src\driver\drv_max6675.c" />
|
||||
<ClCompile Include="src\driver\drv_max72xx_clock.c" />
|
||||
|
||||
@@ -408,6 +408,8 @@
|
||||
<ClCompile Include="src\driver\drv_spi_flash.c" />
|
||||
<ClCompile Include="src\hal\win32\hal_ota_win32.c" />
|
||||
<ClCompile Include="src\driver\drv_tca9554.c" />
|
||||
<ClCompile Include="src\driver\drv_leds_shared.c" />
|
||||
<ClCompile Include="src\driver\drv_dmx512.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\base64\base64.h" />
|
||||
|
||||
@@ -114,6 +114,7 @@ set(OBKM_SRC
|
||||
${OBK_SRCS}driver/drv_soft_spi.c
|
||||
${OBK_SRCS}driver/drv_sm15155e.c
|
||||
${OBK_SRCS}driver/drv_sm16703P.c
|
||||
${OBK_SRCS}driver/drv_leds_shared.c
|
||||
${OBK_SRCS}driver/drv_spi.c
|
||||
${OBK_SRCS}driver/drv_spiLED.c
|
||||
${OBK_SRCS}driver/drv_spi_flash.c
|
||||
|
||||
@@ -128,6 +128,7 @@ OBKM_SRC += $(OBK_SRCS)driver/drv_shiftRegister.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_sht3x.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_sm15155e.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_sm16703P.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_leds_shared.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_sm2135.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_sm2235.c
|
||||
OBKM_SRC += $(OBK_SRCS)driver/drv_soft_i2c.c
|
||||
|
||||
@@ -124,19 +124,23 @@ void DDP_Parse(byte *data, int len) {
|
||||
if(len > 12) {
|
||||
byte r, g, b;
|
||||
|
||||
r = data[10];
|
||||
g = data[11];
|
||||
b = data[12];
|
||||
// This is done by WLED, but not checked in Tasmota
|
||||
// data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
||||
byte bytesPerPixel = ((data[2] & 0b00111000) >> 3 == 0b011) ? 4 : 3;
|
||||
|
||||
#if ENABLE_DRIVER_SM16703P
|
||||
if (spiLED.ready) {
|
||||
// Note that this is limited by DDP msgbuf size
|
||||
uint32_t pixel = (len - 10) / 3;
|
||||
uint32_t numPixels = (len - 10) / 3;
|
||||
// This immediately activates the pixels, maybe we should read the PUSH flag
|
||||
SM16703P_setMultiplePixel(pixel, &data[10], true);
|
||||
SM16703P_setMultiplePixel(numPixels, &data[10], true);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
r = data[10];
|
||||
g = data[11];
|
||||
b = data[12];
|
||||
|
||||
#if ENABLE_LED_BASIC
|
||||
LED_SetDimmerIfChanged(100);
|
||||
if (data[9] == 4) {
|
||||
|
||||
86
src/driver/drv_dmx512.c
Normal file
86
src/driver/drv_dmx512.c
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "../new_cfg.h"
|
||||
#include "../new_common.h"
|
||||
#include "../new_pins.h"
|
||||
// Commands register, execution API and cmd tokenizer
|
||||
#include "../cmnds/cmd_public.h"
|
||||
#include "../hal/hal_pins.h"
|
||||
#include "../httpserver/new_http.h"
|
||||
#include "../logging/logging.h"
|
||||
#include "../mqtt/new_mqtt.h"
|
||||
|
||||
#if ENABLE_DRIVER_DMX
|
||||
|
||||
#include "drv_leds_shared.h"
|
||||
#include "drv_local.h"
|
||||
|
||||
#define DMX_CHANNELS_SIZE 512
|
||||
#define DMX_BUFFER_SIZE (DMX_CHANNELS_SIZE+1)
|
||||
|
||||
static byte *g_dmxBuffer;
|
||||
static int dmx_pixelCount = 0;
|
||||
static int dmx_pixelSize = 3;
|
||||
|
||||
int dmx_pin = 0;
|
||||
|
||||
void DMX_Show() {
|
||||
// BREAK: pull TX low manually
|
||||
HAL_PIN_Setup_Output(dmx_pin);
|
||||
HAL_PIN_SetOutputValue(dmx_pin, 0);
|
||||
HAL_Delay_us(120); // ≥88µs
|
||||
HAL_PIN_SetOutputValue(dmx_pin, 1);
|
||||
HAL_Delay_us(12); // MAB ≥8µs
|
||||
|
||||
// restore UART and send DMX data
|
||||
HAL_UART_Init(250000, 2, true);
|
||||
for (int i = 0; i < DMX_BUFFER_SIZE; i++) {
|
||||
HAL_UART_SendByte(g_dmxBuffer[i]);
|
||||
}
|
||||
//Serial485.begin(250000, SERIAL_8N2, RS485_RX_PIN, RS485_TX_PIN);
|
||||
////Serial485.write(dmxBuffer, sizeof(dmxBuffer));
|
||||
//Serial485.flush();
|
||||
}
|
||||
|
||||
byte DMX_GetByte(uint32_t idx) {
|
||||
if (idx >= DMX_CHANNELS_SIZE)
|
||||
return 0;
|
||||
return g_dmxBuffer[1 + idx];
|
||||
}
|
||||
void DMX_setByte(int idx, byte color) {
|
||||
if (idx >= DMX_CHANNELS_SIZE)
|
||||
return 0;
|
||||
g_dmxBuffer[1 + idx] = color;
|
||||
}
|
||||
|
||||
void DMX_SetLEDCount(int pixel_count, int pixel_size) {
|
||||
dmx_pixelCount = pixel_count;
|
||||
dmx_pixelSize = pixel_size;
|
||||
}
|
||||
|
||||
void DMX_Init() {
|
||||
g_dmxBuffer = (byte*)malloc(DMX_BUFFER_SIZE);
|
||||
memset(g_dmxBuffer, 0, DMX_BUFFER_SIZE);
|
||||
ledStrip_t ws_export;
|
||||
ws_export.apply = DMX_Show;
|
||||
ws_export.getByte = DMX_GetByte;
|
||||
ws_export.setByte = DMX_setByte;
|
||||
ws_export.setLEDCount = DMX_SetLEDCount;
|
||||
|
||||
LEDS_InitShared(&ws_export);
|
||||
}
|
||||
void DMX_OnEverySecond() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DMX_Shutdown() {
|
||||
if (g_dmxBuffer) {
|
||||
free(g_dmxBuffer);
|
||||
g_dmxBuffer = 0;
|
||||
}
|
||||
LEDS_ShutdownShared();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
325
src/driver/drv_leds_shared.c
Normal file
325
src/driver/drv_leds_shared.c
Normal file
@@ -0,0 +1,325 @@
|
||||
#include "../new_cfg.h"
|
||||
#include "../new_common.h"
|
||||
#include "../new_pins.h"
|
||||
// Commands register, execution API and cmd tokenizer
|
||||
#include "../cmnds/cmd_public.h"
|
||||
#include "../hal/hal_pins.h"
|
||||
#include "../httpserver/new_http.h"
|
||||
#include "../logging/logging.h"
|
||||
#include "../mqtt/new_mqtt.h"
|
||||
|
||||
#include "drv_local.h"
|
||||
#include "drv_leds_shared.h"
|
||||
|
||||
static ledStrip_t led_backend;
|
||||
|
||||
enum ColorChannel {
|
||||
COLOR_CHANNEL_RED,
|
||||
COLOR_CHANNEL_GREEN,
|
||||
COLOR_CHANNEL_BLUE,
|
||||
COLOR_CHANNEL_COLD_WHITE,
|
||||
COLOR_CHANNEL_WARM_WHITE
|
||||
};
|
||||
|
||||
#define DEFAULT_PIXEL_SIZE 3
|
||||
const enum ColorChannel default_color_channel_order[3] = {
|
||||
COLOR_CHANNEL_RED,
|
||||
COLOR_CHANNEL_GREEN,
|
||||
COLOR_CHANNEL_BLUE
|
||||
};
|
||||
|
||||
enum ColorChannel *color_channel_order = default_color_channel_order;
|
||||
int pixel_size = DEFAULT_PIXEL_SIZE; // default is RGB -> 3 bytes per pixel
|
||||
// Number of pixels that can be addressed
|
||||
uint32_t pixel_count;
|
||||
|
||||
void SM16703P_GetPixel(uint32_t pixel, byte *dst) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pixel_size; i++) {
|
||||
dst[i] = led_backend.getByte(pixel * pixel_size + i);
|
||||
}
|
||||
}
|
||||
|
||||
bool SM16703P_VerifyPixel(uint32_t pixel, byte r, byte g, byte b) {
|
||||
byte real[4];
|
||||
SM16703P_GetPixel(pixel, real);
|
||||
if (real[0] != r)
|
||||
return false;
|
||||
if (real[1] != g)
|
||||
return false;
|
||||
if (real[2] != b)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool SM16703P_VerifyPixel4(uint32_t pixel, byte r, byte g, byte b, byte w) {
|
||||
byte real[4];
|
||||
SM16703P_GetPixel(pixel, real);
|
||||
if (real[0] != r)
|
||||
return false;
|
||||
if (real[1] != g)
|
||||
return false;
|
||||
if (real[2] != b)
|
||||
return false;
|
||||
if (real[3] != w)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SM16703P_setPixel(int pixel, int r, int g, int b, int c, int w) {
|
||||
if (pixel < 0 || pixel >= pixel_count) {
|
||||
return; // out of range - would crash
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < pixel_size; i++)
|
||||
{
|
||||
byte pcolor;
|
||||
switch (color_channel_order[i])
|
||||
{
|
||||
case COLOR_CHANNEL_RED:
|
||||
pcolor = r;
|
||||
break;
|
||||
case COLOR_CHANNEL_GREEN:
|
||||
pcolor = g;
|
||||
break;
|
||||
case COLOR_CHANNEL_BLUE:
|
||||
pcolor = b;
|
||||
break;
|
||||
case COLOR_CHANNEL_COLD_WHITE:
|
||||
pcolor = c;
|
||||
break;
|
||||
case COLOR_CHANNEL_WARM_WHITE:
|
||||
pcolor = w;
|
||||
break;
|
||||
default:
|
||||
ADDLOG_ERROR(LOG_FEATURE_CMD, "Unknown color channel %d at index %d", color_channel_order[i], i);
|
||||
return;
|
||||
}
|
||||
led_backend.setByte(i + (pixel * pixel_size), pcolor);
|
||||
|
||||
}
|
||||
}
|
||||
void SM16703P_setMultiplePixel(uint32_t pixel, uint8_t *data, bool push) {
|
||||
// Check max pixel
|
||||
if (pixel > pixel_count)
|
||||
pixel = pixel_count;
|
||||
|
||||
// Iterate over pixel
|
||||
for (uint32_t i = 0; i < pixel; i++) {
|
||||
uint8_t r, g, b;
|
||||
r = *data++;
|
||||
g = *data++;
|
||||
b = *data++;
|
||||
// TODO: Not sure how this works. Should we add Cold and Warm white here as well?
|
||||
SM16703P_setPixel((int)i, (int)r, (int)g, (int)b, 0, 0);
|
||||
}
|
||||
if (push) {
|
||||
SM16703P_Show();
|
||||
|
||||
}
|
||||
}
|
||||
extern float g_brightness0to100;//TODO
|
||||
void SM16703P_setPixelWithBrig(int pixel, int r, int g, int b, int c, int w) {
|
||||
// scale brightness
|
||||
#if ENABLE_LED_BASIC
|
||||
r = (int)(r * g_brightness0to100*0.01f);
|
||||
g = (int)(g * g_brightness0to100*0.01f);
|
||||
b = (int)(b * g_brightness0to100*0.01f);
|
||||
c = (int)(c * g_brightness0to100*0.01f);
|
||||
w = (int)(w * g_brightness0to100*0.01f);
|
||||
#endif
|
||||
SM16703P_setPixel(pixel, r, g, b, c, w);
|
||||
}
|
||||
#define SCALE8_PIXEL(x, scale) (uint8_t)(((uint32_t)x * (uint32_t)scale) / 256)
|
||||
|
||||
void SM16703P_scaleAllPixels(int scale) {
|
||||
int pixel;
|
||||
byte b;
|
||||
int ofs;
|
||||
byte *data, *input;
|
||||
|
||||
for (pixel = 0; pixel < pixel_count; pixel++) {
|
||||
for (ofs = 0; ofs < 3; ofs++) {
|
||||
int byteIndex = pixel * 3 + ofs;
|
||||
byte b = led_backend.getByte(byteIndex);
|
||||
b = SCALE8_PIXEL(b, scale);
|
||||
led_backend.setByte(byteIndex, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
void SM16703P_setAllPixels(int r, int g, int b, int c, int w) {
|
||||
int pixel;
|
||||
|
||||
for (pixel = 0; pixel < pixel_count; pixel++) {
|
||||
SM16703P_setPixel(pixel, r, g, b, c, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SM16703P_SetRaw bUpdate byteOfs HexData
|
||||
// SM16703P_SetRaw 1 0 FF000000FF000000FF
|
||||
commandResult_t SM16703P_CMD_setRaw(const void *context, const char *cmd, const char *args, int flags) {
|
||||
int ofs, bPush;
|
||||
Tokenizer_TokenizeString(args, 0);
|
||||
bPush = Tokenizer_GetArgInteger(0);
|
||||
ofs = Tokenizer_GetArgInteger(1);
|
||||
const char *s = Tokenizer_GetArg(2);
|
||||
int i = 0;
|
||||
// parse hex string like FFAABB0011 byte by byte
|
||||
while (s[0] && s[1]) {
|
||||
led_backend.setByte(i, hexbyte(s));
|
||||
i++;
|
||||
s += 2;
|
||||
}
|
||||
if (bPush) {
|
||||
led_backend.apply();
|
||||
}
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
commandResult_t SM16703P_CMD_setPixel(const void *context, const char *cmd, const char *args, int flags) {
|
||||
int i, r, g, b, c, w;
|
||||
int pixel = 0;
|
||||
const char *all = 0;
|
||||
Tokenizer_TokenizeString(args, 0);
|
||||
|
||||
if (Tokenizer_GetArgsCount() < 4) {
|
||||
// We need at least 4 arguments: pixel, red, green, blue - cold and warm white are optional
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Not Enough Arguments for init SM16703P: Amount of LEDs missing");
|
||||
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
||||
}
|
||||
|
||||
all = Tokenizer_GetArg(0);
|
||||
if (*all == 'a') {
|
||||
|
||||
}
|
||||
else {
|
||||
pixel = Tokenizer_GetArgInteger(0);
|
||||
all = 0;
|
||||
}
|
||||
r = Tokenizer_GetArgIntegerRange(1, 0, 255);
|
||||
g = Tokenizer_GetArgIntegerRange(2, 0, 255);
|
||||
b = Tokenizer_GetArgIntegerRange(3, 0, 255);
|
||||
c = 0; // cold white is optional for backward compatibility
|
||||
if (Tokenizer_GetArgsCount() > 4) {
|
||||
c = Tokenizer_GetArgIntegerRange(4, 0, 255);
|
||||
}
|
||||
w = 0; // warm white is optional for backward compatibility
|
||||
if (Tokenizer_GetArgsCount() > 5) {
|
||||
w = Tokenizer_GetArgIntegerRange(5, 0, 255);
|
||||
}
|
||||
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Set Pixel %i to R %i G %i B %i C %i W %i", pixel, r, g, b, c, w);
|
||||
|
||||
if (all) {
|
||||
for (i = 0; i < pixel_count; i++) {
|
||||
SM16703P_setPixel(i, r, g, b, c, w);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SM16703P_setPixel(pixel, r, g, b, c, w);
|
||||
}
|
||||
|
||||
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
|
||||
commandResult_t SM16703P_InitForLEDCount(const void *context, const char *cmd, const char *args, int flags) {
|
||||
|
||||
Tokenizer_TokenizeString(args, 0);
|
||||
|
||||
if (Tokenizer_GetArgsCount() == 0) {
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Not Enough Arguments for init SM16703P: Amount of LEDs missing");
|
||||
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
||||
}
|
||||
|
||||
SM16703P_Shutdown();
|
||||
|
||||
// First arg: number of pixel to address
|
||||
pixel_count = Tokenizer_GetArgIntegerRange(0, 0, 255);
|
||||
// Second arg (optional, default "RGB"): pixel format of "RGB" or "GRB"
|
||||
if (Tokenizer_GetArgsCount() > 1) {
|
||||
const char *format = Tokenizer_GetArg(1);
|
||||
size_t format_length = strlen(format);
|
||||
enum ColorChannel *new_channel_order = os_malloc(sizeof(enum ColorChannel) * (format_length + 1));
|
||||
if (!new_channel_order) {
|
||||
ADDLOG_ERROR(LOG_FEATURE_CMD, "Failed to allocate memory for color channel order");
|
||||
return CMD_RES_ERROR;
|
||||
}
|
||||
int i = 0;
|
||||
for (const char *p = format; *p; p++) {
|
||||
switch (*p) {
|
||||
case 'R':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_RED;
|
||||
break;
|
||||
case 'G':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_GREEN;
|
||||
break;
|
||||
case 'B':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_BLUE;
|
||||
break;
|
||||
case 'C':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_COLD_WHITE;
|
||||
break;
|
||||
case 'W':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_WARM_WHITE;
|
||||
break;
|
||||
default:
|
||||
ADDLOG_ERROR(LOG_FEATURE_CMD, "Invalid color '%c' in format '%s', should be combination of R,G,B,C,W", *p, format);
|
||||
os_free(new_channel_order);
|
||||
return CMD_RES_ERROR;
|
||||
}
|
||||
}
|
||||
pixel_size = i; // number of color channels
|
||||
color_channel_order = new_channel_order;
|
||||
}
|
||||
led_backend.setLEDCount(pixel_count, pixel_size);
|
||||
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Register driver with %i LEDs", pixel_count);
|
||||
|
||||
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
|
||||
static commandResult_t SM16703P_StartTX(const void *context, const char *cmd, const char *args, int flags) {
|
||||
led_backend.apply();
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
|
||||
// startDriver SM16703P
|
||||
// backlog startDriver SM16703P; SM16703P_Test
|
||||
void LEDS_InitShared(ledStrip_t *api) {
|
||||
|
||||
led_backend = *api;
|
||||
|
||||
//cmddetail:{"name":"SM16703P_Init","args":"[NumberOfLEDs][ColorOrder]",
|
||||
//cmddetail:"descr":"This will setup LED driver for a strip with given number of LEDs. Please note that it also works for WS2812B and similiar LEDs. You can optionally set the color order with can be any combination of R, G, B, C and W (e.g. RGBW or GRBWC, default is RGB). See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_Init", SM16703P_InitForLEDCount, NULL);
|
||||
//cmddetail:{"name":"SM16703P_Start","args":"",
|
||||
//cmddetail:"descr":"This will send the currently set data to the strip. Please note that it also works for WS2812B and similiar LEDs. See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_Start", SM16703P_StartTX, NULL);
|
||||
//cmddetail:{"name":"SM16703P_SetPixel","args":"[index/all] [R] [G] [B]",
|
||||
//cmddetail:"descr":"Sets a pixel for LED strip. Index can be a number or 'all' keyword to set all. Then, 3 integer values for R, G and B. Please note that it also works for WS2812B and similiar LEDs. See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_SetPixel", SM16703P_CMD_setPixel, NULL);
|
||||
//cmddetail:{"name":"SM16703P_SetRaw","args":"[bUpdate] [byteOfs] [HexData]",
|
||||
//cmddetail:"descr":"Sets the raw data bytes for SPI DMA LED driver at the given offset. Hex data should be as a hex string, for example, FF00AA, etc. The bUpdate, if set to 1, will run SM16703P_Start automatically after setting data. Please note that it also works for WS2812B and similiar LEDs. See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_SetRaw", SM16703P_CMD_setRaw, NULL);
|
||||
|
||||
//CMD_RegisterCommand("SM16703P_SendBytes", SM16703P_CMD_sendBytes, NULL);
|
||||
}
|
||||
|
||||
void LEDS_ShutdownShared() {
|
||||
if (color_channel_order != default_color_channel_order) {
|
||||
os_free(color_channel_order);
|
||||
color_channel_order = default_color_channel_order;
|
||||
}
|
||||
pixel_size = DEFAULT_PIXEL_SIZE;
|
||||
}
|
||||
19
src/driver/drv_leds_shared.h
Normal file
19
src/driver/drv_leds_shared.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __DRV_LED_SHARED_H__
|
||||
#define __DRV_LED_SHARED_H__
|
||||
|
||||
#include "../new_cfg.h"
|
||||
#include "../new_common.h"
|
||||
#include "../new_pins.h"
|
||||
|
||||
typedef struct ledStrip_s {
|
||||
byte (*getByte)(uint32_t pixel);
|
||||
void (*setByte)(uint32_t idx, byte val);
|
||||
void (*apply)();
|
||||
void (*setLEDCount)(int pixel_count, int pixel_size);
|
||||
} ledStrip_t;
|
||||
|
||||
|
||||
void LEDS_InitShared(ledStrip_t *api);
|
||||
void LEDS_ShutdownShared();
|
||||
|
||||
#endif
|
||||
@@ -190,6 +190,10 @@ void TCA9554_Init();
|
||||
void TCA9554_OnEverySecond();
|
||||
void TCA9554_OnChannelChanged(int ch, int value);
|
||||
|
||||
void DMX_Init();
|
||||
void DMX_OnEverySecond();
|
||||
void DMX_Shutdown();
|
||||
|
||||
void PWMG_Init();
|
||||
|
||||
void Freeze_Init();
|
||||
|
||||
@@ -53,6 +53,13 @@ static driver_t g_drivers[] = {
|
||||
//drvdetail:"requires":""}
|
||||
{ "TCA9554", TCA9554_Init, TCA9554_OnEverySecond, NULL, NULL, NULL, TCA9554_OnChannelChanged , NULL, false },
|
||||
#endif
|
||||
#if ENABLE_DRIVER_DMX
|
||||
//drvdetail:{"name":"DMX",
|
||||
//drvdetail:"title":"TODO",
|
||||
//drvdetail:"descr":"DMX.",
|
||||
//drvdetail:"requires":""}
|
||||
{ "DMX", DMX_Init, DMX_OnEverySecond, NULL, NULL, DMX_Shutdown, NULL , NULL, false },
|
||||
#endif
|
||||
#if ENABLE_DRIVER_FREEZE
|
||||
//drvdetail:{"name":"FREEZE",
|
||||
//drvdetail:"title":"TODO",
|
||||
|
||||
@@ -10,272 +10,35 @@
|
||||
|
||||
#if ENABLE_DRIVER_SM16703P
|
||||
|
||||
#include "drv_leds_shared.h"
|
||||
#include "drv_local.h"
|
||||
#include "drv_spiLED.h"
|
||||
|
||||
// Number of pixels that can be addressed
|
||||
uint32_t pixel_count;
|
||||
|
||||
void SM16703P_GetPixel(uint32_t pixel, byte *dst) {
|
||||
int i;
|
||||
uint8_t *input;
|
||||
void SM16703P_Show() {
|
||||
if (spiLED.ready == 0)
|
||||
return;
|
||||
SPIDMA_StartTX(spiLED.msg);
|
||||
}
|
||||
|
||||
byte SM16703P_GetByte(uint32_t idx) {
|
||||
if (spiLED.msg == 0)
|
||||
return 0;
|
||||
if (spiLED.ready == 0)
|
||||
return 0;
|
||||
byte *input = spiLED.buf + spiLED.ofs + idx * 4;
|
||||
byte ret = reverse_translate_byte(input);
|
||||
return ret;
|
||||
}
|
||||
void SM16703P_setByte(int index, byte color) {
|
||||
if (spiLED.buf == 0)
|
||||
return;
|
||||
|
||||
input = spiLED.buf + spiLED.ofs + (pixel * 3 * 4);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
*dst++ = reverse_translate_byte(input + i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
enum ColorChannel {
|
||||
COLOR_CHANNEL_RED,
|
||||
COLOR_CHANNEL_GREEN,
|
||||
COLOR_CHANNEL_BLUE,
|
||||
COLOR_CHANNEL_COLD_WHITE,
|
||||
COLOR_CHANNEL_WARM_WHITE
|
||||
};
|
||||
const enum ColorChannel default_color_channel_order[3] = {
|
||||
COLOR_CHANNEL_RED,
|
||||
COLOR_CHANNEL_GREEN,
|
||||
COLOR_CHANNEL_BLUE
|
||||
};
|
||||
enum ColorChannel *color_channel_order = default_color_channel_order;
|
||||
int pixel_size = 3; // default is RGB -> 3 bytes per pixel
|
||||
|
||||
bool SM16703P_VerifyPixel(uint32_t pixel, byte r, byte g, byte b) {
|
||||
byte real[3];
|
||||
SM16703P_GetPixel(pixel, real);
|
||||
if (real[0] != r)
|
||||
return false;
|
||||
if (real[1] != g)
|
||||
return false;
|
||||
if (real[2] != b)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SM16703P_setPixel(int pixel, int r, int g, int b, int c, int w) {
|
||||
if (!spiLED.ready)
|
||||
if (spiLED.ready == 0)
|
||||
return;
|
||||
if(pixel < 0 || pixel >= pixel_count) {
|
||||
return; // out of range - would crash
|
||||
}
|
||||
int i;
|
||||
for(i = 0; i < pixel_size; i++)
|
||||
{
|
||||
int pcolor;
|
||||
switch (color_channel_order[i])
|
||||
{
|
||||
case COLOR_CHANNEL_RED:
|
||||
pcolor = r;
|
||||
break;
|
||||
case COLOR_CHANNEL_GREEN:
|
||||
pcolor = g;
|
||||
break;
|
||||
case COLOR_CHANNEL_BLUE:
|
||||
pcolor = b;
|
||||
break;
|
||||
case COLOR_CHANNEL_COLD_WHITE:
|
||||
pcolor = c;
|
||||
break;
|
||||
case COLOR_CHANNEL_WARM_WHITE:
|
||||
pcolor = w;
|
||||
break;
|
||||
default:
|
||||
ADDLOG_ERROR(LOG_FEATURE_CMD, "Unknown color channel %d at index %d", color_channel_order[i], i);
|
||||
return;
|
||||
}
|
||||
translate_byte(pcolor, spiLED.buf + (spiLED.ofs + i * 4 + (pixel * pixel_size * 4)));
|
||||
}
|
||||
}
|
||||
void SM16703P_setMultiplePixel(uint32_t pixel, uint8_t *data, bool push) {
|
||||
|
||||
// Return if driver is not loaded
|
||||
if (!spiLED.ready)
|
||||
return;
|
||||
|
||||
// Check max pixel
|
||||
if (pixel > pixel_count)
|
||||
pixel = pixel_count;
|
||||
|
||||
// Iterate over pixel
|
||||
uint8_t *dst = spiLED.buf + spiLED.ofs;
|
||||
for (uint32_t i = 0; i < pixel; i++) {
|
||||
uint8_t r, g, b;
|
||||
r = *data++;
|
||||
g = *data++;
|
||||
b = *data++;
|
||||
// TODO: Not sure how this works. Should we add Cold and Warm white here as well?
|
||||
SM16703P_setPixel((int)i, (int)r, (int)g, (int)b, 0, 0);
|
||||
}
|
||||
if (push) {
|
||||
SPIDMA_StartTX(spiLED.msg);
|
||||
}
|
||||
}
|
||||
extern float g_brightness0to100;//TODO
|
||||
void SM16703P_setPixelWithBrig(int pixel, int r, int g, int b, int c, int w) {
|
||||
// scale brightness
|
||||
#if ENABLE_LED_BASIC
|
||||
r = (int)(r * g_brightness0to100*0.01f);
|
||||
g = (int)(g * g_brightness0to100*0.01f);
|
||||
b = (int)(b * g_brightness0to100*0.01f);
|
||||
c = (int)(c * g_brightness0to100*0.01f);
|
||||
w = (int)(w * g_brightness0to100*0.01f);
|
||||
#endif
|
||||
SM16703P_setPixel(pixel,r, g, b, c, w);
|
||||
}
|
||||
#define SCALE8_PIXEL(x, scale) (uint8_t)(((uint32_t)x * (uint32_t)scale) / 256)
|
||||
|
||||
void SM16703P_scaleAllPixels(int scale) {
|
||||
int pixel;
|
||||
byte b;
|
||||
int ofs;
|
||||
byte *data, *input;
|
||||
|
||||
for (pixel = 0; pixel < pixel_count; pixel++) {
|
||||
for (ofs = 0; ofs < 3; ofs++) {
|
||||
data = spiLED.buf + (spiLED.ofs + ofs * 4 + (pixel * 3 * 4));
|
||||
b = reverse_translate_byte(data);
|
||||
b = SCALE8_PIXEL(b, scale);
|
||||
translate_byte(b, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
void SM16703P_setAllPixels(int r, int g, int b, int c, int w) {
|
||||
int pixel;
|
||||
if (!spiLED.ready)
|
||||
return;
|
||||
|
||||
for (pixel = 0; pixel < pixel_count; pixel++) {
|
||||
SM16703P_setPixel(pixel, r, g, b, c, w);
|
||||
}
|
||||
translate_byte(color, spiLED.buf + (spiLED.ofs + index * 4));
|
||||
}
|
||||
|
||||
|
||||
// SM16703P_SetRaw bUpdate byteOfs HexData
|
||||
// SM16703P_SetRaw 1 0 FF000000FF000000FF
|
||||
commandResult_t SM16703P_CMD_setRaw(const void *context, const char *cmd, const char *args, int flags) {
|
||||
int ofs, bPush;
|
||||
Tokenizer_TokenizeString(args, 0);
|
||||
bPush = Tokenizer_GetArgInteger(0);
|
||||
ofs = Tokenizer_GetArgInteger(1);
|
||||
SPILED_SetRawHexString(ofs, Tokenizer_GetArg(2), bPush);
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
commandResult_t SM16703P_CMD_setPixel(const void *context, const char *cmd, const char *args, int flags) {
|
||||
int i, r, g, b, c, w;
|
||||
int pixel = 0;
|
||||
const char *all = 0;
|
||||
Tokenizer_TokenizeString(args, 0);
|
||||
|
||||
if (Tokenizer_GetArgsCount() < 4) {
|
||||
// We need at least 4 arguments: pixel, red, green, blue - cold and warm white are optional
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Not Enough Arguments for init SM16703P: Amount of LEDs missing");
|
||||
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
||||
}
|
||||
|
||||
all = Tokenizer_GetArg(0);
|
||||
if (*all == 'a') {
|
||||
|
||||
}
|
||||
else {
|
||||
pixel = Tokenizer_GetArgInteger(0);
|
||||
all = 0;
|
||||
}
|
||||
r = Tokenizer_GetArgIntegerRange(1, 0, 255);
|
||||
g = Tokenizer_GetArgIntegerRange(2, 0, 255);
|
||||
b = Tokenizer_GetArgIntegerRange(3, 0, 255);
|
||||
c = 0; // cold white is optional for backward compatibility
|
||||
if (Tokenizer_GetArgsCount() > 4) {
|
||||
c = Tokenizer_GetArgIntegerRange(4, 0, 255);
|
||||
}
|
||||
w = 0; // warm white is optional for backward compatibility
|
||||
if (Tokenizer_GetArgsCount() > 5) {
|
||||
w = Tokenizer_GetArgIntegerRange(5, 0, 255);
|
||||
}
|
||||
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Set Pixel %i to R %i G %i B %i C %i W %i", pixel, r, g, b, c, w);
|
||||
|
||||
if (all) {
|
||||
for (i = 0; i < pixel_count; i++) {
|
||||
SM16703P_setPixel(i, r, g, b, c, w);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SM16703P_setPixel(pixel, r, g, b, c, w);
|
||||
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Raw Data 0x%02x 0x%02x 0x%02x 0x%02x - 0x%02x 0x%02x 0x%02x 0x%02x - 0x%02x 0x%02x 0x%02x 0x%02x",
|
||||
spiLED.buf[spiLED.ofs + 0 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 1 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 2 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 3 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 4 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 5 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 6 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 7 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 8 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 9 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 10 + (pixel * 3 * 4)],
|
||||
spiLED.buf[spiLED.ofs + 11 + (pixel * 3 * 4)]);
|
||||
}
|
||||
|
||||
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
|
||||
commandResult_t SM16703P_InitForLEDCount(const void *context, const char *cmd, const char *args, int flags) {
|
||||
|
||||
Tokenizer_TokenizeString(args, 0);
|
||||
|
||||
if (Tokenizer_GetArgsCount() == 0) {
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Not Enough Arguments for init SM16703P: Amount of LEDs missing");
|
||||
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
|
||||
}
|
||||
|
||||
SM16703P_Shutdown();
|
||||
|
||||
// First arg: number of pixel to address
|
||||
pixel_count = Tokenizer_GetArgIntegerRange(0, 0, 255);
|
||||
// Second arg (optional, default "RGB"): pixel format of "RGB" or "GRB"
|
||||
if (Tokenizer_GetArgsCount() > 1) {
|
||||
const char *format = Tokenizer_GetArg(1);
|
||||
size_t format_length = strlen(format);
|
||||
enum ColorChannel *new_channel_order = os_malloc(sizeof(enum ColorChannel) * (format_length + 1));
|
||||
if (!new_channel_order) {
|
||||
ADDLOG_ERROR(LOG_FEATURE_CMD, "Failed to allocate memory for color channel order");
|
||||
return CMD_RES_ERROR;
|
||||
}
|
||||
int i = 0;
|
||||
for (const char *p = format; *p; p++) {
|
||||
switch (*p) {
|
||||
case 'R':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_RED;
|
||||
break;
|
||||
case 'G':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_GREEN;
|
||||
break;
|
||||
case 'B':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_BLUE;
|
||||
break;
|
||||
case 'C':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_COLD_WHITE;
|
||||
break;
|
||||
case 'W':
|
||||
new_channel_order[i++] = COLOR_CHANNEL_WARM_WHITE;
|
||||
break;
|
||||
default:
|
||||
ADDLOG_ERROR(LOG_FEATURE_CMD, "Invalid color '%c' in format '%s', should be combination of R,G,B,C,W", *p, format);
|
||||
os_free(new_channel_order);
|
||||
return CMD_RES_ERROR;
|
||||
}
|
||||
}
|
||||
pixel_size = i; // number of color channels
|
||||
color_channel_order = new_channel_order;
|
||||
}
|
||||
void SM16703P_SetLEDCount(int pixel_count, int pixel_size) {
|
||||
// Third arg (optional, default "0"): spiLED.ofs to prepend to each transmission
|
||||
if (Tokenizer_GetArgsCount() > 2) {
|
||||
spiLED.ofs = Tokenizer_GetArgIntegerRange(2, 0, 255);
|
||||
@@ -285,41 +48,10 @@ commandResult_t SM16703P_InitForLEDCount(const void *context, const char *cmd, c
|
||||
//if (Tokenizer_GetArgsCount() > 3) {
|
||||
// spiLED.padding = Tokenizer_GetArgIntegerRange(3, 0, 255);
|
||||
//}
|
||||
|
||||
ADDLOG_INFO(LOG_FEATURE_CMD, "Register driver with %i LEDs", pixel_count);
|
||||
|
||||
// each pixel is RGB, so 3 bytes per pixel
|
||||
SPILED_InitDMA(pixel_count * pixel_size);
|
||||
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
|
||||
void SM16703P_Show() {
|
||||
SPIDMA_StartTX(spiLED.msg);
|
||||
}
|
||||
static commandResult_t SM16703P_StartTX(const void *context, const char *cmd, const char *args, int flags) {
|
||||
if (!spiLED.ready)
|
||||
return CMD_RES_ERROR;
|
||||
SM16703P_Show();
|
||||
return CMD_RES_OK;
|
||||
}
|
||||
//static commandResult_t SM16703P_CMD_sendBytes(const void *context, const char *cmd, const char *args, int flags) {
|
||||
// if (!spiLED.ready)
|
||||
// return CMD_RES_ERROR;
|
||||
// const char *s = args;
|
||||
// int i = spiLED.ofs;
|
||||
// while (*s && s[1]) {
|
||||
// *(spiLED.buf + (i)) = hexbyte(s);
|
||||
// s += 2;
|
||||
// i++;
|
||||
// }
|
||||
// while (i < spiLED.msg->send_len) {
|
||||
// *(spiLED.buf + (i)) = 0;
|
||||
// }
|
||||
// SPIDMA_StartTX(spiLED.msg);
|
||||
// return CMD_RES_OK;
|
||||
//}
|
||||
|
||||
// startDriver SM16703P
|
||||
// backlog startDriver SM16703P; SM16703P_Test
|
||||
void SM16703P_Init() {
|
||||
@@ -327,34 +59,16 @@ void SM16703P_Init() {
|
||||
int pin = PIN_FindPinIndexForRole(IOR_SM16703P_DIN, -1);
|
||||
SPILED_Init(pin);
|
||||
|
||||
//cmddetail:{"name":"SM16703P_Init","args":"[NumberOfLEDs][ColorOrder]",
|
||||
//cmddetail:"descr":"This will setup LED driver for a strip with given number of LEDs. Please note that it also works for WS2812B and similiar LEDs. You can optionally set the color order with can be any combination of R, G, B, C and W (e.g. RGBW or GRBWC, default is RGB). See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_Init", SM16703P_InitForLEDCount, NULL);
|
||||
//cmddetail:{"name":"SM16703P_Start","args":"",
|
||||
//cmddetail:"descr":"This will send the currently set data to the strip. Please note that it also works for WS2812B and similiar LEDs. See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_Start", SM16703P_StartTX, NULL);
|
||||
//cmddetail:{"name":"SM16703P_SetPixel","args":"[index/all] [R] [G] [B]",
|
||||
//cmddetail:"descr":"Sets a pixel for LED strip. Index can be a number or 'all' keyword to set all. Then, 3 integer values for R, G and B. Please note that it also works for WS2812B and similiar LEDs. See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_SetPixel", SM16703P_CMD_setPixel, NULL);
|
||||
//cmddetail:{"name":"SM16703P_SetRaw","args":"[bUpdate] [byteOfs] [HexData]",
|
||||
//cmddetail:"descr":"Sets the raw data bytes for SPI DMA LED driver at the given offset. Hex data should be as a hex string, for example, FF00AA, etc. The bUpdate, if set to 1, will run SM16703P_Start automatically after setting data. Please note that it also works for WS2812B and similiar LEDs. See [tutorial](https://www.elektroda.com/rtvforum/topic4036716.html).",
|
||||
//cmddetail:"fn":"NULL);","file":"driver/drv_sm16703P.c","requires":"",
|
||||
//cmddetail:"examples":""}
|
||||
CMD_RegisterCommand("SM16703P_SetRaw", SM16703P_CMD_setRaw, NULL);
|
||||
ledStrip_t ws_export;
|
||||
ws_export.apply = SM16703P_Show;
|
||||
ws_export.getByte = SM16703P_GetByte;
|
||||
ws_export.setByte = SM16703P_setByte;
|
||||
ws_export.setLEDCount = SM16703P_SetLEDCount;
|
||||
|
||||
//CMD_RegisterCommand("SM16703P_SendBytes", SM16703P_CMD_sendBytes, NULL);
|
||||
LEDS_InitShared(&ws_export);
|
||||
}
|
||||
|
||||
void SM16703P_Shutdown() {
|
||||
if (color_channel_order != default_color_channel_order) {
|
||||
os_free(color_channel_order);
|
||||
color_channel_order = default_color_channel_order;
|
||||
}
|
||||
LEDS_ShutdownShared();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -130,24 +130,7 @@ void SPILED_InitDMA(int numBytes) {
|
||||
|
||||
|
||||
|
||||
void SPILED_SetRawHexString(int start_offset, const char *s, int push) {
|
||||
// start offset is in bytes, and we do 2 bits per dst byte, so *4
|
||||
uint8_t *dst = spiLED.buf + spiLED.ofs + start_offset * 4;
|
||||
|
||||
// parse hex string like FFAABB0011 byte by byte
|
||||
while (s[0] && s[1]) {
|
||||
byte b;
|
||||
b = hexbyte(s);
|
||||
*dst++ = translate_2bit((b >> 6));
|
||||
*dst++ = translate_2bit((b >> 4));
|
||||
*dst++ = translate_2bit((b >> 2));
|
||||
*dst++ = translate_2bit(b);
|
||||
s += 2;
|
||||
}
|
||||
if (push) {
|
||||
SPIDMA_StartTX(spiLED.msg);
|
||||
}
|
||||
}
|
||||
void SPILED_SetRawBytes(int start_offset, byte *bytes, int numBytes, int push) {
|
||||
// start offset is in bytes, and we do 2 bits per dst byte, so *4
|
||||
uint8_t *dst = spiLED.buf + spiLED.ofs + start_offset * 4;
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
#define ENABLE_OBK_SCRIPTING 1
|
||||
#define ENABLE_OBK_BERRY 1
|
||||
#define ENABLE_DRIVER_DS1820_FULL 1
|
||||
#define ENABLE_DRIVER_DMX 1
|
||||
|
||||
#elif PLATFORM_BL602
|
||||
|
||||
|
||||
@@ -437,6 +437,35 @@ void Test_HassDiscovery_Channel_Smoke() {
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING(0, "name", "Smoke");
|
||||
}
|
||||
|
||||
void Test_HassDiscovery_Channel_Ph() {
|
||||
const char *shortName = "WinCustom";
|
||||
const char *fullName = "Windows Fake Custom";
|
||||
const char *mqttName = "testCustom";
|
||||
SIM_ClearOBK(shortName);
|
||||
SIM_ClearAndPrepareForMQTTTesting(mqttName, "bekens");
|
||||
|
||||
CFG_SetShortDeviceName(shortName);
|
||||
CFG_SetDeviceName(fullName);
|
||||
|
||||
CHANNEL_SetType(4, ChType_Ph);
|
||||
|
||||
SIM_ClearMQTTHistory();
|
||||
CMD_ExecuteCommand("scheduleHADiscovery 1", 0);
|
||||
Sim_RunSeconds(5, false);
|
||||
|
||||
// OBK device should publish JSON on MQTT topic "homeassistant"
|
||||
SELFTEST_ASSERT_HAS_MQTT_JSON_SENT("homeassistant", true);
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "name", shortName);
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "sw", USER_SW_VER);
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mf", MANUFACTURER);
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING("dev", "mdl", PLATFORM_MCU_NAME);
|
||||
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING(0, "stat_t", "~/4/get");
|
||||
// user says it should not be set
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING_NOT_PRESENT(0, "unit_of_meas");
|
||||
SELFTEST_ASSERT_JSON_VALUE_STRING(0, "dev_cla", "ph");
|
||||
}
|
||||
|
||||
void Test_HassDiscovery_Channel_Custom() {
|
||||
const char *shortName = "WinCustom";
|
||||
const char *fullName = "Windows Fake Custom";
|
||||
@@ -674,6 +703,7 @@ void Test_HassDiscovery_Ext() {
|
||||
Test_HassDiscovery_Channel_Custom();
|
||||
Test_HassDiscovery_Channel_BatteryLevelPercent();
|
||||
Test_HassDiscovery_Channel_Smoke();
|
||||
Test_HassDiscovery_Channel_Ph();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ void SelfTest_Failed(const char *file, const char *function, int line, const cha
|
||||
#define SELFTEST_ASSERT_HAS_MQTT_JSON_SENT_ANY_4KEY(topic, bPrefixMode, object1, object2, key, value, key2, value2, key3, value3, key4, value4) SELFTEST_ASSERT(SIM_HasMQTTHistoryStringWithJSONPayload(topic, bPrefixMode, object1, object2, key, value, key2, value2, key3, value3, key4, value4));
|
||||
#define SELFTEST_ASSERT_HAS_SENT_UART_STRING(str) SELFTEST_ASSERT(SIM_UART_ExpectAndConsumeHexStr(str));
|
||||
#define SELFTEST_ASSERT_HAS_UART_EMPTY() SELFTEST_ASSERT(SIM_UART_GetDataSize()==0);
|
||||
#define SELFTEST_ASSERT_HAS_SOME_DATA_IN_UART() SELFTEST_ASSERT(SIM_UART_GetDataSize()!=0);
|
||||
|
||||
//#define FLOAT_EQUALS (a,b) (fabs(a-b)<0.001f)
|
||||
float myFabs(float f);
|
||||
@@ -129,6 +130,8 @@ void Test_MQTT_Get_Relay();
|
||||
void Test_TuyaMCU_BatteryPowered();
|
||||
void Test_ChargeLimitDriver();
|
||||
void Test_WS2812B();
|
||||
void Test_LEDstrips();
|
||||
void Test_DMX();
|
||||
void Test_DoorSensor();
|
||||
void Test_Enums();
|
||||
void Test_Expressions_RunTests_Basic();
|
||||
|
||||
@@ -4,11 +4,103 @@
|
||||
|
||||
|
||||
bool SM16703P_VerifyPixel(uint32_t pixel, byte r, byte g, byte b);
|
||||
bool SM16703P_VerifyPixel4(uint32_t pixel, byte r, byte g, byte b, byte a);
|
||||
|
||||
#define SELFTEST_ASSERT_PIXEL(index, r, g, b) SELFTEST_ASSERT(SM16703P_VerifyPixel(index, r, g, b));
|
||||
#define SELFTEST_ASSERT_PIXEL4(index, r, g, b, w) SELFTEST_ASSERT(SM16703P_VerifyPixel4(index, r, g, b, w));
|
||||
|
||||
void SM16703P_setMultiplePixel(uint32_t pixel, uint8_t *data, bool push);
|
||||
|
||||
void Test_DMX_RGB() {
|
||||
// reset whole device
|
||||
SIM_ClearOBK(0);
|
||||
|
||||
SIM_UART_InitReceiveRingBuffer(4096);
|
||||
SIM_ClearUART();
|
||||
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
|
||||
CMD_ExecuteCommand("startDriver DMX", 0);
|
||||
CMD_ExecuteCommand("SM16703P_Init 3", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel all 255 0 128", 0);
|
||||
SELFTEST_ASSERT_PIXEL(0, 255, 0, 128);
|
||||
SELFTEST_ASSERT_PIXEL(1, 255, 0, 128);
|
||||
SELFTEST_ASSERT_PIXEL(2, 255, 0, 128);
|
||||
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
CMD_ExecuteCommand("SM16703P_Start", 0);
|
||||
SELFTEST_ASSERT_HAS_SOME_DATA_IN_UART();
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 FF0080 FF0080 FF0080");
|
||||
// 512 channels, but checked already 10
|
||||
for (int i = 0; i < 100; i++) {
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 00 00 00 00");
|
||||
}
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 00 00");
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 0 128 128 128", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 1 255 255 255", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 2 15 15 15", 0);
|
||||
SELFTEST_ASSERT_PIXEL(0, 128, 128, 128);
|
||||
SELFTEST_ASSERT_PIXEL(1, 255, 255, 255);
|
||||
SELFTEST_ASSERT_PIXEL(2, 15, 15, 15);
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
CMD_ExecuteCommand("SM16703P_Start", 0);
|
||||
SELFTEST_ASSERT_HAS_SOME_DATA_IN_UART();
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 808080 FFFFFF 0F0F0F");
|
||||
// 512 channels, but checked already 10
|
||||
for (int i = 0; i < 100; i++) {
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 00 00 00 00");
|
||||
}
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 00 00");
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
|
||||
// nothing is sent by OBK at that point
|
||||
}
|
||||
void Test_DMX_RGBW() {
|
||||
// reset whole device
|
||||
SIM_ClearOBK(0);
|
||||
|
||||
SIM_UART_InitReceiveRingBuffer(4096);
|
||||
SIM_ClearUART();
|
||||
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
|
||||
CMD_ExecuteCommand("startDriver DMX", 0);
|
||||
CMD_ExecuteCommand("SM16703P_Init 3 RGBC", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel all 255 0 128 255", 0);
|
||||
SELFTEST_ASSERT_PIXEL4(0, 255, 0, 128, 255);
|
||||
SELFTEST_ASSERT_PIXEL4(1, 255, 0, 128, 255);
|
||||
SELFTEST_ASSERT_PIXEL4(2, 255, 0, 128, 255);
|
||||
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
CMD_ExecuteCommand("SM16703P_Start", 0);
|
||||
SELFTEST_ASSERT_HAS_SOME_DATA_IN_UART();
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 FF0080FF FF0080FF FF0080FF");
|
||||
// 512 channels, but checked already 12
|
||||
for (int i = 0; i < 100; i++) {
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 00 00 00 00");
|
||||
}
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 0 128 128 128 128", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 1 255 255 255 255", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 2 15 15 15 15", 0);
|
||||
SELFTEST_ASSERT_PIXEL4(0, 128, 128, 128, 128);
|
||||
SELFTEST_ASSERT_PIXEL4(1, 255, 255, 255, 255);
|
||||
SELFTEST_ASSERT_PIXEL4(2, 15, 15, 15, 15);
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
CMD_ExecuteCommand("SM16703P_Start", 0);
|
||||
SELFTEST_ASSERT_HAS_SOME_DATA_IN_UART();
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 80808080 FFFFFFFF 0F0F0F0F");
|
||||
// 512 channels, but checked already 12
|
||||
for (int i = 0; i < 100; i++) {
|
||||
SELFTEST_ASSERT_HAS_SENT_UART_STRING("00 00 00 00 00");
|
||||
}
|
||||
SELFTEST_ASSERT_HAS_UART_EMPTY();
|
||||
|
||||
// nothing is sent by OBK at that point
|
||||
}
|
||||
void Test_WS2812B() {
|
||||
// reset whole device
|
||||
SIM_ClearOBK(0);
|
||||
@@ -27,6 +119,9 @@ void Test_WS2812B() {
|
||||
SELFTEST_ASSERT_PIXEL(1, 0, 0, 255);
|
||||
SELFTEST_ASSERT_PIXEL(2, 0, 0, 255);
|
||||
|
||||
// cannot crash
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 1234 255 0 0", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel -123 255 0 0", 0);
|
||||
|
||||
// fake 3 pixels data
|
||||
{ // RGB
|
||||
@@ -135,6 +230,35 @@ void Test_WS2812B() {
|
||||
SELFTEST_ASSERT_PIXEL(1, 0xFF, 0, 0);
|
||||
SELFTEST_ASSERT_PIXEL(2, 0xFF, 0, 0xFF);
|
||||
}
|
||||
// fake DDP RGBW packet
|
||||
{
|
||||
byte ddpPacket[128];
|
||||
|
||||
ddpPacket[2] = 0x1A;
|
||||
|
||||
// data starts at offset 10
|
||||
// pixel 0
|
||||
ddpPacket[10] = 0xFF;
|
||||
ddpPacket[11] = 0xFF;
|
||||
ddpPacket[12] = 0xFF;
|
||||
ddpPacket[13] = 0xFF;
|
||||
// pixel 1
|
||||
ddpPacket[14] = 0xFF;
|
||||
ddpPacket[15] = 0x0;
|
||||
ddpPacket[16] = 0x0;
|
||||
ddpPacket[17] = 0xFF;
|
||||
// pixel 2
|
||||
ddpPacket[18] = 0xFF;
|
||||
ddpPacket[19] = 0x0;
|
||||
ddpPacket[20] = 0xFF;
|
||||
ddpPacket[21] = 0xFF;
|
||||
|
||||
DDP_Parse(ddpPacket, sizeof(ddpPacket));
|
||||
|
||||
SELFTEST_ASSERT_PIXEL(0, 0xFF, 0xFF, 0xFF);
|
||||
///SELFTEST_ASSERT_PIXEL(1, 0xFF, 0, 0);
|
||||
//SELFTEST_ASSERT_PIXEL(2, 0xFF, 0, 0xFF);
|
||||
}
|
||||
|
||||
CMD_ExecuteCommand("SM16703P_Init 6 RGB", 0);
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel 0 255 0 0", 0);
|
||||
@@ -150,8 +274,38 @@ void Test_WS2812B() {
|
||||
SELFTEST_ASSERT_PIXEL(4, 0, 255, 0);
|
||||
SELFTEST_ASSERT_PIXEL(5, 0, 0, 255);
|
||||
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel all 123 231 132", 0);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
SELFTEST_ASSERT_PIXEL(i, 123, 231, 132);
|
||||
}
|
||||
|
||||
CMD_ExecuteCommand("SM16703P_SetPixel all 128 128 128", 0);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
SELFTEST_ASSERT_PIXEL(i, 128, 128, 128);
|
||||
}
|
||||
SM16703P_scaleAllPixels(128);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
SELFTEST_ASSERT_PIXEL(i, 64, 64, 64);
|
||||
}
|
||||
SM16703P_scaleAllPixels(128);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
SELFTEST_ASSERT_PIXEL(i, 32, 32, 32);
|
||||
}
|
||||
SM16703P_scaleAllPixels(64);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
SELFTEST_ASSERT_PIXEL(i, 8, 8, 8);
|
||||
}
|
||||
|
||||
CMD_ExecuteCommand("SM16703P_SetRaw 1 0 FF000000FF000000FF", 0);
|
||||
SELFTEST_ASSERT_PIXEL(0, 0xff, 0x00, 0x00);
|
||||
SELFTEST_ASSERT_PIXEL(1, 0x00, 0xff, 0x00);
|
||||
SELFTEST_ASSERT_PIXEL(2, 0x00, 0x00, 0xff);
|
||||
CMD_ExecuteCommand("SM16703P_SetRaw 1 0 AABBCC00BA00000023", 0);
|
||||
SELFTEST_ASSERT_PIXEL(0, 0xAA, 0xBB, 0xCC);
|
||||
SELFTEST_ASSERT_PIXEL(1, 0x00, 0xBA, 0x00);
|
||||
SELFTEST_ASSERT_PIXEL(2, 0x00, 0x00, 0x23);
|
||||
|
||||
|
||||
#if ENABLE_LED_BASIC
|
||||
CMD_ExecuteCommand("startDriver PixelAnim", 0);
|
||||
CMD_ExecuteCommand("led_enableAll 1", 0);
|
||||
@@ -192,5 +346,10 @@ void Test_WS2812B() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void Test_LEDstrips() {
|
||||
Test_DMX_RGB();
|
||||
Test_DMX_RGBW();
|
||||
Test_WS2812B();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,9 +22,10 @@ void SIM_ClearUART() {
|
||||
|
||||
int SIM_UART_GetDataSize()
|
||||
{
|
||||
return (g_recvBufIn >= g_recvBufOut
|
||||
int ret = (g_recvBufIn >= g_recvBufOut
|
||||
? g_recvBufIn - g_recvBufOut
|
||||
: g_recvBufIn + (g_recvBufSize - g_recvBufOut) + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
byte SIM_UART_GetByte(int idx) {
|
||||
|
||||
@@ -183,7 +183,7 @@ void Win_DoUnitTests() {
|
||||
//Test_Enums();
|
||||
Test_Backlog();
|
||||
Test_DoorSensor();
|
||||
Test_WS2812B();
|
||||
Test_LEDstrips();
|
||||
Test_Command_If_Else();
|
||||
Test_MQTT();
|
||||
Test_ChargeLimitDriver();
|
||||
|
||||
Reference in New Issue
Block a user