今天收到了极术社区寄来的礼物,非常感谢。为此今天突击贡献一份蓝牙配网的小Demo,由于我对BLE通信不是很熟,此Demo仅供演示,存在几个问题尚未解决:
- 无法实现广播名
- 没有修改GATT表,直接套用例程的了
- 没有实现二次进入配网的功能
废话不多说,上干货:
首先还是先编译原生库:
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(¶m, 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”}
以下是开发板打印:
====================================================================
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.
然后就可以干物联网该干的事情了,好了在这里先提前预祝各位元旦快乐