Skip to content

Commit 8a6f120

Browse files
committed
v1.8.0 - USB buffer deadlock fix and device naming portability
1 parent 1c2febb commit 8a6f120

File tree

6 files changed

+72
-28
lines changed

6 files changed

+72
-28
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
All notable changes to the Pressboi firmware will be documented in this file.
44

5+
## [1.8.0] - 2025-11-19
6+
7+
### Fixed
8+
- **USB buffer improvements**: Implemented automatic USB host connection detection to prevent buffer overflow
9+
- **Message filtering**: Firmware now only sends USB/network messages when respective interfaces have active listeners
10+
11+
### Changed
12+
- **Device naming portability**: Replaced hardcoded "PRESSBOI" strings with `DEVICE_NAME_UPPER` and `DEVICE_NAME_LOWER` defines from `config.h`
13+
514
## [1.7.0] - 2025-11-18
615

716
### Changed

Debug/pressboi.bin

48 Bytes
Binary file not shown.

Debug/pressboi.elf

640 Bytes
Binary file not shown.

Debug/pressboi.uf2

0 Bytes
Binary file not shown.

inc/config.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212
#pragma once
1313
#include "ClearCore.h"
1414

15+
//==================================================================================================
16+
// Device Identity
17+
//==================================================================================================
18+
/**
19+
* @name Device Identity
20+
* @{
21+
*/
22+
#define DEVICE_NAME_UPPER "PRESSBOI" ///< Device name in uppercase for message prefixes
23+
#define DEVICE_NAME_LOWER "pressboi" ///< Device name in lowercase for identifiers
24+
/** @} */
25+
1526
//==================================================================================================
1627
// Network Configuration
1728
//==================================================================================================
@@ -35,9 +46,8 @@
3546
* @name General System Behavior
3647
* @{
3748
*/
38-
#define FIRMWARE_VERSION "1.7.0" ///< Pressboi firmware version
49+
#define FIRMWARE_VERSION "1.8.0" ///< Pressboi firmware version
3950
#define STATUS_MESSAGE_BUFFER_SIZE 256 ///< Standard buffer size for composing status and error messages.
40-
#define POST_ABORT_DELAY_MS 100 ///< Delay in milliseconds after an abort command to allow motors to come to a complete stop.
4151
/** @} */
4252

4353
//==================================================================================================

src/comms_controller.cpp

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ bool CommsController::enqueueRx(const char* msg, const IpAddress& ip, uint16_t p
4646
int next_head = (m_rxQueueHead + 1) % RX_QUEUE_SIZE;
4747
if (next_head == m_rxQueueTail) {
4848
if(m_guiDiscovered && EthernetMgr.PhyLinkActive()) {
49-
char errorMsg[] = "PRESSBOI_ERROR: RX QUEUE OVERFLOW - COMMAND DROPPED";
49+
char errorMsg[128];
50+
snprintf(errorMsg, sizeof(errorMsg), "%s_ERROR: RX QUEUE OVERFLOW - COMMAND DROPPED", DEVICE_NAME_UPPER);
5051
m_udp.Connect(m_guiIp, m_guiPort);
5152
m_udp.PacketWrite(errorMsg);
5253
m_udp.PacketSend();
@@ -74,7 +75,8 @@ bool CommsController::enqueueTx(const char* msg, const IpAddress& ip, uint16_t p
7475
int next_head = (m_txQueueHead + 1) % TX_QUEUE_SIZE;
7576
if (next_head == m_txQueueTail) {
7677
if(m_guiDiscovered && EthernetMgr.PhyLinkActive()) {
77-
char errorMsg[] = "PRESSBOI_ERROR: TX QUEUE OVERFLOW - MESSAGE DROPPED";
78+
char errorMsg[128];
79+
snprintf(errorMsg, sizeof(errorMsg), "%s_ERROR: TX QUEUE OVERFLOW - MESSAGE DROPPED", DEVICE_NAME_UPPER);
7880
m_udp.Connect(m_guiIp, m_guiPort);
7981
m_udp.PacketWrite(errorMsg);
8082
m_udp.PacketSend();
@@ -136,7 +138,9 @@ void CommsController::processUsbSerial() {
136138
// Buffer overflow protection - discard message
137139
else {
138140
usbBufferIndex = 0;
139-
ConnectorUsb.Send("PRESSBOI_ERROR: USB command too long\n");
141+
char errorMsg[128];
142+
snprintf(errorMsg, sizeof(errorMsg), "%s_ERROR: USB command too long\n", DEVICE_NAME_UPPER);
143+
ConnectorUsb.Send(errorMsg);
140144
}
141145
}
142146
}
@@ -168,35 +172,50 @@ void CommsController::processTxQueue() {
168172
// Note: If ethernet link is down or no valid network IP, UDP send is skipped
169173
// This prevents watchdog timeouts from blocking UDP sends
170174

171-
// Mirror to USB serial with chunking for large messages
172-
// This happens ALWAYS, regardless of network state
173-
// USB CDC buffer is 64 bytes, so we chunk messages larger than 50 bytes
175+
// Mirror to USB serial (if USB host is connected and reading)
176+
// USB CDC buffer is 64 bytes, so we chunk messages larger than 50 bytes
177+
//
178+
// USB Connection Detection:
179+
// - If USB buffer has space, a host is connected and reading data
180+
// - If USB buffer stays full for >3 seconds, no host is reading (disconnected or app closed)
181+
// - Stop sending to prevent buffer deadlock, resume automatically when host reconnects
182+
183+
static uint32_t lastUsbHealthy = 0;
184+
static bool usbHostConnected = true; // Assume connected at boot
185+
uint32_t now = Milliseconds();
186+
int usbAvail = ConnectorUsb.AvailableForWrite();
187+
188+
// Check if USB buffer has space - if yes, a host is actively reading
189+
if (usbAvail > 5) {
190+
lastUsbHealthy = now;
191+
if (!usbHostConnected) {
192+
// USB host reconnected! Resume sending
193+
usbHostConnected = true;
194+
char recoveryMsg[64];
195+
snprintf(recoveryMsg, sizeof(recoveryMsg), "%s_INFO: USB host reconnected\n", DEVICE_NAME_UPPER);
196+
ConnectorUsb.Send(recoveryMsg);
197+
}
198+
} else {
199+
// Buffer is nearly full - either host is slow or disconnected
200+
if (usbHostConnected && (now - lastUsbHealthy) > 3000) {
201+
// Buffer full for 3+ seconds - host disconnected or stopped reading
202+
usbHostConnected = false;
203+
// Stop sending to prevent buffer deadlock
204+
}
205+
}
206+
207+
// Only send to USB if a host is connected and reading
208+
if (usbHostConnected) {
174209
const int CHUNK_SIZE = 50;
175210
int msgLen = strlen(msg.buffer);
176211

177212
if (msgLen <= CHUNK_SIZE) {
178213
// Small message - send directly if buffer available
179-
int usbAvail = ConnectorUsb.AvailableForWrite();
180214
if (usbAvail >= msgLen + 1) {
181215
ConnectorUsb.Send(msg.buffer);
182216
ConnectorUsb.Send("\n");
183-
} else {
184-
// Debug: Report dropped messages
185-
static uint32_t dropCount = 0;
186-
static uint32_t lastReport = 0;
187-
dropCount++;
188-
uint32_t now = Milliseconds();
189-
if (now - lastReport > 2000) {
190-
char dbg[64];
191-
snprintf(dbg, sizeof(dbg), "USB_DROP: %lu msgs, avail=%d need=%d\n", dropCount, usbAvail, msgLen + 1);
192-
// Try to send error if space available
193-
if (ConnectorUsb.AvailableForWrite() > 60) {
194-
ConnectorUsb.Send(dbg);
195-
}
196-
lastReport = now;
197-
dropCount = 0;
198-
}
199217
}
218+
// If buffer full, just drop the message silently
200219
} else {
201220
// Large message - send in chunks with continuation markers
202221
// Format: "MSG_PART_1/3: first_50_chars"
@@ -228,8 +247,9 @@ void CommsController::processTxQueue() {
228247
}
229248
}
230249
}
231-
// If buffer is full, message is silently dropped to prevent blocking
232-
// This prevents watchdog timeouts from blocking USB sends
250+
}
251+
// If USB unhealthy or buffer full, message is silently dropped to prevent blocking
252+
// USB will auto-recover when buffer has space again (host reconnects)
233253
}
234254
}
235255

@@ -251,6 +271,9 @@ void CommsController::setupUsbSerial(void) {
251271
ConnectorUsb.PortOpen();
252272
// USB setup is non-blocking - the connector will become available when ready
253273
// No need to wait here, as the main loop will handle USB when available
274+
275+
// Send a startup message after a delay to confirm USB is working
276+
// (Will be sent in the main loop once USB is ready)
254277
}
255278

256279
void CommsController::setupEthernet() {
@@ -277,7 +300,9 @@ void CommsController::setupEthernet() {
277300
m_udp.Begin(LOCAL_PORT);
278301

279302
// Send status message over USB to confirm network is ready
280-
ConnectorUsb.Send("PRESSBOI_INFO: Network ready, listening on port 8888\n");
303+
char infoMsg[128];
304+
snprintf(infoMsg, sizeof(infoMsg), "%s_INFO: Network ready, listening on port %d\n", DEVICE_NAME_UPPER, LOCAL_PORT);
305+
ConnectorUsb.Send(infoMsg);
281306
}
282307

283308
// parseCommand is now in commands.cpp as a global function

0 commit comments

Comments
 (0)