在蓝牙协议栈开发过程中,有时需要预先知道 LLCP。本文将介绍如何利用 trace 机制实现 LLCP 预览功能。

实现原理

打开 trace PLATFORM_TRACE_ID_LLCP 类型,Controller 会在接收到 LLCP 时通过 trace 回调函数导出数据。 我们可以在回调函数里截获 PLATFORM_TRACE_ID_LLCP,并预览数据。这个的“预览”包含两层含义:

  1. Controller 尚未处理该 PDU(Controller 将于 trace 回调完成后处理 PDU);
  2. 只可读取 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, trace_rtt_t *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");
}

总结

利用 trace 机制实现的 PDU 预览功能,能帮助开发者实时监控 LLCP 通信,实现必要功能。