【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”}
在这里插入图片描述

以下是开发板打印:

====================================================================
	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.

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值