Circumvent problems with UDP fragmentation

The ESP’s IP stack seems not to support UDP packet fragmentation and
drops such packets silently which is problematic for setups with many
LEDs and huge updates.

With this patch, the UDP server processes up to 3 full UDP packets per
frame, allowing much larger updates. Additionally, the new END_OF_UPDATE
flag allows to signal when a update sequence is finished. If this flag
is encountered, no further UDP packets are processed in the current
frame.
This commit is contained in:
Thomas Kolb 2020-04-14 21:03:39 +02:00
parent da37f32096
commit dc8bc98193
2 changed files with 71 additions and 58 deletions

View file

@ -12,6 +12,7 @@ public:
FADE_COLOUR = 1,
ADD_COLOUR = 2,
SET_FADESTEP = 3,
END_OF_UPDATE = 254,
ACK_REQUEST = 255
};
@ -24,6 +25,8 @@ public:
bool loop(void);
private:
const static uint32_t MAX_PACKETS_PER_UPDATE = 3;
WiFiUDP m_udpServer;
Fader *m_fader;
};

View file

@ -39,72 +39,82 @@ bool UDPProto::loop(void)
byte cmd[WS2801_CMD_LEN];
byte action, strip, module, r, g, b, w;
int len;
int packets_processed = 0;
bool done_something = false;
int32_t seq = -1;
int packetSize = m_udpServer.parsePacket();
if(packetSize)
{
// read the packet into packetBufffer
while((len = m_udpServer.read(cmd, WS2801_CMD_LEN)) == WS2801_CMD_LEN) {
action = cmd[0];
strip = cmd[1];
module = cmd[2];
r = cmd[3];
g = cmd[4];
b = cmd[5];
w = cmd[6];
while(packets_processed < MAX_PACKETS_PER_UPDATE) {
int packetSize = m_udpServer.parsePacket();
if(packetSize)
{
// read the packet into packetBufffer
while((len = m_udpServer.read(cmd, WS2801_CMD_LEN)) == WS2801_CMD_LEN) {
action = cmd[0];
strip = cmd[1];
module = cmd[2];
r = cmd[3];
g = cmd[4];
b = cmd[5];
w = cmd[6];
Fader::Color color{r,g,b,w};
Fader::Color color{r,g,b,w};
if(strip >= m_fader->strips()) {
// strip index out of range
continue;
if(strip >= m_fader->strips()) {
// strip index out of range
continue;
}
if(module >= m_fader->modules_per_strip()) {
// module index out of range
continue;
}
switch(action) {
case SET_COLOUR:
m_fader->set_color(strip, module, color);
break;
case FADE_COLOUR:
m_fader->fade_color(strip, module, color);
break;
case ADD_COLOUR:
m_fader->add_color(strip, module, color);
break;
case SET_FADESTEP:
m_fader->set_fadestep(r); // red channel contains the fadestep in this case
break;
case END_OF_UPDATE:
packets_processed = MAX_PACKETS_PER_UPDATE;
break;
case ACK_REQUEST:
seq = ((int32_t)r) << 8 | (int32_t)g;
default:
break;
}
}
// send a reply, to the IP address and port that sent us the packet we received
if(seq >= 0) {
uint8_t data[2];
data[0] = (seq >> 8) & 0xFF;
data[1] = seq & 0xFF;
m_udpServer.beginPacket(m_udpServer.remoteIP(), m_udpServer.remotePort());
m_udpServer.write(data, 2);
m_udpServer.endPacket();
}
if(module >= m_fader->modules_per_strip()) {
// module index out of range
continue;
}
m_udpServer.flush();
switch(action) {
case SET_COLOUR:
m_fader->set_color(strip, module, color);
break;
case FADE_COLOUR:
m_fader->fade_color(strip, module, color);
break;
case ADD_COLOUR:
m_fader->add_color(strip, module, color);
break;
case SET_FADESTEP:
m_fader->set_fadestep(r); // red channel contains the fadestep in this case
break;
case ACK_REQUEST:
seq = ((int32_t)r) << 8 | (int32_t)g;
default:
break;
}
done_something = true;
} else {
break;
}
// send a reply, to the IP address and port that sent us the packet we received
if(seq >= 0) {
uint8_t data[2];
data[0] = (seq >> 8) & 0xFF;
data[1] = seq & 0xFF;
m_udpServer.beginPacket(m_udpServer.remoteIP(), m_udpServer.remotePort());
m_udpServer.write(data, 2);
m_udpServer.endPacket();
}
m_udpServer.flush();
return true; // processed a packet
} else {
return false;
}
return done_something;
}