DCB dcb;
#else
struct termios term;
+ int controlbits;
int rts;
int cts;
int dtr;
#endif
};
+/* Standard baud rates. */
+#ifdef _WIN32
+#define BAUD_TYPE DWORD
+#define BAUD(n) {CBR_##n, n}
+#else
+#define BAUD_TYPE speed_t
+#define BAUD(n) {B##n, n}
+#endif
+
+struct std_baudrate {
+ BAUD_TYPE index;
+ int value;
+};
+
+const struct std_baudrate std_baudrates[] = {
+#ifdef _WIN32
+ /*
+ * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
+ * have documented CBR_* macros.
+ */
+ BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
+ BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
+ BAUD(115200), BAUD(128000), BAUD(256000)
+#else
+ BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200), BAUD(300),
+ BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800), BAUD(9600),
+ BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200), BAUD(230400),
+#if !defined(__APPLE__) && !defined(__OpenBSD__)
+ BAUD(460800)
+#endif
+#endif
+};
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
+
+/* Helper functions for configuring ports. */
+static int start_config(struct sp_port *port, struct sp_port_data *data);
+static int set_baudrate(struct sp_port_data *data, int baudrate);
+static int set_bits(struct sp_port_data *data, int bits);
+static int set_parity(struct sp_port_data *data, int parity);
+static int set_stopbits(struct sp_port_data *data, int stopbits);
+static int set_rts(struct sp_port_data *data, int rts);
+static int set_cts(struct sp_port_data *data, int cts);
+static int set_dtr(struct sp_port_data *data, int dtr);
+static int set_dsr(struct sp_port_data *data, int dsr);
+static int set_xon_xoff(struct sp_port_data *data, int xon_xoff);
+static int apply_config(struct sp_port *port, struct sp_port_data *data);
+
int sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
{
struct sp_port *port;
return SP_ERR_FAIL;
#else
int flags_local = 0;
+ struct sp_port_data data;
/* Map 'flags' to the OS-specific settings. */
if (flags & SP_MODE_RDWR)
if ((port->fd = open(port->name, flags_local)) < 0)
return SP_ERR_FAIL;
+
+ start_config(port, &data);
+
+ /* Turn off all serial port cooking. */
+ data.term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
+ data.term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+ data.term.c_oflag &= ~OFILL;
+#endif
+ /* Disable canonical mode, and don't echo input characters. */
+ data.term.c_lflag &= ~(ICANON | ECHO);
+
+ /* Ignore modem status lines; enable receiver */
+ data.term.c_cflag |= (CLOCAL | CREAD);
+
+ apply_config(port, &data);
#endif
return SP_OK;
if (!GetCommState(port->hdl, &data->dcb))
return SP_ERR_FAIL;
#else
- int controlbits;
-
if (tcgetattr(port->fd, &data->term) < 0)
return SP_ERR_FAIL;
- if (ioctl(port->fd, TIOCMGET, &controlbits) < 0)
+ if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
return SP_ERR_FAIL;
if (data->term.c_cflag & CRTSCTS) {
data->rts = SP_RTS_FLOW_CONTROL;
data->cts = SP_CTS_FLOW_CONTROL;
} else {
- data->rts = (controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
+ data->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
data->cts = SP_CTS_IGNORE;
}
- data->dtr = (controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
+ data->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
data->dsr = SP_DSR_IGNORE;
#endif
return SP_OK;
static int set_baudrate(struct sp_port_data *data, int baudrate)
{
+ unsigned int i;
+ for (i = 0; i < NUM_STD_BAUDRATES; i++) {
+ if (baudrate == std_baudrates[i].value) {
#ifdef _WIN32
- switch (baudrate) {
- /*
- * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
- * have documented CBR_* macros.
- */
- case 110:
- data->dcb.BaudRate = CBR_110;
- break;
- case 300:
- data->dcb.BaudRate = CBR_300;
- break;
- case 600:
- data->dcb.BaudRate = CBR_600;
- break;
- case 1200:
- data->dcb.BaudRate = CBR_1200;
- break;
- case 2400:
- data->dcb.BaudRate = CBR_2400;
- break;
- case 4800:
- data->dcb.BaudRate = CBR_4800;
- break;
- case 9600:
- data->dcb.BaudRate = CBR_9600;
- break;
- case 14400:
- data->dcb.BaudRate = CBR_14400; /* Not available on Unix? */
- break;
- case 19200:
- data->dcb.BaudRate = CBR_19200;
- break;
- case 38400:
- data->dcb.BaudRate = CBR_38400;
- break;
- case 57600:
- data->dcb.BaudRate = CBR_57600;
- break;
- case 115200:
- data->dcb.BaudRate = CBR_115200;
- break;
- case 128000:
- data->dcb.BaudRate = CBR_128000; /* Not available on Unix? */
- break;
- case 256000:
- data->dcb.BaudRate = CBR_256000; /* Not available on Unix? */
- break;
- default:
- return SP_ERR_ARG;
- }
+ data->dcb.BaudRate = std_baudrates[i].index;
#else
- speed_t baud;
- switch (baudrate) {
- case 50:
- baud = B50;
- break;
- case 75:
- baud = B75;
- break;
- case 110:
- baud = B110;
- break;
- case 134:
- baud = B134;
- break;
- case 150:
- baud = B150;
- break;
- case 200:
- baud = B200;
- break;
- case 300:
- baud = B300;
- break;
- case 600:
- baud = B600;
- break;
- case 1200:
- baud = B1200;
- break;
- case 1800:
- baud = B1800;
- break;
- case 2400:
- baud = B2400;
- break;
- case 4800:
- baud = B4800;
- break;
- case 9600:
- baud = B9600;
- break;
- case 19200:
- baud = B19200;
- break;
- case 38400:
- baud = B38400;
- break;
- case 57600:
- baud = B57600;
- break;
- case 115200:
- baud = B115200;
- break;
- case 230400:
- baud = B230400;
- break;
-#if !defined(__APPLE__) && !defined(__OpenBSD__)
- case 460800:
- baud = B460800;
- break;
+ if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
+ return SP_ERR_FAIL;
+
+ if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
+ return SP_ERR_FAIL;
#endif
- default:
- return SP_ERR_ARG;
+ break;
+ }
}
- if (cfsetospeed(&data->term, baud) < 0)
- return SP_ERR_FAIL;
-
- if (cfsetispeed(&data->term, baud) < 0)
- return SP_ERR_FAIL;
+ if (i == NUM_STD_BAUDRATES)
+ return SP_ERR_ARG;
-#endif
return SP_OK;
}
#else
int controlbits;
- /* Turn off all serial port cooking. */
- data->term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
- data->term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
- data->term.c_oflag &= ~OFILL;
-#endif
- /* Disable canonical mode, and don't echo input characters. */
- data->term.c_lflag &= ~(ICANON | ECHO);
-
- /* Ignore modem status lines; enable receiver */
- data->term.c_cflag |= (CLOCAL | CREAD);
-
/* Asymmetric use of RTS/CTS not supported yet. */
if ((data->rts == SP_RTS_FLOW_CONTROL) != (data->cts == SP_CTS_FLOW_CONTROL))
return SP_ERR_ARG;
}
#define TRY(x) do { int ret = x; if (ret != SP_OK) return ret; } while (0)
-#define TRY_SET(x) do { if (config->x >= 0) TRY(set_##x(&data, config->x)); } while (0)
+#define TRY_SET(x, y) do { if (y >= 0) TRY(set_##x(&data, y)); } while (0)
+#define TRY_SET_CONFIG(x) TRY_SET(x, config->x)
int sp_set_config(struct sp_port *port, struct sp_port_config *config)
{
struct sp_port_data data;
TRY(start_config(port, &data));
- TRY_SET(baudrate);
- TRY_SET(bits);
- TRY_SET(parity);
- TRY_SET(stopbits);
- TRY_SET(rts);
- TRY_SET(cts);
- TRY_SET(dtr);
- TRY_SET(dsr);
- TRY_SET(xon_xoff);
+ TRY_SET_CONFIG(baudrate);
+ TRY_SET_CONFIG(bits);
+ TRY_SET_CONFIG(parity);
+ TRY_SET_CONFIG(stopbits);
+ TRY_SET_CONFIG(rts);
+ TRY_SET_CONFIG(cts);
+ TRY_SET_CONFIG(dtr);
+ TRY_SET_CONFIG(dsr);
+ TRY_SET_CONFIG(xon_xoff);
TRY(apply_config(port, &data));
return SP_OK;
}
+int sp_get_config(struct sp_port *port, struct sp_port_config *config)
+{
+ struct sp_port_data data;
+ unsigned int i;
+
+ TRY(start_config(port, &data));
+
+#ifdef _WIN32
+ for (i = 0; i < NUM_STD_BAUDRATES; i++) {
+ if (data.dcb.BaudRate == std_baudrates[i].index) {
+ config->baudrate = std_baudrates[i].value;
+ break;
+ }
+ }
+
+ if (i == NUM_STD_BAUDRATES)
+ /* BaudRate field can be either an index or a custom baud rate. */
+ config->baudrate = data.dcb.BaudRate;
+
+ config->bits = data.dcb.ByteSize;
+
+ if (data.dcb.fParity)
+ switch (data.dcb.Parity) {
+ case NOPARITY:
+ config->parity = SP_PARITY_NONE;
+ break;
+ case EVENPARITY:
+ config->parity = SP_PARITY_EVEN;
+ break;
+ case ODDPARITY:
+ config->parity = SP_PARITY_ODD;
+ break;
+ default:
+ config->parity = -1;
+ }
+ else
+ config->parity = SP_PARITY_NONE;
+
+ switch (data.dcb.StopBits) {
+ case ONESTOPBIT:
+ config->stopbits = 1;
+ break;
+ case TWOSTOPBITS:
+ config->stopbits = 2;
+ break;
+ default:
+ config->stopbits = -1;
+ }
+
+ switch (data.dcb.fRtsControl) {
+ case RTS_CONTROL_DISABLE:
+ config->rts = SP_RTS_OFF;
+ break;
+ case RTS_CONTROL_ENABLE:
+ config->rts = SP_RTS_ON;
+ break;
+ case RTS_CONTROL_HANDSHAKE:
+ config->rts = SP_RTS_FLOW_CONTROL;
+ break;
+ default:
+ config->rts = -1;
+ }
+
+ config->cts = data.dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
+
+ switch (data.dcb.fDtrControl) {
+ case DTR_CONTROL_DISABLE:
+ config->dtr = SP_DTR_OFF;
+ break;
+ case DTR_CONTROL_ENABLE:
+ config->dtr = SP_DTR_ON;
+ break;
+ case DTR_CONTROL_HANDSHAKE:
+ config->dtr = SP_DTR_FLOW_CONTROL;
+ break;
+ default:
+ config->dtr = -1;
+ }
+
+ config->dsr = data.dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
+#else
+ for (i = 0; i < NUM_STD_BAUDRATES; i++) {
+ if (cfgetispeed(&data.term) == std_baudrates[i].index) {
+ config->baudrate = std_baudrates[i].value;
+ break;
+ }
+ }
+
+ if (i == NUM_STD_BAUDRATES)
+ config->baudrate = -1;
+
+ switch (data.term.c_cflag & CSIZE) {
+ case CS8:
+ config->bits = 8;
+ break;
+ case CS7:
+ config->bits = 7;
+ break;
+ case CS6:
+ config->bits = 6;
+ break;
+ case CS5:
+ config->bits = 5;
+ break;
+ default:
+ config->bits = -1;
+ }
+
+ if (!(data.term.c_cflag & PARENB) && (data.term.c_iflag & IGNPAR))
+ config->parity = SP_PARITY_NONE;
+ else if (!(data.term.c_cflag & PARENB) || (data.term.c_iflag & IGNPAR))
+ config->parity = -1;
+ else
+ config->parity = (data.term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
+
+ config->stopbits = (data.term.c_cflag & CSTOPB) ? 2 : 1;
+
+ if (data.term.c_cflag & CRTSCTS) {
+ config->rts = SP_RTS_FLOW_CONTROL;
+ config->cts = SP_CTS_FLOW_CONTROL;
+ } else {
+ config->rts = (data.controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
+ config->cts = SP_CTS_IGNORE;
+ }
+
+ config->dtr = (data.controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
+ config->dsr = SP_DSR_IGNORE;
+#endif
+
+ return SP_OK;
+}
+
+int sp_set_flowcontrol(struct sp_port *port, int flowcontrol)
+{
+ struct sp_port_data data;
+
+ TRY(start_config(port, &data));
+
+ if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
+ TRY_SET(xon_xoff, SP_XONXOFF_INOUT);
+ else
+ TRY_SET(xon_xoff, SP_XONXOFF_DISABLED);
+
+ if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
+ TRY_SET(rts, SP_RTS_FLOW_CONTROL);
+ TRY_SET(cts, SP_CTS_FLOW_CONTROL);
+ } else {
+ TRY_SET(rts, SP_RTS_ON);
+ TRY_SET(cts, SP_CTS_IGNORE);
+ }
+
+ if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
+ TRY_SET(dtr, SP_DTR_FLOW_CONTROL);
+ TRY_SET(dsr, SP_DSR_FLOW_CONTROL);
+ } else {
+ TRY_SET(dtr, SP_DTR_ON);
+ TRY_SET(dsr, SP_DSR_IGNORE);
+ }
+
+ TRY(apply_config(port, &data));
+
+ return SP_OK;
+}
+
+#define CREATE_SETTER(x) int sp_set_##x(struct sp_port *port, int x) { \
+ struct sp_port_data data; \
+ TRY(start_config(port, &data)); \
+ TRY(set_##x(&data, x)); \
+ TRY(apply_config(port, &data)); \
+ return SP_OK; \
+}
+
+CREATE_SETTER(baudrate)
+CREATE_SETTER(bits)
+CREATE_SETTER(parity)
+CREATE_SETTER(stopbits)
+CREATE_SETTER(rts)
+CREATE_SETTER(cts)
+CREATE_SETTER(dtr)
+CREATE_SETTER(dsr)
+CREATE_SETTER(xon_xoff)
+
int sp_last_error_code(void)
{
#ifdef _WIN32