/*
 * com.c
 *
 *  Created on: Jul 20, 2016
 *      Author: roy
 */

#include <msp430f5528.h>
#include <gpio.h>
#include <usci_a_uart.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/uart/UARTUSCIA.h>
#include <ti/drivers/gpio/GPIOMSP430.h>
#include <xdc/std.h>
#include <my_board.h>
#include "misc_stuff.h"
#include "com.h"
#include <xdc/runtime/System.h>

#include <Debug/configPkg/package/cfg/empty_min_pe430X.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/BIOS.h>

#define LOB	10


// For storage of non-volatile data in the flash memory
// segment of the VRS[]
#pragma NOINIT( flash_VRS_lo );
#pragma location = 0x1800;	// Info D
QUADLET flash_VRS_lo[ (LOVRS/2) ];

#pragma NOINIT( flash_VRS_hi );
#pragma location = 0x1880;	// Info C
QUADLET flash_VRS_hi[ (LOVRS/2) ];

QUADLET ram_VRS[LORVRS] = {0,0,0,0,0,0,0};
QUADLET VRS_buffer[ LOVRS ];

BYTE uart_read_buffer[ LOURB ];
// write index Uart Read Buffer
BYTE write_index_URB = 0;
BYTE read_index_URB = 0;
BYTE TC;	// Transaction Code
BYTE TL;	// Transaction Label
BYTE offset;
BYTE com_TX_packet[MAX_TX_PACKET_LENGTH];

QDATA payload;
BYTE calibrate_mode_flag = false;
BYTE do_not_sleep_flag = false;
bool continuous_readout_mode_flag = false;
BYTE continuous_readout_counter;
BYTE continuous_readout_packet[ LOCRP ];

// Normally, the coefficients that are used to compute the output pressure
// are selected based upon the current temperature.  However, when the DUT is under test,
// it is useful for the java test software to be able to direct the DUT which set of
// coefficients to use.  Note that the test sofware must first write the coefficient index
// into the Buffer Register.  See VRS_CMD_FLAG_COEFF_SELECTION_MODE, and I2C_UCB1.c
bool coefficient_selection_mode = false;

typedef enum tag_my_UART
{
	the_UART = 0,

	UART_DRIVER_COUNT
}
my_UART;

// This array forms the basis for the communication protocol's
// RAM based Virtual Register Space.


UARTUSCIA_Object uart_driver_objects[UART_DRIVER_COUNT];

UART_Handle uart_handle;
UART_Params uart_params;


/*
 * see
 * http://processors.wiki.ti.com/index.php/USCI_UART_Baud_Rate_Gen_Mode_Selection
 *
 */

// Baudrate changed 9.6.16
// At 38400 baud we were getting overrun error flags in UCA0STAT.
// By decreasing the baudrate to 9600, we allowed more time for the
// reading of each byte that was received by the UART.
// At 9600 baud, a 9 byte packet can be received in 9.4mS
#define MY_UART_BAUDRATE		9600

const UARTUSCIA_BaudrateConfig my_uart_baudrates[] =
{
    /* {baudrate, input clock, prescalar, UCBRFx, UCBRSx, oversampling} */
    {
        .outputBaudrate = MY_UART_BAUDRATE,
        .inputClockFreq = 8192000,	// this is the default SMCLK value
        .prescalar = 53,			// 213,
        .hwRegUCBRFx = 5,	// this value is only used for oversampling mode
        .hwRegUCBRSx = 0,	// not used in oversampling
        .oversampling = 1	// oversampling
    }

};


const UARTUSCIA_HWAttrs uart_driver_hwattrs[ UART_DRIVER_COUNT ] =
{
    {
        .baseAddr = USCI_A0_BASE,
        .clockSource = USCI_A_UART_CLOCKSOURCE_SMCLK,
        .bitOrder = USCI_A_UART_LSB_FIRST,
        .numBaudrateEntries = sizeof(my_uart_baudrates)/sizeof(UARTUSCIA_BaudrateConfig),
        .baudrateLUT = my_uart_baudrates
    }

};

const UART_Config UART_config[] =
{
    {
        .fxnTablePtr = &UARTUSCIA_fxnTable,
        .object = &uart_driver_objects[0],
        .hwAttrs = &uart_driver_hwattrs[0]
    },
    {NULL, NULL, NULL}
};


void readCallBack(UART_Handle handle, void *buffer, size_t num )
{
	/*
	 * This callback is executed after the specified number of bytes have been
	 * read from UART_read(). Note that this number is always 1 byte.
	 */
	BYTE status;
	status = UCA0STAT;
	if( status & 0x74 )
	{
		__no_operation();
	}
	// for testing !


	Semaphore_post( uart_read_sem );

}	// end of readCallBack() ***************************************************


void writeCallBack(UART_Handle handle, void *buffer, size_t num )
{
	/*
	 * This callback is executed after the specified number of bytes have been
	 * transmitted by UART_write().
	 */

	Semaphore_post( uart_write_sem );

}	// end of readCallBack() ***************************************************


void my_board_init_UART( void )
{
	// P3.4, 	RXD
	// P3.3, 	TXD
    GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_P3,
        (GPIO_PIN4 | GPIO_PIN3) );

    /* Initialize the UART driver */
    UART_init();

    UART_Params_init(&uart_params);

    uart_params.readMode = UART_MODE_CALLBACK;
    uart_params.writeMode = UART_MODE_CALLBACK;
    // clockTick period is currently 1000uS.  See clock module in .cfg
    // t = clockTicks * clockTick period
    uart_params.readTimeout =  UART_WAIT_FOREVER;	// units are clockTicks
    uart_params.writeTimeout = UART_WAIT_FOREVER;
    uart_params.readCallback = &readCallBack;
    uart_params.writeCallback = &writeCallBack;
    uart_params.readReturnMode = UART_RETURN_FULL;
    uart_params.readDataMode = UART_DATA_BINARY;
    uart_params.writeDataMode = UART_DATA_BINARY;
    uart_params.readEcho = UART_ECHO_OFF;
    uart_params.baudRate = MY_UART_BAUDRATE;
    uart_params.dataLength = UART_LEN_8;
    uart_params.stopBits = UART_STOP_ONE;
    uart_params.parityType = UART_PAR_NONE;

    uart_handle = UART_open( 0, &uart_params);


    if (uart_handle == NULL)
   	{
    	System_printf("UART did not open");
   	}


}	// end of void my_board_init_UART() ****************************************



void uart_read_fxn( void )
{
    /*  The BIOS starts this function
     *
     *  Execution will pause at the Semaphore_pend() statement
     *  until a byte is received.
     *
     *  When 1 byte is recieved by the UART, the readCallBack() will be
     *  executed, which posts the uart read semaphore
     *
     *  The posting causes execution to continue from Semaphore_pend()
     *
     * */

	extern void increment_index( BYTE *index_ptr );
	extern BYTE detect_packet( void );
	extern BYTE bytes_available( void );
	extern bool send_read_response_packet( void );
	extern bool send_write_response_packet( void );

	BYTE buffer[LOB];
	int read_size = 1;
	BYTE packet_type, available;

	while( 1 )
	{
		UART_read( uart_handle, &buffer, read_size );

		Semaphore_pend( uart_read_sem, BIOS_WAIT_FOREVER );

		// save the byte
		uart_read_buffer[ write_index_URB ] = buffer[0];
		write_index_URB++;
		if( write_index_URB >= LOURB)
		{
			write_index_URB = 0;
		}

		available = bytes_available();

		if( available >= 9 )
		{
			// A packet could be waiting for service
			packet_type = detect_packet();

			if( packet_type == RD_REQ )
			{

				send_read_response_packet();
			}

			if( packet_type == WR_REQ )
			{
				send_write_response_packet();
			}
		}

	}	// end of while( 1 )

}	// end of uart_read_fxn() **************************************************

BYTE detect_packet( void )
{
	extern QDATA payload;
	extern void increment_index( BYTE *index_ptr );
	extern BYTE bytes_available( void );

	payload.quadlet = 0;
	BYTE ret_value = NO_PKT;
	bool looking = true;
	bool parsing;
	BYTE i, j;
	BYTE state = FIND_START;
	DDATA computed_crc, delivered_crc;
	BYTE linear_packet[LOURB];

	while( looking )
	{

		switch ( state )
		{
			case FIND_START:
			// The first byte in all packets has a value of 0x01
			// Source:  bits 7-4,	Destination: bits 3-0
			// If necessary, advance the read index so it points
			// to the first byte containing a value of 0x01, or becomes empty.

			// First thing, make sure the uart read buffer has some
			// bytes present. Read and write request packets are now both
			// 9 bytes in length. It makes reception easier in this RTOS.
			i = bytes_available();

			if( i < 9  )
			{
				// the size of a read request packet, nothing to look at
				looking = false;
			}
			else
			{
				// The buffer is not empty !
				if( uart_read_buffer[read_index_URB] == 0x01 )
				{
					// The read index is now correctly positioned at what may
					// be the start of a good packet.
					state = FIND_TC_TL;
				}
				else
				{
					// increment the read index, and continue looking
					increment_index( &read_index_URB );

					// Has the read buffer become empty ?
					if( read_index_URB == write_index_URB )
					{
						looking = false;
					}
				}
			}

			break;

			case FIND_TC_TL:
				// The next byte will contain the Transaction Code and
				// Transaction Label.	TC: bits 7-5,   TL: bits 4-0
				i = read_index_URB;
				increment_index( &i );

				// Have we run out of bytes to examine ?
				if( i == write_index_URB )
				{
					looking = false;
				}
				else
				{
					// parse the TC
					TC = (uart_read_buffer[ i ] >> 5);
					// parse the TL
					TL = (uart_read_buffer[ i ]  & 0x1F);

					// only a read request or write request are supported
					switch ( TC )
					{
					case RD_REQ:
						state = CHECK_CRC;
						break;

					case WR_REQ:
						state = CHECK_CRC;
						break;

					default:
						// This cannot be the 2nd byte in a packet
						// advance the read index, and keep looking
						increment_index( &read_index_URB );
						// Has the read buffer become empty ?
						if( read_index_URB == write_index_URB )
						{
							looking = false;
						}
						state = FIND_START;
						break;

					}	// end of switch( TC )
				}

				break;

			case CHECK_CRC:

				// Create a linearized packet, and check the CRC
				j =  read_index_URB;
				parsing = true;
				i = 0;
				while ( parsing )
				{
					linear_packet[i] = uart_read_buffer[j];

					if(i == 8)
					{
						// the packet is complete
						parsing = false;

						// compute the crc using the CRC engine of the MSP430
						CRCINIRES = 0xFFFF;			// initialize the crc
						// read request calculation includes bytes 0-6
						for(i=0; i<=6; i++)
						{
							CRCDIRB_L = linear_packet[i];
						}
						// read the crc from the engine
						computed_crc.doublet = CRCINIRES;

						delivered_crc.byte[1] = linear_packet[7];
						delivered_crc.byte[0] = linear_packet[8];

						// If the computed crc and delivered crc match,
						// you have a good packet !
						if( delivered_crc.doublet == computed_crc.doublet )
						{
							// A success !
							looking = false;
							ret_value =  TC;
							offset = linear_packet[2];
							// get the payload
							payload.byte[3] = linear_packet[3];
							payload.byte[2] = linear_packet[4];
							payload.byte[1] = linear_packet[5];
							payload.byte[0] = linear_packet[6];
							// empty the URB
							read_index_URB = write_index_URB;
							// save the received payload
						}
						else
						{
							// A CRC failure ! Increment the read index,
							// to discard the start of this bad packet.
							// Continue looking for a good packet.
							increment_index( &read_index_URB );
							state = FIND_START;
						}
					}

					i++;
					increment_index( &j );
					// Has the read buffer become empty ?
					if( j == write_index_URB )
					{
						parsing = false;
					}
				}	// end of while( parsing )


				break;


			default:
				// default
				break;

		}	// end of switch( state )

	}	// end of while( looking )


	return ret_value;


}	// end of detect_packet() **************************************************




void increment_index( BYTE *index_ptr )
{
	// increment the value at the address
	(*index_ptr)++;

	// check for rollover
	if( *index_ptr >= LOURB )
	{
		// roll over
		*index_ptr = 0;
	}

	return;
}	// end of increment_index() ************************************************



BYTE bytes_available( void )
{
	BYTE available = 0;
	bool working = true;
	BYTE j;


	j = read_index_URB;
	while( working )
	{
		if( j != write_index_URB )
		{
			available++;
			increment_index( &j );
		}
		else
		{
			// you have run out of bytes to count
			working = false;
		}
	}

	return available;
}	// end of bytes_available() ************************************************


bool send_read_response_packet( void )
{

	// All registers can be read, so the complete response can be handled here.
	// The response packet being sent back to the host PC
	bool success = true;
	extern BYTE com_RX_offset;

	BYTE i, temp;
	QDATA payload;
	DDATA crc;
	int write_size = 8;  	// the length of a read response packet

	if(continuous_readout_mode_flag == true)
	{
		// ignore any requests while in this mode
		success = false;
		return success;
		// the only way to exit this mode is to cycle the power
	}

	// make the source - destination header
	temp  = (MSP430_ID << 4);
	temp |=  DESTINATION_ID;
	com_TX_packet[0] = temp;

	// make the transaction code - transaction label
	temp  = ( RD_RESP << 5 );
	// the TL from the received packet is used here
	temp |= TL;
	com_TX_packet[1] = temp;

	// The Virtual Register Space (VRS) is shared with other processes
	// Such as sensor data being periodically stored from the I2C bus
	Semaphore_pend( mutex_sem_VRS, BIOS_WAIT_FOREVER );	// lock the mutex

	// Is the read from the ram part of the VRS ?
	if( (offset >= (LOVRS-8)) && (offset <= (LOVRS-2))  )
	{
		// Copy the requested data from the ram_VRS[], at the specified offset.
		payload.quadlet = ram_VRS[ (offset - (LOVRS-8)) ];
	}
	else
	{
		// The read is targeting a flash part of the VRS
		// Is the read targeting the low ?
		if( offset < ((LOVRS/2)) )
		{
			// use the flash low
			payload.quadlet = flash_VRS_lo[ offset ];
		}
		else
		{
			// use the flash high
			payload.quadlet = flash_VRS_hi[ (offset - (LOVRS/2)) ];
		}
	}

	Semaphore_post( mutex_sem_VRS );					// unlock the mutex

	// write the individual bytes into the packet
	com_TX_packet[2] = payload.byte[3];
	com_TX_packet[3] = payload.byte[2];
	com_TX_packet[4] = payload.byte[1];
	com_TX_packet[5] = payload.byte[0];

	// make the crc for this packet using the crc-engine of the msp430
	CRCINIRES = 0xFFFF;					// initialize the crc
	for(i=0; i<=5; i++)
	{
		CRCDIRB_L = com_TX_packet[i];
	}
	crc.doublet = CRCINIRES;		// read the crc from the engine

	// The driver is being used in the non-blocking mode. This allows other
	// tasks to execute code while the uart driver is transmitting.
	// Note that when transmission of all the bytes is complete, the
	// uart driver executes the writeCallBack() function. This posts the
	// semaphore.

	// write the crc into the end of the packet using a union
	com_TX_packet[6] = crc.byte[1];
	com_TX_packet[7] = crc.byte[0];

	// Transmitt the read response packet
	UART_write( uart_handle, com_TX_packet, write_size  );

	Semaphore_pend( uart_write_sem, BIOS_WAIT_FOREVER );

	return success;

}	// End of send_read_response_packet() **************************************


bool send_write_response_packet( void )
{

	bool success = true;
	// Most registers are "Read Only".
	// The response packet is being sent back to the host PC

	extern BYTE calibrate_mode_flag;
	extern BYTE do_not_sleep_flag;
	extern QUADLET ram_VRS[LORVRS];
	extern QUADLET flash_VRS_lo[(LOVRS/2)];
	extern QUADLET flash_VRS_hi[(LOVRS/2)];
	extern BYTE com_RX_offset;
	extern QDATA payload;
	extern QUADLET VRS_buffer[ LOVRS ];
	extern BYTE check_Flash_ROM_crc( void );
	extern BYTE continuous_readout_counter;
	extern bool continuous_readout_mode_flag;

	BYTE i, temp;
	DDATA crc;
	int write_size = 4;  	// the length of a write response packet

	if(continuous_readout_mode_flag == true)
	{
		// ignore any requests while in this mode
		success = false;
		return success;
		// the only way to exit this mode is to cycle the power
	}

	// The Virtual Register Space (VRS) is shared with other processes
	// Such as sensor data being periodically stored from the I2C bus
	Semaphore_pend( mutex_sem_VRS, BIOS_WAIT_FOREVER );     // lock the mutex

	// These are the only registers that can be "written"
	// All registers will get a write response packet, but nothing may happen
	// dependant on the particular register.
	switch ( offset )
	{

		case VRS_COMMAND_OFFSET:

			// detertmine which command flag is set in the payload
			switch ( payload.quadlet )
			{
				case VRS_CMD_FLAG_CLEAR_BUFFER:
					// clear the VRS_buffer[]
					for(i=0; i<LOVRS; i++)
					{
						VRS_buffer[i] = 0;
					}
					break;

				case VRS_CMD_FLAG_CLEAR_BUFFER_COUNTER:
					// clear the buffer counter register
					ram_VRS[(VRS_COMMAND_OFFSET - (LOVRS-8))] = 0;
					break;

				case VRS_CMD_FLAG_WRITE_FLASH:

				// clear this flag in the status register
				//ram_VRS[VRS_STATUS_OFFSET - VRS_TSENSOR_OFFSET]
					//	&= ~VRS_STATUS_FLAG_FLASH_ROM_VERIFICATION;


				// Configure the Flash Controller
				SEGMENT_ERASE;

				UNLOCK_FLASH;
				// Perform a write to an address in the the segment
				// This triggers an erase of the whole segment

				// erase Info D (flash_VRS_lo[])
				__data16_write_addr( 0x1800, 0x0000 );

				// check that flash low and high are erased
				for(i=0; i<(LOVRS/2); i++)
				{
					if( flash_VRS_lo[i] != 0xFFFFFFFF )
					{
						// a failure !
						success = false;
						return success;
					}
				}

				// Configure the Flash Controller
				SEGMENT_ERASE;

				UNLOCK_FLASH;
				// Perform a write to an address in the the segment
				// This triggers an erase of the whole segment

				// erase Info C (flash_VRS_hi[])
				__data16_write_addr( 0x1880, 0x0000 );

				for(i=0; i<(LOVRS/2); i++)
				{
					if( flash_VRS_hi[i] != 0xFFFFFFFF )
					{
						// a failure !
						success = false;
						return success;
					}
				}

				// set the flash controller up to do 32-bit writes
				LONG_WORD_WRITE;

				for(i=0; i<LOVRS; i++)
				{
					if( i < (LOVRS/2))
					{
						// use the flash low
						flash_VRS_lo[ i ] = VRS_buffer[i];
					}
					else
					{
						// use the flash high
						flash_VRS_hi[ (i - (LOVRS/2)) ] = VRS_buffer[i];
					}
				}

				// check the flash memory for accuracy
				success = check_Flash_ROM_crc();

				if( success )
				{
					// set this flag in the status register
					//ram_VRS[ (VRS_STATUS_OFFSET - VRS_TSENSOR_OFFSET) ]
					//		|= VRS_STATUS_FLAG_FLASH_ROM_VERIFICATION;
				}
				else
				{
					// clear this flag
					//ram_VRS[(VRS_STATUS_OFFSET - VRS_TSENSOR_OFFSET)]
					//		&= ~VRS_STATUS_FLAG_FLASH_ROM_VERIFICATION;
				}

				break;

				case VRS_CMD_FLAG_GOTO_CALIBRATE_MODE:
					calibrate_mode_flag = true;
					// set the flag in the status register
					//ram_VRS[(VRS_STATUS_OFFSET - VRS_TSENSOR_OFFSET)]
					//		|= VRS_STATUS_FLAG_CALIBRATION_MODE;

					break;

				case VRS_CMD_FLAG_GOTO_TEST_MODE:

					break;

				case VRS_CMD_FLAG_DO_NOT_SLEEP:
					do_not_sleep_flag = true;
					// set the flag in the status register
					//ram_VRS[(VRS_STATUS_OFFSET - VRS_TSENSOR_OFFSET)]
					//		|= VRS_STATUS_FLAG_DO_NOT_SLEEP;

					break;

				case VRS_CMD_FLAG_GOTO_CONT_READOUT_MODE:
					// If this flag is set, every time that the uC reads
					// the pressure sensor, a packet of data will be sent to the
					// host computer.  See pressure_sensor_task(), I2C_UCB1.c
					continuous_readout_mode_flag = true;
					continuous_readout_counter = 0;

					// The only way to clear this flag is by cycling the power.
					// set the flag in the status register
					//ram_VRS[(VRS_STATUS_OFFSET - VRS_TSENSOR_OFFSET)]
					//		|= VRS_STATUS_FLAG_CONT_READOUT_MODE;

					break;

				case VRS_CMD_FLAG_COEFF_SELECTION_MODE:
					// If this flag is set, it inicates to the DUT that it will use the
					// indicated coefficients (temperature, y-intercept, and slope)
					// to compute the output pressure.
					// Before writing this flag, the java test program will have written
					// coefficient index into the VRS Buffer Register
					coefficient_selection_mode = true;

					break;
				default:

					break;
			}	// end of switch ( payload )

			break;

		case VRS_BUFFER_OFFSET:

			// Write the payload into the VRS Buffer Register
			// This value will be needed by the VRS_CMD_FLAG_COEFF_SELECTION_MODE
			//ram_VRS[ (VRS_BUFFER_OFFSET - VRS_TSENSOR_OFFSET) ] = payload.quadlet;

			// write the payload into the VRS_buffer[]
			VRS_buffer[ram_VRS[(VRS_BUFFER_COUNTER_OFFSET - (LOVRS-8))]] = payload.quadlet;
			// increment the buffer counter
			ram_VRS[(VRS_BUFFER_COUNTER_OFFSET - (LOVRS-8))]++;
			break;

		case VRS_BUFFER_COUNTER_OFFSET:
			ram_VRS[offset - (LOVRS-8)] = payload.quadlet;
			break;

		default:
			break;
	}	// end of switch ( offset )

	// unlock the mutex
	Semaphore_post( mutex_sem_VRS );

	// make the source - destination header
	temp  = (MSP430_ID << 4);
	temp |=  DESTINATION_ID;
	com_TX_packet[0] = temp;

	// make the transaction code - transaction label
	temp  = ( WR_RESP << 5 );
	// the TL from the received packet is used here
	temp |= TL;
	com_TX_packet[1] = temp;

	// make the crc for this packet using the crc-engine of the msp430
	CRCINIRES = 0xFFFF;				// initialize the crc
	for(i=0; i<=1; i++)
	{
		CRCDIRB_L = com_TX_packet[i];
	}
	crc.doublet = CRCINIRES;		// read the crc from the engine

	// write the crc into the end of the packet using a union
	com_TX_packet[2] = crc.byte[1];
	com_TX_packet[3] = crc.byte[0];

	// The driver is being used in the non-blocking mode. This allows other
	// tasks to execute code while the uart driver is transmitting.
	// Note that when transmission of all the bytes is complete, the
	// uart driver executes the writeCallBack() function. This posts the
	// semaphore.

	// Transmitt the response packet
	UART_write( uart_handle, com_TX_packet, write_size  );

	Semaphore_pend( uart_write_sem, BIOS_WAIT_FOREVER );

	return success;

}	// End of send_write_response_packet() **************************************


BYTE check_Flash_ROM_crc( void )
{

	BYTE bytes_of_Flash_ROM[((LOVRS)*4)];
	BYTE success = 0; // 0 - Failure, 1 - Success
	DOUBLET Flash_ROM_crc, engine_crc;
	QDATA temp_qdata;
	DOUBLET i, j;
	extern QUADLET flash_VRS_lo[LOVRS/2];
	extern QUADLET flash_VRS_hi[LOVRS/2];

	j = 0;
	// copy the contents of the flash_VRS_lo[] into the byte array
	for(i=0; i<(LOVRS/2); i++)
	{
		temp_qdata.quadlet = flash_VRS_lo[i];
		bytes_of_Flash_ROM[j++] =  temp_qdata.byte[0];
		bytes_of_Flash_ROM[j++] =  temp_qdata.byte[1];
		bytes_of_Flash_ROM[j++] =  temp_qdata.byte[2];
		bytes_of_Flash_ROM[j++] =  temp_qdata.byte[3];
	}

	// copy the contents of the flash_VRS_hi[] into the byte array
	for(i=0; i<(LOVRS/2); i++)
	{
			temp_qdata.quadlet = flash_VRS_hi[i];
			bytes_of_Flash_ROM[j++] =  temp_qdata.byte[0];
			bytes_of_Flash_ROM[j++] =  temp_qdata.byte[1];
			bytes_of_Flash_ROM[j++] =  temp_qdata.byte[2];
			bytes_of_Flash_ROM[j++] =  temp_qdata.byte[3];
	}

	// Use the msp430 crc-engine to calculate a local crc
	// The last quadlet of the VRS_buffer is not used to compute the crc
	j=0;
	CRCINIRES = 0xFFFF;
	for(i=0; i<((LOVRS-1)*4); i++)
	{
		CRCDIRB_L = bytes_of_Flash_ROM[i];
	}

	engine_crc = CRCINIRES;

	// get the crc from the end of the Flash_ROM[]
	temp_qdata.quadlet =  flash_VRS_hi[ (LOVRS/2)-1 ];
	Flash_ROM_crc = temp_qdata.doublet[0];

	// The buffer crc and engine crc should be equal
			if( engine_crc == Flash_ROM_crc )
			{
				// Success !
				// We have recieved the VRS_buffer without any errors
				success = 1;
			}
			else
			{
				// Failure !
				// Some sort of reception error(s)have occurred
				success = 0;
			}

	return success;
}	// end of check_Flash_ROM_crc() ********************************************


void init_VRS( void)
{
	extern BYTE check_Flash_ROM_crc( void );
	extern QUADLET ram_VRS[LORVRS];

	BYTE success;

	success = check_Flash_ROM_crc();


	if( success )
	{
		// set this flag in the status register
		ram_VRS[VRS_STATUS_OFFSET - (LOVRS-8)] |= VRS_STATUS_FLAG_FLASH_ROM_VERIFICATION;
	}
	else
	{
		// clear this flag
		ram_VRS[VRS_STATUS_OFFSET - (LOVRS-8)] &= ~VRS_STATUS_FLAG_FLASH_ROM_VERIFICATION;
	}

	return;

}	// end of init_VRS() ******************************************************


QUADLET read_flash_VRS( BYTE offset )
{
    extern QUADLET flash_VRS_lo[ (LOVRS/2) ];
    extern QUADLET flash_VRS_hi[ (LOVRS/2) ];
    QUADLET value = 0;

    if( offset >= LOVRS )
    {
        // this is an error
        return value;
    }

    if( offset <= ((LOVRS/2)-1) )
    {
        // flash_rom_lo[]
        value = flash_VRS_lo[ offset ];
    }
    else
    {
        // flash_rom_hi[]
        value = flash_VRS_hi[ (offset - (LOVRS/2)) ];
    }

    return value;
}   // end of read_flash_rom() ************************************************





