#include "defs.h"
#include "gdbcore.h"
-#include "terminal.h"
#include "target.h"
#include "wait.h"
#include <varargs.h>
#include <signal.h>
#include <string.h>
+#include <sys/types.h>
+#include "serial.h"
extern struct target_ops st2000_ops; /* Forward declaration */
starts. */
int st2000_desc = -1;
-/* stream which is fdopen'd from st2000_desc. Only valid when
- st2000_desc != -1. */
-FILE *st2000_stream;
-
/* Send data to stdebug. Works just like printf. */
static void
{
va_list args;
char *pattern;
+ char buf[200];
va_start(args);
pattern = va_arg(args, char *);
- vfprintf(st2000_stream, pattern, args);
- fflush(st2000_stream);
+ vsprintf(buf, pattern, args);
+ if (!serial_write(buf, strlen(buf)))
+ fprintf(stderr, "serial_write failed: %s\n", safe_strerror(errno));
}
/* Read a character from the remote system, doing all the fancy
timeout stuff. */
static int
-readchar ()
+readchar(timeout)
+ int timeout;
{
- char buf;
-
- buf = '\0';
-#ifdef HAVE_TERMIO
- /* termio does the timeout for us. */
- read (st2000_desc, &buf, 1);
-#else
- alarm (timeout);
- if (read (st2000_desc, &buf, 1) < 0)
+ int c;
+
+ c = serial_readchar(timeout);
+
+#ifdef LOG_FILE
+ putc(c & 0x7f, log_file);
+#endif
+
+ if (c >= 0)
+ return c & 0x7f;
+
+ if (c == -2)
{
- if (errno == EINTR)
- error ("Timeout reading from remote system.");
- else
- perror_with_name ("remote");
+ if (timeout == 0)
+ return c; /* Polls shouldn't generate timeout errors */
+
+ error("Timeout reading from remote system.");
}
- alarm (0);
-#endif
- if (buf == '\0')
- error ("Timeout reading from remote system.");
-#if defined (LOG_FILE)
- putc (buf & 0x7f, log_file);
-#endif
- return buf & 0x7f;
+ perror_with_name("remote-st2000");
}
-/* Keep discarding input from the remote system, until STRING is found.
+/* Scan input from the remote system, until STRING is found. If DISCARD is
+ non-zero, then discard non-matching input, else print it out.
Let the user break out immediately. */
static void
-expect (string)
+expect(string, discard)
char *string;
+ int discard;
{
char *p = string;
+ int c;
immediate_quit = 1;
while (1)
{
- if (readchar() == *p)
+ c = readchar(timeout);
+ if (c == *p++)
{
- p++;
if (*p == '\0')
{
immediate_quit = 0;
}
}
else
- p = string;
+ {
+ if (!discard)
+ {
+ fwrite(string, 1, (p - 1) - string, stdout);
+ putchar((char)c);
+ fflush(stdout);
+ }
+ p = string;
+ }
}
}
necessary to prevent getting into states from which we can't
recover. */
static void
-expect_prompt ()
+expect_prompt(discard)
+ int discard;
{
#if defined (LOG_FILE)
/* This is a convenient place to do this. The idea is to do it often
enough that we never lose much data if we terminate abnormally. */
- fflush (log_file);
+ fflush(log_file);
#endif
- expect ("dbug> ");
+ expect ("dbug> ", discard);
}
/* Get a hex digit from the remote system & return its value.
If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
static int
-get_hex_digit (ignore_space)
+get_hex_digit(ignore_space)
int ignore_space;
{
int ch;
while (1)
{
- ch = readchar ();
+ ch = readchar(timeout);
if (ch >= '0' && ch <= '9')
return ch - '0';
else if (ch >= 'A' && ch <= 'F')
;
else
{
- expect_prompt ();
- error ("Invalid hex digit from remote system.");
+ expect_prompt(1);
+ error("Invalid hex digit from remote system.");
}
}
}
-/* Get a byte from st2000_desc and put it in *BYT. Accept any number
+/* Get a byte from stdebug and put it in *BYT. Accept any number
leading spaces. */
static void
get_hex_byte (byt)
}
}
-/* Called when SIGALRM signal sent due to alarm() timeout. */
-#ifndef HAVE_TERMIO
-
-#ifndef __STDC__
-#define volatile /**/
-#endif
-volatile int n_alarms;
-
-static void
-st2000_timer ()
-{
- n_alarms++;
-}
-#endif
-
/* This is called not only when we first attach, but also when the
user types "run" after having attached. */
static void
int entry_pt;
if (args && *args)
- error ("Can't pass arguments to remote STDEBUG process");
+ error("Can't pass arguments to remote STDEBUG process");
if (execfile == 0 || exec_bfd == 0)
- error ("No exec file specified");
+ error("No exec file specified");
entry_pt = (int) bfd_get_start_address (exec_bfd);
proceed ((CORE_ADDR)entry_pt, -1, 0); /* Let 'er rip... */
}
-/* Translate baud rates from integers to damn B_codes. Unix should
- have outgrown this crap years ago, but even POSIX wouldn't buck it. */
-
-#ifndef B19200
-#define B19200 EXTA
-#endif
-#ifndef B38400
-#define B38400 EXTB
-#endif
-
-static struct {int rate, damn_b;} baudtab[] = {
- {0, B0},
- {50, B50},
- {75, B75},
- {110, B110},
- {134, B134},
- {150, B150},
- {200, B200},
- {300, B300},
- {600, B600},
- {1200, B1200},
- {1800, B1800},
- {2400, B2400},
- {4800, B4800},
- {9600, B9600},
- {19200, B19200},
- {38400, B38400},
- {-1, -1},
-};
-
-static int
-damn_b (rate)
- int rate;
-{
- int i;
-
- for (i = 0; baudtab[i].rate != -1; i++)
- if (rate == baudtab[i].rate) return baudtab[i].damn_b;
- return B38400; /* Random */
-}
-
-
/* Open a connection to a remote debugger.
NAME is the filename used for communication. */
static int baudrate = 9600;
-static char *dev_name;
-
-static TERMINAL old_sg;
+static char dev_name[100];
static void
-st2000_open (name, from_tty)
- char *name;
+st2000_open(args, from_tty)
+ char *args;
int from_tty;
{
- TERMINAL sg;
-
- char *p;
+ int n;
+ char junk[100];
- target_preopen (from_tty);
-
- if (!name)
- goto erroid;
-
- /* Find the first whitespace character, it separates dev_name from
- the baud rate. */
-
- for (p = name; *p && !isspace (*p); p++)
- ;
- if (*p == '\0')
-erroid:
- error ("\
-Please include the name of the device for the serial port, and the baud rate.");
-
- dev_name = alloca (p - name + 1);
- strncpy (dev_name, name, p - name);
- dev_name[p - name] = '\0';
-
- /* Skip over the whitespace after dev_name */
- for (; isspace (*p); p++)
- /*EMPTY*/;
+ target_preopen(from_tty);
- if (1 != sscanf (p, "%d ", &baudrate))
- goto erroid;
+ n = sscanf(args, " %s %d %s", dev_name, &baudrate, junk);
- st2000_close (0);
+ if (n != 2)
+ error("Bad arguments. Usage: target st2000 <device> <speed>\n\
+or target st2000 <host> <port>\n");
- st2000_desc = open (dev_name, O_RDWR);
- if (st2000_desc < 0)
- perror_with_name (dev_name);
- ioctl (st2000_desc, TIOCGETP, &sg);
- old_sg = sg;
-
-#ifdef HAVE_TERMIO
- sg.c_cc[VMIN] = 0; /* read with timeout. */
- sg.c_cc[VTIME] = timeout * 10;
- sg.c_lflag &= ~(ICANON | ECHO);
- sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate);
-#else
- sg.sg_ispeed = damn_b (baudrate);
- sg.sg_ospeed = damn_b (baudrate);
- sg.sg_flags |= RAW | ANYP;
- sg.sg_flags &= ~ECHO;
-#endif
+ st2000_close(0);
- ioctl (st2000_desc, TIOCSETP, &sg);
- st2000_stream = fdopen (st2000_desc, "r+");
+ st2000_desc = serial_open(dev_name);
- push_target (&st2000_ops);
+ serial_setbaudrate(baudrate);
-#ifndef HAVE_TERMIO
-#ifndef NO_SIGINTERRUPT
- /* Cause SIGALRM's to make reads fail with EINTR instead of resuming
- the read. */
- if (siginterrupt (SIGALRM, 1) != 0)
- perror ("st2000_open: error in siginterrupt");
-#endif
-
- /* Set up read timeout timer. */
- if ((void (*)) signal (SIGALRM, st2000_timer) == (void (*)) -1)
- perror ("st2000_open: error in signal");
-#endif
+ push_target(&st2000_ops);
#if defined (LOG_FILE)
log_file = fopen (LOG_FILE, "w");
#endif
/* Hello? Are you there? */
- printf_stdebug ("\r");
+ printf_stdebug("\003"); /* ^C wakes up dbug */
- expect_prompt ();
+ expect_prompt(1);
if (from_tty)
- printf ("Remote %s connected to %s\n", target_shortname,
- dev_name);
+ printf("Remote %s connected to %s\n", target_shortname,
+ dev_name);
}
/* Close out all files and local state before this target loses control. */
st2000_close (quitting)
int quitting;
{
-
- /* Reset the terminal to its original settings. */
-
- ioctl (st2000_desc, TIOCSETP, &old_sg);
-
- /* Due to a bug in Unix, fclose closes not only the stdio stream,
- but also the file descriptor. So we don't actually close
- st2000_desc. */
- if (st2000_stream)
- fclose (st2000_stream); /* This also closes st2000_desc */
-
- /* Do not try to close st2000_desc again, later in the program. */
- st2000_stream = NULL;
- st2000_desc = -1;
+ serial_close();
#if defined (LOG_FILE)
if (log_file) {
- if (ferror (log_file))
- printf ("Error writing log file.\n");
- if (fclose (log_file) != 0)
- printf ("Error closing log file.\n");
+ if (ferror(log_file))
+ fprintf(stderr, "Error writing log file.\n");
+ if (fclose(log_file) != 0)
+ fprintf(stderr, "Error closing log file.\n");
}
#endif
}
{
printf_stdebug ("ST\r");
/* Wait for the echo. */
- expect ("ST\r");
+ expect ("ST\r", 1);
}
else
{
printf_stdebug ("GO\r");
/* Swallow the echo. */
- expect ("GO\r");
+ expect ("GO\r", 1);
}
}
st2000_wait (status)
WAITTYPE *status;
{
- /* FIXME --- USE A REAL STRING MATCHING ALGORITHM HERE!!! */
-
- static char bpt[] = "dbug> ";
- char *bp = bpt;
-
- /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. */
- char swallowed[50];
- /* Current position in swallowed. */
- char *swallowed_p = swallowed;
-
- int ch;
- int ch_handled;
-
int old_timeout = timeout;
WSETEXIT ((*status), 0);
timeout = 0; /* Don't time out -- user program is running. */
- while (1)
- {
- ch_handled = 0;
- ch = readchar ();
- if (ch == *bp)
- {
- bp++;
- if (*bp == '\0')
- break;
- ch_handled = 1;
- *swallowed_p++ = ch;
- }
- else
- bp = bpt;
+ expect_prompt(0); /* Wait for prompt, outputting extraneous text */
+
+ WSETSTOP ((*status), SIGTRAP);
- if (!ch_handled)
- {
- char *p;
-
- /* Print out any characters which have been swallowed. */
- for (p = swallowed; p < swallowed_p; ++p)
- putc (*p, stdout);
- swallowed_p = swallowed;
-
- putc (ch, stdout);
- }
- }
- if (*bp == '\000')
- WSETSTOP ((*status), SIGTRAP);
- else
- WSETEXIT ((*status), 0);
timeout = old_timeout;
return 0;
{
char *name = get_reg_name (regno);
printf_stdebug ("DR %s\r", name);
- expect (name);
- expect (" : ");
+ expect (name, 1);
+ expect (" : ", 1);
get_hex_regs (1, regno);
- expect_prompt ();
+ expect_prompt (1);
}
return;
}
printf_stdebug ("PR %s %x\r", get_reg_name (regno),
read_register (regno));
- expect_prompt ();
+ expect_prompt (1);
}
}
for (i = 0; i < len; i++)
{
printf_stdebug ("PM.B %x %x\r", memaddr + i, myaddr[i]);
- expect_prompt ();
+ expect_prompt (1);
}
return len;
}
len_this_pass = (len - count);
printf_stdebug ("DI.L %x %x\r", startaddr, len_this_pass);
- expect (": ");
+ expect (": ", 1);
for (i = 0; i < len_this_pass; i++)
get_hex_byte (&myaddr[count++]);
- expect_prompt ();
+ expect_prompt (1);
startaddr += len_this_pass;
}
st2000_read_inferior_memory(addr, shadow, memory_breakpoint_size);
printf_stdebug("BR %x H\r", addr);
- expect_prompt();
+ expect_prompt(1);
return 0;
}
breakaddr[i] = 0;
printf_stdebug("CB %d\r", i);
- expect_prompt();
+ expect_prompt(1);
return 0;
}
return 1;
}
+
+/* Put a command string, in args, out to STDBUG. Output from STDBUG is placed
+ on the users terminal until the prompt is seen. */
+
+static void
+st2000_command (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ if (st2000_desc < 0)
+ error("st2000 target not open.");
+
+ if (!args)
+ error("Missing command.");
+
+ printf_stdebug("%s\r", args);
+ expect_prompt(0);
+}
+
+/* Connect the user directly to STDBUG. This command acts just like the
+ 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
+
+static struct ttystate ttystate;
+
+static void
+cleanup_tty()
+{
+ printf("\r\n[Exiting connect mode]\r\n");
+ serial_restore(0, &ttystate);
+}
+
+static void
+connect_command (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ fd_set readfds;
+ int numfds;
+ int c;
+ char cur_esc = 0;
+
+ dont_repeat();
+
+ if (st2000_desc < 0)
+ error("st2000 target not open.");
+
+ if (args)
+ fprintf("This command takes no args. They have been ignored.\n");
+
+ printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
+
+ serial_raw(0, &ttystate);
+
+ make_cleanup(cleanup_tty, 0);
+
+ FD_ZERO(&readfds);
+
+ while (1)
+ {
+ do
+ {
+ FD_SET(0, &readfds);
+ FD_SET(st2000_desc, &readfds);
+ numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
+ }
+ while (numfds == 0);
+
+ if (numfds < 0)
+ perror_with_name("select");
+
+ if (FD_ISSET(0, &readfds))
+ { /* tty input, send to stdebug */
+ c = getchar();
+ if (c < 0)
+ perror_with_name("connect");
+
+ printf_stdebug("%c", c);
+ switch (cur_esc)
+ {
+ case 0:
+ if (c == '\r')
+ cur_esc = c;
+ break;
+ case '\r':
+ if (c == '~')
+ cur_esc = c;
+ else
+ cur_esc = 0;
+ break;
+ case '~':
+ if (c == '.' || c == '\004')
+ return;
+ else
+ cur_esc = 0;
+ }
+ }
+
+ if (FD_ISSET(st2000_desc, &readfds))
+ {
+ while (1)
+ {
+ c = readchar(0);
+ if (c < 0)
+ break;
+ putchar(c);
+ }
+ fflush(stdout);
+ }
+ }
+}
+
/* Define the target subroutine names */
-static struct target_ops st2000_ops = {
- "st2000", "Remote serial Tandem ST2000 target",
- "Use a remote computer running STDEBUG connected by a serial line,\n\
+struct target_ops st2000_ops = {
+ "st2000",
+ "Remote serial Tandem ST2000 target",
+ "Use a remote computer running STDEBUG connected by a serial line,\n\
or a network connection.\n\
Arguments are the name of the device for the serial line,\n\
the speed to connect at in bits per second.",
- st2000_open, st2000_close,
- 0, st2000_detach, st2000_resume, st2000_wait,
- st2000_fetch_register, st2000_store_register,
- st2000_prepare_to_store, 0, 0, /* conv_to, conv_from */
- st2000_xfer_inferior_memory, st2000_files_info,
- st2000_insert_breakpoint, st2000_remove_breakpoint, /* Breakpoints */
- 0, 0, 0, 0, 0, /* Terminal handling */
- st2000_kill,
- 0, /* load */
- 0, /* lookup_symbol */
- st2000_create_inferior,
- st2000_mourn_inferior,
- process_stratum, 0, /* next */
- 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
- 0, 0, /* Section pointers */
- OPS_MAGIC, /* Always the last thing */
+ st2000_open,
+ st2000_close,
+ 0,
+ st2000_detach,
+ st2000_resume,
+ st2000_wait,
+ st2000_fetch_register,
+ st2000_store_register,
+ st2000_prepare_to_store,
+ 0,
+ 0, /* conv_to, conv_from */
+ st2000_xfer_inferior_memory,
+ st2000_files_info,
+ st2000_insert_breakpoint,
+ st2000_remove_breakpoint, /* Breakpoints */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, /* Terminal handling */
+ st2000_kill,
+ 0, /* load */
+ 0, /* lookup_symbol */
+ st2000_create_inferior,
+ st2000_mourn_inferior,
+ process_stratum,
+ 0, /* next */
+ 1,
+ 1,
+ 1,
+ 1,
+ 1, /* all mem, mem, stack, regs, exec */
+ 0,
+ 0, /* Section pointers */
+ OPS_MAGIC, /* Always the last thing */
};
void
_initialize_remote_st2000 ()
{
add_target (&st2000_ops);
+ add_com ("st2000 <command>", class_obscure, st2000_command,
+ "Send a command to the STDBUG monitor.");
+ add_com ("connect", class_obscure, connect_command,
+ "Connect the terminal directly up to the STDBUG command monitor.\n\
+Use <CR>~. or <CR>~^D to break out.");
}
--- /dev/null
+/* Remote serial interface for OS's with sgttyb
+ Copyright 1992 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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. */
+
+#include "defs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include "serial.h"
+
+static int desc = -1;
+
+void
+serial_raw(fd, oldstate)
+ int fd;
+ struct ttystate *oldstate;
+{
+ struct sgttyb sgttyb;
+
+ oldstate->flags = fcntl(fd, F_GETFL, 0);
+
+ fcntl(fd, F_SETFL, oldstate->flags|FNDELAY);
+
+ if (ioctl(fd, TIOCGETP, &sgttyb))
+ {
+ fprintf(stderr, "TIOCGETP failed: %s\n", safe_strerror(errno));
+ }
+
+ oldstate->sgttyb = sgttyb;
+
+ sgttyb.sg_flags = RAW;
+
+ if (ioctl(fd, TIOCSETP, &sgttyb))
+ {
+ fprintf(stderr, "TIOCSETP failed: %s\n", safe_strerror(errno));
+ }
+}
+
+void
+serial_restore(fd, oldstate)
+ int fd;
+ struct ttystate *oldstate;
+{
+ fcntl(fd, F_SETFL, oldstate->flags);
+
+ ioctl(fd, TIOCSETP, &oldstate->sgttyb);
+}
+
+static struct ttystate oldstate;
+
+static fd_set readfds;
+
+int
+serial_open(name)
+ char *name;
+{
+ struct sgttyb sgttyb;
+
+ desc = open (name, O_RDWR);
+ if (desc < 0)
+ error("Open of %s failed: %s", name, safe_strerror(errno));
+
+ serial_raw(desc, &oldstate);
+
+/* Setup constant stuff for select */
+
+ FD_ZERO(&readfds);
+
+ return desc;
+}
+
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns -2 if timeout expired, EOF if line dropped
+ dead, or -3 for any other error (see errno in that case). */
+
+int
+serial_readchar(timeout)
+ int timeout;
+{
+ static unsigned char buf[BUFSIZ];
+ static unsigned char *bufp;
+ static int bufcnt = 0;
+ int numfds;
+ struct timeval tv;
+
+ if (bufcnt-- > 0)
+ return *bufp++;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_SET(desc, &readfds);
+
+ if (timeout >= 0)
+ numfds = select(desc+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(desc+1, &readfds, 0, 0, 0);
+
+ if (numfds <= 0)
+ if (numfds == 0)
+ return -2; /* Timeout */
+ else
+ return -3; /* Got an error from select */
+
+ bufcnt = read(desc, buf, BUFSIZ);
+
+ if (bufcnt <= 0)
+ if (bufcnt == 0)
+ return EOF; /* 0 chars means end of file */
+ else
+ return -3; /* Got an error from read */
+
+ bufcnt--;
+ bufp = buf;
+ return *bufp++;
+}
+
+#ifndef B19200
+#define B19200 EXTA
+#endif
+
+#ifndef B38400
+#define B38400 EXTB
+#endif
+
+/* Translate baud rates from integers to damn B_codes. Unix should
+ have outgrown this crap years ago, but even POSIX wouldn't buck it. */
+
+static struct
+{
+ int rate;
+ int code;
+} baudtab[] = {
+ {50, B50},
+ {75, B75},
+ {110, B110},
+ {134, B134},
+ {150, B150},
+ {200, B200},
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {1800, B1800},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+ {19200, B19200},
+ {38400, B38400},
+ {-1, -1},
+};
+
+static int
+rate_to_code(rate)
+ int rate;
+{
+ int i;
+
+ for (i = 0; baudtab[i].rate != -1; i++)
+ if (rate == baudtab[i].rate)
+ return baudtab[i].code;
+
+ return -1;
+}
+
+int
+serial_setbaudrate(rate)
+ int rate;
+{
+ struct sgttyb sgttyb;
+
+ if (ioctl(desc, TIOCGETP, &sgttyb))
+ error("TIOCGETP failed: %s\n", safe_strerror(errno));
+
+ sgttyb.sg_ospeed = rate_to_code(rate);
+ sgttyb.sg_ispeed = rate_to_code(rate);
+
+ if (ioctl(desc, TIOCSETP, &sgttyb))
+ error("TIOCSETP failed: %s\n", safe_strerror(errno));
+
+ return 1;
+}
+
+int
+serial_write(str, len)
+ char *str;
+ int len;
+{
+ int cc;
+
+ while (len > 0)
+ {
+ cc = write(desc, str, len);
+
+ if (cc < 0)
+ return 0;
+ len -= cc;
+ str += cc;
+ }
+ return 1;
+}
+
+void
+serial_close()
+{
+ if (desc < 0)
+ return;
+
+ serial_restore(desc, oldstate);
+
+ close(desc);
+ desc = -1;
+}
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
-#include "serial.h"
#include <fcntl.h>
-#include <termios.h>
#include <sys/time.h>
+#include "serial.h"
-/* File descriptor used in termios routines to access serial line. */
-static int desc;
-
-/* Saved state about the terminal. */
-static struct termios otermios;
-static int oflags;
-
-const char *
-serial_default_name ()
-{
- return "/dev/ttya";
-}
+static int desc = -1;
void
-serial_raw ()
+serial_raw(fd, oldstate)
+ int fd;
+ struct ttystate *oldstate;
{
- /* Now happens inside of serial_open */
+ struct termios termios;
+
+ oldstate->flags = fcntl(fd, F_GETFL, 0);
+
+ fcntl(fd, F_SETFL, oldstate->flags|FNDELAY);
+
+ if (tcgetattr(fd, &termios))
+ {
+ fprintf(stderr, "tcgetattr failed: %s\n", safe_strerror(errno));
+ }
+
+ oldstate->termios = termios;
+
+ termios.c_iflag = 0;
+ termios.c_oflag = 0;
+ termios.c_lflag = 0;
+ termios.c_cc[VMIN] = 0;
+ termios.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSANOW, &termios))
+ {
+ fprintf(stderr, "tcsetattr failed: %s\n", safe_strerror(errno));
+ }
}
void
-serial_normal ()
+serial_restore(fd, oldstate)
+ int fd;
+ struct ttystate *oldstate;
{
- fcntl(desc, oflags, 0);
+ fcntl(fd, F_SETFL, oldstate->flags);
- if (tcsetattr(desc, TCSANOW, &otermios))
- {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ tcsetattr(fd, TCSANOW, &oldstate->termios);
}
+static struct ttystate oldstate;
+
+static fd_set readfds;
+
int
-serial_open (name)
- const char *name;
+serial_open(name)
+ char *name;
{
struct termios termios;
desc = open (name, O_RDWR);
if (desc < 0)
- perror("Open failed: ");
-
- oflags = fcntl(desc, F_GETFL, 0);
-
- fcntl(desc, F_SETFL, oflags|FNDELAY);
+ error("Open of %s failed: %s", name, safe_strerror(errno));
- if (tcgetattr(desc, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ serial_raw(desc, &oldstate);
- otermios = termios;
+/* Setup constant stuff for select */
- termios.c_iflag = 0;
- termios.c_oflag = 0;
- termios.c_lflag = 0;
- termios.c_cc[VMIN] = 0;
- termios.c_cc[VTIME] = 0;
-
- if (tcsetattr(desc, TCSANOW, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ FD_ZERO(&readfds);
- return 1;
+ return desc;
}
+/* Read a character with user-specified timeout. TIMEOUT is number of seconds
+ to wait, or -1 to wait forever. Use timeout of 0 to effect a poll. Returns
+ char if successful. Returns -2 if timeout expired, EOF if line dropped
+ dead, or -3 for any other error (see errno in that case). */
+
int
-serial_timedreadchar (timeout, ok)
- int timeout;
- int *ok;
+serial_readchar(timeout)
+ int timeout;
{
- unsigned char buf;
- fd_set readfds;
- int val;
+ static unsigned char buf[BUFSIZ];
+ static unsigned char *bufp;
+ static int bufcnt = 0;
+ int numfds;
struct timeval tv;
- FD_ZERO(&readfds);
- FD_SET(desc, &readfds);
+ if (bufcnt-- > 0)
+ return *bufp++;
tv.tv_sec = timeout;
tv.tv_usec = 0;
- val = select(desc+1, &readfds, 0, 0, &tv);
+ FD_SET(desc, &readfds);
- if (val > 0 && FD_ISSET(desc, &readfds))
- {
- val = read (desc, &buf, 1);
+ if (timeout >= 0)
+ numfds = select(desc+1, &readfds, 0, 0, &tv);
+ else
+ numfds = select(desc+1, &readfds, 0, 0, 0);
- if (val == 1)
- {
- *ok = 1;
- return buf;
- }
- }
+ if (numfds <= 0)
+ if (numfds == 0)
+ return -2; /* Timeout */
+ else
+ return -3; /* Got an error from select */
+
+ bufcnt = read(desc, buf, BUFSIZ);
- *ok = 0;
+ if (bufcnt <= 0)
+ if (bufcnt == 0)
+ return EOF; /* 0 chars means end of file */
+ else
+ return -3; /* Got an error from read */
- return 0;
+ bufcnt--;
+ bufp = buf;
+ return *bufp++;
}
/* Translate baud rates from integers to damn B_codes. Unix should
have outgrown this crap years ago, but even POSIX wouldn't buck it. */
-#ifndef B19200
-#define B19200 EXTA
-#endif
-#ifndef B38400
-#define B38400 EXTB
-#endif
-
-static struct {int rate, damn_b;} baudtab[] = {
- {9600, B9600},
-
- {19200, B19200},
- {38400, B38400},
-#if 0
- {300, B300},
- {1200, B1200},
- {2400, B2400},
- {4800, B4800},
-#endif
- {-1, -1},
+static struct
+{
+ int rate;
+ int code;
+} baudtab[] = {
+ {50, B50},
+ {75, B75},
+ {110, B110},
+ {134, B134},
+ {150, B150},
+ {200, B200},
+ {300, B300},
+ {600, B600},
+ {1200, B1200},
+ {1800, B1800},
+ {2400, B2400},
+ {4800, B4800},
+ {9600, B9600},
+ {19200, B19200},
+ {38400, B38400},
+ {-1, -1},
};
static int
-damn_b (rate)
- int rate;
+rate_to_code(rate)
+ int rate;
{
int i;
+
for (i = 0; baudtab[i].rate != -1; i++)
- {
if (rate == baudtab[i].rate)
- {
- return i;
- }
- }
+ return baudtab[i].code;
+
return -1;
}
-int
-serial_setbaudrate (rate)
+int
+serial_setbaudrate(rate)
int rate;
{
struct termios termios;
- if (tcgetattr(desc, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ if (tcgetattr(desc, &termios))
+ error("tcgetattr failed: %s\n", safe_strerror(errno));
- cfsetospeed(&termios, baudtab[damn_b(rate)].damn_b);
- cfsetispeed(&termios, baudtab[damn_b(rate)].damn_b);
+ cfsetospeed(&termios, rate_to_code(rate));
+ cfsetispeed(&termios, rate_to_code(rate));
- if (tcsetattr(desc, TCSANOW, &termios)) {
- printf("tcgetattr failed: errno=%d\n", errno);
- }
+ if (tcsetattr(desc, TCSANOW, &termios))
+ error("tcsetattr failed: %s\n", safe_strerror(errno));
return 1;
}
int
-serial_nextbaudrate (rate)
- int rate;
+serial_write(str, len)
+ char *str;
+ int len;
{
- int lookup;
- lookup = damn_b(rate);
- if (lookup == -1)
- return baudtab[0].rate;
- lookup++;
- if (baudtab[lookup].rate == -1)
- return baudtab[0].rate;
- return baudtab[lookup].rate;
+ int cc;
+
+ while (len > 0)
+ {
+ cc = write(desc, str, len);
+
+ if (cc < 0)
+ return 0;
+ len -= cc;
+ str += cc;
+ }
+ return 1;
}
-int
-serial_write (str, len)
- const char *str;
- int len;
+void
+serial_close()
{
- return (write (desc, str, len));
-}
+ if (desc < 0)
+ return;
+ serial_restore(desc, oldstate);
-int
-serial_close ()
-{
- return (close(desc));
+ close(desc);
+ desc = -1;
}