主题中讨论的其他器件:CC2640
概述
当 iPhone 7连接到我们的设备时、我们的应用程序似乎会自动通过 LL_LENGTH_REQ 控制数据包作为其第一个业务订单发送。 数据包显示我们的传输数据包大小和间隔是 L2CAP 标准、但接收数据包大小是数据长度扩展的最大值。 iPhone 7以 LL_LENGTH_RSP 响应、表示它可以支持针对 DLE 的最高 Tx 和 Rx 数据长度(数据长度扩展)。 这会导致我们的接收缓冲区大小调整为不必要的大、从而消耗大量堆。 LL_LENGTH_REQ 数据包仍会发送到连接到 iPhone 6s (支持 BLE 4.2、但不支持数据长度扩展)的情况下、但被带有"未知操作码"控制数据包的6s 拒绝、这不会导致我们的应用调整缓冲区大小。 似乎问题不在于 iPhone 7本身、而在于它支持 DLE。 最终、我们要做的是防止发送长度控制数据包、在发送之前"拦截"该数据包并修改其值、或者(如果可能)找出某种方法来设置我们自己的最大 Rx 速率和数据包大小。
详细信息:
在过去几个月中、我们一直在处理与 iPhone 7连接相关的问题。 通过使用 HEAPMGR_metrics 和 HEAPMGR_Profiler、我们确定了导致此问题的原因是堆故障、这就是为什么仅仅添加更多代码就会减少堆的可用存储器。 当 heapmgr.h 堆用完时、分配函数返回 false、并且无法分配指定的对象。 这可能导致连接中断或无响应。 我们调整了一些堆栈大小以避免此问题、从而为我们提供足够的内存来连接到 iPhone 7。 当连接到 iPhone 7时、我们发现 HEAPMGR_MEMMAX 指示堆分配的最高点、它将比 iPhone 6连接后的值大大约1000。
进一步研究、事实证明堆上占用空间最多的对象是通过调用 osal_bufmgr.c 中的 osal_BM_alloc 创建的缓冲区 缓冲区的大小为265 (当它们进入堆时更大一点)、如果堆具有足够的空间、则其中四个缓冲区在 iPhone 7连接期间始终处于活动状态。 如果没有足够的空间供它们使用、应用程序会不断尝试创建它们、如果没有足够的堆、则会导致恒定的堆故障。 当连接终止时、任何现有的缓冲区都会被释放。
当我连接 iPhone 6而不是 iPhone 7时、这些缓冲区会被创建、但大小为41、而不是265。 41 - 27 (最小 LCAP 数据包大小)=大小为14的缓冲器标头、265 - 14 = 251、这是最大数据长度扩展数据包大小。 因此、这些缓冲区似乎是数据包接收缓冲区。 但是、当连接 iPhone 7时、将 MAX_PDU_SIZE 设置为27似乎对接收缓冲区大小没有任何影响。 同样、将 MAX_NUM_PDU 设置为其他值似乎不会影响产生的缓冲区数量。 我不确定是否已禁用数据长度扩展。 在我的 build_config.opt 中、我现在已经注释掉了所有-dv42_features 定义、这是肯定的、但似乎没有帮助。 在 build_config.opt 的注释中、显示"EXT_DATA_LEN_CFG-在控制器中启用扩展数据长度功能(始终启用)"。 这是否意味着无法将其关闭? 或者、如果定义了它、是否意味着无法在运行时禁用它?
我还在由编译运行的 factory_config.opt 中看到行"-dble_V42_feature=V42_features + privacy_1_2_CFG+EXT_DATA_LEN_CFG"。 (此文件有警告、请勿更改它。) 这种定义是否会使 DLE 始终启用?
如果使用 DLE、文档指出连接应以数据包 MTU 23 (包括 L2CAP 头时、数据包大小为27)和连接间隔328us 开始、并且必须在主设备和从设备之间协商对这些连接参数的更改。
当我们的应用程序收到 GAP_LINK_established 事件时、我们执行的操作之一是调用 GATT_ExchangeMTU。 我们发送的 clientRxMTU 为23、最大 L2CAP MTU 大小。 我们收到一个 ATT_EXCHANGE_MTU_RSP、其中服务器 RxMTU 为23、如果我正确理解 CC2640开发人员指南(http://www.ti.com/lit/ug/swru393d/swru393d.pdf、5.5.2.1)、则表明该连接的 MTU 大小应为23。 我们不会收到 ATT_MTU_Update_event、我假设这是因为 MTU 未从默认值更改、因此连接 MTU 未更新。 无论在 iPhone 7或6上、这种行为都是相同的。
但是、在接收 ATT_EXCHANGE_MTU_RSP 之前、我们还会收到 HCI_BLE_DATA_LENGTH_CHANGE_EVENT。 此事件发生在创建任何265大小的缓冲区之前,并且无论是否启动交换 MTU 过程都将发生。 当我们连接到 iPhone 6s 时、不会生成此事件。 从事件中读取值、我们得到:
maxTxOctets:27.
maxTxReceiveTime:328
maxRxOctets:251
maxRxReceiveTime:2120
查看监听器日志、我在连接开始后立即找到了 LL_LENGTH_REQ 和 LL_LENGTH_RSP 数据包。 (我之前忽略过这一点、因为 SmartRF 数据包监听器2.18.1.0显然不会自动标记 LL_LENGTH_REQ 和 LL_LENGTH_RSP 数据包;这些数据包只是显示为"控制"数据包、我必须双击数据包并选择"数据包详细信息"以查看数据、以防其他人进入此数据包)。 我们发送的 LL_LENGTH_REQ 具有与 HCI_BLE_DATA_LENGTH_CHANGE_EVENT 中相同的值、而 iPhone 7以可能的最大 Tx 和 Rx 数据包大小进行响应。 这会导致上面列出的值、因为使用了 Tx 和 Rx 的最小互值。 当连接到 iPhone 6s 时、此数据包仍会发送。 6s 支持 BLE 4.2、但不支持数据长度扩展、并使用"未知操作码"对控制数据包进行响应。 在连接期间、接收缓冲器保持 L2CAP 数据包大小。
使用 CCS 中的 Modules 视图并在函数 lSetupLenCtrlPacket()上设置断点,我发现在设置初始 Rx 缓冲区(使用 lCreateRxBuffer 进行跟踪)之后(很快就会在 GAP_LINK_established _event 之后)调用该断点。
因此、这里的问题似乎在于 LL_LENGTH_REQ 数据包的传出值、我们似乎找不到任何方法来使用定义或常量来控制这些值。
很抱歉、这里的帖子很长;这是我们一直在尝试破解的内容、因为 iPhone 7的额外堆使用限制了我们添加新功能。 我们非常感谢您的任何帮助或想法!