#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <execinfo.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include "osp.h"
#include "ospSoftQue.h"
#include "ospLog.h"
#include "ucp_printf.h"
#include "ospDump.h"
#include "ucp_handshake.h"

#define SPU_DM_SIZE         (0x200000)  /* 2M */
#define APE_CORE_ID_0       (0)
#define APE_CORE_ID_1       (1)
#define APE_CORE_ID_2       (2)
#define APE_CORE_ID_3       (3)
#define APE_CORE_ID_4       (4)
#define APE_CORE_ID_5       (5)
#define APE_CORE_ID_6       (6)
#define APE_CORE_ID_7       (7)
#define APC_CORE_ID_0       (0)
#define APC_CORE_ID_1       (1)
#define APC_CORE_ID_2       (2)
#define APC_CORE_ID_3       (3)


#define DUMP_DM_CORE_FILE_NAME "./dump_dm_core%02d_%04d%02d%02d_%02d%02d%02d"  /* dump dm file */
#define DUMP_DM_CORE_FILE_LEN  (36)


void *gp_static_sm_mem              = NULL;
void *gp_static_dm_mem              = NULL;
void *gp_static_ecs_sm_mem          = NULL;
void *gp_static_pet_sm_mem          = NULL;
void *gp_static_ape_phy_mem         = NULL;
void *gp_static_ape_text            = NULL;
void *gp_static_arm_ape_msg         = NULL;
void *gp_static_ape_log             = NULL;
void *gp_static_arm_stack           = NULL;

uint64_t gp_static_sm_mem_size          = 0;
uint64_t gp_static_dm_mem_size          = 0;
uint64_t gp_static_ecs_sm_mem_size      = 0;
uint64_t gp_static_pet_sm_mem_size      = 0;
uint64_t gp_static_ape_phy_mem_size     = 0;
uint64_t gp_static_ape_text_mem_size = 0;
uint64_t gp_static_arm_ape_msg_size     = 0;
uint64_t gp_static_ape_log_size         = 0;
uint64_t gp_static_arm_stack_size       = 0;

char *gp_dump_buf;

extern uint8_t g_ucIsEcho;

void osp_dump_init(void)
{

    gp_static_sm_mem = get_static_mem(SHARE_MEM, &gp_static_sm_mem_size);
    if (0 == gp_static_sm_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(SHARE_MEM) error......\r\n");
        return ;
    }

    gp_static_dm_mem = get_static_mem(APE_DM, &gp_static_dm_mem_size);
    if (0 == gp_static_dm_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(APE_DM) error......\r\n");
        return ;
    }

    gp_static_ecs_sm_mem = get_static_mem(ECS_SM, &gp_static_ecs_sm_mem_size);
    if (0 == gp_static_ecs_sm_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(ECS_SM) error......\r\n");
        return ;
    }

    gp_static_pet_sm_mem = get_static_mem(PET_SM, &gp_static_pet_sm_mem_size);
    if (0 == gp_static_pet_sm_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(PET_SM) error......\r\n");
        return ;
    }

    gp_static_ape_phy_mem = get_static_mem(APE_PHY, &gp_static_ape_phy_mem_size);
    if (0 == gp_static_ape_phy_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(APE_PHY) error......\r\n");
        return ;
    }

    gp_static_ape_text = get_static_mem(APE_TEXT, &gp_static_ape_text_mem_size);
    if (0 == gp_static_ape_text_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(APE_TEXT) error......\r\n");
        return ;
    }

    gp_static_arm_ape_msg = get_static_mem(ARM_APE_MSG, &gp_static_arm_ape_msg_size);
    if (0 == gp_static_arm_ape_msg_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(ARM_APE_MSG) error......\r\n");
        return ;
    }

    gp_static_ape_log = get_static_mem(APE_LOG, &gp_static_ape_log_size);
    if (0 == gp_static_ape_log_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(APE_LOG) error......\r\n");
        return ;
    }
    
    gp_static_arm_stack = get_static_mem(ARM_STACK, &gp_static_arm_stack_size);
    if (0 == gp_static_arm_stack_size)
    {
        UCP_PRINT_ERROR("osp_dump_init get_static_mem(ARM_STACK) error......\r\n");
        return ;
    }

    return;
}
#if 0
void osp_dump_sm(char *pName, uint32_t ulLen)
{
    OSP_STATUS ret = OSP_OK;

    if(ulLen > gp_static_sm_mem_size)    
    {
        UCP_PRINT_ERROR("osp_dump_sm ulLen:%u > gp_static_sm_mem_size:%ld", ulLen, gp_static_sm_mem_size);
        return ;
    }

    if(NULL == pName)
    {
        UCP_PRINT_ERROR("osp_dump_sm pName is null\r\n");
        return ;
    }

    ret = osp_dump_proc(pName, SHARE_MEM  , ulLen);
    if(OSP_OK != ret)
    {
        UCP_PRINT_ERROR("osp_dump_sm proc error\r\n");
        return;
    }

    return;
}

void osp_dump_dm(char *pName, uint32_t ulLen)
{
    OSP_STATUS ret = OSP_OK;
    
    if(ulLen > gp_static_dm_mem_size)
    {
        UCP_PRINT_ERROR("osp_dump_dm ulLen:%u > gp_static_dm_mem_size:%ld\r\n", ulLen, gp_static_sm_mem_size);
        return ;
    }

    if(NULL == pName)
    {
        UCP_PRINT_ERROR("osp_dump_dm pName is null\r\n");
        return ;
    }

    ret = osp_dump_proc(pName, APE_DM  , ulLen);
    if(OSP_OK != ret)
    {
        UCP_PRINT_ERROR("osp_dump_dm proc error\r\n");
        return;
    }
    
    return;
}
#endif

#ifdef HEARTBEAT_ENABLE
int8_t osp_dump_dm_ape_by_coreid(uint8_t coreid)
{
    int32_t  ret       = OSP_OK;
    char *pbuf         = gp_static_dm_mem;
    char  file_name[DUMP_DM_CORE_FILE_LEN]= {0};
    static FILE *fp    = NULL;
    struct tm *t;
    time_t tt;
    uint64_t u64_start_offset = 0;

    time(&tt);
    t = localtime(&tt);

    switch (coreid)
    {
        case APE_CORE_ID_0:
        case APE_CORE_ID_1:
        {
            u64_start_offset = 0;
            ret = OSP_OK;
            break;
        }
        case APE_CORE_ID_2:
        case APE_CORE_ID_3:
        {
            u64_start_offset = SPU_DM_SIZE;
            ret = OSP_OK;
            break;
        }
        case APE_CORE_ID_4:
        case APE_CORE_ID_5:
        {
            u64_start_offset = SPU_DM_SIZE*2;
            ret = OSP_OK;
            break;
        }
        case APE_CORE_ID_6:
        case APE_CORE_ID_7:
        {
            u64_start_offset = SPU_DM_SIZE*3;
            ret = OSP_OK;
            break;
        }
        default:
        {
            ret = OSP_ERROR;
            UCP_PRINT_ERROR("osp_dump_dm_ape_by_coreid: input coreid(%d) error\r\n", coreid);
            break;
        }
    }

    if (OSP_ERROR == ret)
    {
        return ret;
    }

    sprintf(file_name, DUMP_DM_CORE_FILE_NAME, coreid, t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    UCP_PRINT_ERROR("osp_dump_dm_ape_by_coreid: file_name = %s\r\n", file_name);

    fp = fopen(file_name, "wb+");
    if (fp < 0)
    {
        UCP_PRINT_ERROR("osp_dump_dm_ape_by_coreid: file open failure  \n");
        return OSP_ERROR;
    }

    ret = fwrite((pbuf+u64_start_offset), sizeof(char), SPU_DM_SIZE, fp);
    if(ret < 0)
    {
        UCP_PRINT_ERROR("osp_dump_dm_ape_by_coreid: fwrite error ret:%d\n", ret);
        fclose(fp);
        return OSP_ERROR;
    }

    fflush(fp);
    fclose(fp);

    return OSP_OK;
}


int8_t osp_dump_dm_rfm_by_coreid(uint8_t coreid)
{
    return OSP_OK;
}

int8_t osp_dump_dm_by_coreid(uint8_t coreid)
{
    /* ???? */
    if (coreid > MAX_NUM_SPU)
    {
        UCP_PRINT_ERROR("osp_dump_dm_by_coreid: input parameter error\r\n");
        return OSP_ERROR;
    }

    if (coreid <= APE_CORE_ID_7)
    {
        return osp_dump_dm_ape_by_coreid(coreid);
    }
    else if (coreid <= MAX_NUM_SPU)
    {
        return osp_dump_dm_rfm_by_coreid(coreid);
    }
    return OSP_ERROR;
}
#endif


OSP_STATUS osp_dump_len_is_ok(module_type_e        module, uint64_t ulLen)
{
    uint64_t ulModuleLen = 0;
    
    switch(module)
    {
        case SHARE_MEM:            
            ulModuleLen = gp_static_sm_mem_size;
            break;
        case APE_DM:            
            ulModuleLen = gp_static_dm_mem_size;
            break;
        case ECS_SM:            
            ulModuleLen = gp_static_ecs_sm_mem_size;
            break;
        case PET_SM:            
            ulModuleLen = gp_static_pet_sm_mem_size;
            break;
        case APE_PHY:            
            ulModuleLen = gp_static_ape_phy_mem_size;
            break;
        case APE_TEXT:            
            ulModuleLen = gp_static_ape_text_mem_size;
            break;
        case ARM_APE_MSG:            
            ulModuleLen = gp_static_arm_ape_msg_size;
            break;
        case APE_LOG:            
            ulModuleLen = gp_static_ape_log_size;
            break;
        case ARM_STACK:            
            ulModuleLen = gp_static_arm_stack_size;
            break;
        default:            
            break;

    }

    if(ulLen > ulModuleLen)
    {
        UCP_PRINT_ERROR("osp_dump_len is error ulLen:%ld\n", ulLen);
        return OSP_ERROR;
    }

    return OSP_OK;
}

OSP_STATUS osp_dump_apc_len_is_ok(uint8_t         ucApcId, uint64_t phy_addr,uint64_t ulLen)
{
    uint64_t u64_start_offset = 0;
    uint64_t virt_addr          = 0;
    int32_t  ret                = OSP_OK;    
    uint32_t ulTmp              = 0;

    switch (ucApcId)
    {
        case APC_CORE_ID_0:
        {
            u64_start_offset = 0;
            ret = OSP_OK;
            break;
        }
        case APC_CORE_ID_1:
        {
            u64_start_offset = SPU_DM_SIZE;
            ret = OSP_OK;
            break;
        }
        case APC_CORE_ID_2:
        {
            u64_start_offset = SPU_DM_SIZE*2;
            ret = OSP_OK;
            break;
        }
        case APC_CORE_ID_3:
        {
            u64_start_offset = SPU_DM_SIZE*3;
            ret = OSP_OK;
            break;
        }
        default:
        {
            ret = OSP_ERROR;
            UCP_PRINT_ERROR("osp_dump_apc_len_is_ok: ucApcId:%u error\r\n", ucApcId);
            break;
        }
    }

    if (OSP_ERROR == ret)
    {
        return ret;
    }

    ret = osp_phy_to_virt(  APE_DM, phy_addr, &virt_addr);
    if(ret != OSP_OK)
    {
        UCP_PRINT_ERROR("osp_dump_apc_len APE_DM phy_addr:0x%lx virt_addr:0x%lx\n", phy_addr, virt_addr);
        return OSP_ERROR;
    }

    ulTmp =  virt_addr - (uint64_t)(gp_static_dm_mem + u64_start_offset);
    if(ulTmp < ulLen)
    {
        UCP_PRINT_ERROR("osp_dump_apc_len APE_DM ulTmp:%u\n", ulTmp);
        return OSP_ERROR;
    }
    
    return OSP_OK;
}


/*0x9400000 + apcid*0x200000 +(phy_addr - 0x200000)*/
int8_t osp_dump_dm_by_apcid(char *pName, uint8_t           ucApcId, uint64_t phy_addr, uint32_t ulLen)
{
    int32_t  ret                = OSP_OK;
    static FILE *fp             = NULL;
    uint64_t virt_addr          = 0;    
    uint64_t tmp_phy_addr       = 0;

    if(NULL == pName)
    {
        UCP_PRINT_ERROR("osp_dump_dm_by_apcid: pName is NULL\r\n");
        return OSP_ERROR;
    }

    if(ulLen > SPU_DM_SIZE)
    {
        UCP_PRINT_ERROR("osp_dump_dm_by_apcid: ulLen:%u error\r\n", ulLen);        
        return OSP_ERROR;
    }

    tmp_phy_addr = APE_DM_BASE_PHY_ADDR + ucApcId*APC_DM_LEN +(phy_addr - APC_DM_LEN);
    
    ret = osp_phy_to_virt(  APE_DM, tmp_phy_addr, &virt_addr);
    if(ret != OSP_OK)
    {
        UCP_PRINT_ERROR("osp_dump_proc APE_DM phy_addr:0x%lx virt_addr:0x%lx\n", phy_addr, virt_addr);
        return OSP_ERROR;
    }
	
	fp = fopen(pName, "wb+");
    if (fp < 0)
    {
        UCP_PRINT_ERROR("osp_dump_dm_by_apcid: file open failure  \n");
        return OSP_ERROR;
    }

    ret = fwrite((char *)virt_addr, sizeof(char), ulLen, fp);
    if(ret < 0)
    {
        UCP_PRINT_ERROR("osp_dump_dm_by_apcid: fwrite error ret:%d\n", ret);
        fclose(fp);
        return OSP_ERROR;
    }

    fflush(fp);
    fclose(fp);

    return OSP_OK;
}

int8_t osp_show_dm_by_apcid(uint8_t           ucApcId, uint64_t phy_addr, uint32_t ulLen)
{
    int32_t  ret                = OSP_OK;
    uint64_t virt_addr          = 0;
    uint64_t tmp_phy_addr       = 0;

    if(ulLen > SPU_DM_SIZE)
    {
        UCP_PRINT_ERROR("osp_show_dm_by_apcid: ulLen:%u error\r\n", ulLen);        
        return OSP_ERROR;
    }
    
    tmp_phy_addr = APE_DM_BASE_PHY_ADDR + ucApcId*APC_DM_LEN +(phy_addr - APC_DM_LEN);

    ret = osp_phy_to_virt(  APE_DM, tmp_phy_addr, &virt_addr);
    if(ret != OSP_OK)
    {
        UCP_PRINT_ERROR("osp_dump_proc phy_addr:0x%lx virt_addr:0x%lx\n", phy_addr, virt_addr);
        return OSP_ERROR;
    }

    osp_dump_phy_mem(tmp_phy_addr, ulLen, phy_addr);
	//osp_mem_print((char *)&temp_vir_addr, ulLen);

    return OSP_OK;
}


OSP_STATUS osp_dump_proc(char *pName, module_type_e        module, uint64_t phy_addr, uint64_t ulLen)
{
    int32_t  ret             = 0;
    uint64_t virt_addr       = 0;
    static FILE *fp          = NULL;
    
    if ((NULL == pName) || (0 == ulLen) || (0 == phy_addr))
    {        
        UCP_PRINT_ERROR("osp_dump_proc pName:%s ulLen:%ld phy_addr:%ld\n", pName, ulLen, phy_addr);
        return OSP_ERROR;
    }

    ret = osp_dump_len_is_ok(module, ulLen);
    if(ret != OSP_OK)
    {
        UCP_PRINT_ERROR("osp_dump_proc ulLen:%ld\n", ulLen);
        return OSP_ERROR;
    }

    ret = osp_phy_to_virt(  module, phy_addr, &virt_addr);
    if(ret != OSP_OK)
    {
        UCP_PRINT_ERROR("osp_dump_proc module:%d phy_addr:0x%lx virt_addr:0x%lx\n",module, phy_addr, virt_addr);
        return OSP_ERROR;
    }
	
	fp = fopen(pName, "wb+");
    if (fp < 0)
    {
        UCP_PRINT_ERROR(" file open failure  \n");
        return OSP_ERROR;
    }
        
    ret = fwrite((char *)virt_addr, sizeof(char), ulLen, fp);
    if(ret < 0)
    {
        UCP_PRINT_ERROR("fwrite error ret:%d\n", ret);
        fclose(fp);
        return OSP_ERROR;
    }
    
    fflush(fp);
    fclose(fp);
    
    return OSP_OK;
}

int32_t osp_dump_phy_mem(uint64_t phy_addr, uint32_t len, uint64_t tmp_addr)
{
    uint64_t addr_temp = OSP_ROUND_DOWN(phy_addr,OSP_DISPLAY_PAGE_LEN);
    uint64_t addr_offset = phy_addr - addr_temp;
    uint32_t *mem_vir_addr,*temp_vir_addr; 
    uint32_t i,j;
    int32_t display_fd = 1;
    
    if(OSP_DISPLAY_MAX_LEN < len)
    {
       return OSP_ERROR; 
    }

    //printf("phy_addr=%#llx, mmap_addr=%#llx,virt_addr=%#llx,len = %d:\n",phy_addr,addr_temp,len); 
    //printf("phy_addr=%#lx, mmap_addr=%#lx,len = %d\n",phy_addr,addr_temp,len);
    

    display_fd = open("/dev/mem", O_RDWR|O_SYNC);
    if(display_fd < 0)
    {
        printf("open /dev/mem error\n");
        return OSP_ERROR;
    }

    
    mem_vir_addr = (uint32_t*)mmap(NULL, (OSP_DISPLAY_PAGE_LEN << 1), PROT_READ|PROT_WRITE, MAP_SHARED, display_fd, addr_temp);
    if((uint32_t*)OSP_ERROR == mem_vir_addr)
    {
        printf("mmap error!! return value is %ld\n",(uint64_t)mem_vir_addr);
        return OSP_ERROR;
    }
    
    temp_vir_addr = mem_vir_addr + (addr_offset >> 2);

    for(i = 0; i < len; i += 16)
    {//不足16字节也显示4个字
        printf("0x%016lx: ",tmp_addr + i);
        
        for(j = 0; j < 4; j++)
        {
            printf("0x%08x  ",*temp_vir_addr++);
        }

        printf("\n");
    }
    
    munmap((void*)mem_vir_addr,(OSP_DISPLAY_PAGE_LEN << 1));
    close(display_fd);

    return OSP_OK;

}


void osp_dump_dm_test(uint8_t ucApcId, uint64_t ullAddr, uint32_t ullen)
{
    char abuf[4096]             = {0};
    uint32_t i                  = 0;
    uint64_t u64_start_offset = 0;
    char filename[36]           = {0};
    
    for(i =0; i<ullen;i++)
    {
        abuf[i] = i;
    }

    switch (ucApcId)
     {
         case APC_CORE_ID_0:
         {
             u64_start_offset = 0;
             break;
         }
         case APC_CORE_ID_1:
         {
             u64_start_offset = SPU_DM_SIZE;
             break;
         }
         case APC_CORE_ID_2:
         {
             u64_start_offset = SPU_DM_SIZE*2;
             break;
         }
         case APC_CORE_ID_3:
         {
             u64_start_offset = SPU_DM_SIZE*3;
             break;
         }
         default:
         {
             UCP_PRINT_ERROR("osp_show_dm_by_apcid: ucApcId:%u error\r\n", ucApcId);
             break;
         }
     }

    memcpy(gp_static_dm_mem+u64_start_offset, abuf, ullen);

    osp_show_dm_by_apcid(ucApcId, ullAddr,ullen);

    sprintf(filename, "apc%d.bin",ucApcId);
    osp_dump_dm_by_apcid(filename,    ucApcId, ullAddr, ullen);

    //osp_dump_proc("test1125",pbuf,ullen);

    //osp_dump_dis_mem(pbuf, ullen);

    //osp_write_diaglog(gp_dump_buf, ullen, 0, 0x62);         
    
    return;
}

void osp_mem_print(char *addr , uint32_t ulLen)
{
    uint32_t i;
    if (NULL == addr)
    {
        return;
    }
    
    if (ulLen > 0x200000)
    {
        return;
    }
        
    for (i = 0; i < ulLen; i++)
    {
        if ((i & 0x7) == 0)
        {
            printf("%p: ", addr+i);
        }

        printf("%02x  ", addr[i]);
        
        if ((i & 0x7) == 0x7)
        {
            printf("\n");
        }
    }

    printf("\n");

    return;
}


void osp_dump_dis_mem(char* addr, uint32_t ulLen)
{
    char *p         = NULL;
    uint32_t i        = 0;
    uint32_t len      = 0;

    if (NULL == addr)
    {
        return;
    }
    
    if (ulLen > 0x100000)
    {
        return;
    }
    
    p = addr;
    
    for (i = 0; i < ulLen; i++)
    {
        if ((i & 0x7) == 0)
        {
            len += sprintf(gp_dump_buf + len, "%p : ", p+i);
        }
        len += sprintf(gp_dump_buf + len, "%02x  ", p[i]);
        
        if ((i & 0x7) == 0x7)
            len += sprintf(gp_dump_buf + len, "%c", '\n');
    }
    
    gp_dump_buf[len] = '\0';

    return;
}





