Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Leung_ManWah
ESP32 WIFI蓝牙网关
提交
3bb84607
ESP32 WIFI蓝牙网关
项目概览
Leung_ManWah
/
ESP32 WIFI蓝牙网关
通知
121
Star
6
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
ESP32 WIFI蓝牙网关
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3bb84607
编写于
5月 17, 2022
作者:
Leung_ManWah
1
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Update README.md
上级
0216f760
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
436 addition
and
0 deletion
+436
-0
README.md
README.md
+436
-0
未找到文件。
README.md
浏览文件 @
3bb84607
# 一、项目简介
> **蓝牙网关** 又叫蓝牙探针,是采集蓝牙设备的蓝牙数据,通过 WIFI 等方式传至服务器的一款中继设备。如果类比的话,就如同 WIFI 网络中的无线 AP 的作用。WIFI 网络中无线 AP 是将 WIFI 设备接入网络,而蓝牙网络中的蓝牙网关,是将蓝牙设备接入网络。
![](
https://img-blog.csdnimg.cn/img_convert/54eee4a7fb51ae52349d6e420ebb6057.png
)
**项目特性:**
*
采用 240MHz Xtensa 32-bit LX6 双核处理器
*
支持 STA 工作模式
...
...
@@ -16,6 +18,7 @@
4.
将采集蓝牙数据通过 TCP 方式发送到指定服务器;
5.
上电或按下网关按键发送蓝牙广播数据,时长5秒(默认)。
![](
https://img-blog.csdnimg.cn/img_convert/e7f18c1ecf1358445cde1b4a0d1442d8.png
)
# 三、API接口
## 3.1 外设
...
...
@@ -77,5 +80,438 @@ bool BLE_GetUuidFromAdv(uint8_array_t *pAdvData, uint8_array_t *pTypeData) | 从
bool BLE_GetNameFromAdv(uint8_array_t
*pAdvData, uint8_array_t *
pTypeData) | 从广播包中提取设备名称
bool BLE_GetUserDataFromAdv(uint8_array_t
*pAdvData, uint8_array_t *
pTypeData) | 从广播包中提取用户自定义内容
# 四、工程代码
**GitCode:**
[
https://gitcode.net/qq_36347513/esp32-wifi_ble_gateway
](
https://gitcode.net/qq_36347513/esp32-wifi_ble_gateway
)
将文件解压到 esp-idf/examples 目录下:
![](
https://img-blog.csdnimg.cn/img_convert/ee4d1209ce9935f3ce437c1cdf7a3766.png
)
## 4.1 工程结构
![](
https://img-blog.csdnimg.cn/img_convert/8d0fde9fcb644d4686a03abb8ba899d2.png
)
## 4.2 一键配网
首先在
`main.c`
的
`app_main()`
中初始化 WIFI 模块,然后创建一个
`network_task`
处理网络通信业务。
```
cpp
void
app_main
(
void
)
{
ESP_ERROR_CHECK
(
nvs_flash_init
());
/*-------------------------- 外设驱初始化 ---------------------------*/
···
WIFI_Init
();
// WIFI模块初始化
···
···
/*-------------------------- 创建线程 ---------------------------*/
···
xTaskCreate
(
network_task
,
"network_task"
,
4096
,
NULL
,
5
,
NULL
);
···
}
/**
@brief 通信业务
@param 无
@return 无
*/
static
void
network_task
(
void
*
arg
)
{
while
(
1
)
// 任务都是一个无限循环,不能返回
{
HandleNetworkService
();
Delay
(
1000
);
// 1s
}
}
```
扫描二维码进行
`AirKiss`
一键配网
## 4.3 连接TCP服务器
在
`user_socket.h`
中修改指定服务器的 IP 地址和端口:
![](
https://img-blog.csdnimg.cn/img_convert/a7a28110a743e4785e6b632e4d0c652e.png
)
当
`network_task`
获取到 WIFI 状态已连接路由器成功后,调用
`Socket_Init()`
初始化socket通信,连接到指定 TCP 服务器。
成功连接 TCP 服务器后,发送一条内容为
`TEST`
的消息。
```
cpp
void
HandleNetworkService
(
void
)
{
if
(
CONNECT_WIFI_FAIL
==
WIFI_Status
())
{
return
;
}
if
(
INIT_FAIL
==
g_isSocketInit
)
{
SetNetworkLedStatus
(
NO_NETWORK
);
s_isConnectServer
=
CONNECT_FAIL
;
g_isSocketInit
=
Socket_Init
();
// 初始化socket通信
}
else
if
(
INIT_SUCCESS
==
g_isSocketInit
)
{
if
(
CONNECT_FAIL
==
s_isConnectServer
)
{
SetNetworkLedStatus
(
IDLE
);
s_isConnectServer
=
CONNECT_SUCCESS
;
BLE_Scan
();
Socket_Send
(
"TEST"
);
ESP_LOGI
(
TAG
,
"socket send TEST
\r\n
"
);
}
// 接收服务器数据
char
recvDataBuf
[
MAX_RECV_BUF_SIZE
]
=
{
0
};
int
recvDataLen
=
Socket_Receive
(
recvDataBuf
);
// 接收服务器数据
if
(
recvDataLen
>
0
)
{
handleSocketRecvData
(
recvDataBuf
,
recvDataLen
);
}
}
}
```
## 4.4 发送BLE扫描数据
*
首先在
`main.c`
的
`app_main()`
中初始化 BLE 模块,然后创建一个
`monitor_task`
处理事件业务。
*
创建一个蓝牙消息队列
`MsgQueue_Init(g_pMsgQueue);`
和一个蓝牙 MAC 地址队列
`MacQueue_Init(g_pMacQueue);`
。
*
创建蓝牙 MAC 地址过滤定时器
`CreateFilterMacTimer()`
,过滤短时间内同一 MAC 地址重复的蓝牙广播包。
```
cpp
void
app_main
(
void
)
{
ESP_ERROR_CHECK
(
nvs_flash_init
());
/*-------------------------- 外设驱初始化 ---------------------------*/
timers_init
();
// 定时器驱动初始化(在此加入自定义定时器)
···
BLE_Init
();
// 蓝牙模块初始化
BLE_AdvertisingDataInit
();
BLE_Advertise
();
/*---------------------------- 队列初始化 -----------------------------*/
g_pMsgQueue
=
(
MsgQueue_t
*
)
malloc
(
sizeof
(
MsgQueue_t
));
g_pMacQueue
=
(
MacQueue_t
*
)
malloc
(
sizeof
(
MacQueue_t
));
MsgQueue_Init
(
g_pMsgQueue
);
MacQueue_Init
(
g_pMacQueue
);
/*-------------------------- 创建线程 ---------------------------*/
···
xTaskCreate
(
monitor_task
,
"monitor_task"
,
4096
,
NULL
,
4
,
NULL
);
···
application_timers_start
();
}
static
void
timers_init
(
void
)
{
esp_timer_init
();
// 使用定时器API函数,先调用接口初始化
···
CreateFilterMacTimer
();
}
static
void
application_timers_start
(
void
)
{
···
StartFilterMacTimer
();
}
static
void
monitor_task
(
void
*
arg
)
{
while
(
1
)
// 任务都是一个无限循环,不能返回
{
HandleEventService
();
Delay
(
100
);
// 100ms
}
}
```
当
`network_task`
获取到连接 TCP 服务器成功后,开启扫描
`BLE_Scan()`
。
```
cpp
void
HandleNetworkService
(
void
)
{
if
(
CONNECT_WIFI_FAIL
==
WIFI_Status
())
{
return
;
}
if
(
INIT_FAIL
==
g_isSocketInit
)
{
SetNetworkLedStatus
(
NO_NETWORK
);
s_isConnectServer
=
CONNECT_FAIL
;
g_isSocketInit
=
Socket_Init
();
// 初始化socket通信
}
else
if
(
INIT_SUCCESS
==
g_isSocketInit
)
{
if
(
CONNECT_FAIL
==
s_isConnectServer
)
{
···
s_isConnectServer
=
CONNECT_SUCCESS
;
BLE_Scan
();
···
}
···
}
}
```
当扫描到蓝牙广播时,进去蓝牙事件处理函数
`bleEventHandler()`
处理扫描结果,将蓝牙广播设备的
**MAC 地址、设备名称、UUID、用户数据和RSSI**
等依次封装成消息,加入消息队列。
```
cpp
static
void
bleEventHandler
(
esp_gap_ble_cb_event_t
event
,
esp_ble_gap_cb_param_t
*
param
)
{
esp_err_t
err
;
switch
(
event
)
{
···
/*--------------------------- 扫描 ---------------------------*/
case
ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT
:
{
//the unit of the duration is second, 0 means scan permanently
// uint32_t duration = 0;
// esp_ble_gap_start_scanning(duration);
break
;
}
case
ESP_GAP_BLE_SCAN_START_COMPLETE_EVT
:
//scan start complete event to indicate scan start successfully or failed
if
((
err
=
param
->
scan_start_cmpl
.
status
)
!=
ESP_BT_STATUS_SUCCESS
)
{
ESP_LOGE
(
TAG
,
"Scan start failed: %s"
,
esp_err_to_name
(
err
));
}
break
;
case
ESP_GAP_BLE_SCAN_RESULT_EVT
:
scanResultHandler
(
param
);
break
;
case
ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT
:
if
((
err
=
param
->
scan_stop_cmpl
.
status
)
!=
ESP_BT_STATUS_SUCCESS
)
{
ESP_LOGE
(
TAG
,
"Scan stop failed: %s"
,
esp_err_to_name
(
err
));
}
else
{
ESP_LOGI
(
TAG
,
"Stop scan successfully"
);
}
break
;
default:
break
;
}
}
/**
@brief 处理扫描结果
@param 无
@return 无
*/
static
void
scanResultHandler
(
esp_ble_gap_cb_param_t
*
pScanResult
)
{
bool
result
;
uint8_array_t
advData
;
uint8_array_t
name
;
uint16_t
uuid
=
0
;
uint8_array_t
uuidArray
;
uint8_array_t
userData
;
uint8_t
macAddr
[
ESP_BD_ADDR_LEN
]
=
{
0
};
int8_t
rssi
=
0
;
switch
(
pScanResult
->
scan_rst
.
search_evt
)
{
case
ESP_GAP_SEARCH_INQ_RES_EVT
:
// ESP_LOGI(TAG, "----------Device Found----------");
advData
.
p_data
=
pScanResult
->
scan_rst
.
ble_adv
;
advData
.
size
=
pScanResult
->
scan_rst
.
adv_data_len
+
pScanResult
->
scan_rst
.
scan_rsp_len
;
// MAC地址
memcpy
(
macAddr
,
pScanResult
->
scan_rst
.
bda
,
ESP_BD_ADDR_LEN
);
// esp_log_buffer_hex("Device address:", pScanResult->scan_rst.bda, ESP_BD_ADDR_LEN);
// 设备名称
result
=
BLE_GetNameFromAdv
(
&
advData
,
&
name
);
if
(
result
==
true
)
{
// ESP_LOGI(TAG, "searched Device Name Len %d", name.size);
// esp_log_buffer_char(TAG, (char *)name.p_data, name.size);
}
// UUID
result
=
BLE_GetUuidFromAdv
(
&
advData
,
&
uuidArray
);
if
(
result
==
true
)
{
uuid
=
U8ToU16LittleEndian
(
uuidArray
.
p_data
);
// ESP_LOGI(TAG, "searched uuid:%04x", uuid);
}
// 用户数据
result
=
BLE_GetUserDataFromAdv
(
&
advData
,
&
userData
);
if
(
result
==
true
)
{
// esp_log_buffer_hex("searched user data:", userData.p_data, userData.size);
}
// RSSI
rssi
=
pScanResult
->
scan_rst
.
rssi
;
// ESP_LOGI(TAG, "RSSI of packet:%d dbm", pScanResult->scan_rst.rssi);
// 检查MAC地址不在待发送消息队列中
if
(
!
CheckMac
(
g_pMacQueue
,
macAddr
)
&&
ESP_BT_DEVICE_TYPE_BLE
==
pScanResult
->
scan_rst
.
dev_type
)
{
MacFilter_t
*
pMac
;
pMac
=
(
MacFilter_t
*
)
malloc
(
sizeof
(
MacFilter_t
));
memcpy
(
pMac
->
addr
,
pScanResult
->
scan_rst
.
bda
,
ESP_BD_ADDR_LEN
);
// MAC地址
pMac
->
tick
=
esp_timer_get_time
();
// 当前系统tick,用于过滤重复消息
if
(
MacQueue_GetLength
(
g_pMacQueue
)
<
MAX_MAC_NUM
)
{
MacQueue_PushElement
(
g_pMacQueue
,
*
pMac
);
// 加入MAC队列
}
free
(
pMac
);
pMac
=
NULL
;
DataType_t
*
pMsg
;
pMsg
=
(
DataType_t
*
)
malloc
(
sizeof
(
DataType_t
));
// UUID
pMsg
->
uuid
=
uuid
;
// 广播内容
pMsg
->
adv_data
.
size
=
advData
.
size
;
pMsg
->
adv_data
.
p_data
=
(
uint8_t
*
)
malloc
(
advData
.
size
*
sizeof
(
uint8_t
));
memcpy
(
pMsg
->
adv_data
.
p_data
,
advData
.
p_data
,
advData
.
size
);
// 信号强度
pMsg
->
rssi
=
rssi
;
// MAC地址
memcpy
(
pMsg
->
addr
,
pScanResult
->
scan_rst
.
bda
,
ESP_BD_ADDR_LEN
);
if
(
MsgQueue_GetLength
(
g_pMsgQueue
)
<
MAX_MESSAGE_NUM
)
{
MsgQueue_PushElement
(
g_pMsgQueue
,
*
pMsg
);
// 加入消息队列
}
else
{
free
(
pMsg
->
adv_data
.
p_data
);
pMsg
->
adv_data
.
p_data
=
NULL
;
}
free
(
pMsg
);
pMsg
=
NULL
;
}
break
;
default:
break
;
}
}
```
![](
https://img-blog.csdnimg.cn/img_convert/870fb65e11510c6dd708680d32f504a6.png
)
在
`monitor_task`
中,从消息队列中提取消息发送到 TCP 服务端。
![](
https://img-blog.csdnimg.cn/img_convert/aad6dcceb3d3f7bbc2c4a244e30be946.png
)
![](
https://img-blog.csdnimg.cn/img_convert/c5bf2cd6c233e1f3dd51d086ecd29240.png
)
## 4.5 按键发送BLE广播
*
首先在
`main.c`
的
`app_main()`
中初始化 BLE 模块,然后创建一个
`monitor_task`
处理事件业务。
*
创建蓝牙广播停止的定时器
`CreateKeepAdvertisingTimer()`
,设备上电广播5秒。
```
cpp
void
app_main
(
void
)
{
ESP_ERROR_CHECK
(
nvs_flash_init
());
/*-------------------------- 外设驱初始化 ---------------------------*/
timers_init
();
// 定时器驱动初始化(在此加入自定义定时器)
···
BLE_Init
();
// 蓝牙模块初始化
BLE_AdvertisingDataInit
();
BLE_Advertise
();
···
/*-------------------------- 创建线程 ---------------------------*/
···
xTaskCreate
(
monitor_task
,
"monitor_task"
,
4096
,
NULL
,
4
,
NULL
);
···
application_timers_start
();
}
static
void
timers_init
(
void
)
{
esp_timer_init
();
// 使用定时器API函数,先调用接口初始化
CreateKeepAdvertisingTimer
();
···
}
static
void
application_timers_start
(
void
)
{
StartKeepAdvertisingTimer
();
···
}
static
void
monitor_task
(
void
*
arg
)
{
while
(
1
)
// 任务都是一个无限循环,不能返回
{
HandleEventService
();
Delay
(
100
);
// 100ms
}
}
```
当设备连接上 TCP 服务器时,按下按键通过
`socket`
发送消息。
```
cpp
void
HandleEventService
(
void
)
{
// 网络连接成功
if
(
CONNECT_SUCCESS
==
GetConnectServerStatus
())
{
// 发送呼叫
if
(
KEY_CALL_EVENT
==
GetKeyTriggerEvent
())
{
Buzzer_Beep
(
SHORT
);
Socket_Send
(
"CALL"
);
ESP_LOGI
(
TAG
,
"socket send CALL
\r\n
"
);
SetKeyTriggerEvent
(
0
);
return
;
}
···
}
// 网络故障
else
{
···
}
}
```
![](
https://img-blog.csdnimg.cn/img_convert/8840975c52aafcc98ff803194aa4e9f6.png
)
![](
https://img-blog.csdnimg.cn/img_convert/7ddda1067494ddf910e06d8eab1c1caa.png
)
当设备没有连接上 TCP 服务器时,按下按键通过 BLE 广播发送消息。
```
cpp
void
HandleEventService
(
void
)
{
// 网络连接成功
if
(
CONNECT_SUCCESS
==
GetConnectServerStatus
())
{
···
}
// 网络故障
else
{
if
(
KEY_CALL_EVENT
==
GetKeyTriggerEvent
())
{
Buzzer_Beep
(
SHORT
);
SetWarningLedStatus
(
CALL_WARNING
);
uint8_t
data
[
6
]
=
{
0
};
data
[
0
]
=
APP_COMPANY_IDENTIFIER_L
;
data
[
1
]
=
APP_COMPANY_IDENTIFIER_H
;
data
[
2
]
=
0x11
;
data
[
3
]
=
0x22
;
data
[
4
]
=
0x33
;
data
[
5
]
=
0x44
;
BLE_SetManufacturerData
(
data
,
sizeof
(
data
));
BLE_Advertise
();
// 开启广播
StartKeepAdvertisingTimer
();
SetKeyTriggerEvent
(
0
);
}
}
}
```
![](
https://img-blog.csdnimg.cn/img_convert/753b5ba485d455c435bd9e2f313032d9.png
)
---
• 由
[
Leung
](
https://blog.csdn.net/qq_36347513
)
写于 2022 年 5 月 17 日
Hello Meiwen
@weixin_45825689
·
1月 07, 2024
牛而逼之,学而习之。感谢!
牛而逼之,学而习之。感谢!
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录