mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-24 08:45:10 +03:00
- Rearrange class variables to minimize storage padding. - Add protected getters for EspnowMeshBackend and MeshBackendBase components. - Partially update README.md
1045 lines
42 KiB
C++
1045 lines
42 KiB
C++
/*
|
|
EspnowMeshBackend
|
|
|
|
Copyright (C) 2019 Anders Löfgren
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <ESP8266WiFi.h>
|
|
extern "C" {
|
|
#include <espnow.h>
|
|
}
|
|
|
|
#include "EspnowMeshBackend.h"
|
|
#include "TypeConversionFunctions.h"
|
|
#include "UtilityFunctions.h"
|
|
#include "MutexTracker.h"
|
|
#include "JsonTranslator.h"
|
|
#include "MeshCryptoInterface.h"
|
|
#include "Serializer.h"
|
|
|
|
namespace
|
|
{
|
|
using EspnowProtocolInterpreter::encryptedConnectionKeyLength;
|
|
using EspnowProtocolInterpreter::hashKeyLength;
|
|
|
|
namespace TypeCast = MeshTypeConversionFunctions;
|
|
|
|
EspnowMeshBackend *_espnowRequestManager = nullptr;
|
|
}
|
|
|
|
void espnowDelay(uint32_t durationMs)
|
|
{
|
|
ExpiringTimeTracker timeout(durationMs);
|
|
|
|
do
|
|
{
|
|
// We want to delay before performEspnowMaintenance() so background tasks can be managed first.
|
|
// Initial while combined with YieldAndDelayMs polledTimeout::YieldPolicy is not suitable since the delay then occurs before evaluating the condition (meaning durationMs = 1 never executes the loop interior).
|
|
delay(1);
|
|
EspnowMeshBackend::performEspnowMaintenance();
|
|
}
|
|
while(!timeout);
|
|
}
|
|
|
|
EspnowMeshBackend::EspnowMeshBackend(const requestHandlerType requestHandler, const responseHandlerType responseHandler, const networkFilterType networkFilter,
|
|
const broadcastFilterType broadcastFilter, const String &meshPassword, const String &ssidPrefix, const String &ssidSuffix, const bool verboseMode,
|
|
const uint8 meshWiFiChannel)
|
|
: MeshBackendBase(requestHandler, responseHandler, networkFilter, MeshBackendType::ESP_NOW),
|
|
_database(*getConditionalPrinter(), meshWiFiChannel), _connectionManager(*getConditionalPrinter(), *getDatabase()),
|
|
_transmitter(*getConditionalPrinter(), *getDatabase(), *getConnectionManager()),
|
|
_encryptionBroker(*getConditionalPrinter(), *getDatabase(), *getConnectionManager(), *getTransmitter())
|
|
{
|
|
setBroadcastFilter(broadcastFilter);
|
|
setSSID(ssidPrefix, emptyString, ssidSuffix);
|
|
setMeshPassword(meshPassword);
|
|
setVerboseModeState(verboseMode);
|
|
EspnowMeshBackend::setWiFiChannel(meshWiFiChannel);
|
|
}
|
|
|
|
EspnowMeshBackend::EspnowMeshBackend(const requestHandlerType requestHandler, const responseHandlerType responseHandler, const networkFilterType networkFilter,
|
|
const broadcastFilterType broadcastFilter, const String &meshPassword, const uint8_t espnowEncryptedConnectionKey[encryptedConnectionKeyLength],
|
|
const uint8_t espnowHashKey[hashKeyLength], const String &ssidPrefix, const String &ssidSuffix, const bool verboseMode,
|
|
const uint8 meshWiFiChannel)
|
|
: EspnowMeshBackend(requestHandler, responseHandler, networkFilter, broadcastFilter, meshPassword, ssidPrefix, ssidSuffix, verboseMode, meshWiFiChannel)
|
|
{
|
|
setEspnowEncryptedConnectionKey(espnowEncryptedConnectionKey);
|
|
setEspnowHashKey(espnowHashKey);
|
|
}
|
|
|
|
EspnowMeshBackend::EspnowMeshBackend(const requestHandlerType requestHandler, const responseHandlerType responseHandler, const networkFilterType networkFilter,
|
|
const broadcastFilterType broadcastFilter, const String &meshPassword, const String &espnowEncryptedConnectionKeySeed,
|
|
const String &espnowHashKeySeed, const String &ssidPrefix, const String &ssidSuffix, const bool verboseMode,
|
|
const uint8 meshWiFiChannel)
|
|
: EspnowMeshBackend(requestHandler, responseHandler, networkFilter, broadcastFilter, meshPassword, ssidPrefix, ssidSuffix, verboseMode, meshWiFiChannel)
|
|
{
|
|
setEspnowEncryptedConnectionKey(espnowEncryptedConnectionKeySeed);
|
|
setEspnowHashKey(espnowHashKeySeed);
|
|
}
|
|
|
|
EspnowMeshBackend::~EspnowMeshBackend()
|
|
{
|
|
if(isEspnowRequestManager())
|
|
{
|
|
setEspnowRequestManager(nullptr);
|
|
}
|
|
|
|
_database.deleteSentRequestsByOwner(this);
|
|
}
|
|
|
|
std::vector<EspnowNetworkInfo> & EspnowMeshBackend::connectionQueue()
|
|
{
|
|
return EspnowDatabase::connectionQueue();
|
|
}
|
|
|
|
const std::vector<EspnowNetworkInfo> & EspnowMeshBackend::constConnectionQueue()
|
|
{
|
|
return EspnowDatabase::constConnectionQueue();
|
|
}
|
|
|
|
std::vector<TransmissionOutcome> & EspnowMeshBackend::latestTransmissionOutcomes()
|
|
{
|
|
return EspnowDatabase::latestTransmissionOutcomes();
|
|
}
|
|
|
|
bool EspnowMeshBackend::latestTransmissionSuccessful()
|
|
{
|
|
return latestTransmissionSuccessfulBase(latestTransmissionOutcomes());
|
|
}
|
|
|
|
void EspnowMeshBackend::begin()
|
|
{
|
|
if(!getAPController()) // If there is no active AP controller
|
|
WiFi.mode(WIFI_STA); // WIFI_AP_STA mode automatically sets up an AP, so we can't use that as default.
|
|
|
|
activateEspnow();
|
|
}
|
|
|
|
bool EspnowMeshBackend::activateEspnow()
|
|
{
|
|
if (esp_now_init()==0)
|
|
{
|
|
if(!EspnowConnectionManager::initializeEncryptionKok())
|
|
warningPrint(String(F("Failed to set ESP-NOW KoK!")));
|
|
|
|
if(getEspnowRequestManager() == nullptr)
|
|
{
|
|
setEspnowRequestManager(this);
|
|
}
|
|
|
|
esp_now_register_recv_cb(espnowReceiveCallbackWrapper);
|
|
esp_now_register_send_cb(EspnowTransmitter::espnowSendCallback);
|
|
|
|
// Role must be set before adding peers. Cannot be changed while having peers.
|
|
// With ESP_NOW_ROLE_CONTROLLER, we always transmit from the station interface, which gives predictability.
|
|
if(esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER)) // esp_now_set_self_role returns 0 on success.
|
|
warningPrint(String(F("Failed to set ESP-NOW role! Maybe ESP-NOW peers are already added?")));
|
|
|
|
verboseModePrint(String(F("ESP-NOW activated.")));
|
|
verboseModePrint(String(F("My ESP-NOW STA MAC: ")) + WiFi.macAddress() + '\n'); // Get the station MAC address. The softAP MAC is different.
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
warningPrint(String(F("ESP-NOW init failed!")));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EspnowMeshBackend::deactivateEspnow()
|
|
{
|
|
// esp_now_deinit() clears all ESP-NOW API settings, including receive callback, send callback, Kok and peers.
|
|
// The node will however continue to give acks to received ESP-NOW transmissions as long as the receiving interface (AP or STA) is active, even though the transmissions will not be processed.
|
|
if(esp_now_deinit() == 0)
|
|
{
|
|
EspnowDatabase::responsesToSend().clear();
|
|
EspnowDatabase::peerRequestConfirmationsToSend().clear();
|
|
EspnowDatabase::receivedEspnowTransmissions().clear();
|
|
EspnowDatabase::sentRequests().clear();
|
|
EspnowDatabase::receivedRequests().clear();
|
|
EspnowConnectionManager::encryptedConnections().clear();
|
|
EncryptedConnectionLog::setNewRemovalsScheduled(false);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void EspnowMeshBackend::performEspnowMaintenance(const uint32_t estimatedMaxDuration)
|
|
{
|
|
ExpiringTimeTracker estimatedMaxDurationTracker = ExpiringTimeTracker(estimatedMaxDuration);
|
|
|
|
// Doing this during an ESP-NOW transmission could invalidate iterators
|
|
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex(EspnowConnectionManager::handlePostponedRemovals));
|
|
if(!mutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Transmission in progress. Don't call performEspnowMaintenance from callbacks as this may corrupt program state! Aborting.")));
|
|
return;
|
|
}
|
|
|
|
EspnowDatabase::clearOldLogEntries(false);
|
|
|
|
if(EncryptedConnectionLog::getSoonestExpiringConnectionTracker() && EncryptedConnectionLog::getSoonestExpiringConnectionTracker()->expired())
|
|
{
|
|
EspnowConnectionManager::updateTemporaryEncryptedConnections();
|
|
}
|
|
|
|
if(estimatedMaxDuration > 0)
|
|
{
|
|
if(estimatedMaxDurationTracker.expired())
|
|
return;
|
|
else
|
|
sendStoredEspnowMessages(&estimatedMaxDurationTracker);
|
|
}
|
|
else
|
|
{
|
|
sendStoredEspnowMessages();
|
|
}
|
|
}
|
|
|
|
void EspnowMeshBackend::espnowReceiveCallbackWrapper(uint8_t *macaddr, uint8_t *dataArray, const uint8_t len)
|
|
{
|
|
using namespace EspnowProtocolInterpreter;
|
|
|
|
// Since this callback can be called during any delay(), we should always consider all mutexes captured.
|
|
// This provides a consistent mutex environment, which facilitates development and debugging.
|
|
// Otherwise we get issues such as EspnowTransmitter::_espnowTransmissionMutex will usually be free, but occasionally taken (when callback occurs in a delay() during attemptTransmission).
|
|
MutexTracker captureBanTracker(MutexTracker::captureBan());
|
|
|
|
if(len >= metadataSize()) // If we do not receive at least the metadata bytes, the transmission is invalid.
|
|
{
|
|
//uint32_t callbackStart = millis();
|
|
|
|
// If there is a espnowRequestManager, get it
|
|
EspnowMeshBackend *currentEspnowRequestManager = getEspnowRequestManager();
|
|
|
|
char messageType = getMessageType(dataArray);
|
|
uint64_t receivedMessageID = getMessageID(dataArray);
|
|
|
|
if(currentEspnowRequestManager && !currentEspnowRequestManager->acceptsUnverifiedRequests()
|
|
&& !usesConstantSessionKey(messageType) && !EspnowEncryptionBroker::verifyPeerSessionKey(receivedMessageID, macaddr, messageType))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(EspnowTransmitter::useEncryptedMessages())
|
|
{
|
|
// chacha20Poly1305Decrypt decrypts dataArray in place.
|
|
// We are using the protocol bytes as a key salt.
|
|
if(!experimental::crypto::ChaCha20Poly1305::decrypt(dataArray + metadataSize(), len - metadataSize(), getEspnowMessageEncryptionKey(), dataArray,
|
|
protocolBytesSize, dataArray + protocolBytesSize, dataArray + protocolBytesSize + 12))
|
|
{
|
|
return; // Decryption of message failed.
|
|
}
|
|
}
|
|
|
|
uint64_t uint64StationMac = TypeCast::macToUint64(macaddr);
|
|
bool transmissionEncrypted = usesEncryption(receivedMessageID);
|
|
|
|
// Useful when debugging the protocol
|
|
//Serial.print("Received from Mac: " + TypeCast::macToString(macaddr) + " ID: " + TypeCast::uint64ToString(receivedMessageID));
|
|
//Serial.println(transmissionEncrypted ? " Encrypted" : " Unencrypted");
|
|
|
|
if(messageType == 'Q' || messageType == 'B') // Question (request) or Broadcast
|
|
{
|
|
if(ESP.getFreeHeap() <= criticalHeapLevel())
|
|
{
|
|
warningPrint("WARNING! Free heap below critical level. Suspending ESP-NOW request processing until the situation improves.");
|
|
return;
|
|
}
|
|
|
|
if(currentEspnowRequestManager)
|
|
{
|
|
if(!EspnowDatabase::requestReceived(uint64StationMac, receivedMessageID)) // If the request has not already been received
|
|
{
|
|
if(transmissionEncrypted)
|
|
{
|
|
EncryptedConnectionLog *encryptedConnection = EspnowConnectionManager::getEncryptedConnection(macaddr);
|
|
|
|
if(!encryptedConnection || (!EspnowEncryptionBroker::synchronizePeerSessionKey(receivedMessageID, *encryptedConnection) &&
|
|
!EspnowEncryptionBroker::verifyPeerSessionKey(receivedMessageID, *encryptedConnection, uint64StationMac, messageType)))
|
|
{
|
|
// We received an encrypted transmission
|
|
// and we have no encrypted connection to the transmitting node (in which case we want to avoid sending the secret session key back in an unencrypted response)
|
|
// or the transmission has the wrong session key
|
|
// and it doesn't have a session key that matches any multi-part transmission we are currently receiving (in which case the transmission is invalid).
|
|
return;
|
|
}
|
|
}
|
|
|
|
//Serial.println("espnowReceiveCallbackWrapper before internal callback " + String(millis() - callbackStart));
|
|
|
|
currentEspnowRequestManager->espnowReceiveCallback(macaddr, dataArray, len);
|
|
}
|
|
}
|
|
}
|
|
else if(messageType == 'A') // Answer (response)
|
|
{
|
|
EspnowMeshBackend *requestSender = nullptr;
|
|
uint64_t requestMac = 0;
|
|
|
|
if(transmissionEncrypted)
|
|
{
|
|
// An encrypted transmission can only be sent to the station interface, since it otherwise won't arrive (because of ESP_NOW_ROLE_CONTROLLER).
|
|
requestMac = uint64StationMac;
|
|
requestSender = EspnowDatabase::getOwnerOfSentRequest(requestMac, receivedMessageID);
|
|
}
|
|
else
|
|
{
|
|
// An unencrypted transmission was probably sent to the AP interface as a result of a scan.
|
|
requestMac = getTransmissionMac(dataArray);
|
|
requestSender = EspnowDatabase::getOwnerOfSentRequest(requestMac, receivedMessageID);
|
|
|
|
// But if not, also check if it was sent to the station interface.
|
|
if(!requestSender)
|
|
{
|
|
requestMac = uint64StationMac;
|
|
requestSender = EspnowDatabase::getOwnerOfSentRequest(requestMac, receivedMessageID);
|
|
}
|
|
|
|
// Or if it was sent as a broadcast. (A broadcast can never be encrypted)
|
|
if(!requestSender)
|
|
{
|
|
requestSender = EspnowDatabase::getOwnerOfSentRequest(uint64BroadcastMac, receivedMessageID);
|
|
}
|
|
}
|
|
|
|
// If this node sent the request and it has not already been answered.
|
|
if(requestSender)
|
|
{
|
|
uint8_t macArray[6] = { 0 };
|
|
|
|
requestSender->espnowReceiveCallback(TypeCast::uint64ToMac(requestMac, macArray), dataArray, len);
|
|
}
|
|
}
|
|
else if(messageType == 'S') // Synchronization request
|
|
{
|
|
EspnowEncryptionBroker::synchronizePeerSessionKey(receivedMessageID, macaddr);
|
|
}
|
|
else if(messageType == 'P') // Peer request
|
|
{
|
|
EspnowEncryptionBroker::handlePeerRequest(macaddr, dataArray, len, uint64StationMac, receivedMessageID);
|
|
}
|
|
else if(messageType == 'C') // peer request Confirmation
|
|
{
|
|
EspnowEncryptionBroker::handlePeerRequestConfirmation(macaddr, dataArray, len);
|
|
}
|
|
else
|
|
{
|
|
assert(messageType == 'Q' || messageType == 'A' || messageType == 'B' || messageType == 'S' || messageType == 'P' || messageType == 'C');
|
|
}
|
|
|
|
//Serial.println("espnowReceiveCallbackWrapper duration " + String(millis() - callbackStart));
|
|
}
|
|
}
|
|
|
|
void EspnowMeshBackend::espnowReceiveCallback(const uint8_t *macaddr, uint8_t *dataArray, const uint8_t len)
|
|
{
|
|
using namespace EspnowProtocolInterpreter;
|
|
|
|
////// <Method overview> //////
|
|
/*
|
|
if(messageStart)
|
|
{
|
|
storeTransmission
|
|
}
|
|
else
|
|
{
|
|
if(messageFound)
|
|
storeTransmission or (erase and return)
|
|
else
|
|
return
|
|
}
|
|
|
|
if(transmissionsRemaining != 0)
|
|
return
|
|
|
|
processMessage
|
|
*/
|
|
////// </Method overview> //////
|
|
|
|
char messageType = getMessageType(dataArray);
|
|
uint8_t transmissionsRemaining = getTransmissionsRemaining(dataArray);
|
|
uint64_t uint64Mac = TypeCast::macToUint64(macaddr);
|
|
|
|
// The MAC is 6 bytes so two bytes of uint64Mac are free. We must include the messageType there since it is possible that we will
|
|
// receive both a request and a response that shares the same messageID from the same uint64Mac, being distinguished only by the messageType.
|
|
// This would otherwise potentially cause the request and response to be mixed into one message when they are multi-part transmissions sent roughly at the same time.
|
|
macAndType_td macAndType = createMacAndTypeValue(uint64Mac, messageType);
|
|
uint64_t messageID = getMessageID(dataArray);
|
|
|
|
//uint32_t methodStart = millis();
|
|
|
|
if(isMessageStart(dataArray))
|
|
{
|
|
if(messageType == 'B')
|
|
{
|
|
auto key = std::make_pair(macAndType, messageID);
|
|
if(EspnowDatabase::receivedEspnowTransmissions().find(key) != EspnowDatabase::receivedEspnowTransmissions().end())
|
|
return; // Should not call BroadcastFilter more than once for an accepted message
|
|
|
|
String message = getHashKeyLength(dataArray, len);
|
|
_database.setSenderMac(macaddr);
|
|
uint8_t senderAPMac[6] {0};
|
|
_database.setSenderAPMac(getTransmissionMac(dataArray, senderAPMac));
|
|
_encryptionBroker.setReceivedEncryptedTransmission(usesEncryption(messageID));
|
|
bool acceptBroadcast = getBroadcastFilter()(message, *this);
|
|
if(acceptBroadcast)
|
|
{
|
|
// Does nothing if key already in receivedEspnowTransmissions
|
|
EspnowDatabase::receivedEspnowTransmissions().insert(std::make_pair(key, MessageData(message, getTransmissionsRemaining(dataArray))));
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Does nothing if key already in receivedEspnowTransmissions
|
|
EspnowDatabase::receivedEspnowTransmissions().insert(std::make_pair(std::make_pair(macAndType, messageID), MessageData(dataArray, len)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::map<std::pair<macAndType_td, messageID_td>, MessageData>::iterator storedMessageIterator = EspnowDatabase::receivedEspnowTransmissions().find(std::make_pair(macAndType, messageID));
|
|
|
|
if(storedMessageIterator == EspnowDatabase::receivedEspnowTransmissions().end()) // If we have not stored the key already, we missed the first message part.
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!storedMessageIterator->second.addToMessage(dataArray, len))
|
|
{
|
|
// If we received the wrong message part, remove the whole message if we have missed a part.
|
|
// Otherwise just ignore the received part since it has already been stored.
|
|
|
|
uint8_t transmissionsRemainingExpected = storedMessageIterator->second.getTransmissionsRemaining() - 1;
|
|
|
|
if(transmissionsRemaining < transmissionsRemainingExpected)
|
|
{
|
|
EspnowDatabase::receivedEspnowTransmissions().erase(storedMessageIterator);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Serial.println("methodStart storage done " + String(millis() - methodStart));
|
|
|
|
if(transmissionsRemaining != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::map<std::pair<macAndType_td, messageID_td>, MessageData>::iterator storedMessageIterator = EspnowDatabase::receivedEspnowTransmissions().find(std::make_pair(macAndType, messageID));
|
|
assert(storedMessageIterator != EspnowDatabase::receivedEspnowTransmissions().end());
|
|
|
|
// Copy totalMessage in case user callbacks (request/responseHandler) do something odd with receivedEspnowTransmissions list.
|
|
String totalMessage = storedMessageIterator->second.getTotalMessage(); // https://stackoverflow.com/questions/134731/returning-a-const-reference-to-an-object-instead-of-a-copy It is likely that most compilers will perform Named Value Return Value Optimisation in this case
|
|
|
|
EspnowDatabase::receivedEspnowTransmissions().erase(storedMessageIterator); // Erase the extra copy of the totalMessage, to save RAM.
|
|
|
|
//Serial.println("methodStart erase done " + String(millis() - methodStart));
|
|
|
|
if(messageType == 'Q' || messageType == 'B') // Question (request) or Broadcast
|
|
{
|
|
EspnowDatabase::storeReceivedRequest(uint64Mac, messageID, TimeTracker(millis()));
|
|
//Serial.println("methodStart request stored " + String(millis() - methodStart));
|
|
|
|
_database.setSenderMac(macaddr);
|
|
uint8_t senderAPMac[6] {0};
|
|
_database.setSenderAPMac(getTransmissionMac(dataArray, senderAPMac));
|
|
_encryptionBroker.setReceivedEncryptedTransmission(usesEncryption(messageID));
|
|
String response = getRequestHandler()(totalMessage, *this);
|
|
//Serial.println("methodStart response acquired " + String(millis() - methodStart));
|
|
|
|
if(response.length() > 0)
|
|
{
|
|
EspnowDatabase::responsesToSend().emplace_back(response, macaddr, messageID);
|
|
|
|
//Serial.println("methodStart Q done " + String(millis() - methodStart));
|
|
}
|
|
}
|
|
else if(messageType == 'A') // Answer (response)
|
|
{
|
|
EspnowDatabase::deleteSentRequest(uint64Mac, messageID); // Request has been answered, so stop accepting new answers about it.
|
|
|
|
if(EncryptedConnectionLog *encryptedConnection = EspnowConnectionManager::getEncryptedConnection(macaddr))
|
|
{
|
|
if(encryptedConnection->getOwnSessionKey() == messageID)
|
|
{
|
|
encryptedConnection->setDesync(false); // We just received an answer to the latest request we sent to the node, so the node sending the answer must now be in sync.
|
|
encryptedConnection->incrementOwnSessionKey();
|
|
}
|
|
}
|
|
|
|
_database.setSenderMac(macaddr);
|
|
uint8_t senderAPMac[6] {0};
|
|
_database.setSenderAPMac(getTransmissionMac(dataArray, senderAPMac));
|
|
_encryptionBroker.setReceivedEncryptedTransmission(usesEncryption(messageID));
|
|
getResponseHandler()(totalMessage, *this);
|
|
}
|
|
else
|
|
{
|
|
assert(messageType == 'Q' || messageType == 'A' || messageType == 'B');
|
|
}
|
|
|
|
ESP.wdtFeed(); // Prevents WDT reset in case we receive a lot of transmissions without break.
|
|
|
|
//Serial.println("methodStart wdtFeed done " + String(millis() - methodStart));
|
|
}
|
|
|
|
void EspnowMeshBackend::setEspnowRequestManager(EspnowMeshBackend *espnowMeshInstance)
|
|
{
|
|
_espnowRequestManager = espnowMeshInstance;
|
|
}
|
|
|
|
EspnowMeshBackend *EspnowMeshBackend::getEspnowRequestManager() {return _espnowRequestManager;}
|
|
|
|
bool EspnowMeshBackend::isEspnowRequestManager() const
|
|
{
|
|
return (this == getEspnowRequestManager());
|
|
}
|
|
|
|
void EspnowMeshBackend::setLogEntryLifetimeMs(const uint32_t logEntryLifetimeMs)
|
|
{
|
|
EspnowDatabase::setLogEntryLifetimeMs(logEntryLifetimeMs);
|
|
}
|
|
uint32_t EspnowMeshBackend::logEntryLifetimeMs() { return EspnowDatabase::logEntryLifetimeMs(); }
|
|
|
|
void EspnowMeshBackend::setBroadcastResponseTimeoutMs(const uint32_t broadcastResponseTimeoutMs)
|
|
{
|
|
EspnowDatabase::setBroadcastResponseTimeoutMs(broadcastResponseTimeoutMs);
|
|
}
|
|
uint32_t EspnowMeshBackend::broadcastResponseTimeoutMs() { return EspnowDatabase::broadcastResponseTimeoutMs(); }
|
|
|
|
void EspnowMeshBackend::setCriticalHeapLevelBuffer(const uint32_t bufferInBytes)
|
|
{
|
|
EspnowDatabase::setCriticalHeapLevelBuffer(bufferInBytes);
|
|
}
|
|
|
|
uint32_t EspnowMeshBackend::criticalHeapLevelBuffer()
|
|
{
|
|
return EspnowDatabase::criticalHeapLevelBuffer();
|
|
}
|
|
|
|
uint32_t EspnowMeshBackend::criticalHeapLevel()
|
|
{
|
|
return EspnowDatabase::criticalHeapLevel();
|
|
}
|
|
|
|
void EspnowMeshBackend::setEspnowTransmissionTimeout(const uint32_t timeoutMs)
|
|
{
|
|
EspnowTransmitter::setEspnowTransmissionTimeout(timeoutMs);
|
|
}
|
|
uint32_t EspnowMeshBackend::getEspnowTransmissionTimeout() {return EspnowTransmitter::getEspnowTransmissionTimeout();}
|
|
|
|
void EspnowMeshBackend::setEspnowRetransmissionInterval(const uint32_t intervalMs)
|
|
{
|
|
EspnowTransmitter::setEspnowRetransmissionInterval(intervalMs);
|
|
}
|
|
uint32_t EspnowMeshBackend::getEspnowRetransmissionInterval() {return EspnowTransmitter::getEspnowRetransmissionInterval();}
|
|
|
|
void EspnowMeshBackend::setEncryptionRequestTimeout(const uint32_t timeoutMs)
|
|
{
|
|
EspnowDatabase::setEncryptionRequestTimeout(timeoutMs);
|
|
}
|
|
uint32_t EspnowMeshBackend::getEncryptionRequestTimeout() {return EspnowDatabase::getEncryptionRequestTimeout();}
|
|
|
|
void EspnowMeshBackend::setAutoEncryptionDuration(const uint32_t duration)
|
|
{
|
|
_database.setAutoEncryptionDuration(duration);
|
|
}
|
|
uint32_t EspnowMeshBackend::getAutoEncryptionDuration() const {return _database.getAutoEncryptionDuration();}
|
|
|
|
void EspnowMeshBackend::setBroadcastFilter(const broadcastFilterType broadcastFilter) {_broadcastFilter = broadcastFilter;}
|
|
EspnowMeshBackend::broadcastFilterType EspnowMeshBackend::getBroadcastFilter() const {return _broadcastFilter;}
|
|
|
|
void EspnowMeshBackend::setEspnowEncryptedConnectionKey(const uint8_t espnowEncryptedConnectionKey[encryptedConnectionKeyLength])
|
|
{
|
|
_connectionManager.setEspnowEncryptedConnectionKey(espnowEncryptedConnectionKey);
|
|
}
|
|
|
|
void EspnowMeshBackend::setEspnowEncryptedConnectionKey(const String &espnowEncryptedConnectionKeySeed)
|
|
{
|
|
_connectionManager.setEspnowEncryptedConnectionKey(espnowEncryptedConnectionKeySeed);
|
|
}
|
|
|
|
const uint8_t *EspnowMeshBackend::getEspnowEncryptedConnectionKey() const
|
|
{
|
|
return _connectionManager.getEspnowEncryptedConnectionKey();
|
|
}
|
|
|
|
uint8_t *EspnowMeshBackend::getEspnowEncryptedConnectionKey(uint8_t resultArray[encryptedConnectionKeyLength]) const
|
|
{
|
|
return _connectionManager.getEspnowEncryptedConnectionKey(resultArray);
|
|
}
|
|
|
|
bool EspnowMeshBackend::setEspnowEncryptionKok(uint8_t espnowEncryptionKok[encryptedConnectionKeyLength])
|
|
{
|
|
return EspnowConnectionManager::setEspnowEncryptionKok(espnowEncryptionKok);
|
|
}
|
|
|
|
bool EspnowMeshBackend::setEspnowEncryptionKok(const String &espnowEncryptionKokSeed)
|
|
{
|
|
return EspnowConnectionManager::setEspnowEncryptionKok(espnowEncryptionKokSeed);
|
|
}
|
|
|
|
const uint8_t *EspnowMeshBackend::getEspnowEncryptionKok()
|
|
{
|
|
return EspnowConnectionManager::getEspnowEncryptionKok();
|
|
}
|
|
|
|
void EspnowMeshBackend::setEspnowHashKey(const uint8_t espnowHashKey[hashKeyLength])
|
|
{
|
|
_connectionManager.setEspnowHashKey(espnowHashKey);
|
|
}
|
|
|
|
void EspnowMeshBackend::setEspnowHashKey(const String &espnowHashKeySeed)
|
|
{
|
|
_connectionManager.setEspnowHashKey(espnowHashKeySeed);
|
|
}
|
|
|
|
const uint8_t *EspnowMeshBackend::getEspnowHashKey() const
|
|
{
|
|
return _connectionManager.getEspnowHashKey();
|
|
}
|
|
|
|
void EspnowMeshBackend::setUseEncryptedMessages(const bool useEncryptedMessages)
|
|
{
|
|
EspnowTransmitter::setUseEncryptedMessages(useEncryptedMessages);
|
|
}
|
|
bool EspnowMeshBackend::useEncryptedMessages() { return EspnowTransmitter::useEncryptedMessages(); }
|
|
|
|
void EspnowMeshBackend::setEspnowMessageEncryptionKey(const uint8_t espnowMessageEncryptionKey[experimental::crypto::ENCRYPTION_KEY_LENGTH])
|
|
{
|
|
EspnowTransmitter::setEspnowMessageEncryptionKey(espnowMessageEncryptionKey);
|
|
}
|
|
|
|
void EspnowMeshBackend::setEspnowMessageEncryptionKey(const String &espnowMessageEncryptionKeySeed)
|
|
{
|
|
EspnowTransmitter::setEspnowMessageEncryptionKey(espnowMessageEncryptionKeySeed);
|
|
}
|
|
|
|
const uint8_t *EspnowMeshBackend::getEspnowMessageEncryptionKey()
|
|
{
|
|
return EspnowTransmitter::getEspnowMessageEncryptionKey();
|
|
}
|
|
|
|
String EspnowMeshBackend::getScheduledResponseMessage(const uint32_t responseIndex)
|
|
{
|
|
return EspnowDatabase::getScheduledResponseMessage(responseIndex);
|
|
}
|
|
|
|
const uint8_t *EspnowMeshBackend::getScheduledResponseRecipient(const uint32_t responseIndex)
|
|
{
|
|
return EspnowDatabase::getScheduledResponseRecipient(responseIndex);
|
|
}
|
|
|
|
uint32_t EspnowMeshBackend::numberOfScheduledResponses() {return EspnowDatabase::numberOfScheduledResponses();}
|
|
|
|
void EspnowMeshBackend::clearAllScheduledResponses()
|
|
{
|
|
EspnowDatabase::clearAllScheduledResponses();
|
|
}
|
|
|
|
void EspnowMeshBackend::deleteScheduledResponsesByRecipient(const uint8_t *recipientMac, const bool encryptedOnly)
|
|
{
|
|
EspnowDatabase::deleteScheduledResponsesByRecipient(recipientMac, encryptedOnly);
|
|
}
|
|
|
|
String EspnowMeshBackend::getSenderMac() const {return _database.getSenderMac();}
|
|
uint8_t *EspnowMeshBackend::getSenderMac(uint8_t *macArray) const
|
|
{
|
|
return _database.getSenderMac(macArray);
|
|
}
|
|
|
|
String EspnowMeshBackend::getSenderAPMac() const {return _database.getSenderAPMac();}
|
|
uint8_t *EspnowMeshBackend::getSenderAPMac(uint8_t *macArray) const
|
|
{
|
|
return _database.getSenderAPMac(macArray);
|
|
}
|
|
|
|
bool EspnowMeshBackend::receivedEncryptedTransmission() const {return _encryptionBroker.receivedEncryptedTransmission();}
|
|
|
|
bool EspnowMeshBackend::addUnencryptedConnection(const String &serializedConnectionState)
|
|
{
|
|
return EspnowConnectionManager::addUnencryptedConnection(serializedConnectionState);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::addEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, const uint64_t peerSessionKey, const uint64_t ownSessionKey)
|
|
{
|
|
return _connectionManager.addEncryptedConnection(peerStaMac, peerApMac, peerSessionKey, ownSessionKey);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::addEncryptedConnection(const String &serializedConnectionState, const bool ignoreDuration)
|
|
{
|
|
return _connectionManager.addEncryptedConnection(serializedConnectionState, ignoreDuration);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::addTemporaryEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, const uint64_t peerSessionKey, const uint64_t ownSessionKey, const uint32_t duration)
|
|
{
|
|
return _connectionManager.addTemporaryEncryptedConnection(peerStaMac, peerApMac, peerSessionKey, ownSessionKey, duration);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::addTemporaryEncryptedConnection(const String &serializedConnectionState, const uint32_t duration)
|
|
{
|
|
return _connectionManager.addTemporaryEncryptedConnection(serializedConnectionState, duration);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::requestEncryptedConnection(const uint8_t *peerMac)
|
|
{
|
|
return _encryptionBroker.requestEncryptedConnection(peerMac, *this);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::requestTemporaryEncryptedConnection(const uint8_t *peerMac, const uint32_t durationMs)
|
|
{
|
|
return _encryptionBroker.requestTemporaryEncryptedConnection(peerMac, durationMs, *this);
|
|
}
|
|
|
|
EncryptedConnectionStatus EspnowMeshBackend::requestFlexibleTemporaryEncryptedConnection(const uint8_t *peerMac, const uint32_t minDurationMs)
|
|
{
|
|
return _encryptionBroker.requestFlexibleTemporaryEncryptedConnection(peerMac, minDurationMs, *this);
|
|
}
|
|
|
|
EncryptedConnectionRemovalOutcome EspnowMeshBackend::removeEncryptedConnection(const uint8_t *peerMac)
|
|
{
|
|
return EspnowConnectionManager::removeEncryptedConnection(peerMac);
|
|
}
|
|
|
|
EncryptedConnectionRemovalOutcome EspnowMeshBackend::requestEncryptedConnectionRemoval(const uint8_t *peerMac)
|
|
{
|
|
return _encryptionBroker.requestEncryptedConnectionRemoval(peerMac);
|
|
}
|
|
|
|
void EspnowMeshBackend::setAcceptsUnverifiedRequests(const bool acceptsUnverifiedRequests) { _acceptsUnverifiedRequests = acceptsUnverifiedRequests; }
|
|
bool EspnowMeshBackend::acceptsUnverifiedRequests() const { return _acceptsUnverifiedRequests; }
|
|
|
|
void EspnowMeshBackend::setEncryptedConnectionsSoftLimit(const uint8_t softLimit)
|
|
{
|
|
_connectionManager.setEncryptedConnectionsSoftLimit(softLimit);
|
|
}
|
|
|
|
uint8_t EspnowMeshBackend::encryptedConnectionsSoftLimit() const { return _connectionManager.encryptedConnectionsSoftLimit(); }
|
|
|
|
uint8_t *EspnowMeshBackend::getEncryptedMac(const uint8_t *peerMac, uint8_t *resultArray)
|
|
{
|
|
return EspnowConnectionManager::getEncryptedMac(peerMac, resultArray);
|
|
}
|
|
|
|
void EspnowMeshBackend::prepareForTransmission(const String &message, const bool scan, const bool scanAllWiFiChannels)
|
|
{
|
|
setMessage(message);
|
|
|
|
latestTransmissionOutcomes().clear();
|
|
|
|
if(scan)
|
|
{
|
|
connectionQueue().clear();
|
|
scanForNetworks(scanAllWiFiChannels);
|
|
}
|
|
}
|
|
|
|
TransmissionStatusType EspnowMeshBackend::initiateTransmission(const String &message, const EspnowNetworkInfo &recipientInfo)
|
|
{
|
|
uint8_t targetBSSID[6] {0};
|
|
|
|
assert(recipientInfo.BSSID() != nullptr); // We need at least the BSSID to connect
|
|
recipientInfo.getBSSID(targetBSSID);
|
|
|
|
if(verboseMode()) // Avoid string generation if not required
|
|
{
|
|
printAPInfo(recipientInfo);
|
|
verboseModePrint(emptyString);
|
|
}
|
|
|
|
return initiateTransmissionKernel(message, targetBSSID);
|
|
}
|
|
|
|
TransmissionStatusType EspnowMeshBackend::initiateTransmissionKernel(const String &message, const uint8_t *targetBSSID)
|
|
{
|
|
uint32_t transmissionStartTime = millis();
|
|
TransmissionStatusType transmissionResult = _transmitter.sendRequest(message, targetBSSID, this);
|
|
|
|
uint32_t transmissionDuration = millis() - transmissionStartTime;
|
|
|
|
if(verboseMode() && transmissionResult == TransmissionStatusType::TRANSMISSION_COMPLETE) // Avoid calculations if not required
|
|
{
|
|
totalDurationWhenSuccessful_AT += transmissionDuration;
|
|
++successfulTransmissions_AT;
|
|
if(transmissionDuration > maxTransmissionDuration_AT)
|
|
{
|
|
maxTransmissionDuration_AT = transmissionDuration;
|
|
}
|
|
}
|
|
|
|
return transmissionResult;
|
|
}
|
|
|
|
void EspnowMeshBackend::printTransmissionStatistics() const
|
|
{
|
|
if(verboseMode() && successfulTransmissions_AT > 0) // Avoid calculations if not required
|
|
{
|
|
verboseModePrint(String(F("Average duration of successful transmissions: ")) + String(totalDurationWhenSuccessful_AT/successfulTransmissions_AT) + String(F(" ms.")));
|
|
verboseModePrint(String(F("Maximum duration of successful transmissions: ")) + String(maxTransmissionDuration_AT) + String(F(" ms.")));
|
|
}
|
|
else
|
|
{
|
|
verboseModePrint(String(F("No successful transmission.")));
|
|
}
|
|
}
|
|
|
|
void EspnowMeshBackend::attemptTransmission(const String &message, const bool scan, const bool scanAllWiFiChannels)
|
|
{
|
|
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex(EspnowConnectionManager::handlePostponedRemovals));
|
|
if(!mutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.")));
|
|
return;
|
|
}
|
|
|
|
prepareForTransmission(message, scan, scanAllWiFiChannels);
|
|
|
|
MutexTracker connectionQueueMutexTracker(EspnowDatabase::captureEspnowConnectionQueueMutex());
|
|
if(!connectionQueueMutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! connectionQueue locked. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.")));
|
|
}
|
|
else
|
|
{
|
|
for(const EspnowNetworkInfo ¤tNetwork : constConnectionQueue())
|
|
{
|
|
TransmissionStatusType transmissionResult = initiateTransmission(getMessage(), currentNetwork);
|
|
|
|
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
|
|
|
if(!getTransmissionOutcomesUpdateHook()(*this))
|
|
break;
|
|
}
|
|
}
|
|
|
|
printTransmissionStatistics();
|
|
}
|
|
|
|
TransmissionStatusType EspnowMeshBackend::attemptTransmission(const String &message, const EspnowNetworkInfo &recipientInfo)
|
|
{
|
|
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex(EspnowConnectionManager::handlePostponedRemovals));
|
|
if(!mutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.")));
|
|
return TransmissionStatusType::CONNECTION_FAILED;
|
|
}
|
|
|
|
return initiateTransmission(message, recipientInfo);
|
|
}
|
|
|
|
TransmissionStatusType EspnowMeshBackend::initiateAutoEncryptingTransmission(const String &message, uint8_t *targetBSSID, EncryptedConnectionStatus connectionStatus)
|
|
{
|
|
TransmissionStatusType transmissionResult = TransmissionStatusType::CONNECTION_FAILED;
|
|
|
|
if(EspnowEncryptionBroker::encryptedConnectionEstablished(connectionStatus))
|
|
{
|
|
uint8_t encryptedMac[6] {0};
|
|
assert(getEncryptedMac(targetBSSID, encryptedMac) && esp_now_is_peer_exist(encryptedMac) > 0 && String(F("ERROR! Attempting to send content marked as encrypted via unencrypted connection!")));
|
|
transmissionResult = initiateTransmissionKernel(message, targetBSSID);
|
|
}
|
|
|
|
return transmissionResult;
|
|
}
|
|
|
|
void EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message, const bool requestPermanentConnections, const bool scan, const bool scanAllWiFiChannels)
|
|
{
|
|
MutexTracker outerMutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex(EspnowConnectionManager::handlePostponedRemovals));
|
|
if(!outerMutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Transmission in progress. Don't call attemptAutoEncryptingTransmission from callbacks as this may corrupt program state! Aborting.")));
|
|
return;
|
|
}
|
|
|
|
prepareForTransmission(message, scan, scanAllWiFiChannels);
|
|
|
|
outerMutexTracker.releaseMutex();
|
|
|
|
MutexTracker connectionQueueMutexTracker(EspnowDatabase::captureEspnowConnectionQueueMutex());
|
|
if(!connectionQueueMutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! connectionQueue locked. Don't call attemptAutoEncryptingTransmission from callbacks as this may corrupt program state! Aborting.")));
|
|
}
|
|
else
|
|
{
|
|
for(const EspnowNetworkInfo ¤tNetwork : constConnectionQueue())
|
|
{
|
|
uint8_t currentBSSID[6] {0};
|
|
EncryptedConnectionLog *existingEncryptedConnection = nullptr;
|
|
EncryptedConnectionStatus connectionStatus = _encryptionBroker.initiateAutoEncryptingConnection(currentNetwork, requestPermanentConnections, currentBSSID, &existingEncryptedConnection, *this);
|
|
|
|
MutexTracker innerMutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex());
|
|
if(!innerMutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Unable to recapture Mutex in attemptAutoEncryptingTransmission. Aborting.")));
|
|
return;
|
|
}
|
|
|
|
TransmissionStatusType transmissionResult = initiateAutoEncryptingTransmission(getMessage(), currentBSSID, connectionStatus);
|
|
|
|
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
|
|
|
_encryptionBroker.finalizeAutoEncryptingConnection(currentBSSID, existingEncryptedConnection, requestPermanentConnections);
|
|
|
|
if(!getTransmissionOutcomesUpdateHook()(*this))
|
|
break;
|
|
}
|
|
}
|
|
|
|
printTransmissionStatistics();
|
|
}
|
|
|
|
TransmissionStatusType EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message, const EspnowNetworkInfo &recipientInfo, const bool requestPermanentConnection)
|
|
{
|
|
uint8_t targetBSSID[6] {0};
|
|
EncryptedConnectionLog *existingEncryptedConnection = nullptr;
|
|
EncryptedConnectionStatus connectionStatus = _encryptionBroker.initiateAutoEncryptingConnection(recipientInfo, requestPermanentConnection, targetBSSID, &existingEncryptedConnection, *this);
|
|
|
|
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex(EspnowConnectionManager::handlePostponedRemovals));
|
|
if(!mutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.")));
|
|
return TransmissionStatusType::CONNECTION_FAILED;
|
|
}
|
|
|
|
TransmissionStatusType transmissionResult = initiateAutoEncryptingTransmission(message, targetBSSID, connectionStatus);
|
|
|
|
_encryptionBroker.finalizeAutoEncryptingConnection(targetBSSID, existingEncryptedConnection, requestPermanentConnection);
|
|
|
|
return transmissionResult;
|
|
}
|
|
|
|
void EspnowMeshBackend::broadcast(const String &message)
|
|
{
|
|
MutexTracker mutexTracker(EspnowTransmitter::captureEspnowTransmissionMutex(EspnowConnectionManager::handlePostponedRemovals));
|
|
if(!mutexTracker.mutexCaptured())
|
|
{
|
|
assert(false && String(F("ERROR! Transmission in progress. Don't call broadcast from callbacks as this may corrupt program state! Aborting.")));
|
|
return;
|
|
}
|
|
|
|
EspnowTransmitter::espnowSendToNode(message, EspnowProtocolInterpreter::broadcastMac, 'B', this);
|
|
}
|
|
|
|
void EspnowMeshBackend::setBroadcastTransmissionRedundancy(const uint8_t redundancy) { _transmitter.setBroadcastTransmissionRedundancy(redundancy); }
|
|
uint8_t EspnowMeshBackend::getBroadcastTransmissionRedundancy() const { return _transmitter.getBroadcastTransmissionRedundancy(); }
|
|
|
|
void EspnowMeshBackend::setResponseTransmittedHook(const EspnowTransmitter::responseTransmittedHookType responseTransmittedHook) { _transmitter.setResponseTransmittedHook(responseTransmittedHook); }
|
|
EspnowTransmitter::responseTransmittedHookType EspnowMeshBackend::getResponseTransmittedHook() const { return _transmitter.getResponseTransmittedHook(); }
|
|
|
|
EspnowDatabase *EspnowMeshBackend::getDatabase() { return &_database; }
|
|
const EspnowDatabase *EspnowMeshBackend::getDatabaseConst() const { return &_database; }
|
|
EspnowConnectionManager *EspnowMeshBackend::getConnectionManager() { return &_connectionManager; }
|
|
const EspnowConnectionManager *EspnowMeshBackend::getConnectionManagerConst() const { return &_connectionManager; }
|
|
EspnowTransmitter *EspnowMeshBackend::getTransmitter() { return &_transmitter; }
|
|
const EspnowTransmitter *EspnowMeshBackend::getTransmitterConst() const { return &_transmitter; }
|
|
EspnowEncryptionBroker *EspnowMeshBackend::getEncryptionBroker() { return &_encryptionBroker; }
|
|
const EspnowEncryptionBroker *EspnowMeshBackend::getEncryptionBrokerConst() const { return &_encryptionBroker; }
|
|
|
|
void EspnowMeshBackend::sendStoredEspnowMessages(const ExpiringTimeTracker *estimatedMaxDurationTracker)
|
|
{
|
|
EspnowEncryptionBroker::sendPeerRequestConfirmations(estimatedMaxDurationTracker);
|
|
|
|
if(estimatedMaxDurationTracker && estimatedMaxDurationTracker->expired())
|
|
return;
|
|
|
|
EspnowTransmitter::sendEspnowResponses(estimatedMaxDurationTracker);
|
|
}
|
|
|
|
uint32_t EspnowMeshBackend::getMaxMessageBytesPerTransmission()
|
|
{
|
|
return EspnowProtocolInterpreter::getMaxMessageBytesPerTransmission();
|
|
}
|
|
|
|
void EspnowMeshBackend::setMaxTransmissionsPerMessage(const uint8_t maxTransmissionsPerMessage)
|
|
{
|
|
EspnowTransmitter::setMaxTransmissionsPerMessage(maxTransmissionsPerMessage);
|
|
}
|
|
|
|
uint8_t EspnowMeshBackend::getMaxTransmissionsPerMessage() {return EspnowTransmitter::getMaxTransmissionsPerMessage();}
|
|
|
|
uint32_t EspnowMeshBackend::getMaxMessageLength()
|
|
{
|
|
return EspnowTransmitter::getMaxMessageLength();
|
|
}
|
|
|
|
void EspnowMeshBackend::setVerboseModeState(const bool enabled) {(*getConditionalPrinter()).setVerboseModeState(enabled); ConditionalPrinter::setStaticVerboseModeState(enabled);}
|
|
bool EspnowMeshBackend::verboseMode() const {return ConditionalPrinter::staticVerboseMode();}
|
|
|
|
void EspnowMeshBackend::verboseModePrint(const String &stringToPrint, const bool newline) const
|
|
{
|
|
(*getConditionalPrinterConst()).verboseModePrint(stringToPrint, newline);
|
|
}
|
|
|
|
bool EspnowMeshBackend::staticVerboseMode() {return ConditionalPrinter::staticVerboseMode();}
|
|
void EspnowMeshBackend::staticVerboseModePrint(const String &stringToPrint, const bool newline)
|
|
{
|
|
ConditionalPrinter::staticVerboseModePrint(stringToPrint, newline);
|
|
}
|
|
|
|
uint8_t EspnowMeshBackend::numberOfEncryptedConnections()
|
|
{
|
|
return EspnowConnectionManager::numberOfEncryptedConnections();
|
|
}
|
|
|
|
ConnectionType EspnowMeshBackend::getConnectionInfo(uint8_t *peerMac, uint32_t *remainingDuration)
|
|
{
|
|
return EspnowConnectionManager::getConnectionInfo(peerMac, remainingDuration);
|
|
}
|
|
|
|
ConnectionType EspnowMeshBackend::getConnectionInfo(const uint32_t connectionIndex, uint32_t *remainingDuration, uint8_t *peerMac)
|
|
{
|
|
return EspnowConnectionManager::getConnectionInfo(connectionIndex, remainingDuration, peerMac);
|
|
}
|
|
|
|
double EspnowMeshBackend::getTransmissionFailRate()
|
|
{
|
|
return EspnowTransmitter::getTransmissionFailRate();
|
|
}
|
|
|
|
void EspnowMeshBackend::resetTransmissionFailRate()
|
|
{
|
|
EspnowTransmitter::resetTransmissionFailRate();
|
|
}
|
|
|
|
String EspnowMeshBackend::serializeUnencryptedConnection()
|
|
{
|
|
return EspnowConnectionManager::serializeUnencryptedConnection();
|
|
}
|
|
|
|
String EspnowMeshBackend::serializeEncryptedConnection(const uint8_t *peerMac)
|
|
{
|
|
return EspnowConnectionManager::serializeEncryptedConnection(peerMac);
|
|
}
|
|
|
|
String EspnowMeshBackend::serializeEncryptedConnection(const uint32_t connectionIndex)
|
|
{
|
|
return EspnowConnectionManager::serializeEncryptedConnection(connectionIndex);
|
|
}
|
|
|
|
void EspnowMeshBackend::setWiFiChannel(const uint8 newWiFiChannel)
|
|
{
|
|
MeshBackendBase::setWiFiChannel(newWiFiChannel);
|
|
_database.setWiFiChannel(newWiFiChannel);
|
|
}
|