/*
Forum: https://forum.arduino.cc/t/esp32-esp-now-with-auto-pairing-loop-through-peer-list-help/1199296
Wokwi: https://wokwi.com/projects/383925663410460673
The following declarations and functions handle a mac address list
*/
#include "dummyESPFunctions.h"
// maxPeers is defined as a constant and holds the content of 20
// It will be used to define the number of peer MAC addresses that
// can be stored in the totalPeerList[]
constexpr int maxPeers {20};
// totalPeerList is a two-dimensional array with maxPeers rows and 6 columns
// for the MAC addresses that will be stored in this array
// MAC addresses consist of 6 bytes like e.g. {8,250,30,24,25,1}
// For easier reception by users they are usually written as HEX data
// but when used by ESPNOW it's just six adjacent memory "cells"
//
// To understand the two-D array just think of it as a table (e.g. in a Calc Sheet):
// * The first index addresses the row (in C/C++ index has a range from 0..(n-1) if you have n rows)
// * The second index addresses the column (in C/C++ index has a range from 0..(m-1) if you have m columns)
//
// The short form "totalPeerList[5]" points to the starting "cell" of the sixth row (counted from zero!)
// You may write "totalPeerList[5][3]" if you want to address the forth element in the sixth row
//
// Always remind yourself that C/C++ counts from zero in arrays!
//
uint8_t totalPeerList[maxPeers][6];
// noOfPeersInList is a variable that shall hold the actual number of peers which
// were retrieved via esp_now_fetch_peer()
// It is set to zero so that - if we call printList() - it will not print invalid data
int noOfPeersInList = 0;
// We need a variable of type esp_now_peer_info_t to communicate with the ESPNOW library.
// The content is defined in
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html
//
// In addition with further information this variable might be filled by ESPNOW functions
// with the MAC address of paired peers.
//
// esp_now_peer_info_t declares a structure, that is a combination of data that is bundled
// under one name. To access one of those data you use the name of the structure variable
// (here: slave) and add the name of the internal variable (e.g. peer_addr) with a "." in
// between: slave.peer_addr is a valid name as well as slave.channel.
//
esp_now_peer_info_t slave;
// In setup() we call two functions that are defined after loop()
void setup() {
Serial.begin(115200);
populateList();
printList();
}
// Nothing to be done here for demo purposes
void loop() {
}
// The function populateList() does not need any parameters
// It collects (if available) the MAC addresses of all paired
// peers and copies them one by one in the totalPeerList[]
void populateList() {
// from_head is set to true, so that in the very first call
// of esp_now_fetch_peer() we get the very first entry from the
// ESPNOW's internal list
boolean from_head = true;
// We set the variable count to zero. It is used
// a) as the index where the next entry shall be written in totalPeerList[]
// b) as a counter for the number of peers we get from the function
int count = 0;
// We use the return value of the ESPNOW function to detect whether a
// call was succesful or not
// If it was successful "slave" will hold a valid MAC address
// and the sketch enters the while-loop
//
// otherwise it will skip the while-loop and commence with the
// statement after the closing curly bracket
// So if we don't get a ESP_OK on the first call
// noOfPeersInList will be set to zero (as count is still zero)
// a call of printlist() will not show anything.
//
// If the while-loop is entered ...
while (esp_now_fetch_peer(from_head, &slave) == ESP_OK) {
// from_head is set to false in the first entry here
// This way only the first call starts at the Top of the ESPNOW internal list
// Every following call in while(esp_...) will search for the next entry in
// that internal list
from_head = false;
// The function call in while() has filled the memory where the variable "slave"
// is stored in memory with the content from the ESPNOW internal list.
// We are only interested in the peer_addr part and therefore
// use the standard function memcpy()
// See https://en.cppreference.com/w/cpp/string/byte/memcpy
// to copy 6 bytes from source (slave.peer_addr) to destination totalPeerList[count]
//
// On the first entry count is zero, so we fill totalPeerList[0
//
memcpy(totalPeerList[count],slave.peer_addr,6);
// Now we increase count by one; after the first entry it becomes 1 now
// That's nice:
// a) That is the number of peer MAC addresses we have stored now and
// b) It points to the next row in totalPeerList[] where a further address may
// be stored - if available -
count++;
// To be on the safe side this function should be integrated also:
// If count reaches the maximum number of peers we jump out of the while loop
// to avoid writing data after the end of the array.
// It's not necessary now but might become relevant e.g. if ESPNOW allows more than twenty
// peers to pair
if (count >= maxPeers) {
break;
}
}
// After all is done count does its last duty: It hands over the number of
// stored MAC addresses to noOfPeersInList and ... passes away as typical for local variables ... ;-)
// while noOfPeersInList - being a global variable - survives and saves the heritage of "count"
// for further functions
noOfPeersInList = count;
}
//
// printList() is just trying to print
// from 0 to noOfPeersInList-1
// it calls the separate function printMAC() handing over the address where the first cell out of
// six is that (hopefully) holds a valid MAC address
// Serial.printf() is a function available to ESP controllers that eases mixed printing of
// text and numbers
//
// It uses a format string (here "MAC ADRESS %2d: ") that includes possible text and placeholders
// starting with a "%" and formatting commands for decimal, floating point numbers etc.
//
// The variable(s) which are associated with each placeholder are listed after the format
// string in the same order as their placeholders and separated by a comma
//
// see https://en.cppreference.com/w/cpp/io/c/fprintf
//
void printList() {
for (int i = 0; i<noOfPeersInList;i++){
Serial.printf("MAC ADRESS %2d: ",i+1);
printMAC(totalPeerList[i]);
Serial.println();
}
}
// printMAC() gets the pointer to the begin of a six byte array holding a MAC address
// It uses the standard function snprintf() to fill the char array macStr[18] with
// the hexadecimal printed values of each single array cell.
// The additional for-loop goes through the macStr array character by character and
// converts the characters - if they are letters - to upper case
// ---------------------------- esp_ now -------------------------
void printMAC(const uint8_t * mac_addr){
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
for (int i=0;i<18;i++){
macStr[i] = toupper(macStr[i]);
}
Serial.print(macStr);
}