prelimary support for DDP sending - not tested outside simulator

* ddp send stub etc

* queue

* Update drv_ddp_send.c

* sender

* Update drv_ddp_send.c

* q

* enable

* fx

* test

* fx

* Update selftest_ws2812b.c

* Update drv_ddpSend.c

* Update drv_ddpSend.c

* hder

* test - will udp send adn receive work on github workflw?

* better wait method for self test
This commit is contained in:
openshwprojects
2025-08-29 20:18:31 +02:00
committed by GitHub
parent 4d677604dc
commit 6ea915a574
9 changed files with 300 additions and 9 deletions

View File

@ -214,6 +214,7 @@
<ClCompile Include="src\driver\drv_cse7761.c" />
<ClCompile Include="src\driver\drv_cse7766.c" />
<ClCompile Include="src\driver\drv_ddp.c" />
<ClCompile Include="src\driver\drv_ddpSend.c" />
<ClCompile Include="src\driver\drv_debouncer.c" />
<ClCompile Include="src\driver\drv_dht.c" />
<ClCompile Include="src\driver\drv_dht_internal.c" />

View File

@ -410,6 +410,7 @@
<ClCompile Include="src\driver\drv_tca9554.c" />
<ClCompile Include="src\driver\drv_leds_shared.c" />
<ClCompile Include="src\driver\drv_dmx512.c" />
<ClCompile Include="src\driver\drv_ddpSend.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\base64\base64.h" />

View File

@ -21,8 +21,8 @@ static const char* group = "239.255.250.250";
static int port = 4048;
static int g_ddp_socket_receive = -1;
static int g_retry_delay = 5;
static int stat_packetsReceived = 0;
static int stat_bytesReceived = 0;
int stat_ddpPacketsReceived = 0;
static int stat_ddpBytesReceived = 0;
static char *g_ddp_buffer = 0;
static int g_ddp_bufferSize = 512;
@ -184,12 +184,12 @@ void DRV_DDP_RunFrame() {
}
//addLogAdv(LOG_INFO, LOG_FEATURE_DDP,"Received %i bytes from %s\n",nbytes,inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr));
stat_packetsReceived++;
stat_bytesReceived += nbytes;
stat_ddpPacketsReceived++;
stat_ddpBytesReceived += nbytes;
DDP_Parse((byte*)g_ddp_buffer, nbytes);
if (stat_packetsReceived % 10 == 0) {
if (stat_ddpPacketsReceived % 10 == 0) {
rtos_delay_milliseconds(5);
}
}
@ -203,7 +203,7 @@ void DRV_DDP_Shutdown()
}
void DRV_DDP_AppendInformationToHTTPIndexPage(http_request_t* request)
{
hprintf255(request, "<h2>DDP received: %i packets, %i bytes</h2>", stat_packetsReceived, stat_bytesReceived);
hprintf255(request, "<h2>DDP received: %i packets, %i bytes</h2>", stat_ddpPacketsReceived, stat_ddpBytesReceived);
}
void DRV_DDP_Init()
{

197
src/driver/drv_ddpSend.c Normal file
View File

@ -0,0 +1,197 @@
#include "../new_common.h"
#include "../new_pins.h"
#include "../new_cfg.h"
// Commands register, execution API and cmd tokenizer
#include "../cmnds/cmd_public.h"
#include "../driver/drv_public.h"
#include "../logging/logging.h"
#include "lwip/sockets.h"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "../httpserver/new_http.h"
#include "drv_local.h"
#include "../quicktick.h"
static int g_socket_ddpSend = -1;
static int stat_sendBytes = 0;
static int stat_sendPackets = 0;
static int stat_failedPackets = 0;
typedef struct ddpQueueItem_s {
int curSize;
int totalSize;
byte *data;
int delay;
struct sockaddr_in adr;
struct ddpQueueItem_s *next;
} ddpQueueItem_t;
ddpQueueItem_t *g_queue = 0;
int DRV_DDPSend_SendInternal(struct sockaddr_in *adr, const byte *frame, int numBytes) {
int nbytes = sendto(
g_socket_ddpSend,
(const char*)frame,
numBytes,
0,
(struct sockaddr*) adr,
sizeof(*adr)
);
if (nbytes == numBytes) {
stat_sendBytes += numBytes;
stat_sendPackets++;
return numBytes;
}
stat_failedPackets++;
return 0;
}
void DRV_DDPSend_Send(const char *ip, int port, const byte *frame, int numBytes, int delay) {
struct sockaddr_in adr;
memset(&adr, 0, sizeof(adr));
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = inet_addr(ip);
adr.sin_port = htons(port);
if (delay <= 0) {
DRV_DDPSend_SendInternal(&adr, frame, numBytes);
return;
}
ddpQueueItem_t *it = g_queue;
while (it) {
if (it->curSize == 0) {
break; // found empty
}
it = it->next;
}
if (it == 0) {
it = (ddpQueueItem_t*)malloc(sizeof(ddpQueueItem_t));
if (it == 0) {
// malloc failed
return;
}
memset(it,0,sizeof(ddpQueueItem_t));
it->adr = adr;
it->totalSize = it->curSize = numBytes;
it->data = malloc(numBytes);
if (it->data == 0) {
// malloc failed
free(it);
return;
}
it->next = g_queue;
g_queue = it;
}
if (it->totalSize < numBytes) {
byte *r = (byte*)realloc(it->data, numBytes);
if (r == 0) {
// realloc failed
return;
}
it->data = r;
it->totalSize = numBytes;
}
it->delay = delay;
memcpy(it->data, frame, numBytes);
it->curSize = numBytes;
}
void DRV_DDPSend_RunFrame() {
ddpQueueItem_t *t;
t = g_queue;
while (t) {
if (t->curSize > 0) {
t->delay -= g_deltaTimeMS;
if (t->delay <= 0) {
int sendBytes = DRV_DDPSend_SendInternal(&t->adr, t->data, t->curSize);
// TODO - do not clear if didn't send?
t->curSize = 0; // mark as empty
}
}
t = t->next;
}
}
void DRV_DDPSend_Shutdown()
{
if (g_socket_ddpSend >= 0) {
close(g_socket_ddpSend);
g_socket_ddpSend = -1;
}
ddpQueueItem_t *it = g_queue;
while (it) {
ddpQueueItem_t *n = it->next;
free(it->data);
free(it);
it = n;
}
g_queue = 0;
}
void DRV_DDPSend_AppendInformationToHTTPIndexPage(http_request_t* request)
{
hprintf255(request, "<h2>DDP sent: %i packets, %i bytes, errored packets: %i</h2>",
stat_sendPackets, stat_sendBytes, stat_failedPackets);
}
// ddp as in WLED
#define DDP_TYPE_RGB24 0x0B // 00 001 011 (RGB , 8 bits per channel, 3 channels)
#define DDP_TYPE_RGBW32 0x1B // 00 011 011 (RGBW, 8 bits per channel, 4 channels)
#define DDP_FLAGS1_VER1 0x40 // version=1
// https://github.com/wled/WLED/blob/main/wled00/udp.cpp
void DDP_SetHeader(byte *data, int pixelSize, int bytesCount) {
// set ident
data[0] = DDP_FLAGS1_VER1;
// set pixel size
if (pixelSize == 4) {
data[2] = DDP_TYPE_RGBW32;
}
else if (pixelSize == 3) {
data[2] = DDP_TYPE_RGB24;
}
// set bytes count
data[8] = (byte)((bytesCount >> 8) & 0xFF); // MSB
data[9] = (byte)(bytesCount & 0xFF); // LSB
}
commandResult_t DDP_Send(const void* context, const char* cmd, const char* args, int cmdFlags) {
Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES | TOKENIZER_DONT_EXPAND);
if (Tokenizer_GetArgsCount() < 1) {
return CMD_RES_NOT_ENOUGH_ARGUMENTS;
}
const char *ip = Tokenizer_GetArg(0);
int host = Tokenizer_GetArgInteger(1);
int pixelSize = Tokenizer_GetArgInteger(2);
int delay = Tokenizer_GetArgInteger(3);
const char *pData = Tokenizer_GetArg(4);
int numBytes = strlen(pData) / 2;
int headerSize = 10;
byte *data = malloc(headerSize+numBytes);
int cur = headerSize;
while (*pData) {
data[cur] = CMD_ParseOrExpandHexByte(&pData);
cur++;
}
DDP_SetHeader(data, pixelSize, (cur- headerSize));
DRV_DDPSend_Send(ip, host, data, cur, delay);
free(data);
return CMD_RES_OK;
}
void DRV_DDPSend_Init()
{
// create what looks like an ordinary UDP socket
//
g_socket_ddpSend = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (g_socket_ddpSend < 0) {
g_socket_ddpSend = -1;
addLogAdv(LOG_ERROR, LOG_FEATURE_HTTP, "DRV_DDPSend_Init: failed to do socket\n");
return;
}
CMD_RegisterCommand("DDP_Send", DDP_Send, NULL);
}

View File

@ -224,6 +224,12 @@ void TCL_UART_RunEverySecond(void);
void TCL_AppendInformationToHTTPIndexPage(http_request_t *request, int bPreState);
void TCL_DoDiscovery(const char *topic);
void DRV_DDPSend_Init();
void DRV_DDPSend_Shutdown();
void DRV_DDPSend_RunFrame();
void DRV_DDPSend_AppendInformationToHTTPIndexPage(http_request_t* request);
#define SM2135_DELAY 4
// Software I2C

View File

@ -315,7 +315,14 @@ static driver_t g_drivers[] = {
#if ENABLE_DRIVER_IR2
{ "IR2", DRV_IR2_Init, NULL, NULL, NULL, NULL, NULL, NULL, false },
#endif
#if ENABLE_DRIVER_DDPSEND
//drvdetail:{"name":"DDPSend",
//drvdetail:"title":"TODO",
//drvdetail:"descr":"DDPqqqqqqq. See [DDP topic](https://www.elektroda.com/rtvforum/topic4040325.html)",
//drvdetail:"requires":""}
{ "DDPSend", DRV_DDPSend_Init, NULL, DRV_DDPSend_AppendInformationToHTTPIndexPage, DRV_DDPSend_RunFrame, DRV_DDPSend_Shutdown, NULL, NULL, false },
#endif
#if ENABLE_DRIVER_DDP
//drvdetail:{"name":"DDP",
//drvdetail:"title":"TODO",

View File

@ -273,7 +273,6 @@ This platform is not supported, error!
#include <limits.h>
#define closesocket close
#define SOCKET int
#define closesocket close
#define ISVALIDSOCKET(s) ((s) >= 0)
#define GETSOCKETERRNO() (errno)
#define ioctlsocket ioctl
@ -286,6 +285,7 @@ This platform is not supported, error!
#else
#define close closesocket
#define ISVALIDSOCKET(s) ((s) != INVALID_SOCKET)
#define GETSOCKETERRNO() (WSAGetLastError())

View File

@ -163,6 +163,7 @@
#define ENABLE_DRIVER_DRAWERS 1
#define ENABLE_TASMOTA_JSON 1
#define ENABLE_DRIVER_DDP 1
#define ENABLE_DRIVER_DDPSEND 1
#define ENABLE_DRIVER_SSDP 1
#define ENABLE_DRIVER_ADCBUTTON 1
#define ENABLE_DRIVER_SM15155E 1

View File

@ -57,7 +57,7 @@ void Test_DMX_RGB() {
// nothing is sent by OBK at that point
}
void Test_DMX_RGBW() {
void Test_DMX_RGBC() {
// reset whole device
SIM_ClearOBK(0);
@ -101,6 +101,62 @@ void Test_DMX_RGBW() {
// 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 RGBW", 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
}
extern int stat_ddpPacketsReceived;
void SIM_WaitForDDPPacket() {
int prev = stat_ddpPacketsReceived;
for (int i = 0; i < 100; i++) {
Sim_RunFrames(1, true);
if (stat_ddpPacketsReceived > prev) {
break; // got it
}
}
}
void Test_WS2812B() {
// reset whole device
SIM_ClearOBK(0);
@ -230,6 +286,27 @@ void Test_WS2812B() {
SELFTEST_ASSERT_PIXEL(1, 0xFF, 0, 0);
SELFTEST_ASSERT_PIXEL(2, 0xFF, 0, 0xFF);
}
CMD_ExecuteCommand("startDriver DDP", 0);
CMD_ExecuteCommand("startDriver DDPSend", 0);
CMD_ExecuteCommand("DDP_Send 127.0.0.1 4048 3 0 FF00AB", 0);
SIM_WaitForDDPPacket();
// this requires udp to work so it can pass...
if (1) {
SELFTEST_ASSERT_PIXEL(0, 0xFF, 0x00, 0xAB);
}
CMD_ExecuteCommand("DDP_Send 127.0.0.1 4048 3 0 ABCDEF", 0);
SIM_WaitForDDPPacket();
if (1) {
SELFTEST_ASSERT_PIXEL(0, 0xAB, 0xCD, 0xEF);
}
CMD_ExecuteCommand("DDP_Send 127.0.0.1 4048 3 0 ABCDEFAABBCC", 0);
SIM_WaitForDDPPacket();
if (1) {
SELFTEST_ASSERT_PIXEL(0, 0xAB, 0xCD, 0xEF);
SELFTEST_ASSERT_PIXEL(1, 0xAA, 0xBB, 0xCC);
}
// fake DDP RGBW packet
{
byte ddpPacket[128];
@ -348,6 +425,7 @@ void Test_WS2812B() {
void Test_LEDstrips() {
Test_DMX_RGB();
Test_DMX_RGBC();
Test_DMX_RGBW();
Test_WS2812B();
}