ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/arch/unix/rs232.c

This is rs232.c in view mode; [Download] [Up]

/*
 * rs232.c - RS232 emulation.
 *
 * Written by
 *  André Fachat (a.fachat@physik.tu-chemnitz.de)
 *
 * This file is part of VICE, the Versatile Commodore Emulator.
 * See README for copyright notice.
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307  USA.
 *
 */

/*
 * The RS232 emulation captures the bytes sent to the RS232 interfaces
 * available (currently only ACIA 6551, later UART 16550A, std C64,
 * and Daniel Dallmanns fast RS232 with 9600 Baud).
 * The characters captured are displayed in a special terminal window.
 * Characters typed in the terminal window are sent back to the
 * chip emulations.
 *
 */

#undef        DEBUG

#include <stdio.h>

#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>

#include "vice.h"
#include "types.h"
#include "resources.h"
#include "cmdline.h"
#include "rs232.h"
#include "utils.h"
#include "coproc.h"

#define        MAXRS232        4

/*********************************************************************/
/* resource handling */

#define	NUM_DEVICES	4

static char *devfile[NUM_DEVICES];
static int devbaud[NUM_DEVICES];

static int set_devfile(char *v, int dev) {
    const char *name = (const char *) v;
/*printf("set_devfile(v=%s, dev=%d)\n",v,dev);*/
    if (devfile[dev] != NULL && name != NULL
        && strcmp(name, devfile[dev]) == 0)
        return 0;

    string_set(&devfile[dev], name);
    return 0;
}

static int set_devbaud(int v, int dev) {
    devbaud[dev] = v;
    return 0;
}

/********************************/

static int set_dev1_file(resource_value_t v) {
    return set_devfile((char*)v, 0);
}

static int set_dev2_file(resource_value_t v) {
    return set_devfile((char*)v, 1);
}

static int set_dev3_file(resource_value_t v) {
    return set_devfile((char*)v, 2);
}

static int set_dev4_file(resource_value_t v) {
    return set_devfile((char*)v, 3);
}

static int set_dev1_baud(resource_value_t v) {
    return set_devbaud((int)v, 0);
}

static int set_dev2_baud(resource_value_t v) {
    return set_devbaud((int)v, 1);
}

static int set_dev3_baud(resource_value_t v) {
    return set_devbaud((int)v, 2);
}

static int set_dev4_baud(resource_value_t v) {
    return set_devbaud((int)v, 3);
}


static resource_t resources[] = {
    { "RsDevice1", RES_STRING, (resource_value_t) "/dev/ttyS0",
      (resource_value_t *) &devfile[0], set_dev1_file },
    { "RsDevice1Baud", RES_INTEGER, (resource_value_t) 9600,
      (resource_value_t *) &devbaud[0], set_dev1_baud },
    { "RsDevice2", RES_STRING, (resource_value_t) "/dev/ttyS1",
      (resource_value_t *) &devfile[1], set_dev2_file },
    { "RsDevice2Baud", RES_INTEGER, (resource_value_t) 9600,
      (resource_value_t *) &devbaud[1], set_dev2_baud },
    { "RsDevice3", RES_STRING, (resource_value_t) "rs232.dump",
      (resource_value_t *) &devfile[2], set_dev3_file },
    { "RsDevice3Baud", RES_INTEGER, (resource_value_t) 9600,
      (resource_value_t *) &devbaud[2], set_dev3_baud },
    { "RsDevice4", RES_STRING, (resource_value_t) "|lpr",
      (resource_value_t *) &devfile[3], set_dev4_file },
    { "RsDevice4Baud", RES_INTEGER, (resource_value_t) 9600,
      (resource_value_t *) &devbaud[3], set_dev4_baud },
    { NULL }
};

int rs232_init_resources(void)
{
    return resources_register(resources);
}

static cmdline_option_t cmdline_options[] = {
    { "-rsdev1", SET_RESOURCE, 1, NULL, NULL, "RsDevice1", NULL,
      "<name>", "Specify name of first RS232 device (/dev/ttyS0)" },
    { "-rsdev1baud", SET_RESOURCE, 1, NULL, NULL, "RsDevice1Baud", NULL,
      "<baudrate>", "Specify baudrate of first RS232 device" },

    { "-rsdev2", SET_RESOURCE, 1, NULL, NULL, "RsDevice2", NULL,
      "<name>", "Specify name of second RS232 device (/dev/ttyS1)" },
    { "-rsdev2baud", SET_RESOURCE, 1, NULL, NULL, "RsDevice2Baud", NULL,
      "<baudrate>", "Specify baudrate of second RS232 device" },

    { "-rsdev3", SET_RESOURCE, 1, NULL, NULL, "RsDevice3", NULL,
      "<name>", "Specify name of third RS232 device (rs232.dump)" },
    { "-rsdev3baud", SET_RESOURCE, 1, NULL, NULL, "RsDevice3Baud", NULL,
      "<baudrate>", "Specify baudrate of third RS232 device" },

    { "-rsdev4", SET_RESOURCE, 1, NULL, NULL, "RsDevice4", NULL,
      "<name>", "Specify command to pipe data in/out, preceed with '|' (|lpr)" },
    { "-rsdev4baud", SET_RESOURCE, 1, NULL, NULL, "RsDevice4Baud", NULL,
      "<baudrate>", "Specify baudrate of 4th RS232 device" },

    { NULL }
};

int rs232_init_cmdline_options(void)
{
    return cmdline_register_options(cmdline_options);
}

/*********************************************************************/

typedef struct RS232 {
       int     inuse;
       int     type;
       int     fd_r;
       int     fd_w;
       char    *file;
       struct termios saved;
} RS232;

#define	T_FILE		0
#define	T_TTY		1
#define	T_PROC		2

static RS232 fds[MAXRS232];

/* initializes all RS232 stuff */
void rs232_init(void) {
       int i;

       for(i=0;i<MAXRS232;i++) {
         fds[i].inuse = 0;
       }
}

/* resets terminal to old mode */
static void unset_tty(int i) {
	tcsetattr(fds[i].fd_r, TCSAFLUSH, &fds[i].saved);
}

static struct { int baud; speed_t speed; } speed_tab[]= {
	{ 300, B300 }, { 600, B600 }, { 1200, B1200 }, { 1800, B1800 },
	{ 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 },
	{ 19200, B19200 }, { 38400, B38400 },
	{ 0, B9600 } /* fallback */
};

/* sets terminal to raw mode */
static void set_tty(int i, int baud) {
       /*
	* set tty to raw mode as of
	* "Advanced Programming in the Unix Environment"
	* by W.R. Stevens, Addison-Wesley.
	*/
	speed_t speed;
	int fd = fds[i].fd_r;
	struct termios buf;

	if(tcgetattr(fd, &fds[i].saved) < 0) {
	  return /* -1 */;
	}
	buf = fds[i].saved;

	buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
		/* echho off, cononical mode off, extended input processing
		 * off, signal chars off */
	buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
		/* no SIGINT on Break, CR-to-NL off, input parity check off,
		 * don't strip 8th bit on input, output flow control off */
	buf.c_cflag &= ~(CSIZE | PARENB);
		/* clear size bits, parity checking off */
	buf.c_cflag |= CS8;
		/* set 8 bits/char */
	buf.c_oflag &= ~(OPOST);
		/* ouput processing off */
	buf.c_cc[VMIN] = 1;	/* 1 byte at a time, no timer */
	buf.c_cc[VTIME] = 0;

	for(i=0;speed_tab[i].baud;i++) {
	  if(speed_tab[i].baud >= baud) break;
	}
	speed = speed_tab[i].speed;

	cfsetispeed(&buf, speed);
	cfsetospeed(&buf, speed);

	tcsetattr(fd, TCSAFLUSH, &buf);
}

/* reset RS232 stuff */
void rs232_reset(void) {
       int i;

       for(i=0;i<MAXRS232;i++) {
         if(fds[i].inuse) {
	    rs232_close(i);
	 }
       }
}

/* opens a rs232 window, returns handle to give to functions below. */
int rs232_open(int device) {
       int i, fd;

       for(i=0;i<MAXRS232;i++) {
         if(!fds[i].inuse) break;
       }
       if(i>=MAXRS232) {
	 fprintf(stderr,"RS232: No device available!\n");
	 return -1;
       }
#ifdef DEBUG
       fprintf(stderr,"rs232_open(device=%d)\n",device);
#endif
       if(devfile[device][0] == '|') {
	 if(fork_coproc(&fds[i].fd_w, &fds[i].fd_r, devfile[device]+1) < 0) {
           fprintf(stderr,"coproc(%s): %s\n",devfile[device],strerror(errno));
	   return -1;
	 }
         fds[i].type = T_PROC;
         fds[i].inuse = 1;
         fds[i].file = devfile[device];
       } else {
         fd = open(devfile[device], O_RDWR | O_NOCTTY | O_CREAT,
			S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
         if(fd<0) {
           fprintf(stderr,"open(%s): %s\n",devfile[device],strerror(errno));
           return -1;
         }
         fds[i].fd_r = fds[i].fd_w = fd;
         fds[i].file = devfile[device];

         if(isatty(fd)) {
	   fds[i].type = T_TTY;
	   set_tty(i, devbaud[device]);
         } else {
	   fds[i].type = T_FILE;
         }
         fds[i].inuse = 1;
       }

       return i;
}

/* closes the rs232 window again */
void rs232_close(int fd) {
#ifdef DEBUG
       fprintf(stderr,"RS232 close(fd=%d)\n",fd);
#endif
       if(fd<0 || fd>=MAXRS232) {
         fprintf(stderr, "RS232: close with invalid fd %d!\n", fd);
         return;
       }

       if(!fds[fd].inuse) {
         fprintf(stderr, "RS232: close with non-open fd %d!\n", fd);
         return;
       }

       if(fds[fd].type == T_TTY) {
         unset_tty(fd);
       }
       close(fds[fd].fd_r);
       if((fds[fd].type == T_PROC) && (fds[fd].fd_r != fds[fd].fd_w)) {
         close(fds[fd].fd_w);
       }
       fds[fd].inuse = 0;
}

/* sends a byte to the RS232 line */
int rs232_putc(int fd, BYTE b) {
       size_t n;

       if(fd<0 || fd>=MAXRS232 || !fds[fd].inuse) {
         fprintf(stderr, "RS232: putc with invalid or non-open fd %d!\n", fd);
         return -1;
       }

       /* for the beginning... */
#ifdef DEBUG
       printf("%c",b);
       fflush(stdout);
#endif
       do {
         n = write(fds[fd].fd_w, &b, 1);
         if(n<0) {
           fprintf(stderr,"write(1): %s\n",strerror(errno));
         }
       } while(n!=1);

       return 0;
}

/* gets a byte to the RS232 line, returns !=0 if byte received, byte in *b. */
int rs232_getc(int fd, BYTE *b) {
       int ret;
       size_t n;
       fd_set rdset;
       struct timeval ti;

       if(fd<0 || fd>=MAXRS232 || !fds[fd].inuse) {
         fprintf(stderr, "RS232: getc with invalid or non-open fd %d!\n", fd);
         return 0;
       }
       if(fds[fd].type == T_FILE) return 0;

       FD_ZERO(&rdset);
       FD_SET(fds[fd].fd_r, &rdset);
       ti.tv_sec = ti.tv_usec = 0;
       ret = select(fds[fd].fd_r+1, &rdset, NULL, NULL, &ti);

       if(ret && (FD_ISSET(fds[fd].fd_r,&rdset)) ) {
         n = read(fds[fd].fd_r,b,1);
         if(n) return 1;
       }
       return 0;
}



These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.