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

news2024/11/18 11:45:40

今天收到了极术社区寄来的礼物,非常感谢。为此今天突击贡献一份蓝牙配网的小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.

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1507958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【自动驾驶系列丛书学习】2.《自动驾驶汽车环境感知》学习笔记

《自动驾驶技术概论》学习笔记 致谢&#xff1a;作者&#xff1a;甄先通、黄坚、王亮、夏添 -------------------------------------------------------------------------------------------------------- 笔记目录 《自动驾驶技术概论》学习笔记 1.自动驾驶环境感知概述…

Python从0到100(三):Python中的变量介绍

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

Day31-计算机基础1

Day31-计算机基础1 1. 网络基础介绍1.1 什么是网络&#xff1f;1.2 为什么要有网络&#xff1f;1.3 运维人员需要学习哪些网络知识&#xff1f;1.4 按作用范围对网络分类 2.网络设备知识2.1 网络传输介质及传输信号2.2 网卡设备2.3 中继器&#xff08;RP repeater&#xff09;2…

海思Hi3403V100方案双目视频融合模组测试

Hi3403V100是海思面向高端市场应用推出的专业 Ultra-HD Smart IP Camera SOC&#xff0c;该芯片最高支持四路sensor输入&#xff0c;支持最高4K60的ISP图像处理能力。 海思Hi3403V100方案双目视频模组采用了海思Hi3403V100方案核心板双目视频融合IMX334 Sensor板测试&#xff…

neo4j 删除从一个node开始的所有数据。

##一、 需求 删除红线右边重复的数据 二、 删除与中心点1的右边连线 2.1 中心点1橙色&#xff1a; <elementId>: 4:fbde4fa1-3453-4e00-91ce-92b16aec22e3:425 <id>: 425 fileName: /Users/guibing.gao/Desktop/lib2.2 与中新点1右边链接的node <elementId>…

助力头部银行10倍提升数据化运营效率,NoETL的破局之道丨爱分析活动

在数字化飞速发展的今天&#xff0c;企业经营者们逐渐认识到数据平台对于企业生产经营所不可或缺的价值。随着数据平台不断发展和进化&#xff0c;数据量、数据源、用数人群也日益增加&#xff0c;对于业务用数敏捷和数据管理有序同样带来了全新的挑战。数据应用层面&#xff0…

安卓studio安装

安卓studio安装 2024.3.11官网的版本&#xff08;有些翻墙步骤下载东西也解决了&#xff09; 这次写的略有草率&#xff0c;后面会更新布局的&#xff0c;因为截图量太大了&#xff0c;有需要的小伙伴可以试着接受一下哈哈哈哈 !(https://gitee.com/jiuzheyangbawjf/img/raw/ma…

【C++】关键字:auto

文章目录 1. 介绍2. 如何使用 1. 介绍 从C11开始&#xff0c;auto变成了类型指示符&#xff08;之前auto并不是这个作用&#xff09;。使用auto定义变量时必须对其进行初始化&#xff0c;在编译阶段编译器自动推导auto变量的实际类型。因此auto并非是一种“类型”的声明&#…

在 Python 中从键盘读取用户输入

文章目录 如何在 Python 中从键盘读取用户输入input 函数使用input读取键盘输入使用input读取特定类型的数据处理错误从用户输入中读取多个值 getpass 模块使用 PyInputPlus 自动执行用户输入评估总结 如何在 Python 中从键盘读取用户输入 原文《How to Read User Input From t…

【Idea】八种Debug模式介绍

1.行断点 在对应的代码行左侧边栏点击鼠标左键&#xff0c;会出现一个红色圆圈&#xff0c;以debug模式执行时当代码运行到此处则会停止&#xff0c;并可以查询相关上下文参数 2.方法断点 在方法左侧点击创建断点,在方法进入时会停止&#xff0c;同时可以右键断点&#xff0c;…

使用GraaVIM打包Linux平台本地镜像

1.创建实例&#xff0c;在WindTerm上面连接云服务器 2.安装Lrzsz文件上传工具 yum install lrzsz 3.上传打好的jar包 lrz 使用ls命令查看是否上传成功 3.安装gcc等环境 sudo yum install gcc glibc-devel zlib-devel 4.下载安装配置Linux下的GraaVIM、native-image 下载链…

联想小新电脑出现蓝屏问题解决(暂时没有解决)

电脑出现蓝屏&#xff0c;如下 搜索FAULTY_HARDWARE_CORRUPTED_PAGE寻找解决方案&#xff0c;找到较为靠谱的文章&#xff1a;记录蓝屏问题FAULTY_HARDWARE_CORRUPTED_PAGE 根据文章提示找到官方解答&#xff1a;Bug 检查 0x12B&#xff1a;FAULTY_HARDWARE_CORRUPTED_PAGE&…

【数据结构与算法】贪心算法题解(一)

这里写目录标题 一、455. 分发饼干二、56. 合并区间三、53. 最大子数组和 一、455. 分发饼干 简单 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这…

学习JAVA的第十九天(基础)

目录 File 成员方法&#xff08;判断和获取&#xff09; 成员方法&#xff08;创建和删除&#xff09; 成员方法&#xff08;获取并遍历&#xff09; IO流 FileOutputStream FileInputStream 文件拷贝 前言&#xff1a;学习JAVA的第十八天&#xff08;基础&#xff09;…

NotionAI如何永久使用?NotionAI会员购买方法分享

注册NotionAI账户 首先&#xff0c;如果您还没有NotionAI账户&#xff0c;需要先注册一个账户。百度搜索“nition ai”&#xff0c;进入后&#xff0c;点击“注册”按钮&#xff0c;然后输入您的电子邮件地址和密码进行注册。您也可以使用苹果ID进行注册。 使用NotionAI免费版…

基于php的用户登录实现(v1版)(持续迭代)

目录 版本说明 数据库连接 登录页面&#xff1a;login.html 登录处理实现&#xff1a;login.php 用户欢迎页面&#xff1a;welcome.php 用户注册页面&#xff1a;register.html 注册执行&#xff1a;DoRegister.php 版本说明 v1实现功能&#xff1a; 数据库连接&#x…

selenium高级应用

常见控件应用 复杂的控件操作1.操作Ajax选项2.滑动滑块操作 WebDriver的特殊操作元素class值包含空格property、attribute、text的区别定位动态id 截图功能页面截图页面截图&#xff0c;返回截图的二进制数据页面截图&#xff0c;返回base64的字符串截取指定元素。先定位元素&a…

ARMv8/ARMv9架构下特权程序之间的跳转模型与系统启动探析

文章目录 背景1、前言小结&#xff1a; 2、4个特权等级/4个安全状态之间的跳转模型小结&#xff1a; 3、启动时镜像之间的跳转模型小结&#xff1a; 4、runtime程序之间的跳转模型小结&#xff1a; 推荐 背景 ARMv8和ARMv9架构是ARM公司推出的先进处理器架构&#xff0c;被广泛…

macbook pro 2018 安装 arch linux 双系统

文章目录 友情提醒关于我的 mac在 mac 上需要提前做的事情复制 wifi 驱动 在 linux 上的操作还原 wifi 驱动连接 wifi 网络磁盘分区制作文件系统挂载分区 使用 archinstall 来安装 arch linux遗留问题 友情提醒 安装 archl linux 的时候&#xff0c;mac 的键盘是没法用的&#…

【JAVA】Collections.sort()方法详解

一、简介 Collections.sort() 是 Java 集合框架&#xff08;Java Collections Framework&#xff09;中的一个静态方法&#xff0c;用于对列表&#xff08;List&#xff09;中的元素进行排序。此方法利用了 Java 的泛型机制&#xff0c;可以很方便地对各种类型的列表进行排序。…