diff options
Diffstat (limited to 'sw/programmer/linux/src/serial.c')
-rw-r--r-- | sw/programmer/linux/src/serial.c | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/sw/programmer/linux/src/serial.c b/sw/programmer/linux/src/serial.c index e2544be..42f021e 100644 --- a/sw/programmer/linux/src/serial.c +++ b/sw/programmer/linux/src/serial.c @@ -1,9 +1,23 @@ #include "serial.h" +static int rate_to_constant(int baudrate) { +#define B(x) case x: return B##x + switch(baudrate) { + B(50); B(75); B(110); B(134); B(150); + B(200); B(300); B(600); B(1200); B(1800); + B(2400); B(4800); B(9600); B(19200); B(38400); + B(57600); B(115200); B(230400); B(460800); B(500000); + B(576000); B(921600); B(1000000);B(1152000);B(1500000); + default: return 0; + } +#undef B +} + int serial_open(const char *devpath, unsigned long baudrate) { - int fd; + int fd, speed; struct termios tty; + struct serial_struct serinfo; // struct termios tty_old; // open device @@ -11,14 +25,44 @@ int serial_open(const char *devpath, unsigned long baudrate) return -1; } + speed = rate_to_constant(baudrate); + if (speed == 0) { + /* custom divisor */ + serinfo.reserved_char[0] = 0; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + return -1; + serinfo.flags &= ~ASYNC_SPD_MASK; + serinfo.flags |= ASYNC_SPD_CUST; + serinfo.custom_divisor = (serinfo.baud_base + (baudrate / 2)) / baudrate; + + if (serinfo.custom_divisor < 1) + serinfo.custom_divisor = 1; + if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) + return -1; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + return -1; + if (serinfo.custom_divisor * baudrate != serinfo.baud_base) { + warnx("actual baudrate is %d / %d = %f", + serinfo.baud_base, serinfo.custom_divisor, + (float)serinfo.baud_base / serinfo.custom_divisor); + } + } + + // set custom baudrate + ioctl(fd, TIOCGSERIAL, &serinfo); + serinfo.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY; + serinfo.custom_divisor = serinfo.baud_base / baudrate; + ioctl(fd, TIOCSSERIAL, &serinfo); + // set parameters if (tcgetattr(fd, &tty) != 0) { + // perror("failed tcgetattr"); return -1; } - // TODO: update UI or add support for custom baudrate - // cfsetospeed(&tty, - // cfsetispeed(&tty, + cfsetispeed(&tty, speed ?: B38400); + cfsetospeed(&tty, speed ?: B38400); + cfmakeraw(&tty); tty.c_cflag &= ~PARENB; // no parity tty.c_cflag &= ~CSTOPB; // no stop bit @@ -28,16 +72,19 @@ int serial_open(const char *devpath, unsigned long baudrate) 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; // no block read - tty.c_cc[VTIME] = .5; // .5 seconds read timeout + tty.c_cc[VTIME] = 5; // .5 seconds read timeout tty.c_cflag |= CREAD | CLOCAL; // turn on read and ignore ctrl lines tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw tty.c_oflag &= ~OPOST; // make raw - tcflush(fd , TCIFLUSH); - // if (tcsetaddr( + tcflush(fd , TCIFLUSH); // ? + + if (tcsetattr (fd, TCSANOW, &tty) != 0) { + // perror("failed tcsetattr to set serial port.\n"); + return -1; + } return fd; } - |