#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/mman.h>

#include "osp.h"
#include "ospMsg.h"

#define TIME_MSG_NUM    512 //origin: 8192
#define TIME_MSG_MSK    511 //origin: 8191


#define TIMER_MSG_SIZE sizeof(Osp_Timer_Msg_Block)

/*timer msg has msg_head only*/
Osp_Timer_Msg_Block *TimerMsg[TIME_MSG_NUM] = {0};

char *gOspMsgQue = 0;

OSP_STATUS osp_msg_que_init(void)
{
//    int ret;
    int32_t tasknum = osp_get_task_num();
    int32_t i;
//    int TaskId;
    
    gOspTask = (OSP_TASKCB *)osp_get_init_mem(OSP_ROUND_UP(sizeof(OSP_TASKCB), 32) * tasknum);
    gOspMsgQue = osp_get_init_mem((OSP_ROUND_UP(OSP_MSG_QUE_SIZE, 32)) * tasknum);
    TimerMsg[0] = (Osp_Timer_Msg_Block *)osp_get_init_mem(TIME_MSG_NUM * OSP_ROUND_UP(sizeof(TIMER_MSG_SIZE), 32));


    
    for (i = 0; i < TIME_MSG_NUM; i++)
    {
       TimerMsg[i] = (Osp_Timer_Msg_Block *)((uint64_t)TimerMsg[0] + i * OSP_ROUND_UP(sizeof(TIMER_MSG_SIZE), 32));
    }
    
    
    if (0 == g_ProcessId)
    {
        memset(gOspTask, 0, (OSP_ROUND_UP(sizeof(OSP_TASKCB), 32) * tasknum));
        for (i = 0; i < tasknum; i++)
        {
            gOspTask[i].MsgQOffset = OSP_ROUND_UP(OSP_MSG_QUE_SIZE, 32) * i;
        }
    }
    return OSP_OK;
}

int32_t osp_create_msgq(Osp_MsgQ_Tcb *que, char *name)
{
    return osp_create_softque(&OSP_MSGQ_QUE(que), OSP_MEGQ_DEP, name);
}

int32_t osp_msg_enque(uint64_t value, Osp_MsgQ_Tcb *que)
{
    return osp_soft_que_enque(value, &OSP_MSGQ_QUE(que), QUE_NEED_WAKE);

}

int32_t osp_msg_deque(uint64_t *pvalue, Osp_MsgQ_Tcb *que)
{
    return osp_softque_deque(pvalue, &OSP_MSGQ_QUE(que), QUE_ISBLOCK);

}

int32_t osp_msg_dequetry(uint64_t *pvalue, Osp_MsgQ_Tcb *que)
{
    return osp_softque_dequetry(pvalue, &OSP_MSGQ_QUE(que));
}


int32_t osp_msg_deque_timeout(uint64_t *pvalue, Osp_MsgQ_Tcb *que, uint32_t timeout)
{
    return osp_softque_dequeTimeOut(pvalue, &OSP_MSGQ_QUE(que), timeout);
}





Osp_Msg_Head *osp_alloc_msg(uint32_t Len)
{
    Osp_Msg_Head *pMsg;
    osp_assert(Len > 0);
    pMsg = osp_get_buffer(Len + MSG_HEAD_SIZE, BUF_FOR_MSG, BUFFER_NORMAL_LEVEL);
    if (pMsg)
    {
        TASK_MSG_ALLOCCNT(CURRENT_TASKID)++;
    }
    return pMsg;
}

Osp_Msg_Head *osp_alloc_msgId(uint32_t Len, int32_t id)
{
    Osp_Msg_Head *pMsg;
    osp_assert(Len > 0);
    pMsg = osp_get_buffer(Len + MSG_HEAD_SIZE, BUF_FOR_MSG, BUFFER_NORMAL_LEVEL);
    if (pMsg)
    {
        osp_atomic_inc((int32_t *) & TASK_MSG_ALLOCCNT(id));
    }
    return pMsg;
}


Osp_Msg_Head *osp_alloc_msgTimer(void)
{
    static int32_t cnt = 0;
    Osp_Msg_Head *pMsg = (Osp_Msg_Head *)TimerMsg[(cnt++) & TIME_MSG_MSK];
    return pMsg;
    

}
Osp_Msg_Head*osp_alloc_msg_print_log(void)
{

    Osp_Msg_Head *pMsg = osp_get_buffer(0 + MSG_HEAD_SIZE, BUF_FOR_MSG, BUFFER_PRINTLOG_LEVEL);
    if (pMsg)
    {
        osp_atomic_inc((int32_t *)&TASK_LOGMSG_ALLOCCNT(CURRENT_TASKID));
    }
    return pMsg;
}





void osp_free_msg(Osp_Msg_Head *pHead)
{
    osp_atomic_inc((int32_t *)&TASK_MSG_FREECNT(CURRENT_TASKID));
    if (IS_TIMER_MSG(pHead))
        return;
    osp_free_buffer(pHead);
}
int32_t osp_free_msgid(Osp_Msg_Head *pHead, int32_t id)
{
    osp_atomic_inc((int32_t *)&TASK_MSG_FREECNT(id));
    if (IS_TIMER_MSG(pHead))
        return 0;
    return osp_free_buffer(pHead);
}

OSP_STATUS osp_send_msg(Osp_Msg_Head *p_MsgHead)
{
    OSP_STATUS ret;
 //   U8 *pComm;
    uint32_t TaskId;
//    Osp_Msg_Head *p_NMsgHead;
    OSP_FUNCPTR func_handle;
    uint64_t que;
    
    osp_assert(NULL != p_MsgHead);

    TaskId = p_MsgHead->DstId;

    func_handle = TASK_TXMSG_HANDLE(TaskId);
    if (NULL == func_handle)
    {
        osp_debug_out_with_time(ERR_DEBUG_LEVEL, "task%d can not send msg to task%d\n", CURRENT_TASKID, TaskId);
        osp_free_msg(p_MsgHead);

        return OSP_ERROR;
    }

    
    que = TASK_MSG_QUE(TaskId);
    
        
    osp_atomic_inc((int32_t *)&TASK_MSG_TXCNT(CURRENT_TASKID));
    
    ret = func_handle(p_MsgHead, que);
//    ret = osp_msg_enque(MSG_TO_OFFSET(p_MsgHead), (Osp_MsgQ_Tcb *)TASK_MSGQ(TaskId));
    if (OSP_OK != ret)
    {
//        osp_free_msg(p_MsgHead);
        osp_debug_out_with_time(ERR_DEBUG_LEVEL, "task%d send msg to task%d msgtype 0x%x failed!\n", CURRENT_TASKID, TaskId, p_MsgHead->MsgType);
        osp_atomic_inc((int32_t *)&TASK_MSG_FULLCNT(TaskId)); 
        return ret;
    }
    return OSP_OK;

}
OSP_STATUS osp_send_msgId(Osp_Msg_Head *p_MsgHead, int32_t id)
{
    OSP_STATUS ret;
//    U8 *pComm;
    uint32_t TaskId;
//    Osp_Msg_Head *p_NMsgHead;
//    OSP_FUNCPTR func_handle;
    
    osp_assert(NULL != p_MsgHead);


    TaskId = p_MsgHead->DstId;
    
    osp_atomic_inc((int32_t *)&TASK_MSG_TXCNT(id)); 
    ret = osp_msg_enque(MSG_TO_OFFSET(p_MsgHead), (Osp_MsgQ_Tcb *)TASK_MSGQ(TaskId));
    if (OSP_OK != ret)
    {
//        osp_free_msgid(p_MsgHead,id);
        osp_atomic_inc((int32_t *)&TASK_MSG_FULLCNT(TaskId)); 
        return ret;
    }
    return OSP_OK;
}

Osp_Msg_Head *osp_rev_msg(void)
{
    uint32_t TaskId;
    OSP_FUNCPTR func_handle;
    uint64_t que;
    
    TaskId = CURRENT_TASKID;
    
    que = TASK_MSG_QUE(TaskId);
    func_handle = TASK_RXMSG_HANDLE(TaskId);

    return (Osp_Msg_Head *)func_handle(que);

}

Osp_Msg_Head *osp_rev_msgid(int32_t id)
{

    uint64_t RcvMsg;
    (void)osp_msg_deque((uint64_t *)&RcvMsg, (Osp_MsgQ_Tcb *)(TASK_MSGQ(id)));
    osp_atomic_inc((int32_t*)&TASK_MSG_RXCNT(id));
    
    return OFFSET_TO_MSG(RcvMsg);
}


Osp_Msg_Head *osp_rev_msgtry(void)
{

    uint64_t RcvMsg;
    int32_t ret;
    ret = osp_msg_dequetry((uint64_t *)&RcvMsg, (Osp_MsgQ_Tcb *)(TASK_MSGQ(CURRENT_TASKID)));
    if (0 != ret)
    {
        return NULL;
    }
    osp_atomic_inc((int32_t *)&TASK_MSG_RXCNT(CURRENT_TASKID));
    return OFFSET_TO_MSG(RcvMsg);
}

Osp_Msg_Head *osp_rev_msg_timeout(uint32_t timeout)
{

    uint64_t RcvMsg;
    int32_t ret;
    ret = osp_msg_deque_timeout((uint64_t *)&RcvMsg, (Osp_MsgQ_Tcb *)(TASK_MSGQ(CURRENT_TASKID)), timeout);
    
    if (0 != ret)
    {
        return NULL;
    }
    osp_atomic_inc((int32_t *)&TASK_MSG_RXCNT(CURRENT_TASKID));
    return OFFSET_TO_MSG(RcvMsg);
}

Osp_Msg_Head *osp_rev_idmsg(uint32_t Id)
{

    uint64_t RcvMsg;
    (void)osp_msg_deque((uint64_t *)&RcvMsg, (Osp_MsgQ_Tcb *)(TASK_MSGQ(Id)));
    osp_atomic_inc((int32_t *)&TASK_MSG_RXCNT(Id));
    
    return OFFSET_TO_MSG(RcvMsg);
}

Osp_Msg_Head *osp_rev_idmsgtry(uint32_t Id)
{

    uint64_t RcvMsg;
    int32_t ret;
    ret = osp_msg_dequetry((uint64_t *)&RcvMsg, (Osp_MsgQ_Tcb *)(TASK_MSGQ(Id)));
    
    if (0 != ret)
    {
        return NULL;
    }
    osp_atomic_inc((int32_t *)&TASK_MSG_RXCNT(Id));
    return OFFSET_TO_MSG(RcvMsg);
}

Osp_Msg_Head *osp_rev_id_msg_timeout(uint32_t timeout, uint32_t Id)
{

    uint64_t RcvMsg;
    int32_t ret;
    ret = osp_msg_deque_timeout((uint64_t *)&RcvMsg, (Osp_MsgQ_Tcb *)(TASK_MSGQ(Id)), timeout);
    
    if (0 != ret)
    {
        return NULL;
    }
    osp_atomic_inc((int32_t *)&TASK_MSG_RXCNT(Id));
    return OFFSET_TO_MSG(RcvMsg);
}




void osp_show_msg_que_info(void)
{
    int32_t i;
    Osp_MsgQ_Tcb *MsgQ;
    char *pbuf;
    int32_t len = 0;
    char *p;

    pbuf = malloc(10*1024);
    osp_assert(pbuf != NULL);
        
    len += osp_get_soft_que_desc(pbuf + len);
    
    for (i = 0; i < OSP_MAX_TASK; i++)
    {
        if (gOspTask[i].Active)
        {
            
            MsgQ = TASK_MSGQ(i); 
            len += osp_get_soft_que_info(&OSP_MSGQ_QUE(MsgQ), pbuf + len);

        }
    }
 
    
    for (p = pbuf; p < pbuf+len; p += (MAX_DBGINFO_LEN-1))
    {
        osp_debug_out(CMD_DEBUG_LEVEL, "%s", p);
    }
    free(pbuf);
}


OSP_STATUS osp_send_por_msg(Osp_Msg_Head *p_MsgHead, Osp_MsgQ_Tcb *que)
{
    int32_t ret;
    ret = osp_msg_enque(MSG_TO_OFFSET(p_MsgHead), que);

    return ret;

}

Osp_Msg_Head *osp_rev_promsg(Osp_MsgQ_Tcb *que)
{

    uint64_t RcvMsg;
    
    (void)osp_msg_deque((uint64_t *)&RcvMsg, que);
    
    return OFFSET_TO_MSG(RcvMsg);
}


