summaryrefslogtreecommitdiff
path: root/src/serial.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2007-05-07 02:05:54 +0000
committerIan C <ianc@noddybox.co.uk>2007-05-07 02:05:54 +0000
commit024f069d1f0feb3ecb2eea6b1443536defb01f35 (patch)
treefd108ce1dcc82fe14029db250f4505ea7f4321ff /src/serial.c
parentc657944c91fae5f581839912cb0a55bee84c9278 (diff)
This commit was generated by cvs2svn to compensate for changes in r2,HEADmaster
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'src/serial.c')
-rw-r--r--src/serial.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/src/serial.c b/src/serial.c
new file mode 100644
index 0000000..6f25892
--- /dev/null
+++ b/src/serial.c
@@ -0,0 +1,472 @@
+/*
+
+ atarisio - A UNIX backend for an Atari SIO2PC lead.
+
+ Copyright (C) 2004 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Serial wrappers.
+
+*/
+static const char ident[]="$Id$";
+
+#include <pthread.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+
+#include "serial.h"
+#include "token.h"
+
+static const char ident_h[]=ATARISIO_SERIAL_H;
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define WHICH (pthread_equal(pthread_self(),thread) ? "READ":"MAIN")
+
+/* Just as I'm always forgetting how many...
+*/
+#define MILLI2MICRO(x) ((x)*1000)
+
+
+/* ---------------------------------------- EXTERN
+*/
+const uchar SIO_ACK=0x41;
+const uchar SIO_NACK=0x4e;
+const uchar SIO_COMPLETE=0x43;
+const uchar SIO_ERROR=0x45;
+
+
+/* ---------------------------------------- STATICS
+*/
+static int fd=-1;
+static SIOCallback devtable[256]={0};
+static int debug=FALSE;
+static int thread_created=FALSE;
+
+static int do_debug;
+
+static pthread_mutex_t mutex;
+static pthread_t thread;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Error(const char *p)
+{
+ perror(p);
+
+ if (fd!=-1)
+ {
+ if (pthread_equal(pthread_self(),thread))
+ {
+ printf("WARNING: Reader thread exiting - "
+ "serial port is still open\n");
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ else
+ {
+ printf("Trying to closing serial device\n");
+ SerialClose();
+ }
+ }
+}
+
+
+static void Fatal(const char *p)
+{
+ fprintf(stderr,"FATAL: ");
+ perror(p);
+ exit(EXIT_FAILURE);
+}
+
+
+static void Lock(void)
+{
+ /* printf("[LOCK %s]\n",WHICH); */
+ pthread_mutex_lock(&mutex);
+}
+
+
+static void Unlock(void)
+{
+ /* printf("[UNLOCK %s]\n",WHICH); */
+ pthread_mutex_unlock(&mutex);
+}
+
+
+void SerialPutchar(uchar c)
+{
+ if (do_debug)
+ printf("PUTCHAR: %2.2x (%c)\n",c,isprint(c) ? c:'?');
+
+ if (write(fd,&c,1)==-1)
+ {
+ Error("write:");
+ return;
+ }
+}
+
+
+void SerialWrite(const uchar *p, size_t len)
+{
+ uchar csum;
+
+ if (do_debug)
+ {
+ printf("SENDING:\n");
+ HexDump(p,len);
+ }
+
+ csum=Checksum(p,len);
+
+ while(len>0)
+ {
+ ssize_t w;
+
+ w=write(fd,p,len);
+
+ if (w==-1)
+ {
+ Error("write:");
+ return;
+ }
+
+ p+=w;
+ len-=w;
+ }
+
+ write(fd,&csum,1);
+
+ if (do_debug)
+ printf("CHECKSUM: %2.2x\n",csum);
+}
+
+
+int SerialRead(uchar *p, size_t len)
+{
+ uchar *orig;
+ uchar csum;
+
+ orig=p;
+
+ while(len>0)
+ {
+ ssize_t r;
+
+ r=read(fd,p,len);
+
+ if (r==-1)
+ {
+ Error("read:");
+ return FALSE;
+ }
+
+ p+=r;
+ len-=r;
+ }
+
+ if (read(fd,&csum,1)!=1)
+ {
+ Error("read:");
+ return FALSE;
+ }
+
+ return Checksum(orig,len)==csum;
+}
+
+
+/* ---------------------------------------- READER
+*/
+static void *ReaderThread(void *p)
+{
+ SIOCommand cmd;
+ time_t start;
+ int st;
+ int no;
+ uchar frame[5];
+ uchar c;
+ uchar csum;
+
+ cmd.putchar=SerialPutchar;
+ cmd.write=SerialWrite;
+ cmd.read=SerialRead;
+
+ while(TRUE)
+ {
+ Lock();
+ do_debug=debug;
+ Unlock();
+
+ no=0;
+
+ while(no<5)
+ {
+ if (read(fd,&c,1)==-1)
+ Error("read");
+
+ if (ioctl(fd,TIOCMGET,&st)==-1)
+ Error("ioctl(TIOCMGET)");
+
+ if (st&TIOCM_RNG)
+ {
+ if (do_debug)
+ printf("Got byte %d (%c) and RNG set\n",
+ c,isprint(c) ? c:'?');
+
+ if (no==0)
+ start=time(NULL);
+
+ frame[no++]=c;
+ }
+ else if (do_debug)
+ {
+ printf("Got byte %d (%c) and RNG *NOT* set\n",
+ c,isprint(c) ? c:'?');
+ }
+ }
+
+ if ((time(NULL)-start)>1)
+ {
+ printf("Reader: Got 5 bytes, but too slowly - ignored\n");
+ }
+ else
+ {
+ Lock();
+
+ csum=Checksum(frame,4);
+
+ if (csum==frame[4])
+ {
+ if (do_debug)
+ {
+ printf("Frame:\n");
+ HexDump(frame,5);
+ }
+
+ if (devtable[frame[0]])
+ {
+ /* Fill up the command structure
+ */
+ cmd.device=frame[0];
+ cmd.cmd=frame[1];
+ cmd.aux1=frame[2];
+ cmd.aux2=frame[3];
+
+ /* Let the device do its work
+ */
+ if (do_debug)
+ printf("Calling handler for device %2.2x\n",cmd.device);
+
+ devtable[cmd.device](&cmd);
+ }
+ }
+ else
+ {
+ printf("Reader: Bad checksum, expected %2.2x. Frame:\n",csum);
+ HexDump(frame,5);
+ }
+
+ Unlock();
+ }
+ }
+}
+
+
+/* ---------------------------------------- COMMAND HANDLERS
+*/
+static void Register(int argc, char *argv[])
+{
+ int f;
+
+ for(f=0;f<256;f++)
+ if (devtable[f])
+ printf("Device %2.2x regsitered\n",f);
+}
+
+
+/* ---------------------------------------- COMMAND TABLE
+*/
+static Command cmd[]=
+{
+ {
+ "register",
+ 1,1,
+ "register",
+ "Show registered devices",
+ Register
+ }
+};
+
+
+/* ---------------------------------------- INTERFACES
+*/
+void SerialInit(void)
+{
+ if (pthread_mutex_init(&mutex,NULL)==-1)
+ Fatal("pthread_mutex_init");
+
+ TokenRegister(sizeof cmd/sizeof cmd[0],cmd);
+}
+
+
+void SerialOpen(const char *path)
+{
+ struct termios ios;
+
+ if (fd!=-1)
+ {
+ printf("Serial device already open\n");
+ return;
+ }
+
+ fd=open(path,O_RDWR|O_NOCTTY|O_NDELAY);
+
+ if (fd==-1)
+ {
+ Error(path);
+ return;
+ }
+
+ if (fcntl(fd,F_SETFL,0)==-1)
+ {
+ Error("fcntl(F_SETFL,0)");
+ return;
+ }
+
+ if (tcgetattr(fd,&ios)==-1)
+ {
+ Error("tcgetattr");
+ return;
+ }
+
+ cfsetispeed(&ios,B19200);
+ cfsetospeed(&ios,B19200);
+
+ ios.c_cflag|=(CLOCAL|CREAD);
+
+ ios.c_cflag&=~PARENB;
+ ios.c_cflag&=~CSTOPB;
+ ios.c_cflag&=~CSIZE;
+ ios.c_cflag|=CS8;
+
+ /* Not that it'll work if we can't disable it...
+ */
+#ifdef CRTSCTS
+ ios.c_cflag&=~CRTSCTS;
+#endif
+
+ ios.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
+
+ ios.c_iflag&=~(IXON|IXOFF|IXANY);
+
+ ios.c_oflag&=~OPOST;
+
+ if (tcsetattr(fd,TCSANOW,&ios))
+ {
+ Error("tcsetattr");
+ return;
+ }
+
+ if (pthread_create(&thread,NULL,ReaderThread,NULL)==-1)
+ Fatal("pthread_create");
+
+ thread_created=TRUE;
+}
+
+
+void SerialRegister(int device, SIOCallback func)
+{
+ if (device<0 || device>255)
+ {
+ printf("Illegal device number %d registered\n",device);
+ return;
+ }
+
+ Lock();
+ devtable[device]=func;
+ Unlock();
+}
+
+
+void SerialDeregister(int device)
+{
+ if (device<0 || device>255)
+ {
+ printf("Illegal device number %d deregistered\n",device);
+ return;
+ }
+
+ Lock();
+ devtable[device]=NULL;
+ Unlock();
+}
+
+
+void SerialDebug(int mode)
+{
+ Lock();
+ debug=mode;
+ Unlock();
+}
+
+
+void SerialClose(void)
+{
+ if (fd==-1)
+ {
+ printf("Serial not open\n");
+ }
+
+ Lock();
+
+ if (thread_created)
+ {
+ printf("Cancelling reader thread...");
+ fflush(stdout);
+ pthread_cancel(thread);
+ pthread_join(thread,NULL);
+ printf("Done\n");
+ }
+
+ Unlock();
+
+ close(fd);
+
+ fd=-1;
+ thread_created=FALSE;
+}
+
+
+/* END OF FILE */