//Filename: ppc.c
//Purpose: Main code for ppc.
//$Id: ppc.c,v 1.8 1997/07/29 21:11:35 rkirkpat Exp $

/*
 * Copyright (c) 1996-1997 by Ryan Kirkpatrick (rkirkpat@nag.cs.colorado.edu). 
 *   All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */ 

#include "ppc.h"

unsigned short base;

void help(char *str)
//POST: Help has been printed, and program run terminated.
{
	printf("Invalid Arguments\n");
	printf("Usage: %s [lpn]\n",str);
	printf("            lpn  The parallel port to use, ie lp1, etc...\n");
	printf("                   The default is lp0.\n\n");
	exit(1);
}

void WriteData()
//POST: The inputed data has been written to the port, and the status and
//        data displays updated.
{
	char type;
	int dec = 0;
	char str[4];
	char bin[9];
	int bcd = 0;

	//Ask for type of data entry.
	do 
	{
		//clear bottem of screen.
		move(16,0); 
		clrtobot();

		//Ask
		mvaddstr(17,0,"What type of data entry? (B)inary, (D)ecimal, B(C)D: ");
		type = toupper(getch());
	} 
	while ((type != 'B') && (type != 'D') && (type != 'C'));

	//Ask for data
	//Turn on echo, and turn off no delay mode.
	nodelay(stdscr,FALSE);
	echo();

	do
	{
		move(18,0);
		clrtobot();

		//Choose right question to ask and type of data to expect.
		switch(type)
		{
			case 'B': mvaddstr(19,0,"Enter Binary Number: ");
				  getstr(bin);
				  break;
			case 'D': mvaddstr(19,0,"Enter Decimal Number: ");
				  getstr(str);
				  dec = atoi(str);
				  break;
			case 'C': mvaddstr(19,0,"Enter BCD Number: ");
				  getstr(str);
				  bcd = atoi(str);
				  break;
		}
	}
	while ((dec > 255) || (dec < 0) || (bcd > 99) || (bcd < 0));

	//Put things back the way they were.
	noecho();
	nodelay(stdscr,TRUE);

	//Convert as needed.
	if (type == 'B')
		dec = bin2dec(bin);
	if (type == 'C')
		dec = dec2bcd(bcd);
	
	//Write the data.
	outb(dec,base);

	//Update display
	UpdateStatus(inb(base+1));
	UpdateData(inb(base));
}

void ToggleControl ()
//POST: The inputed data has been written to the port, and the status and
//        data displays updated.
{
	char pos_char;
	int pos = -1;

	//Needed since we can not read the stat of this bit, we just
	//  have to remember it. :(
	static int extModeDir = 1;

	//Ask for data.
	do 
	{
		//clear bottem of screen.
		move(16,0); 
		clrtobot();

		//Ask
		mvaddstr(17,0,"Select which bit to modify: ");
		pos_char = getch();
		mvaddch(17,28,pos_char);
		pos = pos_char - 48;
	} 
	while ((pos > 8) || (pos < 0));

	//Read, Modify (setting extModeDir bit correctly) bit, and write.
	outb(moddec(setdec(inb(base+2),5,extModeDir),pos),base+2);

	//Update display.
	if (pos == 5)
		if (extModeDir == 0)
			extModeDir = 1;
		else
			extModeDir = 0;
	UpdateControl(setdec(inb(base+2),5,extModeDir));
}

int main(int argc, char* argv[])
{
	int choice = 0;

	//Determine which port to use, default to lp0.
	//No arguments, default to lp0
	if (argc == 1)
		base = 0x3bc;
	else
	{
		//Invalid Arguements, print help and exit.
		if ((argv[1][0] != 'l') || (argv[1][1] != 'p'))
			help(argv[0]);

		//Select appropriate port, defaulting once agian to lp0
		switch (argv[1][2])
		{
			case '0': base = 0x3bc; break;
			case '1': base = 0x378; break;
			case '2': base = 0x278; break;
			otherwise: base = 0x3bc;
		}
	}

	//Get permission for port use.
	if (ioperm(base,3,1))
	{
		printf("Unable to gain permission to use port, make sure\n");
		printf("  that the program is run as root.\n");
		exit(1);
	}

	//Initialize the extModeDir bit so it has a known value.
	outb(setdec(inb(base+2),5,1),base+2);

	//Set up the screen for the first time.
	InitScreen();
	Redraw(base);
	UpdateStatus(inb(base+1));
	UpdateData(inb(base));
	UpdateControl(setdec(inb(base+2),5,1));

	//Main loop
	while (choice != '6')
	{
		//Get user input, and display it.
		choice = getch();
		mvaddch(21,44,choice);

		//Act on input
		switch(choice)
		{
			case '1': UpdateStatus(inb(base+1)); break;
			case '2': UpdateData(inb(base)); break;
			case '3': WriteData(); break;
			case '4': ToggleControl(); break;
			case '5': UserHelp(); break;
		}

		//Redraw the menu.
		RedrawMenu();
	}
	
	//Reset the screen back to before.
	erase();
	nocbreak();
	refresh();
	reset_shell_mode();

	//Return successful.
	return 0;
}

//EOF
