/*******************************************************************************
  MPLAB Harmony Application Source File

  Company:
    Microchip Technology Inc.

  File Name:
    app_i2c.c

  Summary:
    This file contains the source code for the MPLAB Harmony application.

  Description:
    This file contains the source code for the MPLAB Harmony application.  It
    implements the logic of the application's state machine and it may call
    API routines of other MPLAB Harmony modules in the system, such as drivers,
    system services, and middleware.  However, it does not call any of the
    system interfaces (such as the "Initialize" and "Tasks" functions) of any of
    the modules in the system or make any assumptions about when those functions
    are called.  That is the responsibility of the configuration-specific system
    files.
 *******************************************************************************/

// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************

#include "app_i2c.h"
#include "user.h"
#include <string.h>
//#include "bqMaximo_Ctrl_G2553.h"

// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************

/* Size of the string written to BQ must be less than or equal to the BQ Register */
static uint8_t  txBQ[2];
static uint8_t  rxBQ[2];

#define txBQ_SIZE               (sizeof(txBQ))
#define rxBQ_SIZE               (sizeof(rxBQ))

//uint8_t WR_BQ_ADDR = (APP_I2C_BQ_ADDR << 1);
//uint8_t RD_BQ_ADDR = (APP_I2C_BQ_ADDR << 1) | 0x01; 

//#define APP_I2C_BQ_RX_BUFFER_SIZE               2  //APP_I2C_BQ_TEST_DATA_SIZE
//#define APP_I2C_BQ_TX_BUFFER_SIZE               3  //(APP_I2C_BQ_TEST_DATA_SIZE + APP_I2C_BQ_NUM_ADDR_BYTES)

#define APP_I2C_BQ_NUM_ADDR_BYTES               1

// *****************************************************************************
/* Application Data

  Summary:
    Holds application data

  Description:
    This structure holds the application's data.

  Remarks:
    This structure should be initialized by the APP_Initialize function.
    Application strings and buffers are be defined outside this structure.
*/

//APP_I2C_DATA app_i2cData;

//static uint8_t testTxData[APP_I2C_BQ_TX_BUFFER_SIZE] = {0};
//static uint8_t testRxData[APP_I2C_BQ_RX_BUFFER_SIZE] = {0};


APP_STATES state;
volatile APP_TRANSFER_STATUS transferStatus;
uint8_t ackData = 0;

// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************

void APP_I2CCallback(uintptr_t context )
{
    APP_TRANSFER_STATUS* transferStatus = (APP_TRANSFER_STATUS*)context;

    if(I2C2_ErrorGet() == I2C_ERROR_NONE)
    {
        if (transferStatus)
        {
            *transferStatus = APP_TRANSFER_STATUS_SUCCESS;
        }
    }
    else
    {
        if (transferStatus)
        {
            *transferStatus = APP_TRANSFER_STATUS_ERROR;
        }
    }
}

// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************

void APP_I2C_Initialize( void )
{
    state = APP_STATE_EEPROM_STATUS_VERIFY;
    transferStatus = APP_TRANSFER_STATUS_ERROR;
    ackData = 0;
    
    txBQ[0] = 0x00;
    txBQ[1] = 0x00;
    APP_I2C_Tasks();
}

// *****************************************************************************
// *****************************************************************************
// Section: Application  APP_Tasks of State Machine Functions
// *****************************************************************************
// *****************************************************************************

void APP_I2C_Tasks( void )
{
    /* Check the application's current state. */
 
    switch (state)
    {
        case APP_STATE_EEPROM_STATUS_VERIFY:

            /* Register the TWIHS Callback with transfer status as context */
            I2C2_CallbackRegister( APP_I2CCallback, (uintptr_t)&transferStatus );

           /* Verify if EEPROM is ready to accept new requests */
            transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
            I2C2_Write(APP_AT24MAC_DEVICE_ADDR, &ackData, APP_ACK_DATA_LENGTH);

            state = APP_STATE_EEPROM_WRITE;
            break;

        case APP_STATE_EEPROM_WRITE:

            if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
            {
                /* Write data to EEPROM */
                transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                I2C2_Write(APP_AT24MAC_DEVICE_ADDR, &testTxData, APP_TRANSMIT_DATA_LENGTH);
                state = APP_STATE_EEPROM_WAIT_WRITE_COMPLETE;
            }
            else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
            {
                /* EEPROM is not ready to accept new requests */
                state = APP_STATE_XFER_ERROR;
            }
            break;

        case APP_STATE_EEPROM_WAIT_WRITE_COMPLETE:

            if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
            {
                /* Read the status of internal write cycle */
                transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                I2C2_Write(APP_AT24MAC_DEVICE_ADDR, &ackData, APP_ACK_DATA_LENGTH);
                state = APP_STATE_EEPROM_CHECK_INTERNAL_WRITE_STATUS;
            }
            else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
            {
                state = APP_STATE_XFER_ERROR;
            }
            break;

         case APP_STATE_EEPROM_CHECK_INTERNAL_WRITE_STATUS:

            if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
            {
               // state = APP_STATE_EEPROM_READ;
                state = APP_STATE_XFER_SUCCESSFUL;
            }
            else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
            {
                /* EEPROM's internal write cycle is not complete. Keep checking. */
                transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
                I2C2_Write(APP_AT24MAC_DEVICE_ADDR, &ackData, APP_ACK_DATA_LENGTH);
            }
            break;

        case APP_STATE_EEPROM_READ:

            transferStatus = APP_TRANSFER_STATUS_IN_PROGRESS;
            /* Read the data from the page written earlier */
            I2C2_WriteRead(APP_AT24MAC_DEVICE_ADDR, &testTxData, APP_RECEIVE_DUMMY_WRITE_LENGTH,  &testRxData, APP_RECEIVE_DATA_LENGTH);

            state = APP_STATE_EEPROM_WAIT_READ_COMPLETE;

            break;

        case APP_STATE_EEPROM_WAIT_READ_COMPLETE:

            if (transferStatus == APP_TRANSFER_STATUS_SUCCESS)
            {
                //state = APP_STATE_VERIFY;
                state = APP_STATE_XFER_SUCCESSFUL;
            }
            else if (transferStatus == APP_TRANSFER_STATUS_ERROR)
            {
                state = APP_STATE_XFER_ERROR;
            }
            break;

        case APP_STATE_VERIFY:

            if (memcmp(&testTxData[2], &testRxData[0], APP_RECEIVE_DATA_LENGTH) != 0)
            {
                /* It means received data is not same as transmitted data */
                state = APP_STATE_XFER_ERROR;
            }
            else
            {
                /* It means received data is same as transmitted data */
                state = APP_STATE_XFER_SUCCESSFUL;
            }
            break;

        case APP_STATE_XFER_SUCCESSFUL:
        {
            break;
        }
        case APP_STATE_XFER_ERROR:
        {
            break;
        }
        default:
            break;
    }
}

// *****************************************************************************
//
// Section: Application Initialization and State Machine Functions
// Follow are BQ7693007 Functions
//
// *****************************************************************************

#include <stdbool.h>
//#include <bqMaximo_Ctrl_G2553.h>
#include <math.h>
#include <float.h>
#include <stdlib.h>
//#include <plib_i2c2_master.h>

/* Disable the I2C Master interrupt */
//  IEC2CLR = _IEC2_I2C2MIE_MASK;

RegisterGroup Registers;

const unsigned int OVPThreshold = 4300;
const unsigned int UVPThreshold = 2500;
const unsigned char SCDDelay = SCD_DELAY_100us;
const unsigned char SCDThresh = SCD_THRESH_89mV_44mV;
const unsigned char OCDDelay = OCD_DELAY_320ms;
const unsigned char OCDThresh = OCD_THRESH_22mV_11mV;
const unsigned char OVDelay = OV_DELAY_2s;
const unsigned char UVDelay = UV_DELAY_8s;

unsigned int CellVoltage[15];
float Gain = 0;
int iGain = 0;

int I2CSendByte(unsigned char I2CSlaveAddress, unsigned char data)
{
    APP_AT24MAC_DEVICE_ADDR = I2CSlaveAddress;
    testTxData[0] = data;
    APP_ACK_DATA_LENGTH = 1;
    
    state = APP_STATE_EEPROM_WRITE;
    APP_I2C_Tasks();
      
    return 0;
    
}

int I2CSendBytes(unsigned char I2CSlaveAddress, unsigned char *DataBuffer, unsigned int ByteCount, unsigned int *SentByte)
{
    unsigned int NumberOfBytesSent = 0;
    unsigned char *DataPointer;
//I2C2_Write(APP_AT24MAC_DEVICE_ADDR, &testTxData, APP_TRANSMIT_DATA_LENGTH);

    APP_AT24MAC_DEVICE_ADDR = I2CSlaveAddress;
#define    APP_TRANSMIT_DATA_LENGTH  ByteCount
    DataPointer = DataBuffer;

    for(NumberOfBytesSent = 0; NumberOfBytesSent < ByteCount; NumberOfBytesSent++)
    {
       // UCB0TXBUF= *DataPointer;  // send data
        testTxData[NumberOfBytesSent] = *DataPointer;
        *SentByte = NumberOfBytesSent;
        //UCB0CTL1 |= UCTXSTP;				//send stop condition
        state = APP_STATE_EEPROM_WRITE;
        APP_I2C_Tasks();
    }

    *SentByte =  NumberOfBytesSent;
    
    return 0; 

}

int I2CWriteRegisterByte(unsigned char I2CSlaveAddress, unsigned char Register, unsigned char Data)
{
    unsigned char DataBuffer[2];
    unsigned int SentByte = 0;


    DataBuffer[0] = Register;
    DataBuffer[1] = Data;

    return(I2CSendBytes(I2CSlaveAddress, DataBuffer, 2, &SentByte));
}

int I2CWriteRegisterByteWithCRC(unsigned char I2CSlaveAddress, unsigned char Register, unsigned char Data)
{
    unsigned char DataBuffer[4];
    unsigned int SentByte = 0;

    DataBuffer[0] = I2CSlaveAddress << 1;
    DataBuffer[1] = Register;
    DataBuffer[2] = Data;
    DataBuffer[3] = CRC8(DataBuffer, 3, CRC_KEY);

    return(I2CSendBytes(I2CSlaveAddress, DataBuffer + 1, 3, &SentByte));
}

int I2CWriteRegisterWordWithCRC(unsigned char I2CSlaveAddress, unsigned char Register, unsigned int Data)
{
    unsigned char DataBuffer[6];
    unsigned int SentByte = 0;

    DataBuffer[0] = I2CSlaveAddress << 1;
    DataBuffer[1] = Register;
    DataBuffer[2] = LOW_BYTE(Data);
    DataBuffer[3] = CRC8(DataBuffer, 3, CRC_KEY);
    DataBuffer[4] = HIGH_BYTE(Data);
    DataBuffer[5] = CRC8(DataBuffer + 4, 1, CRC_KEY);

    return(I2CSendBytes(I2CSlaveAddress, DataBuffer + 1, 5, &SentByte));
}

int I2CWriteBlockWithCRC(unsigned char I2CSlaveAddress, unsigned char StartAddress, unsigned char *Buffer, unsigned char Length)
{
    unsigned char *BufferCRC, *Pointer;
    int i;
    unsigned int SentByte = 0;
    int result;

    BufferCRC = (unsigned char*)malloc(2*Length + 2);
    if (NULL == BufferCRC)
            return -1;

    Pointer = BufferCRC;
    *Pointer = I2CSlaveAddress << 1;
    Pointer++;
    *Pointer = StartAddress;
    Pointer++;
    *Pointer = *Buffer;
    Pointer++;
    *Pointer = CRC8(BufferCRC, 3, CRC_KEY);

    for(i = 1; i < Length; i++)
    {
    Pointer++;
    Buffer++;
    *Pointer = *Buffer;
            *(Pointer + 1) = CRC8(Pointer, 1, CRC_KEY);
            Pointer++;
    }

    result = I2CSendBytes(I2CSlaveAddress, BufferCRC + 1, 2*Length + 1, &SentByte);

    free(BufferCRC);
    BufferCRC = NULL;

    return result;
}

int I2CWriteRegisterWord(unsigned char I2CSlaveAddress, unsigned char Register, unsigned int Data)
{
    unsigned char DataBuffer[3];
    unsigned int SentByte = 0;

    DataBuffer[0] = Register;
    DataBuffer[1] = LOWBYTE(Data);
    DataBuffer[2] = HIGHBYTE(Data);

    return(I2CSendBytes(I2CSlaveAddress, DataBuffer, 3, &SentByte));
}

int I2CReadBytes(unsigned char I2CSlaveAddress, unsigned char *DataBuffer, unsigned int ExpectedByteNumber, unsigned int *NumberOfReceivedBytes)
{
    unsigned char *DataPointer;
    unsigned int *NumberOfReceivedBytesPointer;

//I2C2_WriteRead(APP_AT24MAC_DEVICE_ADDR, &testTxData, APP_RECEIVE_DUMMY_WRITE_LENGTH,  &testRxData, APP_RECEIVE_DATA_LENGTH);
 #define   APP_RECEIVE_DUMMY_WRITE_LENGTH  0
    NumberOfReceivedBytesPointer = NumberOfReceivedBytes;
    *NumberOfReceivedBytesPointer = 0;


    DataPointer = DataBuffer;
    APP_AT24MAC_DEVICE_ADDR = I2CSlaveAddress;

    for(*NumberOfReceivedBytesPointer = 0; *NumberOfReceivedBytesPointer < ExpectedByteNumber; (*NumberOfReceivedBytesPointer)++)
    {
        state = APP_STATE_EEPROM_READ;
        APP_I2C_Tasks();      
        *DataPointer = testRxData;
        DataPointer++;
    }   
    return 0;

}

int I2CReadRegisterByte(unsigned char I2CSlaveAddress, unsigned char Register, unsigned char *Data)
{
    unsigned char TargetRegister = Register;
    unsigned int SentByte = 0;
    unsigned int ReadDataCount = 0;
    int ReadStatus = 0;
    int WriteStatus = 0;

    WriteStatus = I2CSendBytes(I2CSlaveAddress, &TargetRegister, 1, &SentByte);

    ReadStatus = I2CReadBytes(I2CSlaveAddress, Data, 1, &ReadDataCount);

    if (ReadStatus != 0 || WriteStatus != 0)
    {
            return -1;
    }

    return 0;
}

int I2CReadBlock(unsigned char I2CSlaveAddress, unsigned char StartRegisterAddress, unsigned char *Buffer, unsigned int BlockSize, unsigned int *NumberOfBytes)
{
    unsigned char TargetRegister = StartRegisterAddress;
    unsigned int SentByte = 0;
    int ReadStatus = 0;
    int WriteStatus = 0;

    WriteStatus = I2CSendBytes(I2CSlaveAddress, &TargetRegister, 1, &SentByte);

    ReadStatus = I2CReadBytes(I2CSlaveAddress, Buffer, BlockSize, NumberOfBytes);

    if(ReadStatus != 0 || WriteStatus != 0)
    {
            return -1;
    }

    return 0;
}

unsigned char CRC8(unsigned char *ptr, unsigned char len,unsigned char key)
{
    unsigned char i;
    unsigned char crc=0;
    while(len--!=0)
    {
        for(i=0x80; i!=0; i/=2)
        {
            if((crc & 0x80) != 0)
            {
                    crc *= 2;
                    crc ^= key;
            }
            else
                    crc *= 2;

            if((*ptr & i)!=0)
                    crc ^= key;
        }
        ptr++;
    }
    return(crc);
}

int I2CReadRegisterByteWithCRC(unsigned char I2CSlaveAddress, unsigned char Register, unsigned char *Data)
{
    unsigned char TargetRegister = Register;
    unsigned int SentByte = 0;
    unsigned char ReadData[2];
    unsigned int ReadDataCount = 0;
    unsigned char CRCInput[2];
    unsigned char CRC = 0;
    int ReadStatus = 0;
    int WriteStatus = 0;

    WriteStatus = I2CSendBytes(I2CSlaveAddress, &TargetRegister, 1, &SentByte);

    ReadStatus = I2CReadBytes(I2CSlaveAddress, ReadData, 2, &ReadDataCount);

    if (ReadStatus != 0 || WriteStatus != 0)
    {
        return -1;
    }

    CRCInput[0] = (I2CSlaveAddress << 1) + 1;
    CRCInput[1] = ReadData[0];

    CRC = CRC8(CRCInput, 2, CRC_KEY);

    if (CRC != ReadData[1])
        return -1;

    *Data = ReadData[0];
    return 0;
}

int I2CReadRegisterWordWithCRC(unsigned char I2CSlaveAddress, unsigned char Register, unsigned int *Data)
{
    unsigned char TargetRegister = Register;
    unsigned int SentByte = 0;
    unsigned char ReadData[4];
    unsigned int ReadDataCount = 0;
    unsigned char CRCInput[2];
    unsigned char CRC = 0;
    int ReadStatus = 0;
    int WriteStatus = 0;

    WriteStatus = I2CSendBytes(I2CSlaveAddress, &TargetRegister, 1, &SentByte);

    ReadStatus = I2CReadBytes(I2CSlaveAddress, ReadData, 4, &ReadDataCount);

    if (ReadStatus != 0 || WriteStatus != 0)
    {
        return -1;
    }

    CRCInput[0] = (I2CSlaveAddress << 1) + 1;
    CRCInput[1] = ReadData[0];

    CRC = CRC8(CRCInput, 2, CRC_KEY);

    if (CRC != ReadData[1])
        return -1;

    CRC = CRC8(ReadData + 2, 1, CRC_KEY);

    if (CRC != ReadData[3])
        return -1;

    *Data = ReadData[0];

    *Data = (*Data << 8) + ReadData[2];

    return 0;
}

int I2CReadBlockWithCRC(unsigned char I2CSlaveAddress, unsigned char Register, unsigned char *Buffer, unsigned char Length)
{
    unsigned char TargetRegister = Register;
    unsigned int SentByte = 0;
    unsigned char *ReadData = NULL, *StartData = NULL;
    unsigned int ReadDataCount = 0;
    unsigned char CRCInput[2];
    unsigned char CRC = 0;
    int ReadStatus = 0;
    int WriteStatus = 0;
    int i;

    StartData = (unsigned char *)malloc(2 * Length);

    if (NULL == StartData)
    	return -1;

    ReadData = StartData;

    WriteStatus = I2CSendBytes(I2CSlaveAddress, &TargetRegister, 1, &SentByte);

    ReadStatus = I2CReadBytes(I2CSlaveAddress, ReadData, 2 * Length, &ReadDataCount);

    if (ReadStatus != 0 || WriteStatus != 0)
    {
        free(StartData);
        StartData = NULL;

        return -1;
    }

    CRCInput[0] = (I2CSlaveAddress << 1) + 1;
    CRCInput[1] = *ReadData;

    CRC = CRC8(CRCInput, 2, CRC_KEY);

    ReadData++;
    if (CRC != *ReadData)
    {
        free(StartData);
        StartData = NULL;
        return -1;
    }
    else
        *Buffer = *(ReadData - 1);

    for(i = 1; i < Length; i++)
    {
        ReadData++;
        CRC = CRC8(ReadData, 1, CRC_KEY);
        ReadData++;
        Buffer++;

        if (CRC != *ReadData)
        {
            free(StartData);
            StartData = NULL;

            return -1;
        }
        else
            *Buffer = *(ReadData - 1);
    }

    free(StartData);
    StartData = NULL;

    return 0;
}

int GetADCGainOffset()
{
    int result;

    result = I2CReadRegisterByteWithCRC(BQMAXIMO, ADCGAIN1, &(Registers.ADCGain1.ADCGain1Byte));
    result = I2CReadRegisterByteWithCRC(BQMAXIMO, ADCGAIN2, &(Registers.ADCGain2.ADCGain2Byte));
    result = I2CReadRegisterByteWithCRC(BQMAXIMO, ADCOFFSET, &(Registers.ADCOffset));

    return result;
}

int ConfigureBqMaximo()
{
    int result = 0;
    unsigned char bqMaximoProtectionConfig[5];

    result = I2CWriteBlockWithCRC(BQMAXIMO, PROTECT1, &(Registers.Protect1.Protect1Byte), 5);

    result = I2CReadBlockWithCRC(BQMAXIMO, PROTECT1, bqMaximoProtectionConfig, 5);

    if(bqMaximoProtectionConfig[0] != Registers.Protect1.Protect1Byte
                    || bqMaximoProtectionConfig[1] != Registers.Protect2.Protect2Byte
                    || bqMaximoProtectionConfig[2] != Registers.Protect3.Protect3Byte
                    || bqMaximoProtectionConfig[3] != Registers.OVTrip
                    || bqMaximoProtectionConfig[4] != Registers.UVTrip)
    {
        result = -1;
    }

    return result;
}

int InitialisebqMaximo()
{
    int result = 0;

    Registers.Protect1.Protect1Bit.SCD_DELAY = SCDDelay;
    Registers.Protect1.Protect1Bit.SCD_THRESH = SCDThresh;
    Registers.Protect2.Protect2Bit.OCD_DELAY = OCDDelay;
    Registers.Protect2.Protect2Bit.OCD_THRESH = OCDThresh;
    Registers.Protect3.Protect3Bit.OV_DELAY = OVDelay;
    Registers.Protect3.Protect3Bit.UV_DELAY = UVDelay;

    result = GetADCGainOffset();

    Gain = (365 + ((Registers.ADCGain1.ADCGain1Byte & 0x0C) << 1) + ((Registers.ADCGain2.ADCGain2Byte & 0xE0)>> 5)) / 1000.0;
    iGain = 365 + ((Registers.ADCGain1.ADCGain1Byte & 0x0C) << 1) + ((Registers.ADCGain2.ADCGain2Byte & 0xE0)>> 5);

    Registers.OVTrip = (unsigned char)((((unsigned short)((OVPThreshold - Registers.ADCOffset)/Gain + 0.5) - OV_THRESH_BASE) >> 4) & 0xFF);
    Registers.UVTrip = (unsigned char)((((unsigned short)((UVPThreshold - Registers.ADCOffset)/Gain + 0.5) - UV_THRESH_BASE) >> 4) & 0xFF);

    result = ConfigureBqMaximo();

    return result;
}

int UpdateVoltageFromBqMaximo()
{
    int Result = 0, i = 0;
    unsigned char *pRawADCData = NULL;
    unsigned int iTemp = 0;
    unsigned long lTemp = 0;

    Result = I2CReadBlockWithCRC(BQMAXIMO, \
                    VC1_HI_BYTE, \
                    &(Registers.VCell1.VCell1Byte.VC1_HI), \
                    30);
    
    /* Result = I2CReadBlockWithCRC(BQMAXIMO, \
                    VC1_HI_BYTE, \
                    &(Registers.VCell2.VCell2Byte.VC2_HI), \
                    30);*/
    
    pRawADCData = &Registers.VCell1.VCell1Byte.VC1_HI;
    for (i = 0; i < 15; i++)
    {
        iTemp = (unsigned int)(*pRawADCData << 8) + *(pRawADCData + 1);
        lTemp = ((unsigned long)iTemp * iGain)/1000;
        lTemp += Registers.ADCOffset;
        CellVoltage[i] = lTemp;
        pRawADCData += 2;
    }

    return Result;
}

int Read_BQ(void)
{
    int Result;

   // WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer

    //DISABLE_INT;

   // ClockInitialise();

   // I2CInitialise();

    //InitialisebqMaximo();

   // while(1)
    {
    	Result = UpdateVoltageFromBqMaximo();
    }
   // Result=0x02e2;
    printf("BQ          : Cell Nr.1 = %d.%02d V \r\n", (int)Result, (int)((Result - (int)Result)*100.0));
    printf("\n");
    
    return Result;
}



/*******************************************************************************
 End of File
 */
