mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-25 20:02:37 +03:00
- Rework ExpiringTimeTracker to be based on PolledTimeout.
- Ensure espnowDelay and floodingMeshDelay always performs maintenance. - Rework MutexTracker to use shared_ptr. - Change enums to enum class. - Change typedef to using. - Add HeapMonitor class. - Make _messageIDs be a map instead of an unordered_map to reduce heap usage. - Use the possibly broken wifi_country ESP8266 API to check for legal WiFi channels when setting WiFi channels. - Make MessageData, RequestData and ResponseData contain a TimeTracker rather than inherit from TimeTracker. - Add deprecated attribute to TransmissionResult. - Remove superfluous elses. - Reduce cyclomatic complexity. - Change postfix ++ and -- to prefix. - Generalize getEncryptedConnectionIterator method. - Increase code NRVO compatibility. - Change _connectionAttemptTimeoutMs type from int32_t to uint32_t. - Add deprecated attribute to ESP8266WiFiMesh. - Add some constness to TypeConversionFunctions. - Move base36 arrays to PROGMEM in TypeConversionFunctions.cpp. - Add deprecated atttribute to SHA1 and MD5 hashes. - Remove _warningsEnabled in CryptoInterface since this has been replaced by the deprecated attribute. - Prefix all TypeConversion getters with "get". - Improve comments. - Fix merge conflict.
This commit is contained in:
parent
a49f047096
commit
16801f3dac
@ -1,4 +1,4 @@
|
||||
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
|
||||
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <EspnowMeshBackend.h>
|
||||
@ -40,7 +40,7 @@ unsigned int responseNumber = 0;
|
||||
const char broadcastMetadataDelimiter = 23; // 23 = End-of-Transmission-Block (ETB) control character in ASCII
|
||||
|
||||
String manageRequest(const String &request, MeshBackendBase &meshInstance);
|
||||
transmission_status_t manageResponse(const String &response, MeshBackendBase &meshInstance);
|
||||
TransmissionStatusType manageResponse(const String &response, MeshBackendBase &meshInstance);
|
||||
void networkFilter(int numberOfNetworks, MeshBackendBase &meshInstance);
|
||||
bool broadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance);
|
||||
|
||||
@ -55,27 +55,22 @@ EspnowMeshBackend espnowNode = EspnowMeshBackend(manageRequest, manageResponse,
|
||||
@return The string to send back to the other node. For ESP-NOW, return an empy string ("") if no response should be sent.
|
||||
*/
|
||||
String manageRequest(const String &request, MeshBackendBase &meshInstance) {
|
||||
// We do not store strings in flash (via F()) in this function.
|
||||
// The reason is that the other node will be waiting for our response,
|
||||
// so keeping the strings in RAM will give a (small) improvement in response time.
|
||||
// Of course, it is advised to adjust this approach based on RAM requirements.
|
||||
|
||||
// To get the actual class of the polymorphic meshInstance, do as follows (meshBackendCast replaces dynamic_cast since RTTI is disabled)
|
||||
if (EspnowMeshBackend *espnowInstance = TypeCast::meshBackendCast<EspnowMeshBackend *>(&meshInstance)) {
|
||||
String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? ", Encrypted transmission" : ", Unencrypted transmission";
|
||||
Serial.print("ESP-NOW (" + espnowInstance->getSenderMac() + transmissionEncrypted + "): ");
|
||||
String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? F(", Encrypted transmission") : F(", Unencrypted transmission");
|
||||
Serial.print(String(F("ESP-NOW (")) + espnowInstance->getSenderMac() + transmissionEncrypted + F("): "));
|
||||
} else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
|
||||
(void)tcpIpInstance; // This is useful to remove a "unused parameter" compiler warning. Does nothing else.
|
||||
Serial.print("TCP/IP: ");
|
||||
Serial.print(F("TCP/IP: "));
|
||||
} else {
|
||||
Serial.print("UNKNOWN!: ");
|
||||
Serial.print(F("UNKNOWN!: "));
|
||||
}
|
||||
|
||||
/* Print out received message */
|
||||
// Only show first 100 characters because printing a large String takes a lot of time, which is a bad thing for a callback function.
|
||||
// If you need to print the whole String it is better to store it and print it in the loop() later.
|
||||
// Note that request.substring will not work as expected if the String contains null values as data.
|
||||
Serial.print("Request received: ");
|
||||
Serial.print(F("Request received: "));
|
||||
|
||||
if (request.charAt(0) == 0) {
|
||||
Serial.println(request); // substring will not work for multiStrings.
|
||||
@ -84,7 +79,7 @@ String manageRequest(const String &request, MeshBackendBase &meshInstance) {
|
||||
}
|
||||
|
||||
/* return a string to send back */
|
||||
return ("Hello world response #" + String(responseNumber++) + " from " + meshInstance.getMeshName() + meshInstance.getNodeID() + " with AP MAC " + WiFi.softAPmacAddress() + ".");
|
||||
return (String(F("Hello world response #")) + String(responseNumber++) + F(" from ") + meshInstance.getMeshName() + meshInstance.getNodeID() + F(" with AP MAC ") + WiFi.softAPmacAddress() + String('.'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,15 +89,15 @@ String manageRequest(const String &request, MeshBackendBase &meshInstance) {
|
||||
@param meshInstance The MeshBackendBase instance that called the function.
|
||||
@return The status code resulting from the response, as an int
|
||||
*/
|
||||
transmission_status_t manageResponse(const String &response, MeshBackendBase &meshInstance) {
|
||||
transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE;
|
||||
TransmissionStatusType manageResponse(const String &response, MeshBackendBase &meshInstance) {
|
||||
TransmissionStatusType statusCode = TransmissionStatusType::TRANSMISSION_COMPLETE;
|
||||
|
||||
// To get the actual class of the polymorphic meshInstance, do as follows (meshBackendCast replaces dynamic_cast since RTTI is disabled)
|
||||
if (EspnowMeshBackend *espnowInstance = TypeCast::meshBackendCast<EspnowMeshBackend *>(&meshInstance)) {
|
||||
String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? ", Encrypted transmission" : ", Unencrypted transmission";
|
||||
Serial.print("ESP-NOW (" + espnowInstance->getSenderMac() + transmissionEncrypted + "): ");
|
||||
String transmissionEncrypted = espnowInstance->receivedEncryptedTransmission() ? F(", Encrypted transmission") : F(", Unencrypted transmission");
|
||||
Serial.print(String(F("ESP-NOW (")) + espnowInstance->getSenderMac() + transmissionEncrypted + F("): "));
|
||||
} else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
|
||||
Serial.print("TCP/IP: ");
|
||||
Serial.print(F("TCP/IP: "));
|
||||
|
||||
// Getting the sent message like this will work as long as ONLY(!) TCP/IP is used.
|
||||
// With TCP/IP the response will follow immediately after the request, so the stored message will not have changed.
|
||||
@ -111,7 +106,7 @@ transmission_status_t manageResponse(const String &response, MeshBackendBase &me
|
||||
Serial.print(F("Request sent: "));
|
||||
Serial.println(tcpIpInstance->getCurrentMessage().substring(0, 100));
|
||||
} else {
|
||||
Serial.print("UNKNOWN!: ");
|
||||
Serial.print(F("UNKNOWN!: "));
|
||||
}
|
||||
|
||||
/* Print out received message */
|
||||
@ -146,7 +141,7 @@ void networkFilter(int numberOfNetworks, MeshBackendBase &meshInstance) {
|
||||
} else if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
|
||||
tcpIpInstance->connectionQueue().push_back(networkIndex);
|
||||
} else {
|
||||
Serial.println(String(F("Invalid mesh backend!")));
|
||||
Serial.println(F("Invalid mesh backend!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,7 +172,7 @@ bool broadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance)
|
||||
|
||||
String targetMeshName = firstTransmission.substring(0, metadataEndIndex);
|
||||
|
||||
if (targetMeshName != "" && meshInstance.getMeshName() != targetMeshName) {
|
||||
if (!targetMeshName.isEmpty() && meshInstance.getMeshName() != targetMeshName) {
|
||||
return false; // Broadcast is for another mesh network
|
||||
} else {
|
||||
// Remove metadata from message and mark as accepted broadcast.
|
||||
@ -274,7 +269,7 @@ void setup() {
|
||||
// Storing our message in the EspnowMeshBackend instance is not required, but can be useful for organizing code, especially when using many EspnowMeshBackend instances.
|
||||
// Note that calling the multi-recipient versions of espnowNode.attemptTransmission and espnowNode.attemptAutoEncryptingTransmission will replace the stored message with whatever message is transmitted.
|
||||
// Also note that the maximum allowed number of ASCII characters in a ESP-NOW message is given by EspnowMeshBackend::getMaxMessageLength().
|
||||
espnowNode.setMessage(String(F("Hello world request #")) + String(requestNumber) + String(F(" from ")) + espnowNode.getMeshName() + espnowNode.getNodeID() + String(F(".")));
|
||||
espnowNode.setMessage(String(F("Hello world request #")) + String(requestNumber) + F(" from ") + espnowNode.getMeshName() + espnowNode.getNodeID() + String('.'));
|
||||
|
||||
espnowNode.setTransmissionOutcomesUpdateHook(exampleTransmissionOutcomesUpdateHook);
|
||||
espnowNode.setResponseTransmittedHook(exampleResponseTransmittedHook);
|
||||
@ -290,7 +285,7 @@ void setup() {
|
||||
// Uncomment the lines below to use automatic AEAD encryption/decryption of messages sent/received.
|
||||
// All nodes this node wishes to communicate with must then also use encrypted messages with the same getEspnowMessageEncryptionKey(), or messages will not be accepted.
|
||||
// Note that using AEAD encrypted messages will reduce the number of message bytes that can be transmitted.
|
||||
//espnowNode.setEspnowMessageEncryptionKey("ChangeThisKeySeed_TODO"); // The message encryption key should always be set manually. Otherwise a default key (all zeroes) is used.
|
||||
//espnowNode.setEspnowMessageEncryptionKey(F("ChangeThisKeySeed_TODO")); // The message encryption key should always be set manually. Otherwise a default key (all zeroes) is used.
|
||||
//espnowNode.setUseEncryptedMessages(true);
|
||||
}
|
||||
|
||||
@ -306,11 +301,11 @@ void loop() {
|
||||
EspnowMeshBackend::performEspnowMaintenance();
|
||||
|
||||
if (millis() - timeOfLastScan > 10000) { // Give other nodes some time to connect between data transfers.
|
||||
Serial.println("\nPerforming unencrypted ESP-NOW transmissions.");
|
||||
Serial.println(F("\nPerforming unencrypted ESP-NOW transmissions."));
|
||||
|
||||
uint32_t startTime = millis();
|
||||
espnowNode.attemptTransmission(espnowNode.getMessage());
|
||||
Serial.println("Scan and " + String(espnowNode.latestTransmissionOutcomes().size()) + " transmissions done in " + String(millis() - startTime) + " ms.");
|
||||
Serial.println(String(F("Scan and ")) + String(espnowNode.latestTransmissionOutcomes().size()) + F(" transmissions done in ") + String(millis() - startTime) + F(" ms."));
|
||||
|
||||
timeOfLastScan = millis();
|
||||
|
||||
@ -328,19 +323,19 @@ void loop() {
|
||||
Serial.println(F("No mesh AP found."));
|
||||
} else {
|
||||
for (TransmissionOutcome &transmissionOutcome : espnowNode.latestTransmissionOutcomes()) {
|
||||
if (transmissionOutcome.transmissionStatus() == TS_TRANSMISSION_FAILED) {
|
||||
if (transmissionOutcome.transmissionStatus() == TransmissionStatusType::TRANSMISSION_FAILED) {
|
||||
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionOutcome.SSID());
|
||||
} else if (transmissionOutcome.transmissionStatus() == TS_CONNECTION_FAILED) {
|
||||
} else if (transmissionOutcome.transmissionStatus() == TransmissionStatusType::CONNECTION_FAILED) {
|
||||
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionOutcome.SSID());
|
||||
} else if (transmissionOutcome.transmissionStatus() == TS_TRANSMISSION_COMPLETE) {
|
||||
} else if (transmissionOutcome.transmissionStatus() == TransmissionStatusType::TRANSMISSION_COMPLETE) {
|
||||
// No need to do anything, transmission was successful.
|
||||
} else {
|
||||
Serial.println(String(F("Invalid transmission status for ")) + transmissionOutcome.SSID() + String(F("!")));
|
||||
Serial.println(String(F("Invalid transmission status for ")) + transmissionOutcome.SSID() + String('!'));
|
||||
assert(F("Invalid transmission status returned from responseHandler!") && false);
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("\nPerforming ESP-NOW broadcast.");
|
||||
Serial.println(F("\nPerforming ESP-NOW broadcast."));
|
||||
|
||||
startTime = millis();
|
||||
|
||||
@ -348,9 +343,9 @@ void loop() {
|
||||
// Note that data that comes before broadcastMetadataDelimiter should not contain any broadcastMetadataDelimiter characters,
|
||||
// otherwise the broadcastFilter function used in this example file will not work.
|
||||
String broadcastMetadata = espnowNode.getMeshName() + String(broadcastMetadataDelimiter);
|
||||
String broadcastMessage = String(F("Broadcast #")) + String(requestNumber) + String(F(" from ")) + espnowNode.getMeshName() + espnowNode.getNodeID() + String(F("."));
|
||||
String broadcastMessage = String(F("Broadcast #")) + String(requestNumber) + F(" from ") + espnowNode.getMeshName() + espnowNode.getNodeID() + String('.');
|
||||
espnowNode.broadcast(broadcastMetadata + broadcastMessage);
|
||||
Serial.println("Broadcast to all mesh nodes done in " + String(millis() - startTime) + " ms.");
|
||||
Serial.println(String(F("Broadcast to all mesh nodes done in ")) + String(millis() - startTime) + F(" ms."));
|
||||
|
||||
espnowDelay(100); // Wait for responses (broadcasts can receive an unlimited number of responses, other transmissions can only receive one response).
|
||||
|
||||
@ -358,25 +353,25 @@ void loop() {
|
||||
// You can use String::c_str() or String::begin() to retreive the data array later.
|
||||
// Note that certain String methods such as String::substring use null values to determine String length, which means they will not work as normal with multiStrings.
|
||||
uint8_t dataArray[] = {0, '\'', 0, '\'', ' ', '(', 'n', 'u', 'l', 'l', ')', ' ', 'v', 'a', 'l', 'u', 'e'};
|
||||
String espnowMessage = TypeCast::uint8ArrayToMultiString(dataArray, sizeof dataArray) + String(F(" from ")) + espnowNode.getMeshName() + espnowNode.getNodeID() + String(F("."));
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
String espnowMessage = TypeCast::uint8ArrayToMultiString(dataArray, sizeof dataArray) + F(" from ") + espnowNode.getMeshName() + espnowNode.getNodeID() + String('.');
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
espnowDelay(100); // Wait for response.
|
||||
|
||||
Serial.println("\nPerforming encrypted ESP-NOW transmissions.");
|
||||
Serial.println(F("\nPerforming encrypted ESP-NOW transmissions."));
|
||||
|
||||
uint8_t targetBSSID[6] {0};
|
||||
|
||||
// We can create encrypted connections to individual nodes so that all ESP-NOW communication with the node will be encrypted.
|
||||
if (espnowNode.constConnectionQueue()[0].getBSSID(targetBSSID) && espnowNode.requestEncryptedConnection(targetBSSID) == ECS_CONNECTION_ESTABLISHED) {
|
||||
if (espnowNode.constConnectionQueue()[0].getBSSID(targetBSSID) && espnowNode.requestEncryptedConnection(targetBSSID) == EncryptedConnectionStatus::CONNECTION_ESTABLISHED) {
|
||||
// The WiFi scan will detect the AP MAC, but this will automatically be converted to the encrypted STA MAC by the framework.
|
||||
String peerMac = TypeCast::macToString(targetBSSID);
|
||||
|
||||
Serial.println("Encrypted ESP-NOW connection with " + peerMac + " established!");
|
||||
Serial.println(String(F("Encrypted ESP-NOW connection with ")) + peerMac + F(" established!"));
|
||||
|
||||
// Making a transmission now will cause messages to targetBSSID to be encrypted.
|
||||
String espnowMessage = "This message is encrypted only when received by node " + peerMac;
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
String espnowMessage = String(F("This message is encrypted only when received by node ")) + peerMac;
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
espnowDelay(100); // Wait for response.
|
||||
|
||||
@ -389,48 +384,48 @@ void loop() {
|
||||
espnowNode.removeEncryptedConnection(targetBSSID);
|
||||
|
||||
// Note that the peer will still be encrypted, so although we can send unencrypted messages to the peer, we cannot read the encrypted responses it sends back.
|
||||
espnowMessage = "This message is no longer encrypted when received by node " + peerMac;
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
espnowMessage = String(F("This message is no longer encrypted when received by node ")) + peerMac;
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
espnowDelay(100); // Wait for response.
|
||||
Serial.println("Cannot read the encrypted response...");
|
||||
Serial.println(F("Cannot read the encrypted response..."));
|
||||
|
||||
// Let's re-add our stored connection so we can communicate properly with targetBSSID again!
|
||||
espnowNode.addEncryptedConnection(serializedEncryptedConnection);
|
||||
|
||||
espnowMessage = "This message is once again encrypted when received by node " + peerMac;
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
espnowMessage = String(F("This message is once again encrypted when received by node ")) + peerMac;
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
espnowDelay(100); // Wait for response.
|
||||
|
||||
Serial.println();
|
||||
// If we want to remove the encrypted connection on both nodes, we can do it like this.
|
||||
encrypted_connection_removal_outcome_t removalOutcome = espnowNode.requestEncryptedConnectionRemoval(targetBSSID);
|
||||
if (removalOutcome == ECRO_REMOVAL_SUCCEEDED) {
|
||||
Serial.println(peerMac + " is no longer encrypted!");
|
||||
EncryptedConnectionRemovalOutcome removalOutcome = espnowNode.requestEncryptedConnectionRemoval(targetBSSID);
|
||||
if (removalOutcome == EncryptedConnectionRemovalOutcome::REMOVAL_SUCCEEDED) {
|
||||
Serial.println(peerMac + F(" is no longer encrypted!"));
|
||||
|
||||
espnowMessage = "This message is only received by node " + peerMac + ". Transmitting in this way will not change the transmission state of the sender.";
|
||||
Serial.println("Transmitting: " + espnowMessage);
|
||||
espnowMessage = String(F("This message is only received by node ")) + peerMac + F(". Transmitting in this way will not change the transmission state of the sender.");
|
||||
Serial.println(String(F("Transmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, EspnowNetworkInfo(targetBSSID));
|
||||
espnowDelay(100); // Wait for response.
|
||||
|
||||
Serial.println();
|
||||
|
||||
// Of course, we can also just create a temporary encrypted connection that will remove itself once its duration has passed.
|
||||
if (espnowNode.requestTemporaryEncryptedConnection(targetBSSID, 1000) == ECS_CONNECTION_ESTABLISHED) {
|
||||
if (espnowNode.requestTemporaryEncryptedConnection(targetBSSID, 1000) == EncryptedConnectionStatus::CONNECTION_ESTABLISHED) {
|
||||
espnowDelay(42);
|
||||
uint32_t remainingDuration = 0;
|
||||
EspnowMeshBackend::getConnectionInfo(targetBSSID, &remainingDuration);
|
||||
|
||||
espnowMessage = "Messages this node sends to " + peerMac + " will be encrypted for " + String(remainingDuration) + " ms more.";
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
espnowMessage = String(F("Messages this node sends to ")) + peerMac + F(" will be encrypted for ") + String(remainingDuration) + F(" ms more.");
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
|
||||
EspnowMeshBackend::getConnectionInfo(targetBSSID, &remainingDuration);
|
||||
espnowDelay(remainingDuration + 100);
|
||||
|
||||
espnowMessage = "Due to encrypted connection expiration, this message is no longer encrypted when received by node " + peerMac;
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
espnowMessage = String(F("Due to encrypted connection expiration, this message is no longer encrypted when received by node ")) + peerMac;
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
espnowDelay(100); // Wait for response.
|
||||
}
|
||||
@ -438,24 +433,24 @@ void loop() {
|
||||
// Or if we prefer we can just let the library automatically create brief encrypted connections which are long enough to transmit an encrypted message.
|
||||
// Note that encrypted responses will not be received, unless there already was an encrypted connection established with the peer before attemptAutoEncryptingTransmission was called.
|
||||
// This can be remedied via the requestPermanentConnections argument, though it must be noted that the maximum number of encrypted connections supported at a time is 6.
|
||||
espnowMessage = "This message is always encrypted, regardless of receiver.";
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
espnowMessage = F("This message is always encrypted, regardless of receiver.");
|
||||
Serial.println(String(F("\nTransmitting: ")) + espnowMessage);
|
||||
espnowNode.attemptAutoEncryptingTransmission(espnowMessage);
|
||||
espnowDelay(100); // Wait for response.
|
||||
} else {
|
||||
Serial.println("Ooops! Encrypted connection removal failed. Status: " + String(removalOutcome));
|
||||
Serial.println(String(F("Ooops! Encrypted connection removal failed. Status: ")) + String(static_cast<int>(removalOutcome)));
|
||||
}
|
||||
|
||||
// Finally, should you ever want to stop other parties from sending unencrypted messages to the node
|
||||
// setAcceptsUnencryptedRequests(false);
|
||||
// can be used for this. It applies to both encrypted connection requests and regular transmissions.
|
||||
|
||||
Serial.println("\n##############################################################################################");
|
||||
Serial.println(F("\n##############################################################################################"));
|
||||
}
|
||||
|
||||
// Our last request was sent to all nodes found, so time to create a new request.
|
||||
espnowNode.setMessage(String(F("Hello world request #")) + String(++requestNumber) + String(F(" from "))
|
||||
+ espnowNode.getMeshName() + espnowNode.getNodeID() + String(F(".")));
|
||||
espnowNode.setMessage(String(F("Hello world request #")) + String(++requestNumber) + F(" from ")
|
||||
+ espnowNode.getMeshName() + espnowNode.getNodeID() + String('.'));
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
|
@ -5,7 +5,7 @@
|
||||
That way you will get instant confirmation of the mesh communication without checking the Serial Monitor.
|
||||
*/
|
||||
|
||||
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
|
||||
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <TypeConversionFunctions.h>
|
||||
@ -175,7 +175,7 @@ void loop() {
|
||||
floodingMeshDelay(1);
|
||||
|
||||
// If you wish to transmit only to a single node, try using one of the following methods (requires the node to be within range and know the MAC of the recipient):
|
||||
// Unencrypted: transmission_status_t floodingMesh.getEspnowMeshBackend().attemptTransmission(message, EspnowNetworkInfo(recipientMac));
|
||||
// Unencrypted: TransmissionStatusType floodingMesh.getEspnowMeshBackend().attemptTransmission(message, EspnowNetworkInfo(recipientMac));
|
||||
// Encrypted (slow): floodingMesh.getEspnowMeshBackend().attemptAutoEncryptingTransmission(message, EspnowNetworkInfo(recipientMac));
|
||||
|
||||
if (theOne) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
|
||||
#define ESP8266WIFIMESH_DISABLE_COMPATIBILITY // Excludes redundant compatibility code. TODO: Should be used for new code until the compatibility code is removed with release 3.0.0 of the Arduino core.
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <TcpIpMeshBackend.h>
|
||||
@ -25,7 +25,7 @@ unsigned int requestNumber = 0;
|
||||
unsigned int responseNumber = 0;
|
||||
|
||||
String manageRequest(const String &request, MeshBackendBase &meshInstance);
|
||||
transmission_status_t manageResponse(const String &response, MeshBackendBase &meshInstance);
|
||||
TransmissionStatusType manageResponse(const String &response, MeshBackendBase &meshInstance);
|
||||
void networkFilter(int numberOfNetworks, MeshBackendBase &meshInstance);
|
||||
|
||||
/* Create the mesh node object */
|
||||
@ -68,8 +68,8 @@ String manageRequest(const String &request, MeshBackendBase &meshInstance) {
|
||||
@param meshInstance The MeshBackendBase instance that called the function.
|
||||
@return The status code resulting from the response, as an int
|
||||
*/
|
||||
transmission_status_t manageResponse(const String &response, MeshBackendBase &meshInstance) {
|
||||
transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE;
|
||||
TransmissionStatusType manageResponse(const String &response, MeshBackendBase &meshInstance) {
|
||||
TransmissionStatusType statusCode = TransmissionStatusType::TRANSMISSION_COMPLETE;
|
||||
|
||||
// To get the actual class of the polymorphic meshInstance, do as follows (meshBackendCast replaces dynamic_cast since RTTI is disabled)
|
||||
if (EspnowMeshBackend *espnowInstance = TypeCast::meshBackendCast<EspnowMeshBackend *>(&meshInstance)) {
|
||||
@ -142,7 +142,7 @@ bool exampleTransmissionOutcomesUpdateHook(MeshBackendBase &meshInstance) {
|
||||
// The default hook only returns true and does nothing else.
|
||||
|
||||
if (TcpIpMeshBackend *tcpIpInstance = TypeCast::meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
|
||||
if (tcpIpInstance->latestTransmissionOutcomes().back().transmissionStatus() == TS_TRANSMISSION_COMPLETE) {
|
||||
if (tcpIpInstance->latestTransmissionOutcomes().back().transmissionStatus() == TransmissionStatusType::TRANSMISSION_COMPLETE) {
|
||||
// Our last request got a response, so time to create a new request.
|
||||
meshInstance.setMessage(String(F("Hello world request #")) + String(++requestNumber) + F(" from ")
|
||||
+ meshInstance.getMeshName() + meshInstance.getNodeID() + String('.'));
|
||||
@ -209,11 +209,11 @@ void loop() {
|
||||
Serial.println(F("No mesh AP found."));
|
||||
} else {
|
||||
for (TransmissionOutcome &transmissionOutcome : tcpIpNode.latestTransmissionOutcomes()) {
|
||||
if (transmissionOutcome.transmissionStatus() == TS_TRANSMISSION_FAILED) {
|
||||
if (transmissionOutcome.transmissionStatus() == TransmissionStatusType::TRANSMISSION_FAILED) {
|
||||
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionOutcome.SSID());
|
||||
} else if (transmissionOutcome.transmissionStatus() == TS_CONNECTION_FAILED) {
|
||||
} else if (transmissionOutcome.transmissionStatus() == TransmissionStatusType::CONNECTION_FAILED) {
|
||||
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionOutcome.SSID());
|
||||
} else if (transmissionOutcome.transmissionStatus() == TS_TRANSMISSION_COMPLETE) {
|
||||
} else if (transmissionOutcome.transmissionStatus() == TransmissionStatusType::TRANSMISSION_COMPLETE) {
|
||||
// No need to do anything, transmission was successful.
|
||||
} else {
|
||||
Serial.println(String(F("Invalid transmission status for ")) + transmissionOutcome.SSID() + String('!'));
|
||||
|
@ -12,7 +12,7 @@ ESP8266WiFiMesh KEYWORD3
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
transmission_status_t KEYWORD1
|
||||
TransmissionStatusType KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
|
@ -35,8 +35,6 @@ namespace
|
||||
size_t _ctMinDataLength = 0;
|
||||
size_t _ctMaxDataLength = 1024;
|
||||
|
||||
bool _warningsEnabled = true;
|
||||
|
||||
br_hkdf_context _storedHkdfContext;
|
||||
bool _hkdfContextStored = false;
|
||||
|
||||
@ -186,26 +184,44 @@ namespace
|
||||
createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength);
|
||||
return TypeCast::uint8ArrayToHexString(hmac, hmacLength);
|
||||
}
|
||||
|
||||
|
||||
// Helper function to avoid deprecated warnings.
|
||||
void *md5HashHelper(const void *data, const size_t dataLength, void *resultArray)
|
||||
{
|
||||
br_md5_context context;
|
||||
br_md5_init(&context);
|
||||
br_md5_update(&context, data, dataLength);
|
||||
br_md5_out(&context, resultArray);
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
// Helper function to avoid deprecated warnings.
|
||||
void *sha1HashHelper(const void *data, const size_t dataLength, void *resultArray)
|
||||
{
|
||||
br_sha1_context context;
|
||||
br_sha1_init(&context);
|
||||
br_sha1_update(&context, data, dataLength);
|
||||
br_sha1_out(&context, resultArray);
|
||||
return resultArray;
|
||||
}
|
||||
}
|
||||
|
||||
namespace CryptoInterface
|
||||
{
|
||||
void setCtMinDataLength(const size_t ctMinDataLength)
|
||||
{
|
||||
assert(ctMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF);
|
||||
assert(getCtMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF);
|
||||
_ctMinDataLength = ctMinDataLength;
|
||||
}
|
||||
size_t ctMinDataLength() {return _ctMinDataLength;}
|
||||
size_t getCtMinDataLength() {return _ctMinDataLength;}
|
||||
|
||||
void setCtMaxDataLength(const size_t ctMaxDataLength)
|
||||
{
|
||||
assert(ctMaxDataLength - ctMinDataLength() <= CT_MAX_DIFF);
|
||||
assert(ctMaxDataLength - getCtMinDataLength() <= CT_MAX_DIFF);
|
||||
_ctMaxDataLength = ctMaxDataLength;
|
||||
}
|
||||
size_t ctMaxDataLength() {return _ctMaxDataLength;}
|
||||
|
||||
void setWarningsEnabled(bool warningsEnabled) { _warningsEnabled = warningsEnabled; }
|
||||
bool warningsEnabled() { return _warningsEnabled; }
|
||||
size_t getCtMaxDataLength() {return _ctMaxDataLength;}
|
||||
|
||||
void setNonceGenerator(nonceGeneratorType nonceGenerator) { _nonceGenerator = nonceGenerator; }
|
||||
nonceGeneratorType getNonceGenerator() { return _nonceGenerator; }
|
||||
@ -216,22 +232,13 @@ namespace CryptoInterface
|
||||
// resultArray must have size MD5_NATURAL_LENGTH or greater
|
||||
void *md5Hash(const void *data, const size_t dataLength, void *resultArray)
|
||||
{
|
||||
if(warningsEnabled())
|
||||
Serial.println(F("\nWARNING! The MD5 hash is broken in terms of attacker resistance.\n"
|
||||
"Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.\n"
|
||||
"Use CryptoInterface::setWarningsEnabled(false) to turn off this warning.\n"));
|
||||
|
||||
br_md5_context context;
|
||||
br_md5_init(&context);
|
||||
br_md5_update(&context, data, dataLength);
|
||||
br_md5_out(&context, resultArray);
|
||||
return resultArray;
|
||||
return md5HashHelper(data, dataLength, resultArray);
|
||||
}
|
||||
|
||||
String md5Hash(const String &message)
|
||||
{
|
||||
uint8_t hash[MD5_NATURAL_LENGTH];
|
||||
md5Hash(message.c_str(), message.length(), hash);
|
||||
md5HashHelper(message.c_str(), message.length(), hash);
|
||||
return TypeCast::uint8ArrayToHexString(hash, MD5_NATURAL_LENGTH);
|
||||
}
|
||||
|
||||
@ -261,22 +268,13 @@ namespace CryptoInterface
|
||||
// resultArray must have size SHA1_NATURAL_LENGTH or greater
|
||||
void *sha1Hash(const void *data, const size_t dataLength, void *resultArray)
|
||||
{
|
||||
if(warningsEnabled())
|
||||
Serial.println(F("\nWARNING! The SHA-1 hash is broken in terms of attacker resistance.\n"
|
||||
"Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.\n"
|
||||
"Use CryptoInterface::setWarningsEnabled(false) to turn off this warning.\n"));
|
||||
|
||||
br_sha1_context context;
|
||||
br_sha1_init(&context);
|
||||
br_sha1_update(&context, data, dataLength);
|
||||
br_sha1_out(&context, resultArray);
|
||||
return resultArray;
|
||||
return sha1HashHelper(data, dataLength, resultArray);
|
||||
}
|
||||
|
||||
String sha1Hash(const String &message)
|
||||
{
|
||||
uint8_t hash[SHA1_NATURAL_LENGTH];
|
||||
sha1Hash(message.c_str(), message.length(), hash);
|
||||
sha1HashHelper(message.c_str(), message.length(), hash);
|
||||
return TypeCast::uint8ArrayToHexString(hash, SHA1_NATURAL_LENGTH);
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,8 @@ namespace CryptoInterface
|
||||
* naturally yielding constant-time operations. HMAC is naturally as constant-time as the underlying hash function. The size of the MACed data, and the size of the key,
|
||||
* may leak, though; only the contents are protected."
|
||||
*
|
||||
* For messages much smaller than ctMaxDataLength(), constant-time processing takes substantially longer time to complete than a normal HMAC,
|
||||
* determined by the size of (ctMaxDataLength() - ctMinDataLength()).
|
||||
* For messages much smaller than getCtMaxDataLength(), constant-time processing takes substantially longer time to complete than a normal HMAC,
|
||||
* determined by the size of (getCtMaxDataLength() - getCtMinDataLength()).
|
||||
* Constant-time processing also sets limits on the data length.
|
||||
*
|
||||
* Making the fixed data length limits variable will generally defeat the purpose of using constant-time.
|
||||
@ -78,34 +78,26 @@ namespace CryptoInterface
|
||||
* It should not be changed once a constant time function has been used at least once.
|
||||
* Otherwise the constant time will not be constant for the used functions.
|
||||
*
|
||||
* The difference ctMaxDataLength() - ctMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte).
|
||||
* The difference getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte).
|
||||
*/
|
||||
void setCtMinDataLength(const size_t ctMinDataLength);
|
||||
/**
|
||||
* 0 by default.
|
||||
*/
|
||||
size_t ctMinDataLength();
|
||||
size_t getCtMinDataLength();
|
||||
|
||||
/**
|
||||
* This function allows for fine-tuning of the specifications for the constant time calculations.
|
||||
* It should not be changed once a constant time function has been used at least once.
|
||||
* Otherwise the constant time will not be constant for the used functions.
|
||||
*
|
||||
* The difference ctMaxDataLength() - ctMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte).
|
||||
* The difference getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte).
|
||||
*/
|
||||
void setCtMaxDataLength(const size_t ctMaxDataLength);
|
||||
/**
|
||||
* 1024 by default.
|
||||
*/
|
||||
size_t ctMaxDataLength();
|
||||
|
||||
/**
|
||||
* Turn on or off warning Serial prints from the CryptoInterface functions.
|
||||
*
|
||||
* @param warningsEnabled If true, warnings will be printed to Serial.
|
||||
*/
|
||||
void setWarningsEnabled(bool warningsEnabled);
|
||||
bool warningsEnabled();
|
||||
size_t getCtMaxDataLength();
|
||||
|
||||
/**
|
||||
* Set the nonce generator used by the CryptoInterface functions.
|
||||
@ -119,6 +111,9 @@ namespace CryptoInterface
|
||||
// #################### MD5 ####################
|
||||
|
||||
/**
|
||||
* WARNING! The MD5 hash is broken in terms of attacker resistance.
|
||||
* Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.
|
||||
*
|
||||
* Create a MD5 hash of the data. The result will be MD5_NATURAL_LENGTH bytes long and stored in resultArray.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
@ -128,9 +123,12 @@ namespace CryptoInterface
|
||||
*
|
||||
* @return A pointer to resultArray.
|
||||
*/
|
||||
void *md5Hash(const void *data, const size_t dataLength, void *resultArray);
|
||||
void *md5Hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* WARNING! The MD5 hash is broken in terms of attacker resistance.
|
||||
* Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.
|
||||
*
|
||||
* Create a MD5 hash of the data. The result will be MD5_NATURAL_LENGTH bytes long and returned as a String in HEX format.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
@ -138,7 +136,7 @@ namespace CryptoInterface
|
||||
*
|
||||
* @return A String with the generated hash in HEX format.
|
||||
*/
|
||||
String md5Hash(const String &message);
|
||||
String md5Hash(const String &message) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* Create a MD5 HMAC from the data, using the provided hashKey. The result will be up to outputLength bytes long and stored in resultArray.
|
||||
@ -176,7 +174,7 @@ namespace CryptoInterface
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param data The data array from which to create the HMAC.
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
@ -193,7 +191,7 @@ namespace CryptoInterface
|
||||
* Constant-time version.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to MD5_NATURAL_LENGTH.
|
||||
@ -206,6 +204,9 @@ namespace CryptoInterface
|
||||
// #################### SHA-1 ####################
|
||||
|
||||
/**
|
||||
* WARNING! The SHA-1 hash is broken in terms of attacker resistance.
|
||||
* Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.
|
||||
*
|
||||
* Create a SHA1 hash of the data. The result will be SHA1_NATURAL_LENGTH bytes long and stored in resultArray.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
@ -215,9 +216,12 @@ namespace CryptoInterface
|
||||
*
|
||||
* @return A pointer to resultArray.
|
||||
*/
|
||||
void *sha1Hash(const void *data, const size_t dataLength, void *resultArray);
|
||||
void *sha1Hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* WARNING! The SHA-1 hash is broken in terms of attacker resistance.
|
||||
* Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.
|
||||
*
|
||||
* Create a SHA1 hash of the data. The result will be SHA1_NATURAL_LENGTH bytes long and returned as a String in HEX format.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
@ -225,7 +229,7 @@ namespace CryptoInterface
|
||||
*
|
||||
* @return A String with the generated hash in HEX format.
|
||||
*/
|
||||
String sha1Hash(const String &message);
|
||||
String sha1Hash(const String &message) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* Create a SHA1 HMAC from the data, using the provided hashKey. The result will be up to outputLength bytes long and stored in resultArray.
|
||||
@ -263,7 +267,7 @@ namespace CryptoInterface
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param data The data array from which to create the HMAC.
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
@ -280,7 +284,7 @@ namespace CryptoInterface
|
||||
* Constant-time version.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA1_NATURAL_LENGTH.
|
||||
@ -350,7 +354,7 @@ namespace CryptoInterface
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param data The data array from which to create the HMAC.
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
@ -367,7 +371,7 @@ namespace CryptoInterface
|
||||
* Constant-time version.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA224_NATURAL_LENGTH.
|
||||
@ -437,7 +441,7 @@ namespace CryptoInterface
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param data The data array from which to create the HMAC.
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
@ -454,7 +458,7 @@ namespace CryptoInterface
|
||||
* Constant-time version.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA256_NATURAL_LENGTH.
|
||||
@ -524,7 +528,7 @@ namespace CryptoInterface
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param data The data array from which to create the HMAC.
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
@ -541,7 +545,7 @@ namespace CryptoInterface
|
||||
* Constant-time version.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA384_NATURAL_LENGTH.
|
||||
@ -611,7 +615,7 @@ namespace CryptoInterface
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param data The data array from which to create the HMAC.
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param dataLength The length of the data array in bytes. Valid values are in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
@ -628,7 +632,7 @@ namespace CryptoInterface
|
||||
* Constant-time version.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()].
|
||||
* @param message The string from which to create the HMAC. Must have a length in the range [getCtMinDataLength(), getCtMaxDataLength()].
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA512_NATURAL_LENGTH.
|
||||
|
@ -54,7 +54,7 @@ namespace TypeCast = MeshTypeConversionFunctions;
|
||||
|
||||
const IPAddress ESP8266WiFiMesh::emptyIP = IPAddress();
|
||||
|
||||
String ESP8266WiFiMesh::lastSSID = "";
|
||||
String ESP8266WiFiMesh::lastSSID;
|
||||
bool ESP8266WiFiMesh::staticIPActivated = false;
|
||||
|
||||
// IP needs to be at the same subnet as server gateway (192.168.4 in this case). Station gateway ip must match ip for server.
|
||||
@ -88,9 +88,9 @@ ESP8266WiFiMesh::ESP8266WiFiMesh(ESP8266WiFiMesh::requestHandlerType requestHand
|
||||
|
||||
void ESP8266WiFiMesh::updateNetworkNames(const String &newMeshName, const String &newNodeID)
|
||||
{
|
||||
if(newMeshName != "")
|
||||
if(!newMeshName.isEmpty())
|
||||
_meshName = newMeshName;
|
||||
if(newNodeID != "")
|
||||
if(!newNodeID.isEmpty())
|
||||
_nodeID = newNodeID;
|
||||
|
||||
String newSSID = _meshName + _nodeID;
|
||||
@ -469,7 +469,7 @@ void ESP8266WiFiMesh::initiateConnectionToAP(const String &targetSSID, int targe
|
||||
*/
|
||||
transmission_status_t ESP8266WiFiMesh::connectToNode(const String &targetSSID, int targetChannel, uint8_t *targetBSSID)
|
||||
{
|
||||
if(staticIPActivated && lastSSID != "" && lastSSID != targetSSID) // So we only do this once per connection, in case there is a performance impact.
|
||||
if(staticIPActivated && !lastSSID.isEmpty() && lastSSID != targetSSID) // So we only do this once per connection, in case there is a performance impact.
|
||||
{
|
||||
#if LWIP_VERSION_MAJOR >= 2
|
||||
// Can be used with Arduino core for ESP8266 version 2.4.2 or higher with lwIP2 enabled to keep static IP on even during network switches.
|
||||
@ -567,12 +567,12 @@ void ESP8266WiFiMesh::attemptTransmission(const String &message, bool concluding
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
|
||||
String currentSSID = "";
|
||||
String currentSSID;
|
||||
int currentWiFiChannel = NETWORK_INFO_DEFAULT_INT;
|
||||
uint8_t *currentBSSID = NULL;
|
||||
|
||||
// If an SSID has been assigned, it is prioritized over an assigned networkIndex since the networkIndex is more likely to change.
|
||||
if(currentNetwork.SSID != "")
|
||||
if(!currentNetwork.SSID.isEmpty())
|
||||
{
|
||||
currentSSID = currentNetwork.SSID;
|
||||
currentWiFiChannel = currentNetwork.wifiChannel;
|
||||
|
@ -47,8 +47,9 @@
|
||||
#include <WiFiServer.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "NetworkInfo.h"
|
||||
#include "TransmissionResult.h"
|
||||
#include "NetworkInfo.h"
|
||||
|
||||
|
||||
const String WIFI_MESH_EMPTY_STRING = "";
|
||||
|
||||
@ -175,7 +176,7 @@ public:
|
||||
*/
|
||||
ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter,
|
||||
const String &meshPassword, const String &meshName = "MeshNode_", const String &nodeID = WIFI_MESH_EMPTY_STRING, bool verboseMode = false,
|
||||
uint8 meshWiFiChannel = 1, uint16_t serverPort = 4011);
|
||||
uint8 meshWiFiChannel = 1, uint16_t serverPort = 4011) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* A vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
|
@ -102,10 +102,8 @@ bool EncryptedConnectionData::connectedTo(const uint8_t *peerMac) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EncryptedConnectionData::setHashKey(const uint8_t hashKey[espnowHashKeyLength])
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -90,32 +90,34 @@
|
||||
#include "EspnowNetworkInfo.h"
|
||||
#include "CryptoInterface.h"
|
||||
|
||||
typedef enum
|
||||
namespace Espnow
|
||||
{
|
||||
ECT_NO_CONNECTION = 0,
|
||||
ECT_TEMPORARY_CONNECTION = 1,
|
||||
ECT_PERMANENT_CONNECTION = 2
|
||||
} espnow_connection_type_t;
|
||||
enum class ConnectionType
|
||||
{
|
||||
NO_CONNECTION = 0,
|
||||
TEMPORARY_CONNECTION = 1,
|
||||
PERMANENT_CONNECTION = 2
|
||||
};
|
||||
|
||||
// A value greater than 0 means that an encrypted connection has been established.
|
||||
typedef enum
|
||||
enum class EncryptedConnectionStatus
|
||||
{
|
||||
ECS_MAX_CONNECTIONS_REACHED_SELF = -3,
|
||||
ECS_REQUEST_TRANSMISSION_FAILED = -2,
|
||||
ECS_MAX_CONNECTIONS_REACHED_PEER = -1,
|
||||
ECS_API_CALL_FAILED = 0,
|
||||
ECS_CONNECTION_ESTABLISHED = 1,
|
||||
ECS_SOFT_LIMIT_CONNECTION_ESTABLISHED = 2 // Only used if _encryptedConnectionsSoftLimit is less than 6.
|
||||
} encrypted_connection_status_t;
|
||||
MAX_CONNECTIONS_REACHED_SELF = -3,
|
||||
REQUEST_TRANSMISSION_FAILED = -2,
|
||||
MAX_CONNECTIONS_REACHED_PEER = -1,
|
||||
API_CALL_FAILED = 0,
|
||||
CONNECTION_ESTABLISHED = 1,
|
||||
SOFT_LIMIT_CONNECTION_ESTABLISHED = 2 // Only used if _encryptedConnectionsSoftLimit is less than 6.
|
||||
};
|
||||
|
||||
typedef enum
|
||||
enum class EncryptedConnectionRemovalOutcome
|
||||
{
|
||||
ECRO_REMOVAL_REQUEST_FAILED = -1,
|
||||
ECRO_REMOVAL_FAILED = 0,
|
||||
ECRO_REMOVAL_SUCCEEDED = 1,
|
||||
ECRO_REMOVAL_SCHEDULED = 2
|
||||
} encrypted_connection_removal_outcome_t;
|
||||
|
||||
REMOVAL_REQUEST_FAILED = -1,
|
||||
REMOVAL_FAILED = 0,
|
||||
REMOVAL_SUCCEEDED = 1,
|
||||
REMOVAL_SCHEDULED = 2
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* An alternative to standard delay(). Will continuously call performEspnowMaintenance() during the waiting time, so that the ESP-NOW node remains responsive.
|
||||
@ -130,12 +132,14 @@ void espnowDelay(uint32_t durationMs);
|
||||
|
||||
class RequestData;
|
||||
|
||||
using namespace Espnow; // TODO: Remove
|
||||
|
||||
class EspnowMeshBackend : public MeshBackendBase {
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::function<bool(String &, EspnowMeshBackend &)> broadcastFilterType;
|
||||
typedef std::function<bool(const String &, const uint8_t *, uint32_t, EspnowMeshBackend &)> responseTransmittedHookType;
|
||||
using broadcastFilterType = std::function<bool(String &, EspnowMeshBackend &)>;
|
||||
using responseTransmittedHookType = std::function<bool(const String &, const uint8_t *, uint32_t, EspnowMeshBackend &)>;
|
||||
|
||||
public:
|
||||
|
||||
@ -145,7 +149,7 @@ public:
|
||||
* @param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which
|
||||
* is the request string received from another node and returns the string to send back.
|
||||
* @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which
|
||||
* is the response string received from another node. Returns a transmission status code as a transmission_status_t.
|
||||
* is the response string received from another node. Returns a transmission status code as a TransmissionStatusType.
|
||||
* @param networkFilter The callback handler for deciding which WiFi networks to connect to.
|
||||
* @param broadcastFilter The callback handler for deciding which ESP-NOW broadcasts to accept.
|
||||
* @param meshPassword The WiFi password for the mesh network.
|
||||
@ -155,7 +159,7 @@ public:
|
||||
* @param ssidSuffix The suffix (last part) of the node SSID.
|
||||
* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. This setting is shared by all EspnowMeshBackend instances.
|
||||
* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several mesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one mesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
@ -173,7 +177,7 @@ public:
|
||||
* @param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which
|
||||
* is the request string received from another node and returns the string to send back.
|
||||
* @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which
|
||||
* is the response string received from another node. Returns a transmission status code as a transmission_status_t.
|
||||
* is the response string received from another node. Returns a transmission status code as a TransmissionStatusType.
|
||||
* @param networkFilter The callback handler for deciding which WiFi networks to connect to.
|
||||
* @param broadcastFilter The callback handler for deciding which ESP-NOW broadcasts to accept.
|
||||
* @param meshPassword The WiFi password for the mesh network.
|
||||
@ -183,7 +187,7 @@ public:
|
||||
* @param ssidSuffix The suffix (last part) of the node SSID.
|
||||
* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. This setting is shared by all EspnowMeshBackend instances.
|
||||
* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several mesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one mesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
@ -222,7 +226,7 @@ public:
|
||||
static std::vector<TransmissionOutcome> & latestTransmissionOutcomes();
|
||||
|
||||
/**
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TransmissionStatusType::TRANSMISSION_COMPLETE). False otherwise.
|
||||
* The result is unique for each mesh backend.
|
||||
*/
|
||||
static bool latestTransmissionSuccessful();
|
||||
@ -285,7 +289,7 @@ public:
|
||||
*
|
||||
* @param recipientInfo The recipient information.
|
||||
*/
|
||||
transmission_status_t attemptTransmission(const String &message, const EspnowNetworkInfo &recipientInfo);
|
||||
TransmissionStatusType attemptTransmission(const String &message, const EspnowNetworkInfo &recipientInfo);
|
||||
|
||||
/*
|
||||
* Will ensure that an encrypted connection exists to each target node before sending the message,
|
||||
@ -317,7 +321,7 @@ public:
|
||||
* Transmit message to a single recipient without changing the local transmission state (apart from encrypted connections).
|
||||
* Will not change connectionQueue, latestTransmissionOutcomes or stored message.
|
||||
*/
|
||||
transmission_status_t attemptAutoEncryptingTransmission(const String &message, const EspnowNetworkInfo &recipientInfo, bool requestPermanentConnection = false);
|
||||
TransmissionStatusType attemptAutoEncryptingTransmission(const String &message, const EspnowNetworkInfo &recipientInfo, bool requestPermanentConnection = false);
|
||||
|
||||
/**
|
||||
* Send a message simultaneously to all nearby nodes which have ESP-NOW activated.
|
||||
@ -736,32 +740,32 @@ public:
|
||||
|
||||
// Updates connection with current stored encrypted connection key.
|
||||
// At least one of the leftmost 32 bits in each of the session keys should be 1, since the key otherwise indicates the connection is unencrypted.
|
||||
encrypted_connection_status_t addEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, uint64_t peerSessionKey, uint64_t ownSessionKey);
|
||||
EncryptedConnectionStatus addEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, uint64_t peerSessionKey, uint64_t ownSessionKey);
|
||||
// Note that the espnowEncryptedConnectionKey, espnowEncryptionKok, espnowHashKey and espnowMessageEncryptionKey are not serialized.
|
||||
// These will be set to the values of the EspnowMeshBackend instance that is adding the serialized encrypted connection.
|
||||
// @param ignoreDuration Ignores any stored duration serializedConnectionState, guaranteeing that the created connection will be permanent. Returns: ECS_REQUEST_TRANSMISSION_FAILED indicates malformed serializedConnectionState.
|
||||
encrypted_connection_status_t addEncryptedConnection(const String &serializedConnectionState, bool ignoreDuration = false);
|
||||
// @param ignoreDuration Ignores any stored duration serializedConnectionState, guaranteeing that the created connection will be permanent. Returns: EncryptedConnectionStatus::REQUEST_TRANSMISSION_FAILED indicates malformed serializedConnectionState.
|
||||
EncryptedConnectionStatus addEncryptedConnection(const String &serializedConnectionState, bool ignoreDuration = false);
|
||||
|
||||
// Adds a new temporary encrypted connection, or changes the duration of an existing temporary connection (only updates keys, not duration, for existing permanent connections).
|
||||
// As with all these methods, changes will only take effect once the requester proves it has the ability to decrypt the session key.
|
||||
// At least one of the leftmost 32 bits in each of the session keys should be 1, since the key otherwise indicates the connection is unencrypted.
|
||||
encrypted_connection_status_t addTemporaryEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, uint64_t peerSessionKey, uint64_t ownSessionKey, uint32_t duration);
|
||||
EncryptedConnectionStatus addTemporaryEncryptedConnection(uint8_t *peerStaMac, uint8_t *peerApMac, uint64_t peerSessionKey, uint64_t ownSessionKey, uint32_t duration);
|
||||
// Note that the espnowEncryptedConnectionKey, espnowEncryptionKok, espnowHashKey and espnowMessageEncryptionKey are not serialized.
|
||||
// These will be set to the values of the EspnowMeshBackend instance that is adding the serialized encrypted connection.
|
||||
// Uses duration argument instead of any stored duration in serializedConnectionState. Returns: ECS_REQUEST_TRANSMISSION_FAILED indicates malformed serializedConnectionState.
|
||||
encrypted_connection_status_t addTemporaryEncryptedConnection(const String &serializedConnectionState, uint32_t duration);
|
||||
// Uses duration argument instead of any stored duration in serializedConnectionState. Returns: EncryptedConnectionStatus::REQUEST_TRANSMISSION_FAILED indicates malformed serializedConnectionState.
|
||||
EncryptedConnectionStatus addTemporaryEncryptedConnection(const String &serializedConnectionState, uint32_t duration);
|
||||
|
||||
// If an encrypted connection to peerMac already exists, only connection duration is updated. All other settings are kept as is. Use removeEncryptedConnection/requestEncryptedConnectionRemoval first if encryption keys should be updated.
|
||||
// Makes sure both nodes have an encrypted connection to each other that's permanent.
|
||||
encrypted_connection_status_t requestEncryptedConnection(uint8_t *peerMac);
|
||||
EncryptedConnectionStatus requestEncryptedConnection(uint8_t *peerMac);
|
||||
// Makes sure both nodes have an encrypted connection to each other that's either permanent or has the duration specified.
|
||||
encrypted_connection_status_t requestTemporaryEncryptedConnection(uint8_t *peerMac, uint32_t durationMs);
|
||||
EncryptedConnectionStatus requestTemporaryEncryptedConnection(uint8_t *peerMac, uint32_t durationMs);
|
||||
// Makes sure both nodes have an encrypted connection to each other that's either permanent or has at least the duration specified.
|
||||
// Note that if a temporary encrypted connection already exists to a target node, this method will slightly extend the connection duration
|
||||
// depending on the time it takes to verify the connection to the node.
|
||||
encrypted_connection_status_t requestFlexibleTemporaryEncryptedConnection(uint8_t *peerMac, uint32_t minDurationMs);
|
||||
static encrypted_connection_removal_outcome_t removeEncryptedConnection(uint8_t *peerMac);
|
||||
encrypted_connection_removal_outcome_t requestEncryptedConnectionRemoval(uint8_t *peerMac);
|
||||
EncryptedConnectionStatus requestFlexibleTemporaryEncryptedConnection(uint8_t *peerMac, uint32_t minDurationMs);
|
||||
static EncryptedConnectionRemovalOutcome removeEncryptedConnection(uint8_t *peerMac);
|
||||
EncryptedConnectionRemovalOutcome requestEncryptedConnectionRemoval(uint8_t *peerMac);
|
||||
|
||||
/**
|
||||
* Set whether this EspnowMeshBackend instance will accept ESP-NOW requests from unencrypted connections or not, when acting as EspnowRequestManager.
|
||||
@ -824,24 +828,24 @@ public:
|
||||
* @param peerMac The node MAC for which to get information. Both MAC for AP interface and MAC for STA interface can be used (and will yield the same result).
|
||||
* Use the getEncryptedMac method or the indexed based getConnectionInfo if there is a need to find the actual encrypted interface.
|
||||
* @param remainingDuration An optional pointer to a uint32_t variable.
|
||||
* If supplied and the connection type is ECT_TEMPORARY_CONNECTION the variable will be set to the remaining duration of the connection.
|
||||
* If supplied and the connection type is ConnectionType::TEMPORARY_CONNECTION the variable will be set to the remaining duration of the connection.
|
||||
* Otherwise the variable value is not modified.
|
||||
* @return The espnow_connection_type_t of the connection with peerMac.
|
||||
* @return The ConnectionType of the connection with peerMac.
|
||||
*/
|
||||
static espnow_connection_type_t getConnectionInfo(uint8_t *peerMac, uint32_t *remainingDuration = nullptr);
|
||||
static ConnectionType getConnectionInfo(uint8_t *peerMac, uint32_t *remainingDuration = nullptr);
|
||||
|
||||
/**
|
||||
* Get information about any current ESP-NOW connection with another node.
|
||||
*
|
||||
* @param connectionIndex The connection index of the node for which to get information. Valid values are limited by numberOfEncryptedConnections().
|
||||
* @param remainingDuration An optional pointer to a uint32_t variable.
|
||||
* If supplied and the connection type is ECT_TEMPORARY_CONNECTION the variable will be set to the remaining duration of the connection.
|
||||
* If supplied and the connection type is ConnectionType::TEMPORARY_CONNECTION the variable will be set to the remaining duration of the connection.
|
||||
* Otherwise the variable value is not modified.
|
||||
* @param peerMac An optional pointer to an uint8_t array with at least size 6. It will be filled with the MAC of the encrypted peer interface if an encrypted connection exists.
|
||||
* Otherwise the array is not modified.
|
||||
* @return The espnow_connection_type_t of the connection given by connectionIndex.
|
||||
* @return The ConnectionType of the connection given by connectionIndex.
|
||||
*/
|
||||
static espnow_connection_type_t getConnectionInfo(uint32_t connectionIndex, uint32_t *remainingDuration = nullptr, uint8_t *peerMac = nullptr);
|
||||
static ConnectionType getConnectionInfo(uint32_t connectionIndex, uint32_t *remainingDuration = nullptr, uint8_t *peerMac = nullptr);
|
||||
|
||||
/**
|
||||
* @return The proportion of ESP-NOW requests made by this node that have failed, since power on or latest reset.
|
||||
@ -858,7 +862,7 @@ protected:
|
||||
static std::vector<EspnowNetworkInfo> _connectionQueue;
|
||||
static std::vector<TransmissionOutcome> _latestTransmissionOutcomes;
|
||||
|
||||
typedef std::vector<EncryptedConnectionLog>::iterator connectionLogIterator;
|
||||
using connectionLogIterator = std::vector<EncryptedConnectionLog>::iterator;
|
||||
static connectionLogIterator connectionLogEndIterator();
|
||||
|
||||
static const uint8_t broadcastMac[6];
|
||||
@ -866,7 +870,7 @@ protected:
|
||||
|
||||
bool activateEspnow();
|
||||
|
||||
static bool encryptedConnectionEstablished(encrypted_connection_status_t connectionStatus);
|
||||
static bool encryptedConnectionEstablished(EncryptedConnectionStatus connectionStatus);
|
||||
|
||||
/*
|
||||
* Note that ESP-NOW is not perfect and in rare cases messages may be dropped.
|
||||
@ -906,8 +910,8 @@ protected:
|
||||
// Consider using getScheduledResponseRecipient and similar methods for this preparation.
|
||||
// Should only be used when there is no transmissions in progress. In practice when _espnowTransmissionMutex is free.
|
||||
// @param resultingIterator Will be set to the iterator position after the removed element, if an element to remove was found. Otherwise no change will occur.
|
||||
static encrypted_connection_removal_outcome_t removeEncryptedConnectionUnprotected(const uint8_t *peerMac, std::vector<EncryptedConnectionLog>::iterator *resultingIterator = nullptr);
|
||||
static encrypted_connection_removal_outcome_t removeEncryptedConnectionUnprotected(connectionLogIterator &connectionIterator, std::vector<EncryptedConnectionLog>::iterator *resultingIterator);
|
||||
static EncryptedConnectionRemovalOutcome removeEncryptedConnectionUnprotected(const uint8_t *peerMac, std::vector<EncryptedConnectionLog>::iterator *resultingIterator = nullptr);
|
||||
static EncryptedConnectionRemovalOutcome removeEncryptedConnectionUnprotected(connectionLogIterator &connectionIterator, std::vector<EncryptedConnectionLog>::iterator *resultingIterator);
|
||||
|
||||
/**
|
||||
* Set the MAC address considered to be the sender of the most recently received ESP-NOW request, response or broadcast.
|
||||
@ -935,17 +939,17 @@ protected:
|
||||
/**
|
||||
* Will be true if a transmission initiated by a public method is in progress.
|
||||
*/
|
||||
static bool _espnowTransmissionMutex;
|
||||
static std::shared_ptr<bool> _espnowTransmissionMutex;
|
||||
|
||||
/**
|
||||
* Will be true when the connectionQueue should not be modified.
|
||||
*/
|
||||
static bool _espnowConnectionQueueMutex;
|
||||
static std::shared_ptr<bool> _espnowConnectionQueueMutex;
|
||||
|
||||
/**
|
||||
* Will be true when no responsesToSend element should be removed.
|
||||
*/
|
||||
static bool _responsesToSendMutex;
|
||||
static std::shared_ptr<bool> _responsesToSendMutex;
|
||||
|
||||
/**
|
||||
* Check if there is an ongoing ESP-NOW transmission in the library. Used to avoid interrupting transmissions.
|
||||
@ -955,8 +959,8 @@ protected:
|
||||
static bool transmissionInProgress();
|
||||
|
||||
enum class macAndType_td : uint64_t {};
|
||||
typedef uint64_t messageID_td;
|
||||
typedef uint64_t peerMac_td;
|
||||
using messageID_td = uint64_t;
|
||||
using peerMac_td = uint64_t;
|
||||
|
||||
static macAndType_td createMacAndTypeValue(uint64_t uint64Mac, char messageType);
|
||||
static uint64_t macAndTypeToUint64Mac(const macAndType_td &macAndTypeValue);
|
||||
@ -985,19 +989,19 @@ protected:
|
||||
* @return The transmission status for the transmission.
|
||||
*/
|
||||
// Send a message to the node having targetBSSID as mac, changing targetBSSID to the mac of the encrypted connection if it exists and ensuring such an encrypted connection is synchronized.
|
||||
static transmission_status_t espnowSendToNode(const String &message, const uint8_t *targetBSSID, char messageType, EspnowMeshBackend *espnowInstance = nullptr);
|
||||
static TransmissionStatusType espnowSendToNode(const String &message, const uint8_t *targetBSSID, char messageType, EspnowMeshBackend *espnowInstance = nullptr);
|
||||
// Send a message using exactly the arguments given, without consideration for any encrypted connections.
|
||||
static transmission_status_t espnowSendToNodeUnsynchronized(const String message, const uint8_t *targetBSSID, char messageType, uint64_t messageID, EspnowMeshBackend *espnowInstance = nullptr);
|
||||
static TransmissionStatusType espnowSendToNodeUnsynchronized(const String message, const uint8_t *targetBSSID, char messageType, uint64_t messageID, EspnowMeshBackend *espnowInstance = nullptr);
|
||||
|
||||
transmission_status_t sendRequest(const String &message, const uint8_t *targetBSSID);
|
||||
transmission_status_t sendResponse(const String &message, uint64_t requestID, const uint8_t *targetBSSID);
|
||||
TransmissionStatusType sendRequest(const String &message, const uint8_t *targetBSSID);
|
||||
TransmissionStatusType sendResponse(const String &message, uint64_t requestID, const uint8_t *targetBSSID);
|
||||
|
||||
private:
|
||||
|
||||
EspnowMeshBackend(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, broadcastFilterType broadcastFilter,
|
||||
const String &meshPassword, const String &ssidPrefix, const String &ssidSuffix, bool verboseMode, uint8 meshWiFiChannel);
|
||||
|
||||
typedef std::function<String(const String &, const ExpiringTimeTracker &)> encryptionRequestBuilderType;
|
||||
using encryptionRequestBuilderType = std::function<String(const String &, const ExpiringTimeTracker &)>;
|
||||
static String defaultEncryptionRequestBuilder(const String &requestHeader, const uint32_t durationMs, const uint8_t *hashKey, const String &requestNonce, const ExpiringTimeTracker &existingTimeTracker);
|
||||
static String flexibleEncryptionRequestBuilder(const uint32_t minDurationMs, const uint8_t *hashKey, const String &requestNonce, const ExpiringTimeTracker &existingTimeTracker);
|
||||
|
||||
@ -1055,14 +1059,14 @@ private:
|
||||
static EncryptedConnectionLog *getEncryptedConnection(const uint8_t *peerMac);
|
||||
static EncryptedConnectionLog *getTemporaryEncryptedConnection(const uint8_t *peerMac);
|
||||
|
||||
//@return iterator to connection in connectionVector, or connectionVector.end() if element not found
|
||||
//@return iterator to connection in connectionContainer, or connectionContainer.end() if element not found
|
||||
template <typename T>
|
||||
static typename std::vector<T>::iterator getEncryptedConnectionIterator(const uint8_t *peerMac, typename std::vector<T> &connectionVector);
|
||||
static typename T::iterator getEncryptedConnectionIterator(const uint8_t *peerMac, T &connectionContainer);
|
||||
static bool getEncryptedConnectionIterator(const uint8_t *peerMac, connectionLogIterator &iterator);
|
||||
// @return true if an encrypted connection to peerMac is found and the found connection is temporary. Only changes iterator if true is returned.
|
||||
static bool getTemporaryEncryptedConnectionIterator(const uint8_t *peerMac, connectionLogIterator &iterator);
|
||||
|
||||
static espnow_connection_type_t getConnectionInfoHelper(const EncryptedConnectionLog *encryptedConnection, uint32_t *remainingDuration, uint8_t *peerMac = nullptr);
|
||||
static ConnectionType getConnectionInfoHelper(const EncryptedConnectionLog *encryptedConnection, uint32_t *remainingDuration, uint8_t *peerMac = nullptr);
|
||||
|
||||
// Should only be used when there is no transmissions in progress, so it is safe to remove encrypted connections. In practice when _espnowTransmissionMutex is free.
|
||||
// @param scheduledRemovalOnly If true, only deletes encrypted connections where removalScheduled() is true. This means only connections which have been requested for removal will be deleted,
|
||||
@ -1072,6 +1076,9 @@ private:
|
||||
template <typename T, typename U>
|
||||
static void deleteExpiredLogEntries(std::map<std::pair<U, uint64_t>, T> &logEntries, uint32_t maxEntryLifetimeMs);
|
||||
|
||||
template <typename U>
|
||||
static void deleteExpiredLogEntries(std::map<std::pair<U, uint64_t>, TimeTracker> &logEntries, uint32_t maxEntryLifetimeMs);
|
||||
|
||||
static void deleteExpiredLogEntries(std::map<std::pair<peerMac_td, messageID_td>, RequestData> &logEntries, uint32_t requestLifetimeMs, uint32_t broadcastLifetimeMs);
|
||||
|
||||
template <typename T>
|
||||
@ -1082,7 +1089,6 @@ private:
|
||||
|
||||
static uint32_t _encryptionRequestTimeoutMs;
|
||||
|
||||
static uint32_t _timeOfLastLogClear;
|
||||
static uint32_t _criticalHeapLevel;
|
||||
static uint32_t _criticalHeapLevelBuffer;
|
||||
|
||||
@ -1096,8 +1102,7 @@ private:
|
||||
static String _ongoingPeerRequestNonce;
|
||||
static uint8_t _ongoingPeerRequestMac[6];
|
||||
static EspnowMeshBackend *_ongoingPeerRequester;
|
||||
static encrypted_connection_status_t _ongoingPeerRequestResult;
|
||||
static uint32_t _ongoingPeerRequestEncryptionStart;
|
||||
static EncryptedConnectionStatus _ongoingPeerRequestResult;
|
||||
static bool _reciprocalPeerRequestConfirmation;
|
||||
|
||||
template <typename T>
|
||||
@ -1119,7 +1124,7 @@ private:
|
||||
uint8_t _senderAPMac[6] = {0};
|
||||
bool _receivedEncryptedTransmission = false;
|
||||
|
||||
static bool _espnowSendToNodeMutex;
|
||||
static std::shared_ptr<bool> _espnowSendToNodeMutex;
|
||||
static uint8_t _transmissionTargetBSSID[6];
|
||||
|
||||
static void storeSentRequest(const uint64_t targetBSSID, const uint64_t messageID, const RequestData &requestData);
|
||||
@ -1148,9 +1153,9 @@ private:
|
||||
* @param encryptionRequestBuilder A function which is responsible for constructing the request message to send.
|
||||
* Called twice when the request is successful. First to build the initial request message and then to build the connection verification message.
|
||||
* The request message should typically be of the form: JsonTranslator::createEncryptionRequestIntro() + JsonTranslator::createEncryptionRequestEnding().
|
||||
* @return The ultimate status of the requested encrypted connection, as encrypted_connection_status_t.
|
||||
* @return The ultimate status of the requested encrypted connection, as EncryptedConnectionStatus.
|
||||
*/
|
||||
encrypted_connection_status_t requestEncryptedConnectionKernel(uint8_t *peerMac, const encryptionRequestBuilderType &encryptionRequestBuilder);
|
||||
EncryptedConnectionStatus requestEncryptedConnectionKernel(uint8_t *peerMac, const encryptionRequestBuilderType &encryptionRequestBuilder);
|
||||
|
||||
/**
|
||||
* Generate a new message ID to be used when making a data transmission. The generated ID will be different depending on whether an encrypted connection exists or not.
|
||||
@ -1170,12 +1175,12 @@ private:
|
||||
static uint64_t createSessionKey();
|
||||
|
||||
void prepareForTransmission(const String &message, bool scan, bool scanAllWiFiChannels);
|
||||
transmission_status_t initiateTransmission(const String &message, const EspnowNetworkInfo &recipientInfo);
|
||||
transmission_status_t initiateTransmissionKernel(const String &message, const uint8_t *targetBSSID);
|
||||
TransmissionStatusType initiateTransmission(const String &message, const EspnowNetworkInfo &recipientInfo);
|
||||
TransmissionStatusType initiateTransmissionKernel(const String &message, const uint8_t *targetBSSID);
|
||||
void printTransmissionStatistics();
|
||||
|
||||
encrypted_connection_status_t initiateAutoEncryptingConnection(const EspnowNetworkInfo &recipientInfo, bool requestPermanentConnection, uint8_t *targetBSSID, EncryptedConnectionLog **existingEncryptedConnection);
|
||||
transmission_status_t initiateAutoEncryptingTransmission(const String &message, const uint8_t *targetBSSID, encrypted_connection_status_t connectionStatus);
|
||||
EncryptedConnectionStatus initiateAutoEncryptingConnection(const EspnowNetworkInfo &recipientInfo, bool requestPermanentConnection, uint8_t *targetBSSID, EncryptedConnectionLog **existingEncryptedConnection);
|
||||
TransmissionStatusType initiateAutoEncryptingTransmission(const String &message, const uint8_t *targetBSSID, EncryptedConnectionStatus connectionStatus);
|
||||
void finalizeAutoEncryptingConnection(const uint8_t *targetBSSID, const EncryptedConnectionLog *existingEncryptedConnection, bool requestPermanentConnection);
|
||||
|
||||
// Used for verboseMode printing in attemptTransmission, _AT suffix used to reduce namespace clutter
|
||||
|
@ -45,7 +45,7 @@ namespace EspnowProtocolInterpreter
|
||||
constexpr char basicConnectionInfoHeader[] PROGMEM = "BasicCI:"; // Basic connection info
|
||||
constexpr char encryptedConnectionInfoHeader[] PROGMEM = "EncryptedCI:"; // Encrypted connection info
|
||||
constexpr char softLimitEncryptedConnectionInfoHeader[] PROGMEM = "SLEncryptedCI:"; // Soft limit encrypted connection info
|
||||
constexpr char maxConnectionsReachedHeader[] PROGMEM = "ECS_MAX_CONNECTIONS_REACHED_PEER:";
|
||||
constexpr char maxConnectionsReachedHeader[] PROGMEM = "MAX_CONNECTIONS_REACHED_PEER:";
|
||||
constexpr char encryptedConnectionVerificationHeader[] PROGMEM = "ECVerified:"; // Encrypted connection verified
|
||||
constexpr char encryptedConnectionRemovalRequestHeader[] PROGMEM = "RemoveEC:"; // Remove encrypted connection
|
||||
|
||||
|
@ -24,36 +24,101 @@
|
||||
|
||||
#include "ExpiringTimeTracker.h"
|
||||
|
||||
ExpiringTimeTracker::ExpiringTimeTracker(uint32_t duration, uint32_t creationTimeMs) :
|
||||
TimeTracker(creationTimeMs), _duration(duration)
|
||||
{ }
|
||||
ExpiringTimeTracker::ExpiringTimeTracker(const uint32_t duration, const uint32_t creationTimeMs) :
|
||||
timeoutTemplate(0)
|
||||
{
|
||||
setDuration(duration);
|
||||
_start = creationTimeMs;
|
||||
}
|
||||
|
||||
ExpiringTimeTracker::ExpiringTimeTracker(const calculatorType durationCalculator, const uint32_t creationTimeMs) :
|
||||
timeoutTemplate(0)
|
||||
{
|
||||
setDuration(durationCalculator);
|
||||
_start = creationTimeMs;
|
||||
}
|
||||
|
||||
uint32_t ExpiringTimeTracker::duration() const
|
||||
{
|
||||
return _duration;
|
||||
if(useCalculator)
|
||||
return _durationCalculator();
|
||||
|
||||
return getTimeout();
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::setRemainingDuration(uint32_t remainingDuration)
|
||||
IRAM_ATTR // called from ISR
|
||||
void ExpiringTimeTracker::setTimeout(const uint32_t newUserTimeout)
|
||||
{
|
||||
_duration = timeSinceCreation() + remainingDuration;
|
||||
_timeout = newUserTimeout;
|
||||
_neverExpires = (newUserTimeout > timeMax()); // newUserTimeout < 0 is always false for uint32_t
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::setDuration(const uint32_t duration)
|
||||
{
|
||||
setTimeout(duration);
|
||||
useCalculator = false;
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::setDuration(const calculatorType durationCalculator)
|
||||
{
|
||||
_durationCalculator = durationCalculator;
|
||||
useCalculator = true;
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::setRemainingDuration(const uint32_t remainingDuration)
|
||||
{
|
||||
setDuration(elapsedTime() + remainingDuration);
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::setRemainingDuration(const calculatorType remainingDurationCalculator)
|
||||
{
|
||||
uint32_t currentElapsedTime = elapsedTime();
|
||||
setDuration([remainingDurationCalculator, currentElapsedTime](){ return currentElapsedTime + remainingDurationCalculator(); });
|
||||
}
|
||||
|
||||
uint32_t ExpiringTimeTracker::remainingDuration() const
|
||||
{
|
||||
uint32_t remainingDuration = duration() - timeSinceCreation();
|
||||
uint32_t remainingDuration = 0;
|
||||
|
||||
if(expired())
|
||||
if(!expired()) // If expired, overflow will probably occur for remainingDuration calculation.
|
||||
{
|
||||
// Overflow probably occured for remainingDuration calculation.
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return remainingDuration;
|
||||
remainingDuration = duration() - elapsedTime();
|
||||
}
|
||||
|
||||
return remainingDuration;
|
||||
}
|
||||
|
||||
uint32_t ExpiringTimeTracker::elapsedTime() const
|
||||
{
|
||||
return millis() - _start;
|
||||
}
|
||||
|
||||
bool ExpiringTimeTracker::expired() const
|
||||
{
|
||||
return timeSinceCreation() >= duration();
|
||||
if(useCalculator)
|
||||
return elapsedTime() >= duration();
|
||||
|
||||
return expiredOneShot();
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::reset()
|
||||
{
|
||||
timeoutTemplate::reset();
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::reset(const uint32_t newDuration)
|
||||
{
|
||||
setDuration(newDuration);
|
||||
ExpiringTimeTracker::reset();
|
||||
}
|
||||
|
||||
void ExpiringTimeTracker::reset(const calculatorType newDurationCalculator)
|
||||
{
|
||||
setDuration(newDurationCalculator);
|
||||
ExpiringTimeTracker::reset();
|
||||
}
|
||||
|
||||
ExpiringTimeTracker::operator bool() const
|
||||
{
|
||||
return ExpiringTimeTracker::expired();
|
||||
}
|
||||
|
@ -25,24 +25,54 @@
|
||||
#ifndef __EXPIRINGTIMETRACKER_H__
|
||||
#define __EXPIRINGTIMETRACKER_H__
|
||||
|
||||
#include "TimeTracker.h"
|
||||
#include <Arduino.h>
|
||||
#include <PolledTimeout.h>
|
||||
|
||||
class ExpiringTimeTracker : public TimeTracker {
|
||||
class ExpiringTimeTracker : private esp8266::polledTimeout::oneShotMs {
|
||||
|
||||
public:
|
||||
|
||||
~ExpiringTimeTracker() override = default;
|
||||
using calculatorType = std::function<uint32_t()>;
|
||||
|
||||
virtual ~ExpiringTimeTracker() = default;
|
||||
|
||||
ExpiringTimeTracker(const uint32_t duration, const uint32_t creationTimeMs = millis());
|
||||
ExpiringTimeTracker(const calculatorType durationCalculator, const uint32_t creationTimeMs = millis());
|
||||
|
||||
ExpiringTimeTracker(uint32_t duration, uint32_t creationTimeMs = millis());
|
||||
uint32_t duration() const;
|
||||
void setRemainingDuration(uint32_t remainingDuration);
|
||||
void setDuration(const uint32_t duration);
|
||||
void setDuration(const calculatorType durationCalculator);
|
||||
|
||||
uint32_t remainingDuration() const;
|
||||
|
||||
/**
|
||||
* Sets a new duration which includes the current elapsedTime(). This means elapsedTime() is not reset.
|
||||
* Note that reset() will use this new duration, including the saved elapsedTime().
|
||||
*/
|
||||
void setRemainingDuration(const uint32_t remainingDuration);
|
||||
|
||||
/**
|
||||
* Sets a new duration which includes the current elapsedTime(). This means elapsedTime() is not reset.
|
||||
* Note that reset() will use this new duration, including the saved elapsedTime().
|
||||
*/
|
||||
void setRemainingDuration(const calculatorType remainingDurationCalculator);
|
||||
|
||||
/**
|
||||
* Get the time since the ExpiringTimeTracker instance creation or the last reset(), whichever is more recent.
|
||||
*/
|
||||
uint32_t elapsedTime() const;
|
||||
bool expired() const;
|
||||
void reset();
|
||||
void reset(const uint32_t newDuration);
|
||||
void reset(const calculatorType newDurationCalculator);
|
||||
explicit operator bool() const;
|
||||
|
||||
private:
|
||||
|
||||
uint32_t _duration;
|
||||
bool useCalculator = false;
|
||||
calculatorType _durationCalculator;
|
||||
|
||||
void setTimeout(const uint32_t newUserTimeout);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -40,13 +40,16 @@ char FloodingMesh::_metadataDelimiter = 23;
|
||||
|
||||
void floodingMeshDelay(uint32_t durationMs)
|
||||
{
|
||||
uint32_t startingTime = millis();
|
||||
ExpiringTimeTracker timeout(durationMs);
|
||||
|
||||
while(millis() - startingTime < durationMs)
|
||||
do
|
||||
{
|
||||
// We want to delay before performMeshMaintenance() 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);
|
||||
FloodingMesh::performMeshMaintenance();
|
||||
}
|
||||
while(!timeout);
|
||||
}
|
||||
|
||||
FloodingMesh::FloodingMesh(messageHandlerType messageHandler, const String &meshPassword, const uint8_t espnowEncryptedConnectionKey[EspnowProtocolInterpreter::espnowEncryptedConnectionKeyLength],
|
||||
@ -428,9 +431,9 @@ String FloodingMesh::_defaultRequestHandler(const String &request, MeshBackendBa
|
||||
* @param meshInstance The MeshBackendBase instance that called the function.
|
||||
* @return The status code resulting from the response, as an int
|
||||
*/
|
||||
transmission_status_t FloodingMesh::_defaultResponseHandler(const String &response, MeshBackendBase &meshInstance)
|
||||
TransmissionStatusType FloodingMesh::_defaultResponseHandler(const String &response, MeshBackendBase &meshInstance)
|
||||
{
|
||||
transmission_status_t statusCode = TS_TRANSMISSION_COMPLETE;
|
||||
TransmissionStatusType statusCode = TransmissionStatusType::TRANSMISSION_COMPLETE;
|
||||
|
||||
getEspnowMeshBackend().warningPrint(String(F("WARNING! Response to FloodingMesh broadcast received, but none is expected!")));
|
||||
|
||||
@ -503,26 +506,22 @@ bool FloodingMesh::_defaultBroadcastFilter(String &firstTransmission, EspnowMesh
|
||||
{
|
||||
return false; // Broadcast is for another mesh network
|
||||
}
|
||||
else
|
||||
|
||||
int32_t messageIDEndIndex = firstTransmission.indexOf(metadataDelimiter(), metadataEndIndex + 1);
|
||||
|
||||
if(messageIDEndIndex == -1)
|
||||
return false; // metadataDelimiter not found
|
||||
|
||||
uint64_t messageID = TypeCast::stringToUint64(firstTransmission.substring(metadataEndIndex + 1, messageIDEndIndex));
|
||||
|
||||
if(insertPreliminaryMessageID(messageID))
|
||||
{
|
||||
int32_t messageIDEndIndex = firstTransmission.indexOf(metadataDelimiter(), metadataEndIndex + 1);
|
||||
|
||||
if(messageIDEndIndex == -1)
|
||||
return false; // metadataDelimiter not found
|
||||
|
||||
uint64_t messageID = TypeCast::stringToUint64(firstTransmission.substring(metadataEndIndex + 1, messageIDEndIndex));
|
||||
|
||||
if(insertPreliminaryMessageID(messageID))
|
||||
{
|
||||
// Add broadcast identifier to stored message and mark as accepted broadcast.
|
||||
firstTransmission = String(metadataDelimiter()) + firstTransmission;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // Broadcast has already been received the maximum number of times
|
||||
}
|
||||
// Add broadcast identifier to stored message and mark as accepted broadcast.
|
||||
firstTransmission = String(metadataDelimiter()) + firstTransmission;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Broadcast has already been received the maximum number of times
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include "EspnowMeshBackend.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
/**
|
||||
@ -45,8 +44,8 @@ class FloodingMesh {
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::function<bool(String &, FloodingMesh &)> messageHandlerType;
|
||||
typedef std::unordered_map<uint64_t, uint8_t>::iterator messageQueueElementType;
|
||||
using messageHandlerType = std::function<bool(String &, FloodingMesh &)>;
|
||||
using messageQueueElementType = std::map<uint64_t, uint8_t>::iterator;
|
||||
|
||||
public:
|
||||
|
||||
@ -61,7 +60,7 @@ public:
|
||||
* @param ssidSuffix The suffix (last part) of the node SSID.
|
||||
* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. This setting is shared by all EspnowMeshBackend instances.
|
||||
* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several mesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one mesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
@ -83,7 +82,7 @@ public:
|
||||
* @param ssidSuffix The suffix (last part) of the node SSID.
|
||||
* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. This setting is shared by all EspnowMeshBackend instances.
|
||||
* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several mesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one mesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
@ -321,14 +320,14 @@ private:
|
||||
|
||||
uint8_t _originMac[6] = {0};
|
||||
|
||||
std::unordered_map<uint64_t, uint8_t> _messageIDs = {};
|
||||
std::map<uint64_t, uint8_t> _messageIDs = {};
|
||||
std::queue<messageQueueElementType> _messageIdOrder = {};
|
||||
std::list<std::pair<String, bool>> _forwardingBacklog = {};
|
||||
|
||||
String _macIgnoreList;
|
||||
|
||||
String _defaultRequestHandler(const String &request, MeshBackendBase &meshInstance);
|
||||
transmission_status_t _defaultResponseHandler(const String &response, MeshBackendBase &meshInstance);
|
||||
TransmissionStatusType _defaultResponseHandler(const String &response, MeshBackendBase &meshInstance);
|
||||
void _defaultNetworkFilter(int numberOfNetworks, MeshBackendBase &meshInstance);
|
||||
bool _defaultBroadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance);
|
||||
bool _defaultTransmissionOutcomesUpdateHook(MeshBackendBase &meshInstance);
|
||||
|
63
libraries/ESP8266WiFiMesh/src/HeapMonitor.cpp
Normal file
63
libraries/ESP8266WiFiMesh/src/HeapMonitor.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "HeapMonitor.h"
|
||||
|
||||
HeapMonitor::HeapMonitor(const uint32_t criticalHeapLevel, const uint32_t criticalHeapLevelBuffer) :
|
||||
_criticalHeapLevel(criticalHeapLevel), _criticalHeapLevelBuffer(criticalHeapLevelBuffer)
|
||||
{ }
|
||||
|
||||
void HeapMonitor::setCriticalHeapLevel(const uint32_t freeHeapInBytes)
|
||||
{
|
||||
_criticalHeapLevel = freeHeapInBytes;
|
||||
}
|
||||
|
||||
uint32_t HeapMonitor::getCriticalHeapLevel() const
|
||||
{
|
||||
return _criticalHeapLevel;
|
||||
}
|
||||
|
||||
void HeapMonitor::setCriticalHeapLevelBuffer(const uint32_t bufferInBytes)
|
||||
{
|
||||
_criticalHeapLevelBuffer = bufferInBytes;
|
||||
}
|
||||
|
||||
uint32_t HeapMonitor::getCriticalHeapLevelBuffer() const
|
||||
{
|
||||
return _criticalHeapLevelBuffer;
|
||||
}
|
||||
|
||||
HeapMonitor::HeapStatus HeapMonitor::getHeapStatus() const
|
||||
{
|
||||
HeapStatus heapStatus = HeapStatus::NOMINAL;
|
||||
|
||||
uint32_t freeHeap = ESP.getFreeHeap();
|
||||
|
||||
if(freeHeap <= getCriticalHeapLevel())
|
||||
heapStatus = HeapStatus::CRITICAL;
|
||||
else if(freeHeap <= getCriticalHeapLevel() + getCriticalHeapLevelBuffer())
|
||||
heapStatus = HeapStatus::LIMITED;
|
||||
|
||||
return heapStatus;
|
||||
}
|
66
libraries/ESP8266WiFiMesh/src/HeapMonitor.h
Normal file
66
libraries/ESP8266WiFiMesh/src/HeapMonitor.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __ESPHEAPMONITOR_H__
|
||||
#define __ESPHEAPMONITOR_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class HeapMonitor {
|
||||
|
||||
public:
|
||||
|
||||
enum class HeapStatus
|
||||
{
|
||||
NOMINAL = 0,
|
||||
LIMITED = 1,
|
||||
CRITICAL = 2
|
||||
};
|
||||
|
||||
HeapMonitor(const uint32_t criticalHeapLevel, const uint32_t criticalHeapLevelBuffer);
|
||||
|
||||
virtual ~HeapMonitor() = default;
|
||||
|
||||
/**
|
||||
* Set the maximum free heap level in bytes within which free heap size is considered critical.
|
||||
*/
|
||||
void setCriticalHeapLevel(const uint32_t freeHeapInBytes);
|
||||
uint32_t getCriticalHeapLevel() const;
|
||||
|
||||
/**
|
||||
* Set the buffer of the critical heap level, within which free heap size is considered limited.
|
||||
*/
|
||||
void setCriticalHeapLevelBuffer(const uint32_t bufferInBytes);
|
||||
uint32_t getCriticalHeapLevelBuffer() const;
|
||||
|
||||
HeapStatus getHeapStatus() const;
|
||||
|
||||
private:
|
||||
|
||||
uint32_t _criticalHeapLevel;
|
||||
uint32_t _criticalHeapLevelBuffer;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -26,11 +26,11 @@ namespace TypeCast = MeshTypeConversionFunctions;
|
||||
|
||||
MeshBackendBase *MeshBackendBase::apController = nullptr;
|
||||
|
||||
bool MeshBackendBase::_scanMutex = false;
|
||||
std::shared_ptr<bool> MeshBackendBase::_scanMutex = std::make_shared<bool>(false);
|
||||
|
||||
bool MeshBackendBase::_printWarnings = true;
|
||||
|
||||
MeshBackendBase::MeshBackendBase(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, mesh_backend_t classType)
|
||||
MeshBackendBase::MeshBackendBase(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, MeshBackendType classType)
|
||||
{
|
||||
setRequestHandler(requestHandler);
|
||||
setResponseHandler(responseHandler);
|
||||
@ -43,12 +43,12 @@ MeshBackendBase::~MeshBackendBase()
|
||||
deactivateControlledAP();
|
||||
}
|
||||
|
||||
void MeshBackendBase::setClassType(mesh_backend_t classType)
|
||||
void MeshBackendBase::setClassType(MeshBackendType classType)
|
||||
{
|
||||
_classType = classType;
|
||||
}
|
||||
|
||||
mesh_backend_t MeshBackendBase::getClassType() {return _classType;}
|
||||
MeshBackendType MeshBackendBase::getClassType() {return _classType;}
|
||||
|
||||
void MeshBackendBase::activateAP()
|
||||
{
|
||||
@ -115,7 +115,9 @@ bool MeshBackendBase::isAPController()
|
||||
|
||||
void MeshBackendBase::setWiFiChannel(uint8 newWiFiChannel)
|
||||
{
|
||||
assert(1 <= newWiFiChannel && newWiFiChannel <= 13);
|
||||
wifi_country_t wifiCountry;
|
||||
wifi_get_country(&wifiCountry); // Note: Should return 0 on success and -1 on failure, but always seems to return 1. Possibly broken API. Channels 1 to 13 are the default limits.
|
||||
assert(wifiCountry.schan <= newWiFiChannel && newWiFiChannel <= wifiCountry.schan + wifiCountry.nchan - 1);
|
||||
|
||||
_meshWiFiChannel = newWiFiChannel;
|
||||
|
||||
@ -248,10 +250,10 @@ bool MeshBackendBase::latestTransmissionSuccessfulBase(const std::vector<Transmi
|
||||
{
|
||||
if(latestTransmissionOutcomes.empty())
|
||||
return false;
|
||||
else
|
||||
for(const TransmissionOutcome &transmissionOutcome : latestTransmissionOutcomes)
|
||||
if(transmissionOutcome.transmissionStatus() != TS_TRANSMISSION_COMPLETE)
|
||||
return false;
|
||||
|
||||
for(const TransmissionOutcome &transmissionOutcome : latestTransmissionOutcomes)
|
||||
if(transmissionOutcome.transmissionStatus() != TransmissionStatusType::TRANSMISSION_COMPLETE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -23,24 +23,24 @@
|
||||
#include "TransmissionOutcome.h"
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
typedef enum
|
||||
enum class MeshBackendType
|
||||
{
|
||||
MB_TCP_IP = 0,
|
||||
MB_ESP_NOW = 1
|
||||
} mesh_backend_t;
|
||||
TCP_IP = 0,
|
||||
ESP_NOW = 1
|
||||
};
|
||||
|
||||
class MeshBackendBase {
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::function<String(const String &, MeshBackendBase &)> requestHandlerType;
|
||||
typedef std::function<transmission_status_t(const String &, MeshBackendBase &)> responseHandlerType;
|
||||
typedef std::function<void(int, MeshBackendBase &)> networkFilterType;
|
||||
typedef std::function<bool(MeshBackendBase &)> transmissionOutcomesUpdateHookType;
|
||||
using requestHandlerType = std::function<String(const String &, MeshBackendBase &)> ;
|
||||
using responseHandlerType = std::function<TransmissionStatusType(const String &, MeshBackendBase &)>;
|
||||
using networkFilterType = std::function<void(int, MeshBackendBase &)>;
|
||||
using transmissionOutcomesUpdateHookType = std::function<bool(MeshBackendBase &)>;
|
||||
|
||||
public:
|
||||
|
||||
MeshBackendBase(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, mesh_backend_t classType);
|
||||
MeshBackendBase(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter, MeshBackendType classType);
|
||||
|
||||
virtual ~MeshBackendBase();
|
||||
|
||||
@ -109,13 +109,13 @@ public:
|
||||
* Will also change the WiFi channel for the active AP (via an AP restart)
|
||||
* if this MeshBackendBase instance is the current AP controller and it is possible to change channel.
|
||||
*
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several MeshBackendBase instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one MeshBackendBase instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
* make it impossible for other stations to detect the APs whose WiFi channels have changed.
|
||||
*
|
||||
* @param newWiFiChannel The WiFi channel to change to. Valid values are integers from 1 to 13.
|
||||
* @param newWiFiChannel The WiFi channel to change to. Valid values are determined by wifi_get_country, usually integers from 1 to 11 or 1 to 13.
|
||||
*
|
||||
*/
|
||||
void setWiFiChannel(uint8 newWiFiChannel);
|
||||
@ -284,14 +284,14 @@ public:
|
||||
*/
|
||||
static void warningPrint(const String &stringToPrint, bool newline = true);
|
||||
|
||||
mesh_backend_t getClassType();
|
||||
MeshBackendType getClassType();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @param latestTransmissionOutcomes The transmission outcomes vector to check.
|
||||
*
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TransmissionStatusType::TRANSMISSION_COMPLETE). False otherwise.
|
||||
*/
|
||||
static bool latestTransmissionSuccessfulBase(const std::vector<TransmissionOutcome> &latestTransmissionOutcomes);
|
||||
|
||||
@ -310,13 +310,13 @@ protected:
|
||||
*/
|
||||
virtual void deactivateAPHook();
|
||||
|
||||
void setClassType(mesh_backend_t classType);
|
||||
void setClassType(MeshBackendType classType);
|
||||
|
||||
static bool _scanMutex;
|
||||
static std::shared_ptr<bool> _scanMutex;
|
||||
|
||||
private:
|
||||
|
||||
mesh_backend_t _classType;
|
||||
MeshBackendType _classType;
|
||||
|
||||
static MeshBackendBase *apController;
|
||||
|
||||
|
@ -28,15 +28,15 @@
|
||||
#include <assert.h>
|
||||
|
||||
MessageData::MessageData(String &message, uint8_t transmissionsRemaining, uint32_t creationTimeMs) :
|
||||
TimeTracker(creationTimeMs)
|
||||
_timeTracker(creationTimeMs)
|
||||
{
|
||||
_transmissionsExpected = transmissionsRemaining + 1;
|
||||
_totalMessage += message;
|
||||
_transmissionsReceived++;
|
||||
++_transmissionsReceived;
|
||||
}
|
||||
|
||||
MessageData::MessageData(uint8_t *initialTransmission, uint8_t transmissionLength, uint32_t creationTimeMs) :
|
||||
TimeTracker(creationTimeMs)
|
||||
_timeTracker(creationTimeMs)
|
||||
{
|
||||
_transmissionsExpected = EspnowProtocolInterpreter::espnowGetTransmissionsRemaining(initialTransmission) + 1;
|
||||
addToMessage(initialTransmission, transmissionLength);
|
||||
@ -49,7 +49,7 @@ bool MessageData::addToMessage(uint8_t *transmission, uint8_t transmissionLength
|
||||
String message = EspnowProtocolInterpreter::espnowGetMessageContent(transmission, transmissionLength);
|
||||
assert(message.length() <= EspnowMeshBackend::getMaxMessageBytesPerTransmission()); // Should catch some cases where transmission is not null terminated.
|
||||
_totalMessage += message;
|
||||
_transmissionsReceived++;
|
||||
++_transmissionsReceived;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -75,3 +75,5 @@ String MessageData::getTotalMessage()
|
||||
{
|
||||
return _totalMessage;
|
||||
}
|
||||
|
||||
const TimeTracker &MessageData::getTimeTracker() const { return _timeTracker; }
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "TimeTracker.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
class MessageData : public TimeTracker {
|
||||
class MessageData {
|
||||
|
||||
public:
|
||||
|
||||
@ -43,9 +43,11 @@ public:
|
||||
uint8_t getTransmissionsExpected();
|
||||
uint8_t getTransmissionsRemaining();
|
||||
String getTotalMessage();
|
||||
const TimeTracker &getTimeTracker() const;
|
||||
|
||||
private:
|
||||
|
||||
TimeTracker _timeTracker;
|
||||
uint8_t _transmissionsReceived = 0;
|
||||
uint8_t _transmissionsExpected;
|
||||
String _totalMessage;
|
||||
|
@ -24,19 +24,19 @@
|
||||
|
||||
#include "MutexTracker.h"
|
||||
|
||||
bool MutexTracker::_captureBan = false;
|
||||
std::shared_ptr<bool> MutexTracker::_captureBan = std::make_shared<bool>(false);
|
||||
|
||||
bool &MutexTracker::captureBan()
|
||||
std::shared_ptr<bool> MutexTracker::captureBan()
|
||||
{
|
||||
return _captureBan;
|
||||
}
|
||||
|
||||
MutexTracker::MutexTracker(bool &mutexToCapture)
|
||||
MutexTracker::MutexTracker(const std::shared_ptr<bool> &mutexToCapture)
|
||||
{
|
||||
attemptMutexCapture(mutexToCapture);
|
||||
}
|
||||
|
||||
MutexTracker::MutexTracker(bool &mutexToCapture, std::function<void()> destructorHook) : MutexTracker(mutexToCapture)
|
||||
MutexTracker::MutexTracker(const std::shared_ptr<bool> &mutexToCapture, const std::function<void()> destructorHook) : MutexTracker(mutexToCapture)
|
||||
{
|
||||
_destructorHook = destructorHook;
|
||||
}
|
||||
@ -47,12 +47,25 @@ MutexTracker::~MutexTracker()
|
||||
_destructorHook();
|
||||
}
|
||||
|
||||
bool MutexTracker::mutexCaptured()
|
||||
bool MutexTracker::mutexFree(const std::shared_ptr<bool> &mutex)
|
||||
{
|
||||
if(_capturedMutex)
|
||||
if(mutex != nullptr && !(*mutex))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MutexTracker::mutexCaptured(const std::shared_ptr<bool> &mutex)
|
||||
{
|
||||
if(mutex != nullptr && (*mutex))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MutexTracker::mutexCaptured() const
|
||||
{
|
||||
return mutexCaptured(_capturedMutex);
|
||||
}
|
||||
|
||||
void MutexTracker::releaseMutex()
|
||||
@ -60,20 +73,18 @@ void MutexTracker::releaseMutex()
|
||||
if(mutexCaptured())
|
||||
{
|
||||
*_capturedMutex = false;
|
||||
_capturedMutex = nullptr;
|
||||
_capturedMutex.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool MutexTracker::attemptMutexCapture(bool &mutexToCapture)
|
||||
bool MutexTracker::attemptMutexCapture(const std::shared_ptr<bool> &mutexToCapture)
|
||||
{
|
||||
if(!captureBan() && !mutexToCapture)
|
||||
if(mutexFree(captureBan()) && mutexFree(mutexToCapture))
|
||||
{
|
||||
_capturedMutex = &mutexToCapture;
|
||||
_capturedMutex = mutexToCapture;
|
||||
*_capturedMutex = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define __MUTEXTRACKER_H__
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* A SLIM (Scope LImited Manager)/Scope-Bound Resource Management/RAII class to manage the state of a mutex.
|
||||
@ -39,23 +40,23 @@ class MutexTracker
|
||||
* Set to false by default.
|
||||
* captureBan can be managed by MutexTracker like any other mutex.
|
||||
*/
|
||||
static bool &captureBan();
|
||||
static std::shared_ptr<bool> captureBan();
|
||||
|
||||
/**
|
||||
* Attempts to capture the mutex. Use the mutexCaptured() method to check success.
|
||||
*/
|
||||
MutexTracker(bool &mutexToCapture);
|
||||
MutexTracker(const std::shared_ptr<bool> &mutexToCapture);
|
||||
|
||||
/**
|
||||
* Attempts to capture the mutex. Use the mutexCaptured() method to check success.
|
||||
*
|
||||
* @param destructorHook A function to hook into the MutexTracker destructor. Will be called when the MutexTracker instance is being destroyed, after the mutex has been released.
|
||||
*/
|
||||
MutexTracker(bool &mutexToCapture, std::function<void()> destructorHook);
|
||||
MutexTracker(const std::shared_ptr<bool> &mutexToCapture, const std::function<void()> destructorHook);
|
||||
|
||||
~MutexTracker();
|
||||
|
||||
bool mutexCaptured();
|
||||
bool mutexCaptured() const;
|
||||
|
||||
/**
|
||||
* Set the mutex free to roam the binary plains, giving new MutexTrackers a chance to capture it.
|
||||
@ -64,17 +65,20 @@ class MutexTracker
|
||||
|
||||
private:
|
||||
|
||||
static bool _captureBan;
|
||||
static std::shared_ptr<bool> _captureBan;
|
||||
|
||||
bool *_capturedMutex = nullptr;
|
||||
std::shared_ptr<bool> _capturedMutex;
|
||||
std::function<void()> _destructorHook = [](){ };
|
||||
|
||||
static bool mutexFree(const std::shared_ptr<bool> &mutex);
|
||||
static bool mutexCaptured(const std::shared_ptr<bool> &mutex);
|
||||
|
||||
/**
|
||||
* Attempt to capture the mutex.
|
||||
*
|
||||
* @return True if mutex was caught (meaning no other instance is holding the mutex). False otherwise.
|
||||
* @return True if mutex was caught (meaning it exists and no other instance is holding the mutex). False otherwise.
|
||||
*/
|
||||
bool attemptMutexCapture(bool &mutexToCapture);
|
||||
bool attemptMutexCapture(const std::shared_ptr<bool> &mutexToCapture);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -40,7 +40,7 @@ void NetworkInfoBase::storeBSSID(const uint8_t newBSSID[6])
|
||||
_BSSID = _bssidArray;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
for(int i = 0; i < 6; ++i)
|
||||
{
|
||||
_BSSID[i] = newBSSID[i];
|
||||
}
|
||||
|
@ -25,8 +25,9 @@
|
||||
#include "RequestData.h"
|
||||
|
||||
RequestData::RequestData(EspnowMeshBackend &meshInstance, uint32_t creationTimeMs) :
|
||||
TimeTracker(creationTimeMs), _meshInstance(meshInstance)
|
||||
_timeTracker(creationTimeMs), _meshInstance(meshInstance)
|
||||
{ }
|
||||
|
||||
void RequestData::setMeshInstance(EspnowMeshBackend &meshInstance) { _meshInstance = meshInstance; }
|
||||
EspnowMeshBackend &RequestData::getMeshInstance() { return _meshInstance; }
|
||||
void RequestData::setMeshInstance(const EspnowMeshBackend &meshInstance) { _meshInstance = meshInstance; }
|
||||
EspnowMeshBackend &RequestData::getMeshInstance() const { return _meshInstance; }
|
||||
const TimeTracker &RequestData::getTimeTracker() const { return _timeTracker; }
|
||||
|
@ -30,17 +30,19 @@
|
||||
|
||||
class EspnowMeshBackend;
|
||||
|
||||
class RequestData : public TimeTracker {
|
||||
class RequestData {
|
||||
|
||||
public:
|
||||
|
||||
RequestData(EspnowMeshBackend &meshInstance, uint32_t creationTimeMs = millis());
|
||||
|
||||
void setMeshInstance(EspnowMeshBackend &meshInstance);
|
||||
EspnowMeshBackend &getMeshInstance();
|
||||
void setMeshInstance(const EspnowMeshBackend &meshInstance);
|
||||
EspnowMeshBackend &getMeshInstance() const;
|
||||
const TimeTracker &getTimeTracker() const;
|
||||
|
||||
private:
|
||||
|
||||
TimeTracker _timeTracker;
|
||||
EspnowMeshBackend &_meshInstance;
|
||||
};
|
||||
|
||||
|
@ -25,13 +25,13 @@
|
||||
#include "ResponseData.h"
|
||||
|
||||
ResponseData::ResponseData(const String &message, const uint8_t recipientMac[6], uint64_t requestID, uint32_t creationTimeMs) :
|
||||
TimeTracker(creationTimeMs), _message(message), _requestID(requestID)
|
||||
_timeTracker(creationTimeMs), _message(message), _requestID(requestID)
|
||||
{
|
||||
storeRecipientMac(recipientMac);
|
||||
}
|
||||
|
||||
ResponseData::ResponseData(const ResponseData &other)
|
||||
: TimeTracker(other), _message(other.getMessage()), _requestID(other.getRequestID())
|
||||
: _timeTracker(other.getTimeTracker()), _message(other.getMessage()), _requestID(other.getRequestID())
|
||||
{
|
||||
storeRecipientMac(other.getRecipientMac());
|
||||
}
|
||||
@ -40,7 +40,7 @@ ResponseData & ResponseData::operator=(const ResponseData &other)
|
||||
{
|
||||
if(this != &other)
|
||||
{
|
||||
TimeTracker::operator=(other);
|
||||
_timeTracker = other.getTimeTracker();
|
||||
_message = other.getMessage();
|
||||
_requestID = other.getRequestID();
|
||||
storeRecipientMac(other.getRecipientMac());
|
||||
@ -51,21 +51,20 @@ ResponseData & ResponseData::operator=(const ResponseData &other)
|
||||
|
||||
void ResponseData::storeRecipientMac(const uint8_t newRecipientMac[6])
|
||||
{
|
||||
if(newRecipientMac != nullptr)
|
||||
{
|
||||
if(_recipientMac == nullptr)
|
||||
{
|
||||
_recipientMac = _recipientMacArray;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
_recipientMac[i] = newRecipientMac[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
if(newRecipientMac == nullptr)
|
||||
{
|
||||
_recipientMac = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if(_recipientMac == nullptr)
|
||||
{
|
||||
_recipientMac = _recipientMacArray;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; ++i)
|
||||
{
|
||||
_recipientMac[i] = newRecipientMac[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,3 +76,5 @@ String ResponseData::getMessage() const { return _message; }
|
||||
|
||||
void ResponseData::setRequestID(uint64_t requestID) { _requestID = requestID; }
|
||||
uint64_t ResponseData::getRequestID() const { return _requestID; }
|
||||
|
||||
const TimeTracker &ResponseData::getTimeTracker() const { return _timeTracker; }
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "TimeTracker.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
class ResponseData : public TimeTracker {
|
||||
class ResponseData {
|
||||
|
||||
public:
|
||||
|
||||
@ -46,10 +46,14 @@ public:
|
||||
void setRequestID(uint64_t requestID);
|
||||
uint64_t getRequestID() const;
|
||||
|
||||
const TimeTracker &getTimeTracker() const;
|
||||
|
||||
private:
|
||||
|
||||
void storeRecipientMac(const uint8_t newRecipientMac[6]);
|
||||
|
||||
TimeTracker _timeTracker;
|
||||
|
||||
uint8_t _recipientMacArray[6] {0};
|
||||
uint8_t *_recipientMac = nullptr;
|
||||
String _message;
|
||||
|
@ -32,8 +32,8 @@ namespace
|
||||
|
||||
const IPAddress TcpIpMeshBackend::emptyIP;
|
||||
|
||||
bool TcpIpMeshBackend::_tcpIpTransmissionMutex = false;
|
||||
bool TcpIpMeshBackend::_tcpIpConnectionQueueMutex = false;
|
||||
std::shared_ptr<bool> TcpIpMeshBackend::_tcpIpTransmissionMutex = std::make_shared<bool>(false);
|
||||
std::shared_ptr<bool> TcpIpMeshBackend::_tcpIpConnectionQueueMutex = std::make_shared<bool>(false);
|
||||
|
||||
String TcpIpMeshBackend::lastSSID;
|
||||
bool TcpIpMeshBackend::staticIPActivated = false;
|
||||
@ -51,7 +51,7 @@ std::vector<TransmissionOutcome> TcpIpMeshBackend::_latestTransmissionOutcomes =
|
||||
TcpIpMeshBackend::TcpIpMeshBackend(requestHandlerType requestHandler, responseHandlerType responseHandler,
|
||||
networkFilterType networkFilter, const String &meshPassword, const String &ssidPrefix,
|
||||
const String &ssidSuffix, bool verboseMode, uint8 meshWiFiChannel, uint16_t serverPort)
|
||||
: MeshBackendBase(requestHandler, responseHandler, networkFilter, MB_TCP_IP), _server(serverPort)
|
||||
: MeshBackendBase(requestHandler, responseHandler, networkFilter, MeshBackendType::TCP_IP), _server(serverPort)
|
||||
{
|
||||
setSSID(ssidPrefix, emptyString, ssidSuffix);
|
||||
setMeshPassword(meshPassword);
|
||||
@ -111,7 +111,7 @@ void TcpIpMeshBackend::deactivateAPHook()
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
bool TcpIpMeshBackend::transmissionInProgress(){return _tcpIpTransmissionMutex;}
|
||||
bool TcpIpMeshBackend::transmissionInProgress(){return *_tcpIpTransmissionMutex;}
|
||||
|
||||
void TcpIpMeshBackend::setTemporaryMessage(const String &newTemporaryMessage) {_temporaryMessage = newTemporaryMessage;}
|
||||
String TcpIpMeshBackend::getTemporaryMessage() {return _temporaryMessage;}
|
||||
@ -180,12 +180,12 @@ void TcpIpMeshBackend::setMaxAPStations(uint8_t maxAPStations)
|
||||
|
||||
bool TcpIpMeshBackend::getMaxAPStations() {return _maxAPStations;}
|
||||
|
||||
void TcpIpMeshBackend::setConnectionAttemptTimeout(int32_t connectionAttemptTimeoutMs)
|
||||
void TcpIpMeshBackend::setConnectionAttemptTimeout(uint32_t connectionAttemptTimeoutMs)
|
||||
{
|
||||
_connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
|
||||
}
|
||||
|
||||
int32_t TcpIpMeshBackend::getConnectionAttemptTimeout() {return _connectionAttemptTimeoutMs;}
|
||||
uint32_t TcpIpMeshBackend::getConnectionAttemptTimeout() {return _connectionAttemptTimeoutMs;}
|
||||
|
||||
void TcpIpMeshBackend::setStationModeTimeout(int stationModeTimeoutMs)
|
||||
{
|
||||
@ -220,12 +220,11 @@ void TcpIpMeshBackend::fullStop(WiFiClient &currClient)
|
||||
*/
|
||||
bool TcpIpMeshBackend::waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait)
|
||||
{
|
||||
uint32_t connectionStartTime = millis();
|
||||
uint32_t waitingTime = millis() - connectionStartTime;
|
||||
while(currClient.connected() && !currClient.available() && waitingTime < maxWait)
|
||||
ExpiringTimeTracker timeout(maxWait);
|
||||
|
||||
while(currClient.connected() && !currClient.available() && !timeout)
|
||||
{
|
||||
delay(1);
|
||||
waitingTime = millis() - connectionStartTime;
|
||||
}
|
||||
|
||||
/* Return false if the client isn't ready to communicate */
|
||||
@ -246,7 +245,7 @@ bool TcpIpMeshBackend::waitForClientTransmission(WiFiClient &currClient, uint32_
|
||||
* @return A status code based on the outcome of the exchange.
|
||||
*
|
||||
*/
|
||||
transmission_status_t TcpIpMeshBackend::exchangeInfo(WiFiClient &currClient)
|
||||
TransmissionStatusType TcpIpMeshBackend::exchangeInfo(WiFiClient &currClient)
|
||||
{
|
||||
verboseModePrint(String(F("Transmitting")));
|
||||
|
||||
@ -256,13 +255,13 @@ transmission_status_t TcpIpMeshBackend::exchangeInfo(WiFiClient &currClient)
|
||||
if (!waitForClientTransmission(currClient, _stationModeTimeoutMs))
|
||||
{
|
||||
fullStop(currClient);
|
||||
return TS_CONNECTION_FAILED;
|
||||
return TransmissionStatusType::CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
if (!currClient.available())
|
||||
{
|
||||
verboseModePrint(F("No response!"));
|
||||
return TS_TRANSMISSION_FAILED; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(currClient) here since that would force the node to scan for WiFi networks.
|
||||
return TransmissionStatusType::TRANSMISSION_FAILED; // WiFi.status() != WL_DISCONNECTED so we do not want to use fullStop(currClient) here since that would force the node to scan for WiFi networks.
|
||||
}
|
||||
|
||||
String response = currClient.readStringUntil('\r');
|
||||
@ -278,7 +277,7 @@ transmission_status_t TcpIpMeshBackend::exchangeInfo(WiFiClient &currClient)
|
||||
*
|
||||
* @return A status code based on the outcome of the data transfer attempt.
|
||||
*/
|
||||
transmission_status_t TcpIpMeshBackend::attemptDataTransfer()
|
||||
TransmissionStatusType TcpIpMeshBackend::attemptDataTransfer()
|
||||
{
|
||||
// Unlike WiFi.mode(WIFI_AP);, WiFi.mode(WIFI_AP_STA); allows us to stay connected to the AP we connected to in STA mode, at the same time as we can receive connections from other stations.
|
||||
// We cannot send data to the AP in STA_AP mode though, that requires STA mode.
|
||||
@ -286,7 +285,7 @@ transmission_status_t TcpIpMeshBackend::attemptDataTransfer()
|
||||
WiFiMode_t storedWiFiMode = WiFi.getMode();
|
||||
WiFi.mode(WIFI_STA);
|
||||
delay(1);
|
||||
transmission_status_t transmissionOutcome = attemptDataTransferKernel();
|
||||
TransmissionStatusType transmissionOutcome = attemptDataTransferKernel();
|
||||
WiFi.mode(storedWiFiMode);
|
||||
delay(1);
|
||||
|
||||
@ -298,7 +297,7 @@ transmission_status_t TcpIpMeshBackend::attemptDataTransfer()
|
||||
*
|
||||
* @return A status code based on the outcome of the data transfer attempt.
|
||||
*/
|
||||
transmission_status_t TcpIpMeshBackend::attemptDataTransferKernel()
|
||||
TransmissionStatusType TcpIpMeshBackend::attemptDataTransferKernel()
|
||||
{
|
||||
WiFiClient currClient;
|
||||
currClient.setTimeout(_stationModeTimeoutMs);
|
||||
@ -308,11 +307,11 @@ transmission_status_t TcpIpMeshBackend::attemptDataTransferKernel()
|
||||
{
|
||||
fullStop(currClient);
|
||||
verboseModePrint(F("Server unavailable"));
|
||||
return TS_CONNECTION_FAILED;
|
||||
return TransmissionStatusType::CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
transmission_status_t transmissionOutcome = exchangeInfo(currClient);
|
||||
if (transmissionOutcome <= 0)
|
||||
TransmissionStatusType transmissionOutcome = exchangeInfo(currClient);
|
||||
if (static_cast<int>(transmissionOutcome) <= 0)
|
||||
{
|
||||
verboseModePrint(F("Transmission failed during exchangeInfo."));
|
||||
return transmissionOutcome;
|
||||
@ -343,7 +342,7 @@ void TcpIpMeshBackend::initiateConnectionToAP(const String &targetSSID, int targ
|
||||
* @return A status code based on the outcome of the connection and data transfer process.
|
||||
*
|
||||
*/
|
||||
transmission_status_t TcpIpMeshBackend::connectToNode(const String &targetSSID, int targetChannel, uint8_t *targetBSSID)
|
||||
TransmissionStatusType TcpIpMeshBackend::connectToNode(const String &targetSSID, int targetChannel, uint8_t *targetBSSID)
|
||||
{
|
||||
if(staticIPActivated && !lastSSID.isEmpty() && lastSSID != targetSSID) // So we only do this once per connection, in case there is a performance impact.
|
||||
{
|
||||
@ -366,37 +365,36 @@ transmission_status_t TcpIpMeshBackend::connectToNode(const String &targetSSID,
|
||||
verboseModePrint(F("Connecting... "), false);
|
||||
initiateConnectionToAP(targetSSID, targetChannel, targetBSSID);
|
||||
|
||||
int connectionStartTime = millis();
|
||||
int attemptNumber = 1;
|
||||
ExpiringTimeTracker connectionAttemptTimeout([this](){ return _connectionAttemptTimeoutMs; });
|
||||
|
||||
int waitingTime = millis() - connectionStartTime;
|
||||
while((WiFi.status() == WL_DISCONNECTED) && waitingTime <= _connectionAttemptTimeoutMs)
|
||||
while((WiFi.status() == WL_DISCONNECTED) && !connectionAttemptTimeout)
|
||||
{
|
||||
if(waitingTime > attemptNumber * _connectionAttemptTimeoutMs) // _connectionAttemptTimeoutMs can be replaced (lowered) if you want to limit the time allowed for each connection attempt.
|
||||
if(connectionAttemptTimeout.elapsedTime() > attemptNumber * _connectionAttemptTimeoutMs) // _connectionAttemptTimeoutMs can be replaced (lowered) if you want to limit the time allowed for each connection attempt.
|
||||
{
|
||||
verboseModePrint(F("... "), false);
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
initiateConnectionToAP(targetSSID, targetChannel, targetBSSID);
|
||||
attemptNumber++;
|
||||
++attemptNumber;
|
||||
}
|
||||
|
||||
delay(1);
|
||||
waitingTime = millis() - connectionStartTime;
|
||||
}
|
||||
|
||||
verboseModePrint(String(waitingTime));
|
||||
verboseModePrint(String(connectionAttemptTimeout.elapsedTime()));
|
||||
|
||||
/* If the connection timed out */
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
verboseModePrint(F("Timeout"));
|
||||
return TS_CONNECTION_FAILED;
|
||||
return TransmissionStatusType::CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
return attemptDataTransfer();
|
||||
}
|
||||
|
||||
transmission_status_t TcpIpMeshBackend::initiateTransmission(const TcpIpNetworkInfo &recipientInfo)
|
||||
TransmissionStatusType TcpIpMeshBackend::initiateTransmission(const TcpIpNetworkInfo &recipientInfo)
|
||||
{
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
@ -452,7 +450,7 @@ void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, boo
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
transmission_status_t transmissionResult = attemptDataTransfer();
|
||||
TransmissionStatusType transmissionResult = attemptDataTransfer();
|
||||
latestTransmissionOutcomes().push_back(TransmissionOutcome(constConnectionQueue().back(), transmissionResult));
|
||||
|
||||
getTransmissionOutcomesUpdateHook()(*this);
|
||||
@ -474,7 +472,7 @@ void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, boo
|
||||
{
|
||||
for(const TcpIpNetworkInfo ¤tNetwork : constConnectionQueue())
|
||||
{
|
||||
transmission_status_t transmissionResult = initiateTransmission(currentNetwork);
|
||||
TransmissionStatusType transmissionResult = initiateTransmission(currentNetwork);
|
||||
|
||||
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
|
||||
@ -492,16 +490,16 @@ void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, boo
|
||||
attemptTransmission(message, scan, scanAllWiFiChannels, true, false);
|
||||
}
|
||||
|
||||
transmission_status_t TcpIpMeshBackend::attemptTransmission(const String &message, const TcpIpNetworkInfo &recipientInfo, bool concludingDisconnect, bool initialDisconnect)
|
||||
TransmissionStatusType TcpIpMeshBackend::attemptTransmission(const String &message, const TcpIpNetworkInfo &recipientInfo, bool concludingDisconnect, bool initialDisconnect)
|
||||
{
|
||||
MutexTracker mutexTracker(_tcpIpTransmissionMutex);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && String(F("ERROR! TCP/IP transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.")));
|
||||
return TS_CONNECTION_FAILED;
|
||||
return TransmissionStatusType::CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
transmission_status_t transmissionResult = TS_CONNECTION_FAILED;
|
||||
TransmissionStatusType transmissionResult = TransmissionStatusType::CONNECTION_FAILED;
|
||||
setTemporaryMessage(message);
|
||||
|
||||
if(initialDisconnect)
|
||||
|
@ -43,14 +43,14 @@ public:
|
||||
* @param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which
|
||||
* is the request string received from another node and returns the string to send back.
|
||||
* @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which
|
||||
* is the response string received from another node. Returns a transmission status code as a transmission_status_t.
|
||||
* is the response string received from another node. Returns a transmission status code as a TransmissionStatusType.
|
||||
* @param networkFilter The callback handler for deciding which WiFi networks to connect to.
|
||||
* @param meshPassword The WiFi password for the mesh network.
|
||||
* @param ssidPrefix The prefix (first part) of the node SSID.
|
||||
* @param ssidSuffix The suffix (last part) of the node SSID.
|
||||
* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default. This setting is separate for each TcpIpMeshBackend instance.
|
||||
* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several mesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one mesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
@ -91,7 +91,7 @@ public:
|
||||
static std::vector<TransmissionOutcome> & latestTransmissionOutcomes();
|
||||
|
||||
/**
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TransmissionStatusType::TRANSMISSION_COMPLETE). False otherwise.
|
||||
* The result is unique for each mesh backend.
|
||||
*/
|
||||
static bool latestTransmissionSuccessful();
|
||||
@ -124,7 +124,7 @@ public:
|
||||
*
|
||||
* Note that if wifiChannel and BSSID are missing from recipientInfo, connection time will be longer.
|
||||
*/
|
||||
transmission_status_t attemptTransmission(const String &message, const TcpIpNetworkInfo &recipientInfo, bool concludingDisconnect = true, bool initialDisconnect = false);
|
||||
TransmissionStatusType attemptTransmission(const String &message, const TcpIpNetworkInfo &recipientInfo, bool concludingDisconnect = true, bool initialDisconnect = false);
|
||||
|
||||
/**
|
||||
* If any clients are connected, accept their requests and call the requestHandler function for each one.
|
||||
@ -183,8 +183,8 @@ public:
|
||||
*
|
||||
* @param connectionAttemptTimeoutMs The timeout for each connection attempt, in milliseconds.
|
||||
*/
|
||||
void setConnectionAttemptTimeout(int32_t connectionAttemptTimeoutMs);
|
||||
int32_t getConnectionAttemptTimeout();
|
||||
void setConnectionAttemptTimeout(uint32_t connectionAttemptTimeoutMs);
|
||||
uint32_t getConnectionAttemptTimeout();
|
||||
|
||||
/**
|
||||
* Set the timeout to use for transmissions when this TcpIpMeshBackend instance acts as a station (i.e. when connected to another AP).
|
||||
@ -228,12 +228,12 @@ protected:
|
||||
/**
|
||||
* Will be true if a transmission initiated by a public method is in progress.
|
||||
*/
|
||||
static bool _tcpIpTransmissionMutex;
|
||||
static std::shared_ptr<bool> _tcpIpTransmissionMutex;
|
||||
|
||||
/**
|
||||
* Will be true when the connectionQueue should not be modified.
|
||||
*/
|
||||
static bool _tcpIpConnectionQueueMutex;
|
||||
static std::shared_ptr<bool> _tcpIpConnectionQueueMutex;
|
||||
|
||||
/**
|
||||
* Check if there is an ongoing TCP/IP transmission in the library. Used to avoid interrupting transmissions.
|
||||
@ -257,7 +257,7 @@ private:
|
||||
uint16_t _serverPort;
|
||||
WiFiServer _server;
|
||||
uint8_t _maxAPStations = 4; // Only affects TCP/IP connections, not ESP-NOW connections
|
||||
int32_t _connectionAttemptTimeoutMs = 10000;
|
||||
uint32_t _connectionAttemptTimeoutMs = 10000;
|
||||
int _stationModeTimeoutMs = 5000; // int is the type used in the Arduino core for this particular API, not uint32_t, which is why we use int here.
|
||||
uint32_t _apModeTimeoutMs = 4500;
|
||||
|
||||
@ -271,12 +271,12 @@ private:
|
||||
|
||||
void fullStop(WiFiClient &currClient);
|
||||
void initiateConnectionToAP(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t connectToNode(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t exchangeInfo(WiFiClient &currClient);
|
||||
TransmissionStatusType connectToNode(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
TransmissionStatusType exchangeInfo(WiFiClient &currClient);
|
||||
bool waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait);
|
||||
transmission_status_t attemptDataTransfer();
|
||||
transmission_status_t attemptDataTransferKernel();
|
||||
transmission_status_t initiateTransmission(const TcpIpNetworkInfo &recipientInfo);
|
||||
TransmissionStatusType attemptDataTransfer();
|
||||
TransmissionStatusType attemptDataTransferKernel();
|
||||
TransmissionStatusType initiateTransmission(const TcpIpNetworkInfo &recipientInfo);
|
||||
void enterPostTransmissionState(bool concludingDisconnect);
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Minimal time tracking class. Used instead of other classes like ExpiringTimeTracker when small memory footprint is important and other functionality not required.
|
||||
class TimeTracker {
|
||||
|
||||
public:
|
||||
|
@ -24,13 +24,13 @@
|
||||
|
||||
#include "TransmissionOutcome.h"
|
||||
|
||||
TransmissionOutcome::TransmissionOutcome(const NetworkInfoBase &origin, transmission_status_t transmissionStatus)
|
||||
TransmissionOutcome::TransmissionOutcome(const NetworkInfoBase &origin, TransmissionStatusType transmissionStatus)
|
||||
: NetworkInfoBase(origin), _transmissionStatus(transmissionStatus)
|
||||
{ }
|
||||
|
||||
TransmissionOutcome::TransmissionOutcome(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI, bool isHidden, transmission_status_t transmissionStatus)
|
||||
TransmissionOutcome::TransmissionOutcome(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI, bool isHidden, TransmissionStatusType transmissionStatus)
|
||||
: NetworkInfoBase(SSID, wifiChannel, BSSID, encryptionType, RSSI, isHidden), _transmissionStatus(transmissionStatus)
|
||||
{ }
|
||||
|
||||
void TransmissionOutcome::setTransmissionStatus(transmission_status_t transmissionStatus) { _transmissionStatus = transmissionStatus; }
|
||||
transmission_status_t TransmissionOutcome::transmissionStatus() const { return _transmissionStatus; }
|
||||
void TransmissionOutcome::setTransmissionStatus(TransmissionStatusType transmissionStatus) { _transmissionStatus = transmissionStatus; }
|
||||
TransmissionStatusType TransmissionOutcome::transmissionStatus() const { return _transmissionStatus; }
|
||||
|
@ -28,27 +28,27 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
typedef enum
|
||||
enum class TransmissionStatusType
|
||||
{
|
||||
TS_CONNECTION_FAILED = -1,
|
||||
TS_TRANSMISSION_FAILED = 0,
|
||||
TS_TRANSMISSION_COMPLETE = 1
|
||||
} transmission_status_t;
|
||||
CONNECTION_FAILED = -1,
|
||||
TRANSMISSION_FAILED = 0,
|
||||
TRANSMISSION_COMPLETE = 1
|
||||
};
|
||||
|
||||
class TransmissionOutcome : public NetworkInfoBase {
|
||||
|
||||
public:
|
||||
|
||||
TransmissionOutcome(const NetworkInfoBase &origin, transmission_status_t transmissionStatus);
|
||||
TransmissionOutcome(const NetworkInfoBase &origin, TransmissionStatusType transmissionStatus);
|
||||
|
||||
TransmissionOutcome(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI, bool isHidden, transmission_status_t transmissionStatus);
|
||||
TransmissionOutcome(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI, bool isHidden, TransmissionStatusType transmissionStatus);
|
||||
|
||||
void setTransmissionStatus(transmission_status_t transmissionStatus);
|
||||
transmission_status_t transmissionStatus() const;
|
||||
void setTransmissionStatus(TransmissionStatusType transmissionStatus);
|
||||
TransmissionStatusType transmissionStatus() const;
|
||||
|
||||
private:
|
||||
|
||||
transmission_status_t _transmissionStatus;
|
||||
TransmissionStatusType _transmissionStatus;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -54,6 +54,13 @@
|
||||
#include "NetworkInfo.h"
|
||||
#include "TransmissionOutcome.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TS_CONNECTION_FAILED = -1,
|
||||
TS_TRANSMISSION_FAILED = 0,
|
||||
TS_TRANSMISSION_COMPLETE = 1
|
||||
} transmission_status_t;
|
||||
|
||||
class TransmissionResult : public NetworkInfo {
|
||||
|
||||
public:
|
||||
@ -63,11 +70,11 @@ public:
|
||||
/**
|
||||
* @param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results.
|
||||
*/
|
||||
TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill = true);
|
||||
TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill = true) __attribute__((deprecated));
|
||||
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus);
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus) __attribute__((deprecated));
|
||||
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus);
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus) __attribute__((deprecated));
|
||||
|
||||
TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus);
|
||||
};
|
||||
|
@ -27,15 +27,15 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr char chars[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
|
||||
constexpr uint8_t charValues[75] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, // 0 to 10
|
||||
constexpr char chars[36] PROGMEM = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
|
||||
constexpr uint8_t charValues[75] PROGMEM {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, // 0 to 9
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, 0, // Upper case letters
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; // Lower case letters
|
||||
}
|
||||
|
||||
namespace MeshTypeConversionFunctions
|
||||
{
|
||||
String uint64ToString(uint64_t number, byte base)
|
||||
String uint64ToString(uint64_t number, const byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
@ -44,14 +44,14 @@ namespace MeshTypeConversionFunctions
|
||||
if(base == 16)
|
||||
{
|
||||
do {
|
||||
result += chars[ number % base ];
|
||||
result += (char)pgm_read_byte(chars + number % base);
|
||||
number >>= 4; // We could write number /= 16; and the compiler would optimize it to a shift, but the explicit shift notation makes it clearer where the speed-up comes from.
|
||||
} while ( number );
|
||||
}
|
||||
else
|
||||
{
|
||||
do {
|
||||
result += chars[ number % base ];
|
||||
result += (char)pgm_read_byte(chars + number % base);
|
||||
number /= base;
|
||||
} while ( number );
|
||||
}
|
||||
@ -61,7 +61,7 @@ namespace MeshTypeConversionFunctions
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t stringToUint64(const String &string, byte base)
|
||||
uint64_t stringToUint64(const String &string, const byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
@ -72,7 +72,7 @@ namespace MeshTypeConversionFunctions
|
||||
for(uint32_t i = 0; i < string.length(); ++i)
|
||||
{
|
||||
result <<= 4; // We could write result *= 16; and the compiler would optimize it to a shift, but the explicit shift notation makes it clearer where the speed-up comes from.
|
||||
result += charValues[string.charAt(i) - '0'];
|
||||
result += pgm_read_byte(charValues + string.charAt(i) - '0');
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -80,14 +80,14 @@ namespace MeshTypeConversionFunctions
|
||||
for(uint32_t i = 0; i < string.length(); ++i)
|
||||
{
|
||||
result *= base;
|
||||
result += charValues[string.charAt(i) - '0'];
|
||||
result += pgm_read_byte(charValues + string.charAt(i) - '0');
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
String uint8ArrayToHexString(const uint8_t *uint8Array, uint32_t arrayLength)
|
||||
String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength)
|
||||
{
|
||||
String hexString;
|
||||
if(!hexString.reserve(2*arrayLength)) // Each uint8_t will become two characters (00 to FF)
|
||||
@ -95,26 +95,26 @@ namespace MeshTypeConversionFunctions
|
||||
|
||||
for(uint32_t i = 0; i < arrayLength; ++i)
|
||||
{
|
||||
hexString += chars[ uint8Array[i] >> 4 ];
|
||||
hexString += chars[ uint8Array[i] % 16 ];
|
||||
hexString += (char)pgm_read_byte(chars + (uint8Array[i] >> 4));
|
||||
hexString += (char)pgm_read_byte(chars + uint8Array[i] % 16 );
|
||||
}
|
||||
|
||||
return hexString;
|
||||
}
|
||||
|
||||
uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, uint32_t arrayLength)
|
||||
uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength)
|
||||
{
|
||||
assert(hexString.length() >= arrayLength*2); // Each array element can hold two hexString characters
|
||||
|
||||
for(uint32_t i = 0; i < arrayLength; ++i)
|
||||
{
|
||||
uint8Array[i] = (charValues[hexString.charAt(i*2) - '0'] << 4) + charValues[hexString.charAt(i*2 + 1) - '0'];
|
||||
uint8Array[i] = (pgm_read_byte(charValues + hexString.charAt(i*2) - '0') << 4) + pgm_read_byte(charValues + hexString.charAt(i*2 + 1) - '0');
|
||||
}
|
||||
|
||||
return uint8Array;
|
||||
}
|
||||
|
||||
String uint8ArrayToMultiString(uint8_t *uint8Array, uint32_t arrayLength)
|
||||
String uint8ArrayToMultiString(uint8_t *uint8Array, const uint32_t arrayLength)
|
||||
{
|
||||
String multiString;
|
||||
if(!multiString.reserve(arrayLength))
|
||||
@ -137,7 +137,7 @@ namespace MeshTypeConversionFunctions
|
||||
return multiString;
|
||||
}
|
||||
|
||||
String bufferedUint8ArrayToMultiString(const uint8_t *uint8Array, uint32_t arrayLength)
|
||||
String bufferedUint8ArrayToMultiString(const uint8_t *uint8Array, const uint32_t arrayLength)
|
||||
{
|
||||
String multiString;
|
||||
if(!multiString.reserve(arrayLength))
|
||||
@ -174,7 +174,7 @@ namespace MeshTypeConversionFunctions
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t *uint64ToMac(uint64_t macValue, uint8_t *macArray)
|
||||
uint8_t *uint64ToMac(const uint64_t macValue, uint8_t *macArray)
|
||||
{
|
||||
assert(macValue <= 0xFFFFFFFFFFFF); // Overflow will occur if value can't fit within 6 bytes
|
||||
|
||||
@ -188,7 +188,7 @@ namespace MeshTypeConversionFunctions
|
||||
return macArray;
|
||||
}
|
||||
|
||||
uint8_t *uint64ToUint8Array(uint64_t value, uint8_t *resultArray)
|
||||
uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray)
|
||||
{
|
||||
resultArray[7] = value;
|
||||
resultArray[6] = value >> 8;
|
||||
@ -214,27 +214,25 @@ namespace MeshTypeConversionFunctions
|
||||
* Helper function for meshBackendCast.
|
||||
*/
|
||||
template <typename T>
|
||||
T attemptPointerCast(MeshBackendBase *meshBackendBaseInstance, mesh_backend_t resultClassType)
|
||||
T attemptPointerCast(MeshBackendBase *meshBackendBaseInstance, MeshBackendType resultClassType)
|
||||
{
|
||||
if(meshBackendBaseInstance && meshBackendBaseInstance->getClassType() == resultClassType)
|
||||
{
|
||||
return static_cast<T>(meshBackendBaseInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <>
|
||||
EspnowMeshBackend *meshBackendCast<EspnowMeshBackend *>(MeshBackendBase *meshBackendBaseInstance)
|
||||
{
|
||||
return attemptPointerCast<EspnowMeshBackend *>(meshBackendBaseInstance, MB_ESP_NOW);
|
||||
return attemptPointerCast<EspnowMeshBackend *>(meshBackendBaseInstance, MeshBackendType::ESP_NOW);
|
||||
}
|
||||
|
||||
template <>
|
||||
TcpIpMeshBackend *meshBackendCast<TcpIpMeshBackend *>(MeshBackendBase *meshBackendBaseInstance)
|
||||
{
|
||||
return attemptPointerCast<TcpIpMeshBackend *>(meshBackendBaseInstance, MB_TCP_IP);
|
||||
return attemptPointerCast<TcpIpMeshBackend *>(meshBackendBaseInstance, MeshBackendType::TCP_IP);
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param base The radix to convert "number" into. Must be between 2 and 36.
|
||||
* @return A string of "number" encoded in radix "base".
|
||||
*/
|
||||
String uint64ToString(uint64_t number, byte base = 16);
|
||||
String uint64ToString(uint64_t number, const byte base = 16);
|
||||
|
||||
/**
|
||||
* Note that using base 10 instead of 16 increases conversion time by roughly a factor of 2, due to unfavourable 64-bit arithmetic.
|
||||
@ -52,7 +52,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param base The radix of "string". Must be between 2 and 36.
|
||||
* @return A uint64_t of the string, using radix "base" during decoding.
|
||||
*/
|
||||
uint64_t stringToUint64(const String &string, byte base = 16);
|
||||
uint64_t stringToUint64(const String &string, const byte base = 16);
|
||||
|
||||
/**
|
||||
* Convert the contents of a uint8_t array to a String in HEX format. The resulting String starts from index 0 of the array.
|
||||
@ -62,7 +62,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param arrayLength The size of uint8Array, in bytes.
|
||||
* @return Normally a String containing the HEX representation of the uint8Array. An empty String if the memory allocation for the String failed.
|
||||
*/
|
||||
String uint8ArrayToHexString(const uint8_t *uint8Array, uint32_t arrayLength);
|
||||
String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength);
|
||||
|
||||
/**
|
||||
* Convert the contents of a String in HEX format to a uint8_t array. Index 0 of the array will represent the start of the String.
|
||||
@ -73,7 +73,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param arrayLength The number of bytes to fill in uint8Array.
|
||||
* @return A pointer to the uint8Array.
|
||||
*/
|
||||
uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, uint32_t arrayLength);
|
||||
uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength);
|
||||
|
||||
/**
|
||||
* Stores the exact values of uint8Array in a String, even null values.
|
||||
@ -86,7 +86,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param arrayLength The size of uint8Array, in bytes.
|
||||
* @return Normally a String containing the same data as the uint8Array. An empty String if the memory allocation for the String failed.
|
||||
*/
|
||||
String uint8ArrayToMultiString(uint8_t *uint8Array, uint32_t arrayLength);
|
||||
String uint8ArrayToMultiString(uint8_t *uint8Array, const uint32_t arrayLength);
|
||||
|
||||
/**
|
||||
* Stores the exact values of uint8Array in a String, even null values.
|
||||
@ -99,7 +99,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param arrayLength The size of uint8Array, in bytes.
|
||||
* @return Normally a String containing the same data as the uint8Array. An empty String if the memory allocation for the String failed.
|
||||
*/
|
||||
String bufferedUint8ArrayToMultiString(const uint8_t *uint8Array, uint32_t arrayLength);
|
||||
String bufferedUint8ArrayToMultiString(const uint8_t *uint8Array, const uint32_t arrayLength);
|
||||
|
||||
/**
|
||||
* Takes a uint8_t array and converts the first 6 bytes to a hexadecimal string.
|
||||
@ -133,7 +133,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param macArray A uint8_t array that will hold the mac address once the function returns. Should have a size of at least 6 bytes.
|
||||
* @return The macArray.
|
||||
*/
|
||||
uint8_t *uint64ToMac(uint64_t macValue, uint8_t *macArray);
|
||||
uint8_t *uint64ToMac(const uint64_t macValue, uint8_t *macArray);
|
||||
|
||||
/**
|
||||
* Takes a uint64_t value and stores the bits in a uint8_t array. Assumes index 0 of the array should contain MSB.
|
||||
@ -142,7 +142,7 @@ namespace MeshTypeConversionFunctions
|
||||
* @param resultArray A uint8_t array that will hold the result once the function returns. Should have a size of at least 8 bytes.
|
||||
* @return The resultArray.
|
||||
*/
|
||||
uint8_t *uint64ToUint8Array(uint64_t value, uint8_t *resultArray);
|
||||
uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray);
|
||||
|
||||
/**
|
||||
* Takes a uint8_t array and converts the first 8 (lowest index) elements to a uint64_t. Assumes index 0 of the array contains MSB.
|
||||
|
@ -30,7 +30,7 @@ namespace MeshUtilityFunctions
|
||||
{
|
||||
bool macEqual(const uint8_t *macOne, const uint8_t *macTwo)
|
||||
{
|
||||
for(int i = 0; i <= 5; i++)
|
||||
for(int i = 0; i <= 5; ++i)
|
||||
{
|
||||
if(macOne[i] != macTwo[i])
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user