前言
平台的搭建除了海思本身对于音视频的处理,难免需要串口网口之类收发指令并做出处理;每个甲方爸爸对于协议的规定肯定有所差异,以最简单的校对系统时间为例,用网口发送协议,通过ini配置文件加载协议变量的方式实现免编译,只更新ini配置文件就可移植产品功能的作用
配置文件的使用
最关键的变量加载办法详见
配置文件编写
新建配置文件如protocol.ini,按照约定格式编写配置文件内容,规定包长21位 包头为0x55,0xAA,识别时间校对的功能码为0xAB
[attr] ini_cmd_length_total = 21; [content] ini_cmd_head1 = 0x55; ini_cmd_head2 = 0xAA; [func_osd] ini_cmd_func_osdenable = 0xA5; ini_cmd_data_mode_osdoff = 1; ini_cmd_data_mode_osdon = 2; ;2开1关 [func_time] ini_cmd_func_timecorrect = 0xAB;
配置文件的加载
按照约定的用法加载配置文件
static int ini_cmd_length_total;//协议规定的包长度 static int ini_cmd_head1;//协议规定的第一个包头B1 static int ini_cmd_head2;//协议规定的第二个包头B2 static int ini_cmd_length;//协议包内的的包长B3 // static int ini_cmd_func;//协议规定的功能码B4 // static int ini_cmd_data_mode;//协议规定的数据区工作模式B5 static int ini_cmd_func_osdenable = 0;//协议规定的OSD功能码B4 static int ini_cmd_data_mode_osdon = 0;//协议规定的OSD数据区工作模式B5 static int ini_cmd_func_timecorrect = 0;//协议规定的时间校正B4 static int ini_cmd_data_mode_timetype = 0;//协议规定的时间校正类型B5 HI_S32 protocol_ini_init() { dictionary * ini ; ini = iniparser_load(PROTOCOLPATH); if (ini==NULL) { fprintf(stderr, "cannot parse file: %s\n", PROTOCOLPATH); return -1 ; } SAMPLE_PRT("config protocol file load success!\n"); ini_cmd_length_total = iniparser_getint(ini,"attr:ini_cmd_length_total",-1); ini_cmd_head1 = iniparser_getint(ini,"content:ini_cmd_head1",-1); ini_cmd_head2 = iniparser_getint(ini,"content:ini_cmd_head2",-1); ini_cmd_func_osdenable = iniparser_getint(ini,"func_osd:ini_cmd_func_osdenable",-1); ini_cmd_data_mode_osdon = iniparser_getint(ini,"func_osd:ini_cmd_data_mode_osdon",-1); ini_cmd_func_timecorrect = iniparser_getint(ini,"func_time:ini_cmd_func_timecorrect",-1); SAMPLE_PRT("ini_cmd_head1 is 0x%x\n",ini_cmd_head1); SAMPLE_PRT("ini_cmd_head2 is 0x%x\n",ini_cmd_head2); SAMPLE_PRT("ini_cmd_func_osdenable is 0x%x\n",ini_cmd_func_osdenable); SAMPLE_PRT("ini_cmd_data_mode_osdon is %d\n",ini_cmd_data_mode_osdon); SAMPLE_PRT("ini_cmd_func_timecorrect is 0x%x\n",ini_cmd_func_timecorrect); iniparser_freedict(ini);//释放dictionary对象(内存) return 0; }
协议处理
以网口为例,收到数据后进入协议解析函数
/*描述 :网口接收线程 *参数 :arg 无参数传入 *返回值:无 *注意 :使用需打开网口服务器端 */ HI_VOID * eth_client_recv_task(HI_VOID *arg) { cpu_set_t mask;//cpu核的集合 cpu_set_t get;//获取在集合中的cpu int num = sysconf(_SC_NPROCESSORS_CONF); printf("frame_check_task:system has %d processor(s)\n", num); CPU_ZERO(&mask);//置空 CPU_SET(0, &mask);//设置亲和力值 if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)//设置线程CPU亲和力 { fprintf(stderr, "set thread affinity failed\n"); } if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0)//获取线程CPU亲和力 { fprintf(stderr, "get thread affinity failed\n"); } int connect_fd = -1; int recv_len; struct sockaddr_in server; socklen_t saddrlen = sizeof(server); // uint8 data_header[] = {0x55, 0xAA}; // unsigned char addchk=0; // uint8 data_header[] = {0x55, 0xAA}; // printf("\nbeforen DataParser\n "); // DataParser *data_parser = parser_init(data_header, sizeof(data_header), NULL, 0, CMD_LENGTH); // printf("\nDataParser INIT SUCCESS\n "); // char* tmp_cmd=(char*)&g_trk_cmd; memset(&server, 0, sizeof(server)); connect_fd = socket(AF_INET, SOCK_STREAM, 0); if (connect_fd < 0) { printf("socket error!\n"); // return NULL; } printf("\nETH CLIENT RECV TEST\n"); server.sin_family = AF_INET; server.sin_port = htons(SERVER_PORT); // server.sin_addr.s_addr = inet_addr(SERVER_IP); server.sin_addr.s_addr = inet_addr(server_ip); if (connect(connect_fd, (struct sockaddr *)&server, saddrlen) < 0) { printf("connect failed!\n"); // return -1; } // char PLATFORM_IP_SET[64]={0}; // char PLATFORM_IP_CMD[]="192.168.0.168"; // sprintf(PLATFORM_IP_SET,"ifconfig eth0 %s up",PLATFORM_IP_CMD); // system(PLATFORM_IP_SET); else { char recvbuf[1024]={0}; while (1) { recv_len = read(connect_fd, recvbuf, sizeof(recvbuf)); if(recv_len) { // printf("\nEth:recv origin data: "); // recvbuf[len] = '\0'; for (int i = 0;i < recv_len ;i++) { printf("%02x ",recvbuf[i]); } printf("\n"); protocol_parser(recvbuf,recv_len); } } close(connect_fd); } return 0; }
解析方法也很简单,规定一下协议
时间类型:uint8,当前版本固定为0x00;
年:uint8,年份-2000;
月:uint8,月份,取值范围1-12;
日:uint8,日期,取值范围1-31;
毫秒:uint32,当前时间的毫秒计数。
HI_S32 protocol_parser(char* recvbuf,int recv_len) { HI_S32 i; // HI_U8 data_header[] = {0x55, 0xAA}; HI_U8 data_header[] = {ini_cmd_head1, ini_cmd_head2}; HI_U8 addchk=0; DataParser *data_parser = parser_init(data_header, sizeof(data_header), NULL, 0, ini_cmd_length_total); char* tmp_cmd=(char*)&g_trk_cmd; /* 解析协议内容 */ for (i = 0;i < recv_len ;i++) { // printf("%02x ",recvbuf[i]); if(parser_put_data(data_parser, recvbuf[i]) == RESULT_TRUE) { /* 赋值给临时结构体tmp_cmd */ tmp_cmd=(char*)&g_trk_cmd; addchk = 0; for(int jj=0;jj<sizeof(g_trk_cmd)-sizeof(data_header);jj++) { tmp_cmd[jj+2]=parser_get_data(data_parser, jj); // printf("%x ",tmp_cmd[jj+2]); } // printf("\n"); /* 校验尾 */ for(int kk = 2;kk < sizeof(g_trk_cmd)-1;kk++) { // addchk += parser_get_data(data_parser, kk); addchk+=tmp_cmd[kk]; // printf("%x ",tmp_cmd[kk]); } // printf("\n"); g_trk_cmd.addchk = parser_get_data(data_parser,(ini_cmd_length_total-1-2));//第19个数,从0开始计18,故-1,又因为去头在-2 // printf("g_trk_cmd.addchk is %x\n",g_trk_cmd.addchk); if(addchk != g_trk_cmd.addchk ) { printf("warning:please check format :tail\n"); printf("addchk is %x\n",addchk); memset_s(((uint8_t*)&g_trk_cmd)+2, sizeof(g_trk_cmd)-sizeof(data_header), 0, sizeof(g_trk_cmd)-sizeof(data_header)); continue; } else { /* 校验成功则往结构体赋值 */ g_trk_cmd.length = tmp_cmd[2]; // printf(" tmp_cmd[2]is %x\n",tmp_cmd[2]); g_trk_cmd.CmdType = tmp_cmd[3]; // printf(" tmp_cmd[3]is %x\n",tmp_cmd[3]); for (int ii = 0; ii < (ini_cmd_length_total-1-2-2) ;ii++)//去头-2去尾-1去功能-1从0开始计数-1 { g_trk_cmd.Para[ii] = tmp_cmd[ii+4];; } } } } if (g_trk_cmd.CmdType == ini_cmd_func_timecorrect) { printf("time correct\n"); unsigned char tmp_year = g_trk_cmd.Para[1]; unsigned char tmp_month = g_trk_cmd.Para[2]; unsigned char tmp_day = g_trk_cmd.Para[3]; unsigned int tmp_ms = (g_trk_cmd.Para[4]<<24)|(g_trk_cmd.Para[5]<<16)|(g_trk_cmd.Para[6]<<8)|(g_trk_cmd.Para[7]); SetSystemTime(tmp_year,tmp_month,tmp_day,tmp_ms); } return 0; }
没有直接传入时分秒,直接传入ms值也可以计算时间
/* *描述 :协议规定的时间校准功能 *参数 :uint32_t tyear 要设的年 * uint32_t tmonth 要设的月 * uint32_t tday 要设的日 * uint32_t tmsecs 要设的毫秒,用于转成时分秒 *返回值:成功返回0 *注意 :无 */ int SetSystemTime(uint32_t tyear,uint32_t tmonth,uint32_t tday,uint32_t tmsecs) { struct tm t_tm; struct timeval tv; time_t timep; uint32_t thour=0; uint32_t tminutes=0; uint32_t tseconds=0; thour = tmsecs / (1000 * 60 * 60); tminutes = (tmsecs % (1000 * 60 * 60)) / (1000 * 60); tseconds = (tmsecs % (1000 * 60)) / 1000; t_tm.tm_sec = tseconds; t_tm.tm_min = tminutes; t_tm.tm_hour = thour; t_tm.tm_mday = tday; t_tm.tm_mon = tmonth - 1; t_tm.tm_year = tyear +2000- 1900; timep=mktime(&t_tm); stime(&timep); return 0; }