/* --COPYRIGHT--,BSD
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/

#include <msp430.h> 
#include <stdint.h>
#include <stdbool.h>

/*! Define the Target processor: TARGET_G2553 or TARGET_G2452 */
// Pre-Defined Target configuration (Properties->Build->Advanced Options->Predefined Symbols)


//
// Target Application files
// Contain the sample applications sent to the target
//
#ifdef TARGET_G2553
#include "TargetApps\App1_G2553_I2C_BSLBased_G2Host.c"
#include "TargetApps\App2_G2553_I2C_BSLBased_G2Host.c"
#elif (defined(TARGET_G2452))
#include "TargetApps\App1_G2452_I2C_BSLBased_G2Host.c"
#include "TargetApps\App2_G2452_I2C_BSLBased_G2Host.c"
#elif (defined(TARGET_FR5739))
#include "TargetApps\App1_FR5739_I2C_BSLBased_G2Host.c"
#include "TargetApps\App2_FR5739_I2C_BSLBased_G2Host.c"
#elif (defined(TARGET_G2553_UART))
#include "TargetApps\App1_G2553_UART_BSLBased_G2Host.c"
#include "TargetApps\App2_G2553_UART_BSLBased_G2Host.c"
#elif (defined(TARGET_G2553_SPI))
#include "TargetApps\App1_G2553_SPI_BSLBased_G2Host.c"
#include "TargetApps\App2_G2553_SPI_BSLBased_G2Host.c"
#else
#error Define a valid target
#endif


#include "bsl.h"
#include "Crc.h"

/* Statics */
static bool bPerformBSL;
static bool sentBSLFlipFlop;

#ifdef TARGET_G2553
static uint16_t CRC_Addr = 0xC000;
static uint16_t App_StartAddress = 0xC003;
static uint16_t App_EndAddress = 0xFBFF;
#elif (defined(TARGET_G2452))
static uint16_t CRC_Addr = 0xE000;
static uint16_t App_StartAddress = 0xE003;
static uint16_t App_EndAddress = 0xF9FF;
#elif (defined(TARGET_FR5739))
static uint16_t CRC_Addr = 0xC200;
static uint16_t App_StartAddress = 0xC203;
static uint16_t App_EndAddress = 0xF9FF;
#elif (defined(TARGET_G2553_UART))
static uint16_t CRC_Addr = 0xC000;
static uint16_t App_StartAddress = 0xC003;
static uint16_t App_EndAddress = 0xFBFF;
#elif (defined(TARGET_G2553_SPI))
static uint16_t CRC_Addr = 0xC000;
static uint16_t App_StartAddress = 0xC003;
static uint16_t App_EndAddress = 0xFBFF;
#endif
static uint16_t CRC_Val1, CRC_Val2;


/* Error Checking Macro */
#define CHECK_RESPONSE()  if(res != BSL_OK_RES)             \
{                                             \
    break;                                    \
}

static uint16_t Calc_App_CRC(uint16_t * Addr_array, uint16_t *Size_array, uint8_t ** DataPtr_Array, uint8_t num_arrays);

int main(void)
{
    uint8_t res;

    /* Stop the watchdog timer */
    WDTCTL = WDTPW | WDTHOLD;

    if ((CALBC1_8MHZ == 0xFF) || (CALDCO_8MHZ == 0xFF))
    {
        while (1) ;                     /* Trap if DCO constants are not available */
    }
    BCSCTL1 = CALBC1_8MHZ;              /* Set DCO to default of 8Mhz               */
    DCOCTL = CALDCO_8MHZ;

    /* Calculate CRC for both applications */
    CRC_Val1 = Calc_App_CRC( (uint16_t *)&App1_Addr[0],
                              (uint16_t *)&App1_Size[0],
                              (uint8_t **)&App1_Ptr[0],
                              sizeof(App1_Addr)/ sizeof (App1_Addr[0]));
    CRC_Val2 = Calc_App_CRC( (uint16_t *)&App2_Addr[0],
                              (uint16_t *)&App2_Size[0],
                              (uint8_t **)&App2_Ptr[0],
                              sizeof(App2_Addr)/ sizeof (App2_Addr[0]));

    /* Resetting our event flag */
    bPerformBSL = false;
    sentBSLFlipFlop = false;

    BSL_Init();

    /* Start P1.3 (S2 button) as interrupt with pull-up */
    P1OUT |= (BIT3);
    P1OUT &= ~BIT0;
    P1DIR |= BIT0;
    P1REN |= BIT3;
    P1IES |= BIT3;
    P1IFG &= ~BIT3;
    P1IE |= BIT3;

    while (1)
    {
        P1IFG &= ~BIT3; // Clear button flag before going to sleep
        __bis_SR_register(LPM0_bits + GIE);
        __disable_interrupt();

        while (bPerformBSL == true)
        {
            /* Blinking LED to signal BSL start */
            P1OUT ^= (BIT0);
            __delay_cycles(2500000);
            P1OUT ^= (BIT0);
            __delay_cycles(2500000);
            P1OUT ^= (BIT0);
            __delay_cycles(2500000);
            P1OUT ^= (BIT0);

            bPerformBSL = false;


            if (!BSL_slavePresent())
                break;
            /* Sending the BSL Entry command to user app on target */
            BSL_sendSingleByte(VBOOT_ENTRY_CMD);
            __delay_cycles(40000);
            
            BSL_flush();

            /* Sending the version command */
            res = BSL_sendCommand(BSL_VERSION_CMD);

            /* Making sure the version matches (only check upper nibble) */
            if ((res&0xF0) == (VBOOT_VERSION&0xF0))
            {
                /* Erasing the user application */
                res = BSL_sendCommand(BSL_ERASE_APP_CMD);
                CHECK_RESPONSE();

                if(!sentBSLFlipFlop)
                {
                    /* Sending the first segment (application) */
                    res = BSL_programMemorySegment(App1_Addr[0],
                            App1_Ptr[0], App1_Size[0]);
                    CHECK_RESPONSE();

                    /* Sending the second segment (vector table) */
                    res = BSL_programMemorySegment(App1_Addr[1],
                            App1_Ptr[1], App1_Size[1]);
                    CHECK_RESPONSE();
                    /* Sending the CRC */
                    res = BSL_programMemorySegment(CRC_Addr,
                            (uint8_t *) &CRC_Val1, 2);
                    CHECK_RESPONSE();
                }
                else
                {
                    /* Sending the first segment (application) */
                    res = BSL_programMemorySegment(App2_Addr[0],
                            App2_Ptr[0], App2_Size[0]);
                    CHECK_RESPONSE();

                    /* Sending the first segment (vector table) */
                    res = BSL_programMemorySegment(App2_Addr[1],
                            App2_Ptr[1], App2_Size[1]);
                    CHECK_RESPONSE();
                    /* Sending the CRC */
                    res = BSL_programMemorySegment(CRC_Addr,
                            (uint8_t *) &CRC_Val2, 2);
                    CHECK_RESPONSE();
                }
                /* Jumping to user code */
                res = BSL_sendCommand(BSL_JMP_APP_CMD);
                // End of cycle completed OK
                __delay_cycles(2500000);
                P1OUT ^= (BIT0);
                __delay_cycles(2500000);
                P1OUT ^= (BIT0);
                __delay_cycles(2500000);
                P1OUT ^= (BIT0);
            }

            sentBSLFlipFlop = !sentBSLFlipFlop;
        }
    }
}

/* Push button that will invoke BSL send */
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
    P1IFG &= ~BIT3;
    bPerformBSL = true;
    __bic_SR_register_on_exit(LPM0_bits);
}

/* Dummy ISR for unimplemented interrupts */
#pragma vector=PORT2_VECTOR, ADC10_VECTOR, USCIAB0RX_VECTOR, USCIAB0TX_VECTOR,\
               COMPARATORA_VECTOR, NMI_VECTOR, TIMER0_A0_VECTOR, TIMER0_A1_VECTOR,\
               TIMER1_A0_VECTOR, TIMER1_A1_VECTOR, WDT_VECTOR
__interrupt void DummyIsr(void)
{
    // Capture an unimplemented ISR
    while(1)
        ;
}

/* Calculate the CRC of the application*/
static uint16_t Calc_App_CRC(uint16_t * Addr_array, uint16_t *Size_array, uint8_t ** DataPtr_Array, uint8_t num_arrays)
{
    uint16_t addr;
    uint8_t i;
    uint16_t CRC_result = 0xFFFF;

    // Calculate CRC for the whole Application address range
    for (addr=App_StartAddress; addr <= App_EndAddress; addr++)
    {
        for (i = 0; i < num_arrays; i ++)
        {
            // Check if address is defined by application image
            if ( (addr >= Addr_array[i]) &&
                 (addr < (Addr_array[i] + Size_array[i])) )
            {
                // If address is defined, add it to the CRC
                crc16AddByte(DataPtr_Array[i][addr-Addr_array[i]],&CRC_result);
                break;
            }
        }
        if (i==num_arrays)
        {
            // If not, simply add 0xFF
            crc16AddByte(0xFF,&CRC_result);
        }
    }

    return CRC_result;
}
