//-----< MEETING.C >-------------------------------------------------
//
// The "Meeting-Minder" Meeting Timer for Greg F.
//
// "Gee" Job for SRSD 9/96
//
// By: S.C.Hageman -  9/27/96 - 10/2/96       www.sonic.net/~shageman
// 
//-------------------------------------------------------------------
// Rev: 1.0 - SCH 02Oct96 - Initial Release 
// Rev: 1.1 - SCH 17Oct96 - Added blinking red light, 44% RAM 96% ROM
//-------------------------------------------------------------------
// The code is written in CCS PIC-C (www.ccsinfo.com)
//-------------------------------------------------------------------

//-----< Includes >--------------------------------------------------
#include <16c71.h>


//-----< PCM Use directives >----------------------------------------
#use delay(clock = 4000000, RESTART_WDT)
#use standard_io(A)
#use standard_io(B)


//-----< Port/Pin definitions >--------------------------------------
#pragma byte port_b 	= 6

// Lights
#define RED_LIGHT PIN_A2

#define YELLOW_LIGHT PIN_B6

#define GREEN_LIGHT PIN_B7


// A/D Inputs
#define TIME_SET	 PIN_A0
#define BATTERY_CHECK    PIN_A1

// Switches
#define START_STOP PIN_A4


//-----< Program constants >-----------------------------------------
#define DOOMSDAY	0	// Not here yet!!!
#define PUSHED 		0	// Start stop switch pushed, input=0v

#define RED		1
#define YELLOW		2
#define GREEN		3
#define ALL_OFF		4

#define RUN		1	// Run mode
#define STOP		0	// Stop mode

#define OFF		0	// mode off
#define ON		1	// mode on

//-----< Program global variables >----------------------------------
int Set_Time;
long Actual_Time;
int Light_Image;


//-----< General routines >------------------------------------------

void set_lights(int light_on)
{
	if( light_on == GREEN )
	{
		output_high(GREEN_LIGHT);
		output_low(YELLOW_LIGHT);
		output_low(RED_LIGHT);
		Light_Image = 0x80; 
		return;	
	}
	if( light_on == YELLOW )
	{
		output_high(YELLOW_LIGHT);
		output_low(GREEN_LIGHT);
		output_low(RED_LIGHT);
		Light_Image = 0x40; 
		return;	
	}
	if( light_on == RED )
	{
		output_high(RED_LIGHT);
		output_low(GREEN_LIGHT);
		output_low(YELLOW_LIGHT);
		Light_Image = 0x00; 
		return;	
	}
	
	// All off
	output_low(RED_LIGHT);
	output_low(GREEN_LIGHT);
	output_low(YELLOW_LIGHT);
	Light_Image = 0x00;
	return;	
}


//-----< LCD Routines >----------------------------------------------

// LCD is connected to port b, definitions below

// LCD Connections - 
//  RB5  RB4  RB3  RB2  RB1  RB0 - PORT PINS
//   E   R/S   D7   D6   D5   D4 - LCD PINS

		
//-------------------------------------------------------------------
void blip_e_delay()
{
	// Set enable high for 1 cycle then low
	// Designed for 4 MHz clock. Minimum E cycle time is 400 nS.
	#asm
		bsf port_b,5
		nop
		bcf port_b,5
	#endasm
	
	// Wait for longest lcd routine to finish, takes time
	// but saves code in not checking for the busy flag.
	delay_ms(5);
}

//-------------------------------------------------------------------
void blip_e()
{
	// Set enable high for 1 cycle then low
	// Designed for 4 MHz clock. Minimum E cycle time is 400 nS.
	#asm
		bsf port_b,5
		nop
		bcf port_b,5
	#endasm
	
	// Wait for shortest lcd routine to finish, takes time
	// but saves code in not checking for the busy flag.
	delay_ms(1);
}

//-------------------------------------------------------------------
void first_line()
{	
	// Set the LCD to the first display line
	// Send 0xc0 for second line. Use 0x80 to move
	// to the first line.
	port_b = 0x08 | Light_Image;
	blip_e();
	
	port_b = 0x00 | Light_Image;
	blip_e();
}

//-------------------------------------------------------------------
void second_line()
{
	// Set the LCD to the second display line
	// Send 0xc0 for second line. Use 0x80 to move
	// to the first line.
	port_b = 0x0c | Light_Image;
	blip_e();
	
	port_b = 0x00 | Light_Image;
	blip_e();
}

//-------------------------------------------------------------------
void init_lcd()
{
	// Clear and initilize LCD panel to 4 bit mode
	// two line mode, cursor off, display on.
	// RS needs to be low for all of these instructions.
	// -> Takes 60 mS to complete <-
		
	// Send 0x03 three times
	port_b = 0x03;
	blip_e_delay();
	
	port_b = 0x03;
	blip_e_delay();

	port_b = 0x03;
	blip_e_delay();

	// Send 0x02
	port_b = 0x02;
	blip_e_delay();
	
	// send 0x28
	port_b = 0x02;
	blip_e_delay();
	
	port_b = 0x08;
	blip_e_delay();
	
	// send 0x01
	port_b = 0x00;
	blip_e_delay();
	
	port_b = 0x01;
	blip_e_delay();

	// send 0x06
	port_b = 0x00;
	blip_e_delay();
	
	port_b = 0x06;
	blip_e_delay();

	// send 0x0c
	port_b = 0x00;
	blip_e_delay();
	
	port_b = 0x0c;
	blip_e_delay();

	// Send 0x0f to set cursor on with blink
	// Send 0x0e to set cursor on w/o blink
}

//-------------------------------------------------------------------
void write_lcd(byte ch)
{
	// writes the char ch to the lcd. HB then LB.
	// The OR sets RS high 
	
	// Keep the lights the same on port b B6 and B7
	port_b = (ch/0x10) | 0x10 | Light_Image;          
	blip_e();
	
	port_b = (ch & 0x0f) | 0x10 | Light_Image;
	blip_e();
}


//-----< Main Program >----------------------------------------------
main()
{
//----- Local variables -----
short run_mode;
short display_flag;
int time_left;

	//----- Reset Entry Point -----

	//----- Set up port direction reg's -----
	set_tris_b(0b00000000);		// All Output
	
	//----- Turn off all lights -----
	set_lights(ALL_OFF);
	
	//----- Wait for powerup, Initilize LCD -----
	delay_ms(200);
	init_lcd();

	//----- Write a startup message -----
	write_lcd(" Meeting");
	second_line();
	write_lcd("-Minder");
	delay_ms(850);
	init_lcd();
	write_lcd("S.Hagema");
	second_line();
	write_lcd("n   1996");
	delay_ms(850);	
	init_lcd();
	
	//----- Setup the ADC and select channel 0 for input -----
	setup_port_a(RA0_RA1_ANALOG);
	setup_adc(ADC_CLOCK_DIV_8);
	set_adc_channel(TIME_SET);

	//----- Get time -----
	first_line();
	write_lcd("Set Time");
	
	while(input(START_STOP))
	{
		// Get pot position and scale
		Set_Time = read_adc()/4;
		
		// Bound max set time
		if( Set_Time > 60)
			Set_Time = 60;
		
		second_line();
		write_lcd(" = ");
		write_lcd( ((Set_Time / 10) % 10) + '0');
		write_lcd( (Set_Time % 10) + '0');
		
		// Sampling delay
		delay_ms(100);
	}
	
	//----- Wait here till button isn't pushed anymore -----
	while( !input(START_STOP) )
	{
		// Set the pin high again
		output_high(START_STOP);
		delay_ms(10);
	}

	//----- Initilize global variables -----
	init_lcd();
	Actual_Time = 0;
	run_mode = RUN;
	write_lcd("Time Lef");
	
	//----- Start of main stopwatch loop -----			
	while (!DOOMSDAY)
	{	
		// Find the time left
			// Actual_Time unit's = 100 mS / count
			// Set_Time unit's = minutes / count
			// time_left units = minutes / count
			// 600 below = 100mS and 60 sec/min conversion 
		time_left = Set_Time - (Actual_Time/600);
		
		// Set the mode based on the start/stop switch
		
		// Set the pin high again
		output_high(START_STOP);
		delay_ms(10);
		
		if( !input(START_STOP) )
		{
			if( run_mode == RUN )
			{
				// The clock will now be stopped
				run_mode = STOP;
				first_line();
				write_lcd("Pause at");
				second_line();
				write_lcd("  =     ");
				
				// Set the lights off
				set_lights(ALL_OFF);
			}
			else
			{
				// The clock will now be running
				run_mode = RUN;		
				first_line();
				write_lcd("Time Lef");
				second_line();
				write_lcd("t =     ");	
			}
		
			// Wait here till button isn't pushed anymore
			while( !input(START_STOP) )
			{
				// Set the pin high again
				output_high(START_STOP);
				delay_ms(10);
			}
		}		
		// Figure out which light should be on
		if( run_mode == RUN)
		{
			// RUN, OK to set some light's
			if( time_left > 3)
			{
				// It's green
				set_lights(GREEN);
			}
			else
			{
				// Time is <= 3 for sure if here
			
				if( time_left == 0)
				{
					// Write ending message
					first_line();
					write_lcd("  Press ");
					second_line();
					write_lcd("Reset   ");
					
					// Flash light on and off every second
					// for 10 minutes then goto sleep
					// Reuses Actual_Time and run_mode variable
					run_mode = OFF;
					for( Actual_Time = 0 ; Actual_Time <= 2400 ; Actual_Time++ )
					{
					// (0.25 Sec/Loop * 2400 Loops) / 60 Sec/Min = 10 Minutes
						delay_ms(250);
						if( run_mode == ON )
						{
							set_lights(RED);
							run_mode = OFF;
						}
						else
						{
							set_lights(ALL_OFF);
							run_mode = ON;
						}
					}	
										
					// Light's out!
					set_lights(ALL_OFF);

					// Good night	
					sleep();		
				} 
			
				// Time was not zero but is < 3 so it's yellow
				set_lights(YELLOW);
			} 		
			
			// Delay and increment actual time in 100's of mSec
			Actual_Time += 1;
			
			// The nominal delay would be 100 mS, but lots of
			// stuff happens in the loop that causes time to be
			// eaten up! The actual number is adjusted based
			// on a 4.0 MHz PIC and correcting for the other
			// delays (i.e. this is a *fudged* number).
			delay_ms(72);
		}
		else
		{	
			// Mode was stop
			// Lights off
			set_lights(ALL_OFF);
			
			// Delay but don't increment			
			delay_ms(100);
		}	
		
		if( run_mode == RUN)
		{
			if( display_flag )
			{
				// Write the time left on the display
				second_line();
				write_lcd("t = ");
				write_lcd( ((time_left / 10) % 10) + '0');
				write_lcd( (time_left % 10) + '0');
				write_lcd(" *");
				display_flag = !display_flag;
			}
			else
			{
				// Write the time left on the display
				second_line();
				write_lcd("t = ");
				write_lcd( ((time_left / 10) % 10) + '0');
				write_lcd( (time_left % 10) + '0');
				write_lcd("  ");
				display_flag = !display_flag;
			}
		}
		else
		{
			// Stop mode display	
			// Write the time left on the display
			second_line();
			write_lcd("  = ");
			write_lcd( ((time_left / 10) % 10) + '0');
			write_lcd( (time_left % 10) + '0');
			write_lcd("  ");
		}
		
	} // end of main while loop (forever loop)

} // end of main

//-----< Fini - Meeting.C >----------------------------------------------
