// Rev 0.1
#include "driverlib.h"

#define SPI_FRAME_SIZE 6
typedef struct _frame
{
    uint8_t data[32];
} frame_t;
frame_t txFrame, rxFrame;
volatile uint8_t dma_done;
void
init_data(void)
{
    uint16_t i;
    for (i = 0 ; i < SPI_FRAME_SIZE ; ++i)
    {
        uint8_t dat;
        dat = i+1;
        txFrame.data[i] = 0x80|dat;
        rxFrame.data[i] = ~dat;
    }
    return;
}
int
main(void) {

    WDT_A_hold(WDT_A_BASE);

    P1OUT &= ~BIT0; P1DIR |= BIT0;
    P9OUT &= ~BIT7; P9DIR |= BIT7;
    PM5CTL0 &= ~LOCKLPM5;

    // Set DCO frequency to default 16MHz
    CS_setDCOFreq(CS_DCORSEL_1, CS_DCOFSEL_4);
    // Set divider to 2
    CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_2);
    CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_2);

    EUSCI_A_SPI_initSlaveParam spiParam = { 0 };
    spiParam.msbFirst = EUSCI_A_SPI_MSB_FIRST;
    spiParam.clockPhase = EUSCI_A_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
    spiParam.clockPolarity = EUSCI_A_SPI_CLOCKPOLARITY_INACTIVITY_LOW;
    spiParam.spiMode = EUSCI_A_SPI_4PIN_UCxSTE_ACTIVE_LOW;
    EUSCI_A_SPI_initSlave(EUSCI_A0_BASE, &spiParam);
    EUSCI_A_SPI_select4PinFunctionality(EUSCI_A0_BASE, EUSCI_A_SPI_ENABLE_SIGNAL_FOR_4WIRE_SLAVE);

    DMA_initParam dmaRxParam = {
            .channelSelect = DMA_CHANNEL_0,
            .transferModeSelect = DMA_TRANSFER_SINGLE,
            .triggerSourceSelect = DMA_TRIGGERSOURCE_14,
            .transferSize = SPI_FRAME_SIZE, // 6
            .transferUnitSelect = DMA_SIZE_SRCBYTE_DSTBYTE,
            .triggerTypeSelect = DMA_TRIGGER_RISINGEDGE
    };

    DMA_initParam dmaTxParam = {
            .channelSelect = DMA_CHANNEL_1,
            .transferModeSelect = DMA_TRANSFER_SINGLE,
            .triggerSourceSelect = DMA_TRIGGERSOURCE_15,
            .transferSize = SPI_FRAME_SIZE, // 6
            .transferUnitSelect = DMA_SIZE_SRCBYTE_DSTBYTE,
            .triggerTypeSelect = DMA_TRIGGER_HIGH
            //.triggerTypeSelect = DMA_TRIGGER_RISINGEDGE
    };
    P2SEL0 |= (BIT0 | BIT1 | BIT2 | BIT3);    // P2.0-3 as UCA0 per SLAS789D Table 6-22

    DMA_init(&dmaRxParam);
    DMA_init(&dmaTxParam);
    __enable_interrupt();
    while (1)
    {
        P9OUT ^= BIT7;
        init_data();                    // Refresh
        dma_done = 0;                   // Early and often
        DMA_setTransferSize(DMA_CHANNEL_0, SPI_FRAME_SIZE); // for example 6 bytes
        DMA_setTransferSize(DMA_CHANNEL_1, SPI_FRAME_SIZE); // for example 6 bytes

        DMA_setSrcAddress(DMA_CHANNEL_0, EUSCI_A_SPI_getReceiveBufferAddress(EUSCI_A0_BASE), DMA_DIRECTION_UNCHANGED);
        DMA_setDstAddress(DMA_CHANNEL_0, (uint32_t)&rxFrame.data, DMA_DIRECTION_INCREMENT);

        DMA_setSrcAddress(DMA_CHANNEL_1, (uint32_t)&txFrame.data, DMA_DIRECTION_INCREMENT);
        DMA_setDstAddress(DMA_CHANNEL_1, EUSCI_A_SPI_getTransmitBufferAddress(EUSCI_A0_BASE), DMA_DIRECTION_UNCHANGED);

        EUSCI_A_SPI_enable(EUSCI_A0_BASE);
        //UCA0IFG &= ~UCTXIFG;

        DMA_clearInterrupt(DMA_CHANNEL_0);
        DMA_enableInterrupt(DMA_CHANNEL_0);
        DMA_enableTransfers(DMA_CHANNEL_0);
        DMA_enableTransfers(DMA_CHANNEL_1);

        //  Wait for completion
        while (!dma_done) LPM0;
        P9OUT ^= BIT7;          // Success
        P1OUT ^= BIT0;          // Progress
    }
    /*NOTREACHED*/
    return (0);
}

#pragma vector=DMA_VECTOR
__interrupt void dma_ISR(void)
{
    DMA_disableInterrupt(DMA_CHANNEL_0);
    DMA_disableTransfers(DMA_CHANNEL_0);
    DMA_disableTransfers(DMA_CHANNEL_1);
    EUSCI_A_SPI_disable(EUSCI_A0_BASE);
    dma_done = 1;
    LPM0_EXIT;                  // Just in case
    return;
}
