参考
esp32-idf环境安装配置.csdn
bsp_espnow.h
#ifndef __BSP_ESP_NOW_H_
#define __BSP_ESP_NOW_H_
#include "stdbool.h"
#include "stdint.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BSP_MAX_PAIRING_DEVICES 8
/**
* 配对app提供的函数
*/
typedef struct {
/**
* @brief 接收过滤回调(由上层实现,在中断上下文执行,必须快速返回)
* @param srcMac 发送方 MAC 地址(6字节)
* @return true 放行,false 丢弃
*/
bool (*recv_filter)(uint8_t srcMac[6]);
/**
* @brief 获取第 idx 个 MAC 地址的回调(由上层实现)
* @param idx 索引(从0开始)
* @param mac 输出 MAC 地址(6字节)
* @return true 成功获取,false 索引无效
*/
bool (*get_mac)(uint8_t idx, uint8_t mac[6]);
} bsp_macPairingApp_ops;
void bsp_espnow_init(void);
void bsp_espnow_reinit(uint8_t macGroup[8][6],int n);
bool bsp_espnow_add_peer(uint8_t mac[6]);
bool bsp_espnow_del_peer(const uint8_t mac[6]);
uint32_t bsp_espnow_write(uint8_t targetMac[6], uint8_t *buf, uint16_t len);
uint32_t bsp_espnow_read(uint8_t targetMac[6], void *recvBuf, uint32_t toRecvSize, uint32_t timeoutMs);
void bsp_espnow_setRecvCallBack(void (*OnFun)(uint8_t srcMac[6], uint8_t *buf, uint32_t len));
/**
* 获取我自己的mac
* @param retMac
* @return
*/
bool bsp_espnow_getMyMac(uint8_t retMac[6]);
/**
* 获取配对的mac
* @param idx
* @param retMac
* @return
*/
bool bsp_espnow_getPairingMac(uint8_t idx,uint8_t retMac[6]);
/**
* @brief 注册上层回调操作集(过滤 + 获取 MAC)
* @param ops 操作集指针(内部会拷贝一份,外部可释放)
*/
void bsp_espnow_registerPaOps(const bsp_macPairingApp_ops *ops);
#ifdef __cplusplus
}
#endif
#endif
# bsp_espnow.c
#include "bsp_espnow.h"
#include "esp_now.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_mac.h"
#include <string.h>
static uint8_t s_my_mac[6];
static const char *TAG = "bsp_espnow";
static uint8_t s_Broadcast_MAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 全部设备MAC列表
static uint8_t s_MAC_GROUP[8][6] = {
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
};
#define MAC_GROUP_COUNT (sizeof(s_MAC_GROUP)/sizeof(s_MAC_GROUP[0]))
// 外部注册的接收回调
static void (*s_user_recv_cb)(uint8_t srcMac[6], uint8_t *buf, uint32_t len) = NULL;
/* 存储上层注册的操作集 */
static bsp_macPairingApp_ops s_paOps = {0};
// ============================================================
// ESP-NOW 发送完成回调,对方硬件层应答了,应用不一定收到
// ============================================================
static void on_data_sent(
const esp_now_send_info_t *tx_info,
esp_now_send_status_t status)
{
printf("on_data_sent %s\n",status == ESP_NOW_SEND_SUCCESS ? "OK" : "FAIL");
}
// ------------------------------------------------------------
// ESP-NOW 接收回调
// ------------------------------------------------------------
static void on_data_recv(const esp_now_recv_info_t *recv_info,
const uint8_t *data,
int len)
{
if(1){
ESP_LOGI(TAG, "\n========================\n"
"from " MACSTR " to " MACSTR " recv: %d bytes\n",
MAC2STR(recv_info->src_addr),
MAC2STR(s_my_mac),
len);
// 打印十六进制数据
ESP_LOG_BUFFER_HEX(TAG, data, len);
ESP_LOGI(TAG, "========================");
}
// 如果有过滤器且判定丢弃,则直接返回
if (s_paOps.recv_filter != NULL) {
if (!s_paOps.recv_filter((uint8_t*)recv_info->src_addr)) {
return;
}
}
// 调用上层用户回调
if(s_user_recv_cb != NULL)
{
// 注意:这里仍然是回调上下文,不要做阻塞!上层最好拷贝数据丢队列
s_user_recv_cb((uint8_t*)recv_info->src_addr, (uint8_t*)data, (uint32_t)len);
}
}
static void wifi_init(){
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
// 全部设备统一信道 1
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_wifi_get_mac(WIFI_IF_STA, s_my_mac));
ESP_LOGI(TAG, "my MAC: " MACSTR, MAC2STR(s_my_mac));
}
static void espnow_init(){
ESP_ERROR_CHECK(esp_now_init());
// 注册收发回调
ESP_ERROR_CHECK(esp_now_register_send_cb(on_data_sent));
ESP_ERROR_CHECK(esp_now_register_recv_cb(on_data_recv));
esp_now_peer_info_t peer = {0};
peer.channel = 1;
peer.ifidx = WIFI_IF_STA;
peer.encrypt = false;
// 遍历全部MAC_GROUP,**排除自己**
for(size_t i = 0; i < MAC_GROUP_COUNT; i++)
{
uint8_t *mac_item = s_MAC_GROUP[i];
if(memcmp(mac_item, s_my_mac, 6) == 0 || memcmp(mac_item, s_Broadcast_MAC, 6) == 0)
{
ESP_LOGI(TAG, "skip self/broadcast mac: " MACSTR, MAC2STR(mac_item));
continue;
}
memcpy(peer.peer_addr, mac_item, 6);
esp_err_t ret = esp_now_add_peer(&peer);
if(ret != ESP_OK)
{
ESP_LOGE(TAG, "add peer fail " MACSTR " ret=%d", MAC2STR(mac_item), ret);
}
else
{
ESP_LOGI(TAG, "add peer ok " MACSTR, MAC2STR(mac_item));
}
}
/**
* 加入广播地址
*/
uint8_t *mac_item = s_Broadcast_MAC;
memcpy(peer.peer_addr, mac_item, 6);
esp_err_t ret = esp_now_add_peer(&peer);
if(ret != ESP_OK)
{
ESP_LOGE(TAG, "add broadcast peer fail ret=%d", ret);
}
else
{
ESP_LOGI(TAG, "add broadcast peer ok");
}
}
void bsp_espnow_init(void){
wifi_init();
espnow_init();
}
void bsp_espnow_reinit(uint8_t macGroup[8][6],int n){
ESP_ERROR_CHECK(esp_now_deinit());
int pn = (n < 8) ? n : 8;
memcpy(s_MAC_GROUP, macGroup, 6*pn);
espnow_init();
}
bool bsp_espnow_add_peer(uint8_t mac[6])
{
if (!mac) {
ESP_LOGE(TAG, "add_peer: NULL mac");
return false;
}
// 检查是否为无效地址
uint8_t zero[6] = {0};
if (memcmp(mac, zero, 6) == 0 || memcmp(mac, s_Broadcast_MAC, 6) == 0) {
ESP_LOGW(TAG, "refuse to add zero/broadcast address");
return false;
}
esp_now_peer_info_t peer = {0};
peer.channel = 1;
peer.ifidx = WIFI_IF_STA;
peer.encrypt = false;
memcpy(peer.peer_addr, mac, 6); // 修正:使用传入的 mac
esp_err_t ret = esp_now_add_peer(&peer);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "add peer fail " MACSTR " ret=%d", MAC2STR(mac), ret);
return false;
} else {
ESP_LOGI(TAG, "add peer ok " MACSTR, MAC2STR(mac));
return true;
}
}
bool bsp_espnow_del_peer(const uint8_t mac[6])
{
if (!mac) {
ESP_LOGE(TAG, "del_peer: NULL mac");
return false;
}
esp_err_t ret = esp_now_del_peer(mac);
if (ret == ESP_OK || ret == ESP_ERR_ESPNOW_NOT_FOUND) {
ESP_LOGI(TAG, "del peer ok " MACSTR, MAC2STR(mac));
return true;
} else {
ESP_LOGE(TAG, "del peer failed " MACSTR " ret=%d", MAC2STR(mac), ret);
return false;
}
}
uint32_t bsp_espnow_write(uint8_t targetMac[6], uint8_t *buf, uint16_t len)
{
esp_err_t err = esp_now_send(targetMac, buf, len);
if (err == ESP_OK) {
return len;
} else {
ESP_LOGE(TAG, "send to " MACSTR " failed ret=%d", MAC2STR(targetMac), err);
return 0;
}
}
uint32_t bsp_espnow_read(uint8_t targetMac[6], void *recvBuf, uint32_t toRecvSize, uint32_t timeoutMs){
(void)targetMac;
(void)recvBuf;
(void)toRecvSize;
(void)timeoutMs;
return 0;
}
void bsp_espnow_setRecvCallBack(void (*OnFun)(uint8_t srcMac[6], uint8_t *buf, uint32_t len)){
s_user_recv_cb = OnFun;
}
void bsp_espnow_registerPaOps(const bsp_macPairingApp_ops *ops)
{
if (ops) {
s_paOps = *ops;
} else {
memset(&s_paOps, 0, sizeof(s_paOps));
}
}
bool bsp_espnow_getMyMac(uint8_t retMac[6]){
memcpy(retMac,s_my_mac,6);
return true;
}
bool bsp_espnow_getPairingMac(uint8_t idx,uint8_t retMac[6]){
if(s_paOps.get_mac==NULL){
return false;
}
return s_paOps.get_mac(idx,retMac);
}
mac_manager.h
#ifndef MAC_MANAGER_HPP
#define MAC_MANAGER_HPP
#include <cstdint>
#include <cstddef>
#include <functional>
#define MAC_ADDR_LEN 6
// 设备角色
enum class EspNowDeviceRole : uint8_t {
BASE_STATION = 0, // 基站:存储多个按键板 MAC
KEYPAD = 1, // 无线按键板:存储基站 MAC
};
// 最大存储数量
#ifndef MAC_MANAGER_MAX_COUNT
#define MAC_MANAGER_MAX_COUNT 8
#endif
class MacManager {
public:
// 角色在构造时确定,之后不可变
explicit MacManager(EspNowDeviceRole role);
~MacManager() = default;
// 初始化(加载 NVS)
void init();
// 从 NVS 加载 MAC 列表
void loadFromNvs();
// 保存 MAC 列表到 NVS
bool saveToNvs();
// 清空列表并保存到 NVS
bool clear();
// 添加 MAC
bool add(const uint8_t mac[MAC_ADDR_LEN]);
// 删除 MAC
bool remove(const uint8_t mac[MAC_ADDR_LEN]);
// 判断 MAC 是否存在
bool has(const uint8_t mac[MAC_ADDR_LEN]) const;
// 获取当前数量
size_t count() const { return m_count; }
// 获取最大容量
size_t maxCount() const { return m_max_count; }
// 是否已满
bool isFull() const { return m_count >= m_max_count; }
// 按索引获取 MAC
bool get(size_t index, uint8_t mac[MAC_ADDR_LEN]) const;
// 遍历所有 MAC,callback 返回 false 时停止
void foreach(std::function<bool(const uint8_t mac[MAC_ADDR_LEN])> callback) const;
// 打印当前列表
void print() const;
// 获取角色
EspNowDeviceRole getRole() const { return m_role; }
// ===== 对外暴露的 MAC 列表 =====
uint8_t m_mac_list[MAC_MANAGER_MAX_COUNT][MAC_ADDR_LEN];
private:
static bool macEqual(const uint8_t a[MAC_ADDR_LEN], const uint8_t b[MAC_ADDR_LEN]);
static bool macIsValid(const uint8_t mac[MAC_ADDR_LEN]);
EspNowDeviceRole m_role;
size_t m_max_count = MAC_MANAGER_MAX_COUNT;
size_t m_count = 0;
};
#endif
mac_manager.cpp
#include "mac_manager.h"
#include "bsp_nvsflash.h"
#include "bsp_espnow.h"
#include "esp_log.h"
#include <cstring>
static const char *TAG = "MAC_MGR";
// NVS key 根据角色区分
static const char *NVS_KEY_BASE = "base_macs";
static const char *NVS_KEY_KEYPAD = "keypad_macs";
// ============================================================
// 构造
// ============================================================
MacManager::MacManager(EspNowDeviceRole role)
: m_role(role)
, m_max_count(MAC_MANAGER_MAX_COUNT)
{
std::memset(m_mac_list, 0, sizeof(m_mac_list));
}
// ============================================================
// 初始化
// ============================================================
void MacManager::init()
{
loadFromNvs();
}
// ============================================================
// 获取当前角色对应的 NVS key
// ============================================================
static const char *getNvsKey(EspNowDeviceRole role)
{
return (role == EspNowDeviceRole::BASE_STATION) ? NVS_KEY_BASE : NVS_KEY_KEYPAD;
}
// ============================================================
// 从 NVS 加载
// ============================================================
void MacManager::loadFromNvs()
{
m_count = 0;
std::memset(m_mac_list, 0, sizeof(m_mac_list));
const char *key = getNvsKey(m_role);
size_t loaded = bsp_nvsflash_load_blob(
key,
m_mac_list,
sizeof(m_mac_list)
);
if (loaded == 0) {
ESP_LOGW(TAG, "[%s] No MAC list found, start with empty list", key);
return;
}
if (loaded % MAC_ADDR_LEN != 0) {
ESP_LOGE(TAG, "[%s] Invalid MAC list size: %zu", key, loaded);
m_count = 0;
return;
}
m_count = loaded / MAC_ADDR_LEN;
if (m_count > m_max_count) {
ESP_LOGE(TAG, "[%s] MAC count overflow: %zu", key, m_count);
m_count = m_max_count;
}
int addCnt=0;
for (int i = 0; i < m_count; ++i) {
bool ret=bsp_espnow_add_peer(m_mac_list[i]);
if(ret){
addCnt++;
}
}
ESP_LOGI(TAG, "[%s] Loaded %zu MAC(s) %d", key, m_count,addCnt);
}
// ============================================================
// 保存到 NVS
// ============================================================
bool MacManager::saveToNvs()
{
const char *key = getNvsKey(m_role);
if (m_count == 0) {
bsp_nvsflash_erase_key(key);
ESP_LOGI(TAG, "[%s] MAC list cleared in NVS", key);
return true;
}
bool ok = bsp_nvsflash_save_blob(
key,
m_mac_list,
m_count * MAC_ADDR_LEN
);
if (ok) {
ESP_LOGI(TAG, "[%s] Saved %zu MAC(s)", key, m_count);
}
return ok;
}
// ============================================================
// 清空
// ============================================================
bool MacManager::clear()
{
m_count = 0;
std::memset(m_mac_list, 0, sizeof(m_mac_list));
bool ret=saveToNvs();
if(ret){
bsp_espnow_reinit(m_mac_list,0);
}
return ret;
}
// ============================================================
// 比较两个 MAC
// ============================================================
bool MacManager::macEqual(const uint8_t a[MAC_ADDR_LEN], const uint8_t b[MAC_ADDR_LEN])
{
return std::memcmp(a, b, MAC_ADDR_LEN) == 0;
}
// ============================================================
// 判断 MAC 是否有效
// ============================================================
bool MacManager::macIsValid(const uint8_t mac[MAC_ADDR_LEN])
{
uint8_t zero[MAC_ADDR_LEN] = {0};
uint8_t ff[MAC_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if (macEqual(mac, zero) || macEqual(mac, ff)) {
return false;
}
return true;
}
// ============================================================
// 添加 MAC
// ============================================================
bool MacManager::add(const uint8_t mac[MAC_ADDR_LEN])
{
if (!macIsValid(mac)) {
ESP_LOGE(TAG, "Invalid MAC");
return false;
}
if (has(mac)) {
ESP_LOGW(TAG, "MAC already exists");
return false;
}
if (isFull()) {
ESP_LOGE(TAG, "MAC list is full (max=%zu)", m_max_count);
return false;
}
std::memcpy(m_mac_list[m_count], mac, MAC_ADDR_LEN);
m_count++;
bool ret= saveToNvs();
return ret;
}
// ============================================================
// 删除 MAC
// ============================================================
bool MacManager::remove(const uint8_t mac[MAC_ADDR_LEN])
{
if (m_count == 0) {
return false;
}
size_t found = m_count;
for (size_t i = 0; i < m_count; i++) {
if (macEqual(m_mac_list[i], mac)) {
found = i;
break;
}
}
if (found == m_count) {
ESP_LOGW(TAG, "MAC not found");
return false;
}
// 后面的往前移
for (size_t i = found; i + 1 < m_count; i++) {
std::memcpy(m_mac_list[i], m_mac_list[i + 1], MAC_ADDR_LEN);
}
m_count--;
std::memset(m_mac_list[m_count], 0, MAC_ADDR_LEN);
bsp_espnow_del_peer(mac);
return saveToNvs();
}
// ============================================================
// 判断是否存在
// ============================================================
bool MacManager::has(const uint8_t mac[MAC_ADDR_LEN]) const
{
for (size_t i = 0; i < m_count; i++) {
if (macEqual(m_mac_list[i], mac)) {
return true;
}
}
return false;
}
// ============================================================
// 按索引获取
// ============================================================
bool MacManager::get(size_t index, uint8_t mac[MAC_ADDR_LEN]) const
{
if (index >= m_count) {
return false;
}
std::memcpy(mac, m_mac_list[index], MAC_ADDR_LEN);
return true;
}
// ============================================================
// 遍历
// ============================================================
void MacManager::foreach(std::function<bool(const uint8_t mac[MAC_ADDR_LEN])> callback) const
{
if (!callback) {
return;
}
for (size_t i = 0; i < m_count; i++) {
if (!callback(m_mac_list[i])) {
break;
}
}
}
// ============================================================
// 打印
// ============================================================
void MacManager::print() const
{
const char *role_str = (m_role == EspNowDeviceRole::BASE_STATION) ? "BASE_STATION" : "KEYPAD";
ESP_LOGI(TAG, "===== MAC List [%s] (%zu/%zu) =====", role_str, m_count, m_max_count);
for (size_t i = 0; i < m_count; i++) {
ESP_LOGI(TAG, " [%zu] %02X:%02X:%02X:%02X:%02X:%02X",
i,
m_mac_list[i][0], m_mac_list[i][1], m_mac_list[i][2],
m_mac_list[i][3], m_mac_list[i][4], m_mac_list[i][5]);
}
ESP_LOGI(TAG, "================================");
}
MacPairingApp.h
#ifndef MAC_PAIRING_APP_HPP
#define MAC_PAIRING_APP_HPP
#include "mac_manager.h"
#include <cstdint>
#include <functional>
/**
* 终端状态完全由 mac表是否非空决定
* 基站mac则由外部决定
*/
// 配对状态
enum class PairState : uint8_t {
ADDING=0, // 正在添加配对
PAIRED // 已配对
};
// MAC 配对应用App
class MacPairingApp {
public:
// 获取单例实例
static MacPairingApp * getInstance();
// 禁止拷贝和赋值
MacPairingApp(const MacPairingApp&) = delete;
MacPairingApp& operator=(const MacPairingApp&) = delete;
/**
* @brief 初始化:传入 MacManager 引用,加载 NVS,设置初始状态
* @param macManager MacManager 引用(必须保持生命周期)
* @return true 成功
*/
bool init(EspNowDeviceRole role);
/**
* @brief 主循环,需周期性调用(建议 10~100ms)
*/
void loop(uint32_t ms);
/** 清空已配对的mac表
* @brief 启动添加配对(仅 BASE_STATION,且无 MAC 时有效)
*/
bool clearMacList();
/**
* @brief 启动添加配对
*/
void startAdding();
void stopAdding();
/**
* @brief 获取当前已配对的 MAC 数量
*/
size_t getMacCount() const;
/**
* @brief 按索引获取 MAC 地址
* @param index 索引(0 ~ getMacCount()-1)
* @param mac 输出缓冲区(至少 MAC_ADDR_LEN 字节)
* @return true 获取成功
*/
bool getMacByIndex(size_t index, uint8_t mac[MAC_ADDR_LEN]) const;
/**
* @brief 获取当前配对状态
*/
PairState getState() const { return m_state; }
/**
* @brief 设置状态变化回调(外部根据状态控制 LED 等)
*/
void setStateChangeCallback(std::function<void(PairState)> callback);
/**
* @brief 设置发送配对请求的回调(由外部实现实际发送)
*/
void setSendRequestCallback(std::function<void()> callback);
/**
* @brief 收到外部配对请求时调用(由 ESP-NOW 接收回调触发)
* @param srcMac 请求源 MAC
*/
void onPairRequestReceived(const uint8_t* srcMac);
/**
* @brief 收到外部配对响应时调用(由 ESP-NOW 接收回调触发)
* @param srcMac 响应源 MAC
*/
void onPairResponseReceived(const uint8_t* srcMac);
private:
// 私有构造函数
MacPairingApp() = default;
~MacPairingApp() = default;
MacManager* m_macManager;
PairState m_state;
uint32_t m_lastActionTime; // 用于重发/超时
uint32_t m_nowMs;
// 回调
std::function<void(PairState)> m_stateChangeCb;
std::function<void()> m_sendRequestCb;
// 内部方法
void updateState(); // 根据 MAC 数量更新状态
void handleAdding(); // ADDING 状态动作
void handlePaired(); // PAIRED 状态动作
void notifyStateChange(PairState newState);
//BASE 添加超时 2000ms 发送一次扫描
static constexpr uint32_t ADDING_TIMEOUT_MS = 2000;
// 单例标志
bool m_initialized = false;
};
#endif // MAC_PAIRING_APP_HPP
MacPairingApp.cpp
#include "MacPairingApp.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "bsp_espnow.h"
#include <cstring>
static const char* TAG = "MacPairingApp";
static MacPairingApp * s_instance= nullptr;
MacPairingApp * MacPairingApp::getInstance() {
if(s_instance== nullptr){
s_instance=new MacPairingApp();
}
return s_instance;
}
// 给bsp_espnow提供的过滤函数:根据配对状态决定是否放行
static bool espNowMacRecvFilter(uint8_t srcMac[6])
{
MacPairingApp* app = s_instance;
if (!app) {
return false; // 安全处理
}
PairState state = app->getState();
if (state == PairState::ADDING) {
// ADDING 模式:允许所有来源(不过滤)
return true;
} else { // PAIRED
// PAIRED 模式:仅允许已配对的 MAC
size_t count = app->getMacCount();
for (size_t i = 0; i < count; i++) {
uint8_t mac[MAC_ADDR_LEN];
if (app->getMacByIndex(i, mac)) {
if (memcmp(mac, srcMac, MAC_ADDR_LEN) == 0) {
return true;
}
}
}
return false;// 不是已配对的mac过滤掉
}
}
// 给bsp_espnow提供的获取mac函数
static bool espNowGetMac(uint8_t idx, uint8_t mac[6]){
MacPairingApp* app = s_instance;
if (!app) {
return false;
}
return app->getMacByIndex(idx,mac);
}
bool MacPairingApp::init(EspNowDeviceRole role) {
if (m_initialized) {
ESP_LOGW(TAG, "Already initialized");
return true;
}
m_macManager=new MacManager(role);
// 加载 NVS 中的 MAC 列表
m_macManager->loadFromNvs();
//给bsp_espnow提供函数
bsp_macPairingApp_ops ops = {
.recv_filter = espNowMacRecvFilter,
.get_mac = espNowGetMac,
};
bsp_espnow_registerPaOps(&ops);
//默认为已配对
m_state = PairState::PAIRED;
notifyStateChange(m_state);
ESP_LOGI(TAG, "MacPairingApp initialized, role=%d, count=%d, state=%d",(int)role, (int)m_macManager->count(), (int)m_state);
m_initialized= true;
return true;
}
void MacPairingApp::loop(uint32_t ms) {
m_nowMs = ms;
// 更新状态
updateState();
// 根据状态执行动作
switch (m_state) {
case PairState::ADDING:
handleAdding();
break;
case PairState::PAIRED:
handlePaired();
break;
}
}
// ============================ 状态更新,终端根据配对数更新,基站外部更新 ============================
void MacPairingApp::updateState() {
size_t count = m_macManager->count();
EspNowDeviceRole role = m_macManager->getRole();
PairState oldState = m_state;
if (role == EspNowDeviceRole::KEYPAD) {
//终端只有两个状态
m_state = (count == 0) ? PairState::ADDING : PairState::PAIRED;
}
if (m_state != oldState) {
notifyStateChange(m_state);
}
}
void MacPairingApp::handleAdding() {
EspNowDeviceRole role = m_macManager->getRole();
/**
* 只有基站能主动发出配对请求
*/
if(role!=EspNowDeviceRole::BASE_STATION){
return;
}
uint32_t now = m_nowMs;
if (now - m_lastActionTime >= ADDING_TIMEOUT_MS) {
if(m_sendRequestCb!= nullptr){
m_sendRequestCb();
}
m_lastActionTime =m_nowMs;
}
}
void MacPairingApp::handlePaired() {
// 已配对:无需额外动作
}
// ============================ 外部触发 ============================
void MacPairingApp::startAdding() {
if (m_state != PairState::ADDING) {
m_state = PairState::ADDING;
m_lastActionTime =m_nowMs;
notifyStateChange(m_state);
ESP_LOGI(TAG, "Enter ADDING state");
}
}
void MacPairingApp::stopAdding(){
if (m_state != PairState::PAIRED) {
m_state = PairState::PAIRED;
m_lastActionTime =m_nowMs;
notifyStateChange(m_state);
}
}
// ============================ 终端接收基站配对的回调============================
void MacPairingApp::onPairRequestReceived(const uint8_t* srcMac) {
if (m_macManager->getRole() == EspNowDeviceRole::BASE_STATION) {
return;
}
/**
* 已配对的忽略
*/
if (m_state==PairState::PAIRED) {
return;
}
if (m_macManager->has(srcMac)) {
ESP_LOGW(TAG, "Device already paired");
return;
}
if (m_macManager->add(srcMac)) {
ESP_LOGI(TAG, "Added peer MAC " MACSTR, MAC2STR(srcMac));
} else {
ESP_LOGE(TAG, "Failed to add MAC (list full?)");
}
}
void MacPairingApp::onPairResponseReceived(const uint8_t* srcMac) {
if (m_macManager->getRole() == EspNowDeviceRole::KEYPAD) {
return;
}
if (m_macManager->count() == 0) {
if (m_macManager->add(srcMac)) {
ESP_LOGI(TAG, "Added base station MAC " MACSTR, MAC2STR(srcMac));
} else {
ESP_LOGE(TAG, "Failed to add base MAC");
}
}
}
// ============================ 回调设置 ============================
void MacPairingApp::setStateChangeCallback(std::function<void(PairState)> callback) {
m_stateChangeCb = callback;
}
void MacPairingApp::setSendRequestCallback(std::function<void()> callback) {
m_sendRequestCb = callback;
}
void MacPairingApp::notifyStateChange(PairState newState) {
if (m_stateChangeCb) {
m_stateChangeCb(newState);
}
}
bool MacPairingApp::clearMacList() {
if (!m_initialized || m_macManager == nullptr) {
ESP_LOGW(TAG, "Not initialized, cannot clear");
return false;
}
if (m_macManager->clear()) {
// 重置状态为 UNPAIRED
PairState oldState = m_state;
m_state = PairState::ADDING;
// 重置定时器,以便立即发送请求,
m_lastActionTime = m_nowMs;
// 如果处于 ADDING,清除其影响(如果有额外标志)
// 这里因为状态变为 UNPAIRED,ADDING 自然退出
if (oldState != m_state) {
notifyStateChange(m_state);
}
ESP_LOGI(TAG, "MAC list cleared, state reset to UNPAIRED");
return true;
} else {
ESP_LOGE(TAG, "Failed to clear MAC list");
return false;
}
}
size_t MacPairingApp::getMacCount() const {
if (!m_initialized || m_macManager == nullptr) {
return 0;
}
return m_macManager->count();
}
bool MacPairingApp::getMacByIndex(size_t index, uint8_t mac[MAC_ADDR_LEN]) const {
if (!m_initialized || m_macManager == nullptr) {
return false;
}
return m_macManager->get(index, mac);
}
App.h
#ifndef modman_APP_H
#define modman_APP_H
#include "stdint.h"
class App {
public:
static bool Init(void);
static void Loop(uint32_t ms);
};
#endif
EventBus.h
#ifndef EVENT_BUS_H
#define EVENT_BUS_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// 事件类型定义
typedef enum {
EVENT_NONE = 0,
EVENT_PUSH_LED_CMD=1,
EVENT_PUSH_DATA = 2,
//配对请求
EVENT_ESP_MAC_PAIR_REQUEST = 3,
//配对响应
EVENT_ESP_MAC_PAIR_RESPONSE = 4,
//复位配对
EVENT_ESP_MAC_PAIR_RESET = 5
} EventType;
// 事件回调函数类型
typedef void (*EventFunc)(EventType evt, void* data);
// 订阅事件
void Event_Subscribe(EventType evt, EventFunc func);
// 取消订阅
void Event_Unsubscribe(EventType evt);
//发布事件
void Event_Publish(EventType evt, void* data);
#ifdef __cplusplus
}
#endif
#endif // EVENT_BUS_H
EventBus.cpp
#include "EventBus.h"
// ========== 条件编译:是否启用锁 ==========
// 若未定义 ENABLE_EVENT_LOCK,则编译为无锁版本(单线程或裸机环境)
#define ENABLE_EVENT_LOCK 1
#if ENABLE_EVENT_LOCK==1
#include "cxthread.h"
static CxLock g_event_lock;
#define EVENT_LOCK_TAKE() (g_event_lock.WaitFor(portMAX_DELAY))
#define EVENT_LOCK_GIVE() (g_event_lock.Release())
#else
// 无锁模式:所有锁操作定义为空(始终返回真)
#define EVENT_LOCK_TAKE() (1)
#define EVENT_LOCK_GIVE() ((void)0)
#endif
// ========== 常量定义 ==========
#define MAX_EVENT_HANDLERS 1
static EventFunc s_event_handlers[6 + 1][MAX_EVENT_HANDLERS] = { {0} };
// ========== 订阅 ==========
void Event_Subscribe(EventType evt, EventFunc func) {
if (func == 0 || evt >= sizeof(s_event_handlers) / sizeof(s_event_handlers[0])) {
return;
}
if (EVENT_LOCK_TAKE()) {
for (int i = 0; i < MAX_EVENT_HANDLERS; i++) {
if (s_event_handlers[evt][i] == 0) {
s_event_handlers[evt][i] = func;
break;
}
}
EVENT_LOCK_GIVE();
}
}
// ========== 取消订阅 ==========
void Event_Unsubscribe(EventType evt) {
if (evt >= sizeof(s_event_handlers) / sizeof(s_event_handlers[0])) {
return;
}
if (EVENT_LOCK_TAKE()) {
for (int i = 0; i < MAX_EVENT_HANDLERS; i++) {
s_event_handlers[evt][i] = 0;
}
EVENT_LOCK_GIVE();
}
}
// ========== 发布事件 ==========
void Event_Publish(EventType evt, void* data) {
if (evt >= sizeof(s_event_handlers) / sizeof(s_event_handlers[0])) {
return;
}
EventFunc local_handlers[MAX_EVENT_HANDLERS];
int count = 0;
if (EVENT_LOCK_TAKE()) {
for (int i = 0; i < MAX_EVENT_HANDLERS; i++) {
if (s_event_handlers[evt][i] != 0) {
local_handlers[count++] = s_event_handlers[evt][i];
}
}
EVENT_LOCK_GIVE();
}
// 无锁执行回调
for (int i = 0; i < count; i++) {
local_handlers[i](evt, data);
}
}
基站 App.cpp
#define OS_GLOBALS
#include "App.h"
#include "Main_constant.h"
#include "MacPairingApp.h"
#include "EventBus.h"
#include "bsp_espnow.h"
#include "esp_log.h"
#include "esp_mac.h"
static MacPairingApp * s_macPairingApp= nullptr;
static const char *TAG = "App";
static void onEspNowRecvEvent(EventType evt, void* data) {
//基站收到外部配对响应
if(evt == EVENT_ESP_MAC_PAIR_RESPONSE){
uint8_t* srcMac=(uint8_t*)data;
s_macPairingApp->onPairResponseReceived(srcMac);
}
}
/**
* 发送配对请求
*/
static void espNowMacDisCover() {
uint8_t resMac[6];
uint16_t ret= modmanDisCover(resMac);
if(ret){
ESP_LOGI(TAG, "espNowMacDisCover: " MACSTR, MAC2STR(resMac));
Event_Publish(EVENT_ESP_MAC_PAIR_RESPONSE,resMac);
} else{
ESP_LOGW(TAG, "espNowMacDisCover failed, ret=%d", ret);
}
}
/**
* mac 配对状态改变,更改灯闪烁模式
* @param state
*/
static void espNowStatusChangeCallBack(PairState state){
static uint32_t ledCmd= 0;
if(state==PairState::ADDING){
//LED0 快闪
ledCmd=3;
Event_Publish(EVENT_PUSH_LED_CMD,&ledCmd);
} else if(state==PairState::PAIRED){
//灯全灭
ledCmd=0;
Event_Publish(EVENT_PUSH_LED_CMD,&ledCmd);
}
}
bool App::Init() {
//基站
s_macPairingApp= MacPairingApp::getInstance();
s_macPairingApp->init(EspNowDeviceRole::BASE_STATION);
//基站发现终端
s_macPairingApp->setSendRequestCallback(espNowMacDisCover);
//配对状态改变
s_macPairingApp->setStateChangeCallback(espNowStatusChangeCallBack);
//外部来的配对响应
Event_Subscribe(EVENT_ESP_MAC_PAIR_RESPONSE, onEspNowRecvEvent);
return true;
}
/**
* 约100ms每次
* @param ms
*/
void App::Loop(uint32_t ms)
{
s_macPairingApp->loop(ms);
}
终端 App.cpp
#define OS_GLOBALS
#include "App.h"
#include "Main_constant.h"
#include "MacPairingApp.h"
#include "EventBus.h"
#include "esp_log.h"
#include "esp_mac.h"
static MacPairingApp * s_macPairingApp= nullptr;
static const char *TAG = "App";
static void onEspNowRecvEvent(EventType evt, void* data) {
if (evt == EVENT_ESP_MAC_PAIR_REQUEST) {
uint8_t* srcMac = (uint8_t*)data;
ESP_LOGI(TAG, "Pair request from " MACSTR, MAC2STR(srcMac));
s_macPairingApp->onPairRequestReceived(srcMac);
//按键板长配对复位按键则清空配对表
} else if (evt == EVENT_ESP_MAC_PAIR_RESET) {
ESP_LOGI(TAG, "Pair reset triggered");
s_macPairingApp->clearMacList();
}
}
/**
* mac 配对状态改变,更改灯闪烁模式
* @param state
*/
static void espNowStatusChangeCallBack(PairState state){
static uint32_t ledCmd= 0;
if(state==PairState::ADDING){
//LED0 快闪
ledCmd=3;
Event_Publish(EVENT_PUSH_LED_CMD,&ledCmd);
} else if(state==PairState::PAIRED){
//灯全灭
ledCmd=0;
Event_Publish(EVENT_PUSH_LED_CMD,&ledCmd);
}
}
bool App::Init() {
//终端
s_macPairingApp= MacPairingApp::getInstance();
s_macPairingApp->init(EspNowDeviceRole::KEYPAD);
uint8_t macCnt=s_macPairingApp->getMacCount();
//配对状态改变
s_macPairingApp->setStateChangeCallback(espNowStatusChangeCallBack);
//外部来的请求
Event_Subscribe(EVENT_ESP_MAC_PAIR_REQUEST, onEspNowRecvEvent);
Event_Subscribe(EVENT_ESP_MAC_PAIR_RESET, onEspNowRecvEvent);
return true;
}
/**
* 约100ms每次
* @param ms
*/
void App::Loop(uint32_t ms)
{
s_macPairingApp->loop(ms);
}