/*
 *  UART Driver
 */

#include "mcu.h"
#include "Uart.h"
#include "Uart_FM3.h"
#include "Mfs_FM3.h"
#include <stdlib.h>
#include "clock_def.h"
#include "core_cm3.h"


/*
 *  Buffer Information Struct
 */
typedef struct {
    uint32_t  WIdx; /* Write Index (to Buffer)         */
    uint32_t  RIdx; /* Read  Index (from Buffer)       */
    uint32_t  Mask;          /* Buffer Mask Size ( BufSize - 1) */
    uint8_t   *pBuf;         /* Buffer                          */
} Uart_BUF;

/*
 * UART Device Configuration Structure
 */
typedef struct {
    int32_t BaudRate;     /* Baudrate    */
    int32_t DataBits:5;   /* Data bits   */
    int32_t StopBits:3;   /* Stop bits   */
    int32_t Parity:3;     /* Parity      */
    int32_t BitOrder:2;   /* BitOrder    */
    int32_t Reserved:19;
    int32_t BufSize;      /* Buffer Size */
} UartDev_CFG;

/*
 *  Driver Information Control Struct
 */
typedef struct {
    int32_t      State;     /* State            */
    int32_t      RxSuspend; /* Rx Suspend Flag  */
    int32_t      Fifo;      /* FIFO Depth       */
#ifdef USE_CH03
    FM3_MFS03_UART_TypeDef *pReg;   /* Register Struct  */
#else
    FM3_MFS47_UART_TypeDef *pReg;   /* Register Struct  */
#endif
    UartDev_CFG   Cfg;    /* UART Device Configuration Structure */
    Uart_BUF     RxBuf;   /* RX Buffer Struct */
    Uart_BUF     TxBuf;   /* TX Buffer Struct */
    IRQn_Type    RxIRQn;    /* RX IRQ Number    */
    IRQn_Type    TxIRQn;    /* TX IRQ Number    */
} Uart_INFO ;

static Uart_INFO UartInfo = {0};


/*
 *  Internal Function
 */
static int32_t  uart_Init_Internal(void);
static void  uart_UnInit_Internal(void);
static void  uart_StartRx(void);
static void  uart_DataRx(void);
static void  uart_StopRx(void);
static void  uart_StartTx(void);
static void  uart_DataTx(void);
static void  uart_StopTx(void);


/*
 *  Internal Function for Buffer Handling
 */
static uint32_t  atomic_inc(uint32_t *pVar);

#define UART_BUF_RESET(buf)         ((buf).RIdx = (buf).WIdx = 0)
#define UART_BUF_WRITE(buf, data)   ((buf).pBuf[(buf).Mask & atomic_inc(&((buf).WIdx))] = (data))
#define UART_BUF_READ(buf)          ((buf).pBuf[(buf).Mask & atomic_inc(&((buf).RIdx))])
#define UART_BUF_EMPTY(buf)         (((buf).Mask & (buf).RIdx) == ((buf).Mask & (buf).WIdx))
#define UART_BUF_FULL(buf)          (((buf).Mask & (buf).RIdx) == ((buf).Mask & ((buf).WIdx + 1)))
#define UART_BUF_COUNT(buf)         ((buf).Mask & ((buf).WIdx - (buf).RIdx))

static uint32_t  atomic_inc(uint32_t *pVar)
{
    uint32_t var;
    int32_t  exc;
    
    do {
        var = __LDREXW(pVar);
        exc = __STREXW((var+1), pVar);
    } while (exc != 0);
    
    return *pVar;
}


/*
 *  Uart_Init
 */
int32_t  Uart_Init(void)
{
    int32_t ret;
    
    UartInfo.State = UART_UNINITIALIZED;
    UartInfo.RxSuspend = 0;
#ifndef USE_CH03
    UartInfo.Fifo = 0;
#else
    UartInfo.Fifo = UART_FIFO_DEPTH;
#endif
    UartInfo.pReg = UART_REG_ADR;
    UartInfo.Cfg.BaudRate = UART_BAUDRATE;
    UartInfo.Cfg.DataBits = UART_DATABITS;
    UartInfo.Cfg.StopBits = UART_STOPBITS;
    UartInfo.Cfg.Parity = UART_PARITY;
    UartInfo.Cfg.BitOrder = UART_BITODER;
    UartInfo.Cfg.Reserved = 0;
    UartInfo.Cfg.BufSize = UART_BUFSIZE;
    UartInfo.RxBuf.WIdx = 0;
    UartInfo.RxBuf.RIdx = 0;
    UartInfo.RxBuf.Mask = UART_BUFSIZE-1;
    UartInfo.RxBuf.pBuf = 0;
    UartInfo.TxBuf.WIdx = 0;
    UartInfo.TxBuf.RIdx = 0;
    UartInfo.TxBuf.Mask = UART_BUFSIZE-1;
    UartInfo.TxBuf.pBuf = 0;
    UartInfo.RxIRQn = UART_RX_IRQ;
    UartInfo.TxIRQn = UART_TX_IRQ;
    
    /* initialize hardware */
    ret = uart_Init_Internal();
    
    if (ret == SUCCESS) {
        /* enable NVIC */
        NVIC_EnableIRQ(UartInfo.RxIRQn);
        NVIC_EnableIRQ(UartInfo.TxIRQn);
        
        /* change state */
        UartInfo.State = UART_INITIALIZED;
        
        uart_StartRx();
        
        ret = SUCCESS;
    } else {
        ret = ERROR; /* uart_Init error */
    }
    
    return ret;
}


/*
 *  Uart_UnInit
 */
int32_t  Uart_UnInit(void)
{
    int32_t ret;
    
    
    if (UartInfo.State != UART_INITIALIZED) {
        ret = ERROR; /* not initialized */
        
    } else {
        uart_StopRx();
        
        /* change state */
        UartInfo.State = UART_UNINITIALIZED;
        
        /* disable NVIC */
        NVIC_DisableIRQ(UartInfo.RxIRQn);
        NVIC_DisableIRQ(UartInfo.TxIRQn);
        
        /* uninitialize */
        uart_UnInit_Internal();
        
        ret = SUCCESS;
    }
        
    
    return ret;
}


/*
 *  Uart_BufTx
 */
int32_t  Uart_BufTx(void *pData, int32_t *pSize)
{
    int32_t ret;
    int32_t count;
    uint8_t *p_char;
    
    /* check NULL pointer */
    if ((pData == NULL) || (pSize == NULL)) {
        return ERROR;
    }
    
    /* check parameter */
    if (*pSize <= 0) {
        return ERROR;
    }
    
    
    if (UartInfo.State != UART_INITIALIZED) {
        ret = ERROR; /* not initialized */
        
    } else {
        count  = 0;
        p_char = (uint8_t *)pData;
        
        while (!UART_BUF_FULL(UartInfo.TxBuf)) { /* false */
            /* Tx buffer is not full */
            
            if (count < *pSize) {
                UART_BUF_WRITE(UartInfo.TxBuf, p_char[count]);
                count += 1;
            } else {
                /* Writing in tx buffer was completed. */
                break;
            }
        }
        
        /* Tx buffer was full or writing in tx buffer was completed. */
        
        /* return size */
        *pSize = count;
        
        /* start tx : interruption occur */
        uart_StartTx();
        
        ret = SUCCESS;
    }
    
    return ret;
}


/*
 *  Uart_BufRx
 */
int32_t  Uart_BufRx(void *pData, int32_t *pSize)
{
    int32_t ret;
    int32_t count;
    uint8_t *p_char;
    
    /* check NULL pointer */
    if ((pData == NULL) || (pSize == NULL)) {
        return ERROR;
    }
    
    /* check parameter */
    if (*pSize <= 0) {
        return ERROR;
    }
    
    
    if (UartInfo.State != UART_INITIALIZED) {
        ret = ERROR; /* not initialized */
        
    } else {
        count  = 0;
        p_char = (uint8_t *)pData;
        
        while (!UART_BUF_EMPTY(UartInfo.RxBuf)) { /* false */
            /* Rx buffer is not empty. */
            
            if (count < *pSize) {
                p_char[count] = UART_BUF_READ(UartInfo.RxBuf);
                count += 1;
            } else {
                /* Reading from rx buffer was completed. */
                break;
            }
        }
        
        /* Rx buffer was empty or reading from rx buffer was completed. */
        
        /* return size */
        *pSize = count;
        
        /* check suspend */
        if (UartInfo.RxSuspend == 1) {
            /* Resume rx */
            UartInfo.RxSuspend = 0;
            uart_StartRx();
        }
        
        ret = SUCCESS;
    }
    
    return ret;
}


/*
 *  Uart_BufFlush
 */
int32_t  Uart_BufFlush(void)
{
    int32_t ret;
    
    
    if (UartInfo.State != UART_INITIALIZED) {
        ret = ERROR; /* not initialized */
        
    } else {
        uart_StopRx();
        
        /* flush buffer */
        UART_BUF_RESET(UartInfo.RxBuf);
        UART_BUF_RESET(UartInfo.TxBuf);
        
        uart_StartRx();
        
        ret = SUCCESS;
    }
    
    return ret;
}


/*
 *  uart_Init (Internal Function)
 */
static int32_t  uart_Init_Internal(void)
{
    int32_t ret;
    uint16_t reg_bgr;
    uint8_t reg_smr    = 0;
    uint8_t reg_escr   = 0;
#ifndef USE_CH03
    uint8_t reg_fcr0   = 0;
    uint8_t reg_fcr1   = 0;
    uint8_t reg_fbyte1 = 0;
    uint8_t reg_fbyte2 = 0;
#endif
    uint8_t reg_scr    = 0;
    
    /* get memory for buffer */
    UartInfo.RxBuf.pBuf = (uint8_t*)malloc(UART_BUFSIZE);
    UartInfo.TxBuf.pBuf = (uint8_t*)malloc(UART_BUFSIZE);
    
    if ((UartInfo.RxBuf.pBuf != NULL) && (UartInfo.TxBuf.pBuf != NULL)) {
        
        /* initialize buffer info */
        UART_BUF_RESET(UartInfo.RxBuf);
        UartInfo.RxBuf.Mask = (uint32_t)(UartInfo.Cfg.BufSize - 1);
        UART_BUF_RESET(UartInfo.TxBuf);
        UartInfo.TxBuf.Mask = (uint32_t)(UartInfo.Cfg.BufSize - 1);
        
        
        /*
         *  Set value of SMR register
         */
        /* Mode = UART,  serial output enable */
        reg_smr |= (SMR_MD_UART | SMR_SOE);
        
        /* BitOrder */
        if (UartInfo.Cfg.BitOrder != UartDev_BITORDER_LSB) {
            /* MSB first */
            reg_smr |= (SMR_BDS);
            
        } /* Do nothing if LSB first */
        
        /* StopBits */
        if (UartInfo.Cfg.StopBits == UartDev_STOPBITS_2) {
            /* StopBits 2 */
            reg_smr |= (SMR_SBL);
        } /* Do nothing if StopBits 1 */
        
        
        /*
         *  Set value of BGR register
         */
        /* BaudRate : round off reg_bgr to the whole number */
        reg_bgr = (uint16_t)(((SysFrePCLK2 + ((uint32_t)UartInfo.Cfg.BaudRate / 2)) / (uint32_t)UartInfo.Cfg.BaudRate) - 1);
        
        /*
         *  Set value of ESCR register
         */
        /* DataBits */
        switch (UartInfo.Cfg.DataBits) {
        case UartDev_DATABITS_6:
            reg_escr |= (ESCR_DATABITS_6);
            break;
        case UartDev_DATABITS_7:
            reg_escr |= (ESCR_DATABITS_7);
            break;
        default: /* UartDev_DATABITS_8 */
            reg_escr |= (ESCR_DATABITS_8);
        }
        
        /* Parity */
        switch (UartInfo.Cfg.Parity) {
        case UartDev_PARITY_ODD:
            reg_escr |= (ESCR_PEN);
            break;
        case UartDev_PARITY_EVEN:
            reg_escr |= (ESCR_PEN | ESCR_P);
            break;
        default: /* UartDev_PARITY_NONE */
            /* Do nothing if Parity none */
            reg_escr |= 0;  //DMY
        }
        
        
        if (UartInfo.Fifo > 0) { /* HW FIFO is used */
            /*
             *  Set value of FCR1 register
             */
            /* data lost enable, rx FIFO idle ebale */
            /* FCR1_FDRQ : don't care               */
#ifndef USE_CH03  
            reg_fcr1 |= (FCR1_FLSTE | FCR1_FRIIE | FCR1_FDRQ);      
            /*
             *  Set value of FBYTE1/RBYTE2 registers
             */
            /* FIFO1 is tx */
            reg_fbyte1 = 0;
            /* FIFO2 is rx */
            reg_fbyte2 = (uint8_t)(UartInfo.Fifo);
            
            /*
             *  Set value of FCR0 register
             */
            /* FIFO reset, FIFO enable */
            reg_fcr0 |= (FCR0_FCL2 | FCR0_FCL1 | FCR0_FE2 | FCR0_FE1);
#endif             
        } /* Do nothing if HW FIFO is not used */

        
        /*
         *  Set value of SCR register
         */
        /* rx enable, tx enable */
        reg_scr |= (SCR_RXE | SCR_TXE);
        
        
        /*
         *  Register writing
         */
        /* set mode */
        UartInfo.pReg->SMR    = reg_smr;
        
        /* All disable before other registers are set. */
        UartInfo.pReg->SCR    = 0;
        
        UartInfo.pReg->BGR    = reg_bgr;
        UartInfo.pReg->ESCR   = reg_escr;
        
        /* FIFO disable before other FIFO registers are set.*/
#ifndef USE_CH03
        UartInfo.pReg->FCR0   = FCR0_FCL1 | FCR0_FCL2;
        
        UartInfo.pReg->FCR1   = reg_fcr1;
        UartInfo.pReg->FBYTE1 = reg_fbyte1;
        UartInfo.pReg->FBYTE2 = reg_fbyte2;
        UartInfo.pReg->FCR0   = reg_fcr0;
#endif        
        UartInfo.pReg->SCR = reg_scr;
        
        ret = SUCCESS;
        
    } else {
        /* No memory for buffer */
        ret = ERROR;
    }
    
    return ret;
}

/*
 *  uart_UnInit (Internal Function)
 */
static void  uart_UnInit_Internal(void)
{
    uint8_t reg_scr;
#ifndef USE_CH03
    uint8_t reg_fcr0;
#endif
    /* rx interrupt disable, tx interrupt disable, tx bus idle interrupt disable */
    /* rx disable, tx disable                                                    */
    reg_scr = UartInfo.pReg->SCR & ~(SCR_RIE | SCR_TIE | SCR_TBIE | SCR_RXE | SCR_TXE);
    UartInfo.pReg->SCR = reg_scr;
    
    /* tx FIFO disable, rx FIFO disable */
#ifndef USE_CH03
    reg_fcr0 = UartInfo.pReg->FCR0 & ~(FCR0_FE2 | FCR0_FE1);
    UartInfo.pReg->FCR0 = reg_fcr0;
#endif
    /* software rest */
    reg_scr = UartInfo.pReg->SCR | (SCR_UPGL);
    UartInfo.pReg->SCR = reg_scr;
    
    /* uninitialize Uart_INFO struct */
    UartInfo.RxSuspend = 0;
    
    /* uninitialize tx/rx buffer */
    UartInfo.RxBuf.WIdx = 0;
    UartInfo.RxBuf.RIdx = 0;
    UartInfo.RxBuf.Mask = 0;
    if (UartInfo.RxBuf.pBuf != NULL) {
        free(UartInfo.RxBuf.pBuf);
    }
    UartInfo.TxBuf.WIdx = 0;
    UartInfo.TxBuf.RIdx = 0;
    UartInfo.TxBuf.Mask = 0;
    if (UartInfo.TxBuf.pBuf != NULL) {
        free(UartInfo.TxBuf.pBuf);
    }
    
    return;
}

/*
 *  uart_StartRx (Internal Function)
 */
static void  uart_StartRx(void)
{
    uint8_t reg_scr;
    
    /* rx interrupt enable */
    reg_scr = UartInfo.pReg->SCR | (SCR_RIE);
    UartInfo.pReg->SCR = reg_scr;
    
    return;
}

/*
 *  uart_StopRx (Internal Function)
 */
static void  uart_StopRx(void)
{
    uint8_t reg_scr;
    
    /* rx interrupt disable */
    reg_scr = UartInfo.pReg->SCR & ~(SCR_RIE);
    UartInfo.pReg->SCR = reg_scr;
    
    return;
}

/*
 *  uart_StartTx (Internal Function)
 */
static void  uart_StartTx(void)
{
    uint8_t reg_scr;
#ifndef USE_CH03
    uint8_t reg_fcr1;
#endif    
    if (UartInfo.Fifo > 0) { /* HW FIFO is used */
        
        /* tx FIFO interrupt enable */
#ifndef USE_CH03
        reg_fcr1 = UartInfo.pReg->FCR1 | (FCR1_FTIE);
        UartInfo.pReg->FCR1 = reg_fcr1;
#endif        
    } else { /* HW FIFO is not used */
        
        /* tx interrupt enalbe */
        reg_scr = UartInfo.pReg->SCR | (SCR_TIE);
        UartInfo.pReg->SCR = reg_scr;
        
    }
    
    return;
}

/*
 *  uart_StopTx (Internal Function)
 */
static void  uart_StopTx(void)
{
    uint8_t reg_scr;
#ifndef USE_CH03
    uint8_t reg_fcr1;
#endif    
    if (UartInfo.Fifo > 0) { /* HW FIFO is used */
        
        /* tx FIFO interrupt disable */
#ifndef USE_CH03
        reg_fcr1 = UartInfo.pReg->FCR1 & ~(FCR1_FTIE);
        UartInfo.pReg->FCR1 = reg_fcr1;
#endif   
    } else { /* HW FIFO is not used */
        
        /* tx interrupt disable */
        reg_scr = UartInfo.pReg->SCR & ~(SCR_TIE);
        UartInfo.pReg->SCR = reg_scr;
        
    }
    
    return;
}

/*
 *  uart_DataRx (Internal Function)
 */
static void  uart_DataRx(void)
{
    uint16_t reg_data;
    uint8_t  reg_ssr;
    
    reg_ssr = UartInfo.pReg->SSR;
    
    if ((reg_ssr & (SSR_RDRF)) != 0) {
        
        while (!UART_BUF_FULL(UartInfo.RxBuf)) { /* false */
            /* Rx buffer is not full */
            
            reg_ssr = UartInfo.pReg->SSR;
            if ((reg_ssr & (SSR_RDRF)) != 0) {
                /* rx data from the register(or FIFO) to rx buffer */
                reg_data = UartInfo.pReg->RDR;
                UART_BUF_WRITE(UartInfo.RxBuf, (uint8_t)reg_data);
            } else {
                /* No data */
                break;
            }
        }
        
        if (UART_BUF_FULL(UartInfo.RxBuf)) {
            /* Rx buffer is full */
            
            /* Suspend rx */
            UartInfo.RxSuspend = 1;
            uart_StopRx();
        }
        
    } else { /* overrun error, framing error, parity error */
        /* clear rx error interrupt */
        reg_ssr |= SSR_REC;
        UartInfo.pReg->SSR = reg_ssr;
        
    }
    
    return;
}

/*
 *  uart_DataTx (Internal Function)
 */
static void  uart_DataTx(void)
{
    uint32_t count = 0;
    uint8_t reg_ssr;
#ifndef USE_CH03
    uint8_t reg_fcr1;
#endif
    reg_ssr  = UartInfo.pReg->SSR;
#ifndef USE_CH03
    reg_fcr1 = UartInfo.pReg->FCR1;

    if (((reg_ssr & (SSR_TDRE)) != 0) || ((reg_fcr1 & FCR1_FDRQ) != 0)) {
#else
    if ((reg_ssr & (SSR_TDRE)) != 0) {
#endif
        if (UartInfo.Fifo > 0) { /* HW FIFO is used */
            
            while (!UART_BUF_EMPTY(UartInfo.TxBuf)) { /* false */
                /* Tx buffer is not empty. */
                if (count < (uint32_t)UartInfo.Fifo) {
                    /* tx data from tx buffer to tx FIFO */
                    UartInfo.pReg->TDR = UART_BUF_READ(UartInfo.TxBuf);
                    count++;
                } else {
                    /* Tx FIFO is full. */
                    break;
                }
            }
            
            /* clear FIFO tx interrupt */
#ifndef USE_CH03
            reg_fcr1 = reg_fcr1 & ~(FCR1_FDRQ);
            UartInfo.pReg->FCR1 = reg_fcr1;
#endif
        } else { /* HW FIFO is not used */
            
            if (!UART_BUF_EMPTY(UartInfo.TxBuf)) { /* false */
                /* tx data from tx buffer to the register */
                UartInfo.pReg->TDR = UART_BUF_READ(UartInfo.TxBuf);
            }
        }
        
        if (UART_BUF_EMPTY(UartInfo.TxBuf)) {
            /* Tx buffer is empty. */
            uart_StopTx();
        }
        
    } else {
        /* illegal interrupt */
    }
    
    return;
}

/*
 *  uart_IrqHandler (Interrupt Handling Funtion)
 */
void  uart_IrqHandler(void)
{
    uint8_t reg_ssr;
    
    reg_ssr = UartInfo.pReg->SSR;
    if ((reg_ssr & (SSR_RDRF | SSR_ORE | SSR_FRE | SSR_PE)) != 0) { /* true */
        /* rx interrupt */
        uart_DataRx();
        
    } else {
        /* tx interrupt */
        uart_DataTx();
        
    }
    
    return;
}





