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.