You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
530 lines
13 KiB
C
530 lines
13 KiB
C
#ifdef ESP8266
|
|
#include <ESP8266WiFi.h>
|
|
#include <espnow.h>
|
|
#elif defined(ESP32)
|
|
#include <esp_now.h>
|
|
#include <WiFi.h>
|
|
#include <esp_wifi.h>
|
|
#endif
|
|
|
|
#define PEER_TIMEOUT 300000
|
|
FDRSPeer peer_list[16];
|
|
const uint8_t espnow_size = 250 / sizeof(DataReading);
|
|
|
|
#ifdef ESP32
|
|
esp_now_peer_info_t peerInfo;
|
|
#endif
|
|
|
|
bool esp_now_sent_flag;
|
|
const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
|
|
|
const uint8_t mac_prefix[] = {MAC_PREFIX};
|
|
uint8_t selfAddress[] = {MAC_PREFIX, UNIT_MAC};
|
|
uint8_t incMAC[6];
|
|
|
|
uint8_t ESPNOW1[] = {MAC_PREFIX, ESPNOW_NEIGHBOR_1};
|
|
uint8_t ESPNOW2[] = {MAC_PREFIX, ESPNOW_NEIGHBOR_2};
|
|
extern time_t now;
|
|
// JL - pingFlagEspNow var probably to be removed
|
|
bool pingFlagEspNow = false;
|
|
|
|
// Set ESP-NOW send and receive callbacks for either ESP8266 or ESP32
|
|
#if defined(ESP8266)
|
|
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
|
|
{
|
|
esp_now_sent_flag = true;
|
|
}
|
|
void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len)
|
|
{
|
|
#elif defined(ESP32)
|
|
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
|
|
{
|
|
esp_now_sent_flag = true;
|
|
}
|
|
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
|
|
{
|
|
#endif
|
|
memcpy(&incMAC, mac, sizeof(incMAC));
|
|
if (len < sizeof(DataReading))
|
|
{
|
|
DBG1("Incoming ESP-NOW System Packet from 0x" + String(incMAC[5], HEX));
|
|
memcpy(&theCmd, incomingData, sizeof(theCmd));
|
|
// processing is handled in the handlecommands() function in gateway.h - do not process here
|
|
return;
|
|
}
|
|
else {
|
|
memcpy(&theData, incomingData, sizeof(theData));
|
|
DBG("Incoming ESP-NOW DataReading from 0x" + String(incMAC[5], HEX));
|
|
ln = len / sizeof(DataReading);
|
|
if (memcmp(&incMAC, &ESPNOW1, 6) == 0)
|
|
{
|
|
newData = event_espnow1;
|
|
return;
|
|
}
|
|
if (memcmp(&incMAC, &ESPNOW2, 6) == 0)
|
|
{
|
|
newData = event_espnow2;
|
|
return;
|
|
}
|
|
newData = event_espnowg;
|
|
}
|
|
}
|
|
|
|
void begin_espnow()
|
|
{
|
|
DBG("Initializing ESP-NOW!");
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.disconnect();
|
|
// Init ESP-NOW for either ESP8266 or ESP32 and set MAC address
|
|
#if defined(ESP8266)
|
|
#ifdef USE_LR
|
|
DBG(" LR mode is only available on ESP32. ESP-NOW will begin in normal mode.");
|
|
#endif
|
|
wifi_set_macaddr(STATION_IF, selfAddress);
|
|
if (esp_now_init() != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
|
|
esp_now_register_send_cb(OnDataSent);
|
|
esp_now_register_recv_cb(OnDataRecv);
|
|
|
|
#elif defined(ESP32)
|
|
#ifdef USE_LR
|
|
DBG(" ESP-NOW LR mode is active!");
|
|
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR);
|
|
#endif
|
|
esp_wifi_set_mac(WIFI_IF_STA, &selfAddress[0]);
|
|
if (esp_now_init() != ESP_OK)
|
|
{
|
|
DBG("Error initializing ESP-NOW");
|
|
return;
|
|
}
|
|
esp_now_register_send_cb(OnDataSent);
|
|
esp_now_register_recv_cb(OnDataRecv);
|
|
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
|
|
memcpy(peerInfo.peer_addr, broadcast_mac, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer bcast");
|
|
return;
|
|
}
|
|
#endif // ESP8266
|
|
DBG(" ESP-NOW Initialized.");
|
|
}
|
|
|
|
// Returns an expired entry in peer_list, -1 if full.
|
|
int find_espnow_peer()
|
|
{
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (peer_list[i].last_seen == 0)
|
|
{
|
|
DBG1("Using peer entry " + String(i));
|
|
return i;
|
|
}
|
|
}
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (TDIFF(peer_list[i].last_seen,PEER_TIMEOUT))
|
|
{
|
|
DBG1("Recycling peer entry " + String(i));
|
|
esp_now_del_peer(peer_list[i].mac);
|
|
|
|
return i;
|
|
}
|
|
}
|
|
DBG("No open peers");
|
|
return -1;
|
|
}
|
|
|
|
// Returns the index of the peer list array element that contains the provided MAC address, -1 if not found
|
|
int getFDRSPeer(uint8_t *mac)
|
|
{
|
|
DBG2("Getting peer #");
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (memcmp(mac, &peer_list[i].mac, 6) == 0)
|
|
{
|
|
DBG1("Peer is entry #" + String(i));
|
|
return i;
|
|
}
|
|
}
|
|
|
|
DBG1("Couldn't find peer");
|
|
return -1;
|
|
}
|
|
|
|
void add_espnow_peer()
|
|
{
|
|
DBG1("Device requesting peer registration");
|
|
int peer_num = getFDRSPeer(&incMAC[0]);
|
|
if (peer_num == -1) // if the device isn't registered
|
|
{
|
|
int open_peer = find_espnow_peer(); // find open spot in peer_list
|
|
DBG("Registering new peer. Slot: " + String(open_peer));
|
|
memcpy(&peer_list[open_peer].mac, &incMAC, 6); // save MAC to open spot
|
|
peer_list[open_peer].last_seen = millis();
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, incMAC, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return;
|
|
}
|
|
#endif
|
|
#if defined(ESP8266)
|
|
esp_now_add_peer(incMAC, ESP_NOW_ROLE_COMBO, 0, NULL, 0);
|
|
|
|
#endif
|
|
SystemPacket sys_packet = {.cmd = cmd_add, .param = PEER_TIMEOUT};
|
|
esp_now_send(incMAC, (uint8_t *)&sys_packet, sizeof(SystemPacket));
|
|
}
|
|
else
|
|
{
|
|
DBG1("Refreshing existing peer registration");
|
|
peer_list[peer_num].last_seen = millis();
|
|
|
|
SystemPacket sys_packet = {.cmd = cmd_add, .param = PEER_TIMEOUT};
|
|
esp_now_send(incMAC, (uint8_t *)&sys_packet, sizeof(SystemPacket));
|
|
}
|
|
if(validTimeFlag){
|
|
SystemPacket sys_packet = { .cmd = cmd_time, .param = now };
|
|
esp_now_send(incMAC, (uint8_t *)&sys_packet, sizeof(SystemPacket));
|
|
}
|
|
}
|
|
|
|
// Sends ping reply to sender
|
|
void pingback_espnow()
|
|
{
|
|
DBG("Sending ESP-NOW Ping Reply");
|
|
SystemPacket sys_packet;
|
|
sys_packet = { .cmd = cmd_ping, .param = ping_reply };
|
|
if (!esp_now_is_peer_exist(incMAC))
|
|
{
|
|
#ifdef ESP8266
|
|
esp_now_add_peer(incMAC, ESP_NOW_ROLE_COMBO, 0, NULL, 0);
|
|
#endif
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, incMAC, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return;
|
|
}
|
|
#endif
|
|
esp_now_send(incMAC, (uint8_t *)&sys_packet, sizeof(SystemPacket));
|
|
esp_now_del_peer(incMAC);
|
|
}
|
|
else
|
|
{
|
|
esp_now_send(incMAC, (uint8_t *)&sys_packet, sizeof(SystemPacket));
|
|
}
|
|
}
|
|
|
|
void sendESPNowNbr(uint8_t interface)
|
|
{
|
|
switch (interface)
|
|
{
|
|
case 1:
|
|
{ // These brackets are required!
|
|
DBG("Sending DR to ESP-NOW Neighbor #1");
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, ESPNOW1, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return;
|
|
}
|
|
#endif // ESP32
|
|
DataReading thePacket[ln];
|
|
int j = 0;
|
|
|
|
for (int i = 0; i < ln; i++)
|
|
{
|
|
if (j > espnow_size)
|
|
{
|
|
j = 0;
|
|
esp_now_send(ESPNOW1, (uint8_t *)&thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = theData[i];
|
|
j++;
|
|
}
|
|
esp_now_send(ESPNOW1, (uint8_t *)&thePacket, j * sizeof(DataReading));
|
|
esp_now_del_peer(ESPNOW1);
|
|
|
|
break;
|
|
} // These brackets are required!
|
|
case 2:
|
|
{
|
|
DBG("Sending DR to ESP-NOW Neighbor #2");
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, ESPNOW2, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return;
|
|
}
|
|
#endif // ESP32
|
|
DataReading thePacket[ln];
|
|
int j = 0;
|
|
for (int i = 0; i < ln; i++)
|
|
{
|
|
if (j > espnow_size)
|
|
{
|
|
j = 0;
|
|
esp_now_send(ESPNOW2, (uint8_t *)&thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = theData[i];
|
|
j++;
|
|
}
|
|
esp_now_send(ESPNOW2, (uint8_t *)&thePacket, j * sizeof(DataReading));
|
|
esp_now_del_peer(ESPNOW2);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sendESPNowPeers()
|
|
{
|
|
DBG("Sending DR to ESP-NOW peers.");
|
|
DataReading thePacket[ln];
|
|
int j = 0;
|
|
for (int i = 0; i < ln; i++)
|
|
{
|
|
if (j > espnow_size)
|
|
{
|
|
j = 0;
|
|
esp_now_send(0, (uint8_t *)&thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = theData[i];
|
|
j++;
|
|
}
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
if (peer_list[i].last_seen != 0 && (millis() - peer_list[i].last_seen) < PEER_TIMEOUT)
|
|
{
|
|
//uint32_t clktm = millis();
|
|
esp_now_sent_flag = false;
|
|
esp_now_send(peer_list[i].mac, (uint8_t *)&thePacket, j * sizeof(DataReading));
|
|
while (!esp_now_sent_flag) yield();
|
|
//DBG(millis() - clktm);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lower level function meant to be called by other functions
|
|
// Sends SystemPacket via ESP-NOW
|
|
esp_err_t sendESPNow(uint8_t *dest, SystemPacket *data) {
|
|
esp_err_t sendResult;
|
|
if (dest != nullptr && !esp_now_is_peer_exist(dest))
|
|
{
|
|
#ifdef ESP8266
|
|
sendResult = esp_now_add_peer(dest, ESP_NOW_ROLE_COMBO, 0, NULL, 0);
|
|
if (sendResult != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return sendResult;
|
|
}
|
|
#endif
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, dest, 6);
|
|
sendResult = esp_now_add_peer(&peerInfo);
|
|
if (sendResult != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return sendResult;
|
|
}
|
|
#endif
|
|
sendResult = esp_now_send(dest, (uint8_t *)data, sizeof(SystemPacket));
|
|
esp_now_del_peer(dest);
|
|
}
|
|
else
|
|
{
|
|
sendResult = esp_now_send(dest, (uint8_t *)data, sizeof(SystemPacket));
|
|
}
|
|
return sendResult;
|
|
}
|
|
|
|
// Lower level function meant to be called by other functions
|
|
// Sends DataReading via ESP-NOW
|
|
esp_err_t sendESPNow(uint8_t *dest, DataReading *data) {
|
|
esp_err_t sendResult;
|
|
bool tempPeerFlag = false;
|
|
|
|
|
|
if (dest != nullptr && !esp_now_is_peer_exist(dest))
|
|
{
|
|
tempPeerFlag = true;
|
|
#ifdef ESP8266
|
|
sendResult = esp_now_add_peer(dest, ESP_NOW_ROLE_COMBO, 0, NULL, 0);
|
|
if (sendResult != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return sendResult;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, dest, 6);
|
|
sendResult = esp_now_add_peer(&peerInfo);
|
|
if (sendResult != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return sendResult;
|
|
}
|
|
}
|
|
#endif // ESP32
|
|
for(int i = 0; i < ln; ) {
|
|
if(ln > espnow_size) {
|
|
sendResult = esp_now_send(dest, (uint8_t *)&data[i], espnow_size * sizeof(DataReading));
|
|
if(sendResult == ESP_OK) {
|
|
i += espnow_size;
|
|
}
|
|
else {
|
|
// Send failed!
|
|
delay(10);
|
|
return sendResult;
|
|
}
|
|
}
|
|
else {
|
|
sendResult = esp_now_send(dest, (uint8_t *)&data[i], ln * sizeof(DataReading));
|
|
if(sendResult == ESP_OK) {
|
|
ln = 0;
|
|
}
|
|
else {
|
|
// Send Failed!
|
|
delay(10);
|
|
return sendResult;
|
|
}
|
|
}
|
|
}
|
|
if(tempPeerFlag) {
|
|
esp_now_del_peer(dest);
|
|
}
|
|
return sendResult;
|
|
}
|
|
|
|
|
|
|
|
void sendESPNow(uint8_t address)
|
|
{
|
|
DBG("Sending ESP-NOW DR.");
|
|
uint8_t temp_peer[] = {MAC_PREFIX, address};
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, temp_peer, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK)
|
|
{
|
|
DBG("Failed to add peer");
|
|
return;
|
|
}
|
|
#endif // ESP32
|
|
|
|
DataReading thePacket[ln];
|
|
int j = 0;
|
|
for (int i = 0; i < ln; i++)
|
|
{
|
|
if (j > espnow_size)
|
|
{
|
|
j = 0;
|
|
esp_now_send(temp_peer, (uint8_t *)&thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = theData[i];
|
|
j++;
|
|
}
|
|
|
|
esp_now_send(temp_peer, (uint8_t *)&thePacket, j * sizeof(DataReading));
|
|
esp_now_del_peer(temp_peer);
|
|
}
|
|
|
|
void recvTimeEspNow(uint32_t t) {
|
|
// Process time if there is no time source set yet or if LoRa is the time source or if we are already the time source
|
|
if(timeSource.tmNetIf <= TMIF_ESPNOW ) {
|
|
DBG1("Received time via ESP-NOW from 0x" + String(incMAC[5], HEX));
|
|
if(timeSource.tmNetIf < TMIF_ESPNOW) {
|
|
timeSource.tmNetIf = TMIF_ESPNOW;
|
|
timeSource.tmAddress = incMAC[4] << 8 | incMAC[5];
|
|
timeSource.tmSource = TMS_NET;
|
|
DBG1("ESP-NOW time source is 0x" + String(incMAC[5], HEX));
|
|
}
|
|
if(timeSource.tmAddress == incMAC[4] << 8 | incMAC[5]) {
|
|
if(setTime(t)) {
|
|
timeSource.tmLastTimeSet = millis();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DBG2("ESP-NOW 0x" + String(incMAC[5], HEX) + " is not time source, discarding request");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Sends time to both neighbors and all peers
|
|
esp_err_t sendTimeESPNow() {
|
|
|
|
esp_err_t result1 = ESP_OK, result2 = ESP_OK, result3 = ESP_OK;
|
|
SystemPacket sys_packet = { .cmd = cmd_time, .param = now };
|
|
|
|
if((timeSource.tmAddress != (ESPNOW1[4] << 8 | ESPNOW1[5])) && ESPNOW1[5] != 0x00) {
|
|
DBG1("Sending time to ESP-NOW Peer 1");
|
|
result1 = sendESPNow(ESPNOW1, &sys_packet);
|
|
}
|
|
if((timeSource.tmAddress != (ESPNOW2[4] << 8 | ESPNOW2[5])) && ESPNOW2[5] != 0x00) {
|
|
DBG1("Sending time to ESP-NOW Peer 2");
|
|
result2 = sendESPNow(ESPNOW2, &sys_packet);
|
|
}
|
|
DBG1("Sending time to ESP-NOW registered peers");
|
|
result3 = sendESPNow(nullptr, &sys_packet);
|
|
|
|
if(result1 != ESP_OK || result2 != ESP_OK || result3 != ESP_OK){
|
|
return ESP_FAIL;
|
|
}
|
|
else {
|
|
return ESP_OK;
|
|
}
|
|
}
|
|
|
|
// Send the time to a specific node
|
|
esp_err_t sendTimeESPNow(uint8_t *addr) {
|
|
|
|
esp_err_t result = ESP_FAIL;
|
|
SystemPacket sys_packet = { .cmd = cmd_time, .param = now };
|
|
DBG1("Sending time to ESP-NOW address 0x" + String(addr[5],HEX));
|
|
result = sendESPNow(addr, &sys_packet);
|
|
|
|
return result;
|
|
} |