/* --COPYRIGHT--,BSD
 * Copyright (c) 2017, 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--*/
/*******************************************************************************
 * MSP432 DMA - eUSCI SPI Rx Using DMA
 *
 *
 *
 *                      MSP432P401
 *             ---------------------------
 *         /|\|                          |
 *          | |                          |
 *          --|RST                       |
 *            |                          |
 *            |              P3.6 (SIMO) |--------
 *            |              P3.7 (SOMI) |-------
 *            |              P3.5 (CLK)  |--------
 *            |                          |
 *            |              P2.0  (CS)  |-------
 *            |                          |
 *
 ******************************************************************************/

/* DriverLib Includes */
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>

/* Standard Includes */
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

const eUSCI_SPI_SlaveConfig spiSlaveConfig =
{ EUSCI_B_SPI_MSB_FIRST,
        EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT,
        EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH,
        EUSCI_B_SPI_3PIN
        };

/* DMA Control Table */
#if defined(__TI_COMPILER_VERSION__)
#pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024)
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma data_alignment=1024
#elif defined(__GNUC__)
__attribute__ ((aligned (1024)))
#elif defined(__CC_ARM)
__align(1024)
#endif
static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32];

#define MAP_SPI_MSG_LENGTH    33

/*
 * five different delays, each with 33 bytes of payload
 *
 */

uint8_t receiveData0[MAP_SPI_MSG_LENGTH];
uint8_t receiveData1[MAP_SPI_MSG_LENGTH];
uint8_t receiveData2[MAP_SPI_MSG_LENGTH];
uint8_t receiveData3[MAP_SPI_MSG_LENGTH];
uint8_t receiveData4[MAP_SPI_MSG_LENGTH];
uint8_t *arrayPtr[5];
uint8_t arrayIndex;
uint8_t failCheck[5];

const uint8_t mstxData[MAP_SPI_MSG_LENGTH] =
{
     0x01, //  Delay size between TX bytes
     /*
      * Payload
      */
     0xAA,
     0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,
     0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,
     0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,
     0x55
};

int main(void)
{
    /* Halting Watchdog */
    MAP_WDT_A_holdTimer();

    arrayIndex = 0;
    failCheck[arrayIndex] = 0xAA;
    arrayPtr[0] = receiveData0;
    arrayPtr[1] = receiveData1;
    arrayPtr[2] = receiveData2;
    arrayPtr[3] = receiveData3;
    arrayPtr[4] = receiveData4;

    /* Configure SLAVE CLK, MOSI and SPMI (EUSCI_B2) */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,
            GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7,
            GPIO_PRIMARY_MODULE_FUNCTION);
    /* Configuring P1.0 as output for debug */
    MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
    MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
    /*
     * Configuring P2.0 as an input to verify stop and start of communication
     * when P2.0 is low that means communication is going, when high comms have
     * stopped.
     */
    MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN0);
    MAP_GPIO_interruptEdgeSelect(GPIO_PORT_P2,GPIO_PIN0,GPIO_LOW_TO_HIGH_TRANSITION);
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P2, GPIO_PIN0);
    MAP_GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN0);

    /*
     * Revision C silicon supports wait states of 1 at 48Mhz
     */
    MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
    MAP_FlashCtl_setWaitState(FLASH_BANK0, 1);
    MAP_FlashCtl_setWaitState(FLASH_BANK1, 1);

    /*
     * Setting up clocks
     * MCLK = MCLK = 32MHz
     * SMCLK = MCLK = 32Mhz
     * ACLK = REFO = 32Khz
     */
    MAP_CS_setDCOFrequency(48000000);
    MAP_CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
    MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_2);
    MAP_CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);

    /* Configuring SPI module */
    MAP_SPI_initSlave(EUSCI_B2_BASE, &spiSlaveConfig);

    /* Enable the SPI module */
    MAP_SPI_enableModule(EUSCI_B2_BASE);

    /* Configuring DMA module */
    MAP_DMA_enableModule();
    MAP_DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);

    /* Assign DMA channel 0 to EUSCI_B0_TX0, channel 1 to EUSCI_B0_RX0 */
    MAP_DMA_assignChannel(DMA_CH5_EUSCIB2RX0);

    /* Setup the RX transfer characteristics & buffers */
    MAP_DMA_setChannelControl(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    MAP_DMA_setChannelTransfer(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC,
            (void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B2_BASE),
            arrayPtr[arrayIndex],
            MAP_SPI_MSG_LENGTH);

    /* Enable DMA interrupt */
    MAP_DMA_assignInterrupt(INT_DMA_INT1, 5);
    MAP_DMA_clearInterruptFlag(DMA_CH5_EUSCIB2RX0 & 0x0F);

    /* Assigning/Enabling Interrupts */
    MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_enableChannel(5);

    MAP_Interrupt_enableInterrupt(INT_PORT2);
    MAP_Interrupt_enableMaster();

    /* Polling to see if the master receive is finished */
    while (1);
}

void DMA_INT1_IRQHandler(void)
{
    // DEBUG, look here to see if what was received was as expected.
    __no_operation();
    failCheck[arrayIndex] = 0;
}

void PORT2_IRQHandler(void)
{
    volatile uint16_t ii;

    P2IFG &= ~BIT0;

    if(arrayPtr[arrayIndex][0] != arrayIndex+1)
    {
        MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);
    }

    for(ii=1;ii < MAP_SPI_MSG_LENGTH; ii++)
    {
        if(arrayPtr[arrayIndex][ii] != mstxData[ii])
        {
            MAP_GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);
        }
    }

    arrayIndex++;
    if(arrayIndex > 4)
    {
        __no_operation();
        arrayIndex = 0;
        for(ii=0;ii < MAP_SPI_MSG_LENGTH; ii++)
        {
            arrayPtr[0][ii] = 0;
            arrayPtr[1][ii] = 0;
            arrayPtr[2][ii] = 0;
            arrayPtr[3][ii] = 0;
            arrayPtr[4][ii] = 0;

        }

    }
    // reset the DMA


    MAP_SPI_clearInterruptFlag(EUSCI_B2_BASE,EUSCI_SPI_RECEIVE_INTERRUPT);
    /* Configuring SPI module */
    MAP_SPI_initSlave(EUSCI_B2_BASE, &spiSlaveConfig);

    /* Enable the SPI module */
    MAP_SPI_enableModule(EUSCI_B2_BASE);
    MAP_DMA_disableInterrupt(INT_DMA_INT1);
    MAP_DMA_disableChannel(5);
    MAP_DMA_disableModule();

    /* Configuring DMA module */
    MAP_DMA_enableModule();
    MAP_DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);
    /*
     * Setup the DMA + ADC14 interface
     */
    MAP_DMA_disableChannelAttribute(DMA_CH5_EUSCIB2RX0,
                                 UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                 UDMA_ATTR_HIGH_PRIORITY |
                                 UDMA_ATTR_REQMASK);
    /* Assign DMA channel 0 to EUSCI_B0_TX0, channel 1 to EUSCI_B0_RX0 */
    MAP_DMA_assignChannel(DMA_CH5_EUSCIB2RX0);

    /* Setup the RX transfer characteristics & buffers */
    MAP_DMA_setChannelControl(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
    MAP_DMA_setChannelTransfer(DMA_CH5_EUSCIB2RX0 | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC,
            (void *) MAP_SPI_getReceiveBufferAddressForDMA(EUSCI_B2_BASE),
            arrayPtr[arrayIndex],
            MAP_SPI_MSG_LENGTH);

    /* Enable DMA interrupt */
    MAP_DMA_assignInterrupt(INT_DMA_INT1, 5);
    MAP_DMA_clearInterruptFlag(DMA_CH5_EUSCIB2RX0 & 0x0F);

    /* Assigning/Enabling Interrupts */
    MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_enableInterrupt(INT_DMA_INT1);
    MAP_DMA_enableChannel(5);
    failCheck[arrayIndex] = 0xAA;
}

