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

#include "pet_sm_mgt.h"
#include "msg_transfer_mem.h"
#include "ospHeartbeat.h"
#include "ospSem.h"
//#include "ospSoftQue.h"
//#include "ospMsg.h"
//#include "ospDbg.h"
#include "ucp_printf.h"
#include "ospDelay.h"
#include "ospDump.h"
#include "ospCfgToBin.h"
#include "ospSwTimer.h"

#define RESTART_REGISTER_LEN                (0x1000)
#define RESTART_REGISTER_SUBCTRL0_BASE      (0x04A88000)
#define RESTART_REGISTER_SUBCTRL1_BASE      (0x04AD8000)
#define RESTART_REGISTER_SUBCTRL2_BASE      (0x04B28000)
#define RESTART_REGISTER_SUBCTRL3_BASE      (0x04B78000)
#define RESTART_REGISTER_RST_CFG_BASE       (0x04550000)


#define OSP_HEARTBEAT_NAME      "OspHeartbeatTimer"
#define OSP_HEARTBEAT_TMR_OUT   (1000)  /* 1000ms->1s */ 
#define OSP_HB_MAX_CORE_NUM     2//(12) /* 监测的最多核数 */
#define OSP_HB_MAX_COUNTER      (3)     /* 失信计数最大值 */

#define OSP_HEARTBEAT_OFF       (1)     /* 不检测心跳 */
#define OSP_HEARTBEAT_ON        (0)     /* 检测心跳 */

#define HB_NO_CHECK             (1)     /* 不再被检测 */
#define HB_CHECK                (0)     /* 被检测 */

static uint8_t gsu8OspHeartbeatSwitch = 0;      /* 默认检测心跳 */
static OspHeartbeatInfo_t gsstOspHeartbeatCounter[OSP_HB_MAX_CORE_NUM];

uint8_t* gu8virRegAddr = NULL;
uint8_t* gu8VirSubctrlAddr = NULL;
uint8_t* gu8VirRstCfgAddr  = NULL;

/* 获取对应核的心跳计数 */
uint32_t OspGetHeartbeat(uint8_t u8CoreId)
{
	PetSmLocalMgt_t* pPetSmLocalMgt = get_pet_sm_local_mgt();
	UcpHandshake_t*	pHandshake = pPetSmLocalMgt->pHandshake;
    return pHandshake->heartbeat[u8CoreId];
}


/* 重启寄存器 */
int8_t OspRestartRegister(uint8_t u8CoreId)
{
    uint64_t u64SubctrlAddr = 0;
    int iOspRestartFd = -1;
    int8_t  i8ApcId = -1;

    switch(u8CoreId)
    {
        case 0:
        case 1:
        {
            i8ApcId = 0;
            u64SubctrlAddr = RESTART_REGISTER_SUBCTRL0_BASE;
            break;
        }
        case 2:
        case 3:
        {
            i8ApcId = 1;
            u64SubctrlAddr = RESTART_REGISTER_SUBCTRL1_BASE;
            break;
        }
        case 4:
        case 5:
        {
            i8ApcId = 2;
            u64SubctrlAddr = RESTART_REGISTER_SUBCTRL2_BASE;
            break;
        }
        case 6:
        case 7:
        {
            i8ApcId = 3;
            u64SubctrlAddr = RESTART_REGISTER_SUBCTRL3_BASE;
            break;
        }
        default:
        {
            i8ApcId = -1;
            break;
        }
    }

    if (-1 == i8ApcId)
    {
        UCP_PRINT_ERROR("OspRestartRegister: coreid(%d) error.\r\n", u8CoreId);
        return OSP_ERROR;
    }
    UCP_PRINT_DEBUG("OspRestartRegister: Start to restart register(coreid = %d).\r\n", u8CoreId);

    iOspRestartFd = open("/dev/mem", O_RDWR|O_SYNC);
    if (0 > iOspRestartFd)
    {
        UCP_PRINT_ERROR("OspRestartRegister: open /dev/mem error.\r\n");
        return OSP_ERROR;
    }
    UCP_PRINT_DEBUG("OspRestartRegister: start mmap(subctrl).\r\n");

    gu8VirSubctrlAddr = (uint8_t*)mmap(NULL, RESTART_REGISTER_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, iOspRestartFd, u64SubctrlAddr);
    if ((uint8_t*)(-1) == gu8VirSubctrlAddr)
    {
        UCP_PRINT_ERROR("OspRestartRegister: mmap error.\r\n");
        return OSP_ERROR;
    }
    UCP_PRINT_DEBUG("OspRestartRegister: start mmap(rst_cfg).\r\n");

    gu8VirRstCfgAddr = (uint8_t*)mmap(NULL, RESTART_REGISTER_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, iOspRestartFd, RESTART_REGISTER_RST_CFG_BASE);
    if ((uint8_t*)(-1) == gu8VirRstCfgAddr)
    {
        UCP_PRINT_ERROR("OspRestartRegister: mmap error.\r\n");
        return OSP_ERROR;
    }
    UCP_PRINT_DEBUG("OspRestartRegister: Set register for restart.\r\n");

    /* 根据coreid设置对应寄存器 */

    
    *((volatile uint32_t*)(gu8VirSubctrlAddr)) |= 0xC;              //enable ISO, set bit2,3 to 1
    *((volatile uint32_t*)(gu8VirSubctrlAddr)) &= 0xFFFFFFFD;       //apc_arstn is valid, reset bus of apc0
    *((volatile uint32_t*)(gu8VirRstCfgAddr+0x274+i8ApcId*4)) = (0xFFFFFF & (*((volatile uint32_t*)(gu8VirRstCfgAddr+i8ApcId*4)))) | (4 << 24); //reset apc0 core, set bit24 to 0
    osp_delay(1000);
    *((volatile uint32_t*)(gu8VirSubctrlAddr)) |= 0x2;              //apc_arstn is invalid, dereset bus of apc0
    *((volatile uint32_t*)(gu8VirRstCfgAddr+0x274+i8ApcId*4)) = (0xFFFFFF & (*((volatile uint32_t*)(gu8VirRstCfgAddr+i8ApcId*4)))) | (5 << 24); //dereset apc0 core, set bit24 to 1
    *((volatile uint32_t*)(gu8VirSubctrlAddr)) &= 0xFFFFFFF3;       //disable ISO, set bit2,3 to 0

    return OSP_OK;
}

/* DUMP DM内存 */
int8_t OspDumpDm2Ddr(uint8_t u8CoreId)
{
#ifdef HEARTBEAT_ENABLE
    return osp_dump_dm_by_coreid(u8CoreId);
#else
    return OSP_OK;
#endif
}

#define OSP_LOAD_APE0_OUT   "./loadelf_8g -ape dump_im.ape0.out %d 1"
#define OSP_LOAD_APE1_OUT   "./loadelf_8g -ape dump_im.ape1.out %d 1"

/* 二次加载 */
int8_t Osp2Loader(uint8_t u8CoreId)
{
    char cmd[128] = {0};
    if (u8CoreId <= 7)
    {
        if (0 == u8CoreId%2)
        {
            sprintf(cmd, OSP_LOAD_APE0_OUT, u8CoreId);
        }
        else
        {
            sprintf(cmd, OSP_LOAD_APE1_OUT, u8CoreId);
        }
        UCP_PRINT_DEBUG("Osp2Loader: cmd = %s \r\n", cmd);
        system(cmd);
        return OSP_OK;
    }
    return OSP_ERROR;
}

/* DUMP IM内存 */
int8_t OspDumpIm2Ddr(uint8_t u8CoreId)
{
#ifdef HEARTBEAT_ENABLE
    return osp_get_im2ddr_to_file(u8CoreId);
#else
    return OSP_OK;
#endif
}

#define OSP_GET_DUMP_DM2TMP "./exp_file dump_dm_core* /tmp/dumpfile"
#define OSP_GET_DMMP_IM2TMP "./exp_file dump_im_core* /tmp/dumpfile"

void OspGetFileOut(uint8_t u8CoreId)
{
    //UCP_PRINT_DEBUG("OspGetFileOut: cmd = %s \r\n", OSP_GET_DUMP_DM2TMP);
    system(OSP_GET_DUMP_DM2TMP);

    //UCP_PRINT_DEBUG("OspGetFileOut: cmd = %s \r\n", OSP_GET_DMMP_IM2TMP);
    system(OSP_GET_DMMP_IM2TMP);

    //UCP_PRINT_DEBUG("OspGetFileOut: OK \r\n");
    return ;
}

/* 重启 */
void OspRestartPro(uint8_t u8CoreId)
{
    int8_t ret = 0;

    UCP_PRINT_DEBUG("OspRestartPro : u8CoreId = %d \r\n", u8CoreId);

    if (7 < u8CoreId)
    {
        UCP_PRINT_ERROR("OspRestartPro: core_id = %d(big).\r\n", u8CoreId);
        return ;
    }

    ret = OspRestartRegister(u8CoreId);
    if (OSP_ERROR == ret)
    {
        UCP_PRINT_ERROR("OspRestartPro: Call OspRestartRegister return error.\r\n");
        return ;
    }

    //UCP_PRINT_DEBUG("OspRestartPro : OspRestartRegister return ok \r\n");

    ret = OspDumpDm2Ddr(u8CoreId);
    if (OSP_ERROR == ret)
    {
        UCP_PRINT_ERROR("OspRestartPro: Call OspDumpDm2Ddr return error.\r\n");
        return ;
    }
    //UCP_PRINT_DEBUG("OspRestartPro : OspDumpDm2Ddr return ok \r\n");

    ret = Osp2Loader(u8CoreId);
    if (OSP_ERROR == ret)
    {
        UCP_PRINT_ERROR("OspRestartPro: Call Osp2Loader return error.\r\n");
        return ;
    }
    //UCP_PRINT_DEBUG("OspRestartPro : Osp2Loader return ok \r\n");

    ret = OspDumpIm2Ddr(u8CoreId);
    if (OSP_ERROR == ret)
    {
        UCP_PRINT_ERROR("OspRestartPro: Call OspDumpIm2Ddr return error.\r\n");
        return ;
    }
    //UCP_PRINT_DEBUG("OspRestartPro : OspDumpIm2Ddr return ok \r\n");

    OspGetFileOut(u8CoreId);

    UCP_PRINT_DEBUG("****************************************************** \r\n");
    return ;
}


/* 心跳定时器超时处理函数
1. 若不需要监测直接返回
2. 监测每个核的心跳计数
   2.1 与上次的对比，一致则看是否达到最大失信计数--重启
   2.2 不一致，更新上次计数
*/
void OspHeartbeatTimeoutPro(void)
{
    static uint32_t su32Cnt = 0;
    uint8_t  u8CoreId = 0;
    uint32_t u32HeartbeatCunt = 0;
    su32Cnt++;
    //UCP_PRINT_DEBUG("OspHeartbeatTimeoutPro: Enter >>> (%d)", su32Cnt);

    /* 若心跳监测关闭，则不监测各核心跳 */
    if (OSP_HEARTBEAT_OFF == gsu8OspHeartbeatSwitch)
    {
        UCP_PRINT_ERROR("OspHeartbeatTimeoutPro: .gsu8OspHeartbeatSwitch is OSP_HEARTBEAT_OFF.\r\n");
        return ;
    }

    /* 监测各核心跳 */
    for( u8CoreId = 0; u8CoreId < OSP_HB_MAX_CORE_NUM; u8CoreId++)
    {
        if (HB_NO_CHECK == gsstOspHeartbeatCounter[u8CoreId].u32CheckFlag)
        {
            continue;
        }
        u32HeartbeatCunt = OspGetHeartbeat(u8CoreId);
        UCP_PRINT_DEBUG("OspHeartbeatTimeoutPro: coreId(%d) LastBeat(%d) NowBeat(%d)\r\n", u8CoreId, gsstOspHeartbeatCounter[u8CoreId].u32LastCounter, u32HeartbeatCunt);
        if (gsstOspHeartbeatCounter[u8CoreId].u32LastCounter == u32HeartbeatCunt)
        {
            gsstOspHeartbeatCounter[u8CoreId].u32LossCounter++;

            if (gsstOspHeartbeatCounter[u8CoreId].u32LossCounter > OSP_HB_MAX_COUNTER)
            {
                UCP_PRINT_ERROR("OspHeartbeatTimeoutPro: CoreID(%d) should be restart...\r\n", u8CoreId);
                OspRestartPro(u8CoreId);
                if (0 == u8CoreId%2)
                {
                    gsstOspHeartbeatCounter[u8CoreId].u32CheckFlag = HB_NO_CHECK;
                    gsstOspHeartbeatCounter[u8CoreId+1].u32CheckFlag = HB_NO_CHECK;
                }
                else
                {
                    gsstOspHeartbeatCounter[u8CoreId].u32CheckFlag = HB_NO_CHECK;
                    gsstOspHeartbeatCounter[u8CoreId-1].u32CheckFlag = HB_NO_CHECK;
                }
                return ;
            }
        }
        else
        {
            gsstOspHeartbeatCounter[u8CoreId].u32LastCounter = u32HeartbeatCunt;
            gsstOspHeartbeatCounter[u8CoreId].u32LossCounter = 0;
        }
    }
    return ;
}

/* 心跳处理函数：
1. 创建定时器
2. 启动定时器
*/
int8_t OspHeartbeatPro(void)
{
    int8_t ret = 0;
    uint8_t u8TimerIndex = 0;

    memset(gsstOspHeartbeatCounter, 0, sizeof(gsstOspHeartbeatCounter));
    gsu8OspHeartbeatSwitch = OSP_HEARTBEAT_ON;
    //return OSP_OK;

    /* 创建定时器 */
    ret = OspTmrCreate((const char*)OSP_HEARTBEAT_NAME, OSP_HEARTBEAT_TMR_OUT, OSP_TMR_PERIODIC, (OSP_CALLBACK)OspHeartbeatTimeoutPro, NULL);
    if (OSP_ERROR == ret)
    {
        UCP_PRINT_ERROR("OspHeartbeatPro: OspTmrCreate return error.\r\n");
        return OSP_ERROR;
    }
    u8TimerIndex = ret;

    /* 启动定时器 */
    ret = OspTmrStart(u8TimerIndex);
    if (OSP_ERROR == ret)
    {
        UCP_PRINT_ERROR("OspHeartbeatPro: OspTmrStart return error.\r\n");
        return OSP_ERROR;
    }
    return OSP_OK;
}


