/******************************************************************************
版权所有：	
文件名称：	sys_api.c
文件版本：	01.01
创建作者：	xxxxxx
创建日期：	2022-09o
功能说明：	系统接口
其它说明：	
修改记录：
*******************************************************************************/
#include "head.h"

extern int timespec_to_rtchms(struct timespec ts, struct rtc_time_t * p_rtc,int is_round);



/***********************************************************************
函数名称：parseEnvInfo
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-10-31
函数说明：解析环境变量信息
参数说明：*env_buf：环境变量buf首地址
         type_char：环境变量类型字符
         *ver：解析环境变量信息得到的版本信息首地址
返 回 值：true：解析成功 false：解析失败
***********************************************************************/
static bool parseEnvInfo(char* env_buf,char type_char,VERSION* ver)
{
    u8 dat;
    bool ret=false;
    int i,str_len,tab=0;

    str_len = strlen(env_buf);
    for(i=0;i<str_len;i++)
    {
        if(env_buf[i] == type_char)
        {
            tab = i;
        }
        else if(env_buf[i] == 'V' && i == (tab + 1))
        {
            tab = i;
            ret = true;
            continue;
        }

        if(!ret)
            continue;
    
        if(i == (tab + 1))
        {
            dat = atoi(&env_buf[i]);
        }
        if(env_buf[i] == '.')
        {
            if(dat)
            {
                ver->majorVer = dat;
                tab = i;
            }
        }
        else if(ver->majorVer && dat)
        {    
            ver->minorVer = dat;
            break;
        }
    }

    return ret;
}

/***********************************************************************
函数名称：GetUBootVer
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-09-30
函数说明：获取U-Boot版本号
参数说明：none  
返 回 值：版本号对象的首地址 NULL：为获取失败
***********************************************************************/
VERSION *GetUBootVer(void)
{
    char* pboot;
    bool ret=false;
    const char uboot_char = 'U';
    static VERSION g_uBootVer={0};

    pboot = env_get_info(ENV_U_BOOT);
    if(pboot == NULL)
    {
        rt_printf("warning：Get system u-boot version failure!\r\n");
        return NULL;
    }

    ret = parseEnvInfo(pboot,uboot_char,&g_uBootVer);
    if(!ret)
    {
        rt_printf("warning：Get system u-boot version failure!\r\n");
        return NULL;
    }

    if(!g_uBootVer.minorVer && !g_uBootVer.majorVer)
    {
        rt_printf("warning：Get system u-boot version failure!\r\n");
        return NULL;
    }

    rt_printf("Current system u-boot version number：V%02d.%03d\r\n",g_uBootVer.majorVer,g_uBootVer.minorVer);
    
    return &g_uBootVer;
}

/***********************************************************************
函数名称：GetKernelVer
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-09-30
函数说明：获取内核版本号
参数说明：none  
返 回 值：版本号对象的首地址 NULL：为获取失败
***********************************************************************/
VERSION *GetKernelVer(void)
{
    char* pker;
    bool ret=false;
    const char kernel_char = 'K';
    static VERSION g_kernelVer={0};

    pker = env_get_info(ENV_KERNEL);
    if(pker == NULL)
    {
        rt_printf("warning：Get system kernel version failure!\r\n");
        return NULL;
    }

    ret = parseEnvInfo(pker,kernel_char,&g_kernelVer);
    if(!ret)
    {
        rt_printf("warning：Get system kernel version failure!\r\n");
        return NULL;
    }

    if(!g_kernelVer.minorVer && !g_kernelVer.majorVer)
    {
        rt_printf("warning：Get system kernel version failure!\r\n");
        return NULL;
    }

    rt_printf("Current system kernel version number：V%02d.%03d\r\n",g_kernelVer.majorVer,g_kernelVer.minorVer);
    
    return &g_kernelVer;
}

/***********************************************************************
函数名称：GetRootFileSysVer
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-10-31
函数说明：获取文件系统版本号
参数说明：none  
返 回 值：版本号对象的首地址 NULL：为获取失败
***********************************************************************/
VERSION *GetRootFileSysVer(void)
{
    char* proot;
    bool ret=false;
    const char file_sys_char = 'R';
    static VERSION g_fileSysVer={0};

    proot = env_get_info(ENV_ROOT_FS);
    if(proot == NULL)
    {
        rt_printf("warning：Get system file system version failure!\r\n");
        return NULL;
    }

    ret = parseEnvInfo(proot,file_sys_char,&g_fileSysVer);
    if(!ret)
    {
        rt_printf("warning：Get system file system version failure!\r\n");
        return NULL;
    }

    if(!g_fileSysVer.minorVer && !g_fileSysVer.majorVer)
    {
        rt_printf("warning：Get system file system version failure!\r\n");
        return NULL;
    }

    rt_printf("Current system file system version number：V%02d.%03d\r\n",g_fileSysVer.majorVer,g_fileSysVer.minorVer);
    
    return &g_fileSysVer;
}

/***********************************************************************
函数名称：CheckSysProgramVer
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-09-30
函数说明：检查系统程序版本
参数说明：none  
返 回 值：0：版本号合法 非0：版本号非法
***********************************************************************/
int CheckSysProgramVer(void)
{
    int ver_num;    // 版本号
    VERSION *ver;

    ver = GetUBootVer();
    if(ver == NULL)
        return -1;
    ver_num = ver->majorVer*256 + ver->minorVer;
    if(ver_num < UBOOT_VER_BASE)
    {
        rt_printf("warning：Current system u-boot version is low, please upgrade for the u-boot to version higher than or equal V01.%03d\r\n",UBOOT_VER_BASE%256);
        return -2;
    }

    ver = GetKernelVer();
    if(ver == NULL)
        return -3;
    ver_num = ver->majorVer*256 + ver->minorVer;
    if(ver_num < KERNEL_VER_BASE)
    {
        rt_printf("warning：Current system kernel version is low, please upgrade for the kernel to version higher than or equal V01.%03d\r\n",KERNEL_VER_BASE%256);
        return -4;
    }

    ver = GetRootFileSysVer();
    if(ver == NULL)
        return -5;
    ver_num = ver->majorVer*256 + ver->minorVer;
    if(ver_num < ROOT_FILE_SYS_VER_BASE)
    {
        rt_printf("warning：Current system file system version is low, please upgrade for the file system to version higher than or equal V01.%03d\r\n",ROOT_FILE_SYS_VER_BASE%256);
        return -6;
    }

    return 0;
}

/***********************************************************************
函数名称：find_par_cval_param
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：查找遥参参数
参数说明：addr：遥参地址  
返 回 值: 遥参参数实体首地址(获取失败返回NULL指针)
***********************************************************************/
static SET_PARAID* find_par_cval_param(WORD addr)
{
    int i;
    SET_PARAID *pt;

    for(i=0;i<ParaIDNum;i++)
    {
        pt = &tParaID[i];
        if(pt->parId != addr)
            continue;
        
        return pt;
    }

    return NULL;
}

/***********************************************************************
函数名称：set_par_value
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：修改遥参值
参数说明：addr：遥参地址  
         value：写入的值
返 回 值: 0：修改成功 非0：修改失败
***********************************************************************/
int set_par_value(WORD addr,float value)
{
    const SET_PARAID *pt;
    SET_VALUE *psetbuf,*pparabuf,*pcstbuf;

    pt = find_par_cval_param(addr);
    if(pt == NULL)
    {
        rt_printf("%s:地址0x%x在遥参点表里查找失败!\r\n",__func__,addr);
        return -1;
    }

    switch(pt->group_type)
    {
        case SETGROUP_TYPE_BH:
        case SETGROUP_TYPE_PUB:
        	psetbuf = rt_malloc(SET_NUMBER*4);	
	        if(!psetbuf)
        	{
               return -2;
        	}
            if(!ReadSet(m_runsection,(void*)psetbuf))  // 读定值
	        {
	        	GetDefSet((float*)psetbuf);
        	}
            if(pt->group_type == SETGROUP_TYPE_PUB)
            {
                psetbuf[pt->setno].ff = value;
            }
            else
            {
                psetbuf[PUB_SET_NUMBER+pt->setno].ff = value;
            }
            if(SaveSet(m_runsection,(void *)psetbuf))
		    {
			    soe_record_opt(EV_SET_OK,0);
                MakeRunSet(false); 
				rt_err_clr(ERR_CODE_SET,0);
            }
            else
            {
                soe_record_opt(EV_SET_FAIL,0);
            }
        	rt_free(psetbuf); 
            break;
        case SETGROUP_TYPE_PARA:
        	pparabuf = rt_malloc(EQUIP_PARA_NUMBER*4);
            if(!pparabuf)
            {
                return -3;
            }		
            if(!ReadPara((void*)pparabuf,EEP_EQUIP_PARA_ADDR,EQUIP_PARA_NUMBER,&tEquipParaTable[0]))
            {
                GetDefPara((void*)pparabuf,EQUIP_PARA_NUMBER,&tEquipParaTable[0]);		
	        }
            if(tEquipParaTable[pt->setno].wType == SETTYPE_IP)
                pparabuf[pt->setno].tt = (DWORD)value;
            else
                pparabuf[pt->setno].ff = value;
            if(SavePara((void*)pparabuf,EEP_EQUIP_PARA_ADDR,EQUIP_PARA_NUMBER,&tEquipParaTable[0]))
	    	{
               soe_record_opt(EV_EQUPARA_OK,0);
			    MakeRunPara(false, false); 
			    rt_err_clr(ERR_CODE_EQU_PARA,0);
            }
            else
            {
                soe_record_opt(EV_EQUPARA_FAIL,0);
            }
            rt_free(pparabuf); 
            break;
        case SETGROUP_TYPE_CSTSET:
            pcstbuf = rt_malloc(CSTSET_NUMBER*4);
            if(!pcstbuf)
            {
                return -4;
            }	
            if(!ReadPara((void*)pcstbuf,EEP_CSTSET_ADDR,CSTSET_NUMBER,&tCstSetTable[0]))
        	{
		        GetDefPara((void*)pcstbuf,CSTSET_NUMBER,&tCstSetTable[0]);
	        }
            pcstbuf[pt->setno].ff = value;
            if(SavePara((void*)pcstbuf,EEP_CSTSET_ADDR,CSTSET_NUMBER,&tCstSetTable[0]))
		    {
		    	soe_record_opt(EV_CSTSET_OK,0);
		    	MakeRunSet(false); 
			    rt_err_clr(ERR_CODE_SET_IN,0);
	    	}
		    else
		    {
		    	soe_record_opt(EV_CSTSET_FAIL,0);
		    }
            rt_free(pcstbuf); 
            break;
        default:
            return -5;
    }

	return 0;
}

/***********************************************************************
函数名称：get_par_nane
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：获取遥参描述
参数说明：addr：遥参的地址  
返 回 值: 获取的遥参描述首地址(获取失败返回NULL指针)
***********************************************************************/
char *get_par_nane(WORD addr)
{
    char *name=NULL;
    const SET_PARAID *pt = find_par_cval_param(addr);
    if(pt == NULL)
    {
        rt_printf("%s:地址0x%x在遥参点表里查找失败!\r\n",__func__,addr);
        return NULL;
    }

    switch(pt->group_type)
    {
        case SETGROUP_TYPE_BH:
            name = (char*)tSwSetTable[pt->setno].szName;
            break;
        case SETGROUP_TYPE_PUB:
            name = (char*)tPubSetTable[pt->setno].szName;
            break;
        case SETGROUP_TYPE_PARA:
            name = (char*)tEquipParaTable[pt->setno].szName;
            break;
        case SETGROUP_TYPE_CSTSET:
            name = (char*)tCstSetTable[pt->setno].szName;
            break;
        default:
            break;
    }

	return name;
}

/***********************************************************************
函数名称：get_par_nane
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：获取遥参描述
参数说明：addr：遥参的地址  
返 回 值: 获取的遥参描述首地址(获取失败返回NULL指针)
***********************************************************************/
int get_par_value_str(WORD addr,char *buf,const int buf_len)
{
    int str_len;
    DWORD u32_val;
    SET_VALUE tmp_val;
    const SET_PARAID *pt; 
    char tmp_buf[128]={0};
    const TSETTABLE *table;
    struct timespec ts={0};
    struct rtc_time_t time={0};  
    SET_VALUE *psetbuf,*pparabuf,*pcstbuf; 

    if(buf==NULL)
        return -1;

    pt = find_par_cval_param(addr);
    if(pt==NULL)
    {
        rt_printf("%s:地址0x%x在遥参点表里查找失败!\r\n",__func__,addr);
        return -2;
    }

    switch(pt->group_type)
    {
        case SETGROUP_TYPE_BH:
        case SETGROUP_TYPE_PUB:
        	psetbuf = rt_malloc(SET_NUMBER*4);	
	        if(!psetbuf)
        	{
               return -3;
        	}
            if(!ReadSet(m_runsection,(void*)psetbuf))  
	        {
	        	GetDefSet((float*)psetbuf);
        	}
            if(pt->group_type == SETGROUP_TYPE_PUB)
            {
                table = &tPubSetTable[pt->setno];
                tmp_val.ff = psetbuf[pt->setno].ff;
            }
            else
            {
                table = &tSwSetTable[pt->setno];
                tmp_val.ff = psetbuf[PUB_SET_NUMBER+pt->setno].ff;
            }
        	rt_free(psetbuf); 
            break;
        case SETGROUP_TYPE_PARA:
        	pparabuf = rt_malloc(EQUIP_PARA_NUMBER*4);
            if(!pparabuf)
            {
                return -4;
            }		
            if(!ReadPara((void*)pparabuf,EEP_EQUIP_PARA_ADDR,EQUIP_PARA_NUMBER,&tEquipParaTable[0]))
            {
                GetDefPara((void*)pparabuf,EQUIP_PARA_NUMBER,&tEquipParaTable[0]);		
	        }
            table = &tEquipParaTable[pt->setno];	
            tmp_val.ff = pparabuf[pt->setno].ff;
            rt_free(pparabuf); 
            break;
        case SETGROUP_TYPE_CSTSET:
            pcstbuf = rt_malloc(CSTSET_NUMBER*4);
            if(!pcstbuf)
            {
                return -5;
            }	
            if(!ReadPara((void*)pcstbuf,EEP_CSTSET_ADDR,CSTSET_NUMBER,&tCstSetTable[0]))
        	{
		        GetDefPara((void*)pcstbuf,CSTSET_NUMBER,&tCstSetTable[0]);
	        }
            table = &tCstSetTable[pt->setno];
            tmp_val.ff = pcstbuf[pt->setno].ff;
            rt_free(pcstbuf); 
            break;
        default:
            return -6;
    }

    u32_val = (DWORD)tmp_val.ff;
    switch(table->wType)
    {
        case SETTYPE_LIST:  
            str_len = sprintf(tmp_buf,"%s",table->list[u32_val].str);
            break;
        case SETTYPE_IP:
            str_len = sprintf(tmp_buf,"%d.%d.%d.%d",(tmp_val.tt>>24)&0xFF,(tmp_val.tt>>16)&0xFF,(tmp_val.tt>>8)&0xFF,tmp_val.tt&0xFF);	
            break;
        case SETTYPE_YMD:
            ts.tv_sec = tmp_val.tt;	
            timespec_to_rtc(ts,&time,1);
            str_len = sprintf(tmp_buf,"%04d-%02d-%02d",2000+time.year,time.month,time.day);	
            break;
        case SETTYPE_HMS:
            ts.tv_sec = tmp_val.tt;	
            timespec_to_rtchms(ts,&time,1);
            str_len = sprintf(tmp_buf,"%02d:%02d:%02d",time.hour,time.min,time.ms%1000);	
            break;
        default:
            str_len = sprintf(tmp_buf,"%.3f",tmp_val.ff);
            strcat(tmp_buf,SetUints[table->wUnit]);
            str_len += strlen(SetUints[table->wUnit]);
            break;
    }

    if(str_len > buf_len)
    {
        str_len = buf_len;
    }

    memcpy(buf,tmp_buf,str_len);

	return str_len;
}

/***********************************************************************
函数名称：get_plc_yx_nane
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：获取遥信描述
参数说明：addr：遥信地址 
         *buf：缓存遥信描述的首地址
         buf_len：缓存区的字节数
返 回 值: 获取遥信描述的长度
***********************************************************************/
int get_plc_yx_nane(WORD addr,char *buf,const int buf_len)
{
    int index;
    int name_len;
    char name[128]={0};

    if(buf == NULL)
        return 0;

    index = tbl_cp2index(addr);
    if(index < 0)
    {
        return 0;
    }

    tbl_getname(RES_TYPE_YX,index,name);

    name_len = strlen(name);

    if(name_len > buf_len)
    {
        name_len = buf_len;
    }

    memcpy(buf,name,name_len);

	return name_len;
}

/***********************************************************************
函数名称：get_plc_yx_val
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：获取遥信值
参数说明：addr：遥信地址 
返 回 值: 获取遥信的遥信值(正常值：0、1、2 其他：获取失败)
***********************************************************************/
int get_plc_yx_val(WORD addr)
{
    int val,index;

    index = tbl_cp2index(addr);
    if(index < 0)
        return -1;

    val = tbl_get_yx(index,0);

	return val;
}

/***********************************************************************
函数名称：set_plc_yk
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-09
函数说明：控制遥控开出
参数说明：addr：遥控地址 
         cmd：命令码 1：合 0：分 
返 回 值: 0：遥控成功 非0：遥控失败
***********************************************************************/
int set_plc_yk(WORD addr,int cmd)
{
    int i,ret;
    int yk_cmd;

    for(i=0;i<g_table_head->do_num;i++)
    {
        if(addr != g_do_table[i].cp)  
		{
			continue;
		}

        if(cmd == 0)
        {
            yk_cmd = YK_VAL_TZ;
        }
        else if(cmd == 1)
        {
            yk_cmd = YK_VAL_HZ;
        }
        else
        {
            return -1;  // 遥控命令码错误
        }

        ret = RemoteCtrl(YK_TYPE_SEL,i,yk_cmd,MASTER_MAINTAIN); // 预置

        if(ret == 0)
            return RemoteCtrl(YK_TYPE_EXE,i,yk_cmd,MASTER_MAINTAIN);    // 执行
        else
            return ret;
    }

	return -255;    // 遥控地址错误
}

/***********************************************************************
函数名称：get_led_name
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-10
函数说明：获取LED描述
参数说明：slot：板卡号
         addr：LED地址 
返 回 值: led描述的长度 0：失败
***********************************************************************/
char *get_led_name(int slot,int addr)
{
    char *name;
    struct led_config *pt;

    if(slot >= EQU_SLOT_NUM_MAX)
        return NULL;

    pt = &g_led_slot[slot];

    if(addr >= pt->num || pt->sn[addr].no == LED_NULL)
        return NULL;

    if(pt->sn[addr].sw)  // 开关的
    {
        int index = pt->sn[addr].no%SW_LED_NUM;
        name = (char*)g_sw_led_name[index];
    }
    else    // 公共的
    {
        if(pt->sn[addr].no >= PUB_LED_NUM)
            return NULL;

        name = (char*)g_pub_led_name[pt->sn[addr].no];
    }
    
    return name;
}

/***********************************************************************
函数名称：get_led_value
函数版本：01.01
创建作者：xxxxxx
创建日期：2022-11-10
函数说明：获取LED状态值
参数说明：slot：板卡号
         addr：led地址 
返 回 值: 0灭 1快闪 2慢闪 3常亮 其他：错误
***********************************************************************/
int get_led_value(int slot,int addr)
{
    int status;
    struct led_config *pt;

    if(slot >= EQU_SLOT_NUM_MAX)
        return -1;

    pt = &g_led_slot[slot];

    if(addr >= pt->num )
        return -2;

    if(pt->sn[addr].sw >= (SWITCH_NUM_MAX+1) || pt->sn[addr].no == LED_NULL || pt->sn[addr].no >= SW_LED_NUM)
        return -3;

    status = g_led_stu[pt->sn[addr].sw][pt->sn[addr].no];

    return status;
}


int rt_gunzip(char *filename)
{
	int ret;
	
	char *argv[] = {"/bin/gunzip","-f",filename,NULL};
	char *envp[] = { NULL };
	
	ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);

	rt_printf("rt_gunzip=%d,%s\r\n\r\n",ret,filename);

	return ret;
}

int rt_bunzip2(char *filename)
{
	int ret;
	
	char *argv[] = {"/usr/bin/bunzip2","-f",filename,NULL};
	char *envp[] = { NULL };
	
	ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);

	rt_printf("rt_bunzip2=%d,%s\r\n\r\n",ret,filename);
	return ret;
}


int rt_untar_a(char *filename)
{
	int ret=-1;
		
	if(strstr(filename,".gz"))
	{
		ret =rt_gunzip(filename);		
	}
	else if(strstr(filename,".bz2"))
	{		
		ret =rt_bunzip2(filename);		
	}
			
	return ret;
}

