/* ---------------------------------------------------------------------------
 * ssp1.c - v1.0                                         (c) 2006 Micro-key bv
 * ---------------------------------------------------------------------------
 * Micro-key bv
 * Industrieweg 28, 9804 TG Noordhorn
 * Postbus 92, 9800 AA Zuidhorn
 * The Netherlands
 * Tel: +31 594 503020
 * Fax: +31 594 505825
 * Email: support@microkey.nl
 * Web: www.microkey.nl
 * ---------------------------------------------------------------------------
 * Description: ssp1 driver.
 * ---------------------------------------------------------------------------
 * Version(s):  1.0, 27-10-2006, Jos Pasop.
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * System include files.
 * ---------------------------------------------------------------------------
 */
#include "types.h"
#include "lpc23xx.h"
#include "irq.h"
#include "ssp1.h"
#include "ssp1ISR.h"

/* FreeRTOS includes */
#include "FreeRTOS.h"
#include "Task.h"
#include "queue.h"
#include "semphr.h"

/* ---------------------------------------------------------------------------
 * Application include files.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Local constant and macro definitions.
 * ---------------------------------------------------------------------------
 */

#define SSP1_DISPATCH_QUEUE_SIZE    150

#define SSP_CR0         SSP1CR0
#define SSP_CR1         SSP1CR1
#define SSP_CPSR        SSP1CPSR
#define SSP_SR          SSP1SR
#define SSP_DR          SSP1DR
#define SSP_IMSC        SSP1IMSC


/* Functions.                                                               */
#define SPI_RXIM_ENABLE  SSP1IMSC |= SSPIMSC_RXIM
#define SPI_RXIM_DISABLE SSP1IMSC &= ~SSPIMSC_RXIM
#define SPI_TXIM_ENABLE  SSP1IMSC |= SSPIMSC_TXIM
#define SPI_TXIM_DISABLE SSP1IMSC &= ~SSPIMSC_TXIM



/* ---------------------------------------------------------------------------
 * Global variable definitions.
 * ---------------------------------------------------------------------------
 */
xQueueHandle ssp1DispatchedIsrQueue;
xSemaphoreHandle ssp1BusMutex;

/* ---------------------------------------------------------------------------
 * Local variable definitions.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Local function declarations.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * ssp1Init -- SPI1 controller init.
 *
 * This function initialises the SPI1 controller.
 * SPI1 is configured as master for the A/D converters (ADS8344).
 * The SPI clock is used to clock the conversion.
 * Each conversion takes 24 clk pulses. For a 50kHz throughput the SPI clock
 * should be set at 24 * 50kHz = 1,2 MHz. 
 * 
 * Global variables: --
 * ---------------------------------------------------------------------------
 */
void
ssp1Init
    (
    void
    )
{
    // Create queue and task for ISR-dispatching
    ssp1DispatchedIsrQueue = xQueueCreate( SSP1_DISPATCH_QUEUE_SIZE, sizeof(UINT8));
    ssp1BusMutex = xSemaphoreCreateMutex();


    /* enable clock to SSP1 for security reason. By default, it's enabled already */
    PCONP |= (1 << 10);

    /* Configure PIN connect block */
    /* port 1 bits 7, 8, 9, 6 are SSP port SCK1, MISO1, MOSI1 */
    /* set SSEL to GPIO pin that you will have the totoal freedom to set/reset
    the SPI chip-select pin */
    PINSEL0 &= ~0x000FC000;   // Clear de pin selection for SSP1
    PINSEL0 |= 0x000A8000;
    
    
    /* Control register 0.
     * DSS = 16 bit tranfer
     * FRF = SPI
     * CPOL = 0
     * CPHA = 0 
     * SCR = 0
     */
    SSP_CR0 = SSPCR0_DSS_8 | SSPCR0_SPO_L | SSPCR0_SPH_N;

    /* Control register 1.
     * LBM  = 0
     * SSE = 0
     * MS = 0 (master)
     * SOD = 0
     */ 
    SSP_CR1 = 0x0;

    /* SSP Clock Prescale register.                                         */
    SSP_CPSR = 4;                        /*  12 MHz / 4    EEPROM max 5 MHz */

    // Enable SSP1 interrupt
    install_irq( VIC_CHAN_NUM_SSP1, (void *)ssp1ISR, HIGHEST_PRIORITY );
    
    SSP_IMSC = (SSPIMSC_RORIM) | (SSPIMSC_RTIM) | (SSPIMSC_RXIM);
    
    
}

/* ---------------------------------------------------------------------------
 * ssp1Enable -- SPI1 enable.
 *
 * This function enables the SSP controller
 * 
 * Global variables: --
 * ---------------------------------------------------------------------------
 */
void
ssp1Enable
    (
    void
    )
{
    SSP_CR1 |= SSPCR1_SSE;
}

/* ---------------------------------------------------------------------------
 * ssp1Disable -- SPI1 disable.
 *
 * This function disables the SSP controller
 * 
 * Global variables: --
 * ---------------------------------------------------------------------------
 */
void
ssp1Disable
    (
    void
    )
{
    SSP_CR1 &= ~SSPCR1_SSE;
}


void ssp1TakeBus(void)
{
    xSemaphoreTake( ssp1BusMutex, portMAX_DELAY );
}


void ssp1ReleaseBus(void)
{
    xSemaphoreGive( ssp1BusMutex );
}


/* ---------------------------------------------------------------------------
 * ssp1Write -- SPI1 write bit.
 *
 * This function sends bit data through the SPI bus.
 * If the SPI bus is disabled ERROR is returned. Otherwise OK.
 * 
 * Global variables: --
 * ---------------------------------------------------------------------------
 */
RESULT
ssp1Write
    (
    UINT8 data
    )
{
    if ((SSP_CR1 & SSPCR1_SSE) == 0)
        {
        return ERROR;              /* SPI controller is disabled      */
        }

    
    while ((SSP_SR & SSPSR_TNF) == 0);  /* wait if transmit FIFO is full   */

    SSP_DR = data;                       /* write data                      */

    return OK;
}

//BOOLEAN
//ssp1TransmitBufferFull
//(
//)


/* ---------------------------------------------------------------------------
 * ssp1Read -- SPI1 read.
 *
 * This function reads 16 bit data from the SPI bus.
 * If no data is available ERROR is returned. Otherwise OK.
 * 
 * Global variables: --
 * ---------------------------------------------------------------------------
 */
RESULT
ssp1Read
    (
    UINT8 * pData
    )
{
    UINT16 dispatchItem;
    
    if (xQueueReceive(ssp1DispatchedIsrQueue, &dispatchItem, 200))
        {
        *pData = (UINT8)dispatchItem;
        return OK;
        }
    else
    	{
    	return ERROR;
    	}
}

void ssp1WriteBuffer( UINT8 *buffer, UINT16 length )
{
    UINT16 i;
    for ( i = 0; i < length; i++ )
        {
        /* as long as TNF bit is set (TxFIFO is not full), I can always transmit */
        while ( !(SSP_SR & SSPSR_TNF) );
    
        SSP_DR = *buffer;
        buffer++;
        /* Wait until the Busy bit is cleared `(Busy if 1)*/
        while ( (SSP_SR & SSPSR_BSY) );
        }
    return;
}

void ssp1ReadBuffer( UINT8 *buffer, UINT16 length )
{
    UINT16 i;
    UINT8 dispatchItem;

    for ( i = 0; i < length; i++ )
        {
        if (xQueueReceive(ssp1DispatchedIsrQueue, &dispatchItem, 200))
            {
            *buffer = dispatchItem;
            buffer++;
            }
        }
    
    return;
}

void ssp1Loopback( BOOLEAN enable )
{
    if (enable == TRUE)
        {
        SSP_CR1 |= SSPCR1_LBM;
        }
    else
        {
        SSP_CR1 &= ~SSPCR1_LBM;
        }
}


