這兩天在調試即將完成的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.