1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/dist/tools/riotboot_serial/serial.c

167 lines
4.3 KiB
C

/*
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2018 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#define BAUDRATE_DEFAULT (B115200)
#define TTY_TIMEOUT_MS (500U)
static int _set_serial_attribs(int fd, int speed, int parity)
{
struct termios tty;
memset(&tty, 0, sizeof(tty));
if (tcgetattr(fd, &tty) != 0) {
perror("error in tcgetattr");
return -1;
}
cfsetospeed(&tty, speed);
cfsetispeed(&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; /* 8-bit chars */
/* disable IGNBRK for mismatched speed
* tests; otherwise receive break */
/* as \000 chars */
tty.c_iflag &= ~IGNBRK; /* disable break processing */
tty.c_lflag = 0; /* no signaling chars, no echo, */
/* no canonical processing */
tty.c_oflag = 0; /* no remapping, no delays */
tty.c_cc[VMIN] = 0; /* read doesn't block */
tty.c_cc[VTIME] = TTY_TIMEOUT_MS / 100; /* 0.5 seconds read timeout */
/* in tenths of a second */
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* shut off xon/xoff ctrl */
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls, */
/* enable reading */
tty.c_cflag &= ~(PARENB | PARODD); /* shut off parity */
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
cfmakeraw(&tty);
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("error from tcsetattr");
return -1;
}
return 0;
}
static void _set_blocking(int fd, int should_block)
{
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
perror("error from tggetattr");
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = TTY_TIMEOUT_MS / 100; /* 0.5 seconds read timeout */
/* in tenths of a second */
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("error setting term attributes");
}
}
static unsigned _parse_baudrate(char *arg)
{
#define case_baudrate(val) \
case val: \
return B ## val
if (arg == NULL) {
return BAUDRATE_DEFAULT;
}
switch (strtol(arg, NULL, 10)) {
case_baudrate(9600);
case_baudrate(19200);
case_baudrate(38400);
case_baudrate(57600);
case_baudrate(115200);
/* the following baudrates might not be available on all platforms */
#ifdef B230400
case_baudrate(230400);
#endif
#ifdef B460800
case_baudrate(460800);
#endif
#ifdef B500000
case_baudrate(500000);
#endif
#ifdef B576000
case_baudrate(576000);
#endif
#ifdef B921600
case_baudrate(921600);
#endif
#ifdef B1000000
case_baudrate(1000000);
#endif
#ifdef B1152000
case_baudrate(1152000);
#endif
#ifdef B1500000
case_baudrate(1500000);
#endif
#ifdef B2000000
case_baudrate(2000000);
#endif
#ifdef B2500000
case_baudrate(2500000);
#endif
#ifdef B3000000
case_baudrate(3000000);
#endif
#ifdef B3500000
case_baudrate(3500000);
#endif
#ifdef B4000000
case_baudrate(4000000);
#endif
default:
break;
}
#undef case_baudrate
return 0;
}
int serial_open(int argc, char **argv)
{
unsigned baudrate = BAUDRATE_DEFAULT;
int fd;
if (argc > 1) {
baudrate = _parse_baudrate(argv[1]);
}
if (baudrate == 0) {
fputs("Invalid baudrate\n", stderr);
errno = EINVAL;
return -1;
}
fd = open(argv[0], O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
return fd;
}
_set_serial_attribs(fd, baudrate, 0);
_set_blocking(fd, 0);
return fd;
}