Просмотр исходного кода

add: nimble库支持ibeacon模式

Wendal Chen 3 лет назад
Родитель
Сommit
e0fcac768d

+ 4 - 0
components/nimble/inc/luat_nimble.h

@@ -34,5 +34,9 @@ int luat_nimble_blecent_scan(void);
 
 int luat_nimble_blecent_connect(const char* addr);
 
+
+int luat_nimble_ibeacon_setup(void *uuid128, uint16_t major,
+                         uint16_t minor, int8_t measured_power);
+
 #endif
 

+ 51 - 26
components/nimble/src/luat_lib_nimble.c

@@ -6,32 +6,8 @@
 @demo    nimble
 @tag LUAT_USE_NIMBLE
 @usage
--- 本库当前支持Air101/Air103/ESP32/ESP32C3
--- 理论上支持ESP32C2/ESP32S2/ESP32S3,但尚未测试
-
--- 本库当前仅支持BLE Peripheral, 其他模式待添加
-sys.taskInit(function()
-    -- 初始化nimble, 因为当仅支持作为主机,也没有其他配置项
-    nimble.init("LuatOS-Wendal") -- 选取一个蓝牙设备名称
-    sys.wait(1000)
-
-    --local data = string.char(0x5A, 0xA5, 0x12, 0x34, 0x56)
-    local data = "1234567890"
-    while 1 do
-        sys.wait(5000)
-        -- Central端建立连接并订阅后, 可上报数据
-        nimble.send_msg(1, 0, data)
-    end
-end
-sys.subscribe("BLE_GATT_WRITE_CHR", function(info, data)
-    -- Central端建立连接后, 可往设备写入数据
-    log.info("ble", "Data Got", data:toHex())
-end)
-
--- 配合微信小程序 "LuatOS蓝牙调试"
--- 1. 若开发板无天线, 将手机尽量靠近芯片也能搜到
--- 2. 该小程序是开源的, 每次write会自动分包
--- https://gitee.com/openLuat/luatos-miniapps
+-- 本库当前支持Air101/Air103/ESP32/ESP32C3/ESP32S3
+-- 用法请查阅demo, API函数会归于指定的模式
 */
 
 #include "luat_base.h"
@@ -70,6 +46,7 @@ ble_uuid_any_t ble_peripheral_write_uuid;
 @return bool 成功与否
 @usage
 -- 参考 demo/nimble
+-- 本函数对所有模式都适用
 */
 static int l_nimble_init(lua_State* L) {
     int rc = 0;
@@ -97,6 +74,7 @@ static int l_nimble_init(lua_State* L) {
 @return bool 成功与否
 @usage
 -- 仅部分设备支持,当前可能都不支持
+-- 本函数对所有模式都适用
 */
 static int l_nimble_deinit(lua_State* L) {
     int rc = 0;
@@ -142,6 +120,7 @@ static int l_nimble_server_deinit(lua_State* L) {
 @return bool 成功与否
 @usage
 -- 参考 demo/nimble
+-- 本函数对peripheral/从机模式适用
 */
 static int l_nimble_send_msg(lua_State *L) {
     int conn_id = luaL_checkinteger(L, 1);
@@ -167,6 +146,7 @@ static int l_nimble_send_msg(lua_State *L) {
 @return bool 成功与否
 @usage
 -- 参考 demo/nimble
+-- 本函数对central/主机模式适用
 */
 static int l_nimble_scan(lua_State *L) {
     int ret = luat_nimble_blecent_scan();
@@ -216,6 +196,8 @@ static int l_nimble_connok(lua_State *L) {
 @usage
 -- 参考 demo/nimble, 2023-02-25之后编译的固件支持本API
 -- 必须在nimble.init()之前调用
+-- 本函数对peripheral/从机模式适用
+
 -- 设置SERVER/Peripheral模式下的UUID, 支持设置3个
 -- 地址支持 2/4/16字节, 需要二进制数据
 -- 2字节地址示例: AABB, 写 string.fromHex("AABB") ,或者 string.char(0xAA, 0xBB)
@@ -251,6 +233,16 @@ static int l_nimble_set_uuid(lua_State *L) {
     return 1;
 }
 
+/*
+获取蓝牙MAC
+@api nimble.mac()
+@return string 蓝牙MAC地址,6字节
+@usage
+-- 参考 demo/nimble, 2023-02-25之后编译的固件支持本API
+-- 本函数对所有模式都适用
+local mac = nimble.mac()
+log.info("ble", "mac", mac and mac:toHex() or "Unknwn")
+*/
 static int l_nimble_mac(lua_State *L) {
     int rc;
     uint8_t own_addr_type;
@@ -278,6 +270,36 @@ static int l_nimble_mac(lua_State *L) {
     return 0;
 }
 
+/*
+配置iBeacon的参数,仅iBeacon模式可用
+@api nimble.ibeacon(data, major, minor, measured_power)
+@string 数据, 必须是16字节
+@int 主版本号,默认2, 可选
+@int 次版本号,默认10,可选
+@int 名义功率, 默认0, 范围 -126 到 20 
+@return bool 成功返回true,否则返回false
+@usage
+-- 参考 demo/nimble, 2023-02-25之后编译的固件支持本API
+-- 本函数对ibeacon模式适用
+nimble.ibeacon(data, 2, 10, 0)
+nimble.init()
+*/
+static int l_nimble_ibeacon(lua_State *L) {
+    size_t len = 0;
+    const char* data = luaL_checklstring(L, 1, &len);
+    if (len != 16) {
+        LLOGE("ibeacon data MUST 16 bytes, but %d", len);
+        return 0;
+    }
+    uint16_t major = luaL_optinteger(L, 2, 2);
+    uint16_t minor = luaL_optinteger(L, 3, 10);
+    int8_t measured_power = luaL_optinteger(L, 4, 0);
+
+    int rc = luat_nimble_ibeacon_setup(data, major, minor, measured_power);
+    lua_pushboolean(L, rc == 0 ? 1 : 0);
+    return 1;
+}
+
 #include "rotable2.h"
 static const rotable_Reg_t reg_nimble[] =
 {
@@ -298,6 +320,9 @@ static const rotable_Reg_t reg_nimble[] =
     { "scan",           ROREG_FUNC(l_nimble_scan)},
     { "connect",        ROREG_FUNC(l_nimble_connect)},
 
+    // ibeacon广播模式
+    { "ibeacon",        ROREG_FUNC(l_nimble_ibeacon)},
+
     // 放一些常量
     { "STATE_OFF",           ROREG_INT(BT_STATE_OFF)},
     { "STATE_ON",            ROREG_INT(BT_STATE_ON)},

+ 157 - 0
components/nimble/src/luat_nimble_mode_ibeacon.c

@@ -0,0 +1,157 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "luat_base.h"
+#if (defined(AIR101) || defined(AIR103))
+#include "FreeRTOS.h"
+#else
+#include "freertos/FreeRTOS.h"
+#endif
+
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+#include "host/util/util.h"
+#include "services/gap/ble_svc_gap.h"
+#include "services/gatt/ble_svc_gatt.h"
+
+#include "luat_msgbus.h"
+#include "luat_malloc.h"
+#include "luat_nimble.h"
+
+#define LUAT_LOG_TAG "nimble"
+#include "luat_log.h"
+
+/* BLE */
+#include "nimble/nimble_port.h"
+// #include "nimble/nimble_port_freertos.h"
+
+#define ADDR_FMT "%02X%02X%02X%02X%02X%02X"
+#define ADDR_T(addr) addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]
+
+static uint8_t ble_use_custom_name;
+static uint8_t own_addr_type;
+static uint8_t ble_ready;
+void ble_store_config_init(void);
+
+typedef struct ibeacon_data
+{
+    char data[16];
+    uint16_t major;
+    uint16_t minor;
+    int8_t measured_power;
+}ibeacon_data_t;
+
+static ibeacon_data_t ibdata;
+static void ble_app_advertise(void);
+
+int luat_nimble_ibeacon_setup(void *uuid128, uint16_t major,
+                         uint16_t minor, int8_t measured_power) {
+    memcpy(ibdata.data, uuid128, 16);
+    ibdata.major = major;
+    ibdata.minor = minor;
+    ibdata.measured_power = measured_power;
+    if (ble_ready) {
+        int rc = ble_ibeacon_set_adv_data(ibdata.data, ibdata.major, ibdata.minor, ibdata.measured_power);
+        LLOGD("ble_ibeacon_set_adv_data rc %d", rc);
+    }
+    return 0;
+}
+
+static int
+bleprph_gap_event(struct ble_gap_event *event, void *arg)
+{
+    switch (event->type) {
+    case BLE_GAP_EVENT_ADV_COMPLETE:
+        LLOGI("advertise complete; reason=%d", event->adv_complete.reason);
+        return 0;
+    }
+    return 0;
+}
+
+static void
+ble_app_advertise(void)
+{
+    struct ble_gap_adv_params adv_params = {0};
+    // uint8_t uuid128[16];
+    int rc;
+
+    // /* Arbitrarily set the UUID to a string of 0x11 bytes. */
+    // memset(uuid128, 0x11, sizeof uuid128);
+
+    /* Major version=2; minor version=10. */
+    rc = ble_ibeacon_set_adv_data(ibdata.data, ibdata.major, ibdata.minor, ibdata.measured_power);
+    LLOGD("ble_ibeacon_set_adv_data rc %d", rc);
+    // assert(rc == 0);
+
+    /* Begin advertising. */
+    // adv_params = (struct ble_gap_adv_params){ 0 };
+    rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
+                           &adv_params, bleprph_gap_event, NULL);
+    LLOGD("ble_gap_adv_start rc %d", rc);
+}
+
+static void
+bleprph_on_sync(void)
+{
+    LLOGD("iBeacon GoGoGo");
+    int rc;
+    ble_hs_id_infer_auto(0, &own_addr_type);
+    /* Printing ADDR */
+    uint8_t addr_val[6] = {0};
+    rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
+
+    LLOGI("Device Address: " ADDR_FMT, ADDR_T(addr_val));
+    if (ble_use_custom_name == 0) {
+        char buff[32];
+        sprintf_(buff, "LOS-" ADDR_FMT, ADDR_T(addr_val));
+        LLOGD("BLE name: %s", buff);
+        rc = ble_svc_gap_device_name_set((const char*)buff);
+    }
+
+    /* Advertise indefinitely. */
+    ble_app_advertise();
+}
+
+int luat_nimble_init_ibeacon(uint8_t uart_idx, char* name, int mode) {
+    int rc = 0;
+    nimble_port_init();
+
+    /* Set the default device name. */
+    if (name != NULL && strlen(name)) {
+        rc = ble_svc_gap_device_name_set((const char*)name);
+        ble_use_custom_name = 1;
+    }
+
+    if (ibdata.major == 0) {
+        ibdata.major = 2;
+    }
+    if (ibdata.minor == 0) {
+        ibdata.minor = 10;
+    }
+    if (ibdata.data[0] == 0) {
+        memset(ibdata.data, 0x11, 16);
+    }
+
+    /* Initialize the NimBLE host configuration. */
+    // ble_hs_cfg.reset_cb = bleprph_on_reset;
+    ble_hs_cfg.sync_cb = bleprph_on_sync;
+    // ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
+    // ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
+
+    ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
+    ble_hs_cfg.sm_sc = 0;
+
+    ble_svc_gap_init();
+    // ble_svc_gatt_init();
+
+    // rc = gatt_svr_init();
+    // LLOGD("gatt_svr_init rc %d", rc);
+
+    /* XXX Need to have template for store */
+    ble_store_config_init();
+
+    return 0;
+}
+

+ 50 - 0
demo/nimble/ibeacon/main.lua

@@ -0,0 +1,50 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "bledemo"
+VERSION = "1.0.0"
+
+--[[
+BLE iBeacon示例
+支持的模块:
+1. Air101/Air103, 开发板的BLE天线未引出, 需要靠近使用, 且功耗高
+2. ESP32系列, 包括ESP32C3/ESP32S3
+]]
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+    sys.wait(2000)
+
+    -- 设置ibeacon的数据, 16字节
+    -- local data = string.char(0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22)
+    local data = string.fromHex("11223344112233441122334411223344")
+    -- nimble.ibeacon(data, 2, 10, 0)
+    nimble.ibeacon(data)
+    
+    -- BLE模式, 默认是SERVER/Peripheral,即外设模式, 等待被连接的设
+    nimble.mode(nimble.MODE_BLE_BEACON)
+    -- 启动之
+    nimble.init()
+
+    -- 运行时改变数据也是可以的
+    while 1 do
+        sys.wait(60000) -- 每隔1分钟变一次
+        data = crypto.trng(16)
+        log.info("ibeacon", "data", data:toHex())
+        nimble.ibeacon(data)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!