espidf的espnow的配对

参考

esp32-idf环境安装配置.csdn

bsp_espnow.h

c 复制代码
#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

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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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);
}
相关推荐
逆境不可逃1 小时前
Pi Agent 学习笔记:一次提问背后的工具调用循环
java·笔记·学习
Peng7113 小时前
浙大数据可视化课程学习笔记
笔记·学习·信息可视化
笨鸟先飞的橘猫3 小时前
slg游戏面试复盘
学习·面试
你想知道什么?4 小时前
神经网络-学习笔记
笔记·神经网络·学习
CappuccinoRose4 小时前
专项事件体系
前端·学习·网络状态·表单事件·剪贴板事件·拖放事件·页面可见性
(Charon)5 小时前
【Kafka】消息队列学习(一):为什么需要Kafka?从消息队列到整体架构
学习·架构·kafka
传奇开心果编程5 小时前
【Rust入门知识点学与练】第26课:Unsafe Rust
开发语言·学习·rust
励志不掉头发的内向程序员5 小时前
【LibreCAD 2D架构】从 addHistory 到 RS_UndoCycle:LibreCAD 里的两套 History 与撤销机制
开发语言·c++·qt·学习·系统架构
`流年づ5 小时前
人工智能学习笔记 - 自动微分
人工智能·笔记·学习