/****************************************************************************/
/* Copyright 2010 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
#include <p24fxxxx.h>
#include <stdio.h>
#include <ctype.h>
#include "buffer.h"
#include "spi.h"
#include "serial.h"
#include "sys_timer.h"
#include "sys_defs.h"

#define SPI1_CS_BIT LATGbits.LATG9
#define REG_DEBUG 0	

#define MSG_BUFF_SIZE 64
static char msg_buff[MSG_BUFF_SIZE] = { 0 };

#define SPI_SENTINEL 0x1FFF
#define SPI_BYTE_WAIT 100
#define SPI_TIMEOUT 500

void spiInit()
{    
    /* setup SPI1 registers */    
    SPI1CON1bits.MODE16 = 1;    /* Use 16-bit SPI mode */
    SPI1CON1bits.MSTEN = 1;     /* Enable master mode  */

    SPI1CON1bits.SPRE = 0x06;   /* secondary prescale 2:1 */
    SPI1CON1bits.PPRE = 0x03;   /* pimary prescale 1:1    */

    SPI1CON2bits.SPIBEN = 0;    /* Leave in legacy buffer mode for now */

    /* enable SPI module */
    SPI1STATbits.SPIEN = 1;
}


/* hand tuned delay about 100 usecs per spi transaction */
#define SPI_DELAY   20
unsigned int spiReadWrite(unsigned int data)
{
    int i = 0;
    
    /* put data in SPI TX buffer */
    SPI1BUF = data;

    /* wait for xmit to finish */
    while ( !SPI1STATbits.SPIRBF )
        ; /* wait here */

    /* wait for a couple of ticks */
    while (++i < SPI_DELAY)
        Nop();

    return SPI1BUF;
}

void spiCS(int state)
{
    if ( state )
        SPI1_CS_BIT = 1;		
    else
        SPI1_CS_BIT = 0;
    Nop();
}

void spiSendRecvBytes(unsigned char* bytes, unsigned int len)
{   
    unsigned int i, j;
    unsigned int sendWord = 0;
    unsigned int recvWord = 0;
    char tmpbuf[8];
    
    for (i = 0; i < len; i++)
    {
        sendWord = BUFF_CMD << 10;
        sendWord += (bytes[i] & ARG_MASK);
        spiReadWrite(sendWord);
    }
    
    spiReadWrite(SPI_SENTINEL);
    
    for (i = 0; i < 5000; i++) { Nop(); }
    
    /* Start reading in bytes */
    j = 0;
    for (i = 0; i < MSG_BUFF_SIZE; i++)
    {   
        sendWord = BUFF_RET_CMD << 10;
        sendWord += i & ARG_MASK;
        
        recvWord = spiReadWrite(sendWord);
        
        if (isalnum(recvWord) || ispunct(recvWord) || isspace(recvWord))
        {
            msg_buff[j++] = recvWord;
        }
    }
    msg_buff[j] = 0;
    
    serPutString(SER_CONSOLE, msg_buff);
}

unsigned int spiSlaveRead(unsigned int add, int read_type)
{
    unsigned int reg;
    unsigned int dat;

    if ( (read_type != INFO_CMD) && (read_type != READ_CMD) )
        return 0;
    
    /* create read request */
    reg = (read_type << 10);
    reg += (add & ARG_MASK);

    spiCS(1);
    /* send the read request */
    spiReadWrite(reg);

    /* read the data back */
    dat = spiReadWrite(0);
    spiCS(0);

#if REG_DEBUG
sprintf(msg_buff, "reg = 0x%04X\r\n", reg);
serPutString(SER_CONSOLE, msg_buff);
#endif
    
    return dat;
}

void spiSlaveWrite(unsigned int add, unsigned int dat)
{
    unsigned int reg;

    /* create write request */
    reg = (WRITE_CMD << 10);
    reg += (add & ARG_MASK);

    spiCS(1);
    /* send the write request */
    spiReadWrite(reg);

    /* write the data out */
    spiReadWrite(dat);
    spiCS(0);

#if REG_DEBUG
sprintf(msg_buff, "reg = 0x%04X\r\n", reg);
serPutString(SER_CONSOLE, msg_buff);
#endif

    return;
}

void spiSlaveCmd(unsigned int cmd, unsigned int arg)
{
    unsigned int reg;

    if ( (cmd == INFO_CMD) || (cmd == READ_CMD)  || (cmd == WRITE_CMD) )
        return;
   
    /* create request */
    reg = (cmd << 10);
    reg += (arg & ARG_MASK);

    spiCS(1);
    /* send the command */
    spiReadWrite(reg);
    
    spiCS(0);

#if REG_DEBUG
sprintf(msg_buff, "reg = 0x%04X\r\n", reg);
serPutString(SER_CONSOLE, msg_buff);
#endif

    return;
}
