/***** Includes *****/
#include "mbed.h"
#include "max32630fthr.h"
#include "USBSerial.h"

#include "gpio.h"
#include "mxc_config.h"
#include "clkman.h"
#include "ioman.h"
#include "spim.h"
#include "spis.h"

/***** Globals *****/

MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
uint8_t spiwidth = 0;

// Hardware serial port over DAPLink
Serial daplink(P2_1, P2_0);

// Virtual serial port over USB
USBSerial microUSB; 

DigitalOut rLED(LED1);
DigitalOut gLED(LED2);
DigitalOut bLED(LED3);



/***** Functions *****/

union spisRXcontainer32 {
	uint8_t rx8[4];
	uint32_t rx32;
};

uint32_t spis_read_quad32bit() {
	spisRXcontainer32 rxbuf;

	spis_req_t req;

	req.len = 4;
	req.width = SPIS_WIDTH_4;
	req.tx_data  = NULL;
	req.rx_data  = rxbuf.rx8;
	req.deass   = 0;

	SPIS_Trans(MXC_SPIS, &req);

	return rxbuf.rx32;
}

uint8_t spis_read_8bit() {
	uint8_t rxbuf;

	spis_req_t req;

	req.len = 1;
	req.width = SPIS_WIDTH_4;
	req.tx_data  = NULL;
	req.rx_data  = &rxbuf;
	req.deass   = 0;

	SPIS_Trans(MXC_SPIS, &req);

	return rxbuf;
}


void spis_config() {
	//fthr extra, set shared pin to high Z input
	gpio_cfg_t gpio_cfg;
	gpio_cfg.port = 5;
	gpio_cfg.mask = PIN_0 | PIN_1 | PIN_2 | PIN_3 | PIN_4 | PIN_5;
	gpio_cfg.func = GPIO_FUNC_GPIO;
	gpio_cfg.pad= GPIO_PAD_INPUT;
	GPIO_Config(&gpio_cfg);

	int error;
	uint8_t spis_mode = 0;
	sys_cfg_spis_t sys_cfg;

	//IO Config			  req pin, core I/O, quad, fast     usr manual pg333
	sys_cfg.io_cfg = IOMAN_SPIS(0, 1, 1, 1);
	sys_cfg.clk_scale = CLKMAN_SCALE_AUTO;


    if((error = SPIS_Init(MXC_SPIS, spis_mode, &sys_cfg)) != E_NO_ERROR) {
    	microUSB.printf("Error initializing SPIS %d\n", error);
        while(1) {}
    } else {
    	microUSB.printf("SPIS Initialized, SPIS Clock speed %d\n", SYS_SPIS_GetFreq());

    	//Maxim SDK doesn't provide init function to set spis quad mode
    	spiwidth = MXC_SPIS->gen_ctrl & 0b00110000;	//bits location 5:4
    	daplink.printf("initial spi width mode: %d\r\n",  (spiwidth >> 4) );

    	MXC_SPIS->gen_ctrl &= ~(1UL << 4); //set quad
    	MXC_SPIS->gen_ctrl |= 1UL <<  5;

    	spiwidth = MXC_SPIS->gen_ctrl & 0b00110000;	//bits location 5:4
    	daplink.printf("set spi width mode : %d\r\n", (spiwidth >> 4) );

    }
};



// *****************************************************************************
// main() runs in its own thread in the OS
// (note the calls to Thread::wait below for delays)
int main()
{
    daplink.printf("daplink serial port\r\n");
    microUSB.printf("micro USB serial port\r\n");

    rLED = LED_ON;
    gLED = LED_ON;
    bLED = LED_OFF;

    rLED = LED_OFF;

    //c = microUSB.getc();
    spis_config();


    uint8_t readSpi8[8];
    uint32_t readSpi32[8];

    uint8_t spiRxAvail;

	spiRxAvail = SPIS_NumReadAvail(MXC_SPIS);
	daplink.printf("buf avail:%d\r\n", spiRxAvail);

    while(1) {

    	if( (spiwidth<<4) == 0) {
    		//4-wire mode
    		while( SPIS_NumReadAvail(MXC_SPIS) < 8 ) {};

        	for (int i = 0; i< 8; i++){
        		readSpi8[i] = spis_read_8bit();
        	}

        	for (int i = 0; i< 8; i++){
        		daplink.printf("spi read : 0x%08x\r\n", readSpi8[i]);
        	}

    	}

    	if( (spiwidth<<4) == 2) {
    		//6-wire (quad) mode

        	while( SPIS_NumReadAvail(MXC_SPIS) < 4 * 8 ) {};

        	for (int i = 0; i< 8; i++){
        		readSpi32[i] = spis_read_quad32bit();
        	}
        	for (int i = 0; i< 8; i++){
        		daplink.printf("spi read : 0x%08x\r\n", readSpi32[i]);
        	}

        }

    	spiRxAvail = SPIS_NumReadAvail(MXC_SPIS);
    	daplink.printf("buf left:%d\r\n", spiRxAvail);

	}



}

