/***************************
Program:	Beamer-Commander for Sanyo PLV-Z4
Author:	ZZottel (visit www.zzottel.de)
Compiler:	Visual C++ 6.0 SP6
Date:		2008-11-24
**************************/

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>

HANDLE init_com_port(char* comport);
int close_com_port(HANDLE hCom);
int send_data(HANDLE hCom, char* befehl);
int receive_data(HANDLE hCom, char* zeichen, int laenge);

int main(int argc, char* argv[])
{
	HANDLE hCom;
	char zeichen[78];
	int error_code = 0;
	int i;

	char commands[116][27] = 
	{
		"C00", "POWER_ON",
		"C01", "QUICK_POWER_OFF",
		"C02", "POWER_OFF",
		"C0D", "VIDEO_MUTE_ON",
		"C0E", "VIDEO_MUTE_OFF",
		"C0F", "SCREEN_NORMAL_SIZE",
		"C10", "SCREEN_FULL_SIZE",
		"C11", "IMAGE_LIVING",
		"C12", "IMAGE_CREATIVE_CINEMA",
		"C13", "IMAGE_PURE_CINEMA",
		"C14", "IMAGE_1",
		"C15", "IMAGE_2",
		"C16", "IMAGE_3",
		"C17", "IMAGE_4",
		"C18", "IMAGE_VIVID",
		"C19", "IMAGE_DYNAMIC",
		"C1A", "IMAGE_POWERFUL",
		"C1B", "IMAGE_NEUTRAL",
		"C1C", "MENU_ON",
		"C1D", "MENU_OFF",
		"C1E", "DISPLAY_CLEAR",
		"C23", "VIDEO_SOURCE_VIDEO",
		"C24", "VIDEO_SOURCE_S-VIDEO",
		"C25", "VIDEO_SOURCE_COMPONENT_1",
		"C26", "VIDEO_SOURCE_COMPONENT_2",
		"C2A", "POWER_MANAGEMENT_ON",
		"C2B", "POWER_MANAGEMENT_OFF",
		"C2C", "SCREEN_ZOOM_SIZE",
		"C2D", "SCREEN_NATURAL_WIDE_1",
		"C2E", "SCREEN_NATURAL_WIDE_2",
		"C3A", "POINT_RIGHT",
		"C3B", "POINT_LEFT",
		"C3C", "POINT_UP",
		"C3D", "POINT_DOWN",
		"C3F", "ENTER",
		"C50", "COMPUTER_(ANALOG_RGB)",
		"C51", "COMPUTER_(SCART)",
		"C53", "HDMI",
		"C63", "SCREEN_CAPTION_IN_SIZE",
		"C65", "SCREEN_FULL_THROUGH_SIZE",
		"C66", "SCREEN_NORMAL_THROUGH_SIZE",
		"C67", "D4_CONTROL_ON",
		"C68", "D4_CONTROL_OFF",
		"C72", "LAMP_MODE_AUTO_1",
		"C73", "LAMP_MODE_AUTO_2",
		"C74", "LAMP_MODE_NORMAL",
		"C75", "LAMP_MODE_ECO",
		"C76", "CEILING_ON",
		"C77", "CEILING_OFF",
		"C78", "REAR_ON",
		"C79", "REAR_OFF",
		"C7A", "LOGO_OFF",
		"C7B", "LOGO_DEFAULT",
		"C7C", "LOGO_USER",
		"C7D", "LOGO_CAPTURE",
		"C89", "AUTO_PC_ADJ.",
		"C8E", "KEYSTONE_UP",
		"C8F", "KEYSTONE_DOWN"
	};

	if(argc < 3)
	{
		printf("Beamer-Commander for Sanyo PLV-Z4\t2008-11-23\r\n");
		printf("This tool uses the serial service port to remote control the beamer.\r\n");
		printf("For more information visit: www.zzottel.de\r\n\r\n");
		printf("Usage: %s <port> <command>\r\n", argv[0]);
		printf("Example: %s COM1 status\r\n\r\n", argv[0]);
		printf("Following status read commands are available:\r\n");
		printf("status\t\tGet the projector status\r\n");
		printf("input\t\tGet the selected Input\r\n");
		printf("lamp_time\tGet the total lamp running time\r\n");
		printf("setting\t\tGet the screen setting status such as Ceiling / Rear\r\n");
		printf("temp\t\tGet the temperature data inside a projector\r\n\r\n");
		printf("Following functional execution commands are available:\r\n");
		printf("managed_power_off\r\n");
		for (i=1;i<116;i=i+2)
			printf("%s\r\n", strlwr(commands[i]));
		exit(0);
	}

	hCom = init_com_port(strupr(argv[1]));

	for (i=0;i<116;i++)
	{	
		if (strcmp(strupr(argv[2]), commands[i]) == 0)
		{	
			send_data(hCom, commands[i-(i % 2)]); //even elements in array are the command-strings for the Z4
			if ((receive_data(hCom, zeichen, 2) == 0) && (zeichen[0] == 0x06))
			{
				if (	(strcmp(commands[i-(i % 2)], "C23") == 0) ||
						(strcmp(commands[i-(i % 2)], "C24") == 0) ||
						(strcmp(commands[i-(i % 2)], "C25") == 0) ||
						(strcmp(commands[i-(i % 2)], "C26") == 0) ||
						(strcmp(commands[i-(i % 2)], "C50") == 0) ||
						(strcmp(commands[i-(i % 2)], "C51") == 0) ||
						(strcmp(commands[i-(i % 2)], "C53") == 0) )
				{
					printf("Input source is changing now...\r\n");
					Sleep(5000); //input selection needs up to 5 secs to settle
				}
				printf("%s ok\r\n", commands[i-(i % 2)+1]); //odd elements in array are the description
				error_code=2; //means that command is executed successfully
			}
			else
			{
				printf("%s failed\r\n", commands[i-(i % 2)+1]);
				error_code=1;
			}
		}
	}

	if (error_code == 2) //check if command is already excecuted
		error_code=0;

	else if (strcmp(strupr(argv[2]),"MANAGED_POWER_OFF") == 0)
	{
		send_data(hCom, "CR0");
		if (receive_data(hCom, zeichen, 3) == 0)
		{
			if ((zeichen[0] == 0x38) && (zeichen[1] == 0x30))
				printf("Status: Standby\r\n");
			
			else
			{
				int power_down = 0;
				send_data(hCom, "C01");
				if ((receive_data(hCom, zeichen, 2) == 0) && (zeichen[0] == 0x06))
				{
					printf("Beamer is cooling down");
					while (power_down==0)
					{
						printf(".");
						Sleep(3000);
						send_data(hCom, "CR0");
						if (receive_data(hCom, zeichen, 3) == 0)
						{
							if ((zeichen[0] == 0x38) && (zeichen[1] == 0x30))
							{
								printf("\r\nStatus: Standby\r\n");
								power_down = 1;
							}
						}
						else
						{
							printf("MANAGED POWER OFF failed\r\n");
							error_code=1;
						}
					}
				}
			}
		}
		else
		{
			printf("MANAGED POWER OFF failed\r\n");
			error_code=1;
		}
	}
	
	else if (strcmp(strupr(argv[2]),"STATUS") == 0)
	{	
		send_data(hCom, "CR0");
		if (receive_data(hCom, zeichen, 3) == 0)
		{
			if ((zeichen[0] == 0x30) && (zeichen[1] == 0x30))
				printf("Status: Power ON\r\n");
			
			else if ((zeichen[0] == 0x38) && (zeichen[1] == 0x30))
				printf("Status: Standby\r\n");
		
			else if ((zeichen[0] == 0x34) && (zeichen[1] == 0x30))
				printf("Status: Processing Countdown\r\n");

			else if ((zeichen[0] == 0x32) && (zeichen[1] == 0x30))
				printf("Status: Processing Cooling down\r\n");

			else if ((zeichen[0] == 0x31) && (zeichen[1] == 0x30))
				printf("Status: Power Failure\r\n");

			else if ((zeichen[0] == 0x32) && (zeichen[1] == 0x38))
				printf("Status: Processing cooling down due to abnormal temperature\r\n");

			else if ((zeichen[0] == 0x38) && (zeichen[1] == 0x38))
				printf("Status: Standby after Cooling Down due to abnormal temperature\r\n");

			else if ((zeichen[0] == 0x32) && (zeichen[1] == 0x34))
				printf("Status: Processing Power Save / Cooling Down\r\n");

			else if ((zeichen[0] == 0x30) && (zeichen[1] == 0x34))
				printf("Status: Power Save\r\n");

			else if ((zeichen[0] == 0x32) && (zeichen[1] == 0x31))
				printf("Status: Processing Cooling Down after OFF due to lamp failure\r\n");

			else if ((zeichen[0] == 0x38) && (zeichen[1] == 0x31))
				printf("Status: Standby after Cooling Down due to lamp failure\r\n");

			else
			{
				printf("Response from beamer is unknown.\r\n");
				error_code=1;
			}
		}
	}

	else if (strcmp(strupr(argv[2]),"INPUT") == 0)
	{	
		send_data(hCom, "CR1");
		if (receive_data(hCom, zeichen, 2) == 0)
		{
			if (zeichen[0] == 0x30)
				printf("Video is selected\r\n");

			else if (zeichen[0] == 0x31)
				printf("S-Video is selected\r\n");

			else if (zeichen[0] == 0x32)
				printf("Component1 is selected\r\n");

			else if (zeichen[0] == 0x33)
				printf("Component2(D4-Video) is selected\r\n");

			else if (zeichen[0] == 0x34)
				printf("HDMI is selected\r\n");

			else if (zeichen[0] == 0x35)
				printf("Computer(Analog) is selected\r\n");

			else if (zeichen[0] == 0x36)
				printf("Computer(Scart) is selected\r\n");

			else
			{
				printf("Response from beamer is unknown.\r\n");
				error_code=1;
			}

		}
	}

	else if (strcmp(strupr(argv[2]),"LAMP_TIME") == 0)
	{	
		send_data(hCom, "CR3");
		if (receive_data(hCom, zeichen, 6) == 0)
			printf("%c%c%c%c%c Hours\r\n", zeichen[0], zeichen[1], zeichen[2], zeichen[3], zeichen[4]);
		else
		{
			printf("Response from beamer is unknown.\r\n");
			error_code=1;
		}
	}		

	else if (strcmp(strupr(argv[2]),"SETTING") == 0)
	{	
		send_data(hCom, "CR4");
		if (receive_data(hCom, zeichen, 3) == 0)
		{
			if ((zeichen[0] == 0x31) && (zeichen[1] == 0x31))
				printf("Normal Screen Setting\r\n");
			
			else if ((zeichen[0] == 0x31) && (zeichen[1] == 0x30))
				printf("Picture is top/bottom reversed (Status: Mounting)\r\n");
		
			else if ((zeichen[0] == 0x30) && (zeichen[1] == 0x31))
				printf("Picture is left/right reversed (Status: Rear)\r\n");

			else if ((zeichen[0] == 0x31) && (zeichen[1] == 0x31))
				printf("Picture is top/bottom and left/right reversed (Status: Ceiling ON)\r\n");

			else
			{
				printf("Response from beamer is unknown.\r\n");
				error_code=1;
			}
		}
	}

	else if (strcmp(strupr(argv[2]),"TEMP") == 0)
	{	
		send_data(hCom, "CR6");
		if (receive_data(hCom, zeichen, 18) == 0)
		{
			printf("%c%c%c%c%c C around the intake fan.\r\n", zeichen[0], zeichen[1], zeichen[2], zeichen[3], zeichen[4], 248);
			printf("%c%c%c%c%c C above the lamp.\r\n", zeichen[6], zeichen[7], zeichen[8], zeichen[9], zeichen[10], 248);
			printf("%c%c%c%c%c C on the polarized glass.\r\n", zeichen[12], zeichen[13], zeichen[14], zeichen[15], zeichen[16], 248);
		}
	}

	else
	{
		printf("Command unknown.\r\n");
		error_code=1;
	}

	close_com_port(hCom);
	Sleep(500);
	exit(error_code);
}

HANDLE init_com_port(char* comport)
{
	HANDLE hCom;
	COMMTIMEOUTS timeouts;
	DCB dcb;
	hCom = CreateFile(comport, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
 
	if ((GetCommState(hCom, &dcb) != 1) || (hCom == INVALID_HANDLE_VALUE))
	{
		printf("Failed to open specified serial port.\r\n");
		exit(1);
	}

	dcb.BaudRate = 19200;
	dcb.ByteSize = 8;
	dcb.Parity = NOPARITY;
	dcb.StopBits = ONESTOPBIT;
	dcb.fDtrControl = DTR_CONTROL_DISABLE;
	dcb.fInX = FALSE;

	if ((SetCommState(hCom, &dcb) != 1 ) || (GetCommTimeouts (hCom, &timeouts) != 1))
	{
		printf("Failed to configure specified serial port.\r\n");
		exit(1);
	}

	timeouts.ReadIntervalTimeout = MAXDWORD; 
	timeouts.ReadTotalTimeoutMultiplier = 0;
	timeouts.ReadTotalTimeoutConstant = 0; 

	if (SetCommTimeouts (hCom, &timeouts) != 1)
	{
		printf("Failed to configure specified serial port.\r\n");
		exit(1);
	}
	return(hCom);
}

int close_com_port(HANDLE hCom)
{
	if (CloseHandle(hCom) == 0)
	{
		printf("Failed to close serial port.\r\n");
		exit(1);
	}
	return(0);
}

int send_data(HANDLE hCom, char* befehl)
{
	DWORD BytesWrite;
	WriteFile( hCom, "\x0A", 1, &BytesWrite, NULL);
	WriteFile( hCom, strupr(befehl), strlen(befehl), &BytesWrite, NULL);
	WriteFile( hCom, "\x0D", 1, &BytesWrite, NULL);
	return(0);
}

int receive_data(HANDLE hCom, char* zeichen, int laenge)
{
	DWORD BytesRead;
	int i=0;
	char cKb;
	time_t timestamp = time(0);

	do
	{
		ReadFile(hCom, &zeichen[i], 1, &BytesRead, NULL);
		if (BytesRead > 0)
		{
			if ((zeichen[i] == 0x0D) && (i == laenge-1))
				return(0);
			i++;
		}
		else
			Sleep(1);

		if (kbhit())
			cKb = getch();

	} while ((cKb != 27) && (i < laenge) && ((time(0) - timestamp) < 5));
	printf("Communication with beamer failed.\r\n");
	close_com_port(hCom);
	Sleep(500);
	exit(1);
}
