
01 引言. n( D- s) `! y1 k) }. y" p* U 2 K6 E2 k" w0 i- x; }; h% P 0 A& K/ X3 l( H( _/ r! H9 A6 G' r 7 H: n0 @% L5 i' g( q 通常客户在做低功耗蓝牙模块设计的时候,如果蓝牙模块在实际使用场景中和手持移动设备(如手机等)绑定使用的话,往往会非常注意蓝牙模块与不同品牌、不同型号的手机的兼容性测试。这些测试项目可能包括长时间连接状态的保持,频繁建立连接,或主动断连后再次建立连接等场景。本文描述的问题是客户在其兼容性测试中发现的一个比较典型的问题,即当从设备在与手机端处于连接状态下,从设备启动连接参数更新进程后,会导致断连的问题。由于是兼容性测试,测试设备,特别是作为主设备的手机来自不同的供应商,在兼容低功耗蓝牙协议的基础上,某些细节部分的差异难以避免。所以,本文只论述了该客户问题的分析过程及得出的结果,并不期望涵盖所有类似场景下导致断连的原因。 0 e* M) I0 e/ r: a 0 y! G& N6 T' P& { 02 连接参数更新进程简述) d0 Y2 z" N& ]/ ` K 1 r! Y, N$ _( f9 T6 q) P 低功耗蓝牙的核心规范中有规定,当主从设备建立连接后,可以通过启动特定的进程改变当前连接的相关参数,如连接间隔(ConnInterval),从设备延迟(SlaveLatency)和监控超时(SupervisionTimeout)等。 & k: L5 A+ t# b6 G/ e ! X8 c* L" f4 [: ?5 V# h H* h " H; o) w* \* ^! H: g2 G" y - V, b1 Q. j$ l9 V$ @ " G- o0 y J# M3 m% {+ i1 Z 低功耗蓝牙的核心规范中定义了几个不同的连接参数更新流程,有的流程主设备和从设备都可以启动,有的流程只能由从设备或主设备启动。为避免引入过多对本文关注话题的无用信息,我们在这里只介绍一种由从设备启动的连接参数更新的流程。即由从设备通过调用L2CAP 层的命令的方式启动的连接参数更新流程。 ( z7 n/ [9 L" K ( ]: Y) v4 t( v6 k 流程图如图 1 所示。流程图的前提条件是主从设备端之间已建立连接,从设备希望改变当前已建立连接的连接参数。 7 [- o8 G" Y, b" P$ X* S/ P" F; o H9 a 0 l$ y8 {( A- M+ ?1 K* F , w2 O6 c# K: ~" F5 N 整个流程的步骤解析如下: ' Y9 n' X' m( x4 G8 x2 ~ : R. ^- C" s5 P8 W- a. H 第一步:从设备发起 Connection Parameter Update Request,提交新的连接参数给主设备,希望主设备可以采用这些参数。主设备接收到从设备的 Request 后,会根据自身当前条件(是否能支持这些连接参数)决定是否接受请求。如果接受,则执行第二步;如不接受,则直接跳到第四步拒绝该 Request。 6 x$ A! S6 w- Y Z9 S, Q. T& L6 B 第二步:主设备接受请求,给从设备发送链路层数据包LL_CONNECTION_UPDATE_REQ,该数据包中包含了主设备在分析了从设备在第一步中提交连接参数后,决定最终使用的目标连接参数,并约定在后续的特定连接事件开始使用新的连接参数。 5 L4 Q6 y2 p. v+ |! x; X " U) e: O! {/ h& }& m 2 p. i# H# q/ _" W4 }! p : D$ k. E+ e8 h7 d3 N 3 g; o8 q( e& M- G) \5 g8 E( e : l- V' F! m: J' u7 l 第三步:从设备在接收到 LL_CONNECTION_UPDATE_REQ 数据包后发送一个链路层的空包作为响应,并结束当前连接事件。 , A' f+ w4 [; W 3 q( e9 r, o8 }9 o% t1 b( q 1 ]! j: a6 {# Y1 j* i 第四步:主设备发送 L2CAP 层的 Connection Parameter Update Response 命令,作为对第一步中 Request 命令的回复,回复中的相关标志标明是接受(Accept)还是拒绝(Reject)之前的 Request 命令。如果是接受,则主从设备双方会在第二步中LL_CONNECTION_UPDATE_REQ 数据包中所指定的后续特定连接事件中开始使用新的连接参数,并成功完成连接参数更新过程。! B+ O/ u% A, N 8 a j$ f% q: x4 e! ?0 W * x$ T& t7 `' _ 4 }) P, N. G" T! E' ~$ U6 w ! d- e5 |( V+ C) _9 L+ L7 L7 h 图片$ L4 h* P4 Q3 c. b5 K 图1.连接参数更新流程 ( f. `: o' o0 ^ / v: z4 k' Z& Z' ^ 033 N9 E& |% \$ O$ C x9 z! C+ C: g 客户可能的测试逻辑和问题现象描述 6 s2 i7 g! ]/ h& q4 c 7 O4 N9 S8 K) h6 Z. q# C# x 客户使用智能手机和 ST 的 BlueNRG LP 作为测试的主从设备。客户的兼容性测试中需要使用预设连接间隔和监控超时时间。为了在测试过程中可以实时调整相关参数,需要手机端作为主设备通过私有逻辑将新的连接参数通过低功耗蓝牙连接发送给从设备( BlueNRGLP ), 并由从设备启动上述的更新流程,以完成连接参数的更新并继续执行后续的其他测试项。 ( q% l6 D2 l# F/ h$ I( Z ( f% r3 U, v: u" `2 K4 c7 _ 问题现象: $ } |: l: q5 K% S% V1 [6 k; r, X & W' Z! y$ p0 J 主从设备在完成上述流程第四步后,且主设备发送 Connection Parameter UpdateResponse 命令所给出的响应也是接受的情况下,主从设备在上述流程中第二步LL_CONNECTION_UPDATE_REQ 命令所指定的特定连接事件中开始采用新的连接参数时会发生断连。从设备重新进入广播状态。 5 a7 e+ g8 d5 [6 i3 T+ l& e: Q 客户的疑惑点在于主从设备已经完成了上述连接参数更新的交互,意味着应该可以顺利切换到新的连接参数,没有道理会导致后续的断连,由于作为主设备的智能手机是某大品牌产品,怀疑 BlueNRG 的协议栈是否存在兼容性问题。( z( _6 b- w2 h R4 s ! D7 a3 N% ~0 T" i9 D( p0 y) |5 f1 b4 z " R) a. A4 \/ u% T! p9 t 04 + b0 D/ F$ S5 A" S 问题分析5 {& |8 t2 X$ X( A- c& l5 ^ n % Q& _- t5 U+ a5 R! B$ }' b3 \5 u ' R) f* [+ Z$ j% | U G( a$ j4 D* }1 k& d. z $ q( j: o4 [6 g$ q2 R0 `3 K `5 y& Q 根据问题复现时使用低功耗蓝牙抓包工具所抓取的 log 数据,做如下分析。 ! ~' D" M: P* X4 H 0 |3 Z1 Q Q3 C& C1 u8 e& ^ + l0 ~7 r2 ?% C 4.1.分析 LL_CONNECTION_UPDATE_REQ 数据包内容 3 p/ X1 e( _8 C3 C 7 k, h. u z) @/ N6 |; q5 Y 2 ?1 L% S- i$ W; ?: w ! N' k8 c& S' H2 a3 z 4.1.1. 如图 2 所示,LL_CONNECTION_UPDATE_REQ 数据包内容,需要重点关注如下数据: + v! |+ ?. n9 V0 k# m$ S6 Z 7 ^- H2 y: A3 B2 n' P- C 5 x$ B. T, Z: ^. T1 R9 ?# ^7 r 1. Event counter:29, 表示 LL_CONNECTION_UPDATE_REQ 发送时所在的连接事件编号为 29。2 d; u9 B4 w* g3 s$ G8 T 2. Instant:35:约定在第 35 个连接事件中,主从设备开始使用新的连接参数。 3. Interval:816(1020msec), 表示新的连接间隔为 1.02 秒。- T2 A! S/ e+ n( C9 ]( H 4. Window Size/Window Offset:第 35 个连接事件中,主从设备开始使用新的连接参数进行第一次数据包交互时,接收、发送窗口的定时信息。 / f* Q! S6 d# R+ x& N 图片. K) T2 u- }# D 图2.LL_CONNECTION_UPDATE_REQ PDU 抓包数据: V9 N( U7 o# o5 h9 l , D) N) ~! x" N" H6 ` 9 Y% z8 X) ]# i2 N 4.1.2. 从下图 3 中获取从连接事件 29 到从设备进入广播状态这个过程中每个连接事件及连接时间中数据包收发的时间戳。! e$ Y+ ]- g; ]. x2 L4 H- p / \& z1 W7 y6 a0 o; ]5 @ 5 D7 I. p2 u9 H! g2 ?: v& E 图片 图3.时间戳! h8 J5 T( a9 ]! f% f$ B! J" m; k0 E ( @) c( N# A/ |4 j& O5 L 4 o4 [; Z8 {8 w8 e q& c4 O3 J0 `" r# j+ T 0 Z; h. f# P5 O! X5 I , m6 Z& _% j. N' ?( J5 z( u 7 w5 R+ Y) y' t 从图 3 中可以看出: [2 r3 r! A5 E* h1 x # d9 z+ M1 L5 s6 p 2 r% |3 L. x1 O! s7 J: o3 C & c" E* d! N. | f7 N9 \9 o6 S& ` 1. 从连接事件 29 到连接事件 34,连接间隔为 30ms,即旧的连接间隔。 2. 连接事件 35 中主设备的发包时间和连接事件 34 的开始时间差大大超过 30ms,所以可以再次确认是在连接事件 35,主从设备开始使用新的连接参数。! T# [+ x/ h4 i6 b3 K$ u 3. 从连接事件 35 开始及后续的 3 个连接事件中,只有主设备发送空包,从设备没有发送空包。/ Z0 c% k7 @/ _ 4. 由于新的连接参数的监控超时时间在客户的测试中为 4 秒,所以从设备没有发送空包的 4 个连接事件结束后,即发送了断连。然后,从设备重新开始发送广播包。. B, x5 n( o9 h. [) U! c5 p9 _ 9 I8 p2 T( ^ l 9 ]3 `& J* t5 G" B+ e( O9 B - c' {' o' G: g; S! K 4.1.3. 如下图 4,通过分析抓包 LOG 中各个连接事件、即数据包发送的时间戳后发现:0 J4 E W7 t: E9 a: Y$ H* w0 y " z q4 ?2 _7 d5 C8 Q0 r0 P * D g6 `7 i) K$ u, c' C+ ^! x1 C 1. 通过 LL_CONNECTION_UPDATE_REQ 数据包中 transmitWindowOffset 计算出TransmitWindow 的开始时间点应该在 11.477925s 2. 从抓包的 log 信息中发现,主设备实际的发包时间点在 11.477909s,也就是主设备的发包时间先于蓝牙协议中规定的 TransmitWindow 的起始点,导致从设备无法接收到来自主设备的空包,从而无法在同一连接事件(连接事件 35 及后续的 3 个连接事件)中反馈一个空包,进而导致 4 秒监控超时,最终导致断连。从设备退出连接态后重新进入广播态。: o, `1 h g& O , S- l8 g* o% D0 @( y# u: e5 [0 x 图片 图4.连接事件即数据包发送时间分析 : X, N0 ^2 M" {# c G* h' J: E, x4 W, ^ ) {- ]/ Q o$ B6 D! n / G/ `' S5 |' ], D 05 X% z) e3 \' }# c$ v% b5 p3 v5 b7 x ; U' O; G9 Z, K7 p0 x; w: S" A 小结 % V# g& _8 q b8 a% ` . l' \# K3 r! I) p& f2 a + B! h2 W5 X4 k, i , W4 J! `# l9 w+ m5 W6 U % J: `4 H4 T+ q 上述问题的根本原因是作为主设备的智能手机虽然完成了连接参数更新流程中主从设备之间的交互,但由于其在后续规划的连接事件,规划的射频任务的时间点的偏差而导致了断连。 8 v; v' I# ^0 P& I1 {+ L; x 导致低功耗蓝牙断连的可能原因有很多,上述的情况只是其中一种。本文的意图是介绍上述问题的分析过程,读者可以参照本文展现的分析方法、将其运用到类似问题的解决过程中。( N( \4 s4 w; ?: Z & \( q# U1 d/ N) s5 a 通过对抓包 LOG 中的时间戳的分析,有很大机会可以帮助找到解决问题的突破口。 # M2 t) S( W& C" b4 ` |