目录
一.打印管理
简介:
打印管理是管理svr中各模块及svr以上各模块的各类型和级别的打印信息。在线调试模块中的打印管理部分是为提高开发过程中问题分析效率,降低不必要的信息的干扰而设计的一套打印信息分模块,类别及级别可控制输出的方案。
根据打印信息的内容说表明的程序状态,一般将打印信息分为错误打印,警告打印,普通打印三个类别。
错误打印是描述程序发生错误,不可继续完成预定流程的事件描述。
警告打印是描述程序流程或数据发生非预期的改变,而程序有能力进行矫正,不影响程序的正常运行的事件描述。
普通打印是描述程序当前正常的运行状态,运行流程,分支,位置等信息,为分析程序运行过程提供一份数据!
打印级别是为控制打印输出的信息量而定义的。
当程序执行发生错误,指定的操作不能继续执行下去时,这时应该打印相关内容表明程序状态!
例如:接口需要一非空指针参数,但却传递了一NULL指针。
必须的内存分配,但却失败。
api反馈,DEMUX通道打开失败!
卡通信出现错误!
经过多次申请数据仍然错误。
当程序检测到数据不和预期的吻合时,执行到非预期的分支时,这时应该打印相关警告信息。
例如:用户输入的密码错误!
通道数据超时,但可继续等待数据!
数据CRC有错误,但可继续尝试申请数据!
表明动作执行结果,程序执行的流程,分支。跑入if或else,进入了某个case,调用了某个接口等等
例如:调用了demux模块的过滤器申请接口
过滤器申请成功了
程序分支描述
描述指定操作的结果
发生某些正常的事件,demux有数据回调等等。
打印级别除跟类型相关外,就是打印的信息量及信息的重要程度相关。
错误类型的打印,一般设置级别为DLEVEL_HIGH
警告类型的打印,一般设置级别为DLEVEL_HIGH
因为警告和错误的打印信息,通常是重要并且信息输出频率较低的,设置为HIGH级别可以凸显这些信息重要性,并较大可能的防止在配置模块打印信息输出级别时将这些信息的输出关闭。
对于普通打印的打印级别设置,则较为灵活,通常以以下规律设置级别:
DLEVEL_LOW:
循环打印某个信息内容, 打印某个buffer的数据,被频繁调用的流程,而对于分析程序的运行情况,这些流程又不是重要的。
DLEVEL_NORMAL:
这是个比较常设置的级别。一般设置该级别的是表明程序流程分支,又几乎不会影响程序执行效率的打印信息。
DLEVEL_HIGH:
这个级别的使用就得较为谨慎了。使用这个级别一般表明程序执行到了流程的关键点,打印信息是能够有效的判断出程序的执行情况。
对于实际运用情况看,大部分的普通打印应该使用NORMAL级别!高频率的打印使用LOW级别!
一个完整的打印内容,不仅仅表明程序执行到了这里或那里。其更多的表明了程序执行到这里或那里时程序的状态,显示出该状态相关的数据,甚至是时序。
打印推荐使用中文,如果中文表述复杂的,可使用符号,例如:=,:等。
例如: 收到的CAT数据错误,表中CRC=**,实际CRC=**。
申请过滤器失败,PID不能为0x1fff。
指定的节目不存在,NODEID:0x199999。
ERROR()错误打印使用该宏输出,终端会显示为红色,并输出打印所在的函数名和行号;
WARNING()警告打印使用该宏输出,终端会显示为黄色,并输出打印所在的函数名和行号;
TRACE()普通打印使用该宏输出,不改变终端显示颜色,并输出打印所在的函数名和行号;
INFO()普通打印使用该宏输出,不改变终端显示颜色,不输出打印所在函数名和行号,即输出格式和prinf一致;
以上宏都一个对应输出buffer数据的宏,ERROR_BUF(),WARNING_BUF(), TRACE_BUF(),INFO_BUF().
DLEVEL_HIGH,DLEVEL_NORMAL, DLEVEL_LOW分别对应高,普通,低级别。
对于TRACE和INFO的使用的选择,TRACE和INFO的差别在于,INFO没有在打印的开始加入函数名称和行号,也不会自动换行符。所以INFO适合于需要安装原始格式输出的信息,例如在命令行的命令回显中,需要输出类似表格的内容,这时就应该选择INFO。
以下是TRACE的输出:
以下是INFO的输出:
另外一点需要注意的是,FORCE_PRINT_ID, 这是个模块ID,其对应的值是0xFFFFFFFF,如果打印被赋予这个模块ID,打印管理模块会认为这是个需要强制输出的打印信息。当使用了FORCE_PRINT_ID,级别可任意设置。
二.命令行
简介:
命令行是为开发人员和测试人员通过终端控制程序或获取程序状态信息提供的一套机制。操作者通过终端输入命令,命令行依照输入的命令调用对应的代码执行,并输出相关信息。
在线调试模块分为命令行模式和非命令行模式,在命令行模式下可以输入命令并执行,在非命令行模式下,程序不接受用户的终端输入。
和命令名称对应的一段代码段
命令需要用户输入的一些数据,通常是命令后的一串字符串,和shell命令类似
和命令名称对应的代码段是被函数所封装的,这个函数就是命令对应的函数,执行命令就是执行这个函数。
命令和命令之间可以相互调用,被命令调用的命令是它的调用者的关联命令。此调用方式通常用于实现相关信息或动作的执行。
关联参数项是在线调试模块预定义的关键字,即-R项,在命令中有该项参数表明,命令的执行期望一并执行其关联命令。
命令行只是提供了一套命令执行的机制,并未实现命令,命令的实现通常是由各模块自己完成的。所以命令需要通过注册的方式通知命令行,命令名称对应的命令是什么,对应的函数,及其描述信息。
命令对应的函数定义是在线调试模块预定义的,其函数格式为:
static S32 __**(const S8 *param_str, U8 *rdata, U32 rdlen)
返回值表明执行的成功与否;
param_str是参数串(字符串格式,和用户输入的参数一致, 注意已经是出去命令名称后的);
rdata是命令反馈给命令行的字符串数据,命令行将会在命令执行完毕后,输出rdata中的字符串;
rdlen是rdata的buffer大小,命令往rdata中填充数据时要防止溢出。
命令行预定义了命令和命令参数的格式。
命令格式:
命令名称 参数表
参数表格式:
-参数名1参数值1 -参数名2参数值2 …….
参数名由一个大写字母和“-”字符组成,参数值为一字符串,可以没有。每一个参数之间用空格分隔。
例如:es_showinfo –A99
如果命令的参数表是按照命令行预定义的格式书写的,可以使用在线调试模块提供的参数解析函数对参数表进行解析。
cmd_param_split函数可以将参数表中的参数名和参数值,解析为数组形式。
cmd_param_check可以检查参数表中的参数名是否都以”-”开始。
具体参数的解析,可以参考已经实现的命令, 例如:tfca_service_status
命令的实现基本就是按照命令对应的函数定义来定义函数,解析参数表,执行命令相应动作,输出相应信息,释放资源,返回成功或失败!
例如,以下是CA服务的信息显示的命令!
/****************************************************************************
查看TF_CA的服务信息,可提供有选项的显示,需改此函数的参数
命令:
caserviceinfo :显示所有service信息
caserviceinfo -S9889 :显示Service handler为9889的service信息
caserviceinfo -E8899 :显示ECM PID为8899的ECM信息
caserviceinfo -A8888 :显示AUDIO PID为8888的service信息
caserviceinfo -V9999 :显示VIDEO PID为9999的service信息
*****************************************************************************/
S32 um_tfca_service_status(const S8 *param_str,U8 *rdata, U32 rdlen)
{
U32 pid;
U32 i;
SERVICE_HANDLEhandle;
S32 ret;
BOOLshow_relative = FALSE;
if(param_str == param_str || rdata == rdata || rdlen == rdlen)
{
;
}
/*解析参数表,为解析参数表分配资源*/
U32 argc = 10;
cmb_list_t argv;
argv =(cmb_list_t)umapi_malloc(argc*CMD_PARAM_MAX_LEN);
if (argv == NULL)
{
returnES_ERR_NOT_ENOUGH_MEMORY;
}
umapi_memset(argv,0x00, argc*CMD_PARAM_MAX_LEN);
argc =um_cmd_param_split(param_str, argv, argc);
/*检查参数表*/
ret =um_cmd_param_check(argc, argv);
if (ret !=ES_SUCCESS)
{
gotoFREE_RES;
}
for (i = 0;i < argc; i++)
{
/*是否调用管理命令*/
if(argv[i][1] == 'R')
{
show_relative = UM_TRUE;
break;
}
}
if (argc ==0)
{
/*无参数则显示所有信息*/
ret =__tfca_service_info(INVALID_SERVICE_HANDLE);
gotoFREE_RES;
}
for (i = 0; i < argc; i++)
{
switch(argv[i][1])
{
case 'S':
handle = api_atoi(&(argv[i][2]));
ret = __tfca_service_info(handle);
goto FREE_RES;
case 'E':
pid =uai_atoi(&(argv[i][2]));
ret = __tfca_service_ecm_info(pid, show_relative);
goto FREE_RES;
case 'A':
pid = api_atoi(&(argv[i][2]));
ret = __tfca_service_audio_info(pid, show_relative);
goto FREE_RES;
case 'V':
pid = api_atoi(&(argv[i][2]));
ret = __tfca_service_video_info(pid, show_relative);
gotoFREE_RES;
default:
INFO(FORCE_PRINT_ID, DLEVEL_HIGH,"错误参数!%c\n",argv[i][1]);
break;
}
}
FREE_RES:
api_free(argv);
return ret;
}
在解析命令的参数表时,发现有-R项,应该调用关联命令。
如果没有关联命令,可以不处理-R项。
注:关联命令只有1.7.0.0版本之后的版本支持
命令对应的函数中的打印输出,推荐使用INFO。因为INFO不会输出函数名和行号。而模块ID请使用FORCE_PRINT_ID。
命令的注册是通过svr_es_cmd_register接口实现的。
用户需要定义命令表的命令数组,例如:
S32 tfca_entitle_changed(const S8 *param_str, U8 *rdata, U32rdlen)
{
return CA_SUCCESS;
}
S32 tfca_detitle_received(constS8 *param_str, U8 *rdata, U32 rdlen)
{
return CA_SUCCESS;
}
staticES_CMD_FUNCTION_MAP_S tfca_cmd_funs[] =
{
/**************send modulestatus*******************/
{
CA_MODID, /*模块ID*/
tfca_entitle_changed, /*命令对应的函数*/
"entitlechanged", /*命令名称*/
"授权改变!", /*命令帮助信息*/
"", /*命令正则表达式,可不用*/
},
{
CA_MODID,
tfca_detitle_received,
"getdetitlestatus",
"获取未授权存储空间状态!",
"",
},
};
#define TF_CMD_COUNT (sizeof(tfca_cmd_funs)/sizeof(ES_CMD_FUNCTION_MAP_S))
svr_es_cmd_register(tfca_cmd_funs, TF_CMD_COUNT);
在终端按ESC键可进入或退出命令行模式。进入命令行模式时,命令行会关闭打印信息的输出。退出后恢复打印信息的输出配置。
帮助信息分为命令行的帮助信息和命令的帮助信息。
命令行的帮助信息,进入命令行模式后,输入?,help中的一种即可显示命令行帮助信息和命令列表
命令的帮助信息,进入命令行模式后,输入命令名称 ?,即可查看该命令的帮助信息
进入命令行模式后,输入要执行的命令及相关参数,按回车确认即可。在命令的执行过程中,命令行会恢复打印的输出配置,命令执行完毕后关闭打印输出。
命令总长度<1024B (包括回车符)
命令名称长度<20B
参数名及参数长度<100B
命令不可被多线程执行