3、HFP协议详解(上):服务级连接建立、AT指令集、+CIEV指示器、+CLIP来电显示

各位同学,今天我们来啃HFP协议这块硬骨头。说实话,HFP是我在车载蓝牙开发中打交道最多的协议之一。你想想看,车上最常用的两个场景——打电话和听音乐,HFP管的就是前者。很多刚入行的工程师觉得HFP不就是传个语音吗?其实里面的门道多着呢。

这一讲我们先聚焦HFP的上半部分:服务级连接怎么建起来的、AT指令怎么玩、还有那些烦人的指示器和来电显示。我保证,把这些搞懂了,你调试车载蓝牙通话功能时至少能少掉一半头发。

3.1 服务级连接建立:HF和AG的“握手”过程

HFP里有两个角色:HF(Hands-Free,也就是你的车载设备)和AG(Audio Gateway,通常是手机)。服务级连接,说白了就是HF和AG之间建立一条控制通道。这条通道走的是RFCOMM,也就是蓝牙串口模拟协议。

我刚开始做项目时,总以为只要RFCOMM连上了就万事大吉。结果有一次,RFCOMM连接成功了,但手机就是不认车载设备。后来才发现,服务级连接还需要交换一些“身份信息”。

具体流程是这样的:

  1. RFCOMM连接建立:HF向AG发起RFCOMM连接请求,AG同意后,一条串口通道就通了。
  2. AT+BRSF交换:HF发送AT+BRSF=<supported_features>,告诉AG自己支持哪些功能。AG回复+BRSF: <supported_features>,告诉HF它支持哪些功能。这一步很重要,决定了后面哪些功能能用。
  3. AT+CIND读取指示器:HF发送AT+CIND=?查询AG支持哪些指示器,再用AT+CIND?读取当前值。
  4. AT+CMER设置事件报告:HF发送AT+CMER=3,0,0,1,告诉AG“我要开始收事件通知了”。
  5. AT+CHLD设置呼叫保持:HF发送AT+CHLD=?查询AG支持的呼叫保持能力。

嗯,这里要注意:AT+BRSF这一步如果没做好,后面很多功能都会出问题。我曾经遇到过一个奇葩case,HF上报的支持特性里漏了“三个呼叫”标志,结果三方通话功能死活调不通。

关键点:服务级连接的核心就是HF和AG互相“亮底牌”。你支持什么,我支持什么,大家说清楚了再干活。

3.2 AT指令集:HFP的控制语言

AT指令,全称是Attention指令。这玩意儿最早是给调制解调器用的,蓝牙协议栈把它搬过来控制电话功能。说白了,就是HF通过发AT指令让AG做事情,AG通过AT响应告诉HF结果。

HFP里常用的AT指令我列一下:

AT指令 功能 示例
ATD 拨打电话 ATD13800138000;
ATA 接听来电 ATA
AT+CHUP 挂断电话 AT+CHUP
AT+VTS 发送DTMF音 AT+VTS=1
AT+BTRH 查询/设置呼叫保持状态 AT+BTRH?
AT+CLIP 来电显示设置 AT+CLIP=1

AT指令的格式其实很简单:AT<命令>[参数]。响应格式一般是<前缀>: <值>或者直接OK/ERROR

我个人习惯在调试时先用串口工具手动发AT指令,看看AG怎么回复。这样能快速定位问题是出在HF端还是AG端。你想想看,如果手动发ATD10086;能拨通,但车载设备拨不通,那问题肯定在HF的代码里。

调试技巧:用蓝牙抓包工具(比如Ellisys或Frontline)抓RFCOMM层的AT指令交互,比看代码日志直观得多。我曾经靠这个手段半小时定位了一个“AT指令超时”的bug。

3.3 +CIEV指示器:AG状态变化的“广播员”

+CIEV是HFP里非常重要的一个机制。AG通过它主动向HF报告状态变化。比如信号强度变了、电池电量低了、有新的呼叫进来了,AG都会发一条+CIEV通知。

指示器分两种:

  • 必选指示器service(服务状态)、call(呼叫状态)、call_setup(呼叫建立状态)、call_held(呼叫保持状态)、signal(信号强度)、roam(漫游状态)、battchg(电池电量)
  • 可选指示器:比如callwaiting(呼叫等待)

举个例子,当手机信号从满格掉到3格时,AG会发:

+CIEV: signal, 3

HF收到后,就可以更新UI上的信号图标。我见过有些车载设备不处理+CIEV,结果用户看到信号图标一直是满格,实际上手机都快没信号了。这种体验很糟糕。

这里有个坑:+CIEV的指示器索引是从0开始的,但AT+CIND?返回的值也是从0开始。我曾经在项目里把索引和值搞混了,导致信号强度显示反了——信号越差图标越满。嗯,这种低级错误犯过一次就够了。

注意事项:HF必须在服务级连接建立时通过AT+CMER启用事件报告,否则AG不会主动发送+CIEV。很多新手忘了这一步,然后抱怨“为什么手机不给我发通知”。

3.4 +CLIP来电显示:谁在打电话?

+CLIP全称是Calling Line Identification Presentation,说白了就是来电显示。当有来电时,AG会发一条+CLIP通知,告诉HF来电号码。

格式是这样的:

+CLIP: <number>,<type>,,,<alpha>,<CLI_validity>

参数说明:

  • <number>:来电号码,字符串形式
  • <type>:号码类型,129表示国内号码,145表示国际号码
  • <alpha>:联系人名称(如果有的话)
  • <CLI_validity>:号码有效性,0表示有效

举个例子:

+CLIP: "13800138000",129,,,"张三",0

HF收到后,就可以在屏幕上显示“张三 13800138000 来电”。

要启用+CLIP,HF需要在服务级连接建立后发送AT+CLIP=1。AG收到后会回复OK,之后有来电就会带上+CLIP通知。

我记得有一次,客户反馈说车载屏幕上不显示来电号码。我查了半天,发现HF发送了AT+CLIP=1,但AG回复了ERROR。后来一查协议,原来有些AG要求必须先建立服务级连接才能设置+CLIP。调整了时序后问题就解决了。

核心要点+CLIP是HFP里用户体验最直接的功能之一。如果来电显示不工作,用户第一反应就是“这车载系统太烂了”。所以调试时一定要优先保证这个功能正常。

3.5 实战经验:服务级连接调试的常见坑

最后分享几个我在项目中踩过的坑,希望能帮大家少走弯路:

  1. RFCOMM通道号搞错:HFP的RFCOMM通道号通常是1,但有些AG会用其他通道。HF应该通过SDP查询来获取正确的通道号,而不是硬编码。
  2. AT指令超时处理:AG处理AT指令需要时间,HF不能发完指令就立刻等响应。我一般设置3秒超时,超时后重试一次。
  3. 多指令并发问题:HF不能同时发多条AT指令,必须等上一条指令的响应回来后再发下一条。否则AG会乱掉。
  4. 编码问题:来电号码可能包含特殊字符,比如+#*。HF解析时要注意转义。

好了,这一讲的内容就到这里。HFP的服务级连接建立、AT指令集、+CIEV指示器和+CLIP来电显示,这些都是HFP协议的基础。下一讲我们会深入HFP的语音连接建立和SCO/eSCO音频传输,那才是真正考验功底的地方。

有什么问题欢迎在课程群里讨论。咱们下节课见。