Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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 wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
#define REALTIME_MODE_ARTNET 6
#define REALTIME_MODE_TPM2NET 7
#define REALTIME_MODE_DDP 8
#define REALTIME_MODE_OPC 9

//realtime override modes
#define REALTIME_OVERRIDE_NONE 0
Expand Down
10 changes: 10 additions & 0 deletions wled00/fcn_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ void setCronixie();
void _overlayCronixie();
void _drawOverlayCronixie();

//opc.cpp
void initOPCServer();
void freeOPCClient(AsyncClient* client);
void handleOPCClient(void* arg, AsyncClient* client);
void handleOPCData(void* arg, AsyncClient* client, void *data, size_t len);
void handleOPCTimeOut(void* arg, AsyncClient* client, uint32_t time);
void handleOPCError(void* arg, AsyncClient* client, int8_t error);
void handleOPCDisconnect(void* arg, AsyncClient* client);
void handleOPCPacket();
Comment on lines +190 to +198
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Function declarations lack #ifdef WLED_ENABLE_OPC guard, and stub signatures mismatch.

The OPC function declarations here have full signatures (e.g., void handleOPCClient(void* arg, AsyncClient* client)), but the stubs in opc.cpp (lines 137-142) have empty parameter lists (e.g., void handleOPCClient() {}). This will cause linker errors when WLED_ENABLE_OPC is not defined.

Proposed fix: wrap declarations in ifdef and fix stub signatures

In fcn_declare.h:

 //opc.cpp
+#ifdef WLED_ENABLE_OPC
 void initOPCServer();
 void freeOPCClient(AsyncClient* client);
 void handleOPCClient(void* arg, AsyncClient* client);
 void handleOPCData(void* arg, AsyncClient* client, void *data, size_t len);
 void handleOPCTimeOut(void* arg, AsyncClient* client, uint32_t time);
 void handleOPCError(void* arg, AsyncClient* client, int8_t error);
 void handleOPCDisconnect(void* arg, AsyncClient* client);
-void handleOPCPacket();
+#endif
+void handleOPCPacket();  // Always declared, has stub when OPC disabled

In opc.cpp, fix stubs:

 `#else`
 void initOPCServer(){}
-void handleOPCClient() {}
-void freeOPCClient(){}
-void handleOPCData() {}
-void handleOPCTimeOut (){}
-void handleOPCError (){}
-void handleOPCDisconnect (){}
+void handleOPCPacket(){}
 `#endif`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/fcn_declare.h` around lines 190 - 198, The OPC-related function
declarations (initOPCServer, freeOPCClient, handleOPCClient, handleOPCData,
handleOPCTimeOut, handleOPCError, handleOPCDisconnect, handleOPCPacket) must be
wrapped with `#ifdef` WLED_ENABLE_OPC ... `#endif` in fcn_declare.h so they are only
declared when OPC is enabled, and the stub implementations in opc.cpp must have
matching signatures (e.g., change empty-parameter stubs like void
handleOPCClient() {} to void handleOPCClient(void* arg, AsyncClient* client) {}
and similarly for handleOPCData, handleOPCTimeOut, handleOPCError,
handleOPCDisconnect) so the declarations and definitions match and avoid linker
errors when WLED_ENABLE_OPC is not defined.


//playlist.cpp
void shufflePlaylist();
void unloadPlaylist();
Expand Down
1 change: 1 addition & 0 deletions wled00/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ void serializeInfo(JsonObject root)
case REALTIME_MODE_ARTNET: root["lm"] = F("Art-Net"); break;
case REALTIME_MODE_TPM2NET: root["lm"] = F("tpm2.net"); break;
case REALTIME_MODE_DDP: root["lm"] = F("DDP"); break;
case REALTIME_MODE_OPC: root["lm"] = F("Open Pixel Control"); break;
}

if (realtimeIP[0] == 0)
Expand Down
143 changes: 143 additions & 0 deletions wled00/opc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
OPC Protocol support
*/

#include "wled.h"
#include "cbuf.h"

#ifdef WLED_ENABLE_OPC

#define OPC_SERVER_PORT 7890
#define OPC_LISTEN_CHANNEL 1
#define OPC_MAX_FRAME_STORAGE 30
#define OPC_HEADER_SIZE 4

void freeOPCClient(AsyncClient* client) {
client->close(true);
delete clientServed;
clientServed = nullptr;
}
Comment on lines +15 to +19
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical bug: freeOPCClient deletes wrong pointer.

The function receives client as a parameter but deletes clientServed (the global). This causes undefined behavior when client != clientServed. The function should consistently operate on either the parameter or the global, not mix them.

Proposed fix
 void freeOPCClient(AsyncClient* client) {
-  client->close(true);
-  delete clientServed;
+  if (client == nullptr) return;
+  client->close(true);
+  client->free();
+  delete client;
+  if (client == clientServed) clientServed = nullptr;
-  clientServed = nullptr;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/opc.cpp` around lines 15 - 19, freeOPCClient deletes the global
clientServed instead of the passed-in AsyncClient* client causing undefined
behavior; change the function to consistently operate on the passed parameter by
calling client->close(true), deleting client, and only nulling clientServed if
the pointer being deleted equals clientServed (i.e., if (clientServed == client)
clientServed = nullptr), or alternatively make the function operate only on the
global by removing the parameter and using clientServed throughout — update
freeOPCClient, its signature/usages, and any callers to match the chosen
consistent approach.


void handleOPCError(void* arg, AsyncClient* client, int8_t error) {
freeOPCClient(client);
}

void handleOPCDisconnect(void* arg, AsyncClient* client) {
freeOPCClient(client);
}

void handleOPCTimeOut(void* arg, AsyncClient* client, uint32_t time) {
freeOPCClient(client);
}

void handleOPCData(void* arg, AsyncClient* client, void *data, size_t len) {
if (len > opcCircularBufPtr->room()) return;
for (unsigned int i = 0; i < len; i++) {
opcCircularBufPtr->write(*((uint8_t*)data + i));
}
}
Comment on lines +33 to +38
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing null check on opcCircularBufPtr — potential crash.

handleOPCData is registered as a callback and can be invoked asynchronously. If data arrives before opcCircularBufPtr is fully initialized (or after it's been deleted during re-initialization), dereferencing it will crash. Based on learnings, UDP/TCP packet processing must validate state before accessing buffers.

Proposed fix
 void handleOPCData(void* arg, AsyncClient* client, void *data, size_t len) {
+  if (opcCircularBufPtr == nullptr) return;
   if (len > opcCircularBufPtr->room()) return;
   for (unsigned int i = 0; i < len; i++) { 
     opcCircularBufPtr->write(*((uint8_t*)data + i));
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/opc.cpp` around lines 33 - 38, handleOPCData currently dereferences
opcCircularBufPtr without verifying it is valid; add a null check at the top of
handleOPCData to return immediately if opcCircularBufPtr is nullptr (or
otherwise not initialized) before calling opcCircularBufPtr->room() or
->write(), so the callback cannot crash if invoked before initialization or
after teardown; ensure the early return covers both the room() size check and
the write loop to avoid any race where opcCircularBufPtr becomes null between
checks.


void handleOPCClient(void* arg, AsyncClient* client) {
//add client
if (clientServed != nullptr) freeOPCClient(client);
clientServed = client;

//clean and initialize buffer
opcDataLen = 0;
opcCircularBufPtr->flush();
opcParserWaitingForData = false;

// register client events
client->onData(&handleOPCData, NULL);
client->onError(&handleOPCError, NULL);
client->onDisconnect(&handleOPCDisconnect, NULL);
client->onTimeout(&handleOPCTimeOut, NULL);
}
Comment on lines +40 to +55
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical bug: frees wrong client when rejecting new connection.

Line 42 calls freeOPCClient(client) when clientServed != nullptr, intending to reject the new client. However, combined with the bug in freeOPCClient, this closes the new client but deletes the old clientServed pointer — leaving memory corruption and the new (closed) client assigned to clientServed on line 43.

Additionally, line 47 calls opcCircularBufPtr->flush() without a null check, which can crash if opcCircularBufPtr hasn't been initialized yet.

Proposed fix for client handling
 void handleOPCClient(void* arg, AsyncClient* client) {
-  //add client
-  if (clientServed != nullptr) freeOPCClient(client);
-	clientServed = client;
+  // Reject new client if one is already being served
+  if (clientServed != nullptr) {
+    client->close(true);
+    delete client;
+    return;
+  }
+  clientServed = client;
 
-  //clean and initialize buffer
+  // Clean and initialize buffer
   opcDataLen = 0;
-  opcCircularBufPtr->flush();
+  if (opcCircularBufPtr != nullptr) opcCircularBufPtr->flush();
   opcParserWaitingForData = false;
-	
-	// register client events
-	client->onData(&handleOPCData, NULL);
-	client->onError(&handleOPCError, NULL);
-	client->onDisconnect(&handleOPCDisconnect, NULL);
-	client->onTimeout(&handleOPCTimeOut, NULL);
+
+  // Register client events
+  client->onData(&handleOPCData, NULL);
+  client->onError(&handleOPCError, NULL);
+  client->onDisconnect(&handleOPCDisconnect, NULL);
+  client->onTimeout(&handleOPCTimeOut, NULL);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/opc.cpp` around lines 40 - 55, In handleOPCClient: do not call
freeOPCClient(client) when clientServed != nullptr — that closes the new client
and corrupts the served pointer; instead immediately reject the incoming
connection by closing/stopping the incoming AsyncClient (e.g.,
client->close(true) or client->stop()) and return without changing clientServed;
only assign clientServed = client and initialize state (opcDataLen,
opcParserWaitingForData) and register callbacks when accepting a client; also
guard the buffer flush call with a null check (if (opcCircularBufPtr)
opcCircularBufPtr->flush()) so opcCircularBufPtr->flush() cannot crash when
uninitialized.


void discardInvalidData(uint16_t len) {
if (len > opcCircularBufPtr->available()) {
opcCircularBufPtr->flush();
} else {
for (uint16_t i = 0; i < len; i++) opcCircularBufPtr->read();
}
}

void parseOPCLedValues(uint8_t chan, uint8_t cmd) {
const uint16_t opcDataLenDiv = opcDataLen / 3;
uint8_t r, g, b;
if ((chan == 0 || chan == OPC_LISTEN_CHANNEL) && cmd == 0) {
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_OPC);

for (uint16_t i = 0; i < opcDataLenDiv && i < ledCount; i++) {
r = opcCircularBufPtr->read();
g = opcCircularBufPtr->read();
b = opcCircularBufPtr->read();
setRealtimePixel(i, r, g, b, 0);

}
strip.show();
if (opcDataLen > ledCount * 3) discardInvalidData(opcDataLen - ledCount * 3);
} else {
discardInvalidData(opcDataLen);
}
}
Comment on lines +65 to +83
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify ledCount is defined as a global/accessible variable
rg -n '\bledCount\b' --type=cpp --type-add 'cpp:*.h' -g '!opc.cpp' | head -30

Repository: wled/WLED

Length of output: 595


🏁 Script executed:

#!/bin/bash
# Search for ledCount declaration (extern, variable definition)
rg -n 'extern.*ledCount|^\s*uint.*ledCount|^uint.*ledCount' --type=cpp --type-add 'cpp:*.h'

Repository: wled/WLED

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Check includes in opc.cpp
head -30 wled00/opc.cpp | grep -E '^\s*#include'

Repository: wled/WLED

Length of output: 88


🏁 Script executed:

#!/bin/bash
# Search for ledCount in FX.h
rg -n 'ledCount' wled00/FX.h | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Search for ledCount in wled.h
rg -n 'ledCount' wled00/wled.h

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Search for all ledCount declarations/definitions (excluding comments)
rg -n '^\s*(extern\s+)?(uint\d+_t|uint|int)\s+ledCount' --type=cpp --type-add 'cpp:*.h'

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Search for ledCount usage pattern - what does the strip object have?
rg -n 'strip\.getLedCount|ledCount\s*=' wled00/ --type=cpp --type-add 'cpp:*.h' | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Search for how LED count is accessed in the codebase
rg -n 'strip\.(ledCount|getLedCount|length|maxLeds)' wled00/ --type=cpp -A 1 | head -30

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check for any variable that might store LED count
rg -n '\blenstrip\b|\bstrip_len\b|\blastLed\b' wled00/ --type=cpp | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Look at actual opc.cpp full context around line 65-83
sed -n '60,90p' wled00/opc.cpp

Repository: wled/WLED

Length of output: 1058


🏁 Script executed:

#!/bin/bash
# Search for ledCount as macro or in any context
rg -n 'ledCount' wled00/ --type=cpp --type-add 'cpp:*.h' -i

Repository: wled/WLED

Length of output: 885


🏁 Script executed:

#!/bin/bash
# Check how other protocol handlers (like e131, mqtt, etc.) access LED count
rg -n 'for.*<.*ledCount|for.*<.*strip\.|setRealtimePixel' wled00/e131.cpp wled00/mqtt.cpp 2>/dev/null | head -20

Repository: wled/WLED

Length of output: 708


🏁 Script executed:

#!/bin/bash
# Search for LED count access in FX_fcn.cpp (where setRealtimePixel is likely defined)
rg -n 'setRealtimePixel|ledCount|SEGLEN' wled00/FX_fcn.cpp | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Search the entire opc.cpp for ledCount declaration
cat wled00/opc.cpp | head -70 | tail -40

Repository: wled/WLED

Length of output: 1202


🏁 Script executed:

#!/bin/bash
# Look for what strip object provides for LED access
rg -n 'strip\.' wled00/opc.cpp -o | sort -u

Repository: wled/WLED

Length of output: 72


🏁 Script executed:

#!/bin/bash
# Check what type of LED count the strip object has
rg -n 'class.*WS2812FX|uint.*_ledcount|_leds' wled00/FX.h | head -10

Repository: wled/WLED

Length of output: 86


🏁 Script executed:

#!/bin/bash
# Get the full beginning of opc.cpp to see all globals
head -150 wled00/opc.cpp

Repository: wled/WLED

Length of output: 4018


🏁 Script executed:

#!/bin/bash
# Check WS2812FX class members around ledcount
rg -n '_leds|_ledcount|ledcount|getLedCount|length' wled00/FX.h -A 1 -B 1 | head -40

Repository: wled/WLED

Length of output: 1666


🏁 Script executed:

#!/bin/bash
# Look for how many LEDs are stored - check strip initialization
rg -n 'WS2812FX.*strip|new WS2812FX' wled00/ --type=cpp -A 2 | head -20

Repository: wled/WLED

Length of output: 331


🏁 Script executed:

#!/bin/bash
# Search for ledCount extern or global declaration in header files
rg -n 'extern.*ledCount|WLED_GLOBAL.*ledCount' wled00/ --type=cpp --type-add 'cpp:*.h'

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check if ledCount might be in a previous version or another branch
# Let's look for what globals are defined in wled.h that relate to LED count
rg -n 'WLED_GLOBAL.*uint.*LED|WLED_GLOBAL.*ledCount' wled00/wled.h

Repository: wled/WLED

Length of output: 308


🏁 Script executed:

#!/bin/bash
# Verify getLengthTotal() works and is how other code accesses LED count
rg -n 'getLengthTotal\|_length' wled00/ --type=cpp | grep -v 'MIN_SHOW_DELAY\|groupLength' | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Search for any declaration of ledCount as a variable (not in comments)
rg -n '(uint\d+_t|uint|int)\s+ledCount\s*[;=]' wled00/ --type=cpp --type-add 'cpp:*.h'

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check if ledCount might be a macro
rg -n '#define ledCount' wled00/ --type=cpp --type-add 'cpp:*.h'

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Look at the entire wled.h for global declarations
grep -n 'ledCount\|_length' wled00/wled.h | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check if ledCount is perhaps defined conditionally or in another included file
rg -n 'ledCount' wled00/ --type=cpp -B 2 -A 2 | grep -E '^\s*(extern|static|const|uint)' | head -20

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Do a comprehensive search - ledCount must be used somewhere or code won't compile
# Let's check if it's perhaps a very recent addition or if code is broken
git log --oneline -20 wled00/opc.cpp 2>/dev/null || echo "Git not available"

Repository: wled/WLED

Length of output: 93


🏁 Script executed:

#!/bin/bash
# Check what the correct method should be - strip has getLengthTotal()
# Let's see if other realtime handlers use it
rg -n 'realtimeTimeoutMs|setRealtimePixel|getLengthTotal' wled00/mqtt.cpp wled00/ws.cpp 2>/dev/null | head -30

Repository: wled/WLED

Length of output: 112


🏁 Script executed:

#!/bin/bash
# Final check: look at compilation context - search for any conditional defines
# that might create ledCount
rg -n 'ledCount' wled00/ -B 5 -A 1 | head -50

Repository: wled/WLED

Length of output: 2957


🏁 Script executed:

#!/bin/bash
# Check if there's a forward declaration or extern in any header included by opc.cpp
rg -n 'extern.*ledCount' wled00/fcn_declare.h wled00/wled.h wled00/FX.h 2>/dev/null || echo "No extern ledCount found"

Repository: wled/WLED

Length of output: 77


🏁 Script executed:

#!/bin/bash
# Final verification: check the actual current state of the OPC branch
# Look for any variable or macro that might shadow ledCount
rg -n '\bledCount\b' wled00/opc.cpp -B 10 | head -40

Repository: wled/WLED

Length of output: 1130


🏁 Script executed:

#!/bin/bash
# Verify ws.cpp approach works - confirm getLengthTotal() is the right method
rg -n 'class WS2812FX' wled00/FX.h -A 150 | grep -E 'getLengthTotal|getLength' | head -5

Repository: wled/WLED

Length of output: 87


🏁 Script executed:

#!/bin/bash
# One final check - search entire repository for any ledCount declaration or definition
find wled00 -name "*.h" -o -name "*.cpp" | xargs grep -l 'ledCount' | xargs grep -n '^[^/]*\(extern\|static\|uint\|int\).*ledCount'

Repository: wled/WLED

Length of output: 253


🏁 Script executed:

#!/bin/bash
# Verify the exact error - see if ledCount could possibly be defined anywhere
rg -n 'ledCount\s*=' wled00/ --type=cpp --type-add 'cpp:*.h' -B 2

Repository: wled/WLED

Length of output: 35


🏁 Script executed:

#!/bin/bash
# Check if there's a using statement or alias
rg -n 'using.*ledCount|#define.*ledCount' wled00/ --type=cpp --type-add 'cpp:*.h'

Repository: wled/WLED

Length of output: 479


Replace undeclared ledCount with strip.getLengthTotal().

ledCount is not declared anywhere in the codebase and will cause a compilation error. The WLED codebase uses strip.getLengthTotal() to access LED count (as seen in ws.cpp). Replace all three occurrences (lines 71, 79, and 125) with strip.getLengthTotal().

Additionally, verify that discardInvalidData() handles the case where opcDataLen - ledCount * 3 might exceed available buffer bytes—the function already includes this check, but ensure it's correct when opcDataLen is corrupted or malformed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/opc.cpp` around lines 65 - 83, In parseOPCLedValues, replace the
undeclared variable ledCount with strip.getLengthTotal() in all uses (the loop
bound, the later comparison for discardInvalidData, and any other occurrence) so
the code compiles; keep the logic using opcDataLen/opcDataLenDiv,
opcCircularBufPtr->read(), setRealtimePixel(...), realtimeLock(...,
REALTIME_MODE_OPC) and strip.show() unchanged. After the replacement, ensure the
call to discardInvalidData(opcDataLen - strip.getLengthTotal() * 3) is safe by
confirming discardInvalidData correctly bounds/checks large or negative lengths
when opcDataLen is corrupted or malformed.


void handleOPCPacket() {
// channel and command variables need staticity because of fragmented packet possibility
static uint8_t chan, cmd;

if (opcCircularBufPtr != nullptr && millis() - strip.getLastShow() > 15) {
if (opcCircularBufPtr->available() >= 4 && !realtimeOverride) {
//there's at least a header and no override
if(!opcParserWaitingForData) {
chan = (uint8_t)opcCircularBufPtr->read();
cmd = (uint8_t)opcCircularBufPtr->read();
opcDataLen = (uint8_t)opcCircularBufPtr->read() << 8 | (uint8_t)opcCircularBufPtr->read();
if (opcDataLen > opcCircularBufPtr->available()) {
opcParserWaitingForData = true;
} else {
parseOPCLedValues(chan, cmd);
}
} else {
if (opcDataLen <= opcCircularBufPtr->available()) {
parseOPCLedValues(chan, cmd);
opcParserWaitingForData = false;
}
}
} else if (realtimeOverride && opcCircularBufPtr->available()) {
opcCircularBufPtr->flush();
opcParserWaitingForData = false;
}
}
}

void initOPCServer() {
if (opcServer != nullptr) {
opcServer->end();
delete opcServer;
opcServer = nullptr;
}
if (opcCircularBufPtr != nullptr) {
opcCircularBufPtr->flush();
delete opcCircularBufPtr;
opcCircularBufPtr = nullptr;
}
opcCircularBufPtr = new cbuf(OPC_MAX_FRAME_STORAGE * (ledCount + OPC_HEADER_SIZE));
opcServer = new AsyncServer(OPC_SERVER_PORT);
opcServer->onClient(&handleOPCClient, opcServer);
opcServer->setNoDelay(true);
opcServer->begin();

opcDataLen = 0;
opcParserWaitingForData = false;
}

#else
void initOPCServer(){}
void handleOPCClient() {}
void freeOPCClient(){}
void handleOPCData() {}
void handleOPCTimeOut (){}
void handleOPCError (){}
void handleOPCDisconnect (){}
#endif
6 changes: 6 additions & 0 deletions wled00/wled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ void WLED::loop()
handleIR();
handleAlexa();

#ifdef WLED_ENABLE_OPC
handleOPCPacket();
#endif
yield();

if (doReboot)
Expand Down Expand Up @@ -608,6 +611,9 @@ void WLED::initInterfaces()
e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT);
reconnectHue();
initMqtt();
#ifdef WLED_ENABLE_OPC
initOPCServer();
#endif
interfacesInited = true;
wasConnected = true;
}
Expand Down
9 changes: 9 additions & 0 deletions wled00/wled.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#ifndef WLED_DISABLE_WEBSOCKETS
#define WLED_ENABLE_WEBSOCKETS
#endif
#define WLED_ENABLE_OPC
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add #ifndef WLED_DISABLE_OPC to allow complation without OPC. Similar as a line above.


#define WLED_ENABLE_FS_EDITOR // enable /edit page for editing FS content. Will also be disabled with OTA lock

Expand Down Expand Up @@ -400,6 +401,14 @@ WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use i
WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start
#endif

#ifdef WLED_ENABLE_OPC //opc test support
WLED_GLOBAL AsyncClient* clientServed _INIT(nullptr);
WLED_GLOBAL AsyncServer* opcServer _INIT(nullptr);
WLED_GLOBAL uint16_t opcDataLen _INIT(0);
WLED_GLOBAL cbuf* opcCircularBufPtr _INIT(nullptr);
WLED_GLOBAL bool opcParserWaitingForData _INIT(false);
#endif

// internal global variable declarations
// wifi
WLED_GLOBAL bool apActive _INIT(false);
Expand Down