16#include <esp_idf_version.h>
20const uint8_t PC_ESPNOW_BROADCAST[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
25size_t pc_espnow_encode(uint8_t type,
const uint8_t *payload,
size_t len, uint8_t *out,
size_t cap)
27 if (!out || len > PC_ESPNOW_MAX_PAYLOAD || cap < len + PC_ESPNOW_HDR)
31 out[0] = PC_ESPNOW_MAGIC;
33 out[2] = (uint8_t)len;
36 memcpy(out + PC_ESPNOW_HDR, payload, len);
38 return len + PC_ESPNOW_HDR;
41bool pc_espnow_decode(
const uint8_t *buf,
size_t len, uint8_t *type,
const uint8_t **payload,
size_t *plen)
43 if (!buf || len < PC_ESPNOW_HDR || buf[0] != PC_ESPNOW_MAGIC)
47 size_t declared = buf[2];
48 if (declared + PC_ESPNOW_HDR != len)
58 *payload = buf + PC_ESPNOW_HDR;
83 Peer peers[PC_ESPNOW_MAX_PEERS];
85 pc_espnow_recv_fn recv =
nullptr;
91int peer_find(
const EspnowCtx &c,
const uint8_t mac[6])
93 for (
int i = 0; i < PC_ESPNOW_MAX_PEERS; i++)
95 if (c.peers[i].used && memcmp(c.peers[i].mac, mac, 6) == 0)
104void pc_espnow_peers_reset(
void)
106 for (
int i = 0; i < PC_ESPNOW_MAX_PEERS; i++)
108 s_espnow.peers[i].used =
false;
112bool pc_espnow_peer_add(
const uint8_t mac[6])
118 if (peer_find(s_espnow, mac) >= 0)
122 for (
int i = 0; i < PC_ESPNOW_MAX_PEERS; i++)
124 if (!s_espnow.peers[i].used)
126 memcpy(s_espnow.peers[i].mac, mac, 6);
127 s_espnow.peers[i].used =
true;
134bool pc_espnow_peer_has(
const uint8_t mac[6])
136 return mac && peer_find(s_espnow, mac) >= 0;
139bool pc_espnow_peer_remove(
const uint8_t mac[6])
141 int i = mac ? peer_find(s_espnow, mac) : -1;
146 s_espnow.peers[i].used =
false;
150int pc_espnow_peer_count(
void)
153 for (
int i = 0; i < PC_ESPNOW_MAX_PEERS; i++)
155 if (s_espnow.peers[i].used)
172#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
173void on_recv(
const esp_now_recv_info_t *info,
const uint8_t *data,
int len)
175 const uint8_t *mac = info ? info->src_addr :
nullptr;
177void on_recv(
const uint8_t *mac,
const uint8_t *data,
int len)
180 if (!s_espnow.recv || len < 0 || !mac)
185 const uint8_t *payload;
187 if (pc_espnow_decode(data, (
size_t)len, &type, &payload, &plen))
189 s_espnow.recv(mac, type, payload, plen);
193bool radio_add_peer(
const uint8_t mac[6], uint8_t channel)
195 esp_now_peer_info_t p;
196 memset(&p, 0,
sizeof(p));
197 memcpy(p.peer_addr, mac, 6);
200 if (esp_now_is_peer_exist(mac))
204 return esp_now_add_peer(&p) == ESP_OK;
208bool pc_espnow_begin(uint8_t channel, pc_espnow_recv_fn cb)
210 s_espnow.channel = channel;
212 if (esp_now_init() != ESP_OK)
216 esp_now_register_recv_cb(on_recv);
217 pc_espnow_peers_reset();
218 return radio_add_peer(PC_ESPNOW_BROADCAST, channel);
221bool pc_espnow_add_peer(
const uint8_t mac[6])
223 if (!pc_espnow_peer_add(mac))
227 return radio_add_peer(mac, s_espnow.channel);
230bool pc_espnow_send(
const uint8_t mac[6], uint8_t type,
const uint8_t *payload,
size_t len)
232 uint8_t frame[PC_ESPNOW_HDR + PC_ESPNOW_MAX_PAYLOAD];
233 size_t n = pc_espnow_encode(type, payload, len, frame,
sizeof(frame));
238 return esp_now_send(mac, frame, n) == ESP_OK;
241bool pc_espnow_broadcast(uint8_t type,
const uint8_t *payload,
size_t len)
243 return pc_espnow_send(PC_ESPNOW_BROADCAST, type, payload, len);
248bool pc_espnow_begin(uint8_t, pc_espnow_recv_fn)
252bool pc_espnow_add_peer(
const uint8_t mac[6])
254 return pc_espnow_peer_add(mac);
256bool pc_espnow_send(
const uint8_t *, uint8_t,
const uint8_t *,
size_t)
260bool pc_espnow_broadcast(uint8_t,
const uint8_t *,
size_t)
ESP-NOW peer messaging with a typed envelope (PC_ENABLE_ESPNOW).