一些背景
我目前正在使用 Zephyr 在嵌入式系统上使用低功耗蓝牙。
在服务/特性/CCCD发现过程中(我的嵌入式设备是BLE中心),我想存储每个特性,以便以后使用它们(主要是读取它们)。
为此,我使用 Zephyr 提供的链表,并使用
k_calloc()
分配我的节点。
typedef struct lst_chrc_node_s {
sys_snode_t node;
struct bt_uuid *uuid;
uint16_t value_handle;
uint8_t properties;
uint8_t type;
} lst_chrc_node_t;
lst_chrc_node_t *list_create_node(struct bt_gatt_chrc *chrc, uint8_t type)
{
lst_chrc_node_t *new_node = k_calloc(1, sizeof(new_node));
if (!new_node)
return NULL;
new_node->uuid = k_calloc(1, sizeof(new_node->uuid));
if (!new_node->uuid)
{
k_free(new_node);
return NULL;
}
print_uuid128("UUID that will be store", chrc->uuid);
*new_node->uuid = *chrc->uuid;
new_node->value_handle = chrc->value_handle;
new_node->properties = chrc->properties;
new_node->type = type;
print_uuid128("UUID that was stored ", new_node->uuid);
return new_node;
}
如您所见,我想存储在函数参数中传递的 struct
bt_gatt_chrc *chrc
。但是,该结构包含一个指向另一个名为 bt_uuid
的 struct的常量指针。这个 bt_uuid 结构很重要,因为我需要它从 BLE 外设读取正确的特征。
我的链表的节点没有直接的
bt_gatt_chrc
结构,但具有一一相同的成员。这是因为我无法直接将 bt_gatt_chrc 从参数复制到链表的节点,因为指向 bt_uuid
的常量指针在发现服务、特征和 CCCD 时具有相同的地址(当发现不同的 GATT 属性类型时它会发生变化,但仍然相同)对于此类属性)。
问题
创建节点并复制其中的数据后,bt_uuid 值与我从 BLE 外设收到的值不同。
这是一个标准 UUID 的日志:
[00:00:04.293,914] <inf> main: UUID received UUID 128: 070002a4-5720-0045-2020-0013072a0000
[00:00:04.293,945] <inf> main: UUID that will be store UUID 128: 070002a4-5720-0045-2020-0013072a0000
[00:00:04.293,975] <inf> main: UUID that was stored UUID 128: 00000d00-0d61-8c00-0200-020003000000
我觉得很愚蠢,因为AFAIU,我的问题似乎显然在这一行
*new_node->uuid = *chrc->uuid;
,但我不明白我做错了什么。我尝试将 const struct bt_uuid
转换为 struct bt_uuid
,结果也不好(看起来更错误,因为整个 128 位 UUID 在每个标准特性(由蓝牙 SIG 定义)之间发生变化,而不是停留在非常接近相同(比如特性之间只有 2-3 位数字发生变化,而无需转换结构)。
是否因为
bt_uuid
是“暂定”类型,所以我不能这样使用它?有人可以重新表述一下什么是暂定类型吗?我显然不确定我对此的理解。
来自uuid.h:
enum {
BT_UUID_TYPE_16,
BT_UUID_TYPE_32,
BT_UUID_TYPE_128,
};
#define BT_UUID_SIZE_16 2
#define BT_UUID_SIZE_32 4
#define BT_UUID_SIZE_128 16
struct bt_uuid {
uint8_t type;
};
struct bt_uuid_16 {
struct bt_uuid uuid;
uint16_t val;
};
struct bt_uuid_32 {
struct bt_uuid uuid;
uint32_t val;
};
struct bt_uuid_128 {
struct bt_uuid uuid;
uint8_t val[BT_UUID_SIZE_128];
};
struct bt_uuid *
应指向足够的内存来存储 struct bt_uuid_16
、struct bt_uuid_32
或 struct bt_uuid_128
,具体取决于 type
成员 BT_UUID_TYPE_16
、BT_UUID_TYPE_32
或 BT_UUID_TYPE_128
的值.
编辑:OP原始代码中的
new_node = k_calloc(1, sizeof(new_node));
行是错误的(由下面的comment中的@chux和问题的comment中的@ach发现),并且已被在下面的代码中更正了。
未经测试、修改过的代码:
lst_chrc_node_t *list_create_node(struct bt_gatt_chrc *chrc, uint8_t type)
{
lst_chrc_node_t *new_node;
size_t bt_uuid_size;
switch (chrc->uuid->type)
{
case BT_UUID_TYPE_16:
bt_uuid_size = sizeof(struct bt_uuid_16);
break;
case BT_UUID_TYPE_32:
bt_uuid_size = sizeof(struct bt_uuid_32);
break;
case BT_UUID_TYPE_128:
bt_uuid_size = sizeof(struct bt_uuid_128);
break;
default:
return NULL;
}
new_node = k_calloc(1, sizeof(*new_node));
if (!new_node)
return NULL;
new_node->uuid = k_calloc(1, bt_uuid_size);
if (!new_node->uuid)
{
k_free(new_node);
return NULL;
}
print_uuid128("UUID that will be store", chrc->uuid);
memcpy(new_node->uuid, chrc->uuid, bt_uuid_size);
new_node->value_handle = chrc->value_handle;
new_node->properties = chrc->properties;
new_node->type = type;
print_uuid128("UUID that was stored ", new_node->uuid);
return new_node;
}