summaryrefslogtreecommitdiffstats
path: root/sw/programmer/linux/src/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'sw/programmer/linux/src/serial.c')
-rw-r--r--sw/programmer/linux/src/serial.c63
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;
}
-