//
//	MiscSerialPort.m -- an OO wrapper around the serial ports
//		Written by Matt Brandt Copyright (c) 1994 by Matt Brandt.
//				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 <misckit/MiscSerialPort.h>
#import	<fcntl.h>
#import	<sgtty.h>

struct misc_brt
{
	char	name[10];
	int		brate;
}
	misc_brtable[] = {
		{"110",B110},
		{"300",B300},
		{"600",B600},
		{"1200",B1200},
		{"2400",B2400},
		{"4800",B4800},
		{"9600",B9600},
		{"19200",B19200},
		{"38400",B38400},
		{"57600",B57600},
		{"",0}};

@implementation MiscSerialPort

- init
{
	portName[0] = '\0';
	connected = NO;
	delegate = NULL;
	currentBaud = B19200;
	currentParity = -1;		// no parity by default
	return self;
}

- setDeviceName: (const char *)name
{
	if( strcmp(name,portName) == 0 )
		return self;
		
	strncpy(portName,name,63);
	portName[63] = '\0';
	if( connected )
	{
		[self disconnect];
		if( ![self connect] )
			strncpy(portName,"UNCONNECTED",63);
	}
	return self;
}

- setPortParameters
{
	struct sgttyb sg;
	
	ioctl(fd,TIOCGETP,&sg);			// get baudrate and mode
	sg.sg_ispeed = currentBaud;
	sg.sg_ospeed = currentBaud;
	sg.sg_erase = 0;
	sg.sg_kill = 0;
	sg.sg_flags = RAW;
	ioctl(fd,TIOCSETP,&sg);			// set baudrate and raw mode
	ioctl(fd,TIOCEXCL,&sg);			// exclusive access
	ioctl(fd,TIOCHPCL,&sg);			// hang up on close
	return self;
}

- dropDTR
{
	ioctl(fd, TIOCCDTR,0);
	return self;
}

- raiseDTR
{
	ioctl(fd, TIOCSDTR,0);
	return self;
}

- setBaud: (int)baud
{
	currentBaud = baud;
	if( connected )
		[self setPortParameters];
	return self;
}

- setBaudByName: (const char *)speed
{
	struct misc_brt	*brtp;
	
	brtp = misc_brtable;
	while( brtp->name[0] != '\0' )
	{
		if( strcmp(brtp->name,speed) == 0 )
			return [self setBaud: brtp->brate];
		++brtp;
	}
	return NULL;
}

- setParity: (int)parity
{
	currentParity = parity;
	return self;
}

- setDelegate: theConsumer
{
	delegate = theConsumer;
	return self;
}

- delegate
{
	return delegate;
}

- transmitChars: (const char *)buffer length: (int)length
{
	if( connected )
		write(fd,buffer,length);
	return self;
}

- (void)checkReceiver
{
	int		len;
	char	buf[512];
	
	len = read(fd,buf,512);
	if( len > 0 )
	{
		[delegate receiveChars: buf length: len];
	}
}

void	*SerialPortTimedEntry(int fdtag, id thePort)
{
	[thePort checkReceiver];
	return thePort;
}

- (BOOL)connect
{
	if( connected )			// do nothing if already connected
		return YES;
		
	if( portName[0] == '\0' )
		return NO;
		
	fd = open(portName,O_RDWR /* | O_NDELAY*/);
	if( fd < 0 )
		return NO;
			
	connected = YES;
	
	[self setPortParameters];		// set up baudrate etc...
	
	DPSAddFD(fd, 
		(DPSFDProc)SerialPortTimedEntry, 
		self, NX_MODALRESPTHRESHOLD);
	suspended = NO;
	return YES;
}

- disconnect
{
	if( connected )
	{
		if( !suspended )
			DPSRemoveFD(fd);
		close(fd);
		connected = NO;
	}
	return self;
}

- suspend
{
	if( connected )
	{
		if( !suspended )
			DPSRemoveFD(fd);
		suspended = YES;
	}
	return self;
}

- continue
{
	return [self resume];
}

- resume
{
	if( connected && suspended )
	{
		DPSAddFD(fd, 
			(DPSFDProc)SerialPortTimedEntry, 
			self, NX_MODALRESPTHRESHOLD);
		suspended = NO;
	}
	return self;
}

- (BOOL)suspended
{
	return suspended;
}

- (int)filedes
{
	return fd;
}

@end
