Skip to content

Commit 773bb16

Browse files
dontechPeter Dons TychsenAndreRenaud
authored
linux: implement termios2 support, for more precise higher speeds (#56)
* simple_uart: use correct api for flushing * linux: implement termios2 support, for more precise higher speeds --------- Co-authored-by: Peter Dons Tychsen <extptychsen@falcom.net> Co-authored-by: Andre Renaud <andre@ignavus.net>
1 parent 61a17fd commit 773bb16

1 file changed

Lines changed: 61 additions & 10 deletions

File tree

‎simple_uart.c‎

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include <sys/stat.h>
2929
#include <sys/types.h>
3030
#include <sys/wait.h>
31-
#include <termios.h>
3231
#include <unistd.h>
3332
#else
3433
#include <windows.h>
@@ -40,11 +39,12 @@
4039
#endif
4140

4241
#ifdef __linux__
42+
#include <asm/termbits.h>
4343
#include <linux/serial.h>
44-
#include <pty.h>
4544
#endif
4645

4746
#ifdef __APPLE__
47+
#include <termios.h>
4848
#include <IOKit/serial/ioss.h>
4949
#endif
5050

@@ -282,11 +282,12 @@ static int simple_uart_set_config(struct simple_uart *sc, int speed, const char
282282
#if defined(__linux__) || defined(__APPLE__)
283283
static int simple_uart_set_config(struct simple_uart *sc, int speed, const char *mode_string) // Linux Port config
284284
{
285-
struct termios options; // Linux options handle
286-
speed_t sp = B0; // Default linux speed
285+
speed_t sp = B0; // Default mac/linux speed
287286
#ifdef __linux__
287+
struct termios2 options; // Linux options handle
288288
int non_standard = 0;
289289
#else // __APPLE__ type casting
290+
struct termios options; // Mac options handle
290291
speed_t mac_speed = speed;
291292
#endif
292293

@@ -314,6 +315,11 @@ static int simple_uart_set_config(struct simple_uart *sc, int speed, const char
314315
case 3000000: sp = B3000000; break;
315316
case 3500000: sp = B3500000; break;
316317
case 4000000: sp = B4000000; break;
318+
319+
/* These speeds are supported on Linux via termios2, e.g. on FTDI */
320+
case 6000000: sp = 6000000; break;
321+
case 12000000: sp = 12000000; break;
322+
317323
default: sp = B38400; non_standard = 1;
318324
#else // __APPLE__ only
319325
// The IOSSIOSPEED ioctl can be used to set arbitrary baud rates
@@ -327,14 +333,41 @@ static int simple_uart_set_config(struct simple_uart *sc, int speed, const char
327333
}
328334
#endif
329335
}
330-
/* Accquire current port config */
336+
337+
/* Acquire current port config */
338+
#ifdef __linux__
339+
if (ioctl(sc->fd, TCGETS2, &options) < 0)
340+
return -errno;
341+
#else
331342
if (tcgetattr(sc->fd, &options) < 0)
332343
return -errno;
344+
#endif
333345

346+
#ifdef __linux__
347+
options.c_cflag &= ~CBAUD;
348+
if((speed >= 6000000) && (speed <= 12000000))
349+
{
350+
/* Use the BOTHER/CBAUDEX flag for high speeds */
351+
options.c_cflag |= BOTHER;
352+
options.c_cflag |= CBAUDEX;
353+
options.c_ispeed = sp;
354+
options.c_ospeed = sp;
355+
}
356+
else
357+
{
358+
/* Normal options */
359+
options.c_cflag &= ~BOTHER;
360+
options.c_cflag &= ~CBAUDEX;
361+
options.c_cflag |= sp;
362+
options.c_ispeed = 0;
363+
options.c_ospeed = 0;
364+
}
365+
#else
334366
if (sp != 0) {
335367
cfsetospeed(&options, sp);
336368
cfsetispeed(&options, sp);
337369
}
370+
#endif
338371

339372
options.c_cflag &= (tcflag_t) ~(HUPCL);
340373

@@ -392,9 +425,21 @@ static int simple_uart_set_config(struct simple_uart *sc, int speed, const char
392425

393426
options.c_cc[VTIME] = 0;
394427
options.c_cc[VMIN] = 0;
428+
429+
#ifdef __linux__
430+
if (ioctl(sc->fd, TCFLSH, TCIOFLUSH) < 0)
431+
return -errno;
432+
#else
395433
tcflush(sc->fd, TCIOFLUSH);
434+
#endif
435+
436+
#ifdef __linux__
437+
if (ioctl(sc->fd, TCSETS2, &options) < 0)
438+
return -errno;
439+
#else
396440
if (tcsetattr(sc->fd, TCSANOW, &options) < 0)
397441
return -errno;
442+
#endif
398443

399444
#ifdef __linux__
400445
if (HAS_OPTION('R')) {
@@ -839,17 +884,20 @@ int simple_uart_send_break(struct simple_uart *uart)
839884
if (!uart)
840885
return -EINVAL;
841886

842-
#if defined(__linux__) || defined(__APPLE__)
843-
tcsendbreak(uart->fd, 1);
844-
return 0;
887+
#ifdef __linux__
888+
if (ioctl(uart->fd, TCSBRK, 1) < 0)
889+
return -errno;
890+
#elif defined(__APPLE__)
891+
if (tcsendbreak(uart->fd, 1) < 0)
892+
return -errno;
845893
#else
846894
SetCommBreak(uart->port);
847895
// Linux doesn't support durations, it is always 4/10 of a second.
848896
// Replicate that here.
849897
Sleep(400);
850898
ClearCommBreak(uart->port);
851-
return 0;
852899
#endif
900+
return 0;
853901
}
854902

855903
#ifdef _WIN32
@@ -938,7 +986,10 @@ int simple_uart_flush(struct simple_uart *uart)
938986
if (!uart)
939987
return -EINVAL;
940988

941-
#if defined(__linux__) || defined(__APPLE__)
989+
#if defined(__linux__)
990+
if (ioctl(uart->fd, TCFLSH, TCIOFLUSH) < 0)
991+
return -errno;
992+
#elif defined(__APPLE__)
942993
if (tcdrain(uart->fd) < 0)
943994
return -errno;
944995
#else

0 commit comments

Comments
 (0)