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.