#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#include "osp.h"

/*lint -e826*/

/* buffer configuration information,
 *  element size must be (N+1)*basesize, 
 *  where N is element index, basesize is the size of first element
 */

/*buffer address range */
char *OspBufferBase = NULL;
char *OspBufferqueBasePrintLog = NULL;
char *OspBufferDataBasePrintLog = NULL;
char *OspBufferqueBaseShell = NULL;
char *OspBufferDataBaseShell = NULL;
char *OspBufferQueBaseNor = NULL;
char *OspBufferDataBaseNor = NULL;

int32_t osp_create_bufq(Osp_BufQ_Tcb *que, char *name, int32_t order)
{
    OSP_BUFQ_ORDER(que) = order;
    return osp_create_softque(&OSP_BUFQ_QUE(que), MAX_BLOCK_NUM, name);
}



int32_t osp_buf_enque(uint64_t value, Osp_BufQ_Tcb *que)
{
    return osp_soft_que_enque(value, &OSP_BUFQ_QUE(que), QUE_NO_NEED_WAKE);

}

int32_t osp_buf_deque(uint64_t *pvalue, Osp_BufQ_Tcb *que)
{
    return osp_softque_deque(pvalue, &OSP_BUFQ_QUE(que), QUE_NOBLOCK);
}

//INT32 bufgdb = 1;
int32_t osp_buf_cb_init(uint32_t *puiLen)
{
    Osp_BufQ_Tcb *que;
    Osp_BufQ_Tcb *quebase;
    Osp_Block_Head *phead;
    uint32_t Offset;
    uint32_t idx;
    uint32_t buf_size = 0;
    uint8_t order;
    
    /*timer buffer init*/
    quebase = (Osp_BufQ_Tcb *) BUFFERQUE_BASE_PRINT_LOG;
    order = SIZE_ORDER_PRINT_LOG;
    que = quebase;

    osp_create_bufq(que, "timer_buffer", order);
   
    Offset = 0;
    for (idx = 0; idx < MAX_BLOCK_NUM; idx++)
    {    
        phead = (Osp_Block_Head *)(Offset + (uint64_t)BUFFERDATA_BASE_PRINT_LOG);
        phead->MagicOffset = (1 << order) - OSP_BUF_MAGICDATA_SIZE;
        phead->RelaOrder =  0;
        phead->idx = idx;
        phead->UserId = VALIDIDMASK;
        phead->NormalFlag = BUFFER_PRINTLOG_LEVEL;
        *(uint32_t *)((uint64_t)phead + phead->MagicOffset) = BUF_MAGIC_NUM;
        osp_buf_enque(Offset + (uint64_t)BUFFERDATA_BASE_PRINT_LOG - (uint64_t)BUFFER_BASE, que);
        Offset += (1 << order);
    }
    
    /*cmd buffer init*/
    quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_SHELL;
    order = SIZE_ORDER_SHELL;
    que = quebase;

    osp_create_bufq(que, "cmd_buffer", order);

    Offset = 0;
    for (idx = 0; idx < MAX_BLOCK_NUM; idx++)
    {    
        phead = (Osp_Block_Head *)(Offset + (uint64_t)BUFFERDATA_BASE_SHELL);
        phead->MagicOffset = (1 << order) - OSP_BUF_MAGICDATA_SIZE;
        phead->RelaOrder = 0;
        phead->idx = idx;
        phead->UserId = VALIDIDMASK;
        phead->NormalFlag = BUFFER_SHELL_LEVEL;
        *(uint32_t *)((uint64_t)phead + phead->MagicOffset) = BUF_MAGIC_NUM;
        osp_buf_enque(Offset + (uint64_t)BUFFERDATA_BASE_SHELL - (uint64_t)BUFFER_BASE, que);
        Offset += (1 << order);
    }

    /*normal buffer init*/
    quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_NOR;    
    #if 0
    for (order = MIN_SIZE_ORDER; order <= MAX_SIZE_ORDER; order++)
    {
        que = &quebase[order - MIN_SIZE_ORDER];
        
        osp_create_bufq(que, "normal_buffer", order);
    }

    Offset = 0;
    for (order = MIN_SIZE_ORDER; order <= MAX_SIZE_ORDER; order++)
    {
//        que = (Osp_BufQ_Tcb *)((UINTPTR)quebase + OSP_BUFQ_TCBSIZE * (order - MIN_SIZE_ORDER));
        que = &quebase[order - MIN_SIZE_ORDER];    
        for (idx = 0; idx < MAX_BLOCK_NUM; idx++)
        {
            phead = (Osp_Block_Head *)(Offset + (UINTPTR)BUFFERDATA_BASE_NOR);
            phead->MagicOffset = (1 << order) - OSP_BUF_MAGICDATA_SIZE;
            phead->RelaOrder =  order - MIN_SIZE_ORDER;
            phead->idx = idx;
            phead->UserId = VALIDIDMASK;
            phead->NormalFlag = BUFFER_NORMAL_LEVEL;
            *(U32 *)((UINTPTR)phead + phead->MagicOffset) = BUF_MAGIC_NUM;
            osp_buf_enque(Offset + (UINTPTR)BUFFERDATA_BASE_NOR - (UINTPTR)BUFFER_BASE, que);
            Offset += (1 << order);
        }
    }
    #else
    
    Offset = 0;
    for (order = MIN_SIZE_ORDER; order <= MAX_SIZE_ORDER; order++)
    {
        que = &quebase[order - MIN_SIZE_ORDER];
        osp_create_bufq(que, "normal_buffer", order);
        
        buf_size = 1 << order;
        for (idx = 0; idx < MAX_BLOCK_NUM; idx++)
        {
            phead = (Osp_Block_Head *)(Offset + (uint64_t)BUFFERDATA_BASE_NOR);
            phead->MagicOffset = buf_size - OSP_BUF_MAGICDATA_SIZE;
            phead->RelaOrder =  order - MIN_SIZE_ORDER;
            phead->idx = idx;
            phead->UserId = VALIDIDMASK;
            phead->NormalFlag = BUFFER_NORMAL_LEVEL;
            *(uint32_t *)((uint64_t)phead + phead->MagicOffset) = BUF_MAGIC_NUM;
            osp_buf_enque(Offset + (uint64_t)BUFFERDATA_BASE_NOR - (uint64_t)BUFFER_BASE, que);
            Offset += buf_size;
        }
    }
    #endif
    *puiLen =  Offset + (uint64_t)BUFFERDATA_BASE_NOR - (uint64_t)BUFFER_BASE;
    return OSP_OK;
}



void *osp_get_buffer(uint32_t size, uint16_t UseType, uint16_t PriLevel)
{
    Osp_BufQ_Tcb *quebase;
    uint64_t offset;
    int32_t ret;
    int32_t RelaOrder;
    Osp_Block_Head *phead;
    uint32_t bufSize;
    int32_t order = 0;

    bufSize = size + OSP_BLOCK_HEAD_SIZE + OSP_BUF_MAGICDATA_SIZE;
    if ((NULL == BUFFER_BASE) || (bufSize > MAX_OSPBUF_LEN))
    {
        return NULL;
    }    

    /*shell will use itself buffer*/
    if (osp_task_is_shell(CURRENT_TASKID))
    {
        quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_SHELL;
        osp_assert(bufSize <= (1 << (OSP_BUFQ_ORDER(quebase))));
        ret = osp_buf_deque(&offset, quebase);
        if (-1 != ret)
        {
            phead = (Osp_Block_Head *)(offset + (uint64_t)BUFFER_BASE);
            phead->UserId = (VALIDIDMASK | CURRENT_TASKID);
            phead->UseType = UseType;
            return (void *)((uint64_t)phead + OSP_BLOCK_HEAD_SIZE);
        }
        return NULL;
    }
    
    switch (PriLevel)
    {
        case BUFFER_NORMAL_LEVEL:
    
            quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_NOR;

            /*查找满足bufSize的最小order*/
            for(order = MIN_SIZE_ORDER; order <= MAX_SIZE_ORDER; order++)
            {
                if(bufSize < (1 << order))
                {
                    RelaOrder = order - MIN_SIZE_ORDER;
                    ret = osp_buf_deque(&offset, &quebase[RelaOrder]);
                    if (-1 != ret) //若最小order没有buf了，继续向后面的order搜索
                    {
                        phead = (Osp_Block_Head *)(offset + (uint64_t)BUFFER_BASE);
                        phead->UserId = (VALIDIDMASK | CURRENT_TASKID);
                        phead->UseType = UseType;
                        return (void *)((uint64_t)phead + OSP_BLOCK_HEAD_SIZE);
                    }                
                }
            }

            //没有满足条件的buf，返回空
            if(MAX_SIZE_ORDER == order)
            {
                return NULL;
            }
        case BUFFER_PRINTLOG_LEVEL:
            quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_PRINT_LOG;
            osp_assert(bufSize <= (1 << (OSP_BUFQ_ORDER(quebase))));
            ret = osp_buf_deque(&offset, quebase);
            if (-1 != ret)
            {
                phead = (Osp_Block_Head *)(offset + (uint64_t)BUFFER_BASE);
                phead->UserId = (VALIDIDMASK | CURRENT_TASKID);
                phead->UseType = UseType;
                return (void *)((uint64_t)phead + OSP_BLOCK_HEAD_SIZE);
            }
            return NULL; 
        default :
            return NULL;
    }
}     

OSP_STATUS osp_free_buffer(void *pBuffer)
{
    uint32_t offset;
    Osp_Block_Head *phead;
    Osp_BufQ_Tcb *quebase;
    
    
    osp_assert(pBuffer != NULL);
    
    phead = (Osp_Block_Head *)((uint64_t)pBuffer - OSP_BLOCK_HEAD_SIZE);

    osp_assert((phead->UserId & 0xffff0000) == VALIDIDMASK);
    osp_assert((phead->UserId & 0x0000ffff) != FREEUSERID);
    osp_assert(*(uint32_t *)((uint64_t)phead + phead->MagicOffset) == BUF_MAGIC_NUM);
    
    offset = (uint64_t)phead - (uint64_t)BUFFER_BASE;

    phead->UserId = VALIDIDMASK | FREEUSERID;

    switch (phead->NormalFlag)
    {
        case BUFFER_NORMAL_LEVEL:
            quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_NOR;
            osp_buf_enque(offset, &quebase[phead->RelaOrder]); 
            break;
        case BUFFER_SHELL_LEVEL:
            quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_SHELL;
            osp_buf_enque(offset, quebase);
            break;
        case BUFFER_PRINTLOG_LEVEL:
            quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_PRINT_LOG;
            osp_buf_enque(offset, quebase);
            break;
    }    
    return (OSP_OK);
}


void osp_show_buf_count(void)
{
    int32_t order;
    char *pbuf;
    char *p;
    uint32_t len = 0;
    Osp_BufQ_Tcb *quebase;
    Osp_BufQ_Tcb *que;

    pbuf = malloc(10 * 1024);
    osp_assert(pbuf != NULL);
    

    len += sprintf(pbuf, "%-16s%-16s%-16s%-16s%-16s%-16s%-16s\n", "BlockSize", "MallocCnt", "FreeCnt", "UsedNum",
        "TotalCnt", "UsedRate", "type");
        

    
    que = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_SHELL;
    
    len += sprintf(pbuf+len, "%-16d%-16ld%-16ld%-16d%-16d%d%%\t\t%s\n", (1<<SIZE_ORDER_SHELL), OSP_BUFQ_DECNT(que), (OSP_BUFQ_ENCNT(que) - OSP_BUFQ_DEP(que)),
        (OSP_BUFQ_DEP(que) - OSP_BUFQ_CUR(que)), OSP_BUFQ_DEP(que), ((OSP_BUFQ_DEP(que) - OSP_BUFQ_CUR(que)) * 100) / (OSP_BUFQ_DEP(que)), "shell");

    que = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_PRINT_LOG;
    
    len += sprintf(pbuf+len, "%-16d%-16ld%-16ld%-16d%-16d%d%%\t\t%s\n", (1<<SIZE_ORDER_PRINT_LOG), OSP_BUFQ_DECNT(que), (OSP_BUFQ_ENCNT(que) - OSP_BUFQ_DEP(que)),
        (OSP_BUFQ_DEP(que) - OSP_BUFQ_CUR(que)), OSP_BUFQ_DEP(que), ((OSP_BUFQ_DEP(que) - OSP_BUFQ_CUR(que)) * 100) / (OSP_BUFQ_DEP(que)), "Print&Log");

    quebase = (Osp_BufQ_Tcb *)BUFFERQUE_BASE_NOR;
    for (order = MIN_SIZE_ORDER; order < MAX_SIZE_ORDER+1; order++)
    {

        que = &quebase[order - MIN_SIZE_ORDER];
        
        len += sprintf(pbuf+len, "%-16d%-16ld%-16ld%-16d%-16d%d%%\t\t%s\n", (1<<order), OSP_BUFQ_DECNT(que), (OSP_BUFQ_ENCNT(que) - OSP_BUFQ_DEP(que)),
            (OSP_BUFQ_DEP(que) - OSP_BUFQ_CUR(que)), OSP_BUFQ_DEP(que), ((OSP_BUFQ_DEP(que) - OSP_BUFQ_CUR(que)) * 100) / (OSP_BUFQ_DEP(que)), "normal");
    }
    for (p = pbuf; p < pbuf+len; p += (MAX_DBGINFO_LEN-1))
    {
        osp_debug_out(CMD_DEBUG_LEVEL, "%s", p);
    }
    free(pbuf);
}


/*************************************************************************
*           |--------|OspBufferBase(OspBufferqueBasePrintLog)        
*           |        |“timer_buffer” queue的头，队列
*           |        |深度512（MAX_BLOCK_NUM），大小4KB多点
*           |        |
*           |--------|OspBufferDataBasePrintLog        
*           |        |“timer buffer”的数据区，一共512个，每个
*           |        |64KB，共32M
*           |        |        
*           |--------|OspBufferqueBaseShell
*           |        |"cmd_buffer"queue的头，队列
*           |        |深度512（MAX_BLOCK_NUM），大小4KB多点
*           |        |        
*           |--------|OspBufferDataBaseShell
*           |        |"cmd_buffer"的数据区，一共512个，每个
*           |        |64KB，共32M
*           |        |        
*           |--------|OspBufferQueBaseNor
*           |        |"normal_buffer"queue的头，以共有（19-6+1）个队列，
*           |        |每个队列深度深度512（MAX_BLOCK_NUM）大小为4KB*14=56KB多
*           |        |        
*           |--------|OspBufferDataBaseShell
*           |        |"normal_buffer"的数据区，
*           |        |2^6=64B，    512个
*           |        |2^7=128B，   512个       
*           |        |2^8=256B，   512个
*           |        |...     
*           |        |...     
*           |        |...     
*           |--------|2^19=512KB，512个,共512M。osp_buf_init一共申请约576M
***************************************************************************/
OSP_STATUS osp_buf_init(void)
{
    int32_t ret = 0;
    uint32_t SizeOfMem;
    OspBufferBase = osp_get_init_mem(OSPBUF_SIZE);
    
    OspBufferqueBasePrintLog = (char *)OSP_ROUND_UP(OspBufferBase, 32);
    OspBufferDataBasePrintLog = (char *)OSP_ROUND_UP(OspBufferqueBasePrintLog + OSP_BUFQ_TCBSIZE, 32);
    OspBufferqueBaseShell = (char *)OSP_ROUND_UP(OspBufferDataBasePrintLog + (1 << SIZE_ORDER_PRINT_LOG) * MAX_BLOCK_NUM, 32);
    OspBufferDataBaseShell = (char *)OSP_ROUND_UP(OspBufferqueBaseShell + OSP_BUFQ_TCBSIZE,32);
    
    OspBufferQueBaseNor = (char *)OSP_ROUND_UP(OspBufferDataBaseShell + (1 << SIZE_ORDER_SHELL) * MAX_BLOCK_NUM, 32);
    OspBufferDataBaseNor = (char *)OSP_ROUND_UP(OspBufferQueBaseNor + OSP_BUFQ_TCBSIZE * (MAX_SIZE_ORDER - MIN_SIZE_ORDER + 1), 32);

    

    if (0 == g_ProcessId)
    {
        ret = osp_buf_cb_init(&SizeOfMem);
        osp_assert(SizeOfMem <= OSPBUF_SIZE);
 //       osp_debug_out_with_time(CMD_DEBUG_LEVEL, "osp_buf_init SizeOfMem is %d\r\n", SizeOfMem);
    }

    return (ret);
}

