SerialPort.st
changeset 1593 d6d284094d2d
child 1595 eb26b0dfa8f6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SerialPort.st	Thu Feb 02 17:22:51 2006 +0100
@@ -0,0 +1,544 @@
+"
+ COPYRIGHT (c) 2006 by eXept Software AG
+	      All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+
+"{ Package: 'stx:libbasic2' }"
+
+NonPositionableExternalStream subclass:#SerialPort
+	instanceVariableNames:'portName baudRate stopBitsType parityType dataBits
+		inFlowCtrlType outFlowCtrlType xOnChar xOffChar'
+	classVariableNames:'DefaultPortName'
+	poolDictionaries:''
+	category:'Streams-External'
+!
+
+!SerialPort primitiveDefinitions!
+%{
+
+#include "stxOSDefs.h"
+
+#ifdef WIN32
+
+# undef __BEGIN_INTERRUPTABLE__
+# undef __END_INTERRUPTABLE__
+# define __BEGIN_INTERRUPTABLE__ ..
+# define __END_INTERRUPTABLE__ ..
+
+# define WRAP_STDIO
+
+# define PORT_FROM_FD(fd)     (_get_osfhandle(fd))
+# define closePort(port)      closeHandle(port)
+# define SERIALPORT           HANDLE
+
+#else /* not WIN32 */
+
+# define PORT_FROM_FD(fd)     (fd)
+# define closePort(port)      close(port)
+# define SERIALPORT           int
+
+#endif /* WIN32 */
+
+# define PORT_FROM_FILE(f)             (PORT_FROM_FD(fileno(f)))
+# define PORT_FROM_FILE_OBJECT(f)      (PORT_FROM_FILE(__FILEVal(f)))
+
+#include <stdio.h>
+#include <errno.h>
+
+/*
+ * on some systems errno is a macro ... check for it here
+ */
+#ifndef errno
+ extern errno;
+#endif
+
+#ifdef USE_H_ERRNO
+# ifndef h_errno
+ extern h_errno;
+# endif
+#endif
+
+#ifdef DEBUG
+# define DBGPRINTF(x)    { if (__debugging__) printf x; }
+# define DBGFPRINTF(x)   { if (__debugging__) fprintf x; }
+#else
+# define DBGPRINTF(x)    /* as nothing */
+# define DBGFPRINTF(x)   /* as nothing */
+#endif
+
+#ifndef TRUE
+# define TRUE   1
+#endif
+#ifndef FALSE
+# define FALSE  0
+#endif
+#ifndef WIN32
+typedef int BOOL;
+#endif
+
+
+%}
+! !
+
+!SerialPort primitiveVariables!
+%{
+static int __debugging__ = 0;
+%}
+! !
+
+!SerialPort class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2006 by eXept Software AG
+	      All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+documentation
+"
+    This class provides access to serial ports
+"
+!
+
+examples
+"
+    example (get help info from an nntp server):
+									[exBegin]
+	... to be added ...
+									[exEnd]
+"
+! !
+
+!SerialPort class methodsFor:'defaults'!
+
+defaultPortName
+    DefaultPortName notNil ifTrue:[^ DefaultPortName ].
+
+    OperatingSystem isMSDOSlike ifTrue:[
+	^ 'COM1'
+    ].
+    ^ '/dev/cua0'
+! !
+
+!SerialPort class methodsFor:'instance creation'!
+
+portName:portName
+   baudRate:baudRateOrNil stopBitsType:stopBitsTypeOrNil
+   parityType:parityTypeOrNil dataBits:dataBitsOrNil
+   inFlowCtrlType:inFlowCtrlTypeOrNil outFlowCtrlType:outFlowCtrlTypeOrNil
+   xOnChar:xOnCharOrNil xOffChar:xOffCharOrNil
+
+    "arguments are self describing; nil values mean: leave setting as is"
+
+    ^ (self new
+	setPortName:portName
+	baudRate:baudRateOrNil stopBitsType:stopBitsTypeOrNil
+	parityType:parityTypeOrNil dataBits:dataBitsOrNil
+	inFlowCtrlType:inFlowCtrlTypeOrNil outFlowCtrlType:outFlowCtrlTypeOrNil
+	xOnChar:xOnCharOrNil xOffChar:xOffCharOrNil) open
+!
+
+new
+    "create a serial port"
+
+    ^ super new buffered:false
+! !
+
+!SerialPort class methodsFor:'debugging'!
+
+debug:aBoolean
+    "turn on/off internal debugprints.
+     This method is for ST/X debugging only and
+     may  be removed in later versions"
+
+%{  /* NOCONTEXT */
+
+    __debugging__ = (aBoolean == true);
+%}
+    "
+     SerialPort debug:true
+     SerialPort debug:false
+    "
+! !
+
+!SerialPort methodsFor:'accessing'!
+
+setPortName:portNameArg
+	baudRate:baudRateOrNil stopBitsType:stopBitsTypeOrNil
+	parityType:parityTypeOrNil dataBits:dataBitsOrNil
+	inFlowCtrlType:inFlowCtrlTypeOrNil outFlowCtrlType:outFlowCtrlTypeOrNil
+	xOnChar:xOnCharOrNil xOffChar:xOffCharOrNil
+
+    portName := portNameArg.
+    baudRate := baudRateOrNil.
+    stopBitsType := stopBitsTypeOrNil.
+    parityType := parityTypeOrNil.
+    dataBits := dataBitsOrNil.
+    inFlowCtrlType := inFlowCtrlTypeOrNil.
+    outFlowCtrlType := outFlowCtrlTypeOrNil.
+    xOnChar := xOnCharOrNil.
+    xOffChar := xOffCharOrNil.
+! !
+
+!SerialPort protectedMethodsFor:'low level'!
+
+closeFile
+    "low level close"
+
+%{
+    OBJ t;
+
+    t = __INST(filePointer);
+    if (t != nil) {
+	FILE *fp;
+	SERIALPORT port;
+
+	__INST(filePointer) = nil;
+	fp = __FILEVal(t);
+	port = PORT_FROM_FILE(fp);
+
+# ifdef xxDO_WRAP_CALLS
+	{ int ret;
+
+	  do {
+	    __threadErrno = 0;
+	    ret = STX_C_CALL1("fclose", fclose, fp);
+	  } while ((ret < 0) && (__threadErrno == EINTR));
+
+#  ifdef WIN32
+	  do {
+	    __threadErrno = 0;
+	    ret = STX_WSA_CALL1("CloseHandle", CloseHandle, port);
+	  } while ((ret < 0) && (__threadErrno == EINTR));
+	  CloseHandle(port);
+#  endif
+	}
+# else /* !DO_WRAP_CALLS */
+
+	fclose(fp);
+#  ifdef WIN32
+	CloseHandle(port);
+#  endif
+
+# endif /* !DO_WRAP_CALLS */
+    }
+%}
+! !
+
+!SerialPort methodsFor:'low level'!
+
+baudRate:newRate
+%{
+    OBJ fp;
+
+    fp = __INST(filePointer);
+    if ((fp != nil) && __isSmallInteger(newRate)) {
+	SERIALPORT port;
+	int ret;
+
+	port = PORT_FROM_FILE_OBJECT(fp);
+#ifdef WIN32
+	{
+	    DCB dcb;
+
+	    ZeroMemory(&dcb, sizeof(dcb));
+	    dcb.DCBlength = sizeof(dcb);
+	    GetCommState(port, &dcb);
+
+	    dcb.BaudRate = __intVal(newRate);
+
+	    if (! SetCommState(port, &dcb)) {
+		RETURN(false);
+	    }
+	    RETURN(true);
+	}
+# else /* ! WIN32 */
+	/* add code for unix ioctl here ... */
+# endif /* WIN32 */
+    }
+%}.
+    self primitiveFailed.
+! !
+
+!SerialPort methodsFor:'printing & storing'!
+
+printOn:aStream
+    aStream nextPutAll:'SerialPort(baudRate='.
+    baudRate printOn:aStream.
+    aStream nextPutAll:')'.
+! !
+
+!SerialPort methodsFor:'queries'!
+
+getName
+    "return the name; here, we return the devices name"
+
+    ^ portName
+! !
+
+!SerialPort methodsFor:'opening'!
+
+open
+    |errorNumber|
+
+    filePointer notNil ifTrue:[
+	^ self errorAlreadyOpen
+    ].
+%{
+    FILE *fp;
+    SERIALPORT port;
+    char *__portName;
+    int __setBaudRate = 1,
+	__setDataBits = 1,
+	__setXOnChar = 1,
+	__setXOffChar = 1,
+	__setInFlowCtrl = 1,
+	__setOutFlowCtrl = 1,
+	__setStopBits = 1,
+	__setParityType = 1;
+    int __baudRate, __dataBits;
+    int __xOnChar, __xOffChar;
+    int __inFlowCtrl, __outFlowCtrl;
+    int __stopBits, __parityType;
+#ifdef WIN32
+    COMMTIMEOUTS timeouts;
+    DCB dcb;
+#endif /* WIN32 */
+
+#   define XONOFF    1
+#   define HARDWARE  2
+#   define STOP1     1
+#   define STOP2     2
+#   define STOP1_5   3
+#   define ODD       1
+#   define EVEN      2
+#   define NONE      3
+
+    if (__isString(__INST(portName))) {
+	__portName = __stringVal(__INST(portName));
+    } else {
+	goto failure;
+    }
+
+    if (__isSmallInteger(__INST(baudRate))) {
+	__baudRate = __intVal(__INST(baudRate));
+    } else if (__INST(baudRate) == nil) {
+	__setBaudRate = 0;
+    } else {
+	goto failure;
+    }
+
+    if (__isSmallInteger(__INST(dataBits))) {
+	__dataBits = __intVal(__INST(dataBits));
+    } else if (__INST(dataBits == nil)) {
+	__setDataBits = 0;
+    } else {
+	goto failure;
+    }
+
+    if (__isSmallInteger(__INST(xOnChar))) {
+	__xOnChar = __intVal(__INST(xOnChar));
+    } else if (__isCharacter(__INST(xOnChar))) {
+	__xOnChar = __intVal(_characterVal(__INST(xOnChar)));
+    } else if (__INST(xOnChar) == nil) {
+	__setXOnChar = 0;
+    } else {
+	goto failure;
+    }
+
+    if (__isSmallInteger(__INST(xOffChar))) {
+	__xOffChar = __intVal(__INST(xOffChar));
+    } else if (__isCharacter(__INST(xOffChar))) {
+	__xOffChar = __intVal(__characterVal(__INST(xOffChar)));
+    } else if (__INST(xOffChar) == nil) {
+	__setXOffChar = 0;
+    } else {
+	goto failure;
+    }
+
+    if (__INST(inFlowCtrlType) == @symbol(xOnOff)) {
+	__inFlowCtrl = XONOFF;
+    } else if (__INST(inFlowCtrlType) == @symbol(hardware)) {
+	__inFlowCtrl = HARDWARE;
+    } else if (__INST(inFlowCtrlType) == nil) {
+	__setInFlowCtrl = 0;
+    } else {
+	goto failure;
+    }
+
+    if (__INST(outFlowCtrlType) == @symbol(xOnOff)) {
+	__outFlowCtrl = XONOFF;
+    } else if (__INST(outFlowCtrlType) == @symbol(hardware)) {
+	__outFlowCtrl = HARDWARE;
+    } else if (__INST(outFlowCtrlType) == nil) {
+	__setOutFlowCtrl = 0;
+    } else {
+	goto failure;
+    }
+
+    if (__INST(stopBitsType) == @symbol(stop1)) {
+	__stopBits = STOP1;
+    } else if (__INST(stopBitsType) == @symbol(stop2)) {
+	__stopBits = STOP2;
+    } else if (__INST(stopBitsType) == @symbol(stop1_5)) {
+	__stopBits = STOP1_5;
+    } else if (__INST(stopBitsType) == nil) {
+	__setStopBits = 0;
+    } else {
+	goto failure;
+    }
+
+#ifdef WIN32
+    port = CreateFile(__portName,
+	      GENERIC_READ | GENERIC_WRITE,
+	      0,             /* comm devices must be opened with exclusive access */
+	      NULL,          /* no security attrs */
+	      OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */
+	      0,             /* no overlapped I/O */
+	      NULL           /* hTemplate must be NULL for comm devices */
+	   );
+
+    if (port == INVALID_HANDLE_VALUE) {
+	fprintf(stderr, "Win32OS [info]: serial port open failed\n");
+	errorNumber = __mkSmallInteger( __WIN32_ERR(GetLastError()) );
+	goto failure;
+    }
+
+    /* Flush the driver */
+    PurgeComm( port, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
+
+    /* Set driver buffer sizes */
+    SetupComm( port, 4096 /*SERIAL_IN_QUEUE_SIZE*/, 4096 /*SERIAL_OUT_QUEUE_SIZE*/);
+
+    /* Reset timeout constants */
+    timeouts.ReadIntervalTimeout= 0xFFFFFFFF;
+    timeouts.ReadTotalTimeoutMultiplier = 0;
+    timeouts.ReadTotalTimeoutConstant = 0;
+    timeouts.WriteTotalTimeoutMultiplier = 0;
+    timeouts.WriteTotalTimeoutConstant = 0;
+    SetCommTimeouts( port, &timeouts );
+
+    /* Set communication parameters */
+    ZeroMemory(&dcb, sizeof(dcb));
+    dcb.DCBlength = sizeof(dcb);
+    GetCommState(port, &dcb);
+
+    if (__setBaudRate) dcb.BaudRate = __baudRate;
+    if (__setDataBits) dcb.ByteSize = __dataBits;
+    if (__setXOnChar)  dcb.XonChar = __xOnChar;
+    if (__setXOffChar) dcb.XoffChar = __xOffChar;
+
+    if (__setStopBits) {
+	/* set stop bits */
+	switch(__stopBits) {
+	    case STOP1_5: dcb.StopBits = 1; break; /* 1.5 stop bits */
+	    case STOP1: dcb.StopBits = 0; break; /* 1 stop bit */
+	    case STOP2: dcb.StopBits = 2; break; /* 2 stop bits */
+	    default: goto errExit;
+	}
+    }
+
+    if (__setParityType) {
+	/* set parity */
+	switch(__parityType) {
+	    case NONE: dcb.Parity = NOPARITY; break;
+	    case ODD: dcb.Parity = ODDPARITY; break;
+	    case EVEN: dcb.Parity = EVENPARITY; break;
+	    default: goto errExit;
+	}
+    }
+
+    if (__setInFlowCtrl) {
+	/* set control flow */
+	dcb.fInX = FALSE;
+	dcb.fDtrControl = FALSE;
+	if (__inFlowCtrl == XONOFF) dcb.fInX = TRUE;  /* XOn/XOff handshaking */
+	if (__inFlowCtrl == HARDWARE) dcb.fDtrControl = TRUE;  /* hardware handshaking */
+    }
+    if (__setOutFlowCtrl) {
+	dcb.fOutX = FALSE;
+	dcb.fOutxCtsFlow = FALSE;
+
+	if (__outFlowCtrl == XONOFF) dcb.fOutX = TRUE;  /* XOn/XOff handshaking */
+	if (__outFlowCtrl == HARDWARE) dcb.fOutxCtsFlow = TRUE;  /* hardware handshaking */
+    }
+
+    if (! SetCommState(port, &dcb)) {
+	fprintf(stderr, "Win32OS [info]: serial port comm-setup failed\n");
+	errorNumber = __mkSmallInteger( __WIN32_ERR(GetLastError()) );
+	goto errExit;
+    }
+# endif /* WIN32 */
+
+    /*
+     * make it a FILE *
+     */
+# ifdef WIN32
+    {
+	int _fd = _open_osfhandle(port, 0);
+	fp = fdopen(_fd, "r+");
+    }
+# else
+    fp = fdopen(port, "r+");
+# endif
+    if (! fp) {
+	errorNumber = __MKSMALLINT(errno);
+	goto errExit;
+    }
+
+    {
+	OBJ t;
+
+	t = __MKOBJ(fp);
+	__INST(filePointer) = t;
+	__STORE(self, t);
+    }
+
+	RETURN( true );
+
+errExit: ;
+    CloseHandle(port);
+
+failure: ;
+#   undef XONOFF
+#   undef HARDWARE
+#   undef STOP1
+#   undef STOP2
+#   undef STOP1_5
+#   undef ODD
+#   undef EVEN
+#   undef NONE
+
+%}.
+    "all ok?"
+    filePointer notNil ifTrue:[
+	Lobby register:self.
+    ] ifFalse:[
+	errorNumber isNil ifTrue:[
+	    self error:'invalid argument(s)'.
+	] ifFalse:[
+	    (OperatingSystem errorHolderForNumber:errorNumber) reportError
+	].
+    ].
+! !
+
+!SerialPort class methodsFor:'documentation'!
+
+version
+    ^ '$Header: /cvs/stx/stx/libbasic2/SerialPort.st,v 1.1 2006-02-02 16:22:51 cg Exp $'
+! !