/* -*-c-*-
*
- * $Id: tx-serial-unix.c,v 1.1 2002/01/25 19:34:45 mdw Exp $
+ * $Id: tx-serial-unix.c,v 1.2 2002/01/30 09:24:24 mdw Exp $
*
* Unix/POSIX serial transport
*
/*----- Revision history --------------------------------------------------*
*
* $Log: tx-serial-unix.c,v $
+ * Revision 1.2 2002/01/30 09:24:24 mdw
+ * Restructure for new transport configuration interface.
+ *
* Revision 1.1 2002/01/25 19:34:45 mdw
* Initial revision
*
txport tx; /* Transport base */
struct txsu *next, **prev; /* Chain of serial transports */
int fd; /* File descriptor */
- struct termios old_ta; /* Old terminal settings */
+ serial_config sc; /* Internal serial config */
+ struct termios ta, old_ta; /* External serial configs */
} txsu;
/*----- Static variables --------------------------------------------------*/
struct baudmap { unsigned long baud; unsigned long magic; };
-static struct baudmap baudmap[] = {
+static const struct baudmap baudmap[] = {
#ifdef B50
{ 50, B50 },
#endif
tcsetattr(tx->fd, TCSAFLUSH, &tx->old_ta);
}
+/* --- @setconfig@ --- *
+ *
+ * Arguments: @txsu *tx@ = pointer to serial transport
+ * @serial_config *sc@ = pointer to configuration to set
+ *
+ * Returns: Zero if OK, nonzero on error.
+ *
+ * Use: Updates the external configuration from an internal
+ * representation.
+ */
+
+static int setconfig(txsu *tx, serial_config *sc)
+{
+ struct termios *ta = &tx->ta;
+ const struct baudmap *b;
+
+ for (b = baudmap; b->baud && b->baud != sc->baud; b++)
+ ;
+ if (!b->baud ||
+ sc->wordlen < 5 || sc->wordlen > 8 ||
+ sc->stopbits < 1 || sc->stopbits > 2) {
+ err_report(ERR_TXPORT, ERRTX_CONFIG, 0, "bad serial configuration");
+ return (-1);
+ }
+
+ ta->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
+ ta->c_oflag &= ~OPOST;
+ ta->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ ta->c_cc[VMIN] = 1;
+ ta->c_cc[VTIME] = 0;
+
+ cfsetospeed(ta, b->magic);
+ cfsetispeed(ta, b->magic);
+ ta->c_cflag = (ta->c_cflag & ~CSIZE) | csize[sc->wordlen - 5];
+ switch (sc->parity) {
+ case PARITY_NONE: ta->c_cflag &= ~PARENB; break;
+ case PARITY_ODD: ta->c_cflag |= PARENB | PARODD; break;
+ case PARITY_EVEN: ta->c_cflag |= PARENB; ta->c_cflag &= ~PARODD; break;
+ }
+ switch (sc->stopbits) {
+ case 1: ta->c_cflag &= ~CSTOPB; break;
+ case 2: ta->c_cflag |= CSTOPB; break;
+ }
+
+ switch (sc->flow) {
+ case FLOW_NONE:
+ ta->c_cflag &= ~CRTSCTS;
+ ta->c_iflag &= ~(IXON | IXOFF);
+ break;
+ case FLOW_XONXOFF:
+ ta->c_cflag &= ~CRTSCTS;
+ ta->c_iflag |= IXON | IXOFF;
+ break;
+ case FLOW_RTSCTS:
+ ta->c_cflag |= CRTSCTS;
+ ta->c_iflag &= ~(IXON | IXOFF);
+ break;
+ }
+
+ if (tcsetattr(tx->fd, TCSAFLUSH, ta)) {
+ err_report(ERR_TXPORT, ERRTX_CREATE, errno,
+ "couldn't set terminal attributes: %s", strerror(errno));
+ return (-1);
+ }
+
+ tx->sc = *sc;
+ return (0);
+}
+
/* --- @txsu_create@ --- *
*
* Arguments: @const char *file@ = filename for serial port
- * @const char *config@ = configuration string
*
* Returns: Pointer to created transport block.
*
* Use: Creates a serial port transport.
*/
-txport *txsu_create(const char *file, const char *config)
+txport *txsu_create(const char *file)
{
- txsu *tx;
+ txsu *tx = CREATE(txsu);
serial_config sc = SERIAL_INIT;
- struct termios ta, old_ta;
- struct baudmap *b;
- int fd;
-
- /* --- Parse the configuration and check it --- */
- if (config && *config && serial_parse(config, &sc))
- goto conferr;
-
- for (b = baudmap; b->baud && b->baud != sc.baud; b++)
- ;
- if (!b->baud ||
- sc.wordlen < 5 || sc.wordlen > 8 ||
- sc.stopbits < 1 || sc.stopbits > 2)
- goto conferr;
-
- /* --- Open the serial port and fetch attributes --- */
-
- if ((fd = open(file, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) {
+ if ((tx->fd = open(file, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) {
err_report(ERR_TXPORT, ERRTX_CREATE, errno,
"couldn't open device `%s': %s", file, strerror(errno));
goto fail_0;
}
- if (fdflags(fd, O_NONBLOCK, 0, 0, 0)) {
+ if (fdflags(tx->fd, O_NONBLOCK, 0, 0, 0)) {
err_report(ERR_TXPORT, ERRTX_CREATE, errno,
"fcntl(clear O_NONBLOCK): %s", file, strerror(errno));
goto fail_1;
- }
+ }
- if (tcgetattr(fd, &ta)) {
+ if (tcgetattr(tx->fd, &tx->old_ta)) {
err_report(ERR_TXPORT, ERRTX_CREATE, errno,
"couldn't get terminal attributes: %s", strerror(errno));
goto fail_1;
}
- old_ta = ta;
-
- /* --- Fix the attributes --- */
-
- ta.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- ta.c_oflag &= ~OPOST;
- ta.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- ta.c_cflag &= ~(CRTSCTS);
- ta.c_cc[VMIN] = 1;
- ta.c_cc[VTIME] = 0;
-
- cfsetospeed(&ta, b->magic);
- cfsetispeed(&ta, b->magic);
- ta.c_cflag = (ta.c_cflag & ~CSIZE) | csize[sc.wordlen - 5];
- switch (sc.parity) {
- case PARITY_NONE: ta.c_cflag &= ~PARENB; break;
- case PARITY_ODD: ta.c_cflag |= PARENB | PARODD; break;
- case PARITY_EVEN: ta.c_cflag |= PARENB; ta.c_cflag &= ~PARODD; break;
- }
- switch (sc.stopbits) {
- case 1: ta.c_cflag &= ~CSTOPB; break;
- case 2: ta.c_cflag |= CSTOPB; break;
- }
-
- /* --- Set attributes --- */
-
- if (tcsetattr(fd, TCSAFLUSH, &ta)) {
- err_report(ERR_TXPORT, ERRTX_CREATE, errno,
- "couldn't set terminal attributes: %s", strerror(errno));
+ tx->ta = tx->old_ta;
+ if (setconfig(tx, &sc))
goto fail_1;
- }
-
- /* --- Done --- */
- tx = CREATE(txsu);
- tx->fd = fd;
- tx->old_ta = old_ta;
tx->next = active;
tx->prev = &active;
active = tx;
/* --- Tidy up because it all went horribly wrong --- */
fail_1:
- close(fd);
+ close(tx->fd);
fail_0:
+ DESTROY(tx);
return (0);
+}
-conferr:
- err_report(ERR_TXPORT, ERRTX_CONFIG, 0,
- "bad configuration for serial port transport");
- goto fail_0;
+/* --- @txsu_configure@ --- *
+ *
+ * Arguments: @txport *txg@ = pointer to transport block
+ * @const char *k@ = configuration keyword
+ * @const char *v@ = value
+ *
+ * Returns: Nonzero if handled, zero otherwise.
+ *
+ * Use: Configures a serial port.
+ */
+
+int txsu_configure(txport *txg, const char *k, const char *v)
+{
+ txsu *tx = (txsu *)txg;
+ serial_config sc = tx->sc;
+
+ if (!v) {
+ err_report(ERR_TXPORT, ERRTX_CONFIG, 0,
+ "syntax error in serial config `%s'", k);
+ return (-1);
+ }
+ if (serial_parse(&sc, k, v)) {
+ err_report(ERR_TXPORT, ERRTX_CONFIG, 0,
+ "syntax error in serial config `%s=%s'", k, v);
+ return (-1);
+ }
+ if (setconfig(tx, &sc))
+ return (-1);
+ return (1);
}
/* --- @txsu_write@ --- *