/* Copyright (C) 2020 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 */ #ifndef __ESPNOWDATABASE_H__ #define __ESPNOWDATABASE_H__ #include #include "EspnowNetworkInfo.h" #include "TransmissionOutcome.h" #include "ResponseData.h" #include "RequestData.h" #include "EspnowProtocolInterpreter.h" #include #include #include "MessageData.h" #include "MutexTracker.h" #include "PeerRequestLog.h" #include "ConditionalPrinter.h" #include "TypeConversionFunctions.h" class EspnowMeshBackend; class EspnowDatabase { public: EspnowDatabase(ConditionalPrinter &conditionalPrinterInstance, const uint8 espnowWiFiChannel); static std::vector & connectionQueue(); static const std::vector & constConnectionQueue(); static std::vector & latestTransmissionOutcomes(); static uint32_t criticalHeapLevel(); static void setCriticalHeapLevelBuffer(const uint32_t bufferInBytes); static uint32_t criticalHeapLevelBuffer(); static void setLogEntryLifetimeMs(const uint32_t logEntryLifetimeMs); static uint32_t logEntryLifetimeMs(); static void setBroadcastResponseTimeoutMs(const uint32_t broadcastResponseTimeoutMs); static uint32_t broadcastResponseTimeoutMs(); static String getScheduledResponseMessage(const uint32_t responseIndex); static const uint8_t *getScheduledResponseRecipient(const uint32_t responseIndex); static uint32_t numberOfScheduledResponses(); static void clearAllScheduledResponses(); static void deleteScheduledResponsesByRecipient(const uint8_t *recipientMac, const bool encryptedOnly); static void setEncryptionRequestTimeout(const uint32_t timeoutMs); static uint32_t getEncryptionRequestTimeout(); void setAutoEncryptionDuration(const uint32_t duration); uint32_t getAutoEncryptionDuration() const; String getSenderMac() const; uint8_t *getSenderMac(uint8_t *macArray) const; String getSenderAPMac() const; uint8_t *getSenderAPMac(uint8_t *macArray) const; using macAndType_td = EspnowProtocolInterpreter::macAndType_td; using messageID_td = EspnowProtocolInterpreter::messageID_td; using peerMac_td = EspnowProtocolInterpreter::peerMac_td; static size_t deleteSentRequestsByOwner(const EspnowMeshBackend *instancePointer); static std::list & responsesToSend(); static std::list & peerRequestConfirmationsToSend(); static std::map, MessageData> & receivedEspnowTransmissions(); static std::map, RequestData> & sentRequests(); static std::map, TimeTracker> & receivedRequests(); static bool requestReceived(const uint64_t requestMac, const uint64_t requestID); /** * Will be captured when the connectionQueue should not be modified. */ static MutexTracker captureEspnowConnectionQueueMutex(); static MutexTracker captureEspnowConnectionQueueMutex(const std::function destructorHook); /** * Will be captured when no responsesToSend element should be removed. */ static MutexTracker captureResponsesToSendMutex(); static MutexTracker captureResponsesToSendMutex(const std::function destructorHook); static void clearOldLogEntries(bool forced); static void storeSentRequest(const uint64_t targetBSSID, const uint64_t messageID, const RequestData &requestData); static void storeReceivedRequest(const uint64_t senderBSSID, const uint64_t messageID, const TimeTracker &timeTracker); /** * Get a pointer to the EspnowMeshBackend instance that sent a request with the given requestID to the specified mac address. * * @return A valid EspnowMeshBackend pointer if a matching entry is found in the EspnowMeshBackend sentRequests container. nullptr otherwise. */ static EspnowMeshBackend *getOwnerOfSentRequest(const uint64_t requestMac, const uint64_t requestID); /** * Delete all entries in the sentRequests container where requestMac is noted as having received requestID. * * @return The number of entries deleted. */ static size_t deleteSentRequest(const uint64_t requestMac, const uint64_t requestID); /** * Set the MAC address considered to be the sender of the most recently received ESP-NOW request, response or broadcast. * * @param macArray An uint8_t array which contains the MAC address to store. The method will store the first 6 bytes of the array. */ void setSenderMac(const uint8_t *macArray); /** * Set the MAC address considered to be the AP MAC of the sender of the most recently received ESP-NOW request, response or broadcast. * * @param macArray An uint8_t array which contains the MAC address to store. The method will store the first 6 bytes of the array. */ void setSenderAPMac(const uint8_t *macArray); void setWiFiChannel(const uint8 newWiFiChannel); uint8 getWiFiChannel() const; /** * Remove all entries which target peerMac in the logEntries map. * Optionally deletes only entries sent/received by encrypted transmissions. * * @param logEntries The map to process. * @param peerMac The MAC address of the peer node. * @param encryptedOnly If true, only entries sent/received by encrypted transmissions will be deleted. */ template static void deleteEntriesByMac(std::map, T> &logEntries, const uint8_t *peerMac, const bool encryptedOnly) { bool macFound = false; for(typename std::map, T>::iterator entryIterator = logEntries.begin(); entryIterator != logEntries.end(); ) { if(macAndTypeToUint64Mac(entryIterator->first.first) == MeshTypeConversionFunctions::macToUint64(peerMac)) { macFound = true; if(!encryptedOnly || EspnowProtocolInterpreter::usesEncryption(entryIterator->first.second)) { entryIterator = logEntries.erase(entryIterator); continue; } } else if(macFound) { // Since the map is sorted by MAC, we know here that no more matching MAC will be found. return; } ++entryIterator; } } template static void deleteEntriesByMac(std::map, T> &logEntries, const uint8_t *peerMac, const bool encryptedOnly) { bool macFound = false; for(typename std::map, T>::iterator entryIterator = logEntries.begin(); entryIterator != logEntries.end(); ) { if(entryIterator->first.first == MeshTypeConversionFunctions::macToUint64(peerMac)) { macFound = true; if(!encryptedOnly || EspnowProtocolInterpreter::usesEncryption(entryIterator->first.second)) { entryIterator = logEntries.erase(entryIterator); continue; } } else if(macFound) { // Since the map is sorted by MAC, we know here that no more matching MAC will be found. return; } ++entryIterator; } } protected: static std::vector _connectionQueue; static std::vector _latestTransmissionOutcomes; static std::list::const_iterator getScheduledResponse(const uint32_t responseIndex); private: ConditionalPrinter & _conditionalPrinter; uint32_t _autoEncryptionDuration = 50; template static void deleteExpiredLogEntries(std::map, T> &logEntries, const uint32_t maxEntryLifetimeMs); template static void deleteExpiredLogEntries(std::map, TimeTracker> &logEntries, const uint32_t maxEntryLifetimeMs); static void deleteExpiredLogEntries(std::map, RequestData> &logEntries, const uint32_t requestLifetimeMs, const uint32_t broadcastLifetimeMs); template static void deleteExpiredLogEntries(std::list &logEntries, const uint32_t maxEntryLifetimeMs); uint8_t _senderMac[6] = {0}; uint8_t _senderAPMac[6] = {0}; uint8 _espnowWiFiChannel; }; #endif