/*****************************************************************************
 * This program receives Intel HEX file from UART and programs
 * a the data into a file on the SDCard on the Eval C2 board.
 *
 * Please read ReadMe file for details.
 *
 *****************************************************************************
 * FileName:        FlashProgrammer.c
 * Dependencies:    FlashProgrammer.h, MainDemo.h
 * Processor:       PIC24, PIC32
 * Compiler:       	MPLAB C30, MPLAB C32
 * Linker:          MPLAB LINK30, MPLAB LINK32
 * Company:         Microchip Technology Incorporated
 *
 * Software License Agreement
 *
 * Copyright © 2007 Microchip Technology Inc.  All rights reserved.
 * Microchip licenses to you the right to use, modify, copy and distribute
 * Software only when embedded on a Microchip microcontroller or digital
 * signal controller, which is integrated into your product or third party
 * product (pursuant to the sublicense terms in the accompanying license
 * agreement).  
 *
 * You should refer to the license agreement accompanying this Software
 * for additional information regarding your rights and obligations.
 *
 * SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
 * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
 * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR
 * OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
 * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
 * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
 * INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
 * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
 * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
 * OR OTHER SIMILAR COSTS.
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Anton Alkhimenok		10/17/07	...
 * Anton Alkhimenok		02/05/08	PIC32 support is added
 * Paolo Tamayo			06/19/08	Modified to be a module
 *****************************************************************************/
#include "MainDemo.h"
#include "Uart2.h"

/////////////////////////////////////////////////////////////////////////////
//                            LOCAL PROTOTYPES
/////////////////////////////////////////////////////////////////////////////
// Local functions prototypes
BYTE    ConvertRecord2Bin(BYTE *pBuffer);
BYTE    ProcessRecord(BYTE *pBuffer, DWORD_VAL *pAddr);

#define UARTInit()          UART2Init()
#define UARTGetChar(ch)     UART2GetChar(ch)
#define UARTPutChar(ch)     UART2PutChar(ch)
#define UARTClrError()      UART2ClrError()
#define UARTDataReceived()  UART2DataReceived()
#define Char2Hex(ch)        UART2Char2Hex(ch)
#define Hex2Char(ch)        UART2Hex2Char(ch)

/////////////////////////////////////////////////////////////////////////////
//                            MACROS
/////////////////////////////////////////////////////////////////////////////
// Macros to interface with memory are NOT required, since the Eval C2 board 
// has no flash on it. Uses SDCard calls to save binary file to SDCard.
// This code assumes that the SDCard has been initialized in main().

// Acknowledgement for UART
#define FLASH_PROG_ACK  'Y'
#define FLASH_PROG_NAK  'N'

// Main state mashine
#define FLASH_PROG_STATE_START  0
#define FLASH_PROG_STATE_DATA   1

#define PROG_TICK_COUNT         300
#define WAIT_TICK_COUNT         4000

/////////////////////////////////////////////////////////////////////////////
//                            GLOBALS
/////////////////////////////////////////////////////////////////////////////
extern DWORD    tick;
FSFILE *PgmPtr;				// File pointer of opened file to be passed

/************************************************************************
 Function: void ProgramSDCard (void)
 Overview: Programs the SDCard with Font and Image data. Data is coming 
           from UART connected to the host PC. NO System reset required
           after programming.
 Input: none
 Output: none
************************************************************************/
void ProgramSDCard (void)
{
	BYTE        state;
	DWORD       progTick, waitTick;
	BYTE        *pointer = NULL;
	BYTE        byte;
	BYTE        progBuffer[1024];   // progBuffer for incoming data
	DWORD_VAL   address;            // Current memory address

	UARTInit();
	Beep();

	state = FLASH_PROG_STATE_START;
	address.Val = 0;
	progTick = tick;
/*
	// Remove old file, if present
	FSremove ("IMG_DATA.BIN");
	// Open File to receive binary data
	if ((PgmPtr = FSfopen("IMG_DATA.BIN", "wb")) == NULL)
		return;
*/
	LED1 = 0;
	LED2 = 0;
	LED3 = 0;

	while(1)
	{
		// clear any errors before we wait for new character	
		UARTClrError();

		// Check for User Break. If so, close file and return
		if (BTN_S5 == 0)
		{
//			FSfclose(PgmPtr);
			break;
		}

		waitTick = tick;
		while (UARTDataReceived() == 0)
		{
			if ((tick - waitTick) >= WAIT_TICK_COUNT) {
				// set LED to signify waiting
				LED3 = ~LED3;
			}
		}

		byte = UARTGetChar();
		LED1 = 1;

		if ((tick - progTick) >= PROG_TICK_COUNT)
		{
			LED2 = ~LED2;
			progTick = tick;
		}

		switch(state)
		{
			case FLASH_PROG_STATE_START:
				// start of record is detected
				if (byte == ':') {
					pointer = progBuffer;
					state = FLASH_PROG_STATE_DATA;
				}

				if (byte == '\r') {
					UARTPutChar(FLASH_PROG_NAK);
				}
				break;

			case FLASH_PROG_STATE_DATA:
				// end of record
				if (byte == '\r') {
					// end of string
					*pointer++ = 0;
					*pointer++ = 0;
					state = FLASH_PROG_STATE_START;

					if (!ConvertRecord2Bin(progBuffer)) {
						// checksum is wrong
						UARTPutChar(FLASH_PROG_NAK);
						break;
					}

					if (!ProcessRecord(progBuffer, &address)) {
						// programming error
						UARTPutChar(FLASH_PROG_NAK);
						UARTPutChar('P');
						break;
					}

					// record is processed successfully
					UARTPutChar(FLASH_PROG_ACK);
					break;
				}
				*pointer++ = byte;
				break;

			default:
				break;
		}	// end of switch
	}	// end of while
}

/************************************************************************
 Function: BYTE ConvertRecord2Bin (BYTE *pBuffer)
 Overview: Convert a hex data record to binary
 Input:    BYTE  pointer to the input buffer of hey data
 Output:   BYTE  status
************************************************************************/
BYTE ConvertRecord2Bin (BYTE *pBuffer)
{
	BYTE    *pIn;
	BYTE    *pOut;
	WORD    checksum = 0;
	BYTE    byte;

	pIn = pOut = pBuffer;

	while (*pIn)
	{
		// Get first nibble
		byte = Char2Hex(*pIn++);
		byte <<= 4;

		// Get second nibble
		byte |= Char2Hex(*pIn++);
		checksum += byte;
		*pOut++ = byte;
	}

	checksum &= 0x00ff;

	// last byte was a transmitted checksum, compare with calculated
	if(checksum)
		return (0);	// error
	return (1);		// good
}

typedef struct _RECORD_HEADER_
{
    BYTE    reclen;
    BYTE    msbOffset;
    BYTE    lsbOffset;
    BYTE    rectype;
} RECORD_HEADER;

#define REC_DATA        0
#define REC_EOF         1
#define REC_UPPERADDR   4
#define REC_STARTADDR   5

/************************************************************************
 Function: BYTE ProcessRecord (BYTE *pBuffer, DWORD_VAL *pAddr)
 Overview: Process a binary record
 Input:    BYTE  pointer to the input buffer of the data
           DWORD current address of the data
 Output:   BYTE  status
************************************************************************/
BYTE ProcessRecord (BYTE *pBuffer, DWORD_VAL *pAddr)
{
	BYTE            err;
	BYTE            *pData;
	RECORD_HEADER   *pRecord;

	pRecord = (RECORD_HEADER *)pBuffer;
	pData = pBuffer + sizeof(RECORD_HEADER);

	switch (pRecord->rectype)
	{
		// data record
		case REC_DATA:
			// set lower 16 bit of the linear address
			pAddr->v[1] = pRecord->msbOffset;
			pAddr->v[0] = pRecord->lsbOffset;

//			err = FSfseek(PgmPtr, pAddr->Val, SEEK_SET);
			err = FSfwrite(pData, 1, pRecord->reclen, PgmPtr);
			if (err != CE_GOOD)
				return(0);
			else
				return (1);

		// end of file record
		case REC_EOF:
			return (1);

		// extended linear address record
		case REC_UPPERADDR:
			// set upper 16 bit of the linear address
			pAddr->v[3] = *pData++;
			pAddr->v[2] = *pData;
			return (1);

		// start linear address record
		case REC_STARTADDR:
			// set full address
			pAddr->v[3] = *pData++;
			pAddr->v[2] = *pData++;
			pAddr->v[1] = *pData++;
			pAddr->v[0] = *pData;
			return (1);

		default:
			return (1);
	}   // end of switch

	return (0);
}

