Skip to content

feat(esp_now): Add support for ESP NOW V2 #11524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void setup() {
ESP.restart();
}

Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());

Serial.println("Setup complete. Broadcasting messages every 5 seconds.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ void setup() {
ESP.restart();
}

Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());

// Register the new peer callback
ESP_NOW.onNewPeer(register_new_master, nullptr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@
// The following struct is used to send data to the peer device.
// We use the attribute "packed" to ensure that the struct is not padded (all data
// is contiguous in the memory and without gaps).
// The maximum size of the complete message is 250 bytes (ESP_NOW_MAX_DATA_LEN).
// The maximum size of the payload is 250 bytes (ESP_NOW_MAX_DATA_LEN) for ESP-NOW v1.0.
// For ESP-NOW v2.0, the maximum size of the payload is 1470 bytes (ESP_NOW_MAX_DATA_LEN_V2).
// You can use ESP_NOW.getMaxDataLen() after calling ESP_NOW.begin() to get the maximum size
// of the data that can be sent.
// Read about the compatibility between ESP-NOW v1.0 and v2.0 in the ESP-IDF documentation:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html#frame-format

typedef struct {
uint32_t count;
Expand Down Expand Up @@ -276,6 +281,8 @@ void setup() {
fail_reboot();
}

Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());

if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer");
fail_reboot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void setup() {
// Start the ESP-NOW communication
Serial.println("ESP-NOW communication starting...");
NowSerial.begin(115200);
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("You can now send data to the peer device using the Serial Monitor.\n");
}

Expand Down
65 changes: 57 additions & 8 deletions libraries/ESP_NOW/src/ESP32_NOW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status
}
}

ESP_NOW_Class::ESP_NOW_Class() {}
ESP_NOW_Class::ESP_NOW_Class() {
max_data_len = 0;
version = 0;
}

ESP_NOW_Class::~ESP_NOW_Class() {}

Expand All @@ -155,6 +158,23 @@ bool ESP_NOW_Class::begin(const uint8_t *pmk) {
return false;
}

// Unfortunately we can't get the ESP-NOW version before initializing the Wi-Fi
uint32_t esp_now_version;
err = esp_now_get_version(&esp_now_version);
if (err != ESP_OK) {
log_w("esp_now_get_version failed! Assuming ESP-NOW v1.0");
esp_now_version = 1;
}

if (esp_now_version == 1) {
max_data_len = ESP_NOW_MAX_DATA_LEN;
} else {
max_data_len = ESP_NOW_MAX_DATA_LEN_V2;
}

version = esp_now_version;
log_i("ESP-NOW version: %lu, max_data_len: %lu", version, max_data_len);

_esp_now_has_begun = true;

memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM);
Expand Down Expand Up @@ -212,7 +232,7 @@ bool ESP_NOW_Class::end() {
return true;
}

int ESP_NOW_Class::getTotalPeerCount() {
int ESP_NOW_Class::getTotalPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
Expand All @@ -225,7 +245,7 @@ int ESP_NOW_Class::getTotalPeerCount() {
return num.total_num;
}

int ESP_NOW_Class::getEncryptedPeerCount() {
int ESP_NOW_Class::getEncryptedPeerCount() const {
if (!_esp_now_has_begun) {
return -1;
}
Expand All @@ -238,16 +258,38 @@ int ESP_NOW_Class::getEncryptedPeerCount() {
return num.encrypt_num;
}

int ESP_NOW_Class::getMaxDataLen() const {
if (max_data_len == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the max data length.");
return -1;
}

return max_data_len;
}

int ESP_NOW_Class::getVersion() const {
if (version == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the version.");
return -1;
}

return version;
}

int ESP_NOW_Class::availableForWrite() {
return ESP_NOW_MAX_DATA_LEN;
int available = getMaxDataLen();
if (available < 0) {
return 0;
}
return available;
}

size_t ESP_NOW_Class::write(const uint8_t *data, size_t len) {
if (!_esp_now_has_begun) {
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;
if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(nullptr, data, len);
if (result == ESP_OK) {
Expand Down Expand Up @@ -386,8 +428,15 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
log_e("Peer not added.");
return 0;
}
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN;

int max_data_len = ESP_NOW.getMaxDataLen();
if (max_data_len < 0) {
log_e("Error getting max data length.");
return 0;
}

if (len > max_data_len) {
len = max_data_len;
}
esp_err_t result = esp_now_send(mac, data, len);
if (result == ESP_OK) {
Expand Down
10 changes: 8 additions & 2 deletions libraries/ESP_NOW/src/ESP32_NOW.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ class ESP_NOW_Class : public Print {
bool begin(const uint8_t *pmk = nullptr /* 16 bytes */);
bool end();

int getTotalPeerCount();
int getEncryptedPeerCount();
int getTotalPeerCount() const;
int getEncryptedPeerCount() const;
int getMaxDataLen() const;
int getVersion() const;

int availableForWrite();
size_t write(const uint8_t *data, size_t len);
Expand All @@ -34,6 +36,10 @@ class ESP_NOW_Class : public Print {

void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg);
bool removePeer(ESP_NOW_Peer &peer);

protected:
size_t max_data_len;
uint32_t version;
};

class ESP_NOW_Peer {
Expand Down
24 changes: 20 additions & 4 deletions libraries/ESP_NOW/src/ESP32_NOW_Serial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,25 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud) {
//xSemaphoreTake(tx_sem, 0);
xSemaphoreGive(tx_sem);
}
setRxBufferSize(1024); //default if not preset
setTxBufferSize(1024); //default if not preset

size_t buf_size = 0;
if (ESP_NOW.getVersion() == 2) {
// ESP-NOW v2.0 has a larger maximum data length, so we need to increase the buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(4096);
buf_size &= setTxBufferSize(4096);
Comment on lines +78 to +79
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should keep the 1024 buffer size but print a warning that the buffers might be too small.

} else {
// ESP-NOW v1.0 has a smaller maximum data length, so we can use the default buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(1024);
buf_size &= setTxBufferSize(1024);
}

if (buf_size == 0) {
log_e("Failed to set buffer size");
return false;
}

return true;
}

Expand Down Expand Up @@ -164,7 +181,6 @@ void ESP_NOW_Serial_Class::onReceive(const uint8_t *data, size_t len, bool broad

//Print
int ESP_NOW_Serial_Class::availableForWrite() {
//return ESP_NOW_MAX_DATA_LEN;
if (tx_ring_buf == nullptr) {
return 0;
}
Expand All @@ -189,7 +205,7 @@ bool ESP_NOW_Serial_Class::checkForTxData() {
//do we have something that failed the last time?
resend_count = 0;
if (queued_buff == nullptr) {
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW_MAX_DATA_LEN);
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW.getMaxDataLen());
} else {
log_d(MACSTR " : PREVIOUS", MAC2STR(addr()));
}
Expand Down
Loading