This is MiscSerialPort2.m in view mode; [Download] [Up]
/* MiscSerialPort.m -- an OO wrapper around the serial ports Written by Matt Brandt Copyright ( c ) 1994 by Matt Brandt. Modified by Arnaud Meuret Version 2.0. All rights reserved. This notice may not be removed from this source code. This object is included in the MiscKit by permission from the author and its use is governed by the MiscKit license, found in the file "LICENSE.rtf" in the MiscKit distribution. Please refer to that file for a list of all applicable permissions and restrictions. ______________________________________________________________________________*/ #import "MiscSerialPort.h" struct { int intValue; int name; } baudRateTable[] = { {110,B110}, {300,B300}, {600,B600}, {1200,B1200}, {2400,B2400}, {4800,B4800}, {9600,B9600}, {14400,B14400}, {19200,B19200}, {28800,B28800}, {38400,B38400}, {43200,B43200}, {57600,B57600}, {"",0}}; int origLineDisc; struct sgttyb origTtyParms; struct tchars origSpecChars; struct ltchars origLocSpecChars; int origLocMode; @implementation MiscSerialPort //======================================================================== - init { ttyParms.sg_flags = 0; // clear all delay selection ioctl( portFD,TIOCEXCL,&ttyParms ); // exclusive access ioctl( portFD,TIOCHPCL,&ttyParms ); // hang up on close // These set the default behaviour of the instances [self setDeviceName:"/dev/cufa"]; // port A (??name?? on white) with hard flow control flags.connected = NO; // not connected flags.suspended = NO; // not suspended delegate = nil; // no default delegate [self setBaud:B9600]; // 9600 bauds [self setParity:MISC_SP_NONE]; // no parity [self setMode:MISC_SP_COOKED]; // full I/O processing [self translateNL:YES]; // translate NewLines [self setEchoing:NO]; // do not echo received chars [self setFlowControl:MISC_SP_HARDFC]; // assume hardware flow control return self; } //======================================================================== - free { [self disconnect]; return [super free]; // so long and thanks for all the fish. } //======================================================================== - ( BOOL )connect { int ldisc = NTTYDISC; if( flags.connected ) // do nothing if already connected return YES; if( ![self deviceIsAvailable:device]) { status = MISC_SP_CANT_LOCK; return NO; } portFD = open( device,O_RDWR ); if( portFD < 0 ) return NO; // Save current parameters ioctl( portFD, TIOCGETD, &origLineDisc ); ioctl( portFD, TIOCGETP, &origTtyParms ); ioctl( portFD, TIOCGETC, &origSpecChars ); ioctl( portFD, TIOCLGET, &origLocMode ); ioctl( portFD, TIOCGLTC, &origLocSpecChars ); ttyParms = origTtyParms; // set new discipline ioctl( portFD, TIOCSETD, &ldisc ); // pass our parameters structure to the driver ( I/O buffers are flushed ) ioctl( portFD, TIOCSETD, &ttyParms ); flags.connected = YES; // setup file descriptor monitor, the function we register willl be called when something // pops up on the port. DPSAddFD( portFD, ( DPSFDProc )portEventHandler, self, NX_MODALRESPTHRESHOLD ); flags.suspended = NO; status = MISC_SP_OK; return YES; } //======================================================================== - disconnect { if( !flags.connected ) return self; if( !flags.suspended ) DPSRemoveFD( portFD ); // Be a good object and put everything back as it was when we took it! ioctl( portFD, TIOCSETD, &origLineDisc ); ioctl( portFD, TIOCSETP, &origTtyParms ); ioctl( portFD, TIOCSETC, &origSpecChars ); ioctl( portFD, TIOCLSET, &origLocMode ); ioctl( portFD, TIOCSLTC, &origLocSpecChars ); // O.K. I dont bother setting back the "exclusive-use" bit if it has // changed, but does it really matter? Anyway, the "hang-up-on-close" bit // does not seem to be reset-able ! if(close( portFD )<0) { status = MISC_SP_SEE_ERRNO; return self; } flags.connected = NO; status = MISC_SP_OK; return self; } //======================================================================== // The convention is to have the accessor and modifier methods use // the ivar name, however setDevice is a method declared in NXSoundStream! - setDeviceName: ( const char * )name { if( strcmp( name,device ) == 0 ) return self; strncpy( device,name,DEVICE_PATH_LEN ); device[DEVICE_PATH_LEN+1] = '\0'; if( ![self deviceIsAvailable:name]) { status = (MISC_SP_CANT_LOCK & MISC_SP_NO_DEVICE & MISC_SP_NOT_OPEN); return NO; } if( flags.connected ) { [self disconnect]; [self connect]; } return self; } //======================================================================== - ( BOOL ) deviceIsAvailable: ( const char * )name { id lockFilename; lockFilename = [[MiscString alloc] initString:"/usr/spool/uucp/LCK/LCK.."]; // concat the name of the device to the lockfile name [lockFilename concatenate:[[lockFilename filename] stringValueAndFree]]; miscLock = [[MiscLockFile alloc] init]; [miscLock setFileName:lockFilename]; if ([miscLock lock] ) { [miscLock unlock]; return YES; } else return NO; } //======================================================================== - setFlowControl:( int )method; { switch( method ) { case MISC_SP_NOFC: ttyParms.sg_flags &= ~TANDEM; // clear XON/XOFF Flow control bit flags.hardwareFC = NO; break; case MISC_SP_HARDFC: ttyParms.sg_flags &= ~TANDEM; // clear XON/XOFF Flow control bit flags.hardwareFC = YES; break; case MISC_SP_SOFTFC: ttyParms.sg_flags |= TANDEM; // set XON/XOFF Flow control bit flags.hardwareFC = NO; break; default: ttyParms.sg_flags &= ~TANDEM; // clear XON/XOFF Flow control bit flags.hardwareFC = YES; break; } if( flags.connected ) ioctl( portFD,TIOCSETP,&ttyParms ); status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - (int) flowControl; { if( flags.hardwareFC ) return MISC_SP_HARDFC; if( ttyParms.sg_flags & TANDEM ) return MISC_SP_SOFTFC; else return MISC_SP_NOFC; } //======================================================================== - dropDTR { if( flags.connected ) ioctl( portFD, TIOCCDTR,0 ); status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - raiseDTR { if( flags.connected ) ioctl( portFD, TIOCSDTR,0 ); status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - setBaudRateByName: ( int )name { ttyParms.sg_ispeed = name; ttyParms.sg_ospeed = name; if( flags.connected ) ioctl( portFD,TIOCSETP,&ttyParms ); status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - setBaudRate: ( int )speed { UBYTE i=0; // we try to find the first standard speed at least equal to what is requested speed = ( int ) ceil( speed ); while( baudRateTable[i].name ) { if( baudRateTable[i].intValue >=speed ) return [self setBaud: baudRateTable[i].name]; i++; } [self setBaud: B19200]; return self; } //======================================================================== - setBaudRateFromString: ( const char* )speed { // I thought of doing an sprintf on speed to check for a numerical value but it would probably // be useful in 1 case over 42:-). return [self setBaudRate:atoi( speed )]; } //======================================================================== - setParity: ( int )parity { switch( parity ) { case MISC_SP_NONE: ttyParms.sg_flags &= ( ~EVENP | ~ODDP ); break; case MISC_SP_ODD: ttyParms.sg_flags |= ODDP; ttyParms.sg_flags &= ~EVENP; break; case MISC_SP_EVEN: ttyParms.sg_flags |= EVENP; ttyParms.sg_flags &= ~ODDP; break; default: ttyParms.sg_flags &= ( ~EVENP | ~ODDP ); break; } ioctl( portFD,TIOCSETP,&ttyParms ); return self; } //======================================================================== - (int) parity; { // The EVENP bit has precedence whether or not the ODDP is set if( ttyParms.sg_flags & EVENP ) return MISC_SP_EVEN; if( ttyParms.sg_flags & ODDP ) return MISC_SP_ODD; else // <=> none of them are set return MISC_SP_NONE; } //======================================================================== - setMode: ( int )newMode { switch( newMode ) { case MISC_SP_COOKED: ttyParms.sg_flags &= ~CBREAK; ttyParms.sg_flags &= ~RAW; break; case MISC_SP_CBREAK: ttyParms.sg_flags |= CBREAK; ttyParms.sg_flags &= ~RAW; break; case MISC_SP_RAW: ttyParms.sg_flags |= RAW; ttyParms.sg_flags &= ~CBREAK; break; default: ttyStruct.sg_flags &= ~CBREAK; ttyStruct.sg_flags &= ~RAW; break; } if( flags.connected ) // this flag ensures that the file descriptor is valid ioctl( portFD,TIOCSETP,&ttyParms ); return self; } //======================================================================== - (int) mode; { // I *think * that the RAW bit has precedence over the CBREAK if( ttyParms.sg_flags & RAW ) return MISC_SP_RAW; if( ttyParms.sg_flags & CBREAK ) return MISC_SP_CBREAK; else // <=> none of them are set return MISC_SP_COOKED; } //======================================================================== - translateNL: ( BOOL )yesNo { if( yesNo ) ttyParms.sg_flags |= CRMOD; else ttyParms.sg_flags &= ~CRMOD; if( flags.connected ) // this flag ensures that the file descriptor is valid ioctl( portFD,TIOCSETP,&ttyParms ); status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - setEchoing: ( BOOL )yesNo { if( yesNo ) ttyParms.sg_flags |= ECHO; else ttyParms.sg_flags &= ~ECHO; if( flags.connected ) // this flag ensures that the file descriptor is valid ioctl( portFD,TIOCSETP,&ttyParms ); status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - setDelegate: theConsumer { // we only accpet the delegate if it responds to the reception notification message if( [theConsumer respondsTo:@selector( receiveChars:length: )] ) { delegate = theConsumer; status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } delegate=nil; status = MISC_SP_OTHER; // this is just not to say we're OK if the delegate was refused. return nil; // the return value is the thing to check in this case! } //======================================================================== - transmitChars: ( const char * )buffer length: ( int )length { if( !flags.connected ) { status = MISC_SP_NOT_OPEN; return self; } if( write( portFD,buffer,length ) < 0) { status = MISC_SP_SEE_ERRNO; return self; } status = MISC_SP_OK; return self; } //======================================================================== - ( void )checkReceiver { #define BUF_LEN 2048 int red; char buf[BUF_LEN]; red = read( portFD,buf, BUF_LEN ); // If we got here something HAS arrived at the port I'm not sure if the check is useful // On the other hand is this comparison significantly long? if( red > 0 ) [delegate receiveChars: buf length: red]; } //======================================================================== void *portEventHandler( int fdtag, id thePort ) { [thePort checkReceiver]; return thePort; } //======================================================================== - suspendIO { if( flags.connected ) { if( !flags.suspended ) DPSRemoveFD( portFD ); flags.suspended = YES; } status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - continue { return [self resumeIO];} //======================================================================== - resumeIO { if( flags.connected && flags.suspended ) { DPSAddFD( portFD,( DPSFDProc )portEventHandler, self, NX_MODALRESPTHRESHOLD ); flags.suspended = NO; } status = ( flags.connected ) ? MISC_SP_OK : MISC_SP_NOT_OPEN; return self; } //======================================================================== - clearStatus; { status = MISC_SP_OK; return self; } - ( BOOL ) isSuspended { return flags.suspended; } - ( int ) fileDescriptor { return portFD; } - ( int ) status; { return ( int ) status;} - ( const char* ) statusString { return "OK!"; } - ( BOOL ) isConnected { return flags.connected; } - delegate { return delegate; } - ( BOOL ) isEchoing { return ( ttyParms.sg_flags & ECHO ); } - (BOOL) doesTranslateNL { return ( ttyParms.sg_flags & CRMOD ); } - ( int ) baudRate { return 0; } - ( const char* ) deviceName { return ( const char* ) device; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.