/************************************************************************
	main.c

    usbGenericHidCommunication reference LCD example
    Copyright (C) 2010 Simon Inns

    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 3 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.  If not, see <http://www.gnu.org/licenses/>.

	Email: simon.inns@gmail.com

************************************************************************/

#ifndef MAIN_C
#define MAIN_C

// Global includes
#include <htc.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Local includes
#include "usb.h"
#include "HardwareProfile.h"
#include "usb_function_hid.h"
#include "genericHID.h"

#include "lcd.h"

// PIC 18F4550 fuse configuration:
// Config word 1 (Oscillator configuration)
// 20Mhz crystal input scaled to 48Mhz and configured for USB operation
__CONFIG(1, USBPLL & IESODIS & FCMDIS & HSPLL & CPUDIV1 & PLLDIV5);
// Config word 2
__CONFIG(2, VREGEN & PWRTDIS & BOREN & BORV20 & WDTDIS & WDTPS32K);
// Config word 3
__CONFIG(3, PBDIGITAL & LPT1DIS & MCLREN);
// Config word 4
__CONFIG(4, XINSTDIS & STVREN & LVPDIS & ICPORTDIS & DEBUGDIS);
// Config word 5, 6 and 7 (protection configuration)
__CONFIG(5, UNPROTECT);
__CONFIG(6, UNPROTECT);
__CONFIG(7, UNPROTECT);

// Globals

// Success indication globals (used to keep the success LED on so you can see it)
long int successIndicatorCounter = 0;
unsigned char successIndicatorFlag = FALSE;

// Failure indication globals (used to keep the failure LED on so you can see it)
long int failureIndicatorCounter = 0;
unsigned char failureIndicatorFlag = FALSE;

// Initialise system
static void InitialiseSystem(void)
{
	// PIC port set up --------------------------------------------------------

	// Default all pins to digital
    ADCON1 = 0x0F;

	// Note: To complile this code for the PIC18F2550 remove the TRISD, TRISE,
	// PORTD and PORTE commands below.  Then edit HardwareProfile.h to match
	// your target device (only the LED ports are really important).

	// Configure ports as inputs (1) or outputs(0)
	TRISA = 0b00000000;
	TRISB = 0b00000000;
	TRISC = 0b00000000;
	TRISD = 0b00000000;
	TRISE = 0b00000000;

	// Clear all ports
	PORTA = 0b00000000;
	PORTB = 0b00000000;
	PORTC = 0b00000000;
	PORTD = 0b00000000;
	PORTE = 0b00000000;
	
	// LCD set up -------------------------------------------------------------
	lcdInit();

	// USB set up -------------------------------------------------------------

	// USB stack and parameter initialisation
    #if defined(USE_SELF_POWER_SENSE_IO)
    tris_self_power = INPUT_PIN;
    #endif
    
    // Initialize the variable holding the handle for the last
    // transmission
    USBOutHandle = 0;
    USBInHandle = 0;
    
	// Call the stack initialisation functions
    USBDeviceInit();
}

// Process input and output
void ProcessIO(void)
{   
	unsigned char string[64];
	
    // If we are not in the configured state just return
    if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1))
    {
	    // We are not configured, set LED1 to off to show status
	    LED1 = OFF;
	    return;
	}
	
	// We are configured, show state in LED1
	LED1 = ON;
	
	// Check to see if the success indicator is on and update the delay counter
	if (successIndicatorFlag == TRUE)
	{
		LED2 = ON;
		successIndicatorCounter++;
		
		if (successIndicatorCounter == 20000)
		{
			LED2 = OFF;
			successIndicatorCounter = 0;
			successIndicatorFlag = FALSE;
		}
	}
    
    // Check to see if the failure indicator is on and update the delay counter
    if (failureIndicatorFlag == TRUE)
	{
		LED3 = ON;
		failureIndicatorCounter++;
		
		if (failureIndicatorCounter == 80000)
		{
			LED3 = OFF;
			failureIndicatorCounter = 0;
			failureIndicatorFlag = FALSE;
		}
	}

	// Check if data was received from the host.
    if(!HIDRxHandleBusy(USBOutHandle))
    {   
		// Command mode    
        switch(ReceivedDataBuffer[0])
		{
            case 0x80:	// Update the LCD screen
            	//
            	// We expect a command in the following format:
            	//
            	// Byte[0] - 0x80 (command)
            	// Byte[1] - x coordinate of screen
            	// Byte[2] - y coordinate of screen
            	// Byte[3] - Number of characters to display
            	// Byte[4-63] - Characters
            	
            	// Set the display coordinates
            	lcdGoto((int)ReceivedDataBuffer[1], (int)ReceivedDataBuffer[2]);
            	
            	// Assemble the characters for display
				int numberOfCharactersToDisplay = (int)ReceivedDataBuffer[3];
				if (numberOfCharactersToDisplay > 59) numberOfCharactersToDisplay = 59;
				
				if (numberOfCharactersToDisplay != 0)
				{
					// Copy the characters to our string
					for (int counter = 0; counter < numberOfCharactersToDisplay; counter++)
						string[counter] = ReceivedDataBuffer[counter+4];
						
					// Null terminate the string
					string[numberOfCharactersToDisplay] = '\0';
					
					// Update the LCD screen
					lcdPuts(string);
					
					// Show success
					successIndicatorFlag = TRUE;
				}
				else failureIndicatorFlag = FALSE; // Show failure
            	break;
            	
            	case 0x81:	// Clear the screen
            		// Send the clear display command to the LCD
            		lcdClearDisplay();
            		
            		// Show success
					successIndicatorFlag = TRUE;
            		break;
            	            	
            default:	// Unknown command received
           		break;
		}
		
        // Re-arm the OUT endpoint for the next packet
        USBOutHandle = HIDRxPacket(HID_EP,(BYTE*)&ReceivedDataBuffer,64); 
    }  
}   

// Main function

void main(void)
{
    InitialiseSystem();
	//pattern[8]=	{0x04,0x0E,0x0E,0x0E,0x1F,0x00,0x04,0x00};

	// We are up and running, show 'ready' status in LED0
	LED0 = ON;
/*	lcdWrite(CMD_REG,0x00);
	lcdWrite(CMD_REG,0x04);
	lcdWrite(CMD_REG,0x0E);
	lcdWrite(CMD_REG,0x0E);
	lcdWrite(CMD_REG,0x0E);
	lcdWrite(CMD_REG,0x1F);
	lcdWrite(CMD_REG,0x00);
	lcdWrite(CMD_REG,0x04);*/
	//       12345678901234567890
//	lcdPuts("**Klima VEZERLO v1**");
	//LCD_EN=0;
	//lcdWriteNybble(
	//CustomChar(123);
	lcdWrite(CMD_REG,0x40);
	lcdWrite(DATA_REG,0x04);
	lcdWrite(DATA_REG,0x0E);
	lcdWrite(DATA_REG,0x0E);
	lcdWrite(DATA_REG,0x0E);
	lcdWrite(DATA_REG,0x1F);
	lcdWrite(DATA_REG,0x00);
	lcdWrite(DATA_REG,0x04);
	lcdWrite(DATA_REG,0x00);
    while(1)
    {
		//lcdPuts("lala");
		//lcdClearDisplay();
		// Check bus status and service USB interrupts.
        USBDeviceTasks();

		// Application-specific tasks.
        ProcessIO();        
    }
}

#endif
