|
16 | 16 | */ |
17 | 17 |
|
18 | 18 | #include <cstring> |
| 19 | + |
19 | 20 | #ifndef _WIN32 |
20 | 21 | #include <sys/select.h> |
21 | 22 | #include <sys/stat.h> |
| 23 | +#include <sys/ioctl.h> |
22 | 24 | #include <limits.h> |
23 | 25 | #endif |
24 | 26 |
|
@@ -239,7 +241,9 @@ namespace Device |
239 | 241 | } |
240 | 242 | } |
241 | 243 | #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); |
243 | 247 | if (serial_fd == -1) |
244 | 248 | { |
245 | 249 | throw std::runtime_error("Failed to open serial port " + port + " at baudrate " + std::to_string(baudrate) + "."); |
@@ -286,41 +290,53 @@ namespace Device |
286 | 290 | throw std::runtime_error("Serial: cfsetispeed failed."); |
287 | 291 | } |
288 | 292 |
|
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 |
292 | 297 | tty.c_cflag |= CS8; // 8 bits per byte |
293 | 298 | tty.c_cflag |= CREAD | CLOCAL; // Enable receiver, ignore modem control lines |
| 299 | + tty.c_cflag &= ~CRTSCTS; // Disable hardware flow control (both Linux and macOS) |
294 | 300 |
|
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 |
299 | 309 |
|
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; |
304 | 317 |
|
305 | 318 | if (tcsetattr(serial_fd, TCSANOW, &tty) < 0) |
306 | 319 | { |
307 | 320 | perror("tcsetattr"); |
308 | 321 | throw std::runtime_error("Serial: tcsetattr failed."); |
309 | 322 | } |
310 | 323 |
|
311 | | -#ifdef __APPLE__ |
312 | | - // macOS-specific: Give the port time to stabilize after configuration |
313 | 324 | SleepSystem(200); |
314 | | -#endif |
315 | | - |
316 | | - // Flush any stale data |
317 | 325 | tcflush(serial_fd, TCIOFLUSH); |
318 | 326 |
|
| 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 | + |
319 | 335 | if (init_sequence.length()) |
320 | 336 | { |
321 | 337 | SleepSystem(100); |
322 | 338 |
|
323 | | - // Send initial carriage return (before setting non-blocking mode) |
| 339 | + // Send initial carriage return |
324 | 340 | const char *initial_cr = "\r"; |
325 | 341 | if (write(serial_fd, initial_cr, 1) < 0) |
326 | 342 | { |
@@ -351,6 +367,7 @@ namespace Device |
351 | 367 | } |
352 | 368 | } |
353 | 369 |
|
| 370 | + // Switch to non-blocking mode for async reading |
354 | 371 | int flags = fcntl(serial_fd, F_GETFL, 0); |
355 | 372 | fcntl(serial_fd, F_SETFL, flags | O_NONBLOCK); |
356 | 373 | #endif |
|
0 commit comments