/* * This file is part of x48, an emulator of the HP-48sx Calculator. * Copyright (C) 1994 Eddie C. Dost (ecd@dressler.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Log: serial.c,v $ * Revision 1.11 1995/01/11 18:20:01 ecd * major update to support HP48 G/GX * * Revision 1.10 1994/12/07 20:20:50 ecd * complete change in handling of serial line, * lines can be turned off now * * Revision 1.10 1994/12/07 20:20:50 ecd * complete change in handling of serial line, * lines can be turned off now * * Revision 1.9 1994/11/28 02:00:51 ecd * added support for drawing the connections in the window title * * Revision 1.8 1994/11/02 14:44:28 ecd * support for HPUX added * * Revision 1.7 1994/10/06 16:30:05 ecd * new init for IRIX * added CREAD for serial line * * Revision 1.6 1994/10/05 08:49:59 ecd * changed printf() to print the correct /dev/ttyp? * * Revision 1.5 1994/09/30 12:37:09 ecd * check if serial device is opened by OPENIO * * Revision 1.4 1994/09/18 15:29:22 ecd * turned off unused rcsid message * * Revision 1.3 1994/09/13 16:57:00 ecd * changed to plain X11 * * Revision 1.2 1994/08/31 18:23:21 ecd * changed IR and wire definitions. * * Revision 1.1 1994/08/26 11:09:02 ecd * Initial revision * * $Id: serial.c,v 1.11 1995/01/11 18:20:01 ecd Exp ecd $ */ #include "global.h" #include #include #include #include #include #include #if defined(HPUX) || defined(CSRG_BASED) # include #endif #include #include #ifdef SOLARIS # include # include # include #endif #include "hp48.h" #include "device.h" #include "hp48_emu.h" #include "resources.h" static int wire_fd; static int ir_fd; static int ttyp; extern int rece_instr; static char *wire_name = (char *)0; static char *ir_name = (char *)0; /* #define DEBUG_SERIAL */ void #ifdef __FunctionProto__ update_connection_display(void) #else update_connection_display() #endif { if (wire_fd == -1) { if (wire_name) free(wire_name); wire_name = (char *)0; } if (ir_fd == -1) { if (ir_name) free(ir_name); ir_name = (char *)0; } ShowConnections(wire_name, ir_name); } int #ifdef __FunctionProto__ serial_init(void) #else serial_init() #endif { char *p; int c; int n; char tty_dev_name[128]; struct termios ttybuf; wire_fd = -1; ttyp = -1; if (useTerminal) { #if defined(IRIX) if ((p = _getpty(&wire_fd, O_RDWR | O_EXCL | O_NDELAY, 0666, 0)) == NULL) { wire_fd = -1; ttyp = -1; } else { if ((ttyp = open(p, O_RDWR | O_NDELAY, 0666)) < 0) { close(wire_fd); wire_fd = -1; ttyp = -1; } else { if (verbose) printf("%s: wire connection on %s\n", progname, p); wire_name = strdup(p); } } #elif defined(SOLARIS) if ((wire_fd = open("/dev/ptmx", O_RDWR | O_NONBLOCK, 0666)) >= 0) { grantpt(wire_fd); unlockpt(wire_fd); p = ptsname(wire_fd); strcpy(tty_dev_name, p); if ((ttyp = open(tty_dev_name, O_RDWR | O_NDELAY, 0666)) >= 0) { ioctl(ttyp, I_PUSH, "ptem"); ioctl(ttyp, I_PUSH, "ldterm"); if (verbose) printf("%s: wire connection on %s\n", progname, tty_dev_name); wire_name = strdup(tty_dev_name); } } #elif defined(LINUX) /* Unix98 PTY (Preferred) */ if ((wire_fd = open("/dev/ptmx", O_RDWR | O_NONBLOCK, 0666)) >= 0) { grantpt(wire_fd); unlockpt(wire_fd); if (ptsname_r(wire_fd, tty_dev_name, 128)) { perror("Could not get the name of the wire device."); exit(-1); } if ((ttyp = open(tty_dev_name, O_RDWR | O_NDELAY, 0666)) >= 0) { if (verbose) printf("%s: wire connection on %s\n", progname, tty_dev_name); wire_name = strdup(tty_dev_name); } } /* BSD PTY (Legacy) */ else { c = 'p'; do { for (n = 0; n < 16; n++) { sprintf(tty_dev_name, "/dev/pty%c%x", c, n); if ((wire_fd = open(tty_dev_name, O_RDWR | O_EXCL | O_NDELAY, 0666)) >= 0) { ttyp = wire_fd; sprintf(tty_dev_name, "/dev/tty%c%x", c, n); if (verbose) printf("%s: wire connection on %s\n", progname, tty_dev_name); wire_name = strdup(tty_dev_name); break; } } c++; } while ((wire_fd < 0) && (errno != ENOENT)); } #else /* * Here we go for SUNOS, HPUX */ c = 'p'; do { for (n = 0; n < 16; n++) { sprintf(tty_dev_name, "/dev/ptyp%x", n); if ((wire_fd = open(tty_dev_name, O_RDWR | O_EXCL | O_NDELAY, 0666)) >= 0) { sprintf(tty_dev_name, "/dev/tty%c%x", c, n); if ((ttyp = open(tty_dev_name, O_RDWR | O_NDELAY, 0666)) < 0) { wire_fd = -1; ttyp = -1; } else { if (verbose) printf("%s: wire connection on %s\n", progname, tty_dev_name); wire_name = strdup(tty_dev_name); break; } } } c++; } while ((wire_fd < 0) && (errno != ENOENT)); #endif } if (ttyp >= 0) { #if defined(TCSANOW) if (tcgetattr(ttyp, &ttybuf) < 0) #else if (ioctl(ttyp, TCGETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(wire, TCGETS) failed, errno = %d\n", progname, errno); wire_fd = -1; ttyp = -1; } } ttybuf.c_lflag = 0; ttybuf.c_iflag = 0; ttybuf.c_oflag = 0; ttybuf.c_cflag = B9600 | CS8 | CLOCAL | CREAD; for (n = 0; n < NCCS; n++) ttybuf.c_cc[n] = 0; ttybuf.c_cc[VTIME] = 0; ttybuf.c_cc[VMIN] = 1; if (ttyp >= 0) { #if defined(TCSANOW) if (tcsetattr(ttyp, TCSANOW, &ttybuf) < 0) #else if (ioctl(ttyp, TCSETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(wire, TCSETS) failed, errno = %d\n", progname, errno); wire_fd = -1; ttyp = -1; } } ir_fd = -1; if (useSerial) { sprintf(tty_dev_name, serialLine); if ((ir_fd = open(tty_dev_name, O_RDWR | O_NDELAY)) >= 0) { if (verbose) printf("%s: IR connection on %s\n", progname, tty_dev_name); ir_name = strdup(tty_dev_name); } } if (ir_fd >= 0) { #if defined(TCSANOW) if (tcgetattr(ir_fd, &ttybuf) < 0) #else if (ioctl(ir_fd, TCGETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(IR, TCGETS) failed, errno = %d\n", progname, errno); ir_fd = -1; } } ttybuf.c_lflag = 0; ttybuf.c_iflag = 0; ttybuf.c_oflag = 0; ttybuf.c_cflag = B9600 | CS8 | CLOCAL | CREAD; for (n = 0; n < NCCS; n++) ttybuf.c_cc[n] = 0; ttybuf.c_cc[VTIME] = 0; ttybuf.c_cc[VMIN] = 1; if (ir_fd >= 0) { #if defined(TCSANOW) if (tcsetattr(ir_fd, TCSANOW, &ttybuf) < 0) #else if (ioctl(ir_fd, TCSETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(IR, TCSETS) failed, errno = %d\n", progname, errno); ir_fd = -1; } } update_connection_display(); return 1; } void #ifdef __FunctionProto__ serial_baud(int baud) #else serial_baud(baud) int baud; #endif { int error = 0; struct termios ttybuf; if (ir_fd >= 0) { #if defined(TCSANOW) if (tcgetattr(ir_fd, &ttybuf) < 0) #else if (ioctl(ir_fd, TCGETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(IR, TCGETS) failed, errno = %d\n", progname, errno); ir_fd = -1; error = 1; } } #if defined(__APPLE__) baud &= 0x7; switch (baud) { case 0: /* 1200 */ ttybuf.c_cflag |= B1200; break; case 1: /* 1920 */ # ifdef B1920 ttybuf.c_cflag |= B1920; # endif break; case 2: /* 2400 */ ttybuf.c_cflag |= B2400; break; case 3: /* 3840 */ # ifdef B3840 ttybuf.c_cflag |= B3840; # endif break; case 4: /* 4800 */ ttybuf.c_cflag |= B4800; break; case 5: /* 7680 */ # ifdef B7680 ttybuf.c_cflag |= B7680; # endif break; case 6: /* 9600 */ ttybuf.c_cflag |= B9600; break; case 7: /* 15360 */ # ifdef B15360 ttybuf.c_cflag |= B15360; # endif break; } if ((ir_fd >= 0) && ((ttybuf.c_ospeed) == 0)) { if (!quiet) LOGE( "%s: can\'t set baud rate, using 9600\n", progname); ttybuf.c_cflag |= B9600; } #else ttybuf.c_cflag &= ~CBAUD; baud &= 0x7; switch (baud) { case 0: /* 1200 */ ttybuf.c_cflag |= B1200; break; case 1: /* 1920 */ # ifdef B1920 ttybuf.c_cflag |= B1920; # endif break; case 2: /* 2400 */ ttybuf.c_cflag |= B2400; break; case 3: /* 3840 */ # ifdef B3840 ttybuf.c_cflag |= B3840; # endif break; case 4: /* 4800 */ ttybuf.c_cflag |= B4800; break; case 5: /* 7680 */ # ifdef B7680 ttybuf.c_cflag |= B7680; # endif break; case 6: /* 9600 */ ttybuf.c_cflag |= B9600; break; case 7: /* 15360 */ # ifdef B15360 ttybuf.c_cflag |= B15360; # endif break; } if ((ir_fd >= 0) && ((ttybuf.c_cflag & CBAUD) == 0)) { if (!quiet) LOGE( "%s: can\'t set baud rate, using 9600\n", progname); ttybuf.c_cflag |= B9600; } #endif if (ir_fd >= 0) { #if defined(TCSANOW) if (tcsetattr(ir_fd, TCSANOW, &ttybuf) < 0) #else if (ioctl(ir_fd, TCSETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(IR, TCSETS) failed, errno = %d\n", progname, errno); ir_fd = -1; error = 1; } } if (ttyp >= 0) { #if defined(TCSANOW) if (tcgetattr(ttyp, &ttybuf) < 0) #else if (ioctl(ttyp, TCGETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(wire, TCGETS) failed, errno = %d\n", progname, errno); wire_fd = -1; ttyp = -1; error = 1; } } #if defined(__APPLE__) #else ttybuf.c_cflag &= ~CBAUD; baud &= 0x7; switch (baud) { case 0: /* 1200 */ ttybuf.c_cflag |= B1200; break; case 1: /* 1920 */ # ifdef B1920 ttybuf.c_cflag |= B1920; # endif break; case 2: /* 2400 */ ttybuf.c_cflag |= B2400; break; case 3: /* 3840 */ # ifdef B3840 ttybuf.c_cflag |= B3840; # endif break; case 4: /* 4800 */ ttybuf.c_cflag |= B4800; break; case 5: /* 7680 */ # ifdef B7680 ttybuf.c_cflag |= B7680; # endif break; case 6: /* 9600 */ ttybuf.c_cflag |= B9600; break; case 7: /* 15360 */ # ifdef B15360 ttybuf.c_cflag |= B15360; # endif break; } if ((ttyp >= 0) && ((ttybuf.c_cflag & CBAUD) == 0)) { if (!quiet) LOGE( "%s: can\'t set baud rate, using 9600\n", progname); ttybuf.c_cflag |= B9600; } #endif if (ttyp >= 0) { #if defined(TCSANOW) if (tcsetattr(ttyp, TCSANOW, &ttybuf) < 0) #else if (ioctl(ttyp, TCSETS, (char *)&ttybuf) < 0) #endif { if (!quiet) LOGE( "%s: ioctl(wire, TCSETS) failed, errno = %d\n", progname, errno); wire_fd = -1; ttyp = -1; error = 1; } } if (error) update_connection_display(); } void #ifdef __FunctionProto__ transmit_char(void) #else transmit_char() #endif { #ifdef DEBUG_SERIALx LOGE( "XMT %s\n", (saturn.ir_ctrl & 0x04) ? "IR" : "wire"); #endif if (saturn.ir_ctrl & 0x04) { if (ir_fd == -1) { saturn.tcs &= 0x0e; if (saturn.io_ctrl & 0x04) { do_interupt(); } return; } } else { if (wire_fd == -1) { saturn.tcs &= 0x0e; if (saturn.io_ctrl & 0x04) { do_interupt(); } return; } } #ifdef DEBUG_SERIAL if (isprint(saturn.tbr)) { LOGE( "-> \'%c\'\n", saturn.tbr); } else { LOGE( "-> %x\n", saturn.tbr); } #endif if (saturn.ir_ctrl & 0x04) { if (write(ir_fd, &saturn.tbr, 1) == 1) { saturn.tcs &= 0x0e; if (saturn.io_ctrl & 0x04) { do_interupt(); } } else { if (errno != EAGAIN) { LOGE( "%s: serial write error: %d\n", progname, errno); } saturn.tcs &= 0x0e; if (saturn.io_ctrl & 0x04) { do_interupt(); } } } else { if (write(wire_fd, &saturn.tbr, 1) == 1) { saturn.tcs &= 0x0e; if (saturn.io_ctrl & 0x04) { do_interupt(); } } else { if (errno != EAGAIN) { if (!quiet) LOGE( "%s: serial write error: %d\n", progname, errno); } saturn.tcs &= 0x0e; if (saturn.io_ctrl & 0x04) { do_interupt(); } } } } #define NR_BUFFER 256 void #ifdef __FunctionProto__ receive_char() #else receive_char() #endif { struct timeval tout; fd_set rfds; int nfd; static unsigned char buf[NR_BUFFER + 1]; static int nrd = 0, bp = 0; #ifdef DEBUG_SERIALx LOGE( "RCV %s\n", (saturn.ir_ctrl & 0x04) ? "IR" : "wire"); #endif rece_instr = 0; if (saturn.ir_ctrl & 0x04) { if (ir_fd == -1) return; } else { if (wire_fd == -1) return; } if (saturn.rcs & 0x01) { return; } if (nrd == 0) { tout.tv_sec = 0; tout.tv_usec = 0; FD_ZERO(&rfds); if (saturn.ir_ctrl & 0x04) { FD_SET(ir_fd, &rfds); nfd = ir_fd + 1; } else { FD_SET(wire_fd, &rfds); nfd = wire_fd + 1; } if ((nfd = select(nfd, &rfds, (fd_set *)0, (fd_set *)0, &tout)) > 0) { #ifdef DEBUG_SERIAL LOGE( "select = %d\n", nfd); #endif if (saturn.ir_ctrl & 0x04) { if (FD_ISSET(ir_fd, &rfds)) { nrd = read(ir_fd, buf, NR_BUFFER); if (nrd < 0) { nrd = 0; return; } bp = 0; } else { return; } } else { if (FD_ISSET(wire_fd, &rfds)) { nrd = read(wire_fd, buf, NR_BUFFER); if (nrd < 0) { nrd = 0; return; } bp = 0; } else { return; } } } else { return; } } if (nrd == 0) { return; } if (!(saturn.io_ctrl & 0x08)) { nrd = 0; return; } saturn.rbr = buf[bp++]; nrd--; saturn.rcs |= 0x01; if (saturn.io_ctrl & 0x02) { do_interupt(); } }