Skip to content

Commit e2d4a6c

Browse files
committed
update linux serial code
1 parent 168fa73 commit e2d4a6c

File tree

1 file changed

+35
-18
lines changed

1 file changed

+35
-18
lines changed

Source/Device/Serial.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
*/
1717

1818
#include <cstring>
19+
1920
#ifndef _WIN32
2021
#include <sys/select.h>
2122
#include <sys/stat.h>
23+
#include <sys/ioctl.h>
2224
#include <limits.h>
2325
#endif
2426

@@ -239,7 +241,9 @@ namespace Device
239241
}
240242
}
241243
#else
242-
serial_fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
244+
// CRITICAL FIX: Open in BLOCKING mode first for proper initialization
245+
// This prevents hanging with CDC ACM devices (like Daisy2+)
246+
serial_fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_CLOEXEC);
243247
if (serial_fd == -1)
244248
{
245249
throw std::runtime_error("Failed to open serial port " + port + " at baudrate " + std::to_string(baudrate) + ".");
@@ -286,41 +290,53 @@ namespace Device
286290
throw std::runtime_error("Serial: cfsetispeed failed.");
287291
}
288292

289-
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity
290-
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication
291-
tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size
293+
// 1. Control Modes (c_cflag)
294+
tty.c_cflag &= ~PARENB; // No parity bit
295+
tty.c_cflag &= ~CSTOPB; // 1 stop bit
296+
tty.c_cflag &= ~CSIZE; // Clear all size bits
292297
tty.c_cflag |= CS8; // 8 bits per byte
293298
tty.c_cflag |= CREAD | CLOCAL; // Enable receiver, ignore modem control lines
299+
tty.c_cflag &= ~CRTSCTS; // Disable hardware flow control (both Linux and macOS)
294300

295-
#ifdef __APPLE__
296-
// macOS-specific: Disable hardware flow control
297-
tty.c_cflag &= ~CRTSCTS;
298-
#endif
301+
// 2. Local Modes (c_lflag)
302+
// Clear IEXTEN to prevent eating special chars like 0x16 (LNEXT)
303+
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN);
304+
305+
// 3. Input Modes (c_iflag)
306+
// Comprehensive clearing for true raw input
307+
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable software flow control
308+
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable all input processing
299309

300-
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Raw mode, no echo
301-
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable software flow control
302-
tty.c_iflag &= ~(ICRNL | INLCR); // Disable CR/LF conversion
303-
tty.c_oflag &= ~OPOST; // Raw output
310+
// 4. Output Modes (c_oflag)
311+
tty.c_oflag &= ~OPOST; // Raw output - no processing
312+
313+
// 5. Control Characters (c_cc)
314+
// Set for non-blocking behavior (will be overridden by select() in ReadAsync)
315+
tty.c_cc[VMIN] = 0;
316+
tty.c_cc[VTIME] = 0;
304317

305318
if (tcsetattr(serial_fd, TCSANOW, &tty) < 0)
306319
{
307320
perror("tcsetattr");
308321
throw std::runtime_error("Serial: tcsetattr failed.");
309322
}
310323

311-
#ifdef __APPLE__
312-
// macOS-specific: Give the port time to stabilize after configuration
313324
SleepSystem(200);
314-
#endif
315-
316-
// Flush any stale data
317325
tcflush(serial_fd, TCIOFLUSH);
318326

327+
int status;
328+
if (ioctl(serial_fd, TIOCMGET, &status) == 0)
329+
{
330+
status |= TIOCM_DTR | TIOCM_RTS;
331+
ioctl(serial_fd, TIOCMSET, &status);
332+
SleepSystem(100);
333+
}
334+
319335
if (init_sequence.length())
320336
{
321337
SleepSystem(100);
322338

323-
// Send initial carriage return (before setting non-blocking mode)
339+
// Send initial carriage return
324340
const char *initial_cr = "\r";
325341
if (write(serial_fd, initial_cr, 1) < 0)
326342
{
@@ -351,6 +367,7 @@ namespace Device
351367
}
352368
}
353369

370+
// Switch to non-blocking mode for async reading
354371
int flags = fcntl(serial_fd, F_GETFL, 0);
355372
fcntl(serial_fd, F_SETFL, flags | O_NONBLOCK);
356373
#endif

0 commit comments

Comments
 (0)