/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    GKI_io.c
* Description:  I/O abstraction layer
*
* Copyright (c) 2013 Amped'RF Inc., AR Technology  All rights reserved.
*******************************************************************************/
#include "SDK_Common.h"
#include "GKI_lib.h"

//------------------------------------------------------------------------------
//     I/O ID Values
//------------------------------------------------------------------------------
/*
u16 io_HCI_TX           =   IO_HCI_TX;
u16 io_HCI_RX	        =   IO_HCI_RX;
#if !defined(BT24)
u16 io_HCI_CTS          =   IO_HCI_CTS;
#endif
u16 io_HCI_RTS          =   IO_HCI_RTS;
//------------------------------------------------
u16 io_MAIN_TX	        =   IO_MAIN_TX;
u16 io_MAIN_RX	        =   IO_MAIN_RX;
u16 io_MAIN_CTS         =   IO_MAIN_CTS;
u16 io_MAIN_RTS         =   IO_MAIN_RTS;
//------------------------------------------------
u16 io_HCI_BT_PWR_ON    =   IO_HCI_BT_PWR_ON;
u16 io_PA_BIAS          =   IO_PA_BIAS;
u16 io_LPOCLK_EN        =   IO_LPOCLK_EN;
#ifdef TI2564
u16 io_HCI_BT_WAKE      =   IO_HCI_BT_NSHUTDO;
#else
u16 io_HCI_BT_RESET     =   IO_HCI_BT_RESET;
u16 io_HCI_BT_WAKE      =   IO_HCI_BT_WAKE;
#endif
#ifndef TI2564
u16 io_HCI_HOST_WAKE    =   IO_HCI_HOST_WAKE;
#endif
u16 io_HCI_BT_CLK       =   IO_HCI_BT_CLK;
u16 io_HCI_LPCLK        =   IO_HCI_LPCLK;
u16 io_BT_POWERUP       =   IO_BT_POWERUP;
//------------------------------------------------
u16 io_I2C_SCL          =   IO_I2C_SCL;
u16 io_I2C_SDA          =   IO_I2C_SDA;
u16 io_SCL              =   IO_I2C_SCL;
u16 io_SDA              =   IO_I2C_SDA;
//------------------------------------------------
u16 io_HOST_WAKEUP      =   IO_UNDEFINED;//IO_HCI_HOST_WAKE;
//------------------------------------------------
u16 io_JTDO_SWO         =   IO_JTDO_SWO;
u16 io_JTRST            =   IO_JTRST;
u16 io_JTMS_SWDIO       =   IO_JTMS_SWDIO;
u16 io_JTCK_SWCLK       =   IO_JTCK_SWCLK;
u16 io_JTDI             =   IO_JTDI;
//------------------------------------------------
*/


void * _Port[3] = {
    ((void *) GPIOA_BASE),
    ((void *) GPIOB_BASE),
    ((void *) GPIOC_BASE)
};



#include <stdio.h>
void SerialPutString(char *);
void SerialPutChar(char ch);



//------------------------------------------------
//------------------------------------------------
static GPIOMode_TypeDef GetIoMode(u16 x)
{
#if defined(STM32F2xx) || defined(STM32F4xx)
    switch (x & GKI_IO_MODE_MASK) {
    case GKI_IO_IN_FLOATING:    return GPIO_Mode_IN;
    case GKI_IO_OUT_PP:         return GPIO_Mode_OUT;
    case GKI_IO_IPD:            return GPIO_Mode_IN;
    case GKI_IO_IPU:            return GPIO_Mode_IN;
    case GKI_IO_AF_PP:          return GPIO_Mode_AF;
    case GKI_IO_AIN:            return GPIO_Mode_IN;
    case GKI_IO_AF_IN:          return GPIO_Mode_AF;
    case GKI_IO_OUT_OD:         return GPIO_Mode_OUT;
    default:                    return GPIO_Mode_IN;
    }
#elif defined(STM32F10x)
    switch (x & GKI_IO_MODE_MASK) {
    case GKI_IO_IN_FLOATING:    return GPIO_Mode_IN_FLOATING;
    case GKI_IO_OUT_PP:         return GPIO_Mode_Out_PP;
    case GKI_IO_IPD:            return GPIO_Mode_IPD;
    case GKI_IO_IPU:            return GPIO_Mode_IPU;
    case GKI_IO_AF_PP:          return GPIO_Mode_AF_PP;
    case GKI_IO_OUT_OD:         return GPIO_Mode_Out_OD;
    case GKI_IO_AIN:            return GPIO_Mode_AIN;
    case GKI_IO_AF_IN:          return GPIO_PuPd_UP;
    default:                    return GPIO_Mode_IN_FLOATING;
    }
#endif
}



//------------------------------------------------
//------------------------------------------------
#if defined(STM32F2xx) || defined(STM32F4xx)
static GPIOPuPd_TypeDef GetIoUpDn(u16 x)
{
    switch (x & GKI_IO_MODE_MASK) {
    case GKI_IO_IPD:            return GPIO_PuPd_DOWN;
    case GKI_IO_IPU:            return GPIO_PuPd_UP;
    default:                    return GPIO_PuPd_NOPULL;
    }
}
#endif

//------------------------------------------------
//------------------------------------------------
#if defined(STM32F2xx) || defined(STM32F4xx)
GPIOOType_TypeDef GetIoOType(u16 x)
{
    switch (x & GKI_IO_MODE_MASK) {
    case GKI_IO_OUT_OD:     return GPIO_OType_OD;
    default:                return GPIO_OType_PP;
    }
}
#endif

//------------------------------------------------
//------------------------------------------------
static GPIOSpeed_TypeDef GetIoSpeed(u16 x)
{
#if defined(STM32F2xx) || defined(STM32F4xx)
    switch (x & GKI_IO_Speed_MASK) {
    case GKI_IO_Speed_2MHz:     return GPIO_Speed_2MHz;
    case GKI_IO_Speed_10MHz:    return GPIO_Speed_25MHz;
    case GKI_IO_Speed_25MHz:    return GPIO_Speed_25MHz;
    case GKI_IO_Speed_50MHz:    return GPIO_Speed_50MHz;
    case GKI_IO_Speed_100MHz:   return GPIO_Speed_100MHz;
    default:                    return GPIO_Speed_25MHz;
    }
#elif defined(STM32F10x)
    switch (x & GKI_IO_Speed_MASK) {
    case GKI_IO_Speed_2MHz:     return GPIO_Speed_2MHz;
    case GKI_IO_Speed_10MHz:    return GPIO_Speed_10MHz;
    case GKI_IO_Speed_25MHz:    return GPIO_Speed_10MHz;
    case GKI_IO_Speed_50MHz:    return GPIO_Speed_50MHz;
    case GKI_IO_Speed_100MHz:   return GPIO_Speed_50MHz;
    default:                    return GPIO_Speed_10MHz;
    }
#endif
}



//------------------------------------------------
// Configure GPIO -- replaces GPIO_Config()
//------------------------------------------------
void  GKI_io_Config(u16 io, u16 x)
{
    if (io!=IO_UNDEFINED) {
#if defined(STM32F10x)
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_StructInit(&GPIO_InitStruct);
        GPIO_InitStruct.GPIO_Pin   = _MASK(io);
        GPIO_InitStruct.GPIO_Speed = GetIoSpeed(x);
        GPIO_InitStruct.GPIO_Mode  = GetIoMode(x);
        GPIO_Init(_BASE(io), &GPIO_InitStruct);
#elif defined(STM32F2xx) || defined(STM32F4xx)
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_StructInit(&GPIO_InitStruct);
        GPIO_InitStruct.GPIO_Pin   = _MASK(io);
        GPIO_InitStruct.GPIO_Speed = GetIoSpeed(x);
        GPIO_InitStruct.GPIO_Mode  = GetIoMode(x);
        GPIO_InitStruct.GPIO_PuPd  = GetIoUpDn(x);
        GPIO_InitStruct.GPIO_OType = GetIoOType(x);
        GPIO_Init(_BASE(io), &GPIO_InitStruct);
        if (io == PB0) {
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, DISABLE);
        }
#endif
    }
}



void GKI_io_Enable_Tristate_All(void)
{
#if defined(GPS)
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_Init(GPIOC, &GPIO_InitStructure);
#else
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin ^= 0xE000;  // Don't touch JTAG IOs
    GPIO_Init(GPIOA, &GPIO_InitStructure);
#endif
}



//------------------------------------------------
// Write GPIO bit -- replaces GPIO_BitWrite()
//------------------------------------------------
void  GKI_io_WriteBit(u16 io, u8 val)
{
    if (io!=IO_UNDEFINED) {
        GPIO_WriteBit(_BASE(io), _MASK(io), val);
    }
}


//------------------------------------------------
// Read GPIO bit -- replaces GPIO_BitRead()
//------------------------------------------------
bool  GKI_io_ReadBit(u16 io)
{
    if (io==IO_UNDEFINED) {
        return 0;
    }

    return GPIO_ReadInputDataBit(_BASE(io), _MASK(io));
}



//------------------------------------------------
// GKI_io_Tristate_All - was GPIO_Tristate_All
//------------------------------------------------
void  GKI_io_Tristate_All(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}



//------------------------------------------------
// Return text of io
//------------------------------------------------
char * GKI_io_Text(u16 io)
{
    static char ioText[8];
    u16 ioPort = (io>>4) & 0x0f;
    u16 ioPin  = io & 0xf;

    if (io == IO_UNDEFINED)
        return "Undefined";
    else if (ioPort>=3 || ioPin>=16)
        return "Invalid";
    else {
        ioText[0] = 'P';
        ioText[1] = 'A' + ioPort;
        sprintf(&ioText[2], "%d", ioPin);
        return ioText;
    }
}


//------------------------------------------------
// Return text of io mode
//------------------------------------------------
char * GKI_io_ModeText(u16 io)
{
    static char *ConfigGPOutText[8]={
        "Out PP",
        "Out PP PU",
        "Out PP PD",
        "Reserved",
        "Out OD",
        "Out OD PU",
        "Out OD PD",
        "Reserved"};
    static char *ConfigAFText[8]={
        "AF PP",
        "AF PP PU",
        "AF PP PD",
        "Reserved",
        "AF OD",
        "AF OD PU",
        "AF OD PD",
        "Reserved"};
    static char *ConfigInpText[4]={
        "Inp Float",
        "Inp PU",
        "Inp PD",
        "Reserved"};
    static char *ConfigAnalogText[4]={
        "Analog",
        "Reserved",
        "Reserved",
        "Reserved"};
    GPIO_TypeDef * GPIOx;
    u16 sft1b, sft2b;
    u32 mode, otype, pupd;
    u16 ix;

    if (io==IO_UNDEFINED)
        return "";

    GPIOx = _Port[ io>>4 ];
    sft1b = io & 0x0F;
    sft2b = sft1b << 1;

    mode  = (GPIOx->MODER >> sft2b) & 3;
    otype = (GPIOx->OTYPER >> sft1b) & 1;
    pupd  = (GPIOx->PUPDR >> sft2b) & 3;

    switch (mode) {
    case 1:
        ix = otype<<2 + pupd;
        return ConfigGPOutText[ix];
    case 2:
        ix = otype<<2 + pupd;
        return ConfigAFText[ix];
    case 0:
        return ConfigInpText[pupd];
    case 3:
    default:
        return ConfigAnalogText[pupd];
    }
}


//------------------------------------------------
// Return text of io mode
//------------------------------------------------
char * GKI_io_ValueText(u16 io)
{
    GPIO_TypeDef * GPIOx;
    u16 sft1b, sft2b;
    u32 mode, dr;

    if (io==IO_UNDEFINED)
        return "";

    GPIOx = _Port[ io>>4 ];
    sft1b = io & 0x0F;
    sft2b = sft1b << 1;

    mode  = (GPIOx->MODER >> sft2b) & 3;
    if (mode==0)
        dr = (GPIOx->IDR >> sft1b) & 1;
    else
        dr = (GPIOx->ODR >> sft1b) & 1;

    return dr ? "1" : "0";
}




//------------------------------------------------
// Return true if input
//------------------------------------------------
bool GKI_io_IsInput(u16 io)
{
    GPIO_TypeDef *GPIOx;
    u16 sft1b, sft2b;
    u32 mode;

    if (io != IO_UNDEFINED) {
        GPIOx = _Port[ io>>4 ];
        sft1b = io & 0x0F;
        sft2b = sft1b << 1;
        mode  = (GPIOx->MODER >> sft2b) & 3;

        return (mode==0);
    }
    return false;
}

