/* ---------------------------------------------------------------------------
 * bus.c - v0.1                                       (c) 2007 Micro-key bv
 * ---------------------------------------------------------------------------
 * Micro-key bv
 * Industrieweg 28, 9804 TG Noordhorn
 * Postbus 92, 9800 AB Zuidhorn
 * The Netherlands
 * Tel: +31 594 503020
 * Fax: +31 594 505825
 * Email: support@microkey.nl  
 * Web: www.microkey.nl
 * ---------------------------------------------------------------------------
 * Description: RS-485 bus driver
 * ---------------------------------------------------------------------------
 * Version(s):  0.1, 28-11-2007, fvds.
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * System include files
 * ---------------------------------------------------------------------------
 */
#include <stdio.h>
#include <stdlib.h>


/* ---------------------------------------------------------------------------
 * Application include files
 * ---------------------------------------------------------------------------
 */
#include "LPC23xx.h"
#include "types.h"
#include "bus.h"
#include "armVIC.h"
#include "uart2.h"
#include "uart3.h"


/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */
#define NR_OF_BUSPORTS        2

// \MARK NEW PINSETTINGS FOR TESTER (2)
// \TODO WATCH OUT PATCHES FOR UART2
#if (PINSET_TESTER == 2)
#define UB2_DE_PINSEL_REG    PINSEL2
#define UB2_DE_PINSEL        (0UL<<4)  /* PINSEL8 Value for GPIO (P2.2)     */
#define UB2_DE_PINMASK       (3UL<<4)  /* PINSEL8 Mask  for GPIO (P2.2)     */
#define UB2_RE_PINSEL_REG    PINSEL2
#define UB2_RE_PINSEL        (0UL<<6)  /* PINSEL8 Value for GPIO (P2.3)     */
#define UB2_RE_PINMASK       (3UL<<6)  /* PINSEL8 Mask  for GPIO (P2.3)     */
#define UB3_DE_PINSEL_REG    PINSEL2
#define UB3_DE_PINSEL        (0UL<<10) /* PINSEL8 Value for GPIO (P2.5)     */
#define UB3_DE_PINMASK       (3UL<<10) /* PINSEL8 Mask  for GPIO (P2.5)     */
#define UB3_RE_PINSEL_REG    PINSEL2
#define UB3_RE_PINSEL        (0UL<<12) /* PINSEL8 Value for GPIO (P2.6)     */
#define UB3_RE_PINMASK       (3UL<<12) /* PINSEL8 Mask  for GPIO (P2.6)     */
#else
#define UB2_DE_PINSEL_REG    PINSEL3
#define UB2_DE_PINSEL        (0UL<<0)  /* PINSEL3 Value for GPIO */
#define UB2_DE_PINMASK       (3UL<<0)  /* PINSEL3 Mask  for GPIO */
#define UB2_RE_PINSEL_REG    PINSEL3
#define UB2_RE_PINSEL        (0UL<<2)  /* PINSEL3 Value for GPIO */
#define UB2_RE_PINMASK       (3UL<<2)  /* PINSEL3 Mask  for GPIO */
#define UB3_DE_PINSEL_REG    PINSEL3
#define UB3_DE_PINSEL        (0UL<<4)  /* PINSEL3 Value for GPIO */
#define UB3_DE_PINMASK       (3UL<<4)  /* PINSEL3 Mask  for GPIO */
#define UB3_RE_PINSEL_REG    PINSEL3
#define UB3_RE_PINSEL        (0UL<<6)  /* PINSEL3 Value for GPIO */
#define UB3_RE_PINMASK       (3UL<<6)  /* PINSEL3 Mask  for GPIO */
#endif

// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define UB2_REN_DE_DIR_REG    FIO2DIR
#define UB2_REN_DE_SET_REG    FIO2SET
#define UB2_REN_DE_CLR_REG    FIO2CLR
#else
#define UB2_REN_DE_DIR_REG    FIO1DIR
#define UB2_REN_DE_SET_REG    FIO1SET
#define UB2_REN_DE_CLR_REG    FIO1CLR
#endif
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define UB2_REN_BIT           BIT(3)
#define UB2_DE_BIT            BIT(2)
#else
#define UB2_REN_BIT           BIT(17)
#define UB2_DE_BIT            BIT(16)
#endif
#define UB2_REN_DE_BITS       (UB2_REN_BIT | UB2_DE_BIT)
#define UB2_TX_MODE           (UB2_REN_DE_SET_REG = UB2_REN_DE_BITS)
#define UB2_RX_MODE           (UB2_REN_DE_CLR_REG = UB2_REN_DE_BITS)
#define UB2_LOOPBACK_MODE 
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define UB3_REN_DE_DIR_REG    FIO2DIR
#define UB3_REN_DE_SET_REG    FIO2SET
#define UB3_REN_DE_CLR_REG    FIO2CLR
#else
#define UB3_REN_DE_DIR_REG    FIO1DIR
#define UB3_REN_DE_SET_REG    FIO1SET
#define UB3_REN_DE_CLR_REG    FIO1CLR
#endif
// \MARK NEW PINSETTINGS FOR TESTER (2)
#if (PINSET_TESTER == 2)
#define UB3_REN_BIT           BIT(6)
#define UB3_DE_BIT            BIT(5)
#else
#define UB3_REN_BIT           BIT(19)
#define UB3_DE_BIT            BIT(18)
#endif
#define UB3_REN_DE_BITS       (UB3_REN_BIT | UB3_DE_BIT)
#define UB3_TX_MODE           (UB3_REN_DE_SET_REG = UB3_REN_DE_BITS)
#define UB3_RX_MODE           (UB3_REN_DE_CLR_REG = UB3_REN_DE_BITS)
#define UB3_LOOPBACK_MODE     


/* ---------------------------------------------------------------------------
 * Global variable definitions
 * ---------------------------------------------------------------------------
 */

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

/* ---------------------------------------------------------------------------
 * Local function definitions
 * ---------------------------------------------------------------------------
 */

void onUart2TxFinished();
void onUart3TxFinished();


/** \brief Initialize of serial interface.*/  
void   busInit (
        t_bus_devices device
)
{
    SCS |= (1UL<<0); // set GPIOM in SCS for fast IO    
    
    switch( device )
    {
    case(BUS1):
        // set EN/DE pins for BUS0
        UB2_DE_PINSEL_REG = ( UB2_DE_PINSEL_REG & ~UB2_DE_PINMASK ) | UB2_DE_PINSEL;
        UB2_RE_PINSEL_REG = ( UB2_RE_PINSEL_REG & ~UB2_RE_PINMASK ) | UB2_RE_PINSEL;

        // set EN/DE pin as output and in Receive mode
        UB2_REN_DE_DIR_REG |= UB2_REN_DE_BITS;
        UB2_RX_MODE;
        uart2Init( B38400, UART_8N1, UART_FIFO_8 );     // \TODO BAUDRATE
        uart2SubscribeTxFinished( onUart2TxFinished );
        
        break;
    case(BUS2):
        // set EN/DE pins for BUS1
        UB3_DE_PINSEL_REG = ( UB3_DE_PINSEL_REG & ~UB3_DE_PINMASK ) | UB3_DE_PINSEL;
        UB3_RE_PINSEL_REG = ( UB3_RE_PINSEL_REG & ~UB3_RE_PINMASK ) | UB3_RE_PINSEL;

        // set EN/DE pin as output and in Receive mode
        UB3_REN_DE_DIR_REG |= UB3_REN_DE_BITS;
        UB3_RX_MODE;

        uart3Init( B38400, UART_8N1, UART_FIFO_8 );     // \TODO BAUDRATE
        uart3SubscribeTxFinished( onUart3TxFinished );
      
        break;
    }
    
}

/** \brief Write data of a certain length to a serial port.*/  
void busWrite (
        t_bus_devices device, 
        UINT16 length, /**< Lengh of data in bytes */ 
        UINT8 *data   /**< Pointer to data */
)
{
    switch( device )
    {
    case(BUS1):
        UB2_TX_MODE;
        uart2Write( (char *)data, length);
        break;
        
    case(BUS2):
        UB3_TX_MODE;
        uart3Write( (char *)data, length);
        break;
    }
}

/** \brief Reads data from serial port.
    \retval Length of received data in bytes*/  
UINT16 busRead (
        t_bus_devices device, 
        UINT8 * data /**< Pointer to data */
)
{
    UINT16 bytesReceived = 0;
    BOOLEAN receivedSomething;
    do
        {
        receivedSomething = busGet( device, &(data[bytesReceived]));
        if (receivedSomething)
            bytesReceived++;
        } while(receivedSomething);
    
    return bytesReceived;
}

/** \brief Get byte from serial port.
    \retval bool Returns true if there was data */
BOOLEAN busGet(
        t_bus_devices device,
        UINT8 * byte /**< Pointer to byte to return data*/
)
{
    int receivedChar = -1;
    
    switch( device )
        {
        case(BUS1):
            receivedChar = uart2Getch();
            break;
        case(BUS2):
            receivedChar = uart3Getch();
            break;
        }
    
    if (receivedChar >= 0)
        {
        *byte = (UINT8)receivedChar;
        return TRUE;
        }
    else
        {
        return FALSE;
        }
}

/** \brief Send byte to serial port. */
void busPut(
        t_bus_devices device, 
        UINT8 value /**< Byte to send*/
)
{
    switch( device )
        {
        case(BUS1):
            UB2_TX_MODE;
            uart2Putch( value );
            break;
        case(BUS2):
            UB3_TX_MODE;
            uart3Putch( value );
            break;
        }

}

/** \brief Flush serial port buffers. */
void   busFlush(
        t_bus_devices device
)
{
    switch( device )
        {
        case(BUS1):
            uart2TxFlush( );
            break;
        case(BUS2):
            uart3TxFlush( );
            break;
        }
    
}

/** \brief Check if receive buffers is empty.
    \retval bool Returns true if recieve buffer is empty */
BOOLEAN busEmpty(
        t_bus_devices device
)
{
    switch( device )
        {
        case(BUS1):
            return (uart2RxEmpty( ) != 0);
            break;
        case(BUS2):
            return (uart3RxEmpty( ) != 0);
            break;
        }

    return FALSE;
}


void onUart2TxFinished()
{
    // After all characters are send, put back in Receiver mode
    UB2_RX_MODE;
}

void onUart3TxFinished()
{
    // After all characters are send, put back in Receiver mode
    UB3_RX_MODE;
}

