这两天在调试即将完成的Hands Free Profile的AG部分代码,在调试与HF Client设备收发AT指令部分时遇到了AT+CNUM指令HF Client端 “解析AT指令错误”的提示。由于HFP中,AT指令参数都是存放在字符串中进行收发的,字符串的解析就至关重要,而在解掉bug的同时,我也在不断地学习。本文便介绍一个在HF Client端利用sscanf()按格式读取字符串时的一个小技巧%n。
首先,我们来看一眼HFP 1.7.1协议关于CNUM指令的介绍。
其中字符串的格式如图所示," [,,<service>] " 为option选项。在我的AG模块中并不选择发送service,所以从AG发送到HF Client端的字符内容应该为 "\r\n +CNUM: ,<number>,<type>\r\n"。 AG和HF Client的字符串解析代码如下:
/* AG 端字符串内容*/
if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
tBTA_AG_RES_DATA ag_res;
memset(&ag_res, 0, sizeof (ag_res));
BTC_TRACE_EVENT("cnum_response: number = %s, type = %d", number, type);
if (number) {
sprintf(ag_res.str, ",\"%s\",%d",number, type);
} else {
sprintf(ag_res.str, ",\"\",%d",type);
}
ag_res.ok_flag = BTA_AG_OK_DONE;
BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_CNUM_RES, &ag_res);
这里顺便解释一下,%32[^\"]的意思是:忽略掉所有的 “ 字符并最多读取32字节的数据。
/* HF Client端字符串解析*/
AT_CHECK_EVENT(buffer, "+CNUM:");
res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service, &offset);
if (res < 0) {
return NULL;
}
if (res == 0) {
res = sscanf(buffer, ",\"\",%hu,,%hu%n", &type, &service, &offset);
if (res < 0) {
return NULL;
}
/* numstr is not matched in second attempt, correct this */
res++;
numstr[0] = '\0';
}
if (res < 2) {
return NULL;
}
buffer += offset;
printf("buffer :%s, offset %d\n",buffer,offset);
AT_CHECK_RN(buffer);
当使用上述代码进行测试时,HF Client端的错误信息如图:
上图打印中,buffer内为HF Client端已经去除掉 “+CNUM: ”部分剩余的打印,可以看出并不符合协议要求的CNUM指令字符串,故出现报错。经过分析,原因处在offset的数值上。offset是HF Client端在解析字符串时进行赋值的,而HF Client端代码的offset仅仅出现在了option选项(service)的后面,这就导致在并不发送service的情况下offset是一个随机值,此处为2,也就是说,HF Client方面并不认为service是一个option选项,这与协议相违背。故,应该予以修改。
/* 原 HF Client 代码*/
res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service, &offset);
/* 修改后 HF Client 代码*/
res = sscanf(buffer, ",\"%32[^\"]\",%hu%n,,%hu%n", numstr, &type, &offset, &service, &offset);
从上端代码可以看出,我在type对应的%hu后面加上了一个%n来更新offset的值,并且保持了service对应%hu后面%n和offset不便,这样就可以利用一句代码适配协议中service选项的option要求。由于sscanf()在读取数据时遵循从左至右的方向性进行,所以只需要在type后对offset进行更新(更新后为16),便可以正确地进行解析。修改后效果如下:
=====================THE END=========================
如果觉得有用,请点赞、收藏、关注、或转发给你觉得有用的人。
本帐号会不定期记录与ESP-IDF调试小技巧,或者其他功能模块介绍。
LOVE AND SHARE. PEACE.