ESP-IDF NimBLE:将接收的BLE数据转为整数/十六进制并存储
解决方案:修改BLE写入回调存储数据为整数/十六进制格式
首先明确:ctxt->om->om_data 是指向接收到的BLE字节数据的指针,ctxt->om->om_len 是数据长度。以下提供两种适配不同需求的实现方式:
方式1:存储为十六进制字节数组(保留原始数据)
适合需要保留BLE原始字节数据的场景,每个字节对应十六进制的两位。我们可以定义全局缓冲区存储数据(新手场景下先简化处理,多连接场景可后续加锁优化)。
修改后的核心代码
#include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_wifi.h" #include "esp_system.h" #include "esp_event.h" #include "nvs_flash.h" #include "driver/gpio.h" #include <stdio.h> #include "esp_log.h" #include "esp_nimble_hci.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "host/ble_hs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" #include "sdkconfig.h" #include "string.h" char *TAG = "BLE-Server"; uint8_t ble_addr_type; void ble_app_advertise(void); // 定义全局缓冲区,适配BLE单包最大20字节的常规场景 #define MAX_RECV_BUF_LEN 20 uint8_t ble_recv_buf[MAX_RECV_BUF_LEN]; size_t ble_recv_len = 0; // 记录实际接收数据长度 // Write data to ESP32 defined as server static int device_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { // 校验数据长度,避免缓冲区溢出 if (ctxt->om->om_len > MAX_RECV_BUF_LEN) { ESP_LOGE(TAG, "Data too long, max support %d bytes", MAX_RECV_BUF_LEN); return BLE_HS_EINVAL; } // 将BLE接收数据复制到全局缓冲区 memcpy(ble_recv_buf, ctxt->om->om_data, ctxt->om->om_len); ble_recv_len = ctxt->om->om_len; // 以十六进制格式打印(替换原printf) ESP_LOGI(TAG, "Received BLE data (hex): "); for (size_t i = 0; i < ble_recv_len; i++) { printf("%02X ", ble_recv_buf[i]); } printf("\n"); return 0; } // 其余代码保持不变...
方式2:解析为整数类型(如uint16_t/uint32_t)
如果客户端发送固定长度的整数数据(比如2字节表示16位整数),可直接解析为对应整数类型。注意BLE通信通常采用小端字节序,需做字节序转换适配主机端。
修改后的核心代码(以解析16位无符号整数为例)
#include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_wifi.h" #include "esp_system.h" #include "esp_event.h" #include "nvs_flash.h" #include "driver/gpio.h" #include <stdio.h> #include "esp_log.h" #include "esp_nimble_hci.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "host/ble_hs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" #include "sdkconfig.h" #include "string.h" #include "endian.h" // 用于字节序转换 char *TAG = "BLE-Server"; uint8_t ble_addr_type; void ble_app_advertise(void); // 全局变量存储解析后的16位整数 uint16_t ble_recv_uint16 = 0; // Write data to ESP32 defined as server static int device_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { // 校验数据长度是否匹配16位整数要求 if (ctxt->om->om_len != sizeof(uint16_t)) { ESP_LOGE(TAG, "Invalid length for uint16_t, expected %d bytes", sizeof(uint16_t)); return BLE_HS_EINVAL; } // 小端字节序转主机字节序并存储 ble_recv_uint16 = le16toh(*(uint16_t *)ctxt->om->om_data); // 打印解析结果(十进制/十六进制可选) ESP_LOGI(TAG, "Received BLE data (uint16): %u", ble_recv_uint16); // ESP_LOGI(TAG, "Received BLE data (hex uint16): 0x%04X", ble_recv_uint16); return 0; } // 其余代码保持不变...
关键注意事项
- 直接强转
ctxt->om->om_data时,必须确保数据长度和目标类型匹配,否则会引发内存越界问题。 - 全局变量是新手场景下最便捷的存储方式,多连接场景可改用连接句柄关联的数组或哈希表存储。
- 字节序转换:遵循BLE规范用
le16toh/le32toh转换,即使主机本身是小端(如ESP32),保持规范写法也能提升代码兼容性。
内容的提问来源于stack exchange,提问作者o-ozdemir
相关产品推荐
相关产品推荐

