ctspot · 2021年12月27日

【XR806开发板试用】新鲜出炉的蓝牙配网Demo

今天收到了极术社区寄来的礼物,非常感谢。为此今天突击贡献一份蓝牙配网的小Demo,由于我对BLE通信不是很熟,此Demo仅供演示,存在几个问题尚未解决:

  1. 无法实现广播名
  2. 没有修改GATT表,直接套用例程的了
  3. 没有实现二次进入配网的功能
    废话不多说,上干货:
    首先还是先编译原生库:

    cd device/xradio/xr806/xr_skylark                               
    cp project/demo/wlan_ble_demo/gcc/defconfig .config
    make menuconfig                                                 
    make build_clean                                                
    make lib -j                                                     
    cd ../../../..                                                   
    hb set                                                          
    hb build -f

    然后ohosdemo目录下面复制hello_demo,改名为ble_demo,目录结构如下:

    ble_demo
    ├── BUILD.gn
    └── src
     └── main.c

    然后修改ohosdemo目录下的BUILD.gn,内容如下:

    group("ohosdemo") {
     deps = [
         "ble_demo:app_ble",
     ]
    }

    接下来修改ble_demo下的BUILD.gn,内容如下:

    import("//device/xradio/xr806/liteos_m/config.gni")
    
    static_library("app_ble") {
    configs = []
    
    sources = [
       "src/main.c",
    ]
    
    cflags = board_cflags
    
    include_dirs = board_include_dirs
    include_dirs += [
       "//kernel/liteos_m/kernel/arch/include",
       "//base/iot_hardware/peripheral/interfaces/kits",
    
       ".",
       "//utils/native/lite/include",
       "//foundation/communication/wifi_lite/interfaces/wifiservice",
       "//device/xradio/xr806/xr_skylark/project",
       "//device/xradio/xr806/xr_skylark/include/ble",
    ]
    }

    然后是主程序:

    #include <stdio.h>
    #include <string.h>
    #include <stddef.h>
    #include <errno.h>
    
    #include "ohos_init.h"
    #include "kernel/os/os.h"
    
    #include <ble/sys/byteorder.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/conn.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    #include "wifi_device.h"
    #include "cjson/cJSON.h"
    
    static OS_Thread_t g_main_thread;
    static struct bt_conn *default_conn = NULL;
    static OS_Semaphore_t sem;
    
    static uint8_t g_ssid[33] = "";
    static uint8_t g_pwd[65] = "";
    static uint8_t g_ble_config = 0;
    
    static void conn_addr_str(struct bt_conn *conn, char *addr, size_t len) {
     struct bt_conn_info info;
     if (bt_conn_get_info(conn, &info) < 0) {
         addr[0] = '\0';
         return;
     }
     if(info.type == BT_CONN_TYPE_LE) {
         bt_addr_le_to_str(info.le.dst, addr, len);
     }
    }
    
    static void connected(struct bt_conn *conn, uint8_t err) {
     char addr[BT_ADDR_LE_STR_LEN];
    
     conn_addr_str(conn, addr, sizeof(addr));
     if (err) {
         printf("Failed to connect to %s (0x%02x)\n", addr, err);
         return;
     }
    
     bt_le_adv_stop();
     printf("Connected: %s\n", addr);
     if (!default_conn) {
         default_conn = bt_conn_ref(conn);
     }
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason) {
     char addr[BT_ADDR_LE_STR_LEN];
    
     conn_addr_str(conn, addr, sizeof(addr));
     printf("Disconnected: %s (reason 0x%02x)\n", addr, reason);
     if (default_conn == conn) {
         bt_conn_unref(default_conn);
         default_conn = NULL;
     }
    }
    
    static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param) {
     printf("LE conn  param req: int (0x%04x, 0x%04x) lat %d to %d\n", 
         param->interval_min, param->interval_max, param->latency, param->timeout);
     return true;
    }
    
    static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout) {
     printf("LE conn param updated: int 0x%04x lat %d to %d\n", interval, latency, timeout);
    }
    
    static const char *ver_str(uint8_t ver) {
     const char * const str[] = {
         "1.0b", "1.1", "1.2", "2.0", "2.1", "3.0", "4.0", "4.1", "4.2", "5.0", "5.1",
     };
    
     if (ver < ARRAY_SIZE(str)) {
         return str[ver];
     }
     return "unknown";
    }
    
    static void remote_info_available(struct bt_conn *conn, struct bt_conn_remote_info *remote_info) {
     struct bt_conn_info info;
     bt_conn_get_info(conn, &info);
    
     if (IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) {
         printf("Remote LMP version %s (0x%02x) subversion 0x%04x manufacturer 0x%04x\n", 
                 ver_str(remote_info->version),
                 remote_info->version, remote_info->subversion,
                 remote_info->manufacturer);
     }
    
     if (info.type == BT_CONN_TYPE_LE) {
         uint8_t features[8];
         char features_str[2 * sizeof(features) +  1];
    
         sys_memcpy_swap(features, remote_info->le.features, sizeof(features));
         bin2hex(features, sizeof(features), features_str, sizeof(features_str));
         printf("LE Features: 0x%s\n", features_str);
     }
    }
    
    static void le_data_len_updated(struct bt_conn *conn, struct bt_conn_le_data_len_info *info) {
     printf("LE data len updated: TX (len: %d time: %d) RX (len: %d time: %d)\n", 
             info->tx_max_len, info->tx_max_time, info->rx_max_len, info->rx_max_time);
    };
    
    static struct bt_conn_cb conn_callbacks = {
     .connected = connected,
     .disconnected = disconnected,
     .le_param_req = le_param_req,
     .le_param_updated = le_param_updated,
     .remote_info_available = remote_info_available,
     .le_data_len_updated = le_data_len_updated,
    };
    
    static void bt_ready(int err) {
     if (err) {
         printf("Bluetooth init failed (err %d)\n", err);
         return ;
     }
     if (IS_ENABLED(CONFIG_SETTINGS)) {
         settings_load();
         printf("Settings Loaded\n");
     }
     bt_conn_cb_register(&conn_callbacks);
    }
    
    /////////////////////////////////////////////////////////////////////
    static const struct bt_data ad_discov[] = {
     BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
     //BT_DATA_BYTES(BT_DATA_NAME_COMPLETE, 't', 'e', 's', 't'),
    };
    
    static int advertise_on(void) {
     struct bt_le_adv_param param = {};
     int err;
    
     param.id = BT_ID_DEFAULT;
     param.interval_min = BT_GAP_ADV_FAST_INT_MIN_2;
     param.interval_max = BT_GAP_ADV_FAST_INT_MAX_2;
     param.options = (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME);
    
     err = bt_le_adv_start(&param, ad_discov, ARRAY_SIZE(ad_discov), NULL, 0);
     if (err < 0) {
         printf("Failed to start advertising (err %d)\n", err);
         return err;
     } else {
         printf("Advertising started\n");
     }
     return 0;
    }
    
    /////////////////////////////////////////////////////////////////////
    #define CHAR_SIZE_MAX           512
    static struct bt_uuid_128 met_svc_uuid = BT_UUID_INIT_128(
     0x01, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
     0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
    
    static const struct bt_uuid_128 met_char_uuid = BT_UUID_INIT_128(
     0x02, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
     0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
    
    static uint8_t met_char_value[CHAR_SIZE_MAX] = "hello";
    
    static ssize_t read_met(struct bt_conn *conn, const struct bt_gatt_attr *attr,
         void *buf, uint16_t len, uint16_t offset) {
     const char *value = attr->user_data;
     uint16_t value_len;
    
     value_len = MIN(strlen(value), CHAR_SIZE_MAX);
     return bt_gatt_attr_read(conn, attr, buf, len, offset, value, value_len);
    }
    
    static ssize_t write_met(struct bt_conn *conn, const struct bt_gatt_attr *attr,
     const void *buf, uint16_t len, uint16_t offset, uint8_t flags) {
     uint8_t *value = attr->user_data;
    
     if (offset + len > sizeof(met_char_value)) {
         return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
     }
     memcpy(value + offset, buf, len);
     value[offset + len] = '\0';
     cJSON *root = NULL;
     root = cJSON_Parse(value);
     cJSON *ssid = cJSON_GetObjectItem(root, "ssid");
     cJSON *pwd = cJSON_GetObjectItem(root, "pwd");
     if(ssid && ssid->type == cJSON_String && pwd && pwd->type == cJSON_String) {
         strncpy(g_ssid, ssid->valuestring, sizeof(g_ssid) - 1);
         strncpy(g_pwd, pwd->valuestring, sizeof(g_pwd) - 1);
         g_ble_config = 1;
     }
     cJSON_Delete(root);
     if(OS_SemaphoreRelease(&sem) != OS_OK) {
         printf("OS_SemaphoreRelease fail\n");
     }
     return len;
    }
    
    static struct bt_gatt_attr met_attrs[] = {
     BT_GATT_PRIMARY_SERVICE(&met_svc_uuid),
    
     BT_GATT_CHARACTERISTIC(&met_char_uuid.uuid,
                    BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
                    BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
                    read_met, write_met, met_char_value),
    };
    
    static struct bt_gatt_service met_svc = BT_GATT_SERVICE(met_attrs);
    
    /*****************************************************************
    *****************************************************************/
    static void MainThread(void *arg)   {
     int err;
     if(OS_SemaphoreCreate(&sem, 0, 1) != OS_OK) {
         printf("OS_SemaphoreCreate fail!\n");
         return;
     }
     bt_ctrl_enable();
     printf("Start BLE Example!\n");
     err = bt_enable(NULL);
     bt_ready(err);
     advertise_on();
     bt_gatt_service_register(&met_svc);
    
     printf("--------------\n"    );
    
     if(OS_SemaphoreWait(&sem, OS_WAIT_FOREVER) != OS_OK) {
         printf("OS_SemaphoreWait fail!\n");
         return;
     }
     OS_Sleep(1);
     bt_ctrl_disable();
     if (WIFI_SUCCESS != EnableWifi()) {
         printf("Error: EnableWifi fail\n");
         return;
     }
    
     OS_Sleep(1);
    
     if (WIFI_SUCCESS != Scan()) {
         printf("Error: Scan fail.\n");
         return;
     }
    
     OS_Sleep(4);
    
     WifiScanInfo scan_results[30];
     unsigned int scan_num = 30;
    
     if (WIFI_SUCCESS != GetScanInfoList(scan_results, &scan_num)) {
         printf("Error: GetScanInfoList fail.\n");
         return;
     }
    
     WifiDeviceConfig config = { 0 };
     int netId = 0;
    
     int i;
     for (i = 0; i < scan_num; i++) {
         printf("ssid: %s    ", scan_results[i].ssid);
         printf("securityType: %d\n", scan_results[i].securityType);
         if (0 == strcmp(scan_results[i].ssid, g_ssid)) {
             memcpy(config.ssid, scan_results[i].ssid,
                    WIFI_MAX_SSID_LEN);
             memcpy(config.bssid, scan_results[i].bssid,
                    WIFI_MAC_LEN);
             strcpy(config.preSharedKey, g_pwd);
             config.securityType = scan_results[i].securityType;
             config.wapiPskType = WIFI_PSK_TYPE_ASCII;
             config.freq = scan_results[i].frequency;
             break;
         }
     }
    
     if (i >= scan_num) {
         printf("Error: No found ssid in scan_results\n");
         return;
     }
    
     if (WIFI_SUCCESS != AddDeviceConfig(&config, &netId)) {
         printf("Error: AddDeviceConfig Fail\n");
         return;
     }
     printf("Config Success\n");
    
     if (WIFI_SUCCESS != ConnectTo(netId)) {
         printf("Error: ConnectTo Fail\n");
         return;
     }
     
     while(1) {
     }
    }
    
    void BLEMain(void) {
     if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
         printf("[ERR] Create MainThread Failed\n");
     }
    }
    
    SYS_RUN(BLEMain);

    然后解决编译过程中容量超限问题参照编译手册,烧录成功后,我们用nrfConnect APP将路由器的SSID和PWD传输过去,注意安卓手机APP在发送前设置MTU,防止只能发20个字节。
    以下是开发板发送内容:
    选择text,发送{"ssid":"abc","pwd":"def"}
    lADPJv8gRqGIQxPNBQDNA8A_960_1280.jpg_620x10000q90g.jpg
    以下是开发板打印:

    ====================================================================
     Hello! OpenHarmony!
     System tag : OpenHarmony 1.1.2_LTS
    ====================================================================
     
    use default flash chip mJedec 0x0
    [FD I]: mode: 0x10, freq: 96000000Hz, drv: 0
    [FD I]: jedec: 0x0, suspend_support: 1
    mode select:e
    
    wlan information ===================================================
    firmware:
     version : R0-XR_C07.08.52.65_02.84 May 27 2021 11:41:33-Y02.84 
     buffer  : 8
    driver:
     version : XR_V02.05
    mac address:
     in use        : 1c:98:c9:bc:50:01
     in use        : 1c:98:c9:bc:50:02
    ====================================================================
    
    wlan mode:a
    [VFS INF] SPIFFS mount success.
    
    platform information ===============================================
    XR806 SDK v1.2.0  Dec 19 2021 13:12:37
    
    heap space [0x2294e8, 0x247c00), size 124696
    
    cpu  clock 160000000 Hz
    HF   clock  40000000 Hz
    
    sdk option:
     XIP           : enable
     INT LF OSC    : enable
     SIP flash     : enable
    
    mac address:
     efuse         : 80:74:84:21:38:8e
     in use        : 1c:98:c9:bc:50:01
    ====================================================================
    
    hiview init success.
    
    ble controller open
    version    : 9.1.19
    build sha1 : v9.1.19-20210601
    build date : Jun  1 2021
    build time : 19:32:17
    
    
    console init success
    
    platform   : xr806
    
    
    ble rf_init done!
    BLE INIT ALL DONE!
    BT Coex. Init. OK.
    Start BLE Example!
    == XRadio BLE HOST V2.5.0 ==
    [bt] [WRN] set_flow_control: Controller to host flow control not supported
    [bt] [INF] bt_init: No ID address. App must call settings_load()
    [bt] [INF] bt_dev_show_info: Identity: DB:54:FC:5A:09:10 (random)
    [bt] [INF] bt_dev_show_info: HCI: version 5.0 (0x09) revision 0x0113, manufacturer 0x063d
    [bt] [INF] bt_dev_show_info: LMP: version 5.0 (0x09) subver 0x0113
    Settings Loaded
    *************************************************
    [RandomAddress 63:26:7B:59:9F:70 ]
    *************************************************
    Advertising started
    --------------
    Connected: 69:06:6D:65:26:0F (random)
    Remote LMP version 4.2 (0x08) subversion 0x0710 manufacturer 0x0046
    LE Features: 0x0000000000000000
    LE conn param updated: int 0x0006 lat 0 to 500
    LE conn param updated: int 0x0024 lat 0 to 500
    [net INF] no need to switch wlan mode 0
    [net INF] msg <wlan scan success>
    ssid: abc    securityType: 2
    Config Success
    [net INF] no need to switch wlan mode 0
    en1: Trying to associate with a4:c7:4b:71:f9:84 (SSID='abc' freq=2462 MHz)
    en1: Associated with a4:c7:4b:71:f9:84
    en1: WPA: Key negotiation completed with a4:c7:4b:71:f9:84 [PTK=CCMP GTK=CCMP]
    en1: CTRL-EVENT-CONNECTED - Connection to a4:c7:4b:71:f9:84 completed [id=0 id_str=]
    [net INF] msg <wlan connected>
    [net INF] netif is link up
    [net INF] start DHCP...
    [net INF] netif (IPv4) is up
    [net INF] address: 192.168.3.65
    [net INF] gateway: 192.168.3.1
    [net INF] netmask: 255.255.255.0
    [net INF] msg <network IPv6 state>
    [net INF] IPv6 addr state change: 0x0 --> 0x1
    [net INF] msg <>
    WAR drop=1117, fctl=0x00d0.

    然后就可以干物联网该干的事情了,好了在这里先提前预祝各位元旦快乐

推荐阅读
关注数
13820
内容数
140
全志XR806开发板相关的知识介绍以及应用专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息