X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fcommon%2Fserial.c;h=4a92a6684eba4edac865ab4c6ccd6658e1989877;hb=6f22a8ef2ccf7091324b41b553632695507215a7;hp=822b4ccd5c97f0fcf14674f125b69e317b029bce;hpb=f8c1fcda46584c3550a198625e0b5f0a58794b6e;p=libsigrok.git diff --git a/hardware/common/serial.c b/hardware/common/serial.c index 822b4ccd..4a92a668 100644 --- a/hardware/common/serial.c +++ b/hardware/common/serial.c @@ -30,8 +30,8 @@ #endif #include #include -#include "sigrok.h" -#include "sigrok-internal.h" +#include "libsigrok.h" +#include "libsigrok-internal.h" // FIXME: Must be moved, or rather passed as function argument. #ifdef _WIN32 @@ -218,6 +218,12 @@ SR_PRIV int serial_set_params(int fd, int baudrate, int bits, int parity, case 9600: dcb.BaudRate = CBR_9600; break; + case 4800: + dcb.BaudRate = CBR_4800; + break; + case 2400: + dcb.BaudRate = CBR_2400; + break; default: /* TODO: Error handling. */ break; @@ -234,7 +240,16 @@ SR_PRIV int serial_set_params(int fd, int baudrate, int bits, int parity, struct termios term; speed_t baud; + if (tcgetattr(fd, &term) < 0) + return SR_ERR; + switch (baudrate) { + case 2400: + baud = B2400; + break; + case 4800: + baud = B4800; + break; case 9600: baud = B9600; break; @@ -255,8 +270,7 @@ SR_PRIV int serial_set_params(int fd, int baudrate, int bits, int parity, default: return SR_ERR; } - - if (tcgetattr(fd, &term) < 0) + if (cfsetospeed(&term, baud) < 0) return SR_ERR; if (cfsetispeed(&term, baud) < 0) return SR_ERR; @@ -283,13 +297,17 @@ SR_PRIV int serial_set_params(int fd, int baudrate, int bits, int parity, return SR_ERR; } - term.c_cflag &= ~(IXON | IXOFF | CRTSCTS); + term.c_iflag &= ~(IXON | IXOFF); + term.c_cflag &= ~CRTSCTS; switch (flowcontrol) { - case 2: - term.c_cflag |= IXON | IXOFF; + case 0: + /* No flow control. */ break; case 1: term.c_cflag |= CRTSCTS; + case 2: + term.c_iflag |= IXON | IXOFF; + break; default: return SR_ERR; } @@ -310,9 +328,92 @@ SR_PRIV int serial_set_params(int fd, int baudrate, int bits, int parity, return SR_ERR; } + /* Some default parameters */ + term.c_iflag &= ~(ICRNL); + term.c_lflag &= ~(ICANON | ECHO); + if (tcsetattr(fd, TCSADRAIN, &term) < 0) return SR_ERR; #endif return SR_OK; } + +#define SERIAL_COMM_SPEC "^(\\d+)/([78])([neo])([12])$" +SR_PRIV int serial_set_paramstr(int fd, const char *paramstr) +{ + GRegex *reg; + GMatchInfo *match; + int speed, databits, parity, stopbits; + char *mstr; + + speed = databits = parity = stopbits = 0; + reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL); + if (g_regex_match(reg, paramstr, 0, &match)) { + if ((mstr = g_match_info_fetch(match, 1))) + speed = strtoul(mstr, NULL, 10); + g_free(mstr); + if ((mstr = g_match_info_fetch(match, 2))) + databits = strtoul(mstr, NULL, 10); + g_free(mstr); + if ((mstr = g_match_info_fetch(match, 3))) { + switch (mstr[0]) { + case 'n': + parity = SERIAL_PARITY_NONE; + break; + case 'e': + parity = SERIAL_PARITY_EVEN; + break; + case 'o': + parity = SERIAL_PARITY_ODD; + break; + } + } + g_free(mstr); + if ((mstr = g_match_info_fetch(match, 4))) + stopbits = strtoul(mstr, NULL, 10); + g_free(mstr); + } + g_match_info_unref(match); + g_regex_unref(reg); + + if (speed) + return serial_set_params(fd, speed, databits, parity, stopbits, 0); + else + return SR_ERR_ARG; +} + +SR_PRIV int serial_readline(int fd, char **buf, int *buflen, + uint64_t timeout_ms) +{ + uint64_t start; + int maxlen, len; + + timeout_ms *= 1000; + start = g_get_monotonic_time(); + + maxlen = *buflen; + *buflen = len = 0; + while(1) { + len = maxlen - *buflen - 1; + if (len < 1) + break; + len = serial_read(fd, *buf + *buflen, 1); + if (len > 0) { + *buflen += len; + *(*buf + *buflen) = '\0'; + if (*buflen > 0 && *(*buf + *buflen - 1) == '\r') { + /* Strip LF and terminate. */ + *(*buf + --*buflen) = '\0'; + break; + } + } + if (g_get_monotonic_time() - start > timeout_ms) + /* Timeout */ + break; + g_usleep(2000); + } + sr_dbg("Received %d: '%s'.", *buflen, *buf); + + return SR_OK; +}