ESP-NOW bridge for P4 (#573)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include "ChatState.h"
|
||||
#include "ChatView.h"
|
||||
@@ -43,4 +43,4 @@ public:
|
||||
|
||||
} // namespace tt::app::chat
|
||||
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -94,4 +94,4 @@ size_t getMaxMessageLength(size_t nicknameLen, size_t targetLen);
|
||||
|
||||
} // namespace tt::app::chat
|
||||
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -28,4 +28,4 @@ bool settingsFileExists();
|
||||
|
||||
} // namespace tt::app::chat
|
||||
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
|
||||
@@ -56,4 +56,4 @@ public:
|
||||
|
||||
} // namespace tt::app::chat
|
||||
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) && !defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include "ChatState.h"
|
||||
#include "ChatSettings.h"
|
||||
@@ -76,4 +76,4 @@ public:
|
||||
|
||||
} // namespace tt::app::chat
|
||||
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED && !CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include <Tactility/service/espnow/EspNow.h>
|
||||
|
||||
namespace tt::service::espnow::backend {
|
||||
|
||||
/**
|
||||
* Bring up the backend (WiFi if needed + ESP-NOW init + recv/send callbacks + PMK).
|
||||
* Native backend calls esp_now_* directly; hosted backend bridges over esp_hosted's
|
||||
* custom RPC channel to the co-processor. Either way, recvCallback is invoked with
|
||||
* the same signature ESP-NOW itself uses.
|
||||
*/
|
||||
bool init(const EspNowConfig& config, esp_now_recv_cb_t recvCallback);
|
||||
|
||||
bool deinit();
|
||||
|
||||
bool addPeer(const esp_now_peer_info_t& peer);
|
||||
|
||||
bool send(const uint8_t* address, const uint8_t* buffer, size_t bufferLength);
|
||||
|
||||
/** Returns 0 if not initialized. */
|
||||
uint32_t getVersion();
|
||||
|
||||
}
|
||||
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::service::espnow::backend {
|
||||
|
||||
/**
|
||||
* The esp_hosted SDIO transport to the co-processor is brought up by esp_hosted_init()
|
||||
* (auto-called at process startup via a constructor attribute - always runs regardless of
|
||||
* WiFi/BT state), but the actual slave handshake only happens via esp_hosted_connect_to_slave(),
|
||||
* which today is only called as a side effect of the WiFi or BT stack starting
|
||||
* (esp32_wifi.cpp / vhci_drv.c). Nothing in Tactility's boot sequence calls it on its own, so
|
||||
* without this, ESP-NOW-over-bridge would require WiFi or BT to already be enabled - unlike
|
||||
* native ESP32 chips where ESP-NOW works standalone.
|
||||
*
|
||||
* This actively triggers the slave connect (safe to call even if already connected - the
|
||||
* underlying transport_drv_reconfigure() checks is_transport_tx_ready() first and returns
|
||||
* immediately if so) and then polls until the link is confirmed up or the timeout expires.
|
||||
*
|
||||
* @param timeoutMs how long to poll after triggering the connect before giving up
|
||||
* @return true once the transport is confirmed up, false on timeout
|
||||
*/
|
||||
bool waitForHostedTransport(uint32_t timeoutMs);
|
||||
|
||||
}
|
||||
|
||||
#endif // CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_ENABLED
|
||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||
|
||||
#include <Tactility/service/Service.h>
|
||||
#include <Tactility/service/espnow/EspNow.h>
|
||||
@@ -75,4 +75,4 @@ std::shared_ptr<EspNowService> findService();
|
||||
|
||||
}
|
||||
|
||||
#endif // ESP_PLATFORM
|
||||
#endif // CONFIG_SOC_WIFI_SUPPORTED || CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_ENABLED
|
||||
|
||||
#include "Tactility/service/espnow/EspNow.h"
|
||||
|
||||
namespace tt::service::espnow {
|
||||
|
||||
bool initWifi(const EspNowConfig& config);
|
||||
|
||||
bool deinitWifi();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Tactility
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Wire format for bridging ESP-NOW across esp-hosted-mcu's custom RPC
|
||||
* channel (esp_hosted_send_custom_data / esp_hosted_register_custom_callback).
|
||||
* Shared verbatim between slave (runs real esp_now_*) and host (P4, no radio).
|
||||
*
|
||||
* Kept in sync by hand with the copy in the esp-hosted-mcu fork at
|
||||
* common/espnow_bridge/esp_hosted_espnow_bridge_proto.h (Shadowtrance/esp-hosted-mcu,
|
||||
* branch feature/espnow-bridge) — this is a wire-format contract between two repos.
|
||||
*/
|
||||
|
||||
#ifndef __ESP_HOSTED_ESPNOW_BRIDGE_PROTO_H
|
||||
#define __ESP_HOSTED_ESPNOW_BRIDGE_PROTO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* msg_id namespace: any uint32_t except 0xFFFFFFFF (reserved by esp_hosted). */
|
||||
#define ESPNOW_BRIDGE_MSG_BASE 0xE500U
|
||||
#define ESPNOW_BRIDGE_REQ_INIT (ESPNOW_BRIDGE_MSG_BASE + 0)
|
||||
#define ESPNOW_BRIDGE_RESP_INIT (ESPNOW_BRIDGE_MSG_BASE + 1)
|
||||
#define ESPNOW_BRIDGE_REQ_DEINIT (ESPNOW_BRIDGE_MSG_BASE + 2)
|
||||
#define ESPNOW_BRIDGE_RESP_DEINIT (ESPNOW_BRIDGE_MSG_BASE + 3)
|
||||
#define ESPNOW_BRIDGE_REQ_ADD_PEER (ESPNOW_BRIDGE_MSG_BASE + 4)
|
||||
#define ESPNOW_BRIDGE_RESP_ADD_PEER (ESPNOW_BRIDGE_MSG_BASE + 5)
|
||||
#define ESPNOW_BRIDGE_REQ_SEND (ESPNOW_BRIDGE_MSG_BASE + 6)
|
||||
#define ESPNOW_BRIDGE_RESP_SEND (ESPNOW_BRIDGE_MSG_BASE + 7)
|
||||
#define ESPNOW_BRIDGE_EVT_RECV (ESPNOW_BRIDGE_MSG_BASE + 8)
|
||||
#define ESPNOW_BRIDGE_EVT_SEND_STATUS (ESPNOW_BRIDGE_MSG_BASE + 9)
|
||||
|
||||
#define ESPNOW_BRIDGE_ETH_ALEN 6
|
||||
#define ESPNOW_BRIDGE_KEY_LEN 16
|
||||
/* ESP-NOW v2.0 payload limit (ESP_NOW_MAX_DATA_LEN_V2 in esp_now.h). The slave reports its
|
||||
* actual negotiated esp_now_get_version() back to the host in RESP_INIT; hosts talking to a
|
||||
* v1.0-only slave still work, they just never send payloads over 250B (native ESP-NOW callers
|
||||
* enforce that themselves based on the reported version, same as the non-bridged backend). */
|
||||
#define ESPNOW_BRIDGE_MAX_DATA_LEN 1470
|
||||
|
||||
/* req_init mode: matches tt::service::espnow::Mode / WIFI_MODE_STA vs WIFI_MODE_AP on the slave */
|
||||
#define ESPNOW_BRIDGE_MODE_STATION 0U
|
||||
#define ESPNOW_BRIDGE_MODE_ACCESS_POINT 1U
|
||||
|
||||
/* req: ESPNOW_BRIDGE_REQ_INIT */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t txn_id; /* echoed back verbatim in the matching resp_status_t/resp_init_t so a
|
||||
* response arriving after its request already timed out (e.g. a slow
|
||||
* REQ_INIT retry) can't be mistaken for the answer to a newer request
|
||||
* of the same type - see EspNowBackendHosted.cpp's doRequest(). */
|
||||
uint8_t pmk[ESPNOW_BRIDGE_KEY_LEN];
|
||||
uint8_t channel; /* 0 = use current STA/AP channel */
|
||||
uint8_t long_range; /* bool as uint8_t: fixed 1-byte width for this hand-synced wire struct */
|
||||
uint8_t mode; /* ESPNOW_BRIDGE_MODE_STATION / ESPNOW_BRIDGE_MODE_ACCESS_POINT: which WiFi
|
||||
* mode+interface the slave should bring up and register ESP-NOW against */
|
||||
} espnow_bridge_req_init_t;
|
||||
|
||||
/* req: ESPNOW_BRIDGE_REQ_DEINIT */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t txn_id; /* see espnow_bridge_req_init_t::txn_id */
|
||||
} espnow_bridge_req_deinit_t;
|
||||
|
||||
/* resp: ESPNOW_BRIDGE_RESP_DEINIT / RESP_ADD_PEER / RESP_SEND */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t txn_id; /* copied from the request this responds to */
|
||||
int32_t esp_err; /* raw esp_err_t from the slave-side call */
|
||||
} espnow_bridge_resp_status_t;
|
||||
|
||||
/* resp: ESPNOW_BRIDGE_RESP_INIT */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t txn_id; /* copied from the request this responds to */
|
||||
int32_t esp_err; /* raw esp_err_t from the slave-side esp_now_init() call */
|
||||
uint32_t espnow_version; /* esp_now_get_version() result, 0 if esp_err != ESP_OK */
|
||||
} espnow_bridge_resp_init_t;
|
||||
|
||||
/* req: ESPNOW_BRIDGE_REQ_ADD_PEER */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t txn_id; /* see espnow_bridge_req_init_t::txn_id */
|
||||
uint8_t peer_addr[ESPNOW_BRIDGE_ETH_ALEN];
|
||||
uint8_t lmk[ESPNOW_BRIDGE_KEY_LEN];
|
||||
uint8_t channel;
|
||||
uint8_t encrypt; /* bool as uint8_t: fixed 1-byte width for this hand-synced wire struct */
|
||||
uint8_t ifidx; /* ESPNOW_BRIDGE_MODE_STATION / ESPNOW_BRIDGE_MODE_ACCESS_POINT: which
|
||||
* interface (WIFI_IF_STA / WIFI_IF_AP) to bind the peer to on the slave,
|
||||
* matching esp_now_peer_info_t::ifidx on native */
|
||||
} espnow_bridge_req_add_peer_t;
|
||||
|
||||
/* req: ESPNOW_BRIDGE_REQ_SEND */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t txn_id; /* see espnow_bridge_req_init_t::txn_id */
|
||||
uint8_t dest_addr[ESPNOW_BRIDGE_ETH_ALEN];
|
||||
uint8_t broadcast; /* bool as uint8_t; true: dest_addr ignored, esp_now_send(NULL, ...) */
|
||||
uint16_t data_len;
|
||||
uint8_t data[ESPNOW_BRIDGE_MAX_DATA_LEN];
|
||||
} espnow_bridge_req_send_t;
|
||||
|
||||
/* event: ESPNOW_BRIDGE_EVT_RECV (slave-initiated, unsolicited) */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t src_addr[ESPNOW_BRIDGE_ETH_ALEN];
|
||||
uint8_t des_addr[ESPNOW_BRIDGE_ETH_ALEN];
|
||||
int8_t rssi;
|
||||
uint8_t channel;
|
||||
uint16_t data_len;
|
||||
uint8_t data[ESPNOW_BRIDGE_MAX_DATA_LEN];
|
||||
} espnow_bridge_evt_recv_t;
|
||||
|
||||
/* event: ESPNOW_BRIDGE_EVT_SEND_STATUS (slave-initiated, unsolicited) */
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t peer_addr[ESPNOW_BRIDGE_ETH_ALEN];
|
||||
uint8_t success; /* bool as uint8_t: fixed 1-byte width for this hand-synced wire struct */
|
||||
} espnow_bridge_evt_send_status_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_HOSTED_ESPNOW_BRIDGE_PROTO_H */
|
||||
Reference in New Issue
Block a user