
 		/* PRINTER port output examples */

#include	<stdio.h>
#include	<dos.h>	          /*inport, outport, delay function used.*/
#include	<conio.h>	  /*cursor control*/

/* main function prototypes */

/*	INITIALISATION */
void	init_screen();
void	find_port();
void	port_address();
void	init_port();

/*	TOPMENU */
void	main_menu();
void	main_menu_choice();

/* 	STATUS REGISTER ROUTINES */
void	status();
void	power_switches();

/* 	CONTROL REGISTER ROUTINES */
void	control();

/* 	DATA REGISTER ROUTINES */
void	data();
void	sub_menu();
void	sub_menu_option();
void	initial_data_out();
void	data_out();

/* 	embedded function prototypes */
void	up();
void	down();
void	left();
void	right();
void	finish();
void	terminate();
char	get_menu_option();


/* global variables */

typedef	unsigned int 	WORD;
int	data_reg,status_reg,cont_reg;
unsigned char	init_val=0x00; 		/* set initial value to 0 and limit
					   values to 0->255 only */

main()
{

	/* local variable */
	char	choice;

	/* INITIALISE SYSTEM */
	init_screen();
	find_port();
	port_address();
	init_port();

	/* TOP MENU */
	main_menu();

	{

		do
		{
			choice = get_menu_option();

			if	(choice == 'S')
			{
				status();
			}

			if	(choice == 'O')
			{
				data();
			}

			if	(choice == 'C')
			{
				control();
			}

		}

	while	(choice != 'Q');

	terminate();                  /* programme ends here */


	}



	return;
}


/******************************* INITIALISATION **************************/

void	init_screen()
/* initialise screen */

{
	clrscr();                        /* of any previous rubbish */
	_setcursortype(_NOCURSOR);       /* temporarily remove cursor */
}


void	find_port()
/* find out the address of the printer port */

{

	/****************************************************
	* THIS FUNCTION READS THE BIOS ADDRESS 0040h WITH AN
	* OFFSET OF 08h TO OBTAIN THE ADDRESS OF LPT_1.
	****************************************************/
	data_reg = *(WORD far *) MK_FP (0x0040,0x08);
	status_reg = data_reg + 1;
	cont_reg = data_reg + 2;

}


void	port_address()
/* print port address on screen */

{
	printf("\t\t\tdata register is at address: %0Xh\n", data_reg);
	printf("\t\t\tstatus register is at address: %0Xh\n", status_reg);
	printf("\t\t\tcontrol register is at address: %0Xh\n", cont_reg);
}


void	init_port()
/* initialise printer port */

{

	/* output data */
	outportb(data_reg,init_val);
	outportb(cont_reg,0x0b);	/* turn all outputs off */

}
/***************************** end of INITIALISATION **********************/


/******************************* TOPMENU **********************************/

void	main_menu()
/* print menu options on screen */

{

	/* position start of menu */
	/* print menu */
	printf("\n\n\n");
	printf("\t\t    ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º              MAIN MENU                 º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter S to read Status register        º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter O to write to data register      º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter C to write to Control register   º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter Q to Quit the programme          º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼\n\n");

}

/************************** end of TOPMENU *******************************/



/********************* STATUS REGISTER ROUTINES **************************/

void	status()
/* Routine that reads the switch inputs (via the STATUS register) that are
	connected to the parallel port  */

{
	/* local variables */
	unsigned char	raw_data,corrected_data,switches;

	while (!kbhit()) /* do all of the following until a key is pressed */

	{
		clrscr();

		printf("\n\n\n\t\t\t PRESS ANY KEY TO QUIT ROUTINE");

		power_switches();       /* provide power for the switches */


		/*****************************************************
			PARALLEL PORT STATUS REGISTER

			d7 = /BUSY		pin 11	       *inverted*
			d6 = /ACKNOWLEDGE	pin 10
			d5 =  PAPER OUT	pin 12
			d4 =  SELECT   	pin 13
			d3 = /ERROR		pin 14
			d2 = unconfigured			not used
			d1 = unconfigured			not used
			d0 = unconfigured			not used
		*****************************************************/

		/* read Status register and shift right 3 times */
		/* inputs can now be read on d0 to d4  */
		raw_data = inportb(status_reg) >> 3;

		/* mask off bit d4 and invert its value to correct polarity */
		corrected_data = (~raw_data & 0X10);

		/* NOW COMES THE CLEVER BIT!
		   The upper nibble has been masked off, d4 inverted
		   and equated to corrected_data.
		   The lower nibble now needs to be masked off to dump
		   the upper nibble.
		   The upper and lower nibbles are now added together
		   and equated to switches. */
		switches = (corrected_data | (raw_data & 0X0f));

		printf("\n\n\n\t\t\t       Status Register = % .02X\r",switches);
		delay(200);         /* switch debounce */
	}

	finish();
	return;

}


void	power_switches()
/* set the /select in (D3 in control register) to provide power
	for the switches */

{
	/* output data */
	outportb(cont_reg,0x03);
}

/****************** end of STATUS REGISTER ROUTINES ***********************/

/******************** DATA REGISTER ROUTINES ******************************/

void	data()
{

	/* local variable */
	char	choice;

	clrscr();
	sub_menu();
	initial_data_out();
	sub_menu_option();

}


 void	sub_menu()
/* print menu options on screen */

{
	/* position start of menu */
	/* print menu */
	printf("\n\n\n");
	printf("\t\t    ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º          DATA REGISTER MENU            º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter L to shift a single bit Left     º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter R to shift a single bit Right    º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter U to increment binary count Up   º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter D to decrement binary count Down º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    º enter Q to Quit                        º\n");
	printf("\t\t    º                                        º\n");
	printf("\t\t    ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼\n\n");

}

void	initial_data_out()

{
	/* print the value of the data register on screen */
	printf("\n\t\t\t    initial output state = % 02X",init_val);
}

void	sub_menu_option()
/* get the required MENU option */

{
	/* local variable */
	char	choice;

	do

	{
		choice = get_menu_option();

		if	(choice == 'U')
		{
			up();
		}

		if	(choice == 'D')
		{
			down();
		}

		if	(choice == 'L')
		{
			left();
		}

		if	(choice == 'R')
		{
			right();
		}

		data_out();

	}

	while	(choice != 'Q');      /* program returns to main menu */

	finish();


}


void	up()
/* increment output by one upto FFh and stop */

{
	/* set upper limit */
	if (init_val <= 0xFE)
	{
		init_val++;
	}

	/* if already at upper limit dont go any further */
	else
	{
		init_val = 0xFF;
	}
}

void	down()
/* decrement output down by one to 00h and stop */

{
	/* set lower limit */
	if (init_val >= 1)
	{
		init_val--;
	}

	/* if already at lower limit dont go any further */
	else
	{
		init_val = 0;
	}

}


void	left()
/* shift left a single bit upto 80h and stop */

{
	/* set start condition by preloading the lsb */
	if(init_val == 0)
	{
		init_val++;
	}

	/* shift left */
	else
	{
		init_val <<= 1;
	}

}


void	right()
/* shift right a single bit down to 00h.
no need to stop as bits are 'lost'as there is no rotate through carry !! */

{
	init_val >>=1;

}


void	data_out()
{
	printf("\r\t\t\t    current output state = % .02X",init_val);

	outportb(data_reg,init_val);

}

/****************** end of DATA REGISTER ROUTINES ************************/


/******************* CONTROL REGISTER ROUTINES ***************************/

void	control()
/* Exercises the LED's attached to the printer port via the CONTROL register */

{
	/* initialise outputs */
	outportb(cont_reg,0x0b);	/* switch all outputs off */
	clrscr();
	printf("\n\n\n\t\t\t PRESS ANY KEY TO QUIT ROUTINE");

	delay(1000);


	while (!kbhit()) /* do all of the following until a keypress */
	{


		/********************************************************
			PARALLEL PORT CONTROL REGISTER

			d7 = unconfigured			not used
			d6 = unconfigured			not used
			d5 = 		    DIRECTION CONTROL   not used
			d4 = 		    IRQ ENABLE		not used

			d3 = /SELECT IN		pin 17         (inverted)
			d2 = /INITIALISE	pin 16         (inverted)
			d1 = /AUTOFEED		pin 14
			d0 = /STROBE		pin 1          (inverted)
		********************************************************/

		/* output following bit pattern to cycle leds
		   NOTE: cannot use a for loop as the required bit
			 pattern is not contiguous

			0x0a	strobe on     (inverted)
			0x09	autofeed on   (inverted)
			0x0f	initialise on
			0x03	select-in on  (inverted)
			0x0b	all outputs off

		*/

		{
			/* shift left */
			outportb(cont_reg,0x0a);        /* strobe on */
			delay(1000);
			outportb(cont_reg,0x09);        /* autofeed on */
			delay(1000);
			outportb(cont_reg,0x0f);        /* initialise on */
			delay(1000);
			outportb(cont_reg,0x03);        /* select-in on */
			delay(1000);

			/* shift right */
			outportb(cont_reg,0x0f);        /* initialise on */
			delay(1000);
			outportb(cont_reg,0x09);        /* autofeed on */
			delay(1000);

		}

	}
	finish();
	return;
}


/******************* end of CONTROL REGISTER ROUTINES ********************/


/********************* embedded functions ********************************/

char	get_menu_option()
/* This routine returns the value of menu selected option */

{
	char	choice;

	/* using getch() does not echo choice to screen, also
	   using toupper makes the case of the keyboard insensitive */
	choice = toupper(getch());
	return(choice);

}

void	finish()
/* reset printer port and clear current menu option data from screen */

{
	outportb(data_reg,0x00);
	outportb(cont_reg,0x0b);
	clrscr();
	main_menu();
}


void	terminate()
/* reset printer port and clear all program data from screen */

{
	clrscr();
	_setcursortype(_NORMALCURSOR);
	exit(1);
}
/************************ END OF PROGRAMME *******************************/
