//
// connect.m
// LGDCommunicationKit Examples, Release 1.0 (prerelease)
//
// Copyright (c) 1993, Looking Glass Design, Inc.
// All rights reserved.
//
// Project Manager:  Paul Girone
// Original Author:  Mike Gobbi
// Creation Date:    June 16, 1993
// $Revision: 1.3 $
//

#import "connect.h"
#import <assert.h>
#import <errno.h>
#import <lgd/commkit/LGDSerialPort.h>
#import <libc.h>
#import <sgtty.h>
#import <stdio.h>

static LGDSerialPort *port;	// the object used to connect to the port
static int tty;			// the file descriptor of the terminal
int orig_fcntl;			// original settings
struct sgttyb orig_sgttyb;	// original settings

void configure(const char *device)
{
	int signals[] = {
		SIGINT, SIGQUIT, SIGBUS, SIGSEGV, SIGTERM, 0
	};
	int i;
	struct sgttyb sgttyb;

	// set ourself up to die nicely no matter what happens
	for (i=0; signals[i]; i++) {
		signal(signals[i], (void *)cleanup);
	}
	
	// open tty
	tty = open("/dev/tty", O_RDWR, 0644);
	assert(tty>=0);
	
	// configure tty
	errno = 0;
	orig_fcntl = fcntl(tty, F_GETFL, 0);
	fcntl(tty, F_SETFL, orig_fcntl | FNDELAY);
	ioctl(tty, TIOCGETP, &sgttyb);
	orig_sgttyb = sgttyb;
	sgttyb.sg_flags |= RAW;
	ioctl(tty, TIOCSETP, &sgttyb);
	assert(errno==0);

	// open port
	port = [[LGDSerialPort alloc] init];
	if (![port openAndLockDevice:device mode:LGD_SP_COOKED timeout:0]) {
		deconfigure();
		printf("unable to open device %s\n", device);
		exit(1);
	}
	[port setDuplex:LGD_SP_HALFDUPLEX];
	
}

void deconfigure(void)
{
	// shut down serial port
	if ([port isOpen]) {
		[port flush];
		[port unlockAndClose];
	}
	[port free];
	
	// deconfigure tty
	errno = 0;
	ioctl(tty, TIOCSETP, &orig_sgttyb);
	fcntl(tty, F_SETFL, orig_fcntl);
	assert(errno==0);

	// close tty
	if (tty>=0) {
		close(tty);
	}

}

void cleanup(void)
{
	if ([port isOpen]) {
		[port unlockAndClose];
	}
	exit(2);
}

int keyboard_ready(int tty)
{
	fd_set set;
	struct timeval tv;
	
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	FD_ZERO(&set);
	FD_SET(tty, &set);
	select(tty+1, &set, NULL, NULL, &tv);
	
	return 0!=FD_ISSET(tty, &set);
}

void loop(void)
{
	while (1) {
		
		// send characters to port
		if (keyboard_ready(tty)) {
			char out;
			
			errno = 0;
			while (1==read(tty, &out, 1)) {
				if (out==3) {
					return;
				}
				if (out=='\n') out = '\r';
				if (out=='z') kill(0, SIGIO);
				if (1!=[port sendCharacter:out]) {
					return;
				}
			}
			if (errno && errno!=EWOULDBLOCK) {
				return;
			}
		}
		
		// get characters from port
		if ([port dataAvailable]) {
			int in;
			
			while (1==[port getCharacter:&in]) {
				char c = in;
				if (1!=write(tty, &c, 1)) {
					return;
				}
			}
			if ([port status]) {
				return;
			}
		}
		
	}
}

int main(int argc, char *argv[])
{
	// display instructions
	printf("Press ^C to exit\n");
	
	// configure things
	configure(argv[1] ? argv[1] : "cufa");
	
	// run the loop
	loop();
	
	// display error messages
	if ([port status]) {
		printf("%s", [port statusString]);
	}

	// tidy up
	deconfigure();
	
	// display message
	printf("clean exit\n");
	
	return 0;
}
