/*
	SC1DM232.C
	
	CM71xx/Z1 and CM72xx/Z2

	Shows the use of DMA0 for RS232 communication on serial port 0 with
	another RS232 device.

	The PC terminal or communication program should be set for 9600 baud, 
	8 data bits, 1 stop bit and no parity. If the terminal program in
	windows is used, select terminal font under terminal preference option.
*/

#use vdriver.lib

char *text[] = {
 "\x1b[2J",
 "\x1b[03;05H**********************************************************************",
 "\x1b[04;05H* This sample program uses the DMA channel 0 for RS232 communication *",
 "\x1b[05;05H* between the Z180 port0 and another RS232 device. This method is    *",
 "\x1b[06;05H* ideal for half duplex RS232 communication. Note that the DMA0 is   *",
 "\x1b[07;05H* either waiting to receive a specified number of bytes or it is     *",
 "\x1b[08;05H* trasmitting a specified number of bytes. Never both.               *",
 "\x1b[09;05H* Key Choices:                                                       *",
 "\x1b[10;05H* 'a' Toggle leds                                                    *",
 "\x1b[11;05H* 'b' Beep for 1 second                    ***********************   *",
 "\x1b[12;05H* 'f' Move time adjust field               *                     *   *",
 "\x1b[13;05H* 'u' Increment time adjust field          *                     *   *",
 "\x1b[14;05H* 'd' Decrement time adjust field          ***********************   *",
 "\x1b[15;05H* Type your selection :                                              *",
 "\x1b[16;05H**********************************************************************"
};

char receive_flag;

CoData ShowMenu;
CoData ShowTime;
CoData GetKey;
int ledonoff;
int beeponoff;

main()
{
	int i;
	struct tm dtime;
	struct tm thistime;
	int old_sec;
	char data;     
	int ercode;
	char cursor;
	char nextcursor[] = {1,3,3,4,6,6,7,9,9,11,11,12,14,14,15,17,17,18,1};
	char dummy[20];
	char dummy2[20];
	char prompt[] = "\x1b[15;30H";
	char timestring[20];
	
	VdInit();         // initialize the virtual driver

	tm_rd(&thistime); // read the real time clock

	// adjust real time clock if not yet running or out of range
	if( (thistime.tm_year < 95) || (thistime.tm_year >99) )
	{
		thistime.tm_hour = 8;
		thistime.tm_min = 0;
		thistime.tm_sec = 0;
		thistime.tm_mon = 6;
		thistime.tm_mday = 1;
		thistime.tm_year = 95;
		thistime.tm_wday = 4;
		tm_wr(&thistime);
	}  

	DMA0_SerialInit(0, 0x04, 9600/1200);   // initialize DMA0 to support
														// serial chan 0 at 9600 baud,
														// 1 start, 1 stop and 8 data 
														// bit.
	cursor = 1;
	old_sec = ledonoff = beeponoff = 0;
	strcpy(timestring,"\x1b[12;50H");      

	while(1)
	{
		costate  ShowMenu init_on        // show menu to the dumb terminal
		{
			for(i=0;i<15;i++)
			{
				waitfor(DMA0_Tx(0, phy_adr(text[i]), strlen(text[i]), 0, 0) ==1);
			}
			sprintf(dummy2,"\x1b[%02d;%02dH^",13,cursor+50);
			waitfor(DMA0_Tx(0, phy_adr(dummy2), strlen(dummy2), 0, 0)==1);
			CoBegin(&GetKey);
		}

		costate
		{
			waitfor(DelayMs(25L));        // scan beeper every 25 ms.
			lc_beepscan();
		}
		
		costate GetKey                   
		{
			waitfor(DMA0_Tx(0, phy_adr(prompt), 8, 0, 0)==1);
													// locate cursor for effects
			receive_flag = 0;
			waitfor(DMA0_Rx(0, phy_adr(&data), 1, 1, 0)==1);
													// set DMA0 to receive one serial byte
													// with interrupt
			waitfor(receive_flag || DelayMs(250L));
													// wait for data or 250 ms
			if(receive_flag)              // if data is received
			{
					switch(data)
					{
							case 'a':
							case 'A':
									up_beep(100);                 // beep for 100 ms
									if(ledonoff) ledonoff = 0;
									else ledonoff = 1;
									outport(CS1, ledonoff);
									outport(CS1+1, ledonoff);
									outport(CS1+2, ledonoff);
									outport(CS1+3, ledonoff);
									CoBegin(&ShowTime);
									break;
							case 'b':
							case 'B':
									up_beep(1000);                // beep for 1000 ms
									CoBegin(&ShowTime);
									break;
							case 'f':   // move the '^' for RTC adjustment
							case 'F':      
									up_beep(100);                 // beep for 100 ms
									sprintf(dummy2,"\x1b[%02d;%02dH ",13,cursor+50);
									waitfor(DMA0_Tx(0, phy_adr(dummy2), 
												strlen(dummy2), 0, 0)==1);
									cursor = nextcursor[cursor];
									sprintf(dummy,"\x1b[%02d;%02dH^",13,cursor+50);
									waitfor(DMA0_Tx(0, phy_adr(dummy), 
												strlen(dummy), 0, 0)==1);
									CoBegin(&ShowTime);
									break;
							case 'u':
							case 'd':
							case 'U':
							case 'D':
									up_beep(100);           // beep for 100 ms
									old_sec = adjust_rtc(data, cursor);
									CoBegin(&ShowTime);
									break;                                          
							default:
									up_beep(250);           // beep for 250 ms if
																	// a non key is selected.
									CoBegin(&ShowMenu);
									break;
					}
			}
			else
			{
					 DMA0_Off();   // reset the DMA0, if nothing receive
					 CoBegin(&ShowTime);    // show the time
			}
			
		}

		costate ShowTime
		{
			tm_rd(&dtime);
			if(old_sec != dtime.tm_sec)
			{
				sprintf(timestring+8, "%02d-%02d-%02d-%d %02d:%02d:%02d",
											dtime.tm_mon, dtime.tm_mday, dtime.tm_year, dtime.tm_wday,
											dtime.tm_hour, dtime.tm_min, dtime.tm_sec);
				waitfor(DMA0_Tx(0, phy_adr(timestring), strlen(timestring),0, 0)==1);
				old_sec = dtime.tm_sec;
			}
			CoBegin(&GetKey);                                  
		}                 
		hitwd();
		runwatch();
		
	}


}

// Adjust the real time clock based on the adjust field position and
// the character data from the dumb terminal.
int adjust_rtc(int data, int cursor)
{
		int monlimit, temp;
		struct tm thistime;
		
		tm_rd(&thistime);
		switch(thistime.tm_mon)
		{
			case 1:
			case 3:
			case 5:
			case 7:
			case 8:
			case 10:
			case 12: monlimit = 31;
						break;
			case 4:
			case 6:
			case 9:
			case 11:
						monlimit = 30;
						break;
			case 2:
						if(((thistime.tm_year+1900) % 4)==0)
							monlimit = 29;
						else
							monlimit = 28;
						break;
			default:
						break;
		}  

		if((data == 'u') || (data == 'U'))
		{
			switch(cursor)
			{
				case 1:
						thistime.tm_mon = thistime.tm_mon + 1;
						if(thistime.tm_mon > 12) thistime.tm_mon = 1;
						break;
				case 3:
						thistime.tm_mday = thistime.tm_mday + 10;
						if(thistime.tm_mday > monlimit)
							thistime.tm_mday = 1;
						break;
				case 4:
						thistime.tm_mday = thistime.tm_mday + 1;
						if(thistime.tm_mday > monlimit) 
							thistime.tm_mday = 1;
						break;
				case 6:
						thistime.tm_year = thistime.tm_year + 10;
						if(thistime.tm_year > 99) thistime.tm_year = 0; 
						break;
				case 7:
						thistime.tm_year = thistime.tm_year + 1;
						if(thistime.tm_year > 99) thistime.tm_year = 0;
						break;
				case 9:
						thistime.tm_wday = thistime.tm_wday + 1;
						if(thistime.tm_wday > 6) thistime.tm_wday = 0;
						break;
				case 11:
						thistime.tm_hour = thistime.tm_hour + 10;
						if(thistime.tm_hour > 23) thistime.tm_hour = 0;
						break;
				case 12:
						thistime.tm_hour = thistime.tm_hour + 1;
						if(thistime.tm_hour > 23) thistime.tm_hour = 0;
						break;
				case 14:
						thistime.tm_min = thistime.tm_min + 10;
						if(thistime.tm_min > 59) thistime.tm_min = 0;
						break;
				case 15:
						thistime.tm_min = thistime.tm_min + 1;
						if(thistime.tm_min > 59) thistime.tm_min = 0;
						break;
				case 17:
						thistime.tm_sec = thistime.tm_sec + 10;
						if(thistime.tm_sec > 59) thistime.tm_sec = 0;
						break;
				case 18:
						thistime.tm_sec = thistime.tm_sec + 1;
						if(thistime.tm_sec > 59) thistime.tm_sec = 0;
						break;
			}
		}
		else
		{
			switch(cursor)
			{
				case 1:
						thistime.tm_mon = thistime.tm_mon - 1;
						if(thistime.tm_mon < 1 ) thistime.tm_mon = 12;
						break;
				case 3:
						temp = thistime.tm_mday;
						temp = temp - 10;
						if(temp < 1) temp = monlimit;
						thistime.tm_mday = temp;
						break;
				case 4:
						temp = thistime.tm_mday;
						temp = temp - 1;
						if(temp < 1) temp = monlimit;
						thistime.tm_mday = temp;
						break;
				case 6:
						temp = thistime.tm_year;
						temp = temp - 10;
						if(temp < 0) temp = 99;
						thistime.tm_year = temp;
						break;
				case 7:
						temp = thistime.tm_year;
						temp = temp - 1;
						if(temp < 0) temp = 99;
						thistime.tm_year = temp;
						break;
				case 9:
						temp = thistime.tm_wday;
						temp = temp - 1;
						if(temp < 0) temp = 6;
						thistime.tm_wday = temp;
						break;
				case 11:
						temp = thistime.tm_hour;
						temp = temp - 10;
						if(temp < 0) temp = 23;
						thistime.tm_hour = temp;
						break;
				case 12:
						temp = thistime.tm_hour;
						temp = temp - 1;
						if(temp < 0) temp = 23;
						thistime.tm_hour = temp;
						break;
				case 14:
						temp = thistime.tm_min;
						temp = temp - 10;
						if(temp < 0) temp = 59;
						thistime.tm_min = temp;
						break;
				case 15:
						temp = thistime.tm_min;
						temp = temp - 1;
						if(temp < 0) temp = 59;
						thistime.tm_min = temp;
						break;
				case 17:
						temp = thistime.tm_sec;
						temp = temp - 10;
						if(temp < 0) temp = 59;
						thistime.tm_sec = temp;
						break;
				case 18:
						temp = thistime.tm_sec;
						temp = temp - 1;
						if(temp < 0) temp = 59;
						thistime.tm_sec = temp;
						break;
			}
		}
		tm_wr(&thistime);
		return(thistime.tm_sec - 1); // return sec - 1 of new set time
}

// Interrupt service routine for DMA0.
#INT_VEC DMA0_VEC dma0_int;
interrupt void dma0_int()
{
	outport(DSTAT, '\B00100000' | (inport(DSTAT) & '\B10101000'));
	receive_flag = 1;
}


	

