This is SerialPort.m in view mode; [Download] [Up]
/* SerialPort.m 24 March 1993 Eric Celeste / AppTech / 5 Exeter Street / Belmont, MA 02178 efc@mit.edu This simple serial port object was originally created by: Michael Hawley MIT Media Laboratory mike@media-lab.mit.edu, mjh@next.com Please send us both any improvements. For example: port = [SerialPort new:"/dev/ttyb" baud:B4800]; ... [port puts:"a string"]; character = [port getc]; ... [port free]; I've simplified this object for distribution with the Laserdisc object. My contribution to its function is nil (I may even have made it less elegant). Mostly I needed to rewrite it so that I could read the code and understand what was going on. ////////////////////////////////////////// History 930213 mh shared this object with efc 930324 efc reformated the code so he could understand it */ #import "SerialPort.h" #import <stdio.h> #import <sys/time.h> #import <dpsclient/dpsNeXT.h> extern int open(), close(), read(), write(), ioctl(), select(), strlen(); @implementation SerialPort ////////////////////////////////////////////// Private Method - _fdHandler:(int)f /* DPS handler for output from process */ { #define BUFSIZE 1024 char b[BUFSIZE]; int n; #define min(a,b) (a<b? a : b) if (fdWaitInput(f,1)<=0 || (n=read(f,b,min(fdHasInput(f),BUFSIZE-1)))<=0) return self; b[n] = '\0'; if (delegate && [delegate respondsTo:action]) [delegate perform:action with:(void *)&b]; return self; } ////////////////////////////////////////////// Private Functions static void _fgets(char *s, int n, int fd, char *eol, int delay) { while (fdWaitInput(fd,1) <= 0 && fdHasInput(fd) <= 0) { /* skip this */ } while (fdWaitInput(fd,delay)>0) { if (read(fd,s,1) != 1) { *s = '\0'; return; } if (*s == *eol || --n <= 0) { *++s = '\0'; return; } ++s; } *++s = '\0'; } static void fdHandler(int f, id self) { [self _fdHandler:f]; } ////////////////////////////////////////////// Allocation Methods + new: (char *) devicepath baud:(int)b parity:(int)p echo:(int)e raw:(int)r /* Open a serial port with the given speed and modes. For example, a 4800 baud video disk device is hooked to Serial Port B. The correct call for this baud rate, any parity taken/ none given, and no echo by the NeXT is: p = [SerialPort new: "/dev/ttyb" baud: B4800 parity: ANYP echo: NO raw: YES]; */ { self = [super new]; eol = "\r"; delay = 3; if ((fd = open(devicepath,O_RDWR)) > 0) { [self setBaud:b parity:p echo:e raw:r]; } else { self = nil; } return self; } + new:(char *)devicepath baud:(int)b /* new: with parity:ANYP echo:NO raw:YES */ { return [SerialPort new:devicepath baud:b parity:ANYP echo:NO raw:YES]; } - free { if (fd>0){ if (action) DPSRemoveFD(fd); close(fd); } self = [super free]; return self; } ////////////////////////////////////////////// Parameter Methods - setBaud:(int)b parity:(int)p echo:(int)e raw:(int)r { struct sgttyb s; speed = b; parity = p; echo = e; raw = r; ioctl(fd, TIOCGETP, &s); s.sg_ispeed = s.sg_ospeed = speed; s.sg_flags = 0; #define setbits(f,mask) if (f) s.sg_flags|=mask; else s.sg_flags&=~(mask) setbits(r,RAW|CBREAK); setbits(e,ECHO); s.sg_flags |= p; ioctl(fd, TIOCSETP, &s); ioctl(fd, TIOCFLUSH, &s); // maybe not necessary return self; } - (char *)eol { return eol; } - setEol:(char *)s { eol = s; return self; } - (int)delay { return delay; } - setDelay:(int)n { delay = n; return self; } - (int)fd { return fd; } ////////////////////////////////////////////// Input int fdHasInput(int fd) /* Number of pending input characters. */ { int x; ioctl(fd,FIONREAD,&x); return x; } - (int)hasInput { return fdHasInput(fd); } int fdWaitInput(int fd, int timeout) /* Return >0 when 'fd' is readable (has input pending), '0' if timeout, '-1' on error. e.g., 'fdWaitInput(0,0)' will be true when the standard input contains something. */ { int readfd = 1<<fd; struct timeval t = {(unsigned long)timeout,0}; return select(fd+1, (fd_set *)&readfd, NULL, NULL, &t); } - (int)waitInput:(int)seconds { return fdWaitInput(fd,seconds); } - flush { int x; ioctl(fd, TIOCFLUSH, &x); return self; } ////////////////////////////////////////////// Reading & Writing Methods - (int)putc:(char)c { return write(fd,&c,1); } - (int)write:(char *)s length:(int)n { return write(fd,s,n); } - (int)puts:(char *)s { write(fd, s, strlen(s)); return write(fd, eol, strlen(eol)); } - (char)getc { char c = '\0'; read(fd,&c,1); return c; } - (int)read:(char *)s length:(int)n { return read(fd,s,n); } - (char *)gets:(char *)s length:(int)n { *s = '\0'; _fgets(s,n,fd,eol,delay); return s; } - (char *)gets:(char *)s { return [self gets:s length:256]; } - (char *)puts:(char *)s gets:(char *)response { [self puts:s]; [self gets:response]; while ([self hasInput]) [self gets:response]; return response; } ////////////////////////////////////////////// Delegate Methods /* Delegate methods, for asynchronous input. For example, to have a delegate routine called when input arrives: [port setDelegate:self]; [port setAction:@selector(processOutput:)]; ... - processOutput:(char *)s { ... } NB, unlike gets:..., fdHandler does not do fancy waiting or eol-processing. This is probably alright for line-buffered devices. */ - (void)setAction:(SEL)theAction { DPSAddFD(fd,(DPSFDProc)fdHandler,(id)self,11); action = theAction; } - delegate { return delegate; } - setDelegate:d { delegate = d; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.