在蓝牙协议栈开发过程中,有时需要预先知道 LLCP。本文将介绍如何利用 Trace 机制实现 LLCP 预览功能。
实现原理
打开 Trace PLATFORM_TRACE_ID_LLCP
类型,Controller 会在接收到 LLCP 时通过 Trace 回调函数导出数据。
我们可以在回调函数里截获 PLATFORM_TRACE_ID_LLCP
,并预览数据。这个的“预览”包含两层含义:
- Controller 尚未处理该 PDU(Controller 将于 Trace 回调完成后处理 PDU);
- 只可读取 PDU 内容,不可修改。
让我们详细介绍实现方法。
1. Trace 数据结构
PLATFORM_TRACE_ID_LLCP
Trace 类型使用的头信息结构如下:
#pragma pack (push, 1)
typedef struct
{
uint32_t A;
uint32_t B;
uint8_t id;
uint8_t tag;
} header_t;
#pragma pack (pop)
这个结构使用 #pragma pack (push, 1)
指令确保内存对齐。
2. Trace 回调处理
假设 cb_trace_read_llcp
函数为 Trace 回调函数,在函数开头添加代码截获接收到的 LLCP:
static uint32_t cb_trace_read_llcp(const platform_evt_trace_t *Trace, void *ctx)
{
if (Trace->len1 == sizeof(header_t))
{
const header_t *p = (const header_t *)Trace->data1;
if ((p->id == PLATFORM_TRACE_ID_LLCP) && (p->tag & 1))
{
const uint8_t *p8 = (const uint8_t *)Trace->data2;
llcp_preview(p->tag >> 1, p8[0], p8 + 1, Trace->len2 - 1);
}
}
// ...
return 0;
}
3. PDU 预览显示
llcp_preview
函数负责预览 LLCP。下面的参考代码打印了关于 LLCP 的完整信息:
- 连接句柄(handle)
- 操作码(op_code)
- 控制数据
static void llcp_preview(hci_con_handle_t handle, uint8_t op_code, const uint8_t *ctr_data, int ctr_data_len)
{
platform_printf("LLCP[%d] OP %02x: ", handle, op_code);
printf_hexdump(ctr_data, ctr_data_len);
platform_printf("\n");
}
特殊用法
目前 SDK 未提供设置公司 ID 的接口,暂时可以通过直接修改 LLCP_VERSION_IND
内容的方法修改公司 ID(修改这个值不影响 Controller 的行为和流程。)
在下面的代码里,公司 ID 被修改为 0xABCD
,小版本号被修改为 0x1234
。
#pragma pack (push, 1)
typedef struct
{
uint8_t version;
uint16_t company_id;
uint16_t subversion;
} llcp_version_ind_t;
#pragma pack (pop)
static uint32_t cb_trace_read_llcp(const platform_evt_trace_t *trace, void *ctx)
{
if (trace->len1 == sizeof(header_t))
{
const header_t *p = (const header_t *)trace->data1;
// 判断是否为发送方向的 LLCP
if ((p->id == PLATFORM_TRACE_ID_LLCP) && (0 == (p->tag & 1)))
{
const uint8_t *p8 = (const uint8_t *)trace->data2;
const uint16_t con_handle = p->tag >> 1;
const uint8_t op_code = p8[0];
const int ctrl_data_len = trace->len2 - 1;
uint8_t * ctrl_data = (uint8_t *)p8 + 1;
// 判断是否为 LLCP_VERSION_IND
if ((op_code == 0x0c) && (ctrl_data_len == sizeof(llcp_version_ind_t)))
{
llcp_version_ind_t *ver_ind = (llcp_version_ind_t *)(ctrl_data);
ver_ind->company_id = 0xABCD;
ver_ind->subversion = 0x1234;
}
}
}
// ...
return 0;
}
总结
利用 Trace 机制实现的 PDU 预览功能,能帮助开发者实时监控 LLCP 通信,实现必要功能。
温馨提示:不要忘记设置
PLATFORM_CFG_TRACE_MASK
,其中要包含 PLATFORM_TRACE_ID_LLCP
。