diff -r 310d6e74d61f -r d6d284094d2d SerialPort.st --- /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 +#include + +/* + * 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 $' +! !