mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-22 21:23:07 +03:00
- Make each mesh backend use a unique NetworkInfo class and separate connectionQueue and latestTransmissionOutcomes vectors.
- Deprecate NetworkInfo and TransmissionResult classes. - Add single recipient transmission methods. - Add a getCurrentMessage method to TcpIpMeshBackend to maintain feature parity when using single recipient transmission methods. - Increase code abstraction level in transmission methods. - Remove use of networkIndex except for in constructors, since it can change after each scan. - Make Espnow backend require at least BSSID to connect, and the TcpIp backend require at least SSID. - Make printAPInfo method take NetworkInfo as argument. - Add new TransmissionOutcome class to replace obsolete TransmissionResult. - Add _scanMutex. - Improve code abstraction in HelloEspnow.ino. - Update HelloEspnow.ino example to demonstrate the new features. - Update and improve comments.
This commit is contained in:
parent
2576a0912b
commit
86025c7884
@ -14,7 +14,7 @@
|
||||
https://github.com/esp8266/Arduino/issues/1143
|
||||
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
|
||||
*/
|
||||
const char exampleMeshName[] PROGMEM = "MeshNode_"; // The name of the mesh network. Used as prefix for the node SSID and to find other network nodes during ESP-NOW broadcasts and in the example networkFilter function below.
|
||||
const char exampleMeshName[] PROGMEM = "MeshNode_"; // The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example networkFilter and broadcastFilter functions below.
|
||||
const char exampleWiFiPassword[] PROGMEM = "ChangeThisWiFiPassword_TODO"; // The password has to be min 8 and max 64 characters long, otherwise an AP which uses it will not be found during scans.
|
||||
|
||||
// A custom encryption key is required when using encrypted ESP-NOW transmissions. There is always a default Kok set, but it can be replaced if desired.
|
||||
@ -32,6 +32,8 @@ uint8_t espnowHashKey[16] = {0xEF, 0x44, 0x33, 0x0C, 0x33, 0x44, 0xFE, 0x44, //
|
||||
unsigned int requestNumber = 0;
|
||||
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);
|
||||
void networkFilter(int numberOfNetworks, MeshBackendBase &meshInstance);
|
||||
@ -96,7 +98,7 @@ transmission_status_t manageResponse(const String &response, MeshBackendBase &me
|
||||
// With ESP-NOW there is no guarantee when or if a response will show up, it can happen before or after the stored message is changed.
|
||||
// So for ESP-NOW, adding unique identifiers in the response and request is required to associate a response with a request.
|
||||
Serial.print(F("Request sent: "));
|
||||
Serial.println(tcpIpInstance->getMessage().substring(0, 100));
|
||||
Serial.println(tcpIpInstance->getCurrentMessage().substring(0, 100));
|
||||
} else {
|
||||
Serial.print("UNKNOWN!: ");
|
||||
}
|
||||
@ -127,13 +129,17 @@ void networkFilter(int numberOfNetworks, MeshBackendBase &meshInstance) {
|
||||
uint64_t targetNodeID = stringToUint64(currentSSID.substring(meshNameIndex + meshInstance.getMeshName().length()));
|
||||
|
||||
if (targetNodeID < stringToUint64(meshInstance.getNodeID())) {
|
||||
MeshBackendBase::connectionQueue.push_back(NetworkInfo(networkIndex));
|
||||
if (EspnowMeshBackend *espnowInstance = meshBackendCast<EspnowMeshBackend *>(&meshInstance)) {
|
||||
espnowInstance->connectionQueue().push_back(networkIndex);
|
||||
} else if (TcpIpMeshBackend *tcpIpInstance = meshBackendCast<TcpIpMeshBackend *>(&meshInstance)) {
|
||||
tcpIpInstance->connectionQueue().push_back(networkIndex);
|
||||
} else {
|
||||
Serial.println(String(F("Invalid mesh backend!")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char broadcastMetadataDelimiter = 23; // 23 = End-of-Transmission-Block (ETB) control character in ASCII
|
||||
|
||||
/**
|
||||
Callback used to decide which broadcast messages to accept. Only called for the first transmission in each broadcast.
|
||||
@ -147,10 +153,8 @@ const char broadcastMetadataDelimiter = 23; // 23 = End-of-Transmission-Block (E
|
||||
@return True if the broadcast should be accepted. False otherwise.
|
||||
*/
|
||||
bool broadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance) {
|
||||
/**
|
||||
This example broadcastFilter will accept a transmission if it contains the broadcastMetadataDelimiter
|
||||
and as metaData either no targetMeshName or a targetMeshName that matches the MeshName of meshInstance.
|
||||
*/
|
||||
// This example broadcastFilter will accept a transmission if it contains the broadcastMetadataDelimiter
|
||||
// and as metaData either no targetMeshName or a targetMeshName that matches the MeshName of meshInstance.
|
||||
|
||||
int32_t metadataEndIndex = firstTransmission.indexOf(broadcastMetadataDelimiter);
|
||||
|
||||
@ -230,7 +234,7 @@ void loop() {
|
||||
|
||||
uint32_t startTime = millis();
|
||||
espnowNode.attemptTransmission(espnowNode.getMessage());
|
||||
Serial.println("Scan and " + String(MeshBackendBase::latestTransmissionOutcomes.size()) + " transmissions done in " + String(millis() - startTime) + " ms.");
|
||||
Serial.println("Scan and " + String(espnowNode.latestTransmissionOutcomes().size()) + " transmissions done in " + String(millis() - startTime) + " ms.");
|
||||
|
||||
timeOfLastScan = millis();
|
||||
|
||||
@ -239,23 +243,23 @@ void loop() {
|
||||
espnowDelay(100);
|
||||
|
||||
// One way to check how attemptTransmission worked out
|
||||
if (MeshBackendBase::latestTransmissionSuccessful()) {
|
||||
if (espnowNode.latestTransmissionSuccessful()) {
|
||||
Serial.println(F("Transmission successful."));
|
||||
}
|
||||
|
||||
// Another way to check how attemptTransmission worked out
|
||||
if (MeshBackendBase::latestTransmissionOutcomes.empty()) {
|
||||
if (espnowNode.latestTransmissionOutcomes().empty()) {
|
||||
Serial.println(F("No mesh AP found."));
|
||||
} else {
|
||||
for (TransmissionResult &transmissionResult : MeshBackendBase::latestTransmissionOutcomes) {
|
||||
if (transmissionResult.transmissionStatus == TS_TRANSMISSION_FAILED) {
|
||||
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionResult.SSID);
|
||||
} else if (transmissionResult.transmissionStatus == TS_CONNECTION_FAILED) {
|
||||
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionResult.SSID);
|
||||
} else if (transmissionResult.transmissionStatus == TS_TRANSMISSION_COMPLETE) {
|
||||
for (TransmissionOutcome &transmissionOutcome : espnowNode.latestTransmissionOutcomes()) {
|
||||
if (transmissionOutcome.transmissionStatus() == TS_TRANSMISSION_FAILED) {
|
||||
Serial.println(String(F("Transmission failed to mesh AP ")) + transmissionOutcome.SSID());
|
||||
} else if (transmissionOutcome.transmissionStatus() == TS_CONNECTION_FAILED) {
|
||||
Serial.println(String(F("Connection failed to mesh AP ")) + transmissionOutcome.SSID());
|
||||
} else if (transmissionOutcome.transmissionStatus() == TS_TRANSMISSION_COMPLETE) {
|
||||
// No need to do anything, transmission was successful.
|
||||
} else {
|
||||
Serial.println(String(F("Invalid transmission status for ")) + transmissionResult.SSID + String(F("!")));
|
||||
Serial.println(String(F("Invalid transmission status for ")) + transmissionOutcome.SSID() + String(F("!")));
|
||||
assert(F("Invalid transmission status returned from responseHandler!") && false);
|
||||
}
|
||||
}
|
||||
@ -276,14 +280,16 @@ void loop() {
|
||||
|
||||
Serial.println("\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.requestEncryptedConnection(MeshBackendBase::connectionQueue[0].BSSID) == ECS_CONNECTION_ESTABLISHED) {
|
||||
if (espnowNode.connectionQueue()[0].getBSSID(targetBSSID) && espnowNode.requestEncryptedConnection(targetBSSID) == ECS_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 = macToString(MeshBackendBase::connectionQueue[0].BSSID);
|
||||
String peerMac = macToString(targetBSSID);
|
||||
|
||||
Serial.println("Encrypted ESP-NOW connection with " + peerMac + " established!");
|
||||
|
||||
// Making a transmission now will cause messages to MeshBackendBase::connectionQueue[0].BSSID to be encrypted.
|
||||
// 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);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
@ -291,11 +297,11 @@ void loop() {
|
||||
|
||||
// A connection can be serialized and stored for later use.
|
||||
// Note that this saves the current state only, so if encrypted communication between the nodes happen after this, the stored state is invalid.
|
||||
String serializedEncryptedConnection = EspnowMeshBackend::serializeEncryptedConnection(MeshBackendBase::connectionQueue[0].BSSID);
|
||||
String serializedEncryptedConnection = EspnowMeshBackend::serializeEncryptedConnection(targetBSSID);
|
||||
|
||||
Serial.println();
|
||||
// We can remove an encrypted connection like so.
|
||||
espnowNode.removeEncryptedConnection(MeshBackendBase::connectionQueue[0].BSSID);
|
||||
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;
|
||||
@ -304,7 +310,7 @@ void loop() {
|
||||
espnowDelay(100); // Wait for response.
|
||||
Serial.println("Cannot read the encrypted response...");
|
||||
|
||||
// Let's re-add our stored connection so we can communicate properly with MeshBackendBase::connectionQueue[0].BSSID again!
|
||||
// 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;
|
||||
@ -314,21 +320,28 @@ void loop() {
|
||||
|
||||
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(MeshBackendBase::connectionQueue[0].BSSID);
|
||||
encrypted_connection_removal_outcome_t removalOutcome = espnowNode.requestEncryptedConnectionRemoval(targetBSSID);
|
||||
if (removalOutcome == ECRO_REMOVAL_SUCCEEDED) {
|
||||
Serial.println(peerMac + " is no longer encrypted!\n");
|
||||
Serial.println(peerMac + " 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);
|
||||
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(MeshBackendBase::connectionQueue[0].BSSID, 1000) == ECS_CONNECTION_ESTABLISHED) {
|
||||
if (espnowNode.requestTemporaryEncryptedConnection(targetBSSID, 1000) == ECS_CONNECTION_ESTABLISHED) {
|
||||
espnowDelay(42);
|
||||
uint32_t remainingDuration = 0;
|
||||
EspnowMeshBackend::getConnectionInfo(MeshBackendBase::connectionQueue[0].BSSID, &remainingDuration);
|
||||
EspnowMeshBackend::getConnectionInfo(targetBSSID, &remainingDuration);
|
||||
|
||||
espnowMessage = "Messages this node sends to " + peerMac + " will be encrypted for " + String(remainingDuration) + " ms more.";
|
||||
Serial.println("\nTransmitting: " + espnowMessage);
|
||||
espnowNode.attemptTransmission(espnowMessage, false);
|
||||
|
||||
EspnowMeshBackend::getConnectionInfo(MeshBackendBase::connectionQueue[0].BSSID, &remainingDuration);
|
||||
EspnowMeshBackend::getConnectionInfo(targetBSSID, &remainingDuration);
|
||||
espnowDelay(remainingDuration + 100);
|
||||
|
||||
espnowMessage = "Due to encrypted connection expiration, this message is no longer encrypted when received by node " + peerMac;
|
||||
|
@ -50,6 +50,9 @@ std::list<PeerRequestLog> EspnowMeshBackend::peerRequestConfirmationsToSend = {}
|
||||
|
||||
std::vector<EncryptedConnectionLog> EspnowMeshBackend::encryptedConnections = {};
|
||||
|
||||
std::vector<EspnowNetworkInfo> EspnowMeshBackend::_connectionQueue = {};
|
||||
std::vector<TransmissionOutcome> EspnowMeshBackend::_latestTransmissionOutcomes = {};
|
||||
|
||||
uint32_t EspnowMeshBackend::_espnowTransmissionTimeoutMs = 40;
|
||||
uint32_t EspnowMeshBackend::_espnowRetransmissionIntervalMs = 15;
|
||||
|
||||
@ -133,6 +136,16 @@ void EspnowMeshBackend::begin()
|
||||
activateEspnow();
|
||||
}
|
||||
|
||||
std::vector<EspnowNetworkInfo> & EspnowMeshBackend::connectionQueue()
|
||||
{
|
||||
return _connectionQueue;
|
||||
}
|
||||
|
||||
std::vector<TransmissionOutcome> & EspnowMeshBackend::latestTransmissionOutcomes()
|
||||
{
|
||||
return _latestTransmissionOutcomes;
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::performEspnowMaintainance()
|
||||
{
|
||||
// Doing this during an ESP-NOW transmission could invalidate iterators
|
||||
@ -1671,7 +1684,7 @@ encrypted_connection_removal_outcome_t EspnowMeshBackend::removeEncryptedConnect
|
||||
}
|
||||
}
|
||||
|
||||
encrypted_connection_removal_outcome_t EspnowMeshBackend::removeEncryptedConnectionUnprotected(uint8_t *peerMac, std::vector<EncryptedConnectionLog>::iterator *resultingIterator)
|
||||
encrypted_connection_removal_outcome_t EspnowMeshBackend::removeEncryptedConnectionUnprotected(const uint8_t *peerMac, std::vector<EncryptedConnectionLog>::iterator *resultingIterator)
|
||||
{
|
||||
connectionLogIterator connectionIterator = getEncryptedConnectionIterator(peerMac, encryptedConnections);
|
||||
return removeEncryptedConnectionUnprotected(connectionIterator, resultingIterator);
|
||||
@ -1908,52 +1921,39 @@ uint8_t *EspnowMeshBackend::getEncryptedMac(const uint8_t *peerMac, uint8_t *res
|
||||
}
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels)
|
||||
void EspnowMeshBackend::prepareForTransmission(const String &message, bool scan, bool scanAllWiFiChannels)
|
||||
{
|
||||
MutexTracker mutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
setMessage(message);
|
||||
|
||||
latestTransmissionOutcomes.clear();
|
||||
latestTransmissionOutcomes().clear();
|
||||
|
||||
if(scan)
|
||||
{
|
||||
connectionQueue().clear();
|
||||
scanForNetworks(scanAllWiFiChannels);
|
||||
}
|
||||
|
||||
for(NetworkInfo ¤tNetwork : connectionQueue)
|
||||
{
|
||||
String currentSSID = "";
|
||||
int currentWiFiChannel = NETWORK_INFO_DEFAULT_INT;
|
||||
uint8_t *currentBSSID = NULL;
|
||||
|
||||
// If a BSSID has been assigned, it is prioritized over an assigned networkIndex since the networkIndex is more likely to change.
|
||||
if(currentNetwork.BSSID != NULL)
|
||||
{
|
||||
currentSSID = currentNetwork.SSID;
|
||||
currentWiFiChannel = currentNetwork.wifiChannel;
|
||||
currentBSSID = currentNetwork.BSSID;
|
||||
}
|
||||
else // Use only networkIndex
|
||||
|
||||
transmission_status_t EspnowMeshBackend::initiateTransmission(const String &message, const EspnowNetworkInfo &recipientInfo)
|
||||
{
|
||||
currentSSID = WiFi.SSID(currentNetwork.networkIndex);
|
||||
currentWiFiChannel = WiFi.channel(currentNetwork.networkIndex);
|
||||
currentBSSID = WiFi.BSSID(currentNetwork.networkIndex);
|
||||
}
|
||||
uint8_t targetBSSID[6] {0};
|
||||
|
||||
assert(recipientInfo.BSSID() != nullptr); // We need at least the BSSID to connect
|
||||
recipientInfo.getBSSID(targetBSSID);
|
||||
|
||||
if(verboseMode()) // Avoid string generation if not required
|
||||
{
|
||||
printAPInfo(currentNetwork.networkIndex, currentSSID, currentWiFiChannel);
|
||||
printAPInfo(recipientInfo);
|
||||
verboseModePrint(F(""));
|
||||
}
|
||||
|
||||
return initiateTransmissionKernel(message, targetBSSID);
|
||||
}
|
||||
|
||||
transmission_status_t EspnowMeshBackend::initiateTransmissionKernel(const String &message, const uint8_t *targetBSSID)
|
||||
{
|
||||
uint32_t transmissionStartTime = millis();
|
||||
transmission_status_t transmissionResult = sendRequest(getMessage(), currentBSSID);
|
||||
transmission_status_t transmissionResult = sendRequest(message, targetBSSID);
|
||||
|
||||
uint32_t transmissionDuration = millis() - transmissionStartTime;
|
||||
|
||||
@ -1967,9 +1967,11 @@ void EspnowMeshBackend::attemptTransmission(const String &message, bool scan, bo
|
||||
}
|
||||
}
|
||||
|
||||
latestTransmissionOutcomes.push_back(TransmissionResult{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
return transmissionResult;
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::printTransmissionStatistics()
|
||||
{
|
||||
if(verboseMode() && successfulTransmissions_AT > 0) // Avoid calculations if not required
|
||||
{
|
||||
verboseModePrint("Average duration of successful transmissions: " + String(totalDurationWhenSuccessful_AT/successfulTransmissions_AT) + " ms.");
|
||||
@ -1981,6 +1983,82 @@ void EspnowMeshBackend::attemptTransmission(const String &message, bool scan, bo
|
||||
}
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels)
|
||||
{
|
||||
MutexTracker mutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
prepareForTransmission(message, scan, scanAllWiFiChannels);
|
||||
|
||||
for(EspnowNetworkInfo ¤tNetwork : connectionQueue())
|
||||
{
|
||||
transmission_status_t transmissionResult = initiateTransmission(getMessage(), currentNetwork);
|
||||
|
||||
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
}
|
||||
|
||||
printTransmissionStatistics();
|
||||
}
|
||||
|
||||
transmission_status_t EspnowMeshBackend::attemptTransmission(const String &message, const EspnowNetworkInfo &recipientInfo)
|
||||
{
|
||||
MutexTracker mutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.");
|
||||
return TS_CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
return initiateTransmission(message, recipientInfo);
|
||||
}
|
||||
|
||||
encrypted_connection_status_t EspnowMeshBackend::initiateAutoEncryptingConnection(const EspnowNetworkInfo &recipientInfo, bool createPermanentConnection, uint8_t *targetBSSID, EncryptedConnectionLog **encryptedConnection)
|
||||
{
|
||||
assert(recipientInfo.BSSID() != nullptr); // We need at least the BSSID to connect
|
||||
recipientInfo.getBSSID(targetBSSID);
|
||||
|
||||
if(verboseMode()) // Avoid string generation if not required
|
||||
{
|
||||
printAPInfo(recipientInfo);
|
||||
verboseModePrint(F(""));
|
||||
}
|
||||
|
||||
*encryptedConnection = getEncryptedConnection(targetBSSID);
|
||||
encrypted_connection_status_t connectionStatus = ECS_MAX_CONNECTIONS_REACHED_SELF;
|
||||
|
||||
if(createPermanentConnection)
|
||||
connectionStatus = requestEncryptedConnection(targetBSSID);
|
||||
else
|
||||
connectionStatus = requestFlexibleTemporaryEncryptedConnection(targetBSSID, getAutoEncryptionDuration());
|
||||
|
||||
return connectionStatus;
|
||||
}
|
||||
|
||||
transmission_status_t EspnowMeshBackend::initiateAutoEncryptingTransmission(const String &message, const uint8_t *targetBSSID, encrypted_connection_status_t connectionStatus)
|
||||
{
|
||||
transmission_status_t transmissionResult = TS_CONNECTION_FAILED;
|
||||
|
||||
if(connectionStatus == ECS_CONNECTION_ESTABLISHED)
|
||||
{
|
||||
transmissionResult = initiateTransmissionKernel(message, targetBSSID);
|
||||
}
|
||||
|
||||
return transmissionResult;
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::finalizeAutoEncryptingConnection(const uint8_t *targetBSSID, const EncryptedConnectionLog *encryptedConnection, bool createPermanentConnection)
|
||||
{
|
||||
if(!encryptedConnection && !createPermanentConnection)
|
||||
{
|
||||
// Remove any connection that was added during the transmission attempt.
|
||||
removeEncryptedConnectionUnprotected(targetBSSID);
|
||||
}
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message, bool scan, bool scanAllWiFiChannels, bool createPermanentConnections)
|
||||
{
|
||||
MutexTracker outerMutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
|
||||
@ -1990,19 +2068,16 @@ void EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message,
|
||||
return;
|
||||
}
|
||||
|
||||
setMessage(message);
|
||||
|
||||
latestTransmissionOutcomes.clear();
|
||||
|
||||
if(scan)
|
||||
{
|
||||
scanForNetworks(scanAllWiFiChannels);
|
||||
}
|
||||
prepareForTransmission(message, scan, scanAllWiFiChannels);
|
||||
|
||||
outerMutexTracker.releaseMutex();
|
||||
|
||||
for(NetworkInfo ¤tNetwork : connectionQueue)
|
||||
for(EspnowNetworkInfo ¤tNetwork : connectionQueue())
|
||||
{
|
||||
uint8_t currentBSSID[6] {0};
|
||||
EncryptedConnectionLog *encryptedConnection = nullptr;
|
||||
encrypted_connection_status_t connectionStatus = initiateAutoEncryptingConnection(currentNetwork, createPermanentConnections, currentBSSID, &encryptedConnection);
|
||||
|
||||
MutexTracker innerMutexTracker = MutexTracker(_espnowTransmissionMutex);
|
||||
if(!innerMutexTracker.mutexCaptured())
|
||||
{
|
||||
@ -2010,87 +2085,34 @@ void EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message,
|
||||
return;
|
||||
}
|
||||
|
||||
String currentSSID = "";
|
||||
int currentWiFiChannel = NETWORK_INFO_DEFAULT_INT;
|
||||
uint8_t *currentBSSID = NULL;
|
||||
transmission_status_t transmissionResult = initiateAutoEncryptingTransmission(getMessage(), currentBSSID, connectionStatus);
|
||||
|
||||
// If a BSSID has been assigned, it is prioritized over an assigned networkIndex since the networkIndex is more likely to change.
|
||||
if(currentNetwork.BSSID != NULL)
|
||||
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
|
||||
finalizeAutoEncryptingConnection(currentBSSID, encryptedConnection, createPermanentConnections);
|
||||
}
|
||||
|
||||
printTransmissionStatistics();
|
||||
}
|
||||
|
||||
transmission_status_t EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message, const EspnowNetworkInfo &recipientInfo, bool createPermanentConnection)
|
||||
{
|
||||
currentSSID = currentNetwork.SSID;
|
||||
currentWiFiChannel = currentNetwork.wifiChannel;
|
||||
currentBSSID = currentNetwork.BSSID;
|
||||
}
|
||||
else // Use only networkIndex
|
||||
uint8_t targetBSSID[6] {0};
|
||||
EncryptedConnectionLog *encryptedConnection = nullptr;
|
||||
encrypted_connection_status_t connectionStatus = initiateAutoEncryptingConnection(recipientInfo, createPermanentConnection, targetBSSID, &encryptedConnection);
|
||||
|
||||
MutexTracker mutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
currentSSID = WiFi.SSID(currentNetwork.networkIndex);
|
||||
currentWiFiChannel = WiFi.channel(currentNetwork.networkIndex);
|
||||
currentBSSID = WiFi.BSSID(currentNetwork.networkIndex);
|
||||
assert(false && "ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.");
|
||||
return TS_CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
if(verboseMode()) // Avoid string generation if not required
|
||||
{
|
||||
printAPInfo(currentNetwork.networkIndex, currentSSID, currentWiFiChannel);
|
||||
verboseModePrint(F(""));
|
||||
}
|
||||
transmission_status_t transmissionResult = initiateAutoEncryptingTransmission(message, targetBSSID, connectionStatus);
|
||||
|
||||
EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(currentBSSID);
|
||||
encrypted_connection_status_t connectionStatus = ECS_MAX_CONNECTIONS_REACHED_SELF;
|
||||
finalizeAutoEncryptingConnection(targetBSSID, encryptedConnection, createPermanentConnection);
|
||||
|
||||
innerMutexTracker.releaseMutex();
|
||||
|
||||
if(createPermanentConnections)
|
||||
connectionStatus = requestEncryptedConnection(currentBSSID);
|
||||
else
|
||||
connectionStatus = requestFlexibleTemporaryEncryptedConnection(currentBSSID, getAutoEncryptionDuration());
|
||||
|
||||
innerMutexTracker = MutexTracker(_espnowTransmissionMutex);
|
||||
if(!innerMutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! Unable to recapture Mutex in attemptAutoEncryptingTransmission. Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(connectionStatus == ECS_CONNECTION_ESTABLISHED)
|
||||
{
|
||||
uint32_t transmissionStartTime = millis();
|
||||
transmission_status_t transmissionResult = sendRequest(getMessage(), currentBSSID);
|
||||
|
||||
uint32_t transmissionDuration = millis() - transmissionStartTime;
|
||||
|
||||
if(verboseMode() && transmissionResult == TS_TRANSMISSION_COMPLETE) // Avoid calculations if not required
|
||||
{
|
||||
totalDurationWhenSuccessful_AT += transmissionDuration;
|
||||
successfulTransmissions_AT++;
|
||||
if(transmissionDuration > maxTransmissionDuration_AT)
|
||||
{
|
||||
maxTransmissionDuration_AT = transmissionDuration;
|
||||
}
|
||||
}
|
||||
|
||||
latestTransmissionOutcomes.push_back(TransmissionResult{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
}
|
||||
else
|
||||
{
|
||||
latestTransmissionOutcomes.push_back(TransmissionResult{.origin = currentNetwork, .transmissionStatus = TS_CONNECTION_FAILED});
|
||||
}
|
||||
|
||||
if(!encryptedConnection && !createPermanentConnections)
|
||||
{
|
||||
// Remove any connection that was added during the transmission attempt.
|
||||
removeEncryptedConnectionUnprotected(currentBSSID);
|
||||
}
|
||||
}
|
||||
|
||||
if(verboseMode() && successfulTransmissions_AT > 0) // Avoid calculations if not required
|
||||
{
|
||||
verboseModePrint("Average duration of successful transmissions: " + String(totalDurationWhenSuccessful_AT/successfulTransmissions_AT) + " ms.");
|
||||
verboseModePrint("Maximum duration of successful transmissions: " + String(maxTransmissionDuration_AT) + " ms.");
|
||||
}
|
||||
else
|
||||
{
|
||||
verboseModePrint("No successful transmission.");
|
||||
}
|
||||
return transmissionResult;
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::broadcast(const String &message)
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include "Crypto.h"
|
||||
#include "EspnowNetworkInfo.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -130,6 +131,24 @@ public:
|
||||
|
||||
~EspnowMeshBackend() override;
|
||||
|
||||
/**
|
||||
* Returns a vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
* This vector is unique for each mesh backend.
|
||||
* The connectionQueue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes.
|
||||
* WiFi connections will start with connectionQueue[0] and then incrementally proceed to higher vector positions.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
std::vector<EspnowNetworkInfo> & connectionQueue();
|
||||
|
||||
/**
|
||||
* Returns a vector with the TransmissionOutcome for each AP to which a transmission was attempted during the latest attemptTransmission call.
|
||||
* This vector is unique for each mesh backend.
|
||||
* The latestTransmissionOutcomes vector is cleared before each new transmission attempt.
|
||||
* Connection attempts are indexed in the same order they were attempted.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
std::vector<TransmissionOutcome> & latestTransmissionOutcomes() override;
|
||||
|
||||
/**
|
||||
* Initialises the node.
|
||||
*/
|
||||
@ -178,6 +197,12 @@ public:
|
||||
|
||||
void attemptTransmission(const String &message, bool scan = true, bool scanAllWiFiChannels = false) override;
|
||||
|
||||
/**
|
||||
* Transmit message to a single recipient without changing the local transmission state.
|
||||
* Will not change connectionQueue, latestTransmissionOutcomes or stored message.
|
||||
*/
|
||||
transmission_status_t attemptTransmission(const String &message, const EspnowNetworkInfo &recipientInfo);
|
||||
|
||||
/*
|
||||
* Will ensure that an encrypted connection exists to each target node before sending the message,
|
||||
* establishing a temporary encrypted connection with duration getAutoEncryptionDuration() first if neccessary.
|
||||
@ -201,6 +226,12 @@ public:
|
||||
*/
|
||||
void attemptAutoEncryptingTransmission(const String &message, bool scan = true, bool scanAllWiFiChannels = false, bool createPermanentConnections = false);
|
||||
|
||||
/**
|
||||
* 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 createPermanentConnection = false);
|
||||
|
||||
/**
|
||||
* Send a message simultaneously to all nearby nodes which have ESP-NOW activated.
|
||||
* A broadcast is always treated as a request by the receiving node.
|
||||
@ -535,6 +566,9 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
static std::vector<EspnowNetworkInfo> _connectionQueue;
|
||||
static std::vector<TransmissionOutcome> _latestTransmissionOutcomes;
|
||||
|
||||
typedef std::vector<EncryptedConnectionLog>::iterator connectionLogIterator;
|
||||
static connectionLogIterator connectionLogEndIterator();
|
||||
|
||||
@ -564,7 +598,7 @@ 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(uint8_t *peerMac, std::vector<EncryptedConnectionLog>::iterator *resultingIterator = nullptr);
|
||||
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);
|
||||
|
||||
/**
|
||||
@ -791,6 +825,15 @@ 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);
|
||||
void printTransmissionStatistics();
|
||||
|
||||
encrypted_connection_status_t initiateAutoEncryptingConnection(const EspnowNetworkInfo &recipientInfo, bool createPermanentConnection, uint8_t *targetBSSID, EncryptedConnectionLog **encryptedConnection);
|
||||
transmission_status_t initiateAutoEncryptingTransmission(const String &message, const uint8_t *targetBSSID, encrypted_connection_status_t connectionStatus);
|
||||
void finalizeAutoEncryptingConnection(const uint8_t *targetBSSID, const EncryptedConnectionLog *encryptedConnection, bool createPermanentConnection);
|
||||
|
||||
// Used for verboseMode printing in attemptTransmission, _AT suffix used to reduce namespace clutter
|
||||
uint32_t totalDurationWhenSuccessful_AT = 0;
|
||||
uint32_t successfulTransmissions_AT = 0;
|
||||
|
32
libraries/ESP8266WiFiMesh/src/EspnowNetworkInfo.cpp
Normal file
32
libraries/ESP8266WiFiMesh/src/EspnowNetworkInfo.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 "EspnowNetworkInfo.h"
|
||||
|
||||
EspnowNetworkInfo::EspnowNetworkInfo(int networkIndex) : NetworkInfoBase(networkIndex) { };
|
||||
|
||||
EspnowNetworkInfo::EspnowNetworkInfo(const uint8_t BSSID[6], const String &SSID, int32_t wifiChannel, uint8_t encryptionType, int32_t RSSI , bool isHidden)
|
||||
: NetworkInfoBase(SSID, wifiChannel, BSSID, encryptionType, RSSI, isHidden)
|
||||
{ }
|
||||
|
43
libraries/ESP8266WiFiMesh/src/EspnowNetworkInfo.h
Normal file
43
libraries/ESP8266WiFiMesh/src/EspnowNetworkInfo.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ESPNOWNETWORKINFO_H__
|
||||
#define __ESPNOWNETWORKINFO_H__
|
||||
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
class EspnowNetworkInfo : public NetworkInfoBase {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Automatically fill in the rest of the network info using networkIndex and the WiFi scan results.
|
||||
*/
|
||||
EspnowNetworkInfo(int networkIndex);
|
||||
|
||||
EspnowNetworkInfo(const uint8_t BSSID[6], const String &SSID = defaultSSID, int32_t wifiChannel = defaultWifiChannel, uint8_t encryptionType = defaultEncryptionType,
|
||||
int32_t RSSI = defaultRSSI, bool isHidden = defaultIsHidden);
|
||||
};
|
||||
|
||||
#endif
|
@ -17,13 +17,14 @@
|
||||
*/
|
||||
|
||||
#include "MeshBackendBase.h"
|
||||
#include "TypeConversionFunctions.h"
|
||||
#include "MutexTracker.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
MeshBackendBase *MeshBackendBase::apController = nullptr;
|
||||
|
||||
std::vector<NetworkInfo> MeshBackendBase::connectionQueue = {};
|
||||
std::vector<TransmissionResult> MeshBackendBase::latestTransmissionOutcomes = {};
|
||||
bool MeshBackendBase::_scanMutex = false;
|
||||
|
||||
bool MeshBackendBase::_printWarnings = true;
|
||||
|
||||
@ -231,11 +232,11 @@ bool MeshBackendBase::getAPHidden() {return _apHidden;}
|
||||
|
||||
bool MeshBackendBase::latestTransmissionSuccessful()
|
||||
{
|
||||
if(MeshBackendBase::latestTransmissionOutcomes.empty())
|
||||
if(latestTransmissionOutcomes().empty())
|
||||
return false;
|
||||
else
|
||||
for(TransmissionResult &transmissionResult : MeshBackendBase::latestTransmissionOutcomes)
|
||||
if(transmissionResult.transmissionStatus != TS_TRANSMISSION_COMPLETE)
|
||||
for(TransmissionOutcome &transmissionOutcome : latestTransmissionOutcomes())
|
||||
if(transmissionOutcome.transmissionStatus() != TS_TRANSMISSION_COMPLETE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -243,10 +244,16 @@ bool MeshBackendBase::latestTransmissionSuccessful()
|
||||
|
||||
void MeshBackendBase::scanForNetworks(bool scanAllWiFiChannels)
|
||||
{
|
||||
MutexTracker mutexTracker(_scanMutex);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! Scan already in progress. Don't call scanForNetworks from callbacks as this may corrupt program state! Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
verboseModePrint(F("Scanning... "), false);
|
||||
|
||||
/* Scan for APs */
|
||||
connectionQueue.clear();
|
||||
|
||||
// If scanAllWiFiChannels is true, scanning will cause the WiFi radio to cycle through all WiFi channels.
|
||||
// This means existing WiFi connections are likely to break or work poorly if done frequently.
|
||||
@ -264,14 +271,20 @@ void MeshBackendBase::scanForNetworks(bool scanAllWiFiChannels)
|
||||
getNetworkFilter()(n, *this); // Update the connectionQueue.
|
||||
}
|
||||
|
||||
void MeshBackendBase::printAPInfo(const int apNetworkIndex, const String &apSSID, const int apWiFiChannel)
|
||||
void MeshBackendBase::printAPInfo(const NetworkInfoBase &apNetworkInfo)
|
||||
{
|
||||
verboseModePrint(String(F("AP acquired: ")) + apSSID + String(F(", Ch:")) + String(apWiFiChannel) + " ", false);
|
||||
String mainNetworkIdentifier = apNetworkInfo.SSID();
|
||||
if(mainNetworkIdentifier == NetworkInfoBase::defaultSSID) // If SSID not provided, use BSSID instead
|
||||
{
|
||||
mainNetworkIdentifier = macToString(apNetworkInfo.BSSID());
|
||||
}
|
||||
|
||||
if(apNetworkIndex != NETWORK_INFO_DEFAULT_INT)
|
||||
verboseModePrint(String(F("AP acquired: ")) + mainNetworkIdentifier + String(F(", Ch:")) + String(apNetworkInfo.wifiChannel()) + " ", false);
|
||||
|
||||
if(apNetworkInfo.RSSI() != NetworkInfoBase::defaultRSSI)
|
||||
{
|
||||
verboseModePrint("(" + String(WiFi.RSSI(apNetworkIndex)) + String(F("dBm) ")) +
|
||||
(WiFi.encryptionType(apNetworkIndex) == ENC_TYPE_NONE ? String(F("open")) : ""), false);
|
||||
verboseModePrint("(" + String(apNetworkInfo.RSSI()) + String(F("dBm) ")) +
|
||||
(apNetworkInfo.encryptionType() == ENC_TYPE_NONE ? String(F("open")) : ""), false);
|
||||
}
|
||||
|
||||
verboseModePrint(F("... "), false);
|
||||
|
@ -20,7 +20,8 @@
|
||||
#define __MESHBACKENDBASE_H__
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "TransmissionResult.h"
|
||||
#include "TransmissionOutcome.h"
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
const String ESP8266_MESH_EMPTY_STRING = "";
|
||||
|
||||
@ -45,25 +46,18 @@ public:
|
||||
virtual ~MeshBackendBase();
|
||||
|
||||
/**
|
||||
* A vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
* The connectionQueue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes.
|
||||
* WiFi connections will start with connectionQueue[0] and then incrementally proceed to higher vector positions.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
static std::vector<NetworkInfo> connectionQueue;
|
||||
|
||||
/**
|
||||
* A vector with the TransmissionResult for each AP to which a transmission was attempted during the latest attemptTransmission call.
|
||||
* Returns a vector with the TransmissionOutcome for each AP to which a transmission was attempted during the latest attemptTransmission call.
|
||||
* This vector is unique for each mesh backend.
|
||||
* The latestTransmissionOutcomes vector is cleared before each new transmission attempt.
|
||||
* Connection attempts are indexed in the same order they were attempted.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
static std::vector<TransmissionResult> latestTransmissionOutcomes;
|
||||
virtual std::vector<TransmissionOutcome> & latestTransmissionOutcomes() = 0;
|
||||
|
||||
/**
|
||||
* @return True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
*/
|
||||
static bool latestTransmissionSuccessful();
|
||||
bool latestTransmissionSuccessful();
|
||||
|
||||
/**
|
||||
* Initialises the node.
|
||||
@ -271,7 +265,7 @@ public:
|
||||
protected:
|
||||
|
||||
virtual void scanForNetworks(bool scanAllWiFiChannels);
|
||||
virtual void printAPInfo(const int apNetworkIndex, const String &apSSID, const int apWiFiChannel);
|
||||
virtual void printAPInfo(const NetworkInfoBase &apNetworkInfo);
|
||||
|
||||
/**
|
||||
* Called just before we activate the AP.
|
||||
@ -287,6 +281,8 @@ protected:
|
||||
|
||||
void setClassType(mesh_backend_t classType);
|
||||
|
||||
static bool _scanMutex;
|
||||
|
||||
private:
|
||||
|
||||
mesh_backend_t _classType;
|
||||
|
@ -23,6 +23,29 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************
|
||||
* NOTE!
|
||||
*
|
||||
* This class is deprecated and will be removed in core version 3.0.0.
|
||||
* If you are still using this class, please consider migrating to the new API shown in
|
||||
* the EspnowNetworkInfo.h or TcpIpNetworkInfo.h source files.
|
||||
*
|
||||
* TODO: delete this file.
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "NetworkInfo.h"
|
||||
|
||||
void NetworkInfo::copyBSSID(uint8_t newBSSID[6])
|
||||
@ -74,4 +97,3 @@ NetworkInfo & NetworkInfo::operator=(const NetworkInfo &other)
|
||||
networkIndex = other.networkIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,34 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************
|
||||
* NOTE!
|
||||
*
|
||||
* This class is deprecated and will be removed in core version 3.0.0.
|
||||
* If you are still using this class, please consider migrating to the new API shown in
|
||||
* the EspnowNetworkInfo.h or TcpIpNetworkInfo.h source files.
|
||||
*
|
||||
* TODO: delete this file.
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef __NETWORKINFO_H__
|
||||
#define __NETWORKINFO_H__
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
const int NETWORK_INFO_DEFAULT_INT = -1;
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
class NetworkInfo {
|
||||
|
||||
|
119
libraries/ESP8266WiFiMesh/src/NetworkInfoBase.cpp
Normal file
119
libraries/ESP8266WiFiMesh/src/NetworkInfoBase.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 "NetworkInfoBase.h"
|
||||
|
||||
const String NetworkInfoBase::defaultSSID = "";
|
||||
const int32_t NetworkInfoBase::defaultWifiChannel = NETWORK_INFO_DEFAULT_INT;
|
||||
const uint8_t NetworkInfoBase::defaultEncryptionType = 0;
|
||||
const int32_t NetworkInfoBase::defaultRSSI = ~0;
|
||||
const bool NetworkInfoBase::defaultIsHidden = false;
|
||||
|
||||
void NetworkInfoBase::storeBSSID(const uint8_t newBSSID[6])
|
||||
{
|
||||
if(newBSSID != nullptr)
|
||||
{
|
||||
if(_BSSID == nullptr)
|
||||
{
|
||||
_BSSID = _bssidArray;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
{
|
||||
_BSSID[i] = newBSSID[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_BSSID = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkInfoBase::NetworkInfoBase() {};
|
||||
|
||||
NetworkInfoBase::NetworkInfoBase(uint8_t networkIndex)
|
||||
{
|
||||
uint8_t *bssidPtr = nullptr;
|
||||
WiFi.getNetworkInfo(networkIndex, _SSID, _encryptionType, _RSSI, bssidPtr, _wifiChannel, _isHidden);
|
||||
storeBSSID(bssidPtr);
|
||||
}
|
||||
|
||||
NetworkInfoBase::NetworkInfoBase(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI, bool isHidden) :
|
||||
_SSID(SSID), _wifiChannel(wifiChannel), _encryptionType(encryptionType), _RSSI(RSSI), _isHidden(isHidden)
|
||||
{
|
||||
storeBSSID(BSSID);
|
||||
}
|
||||
|
||||
NetworkInfoBase::NetworkInfoBase(const NetworkInfoBase &other) : _SSID(other.SSID()), _wifiChannel(other.wifiChannel()), _encryptionType(other.encryptionType()),
|
||||
_RSSI(other.RSSI()), _isHidden(other.isHidden())
|
||||
{
|
||||
storeBSSID(other.BSSID());
|
||||
}
|
||||
|
||||
NetworkInfoBase & NetworkInfoBase::operator=(const NetworkInfoBase &other)
|
||||
{
|
||||
if(this != &other)
|
||||
{
|
||||
storeBSSID(other.BSSID());
|
||||
_SSID = other.SSID();
|
||||
_wifiChannel = other.wifiChannel();
|
||||
_encryptionType = other.encryptionType();
|
||||
_RSSI = other.RSSI();
|
||||
_isHidden = other.isHidden();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NetworkInfoBase::~NetworkInfoBase() { };
|
||||
|
||||
void NetworkInfoBase::setBSSID(const uint8_t BSSID[6]) { storeBSSID(BSSID); }
|
||||
const uint8_t *NetworkInfoBase::BSSID() const { return _BSSID; }
|
||||
uint8_t *NetworkInfoBase::getBSSID(uint8_t resultArray[6]) const
|
||||
{
|
||||
if(BSSID())
|
||||
{
|
||||
std::copy_n(_bssidArray, 6, resultArray);
|
||||
return resultArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkInfoBase::setSSID(String &SSID) { _SSID = SSID; }
|
||||
String NetworkInfoBase::SSID() const { return _SSID; }
|
||||
|
||||
void NetworkInfoBase::setWifiChannel(int32_t wifiChannel) { _wifiChannel = wifiChannel; }
|
||||
int32_t NetworkInfoBase::wifiChannel() const { return _wifiChannel; }
|
||||
|
||||
void NetworkInfoBase::setEncryptionType(uint8_t encryptionType) { _encryptionType = encryptionType; }
|
||||
uint8_t NetworkInfoBase::encryptionType() const { return _encryptionType; }
|
||||
|
||||
void NetworkInfoBase::setRSSI(int32_t RSSI) { _RSSI = RSSI; }
|
||||
int32_t NetworkInfoBase::RSSI() const { return _RSSI; }
|
||||
|
||||
void NetworkInfoBase::setIsHidden(bool isHidden) { _isHidden = isHidden; }
|
||||
bool NetworkInfoBase::isHidden() const { return _isHidden; }
|
101
libraries/ESP8266WiFiMesh/src/NetworkInfoBase.h
Normal file
101
libraries/ESP8266WiFiMesh/src/NetworkInfoBase.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORKINFOBASE_H__
|
||||
#define __NETWORKINFOBASE_H__
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
const int NETWORK_INFO_DEFAULT_INT = -1;
|
||||
|
||||
class NetworkInfoBase {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Automatically fill in the rest of the network info using networkIndex and the WiFi scan results.
|
||||
*/
|
||||
NetworkInfoBase(uint8_t networkIndex);
|
||||
|
||||
/**
|
||||
* Without giving channel and BSSID, connection time is longer.
|
||||
*/
|
||||
NetworkInfoBase(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI, bool isHidden);
|
||||
|
||||
NetworkInfoBase(const NetworkInfoBase &other);
|
||||
|
||||
NetworkInfoBase & operator=(const NetworkInfoBase &other);
|
||||
|
||||
void setBSSID(const uint8_t BSSID[6]);
|
||||
const uint8_t *BSSID() const;
|
||||
/**
|
||||
* @return If BSSID is set, a pointer to resultArray which will contain a copy of BSSID. nullptr otherwise.
|
||||
*/
|
||||
uint8_t *getBSSID(uint8_t resultArray[6]) const;
|
||||
|
||||
void setSSID(String &SSID);
|
||||
String SSID() const;
|
||||
|
||||
void setWifiChannel(int32_t wifiChannel);
|
||||
int32_t wifiChannel() const;
|
||||
|
||||
void setEncryptionType(uint8_t encryptionType);
|
||||
uint8_t encryptionType() const;
|
||||
|
||||
void setRSSI(int32_t RSSI);
|
||||
int32_t RSSI() const;
|
||||
|
||||
void setIsHidden(bool isHidden);
|
||||
bool isHidden() const;
|
||||
|
||||
static const String defaultSSID;
|
||||
static const int32_t defaultWifiChannel;
|
||||
static const uint8_t defaultEncryptionType;
|
||||
static const int32_t defaultRSSI;
|
||||
static const bool defaultIsHidden;
|
||||
|
||||
protected:
|
||||
|
||||
~NetworkInfoBase();
|
||||
|
||||
NetworkInfoBase();
|
||||
|
||||
/**
|
||||
* Copy newBSSID into _BSSID.
|
||||
* Prefer this method for changing NetworkInfo BSSID, unless you actually want to change the _BSSID pointer.
|
||||
*/
|
||||
void storeBSSID(const uint8_t newBSSID[6]);
|
||||
|
||||
private:
|
||||
|
||||
uint8_t _bssidArray[6] {0};
|
||||
uint8_t *_BSSID = nullptr;
|
||||
String _SSID = defaultSSID;
|
||||
int32_t _wifiChannel = defaultWifiChannel;
|
||||
uint8_t _encryptionType = defaultEncryptionType; // see enum wl_enc_type for values
|
||||
int32_t _RSSI = defaultRSSI;
|
||||
bool _isHidden = defaultIsHidden;
|
||||
};
|
||||
|
||||
#endif
|
@ -34,11 +34,16 @@ bool TcpIpMeshBackend::_tcpIpTransmissionMutex = false;
|
||||
String TcpIpMeshBackend::lastSSID = "";
|
||||
bool TcpIpMeshBackend::staticIPActivated = false;
|
||||
|
||||
String TcpIpMeshBackend::_temporaryMessage = "";
|
||||
|
||||
// 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.
|
||||
IPAddress TcpIpMeshBackend::staticIP = emptyIP;
|
||||
IPAddress TcpIpMeshBackend::gateway = IPAddress(192,168,4,1);
|
||||
IPAddress TcpIpMeshBackend::subnetMask = IPAddress(255,255,255,0);
|
||||
|
||||
std::vector<TcpIpNetworkInfo> TcpIpMeshBackend::_connectionQueue = {};
|
||||
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)
|
||||
@ -51,6 +56,16 @@ TcpIpMeshBackend::TcpIpMeshBackend(requestHandlerType requestHandler, responseHa
|
||||
setServerPort(serverPort);
|
||||
}
|
||||
|
||||
std::vector<TcpIpNetworkInfo> & TcpIpMeshBackend::connectionQueue()
|
||||
{
|
||||
return _connectionQueue;
|
||||
}
|
||||
|
||||
std::vector<TransmissionOutcome> & TcpIpMeshBackend::latestTransmissionOutcomes()
|
||||
{
|
||||
return _latestTransmissionOutcomes;
|
||||
}
|
||||
|
||||
void TcpIpMeshBackend::begin()
|
||||
{
|
||||
if(!TcpIpMeshBackend::getAPController()) // If there is no active AP controller
|
||||
@ -78,6 +93,20 @@ void TcpIpMeshBackend::deactivateAPHook()
|
||||
|
||||
bool TcpIpMeshBackend::transmissionInProgress(){return _tcpIpTransmissionMutex;}
|
||||
|
||||
void TcpIpMeshBackend::setTemporaryMessage(const String &newTemporaryMessage) {_temporaryMessage = newTemporaryMessage;}
|
||||
String TcpIpMeshBackend::getTemporaryMessage() {return _temporaryMessage;}
|
||||
void TcpIpMeshBackend::clearTemporaryMessage() {_temporaryMessage = "";}
|
||||
|
||||
String TcpIpMeshBackend::getCurrentMessage()
|
||||
{
|
||||
String message = getTemporaryMessage();
|
||||
|
||||
if(message == "") // If no temporary message stored
|
||||
message = getMessage();
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void TcpIpMeshBackend::setStaticIP(const IPAddress &newIP)
|
||||
{
|
||||
// Comment out the line below to remove static IP and use DHCP instead.
|
||||
@ -201,7 +230,7 @@ transmission_status_t TcpIpMeshBackend::exchangeInfo(WiFiClient &currClient)
|
||||
{
|
||||
verboseModePrint("Transmitting"); // Not storing strings in flash (via F()) to avoid performance impacts when using the string.
|
||||
|
||||
currClient.print(getMessage() + "\r");
|
||||
currClient.print(getCurrentMessage() + "\r");
|
||||
yield();
|
||||
|
||||
if (!waitForClientTransmission(currClient, _stationModeTimeoutMs))
|
||||
@ -347,6 +376,41 @@ transmission_status_t TcpIpMeshBackend::connectToNode(const String &targetSSID,
|
||||
return attemptDataTransfer();
|
||||
}
|
||||
|
||||
transmission_status_t TcpIpMeshBackend::initiateTransmission(const TcpIpNetworkInfo &recipientInfo)
|
||||
{
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
|
||||
assert(recipientInfo.SSID() != ""); // We need at least SSID to connect
|
||||
String targetSSID = recipientInfo.SSID();
|
||||
int32_t targetWiFiChannel = recipientInfo.wifiChannel();
|
||||
uint8_t targetBSSID[6] {0};
|
||||
recipientInfo.getBSSID(targetBSSID);
|
||||
|
||||
if(verboseMode()) // Avoid string generation if not required
|
||||
{
|
||||
printAPInfo(recipientInfo);
|
||||
}
|
||||
|
||||
return connectToNode(targetSSID, targetWiFiChannel, targetBSSID);
|
||||
}
|
||||
|
||||
void TcpIpMeshBackend::enterPostTransmissionState(bool concludingDisconnect)
|
||||
{
|
||||
if(WiFi.status() == WL_CONNECTED && staticIP != emptyIP && !staticIPActivated)
|
||||
{
|
||||
verboseModePrint(F("Reactivating static IP to allow for faster re-connects."));
|
||||
setStaticIP(staticIP);
|
||||
}
|
||||
|
||||
// If we do not want to be connected at end of transmission, disconnect here so we can re-enable static IP first (above).
|
||||
if(concludingDisconnect)
|
||||
{
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels, bool concludingDisconnect, bool initialDisconnect)
|
||||
{
|
||||
MutexTracker mutexTracker(_tcpIpTransmissionMutex);
|
||||
@ -364,66 +428,30 @@ void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, boo
|
||||
|
||||
setMessage(message);
|
||||
|
||||
latestTransmissionOutcomes.clear();
|
||||
latestTransmissionOutcomes().clear();
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
transmission_status_t transmissionResult = attemptDataTransfer();
|
||||
latestTransmissionOutcomes.push_back(TransmissionResult(connectionQueue.back(), transmissionResult));
|
||||
latestTransmissionOutcomes().push_back(TransmissionOutcome(connectionQueue().back(), transmissionResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(scan)
|
||||
{
|
||||
connectionQueue().clear();
|
||||
scanForNetworks(scanAllWiFiChannels);
|
||||
}
|
||||
|
||||
for(NetworkInfo ¤tNetwork : connectionQueue)
|
||||
for(TcpIpNetworkInfo ¤tNetwork : connectionQueue())
|
||||
{
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
transmission_status_t transmissionResult = initiateTransmission(currentNetwork);
|
||||
|
||||
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 != "")
|
||||
{
|
||||
currentSSID = currentNetwork.SSID;
|
||||
currentWiFiChannel = currentNetwork.wifiChannel;
|
||||
currentBSSID = currentNetwork.BSSID;
|
||||
}
|
||||
else // Use only networkIndex
|
||||
{
|
||||
currentSSID = WiFi.SSID(currentNetwork.networkIndex);
|
||||
currentWiFiChannel = WiFi.channel(currentNetwork.networkIndex);
|
||||
currentBSSID = WiFi.BSSID(currentNetwork.networkIndex);
|
||||
}
|
||||
|
||||
if(verboseMode()) // Avoid string generation if not required
|
||||
{
|
||||
printAPInfo(currentNetwork.networkIndex, currentSSID, currentWiFiChannel);
|
||||
}
|
||||
|
||||
transmission_status_t transmissionResult = connectToNode(currentSSID, currentWiFiChannel, currentBSSID);
|
||||
|
||||
latestTransmissionOutcomes.push_back(TransmissionResult{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
|
||||
}
|
||||
}
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED && staticIP != emptyIP && !staticIPActivated)
|
||||
{
|
||||
verboseModePrint(F("Reactivating static IP to allow for faster re-connects."));
|
||||
setStaticIP(staticIP);
|
||||
}
|
||||
|
||||
// If we do not want to be connected at end of transmission, disconnect here so we can re-enable static IP first (above).
|
||||
if(concludingDisconnect)
|
||||
{
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
}
|
||||
enterPostTransmissionState(concludingDisconnect);
|
||||
}
|
||||
|
||||
void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels)
|
||||
@ -431,6 +459,39 @@ 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)
|
||||
{
|
||||
MutexTracker mutexTracker(_tcpIpTransmissionMutex);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! TCP/IP transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.");
|
||||
return TS_CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
transmission_status_t transmissionResult = TS_CONNECTION_FAILED;
|
||||
setTemporaryMessage(message);
|
||||
|
||||
if(initialDisconnect)
|
||||
{
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
}
|
||||
|
||||
if(WiFi.status() == WL_CONNECTED && WiFi.SSID() == recipientInfo.SSID())
|
||||
{
|
||||
transmissionResult = attemptDataTransfer();
|
||||
}
|
||||
else
|
||||
{
|
||||
transmissionResult = initiateTransmission(recipientInfo);
|
||||
}
|
||||
|
||||
enterPostTransmissionState(concludingDisconnect);
|
||||
clearTemporaryMessage();
|
||||
|
||||
return transmissionResult;
|
||||
}
|
||||
|
||||
void TcpIpMeshBackend::acceptRequest()
|
||||
{
|
||||
MutexTracker mutexTracker(_tcpIpTransmissionMutex);
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "MeshBackendBase.h"
|
||||
#include "NetworkInfo.h"
|
||||
#include "TcpIpNetworkInfo.h"
|
||||
|
||||
class TcpIpMeshBackend : public MeshBackendBase {
|
||||
|
||||
@ -65,6 +65,24 @@ public:
|
||||
const String &meshPassword, const String &ssidPrefix, const String &ssidSuffix, bool verboseMode = false,
|
||||
uint8 meshWiFiChannel = 1, uint16_t serverPort = 4011);
|
||||
|
||||
/**
|
||||
* Returns a vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
* This vector is unique for each mesh backend.
|
||||
* The connectionQueue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes.
|
||||
* WiFi connections will start with connectionQueue[0] and then incrementally proceed to higher vector positions.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
std::vector<TcpIpNetworkInfo> & connectionQueue();
|
||||
|
||||
/**
|
||||
* Returns a vector with the TransmissionOutcome for each AP to which a transmission was attempted during the latest attemptTransmission call.
|
||||
* This vector is unique for each mesh backend.
|
||||
* The latestTransmissionOutcomes vector is cleared before each new transmission attempt.
|
||||
* Connection attempts are indexed in the same order they were attempted.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
std::vector<TransmissionOutcome> & latestTransmissionOutcomes() override;
|
||||
|
||||
/**
|
||||
* Initialises the node.
|
||||
*/
|
||||
@ -87,11 +105,25 @@ public:
|
||||
|
||||
void attemptTransmission(const String &message, bool scan = true, bool scanAllWiFiChannels = false) override;
|
||||
|
||||
/**
|
||||
* Transmit message to a single recipient without changing the local transmission state (apart from connecting to the recipient if required).
|
||||
* Will not change connectionQueue, latestTransmissionOutcomes or stored message.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* If any clients are connected, accept their requests and call the requestHandler function for each one.
|
||||
*/
|
||||
void acceptRequest();
|
||||
|
||||
/**
|
||||
* Get the TCP/IP message that is currently scheduled for transmission.
|
||||
* Unlike the getMessage() method, this will be correct even when the single recipient attemptTransmission method is used.
|
||||
*/
|
||||
String getCurrentMessage();
|
||||
|
||||
/**
|
||||
* Set a static IP address for the ESP8266 and activate use of static IP.
|
||||
* The static IP needs to be at the same subnet as the server's gateway.
|
||||
@ -165,6 +197,9 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
static std::vector<TcpIpNetworkInfo> _connectionQueue;
|
||||
static std::vector<TransmissionOutcome> _latestTransmissionOutcomes;
|
||||
|
||||
/**
|
||||
* Called just before we activate the AP.
|
||||
* Put _server.stop() in deactivateAPHook() in case you use _server.begin() here.
|
||||
@ -189,6 +224,16 @@ protected:
|
||||
*/
|
||||
static bool transmissionInProgress();
|
||||
|
||||
/**
|
||||
* Set a message that will be sent to other nodes when calling attemptTransmission, instead of the regular getMessage().
|
||||
* This message is used until clearTemporaryMessage() is called.
|
||||
*
|
||||
* @param newMessage The message to send.
|
||||
*/
|
||||
void setTemporaryMessage(const String &newMessage);
|
||||
String getTemporaryMessage();
|
||||
void clearTemporaryMessage();
|
||||
|
||||
private:
|
||||
|
||||
uint16_t _serverPort;
|
||||
@ -198,6 +243,7 @@ private:
|
||||
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;
|
||||
|
||||
static String _temporaryMessage;
|
||||
static String lastSSID;
|
||||
static bool staticIPActivated;
|
||||
bool useStaticIP;
|
||||
@ -212,6 +258,8 @@ private:
|
||||
bool waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait);
|
||||
transmission_status_t attemptDataTransfer();
|
||||
transmission_status_t attemptDataTransferKernel();
|
||||
transmission_status_t initiateTransmission(const TcpIpNetworkInfo &recipientInfo);
|
||||
void enterPostTransmissionState(bool concludingDisconnect);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
31
libraries/ESP8266WiFiMesh/src/TcpIpNetworkInfo.cpp
Normal file
31
libraries/ESP8266WiFiMesh/src/TcpIpNetworkInfo.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 "TcpIpNetworkInfo.h"
|
||||
|
||||
TcpIpNetworkInfo::TcpIpNetworkInfo(int networkIndex) : NetworkInfoBase(networkIndex) { };
|
||||
|
||||
TcpIpNetworkInfo::TcpIpNetworkInfo(const String &SSID, int32_t wifiChannel, const uint8_t BSSID[6], uint8_t encryptionType, int32_t RSSI , bool isHidden)
|
||||
: NetworkInfoBase(SSID, wifiChannel, BSSID, encryptionType, RSSI, isHidden)
|
||||
{ }
|
46
libraries/ESP8266WiFiMesh/src/TcpIpNetworkInfo.h
Normal file
46
libraries/ESP8266WiFiMesh/src/TcpIpNetworkInfo.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __TCPIPNETWORKINFO_H__
|
||||
#define __TCPIPNETWORKINFO_H__
|
||||
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
class TcpIpNetworkInfo : public NetworkInfoBase {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Automatically fill in the rest of the network info using networkIndex and the WiFi scan results.
|
||||
*/
|
||||
TcpIpNetworkInfo(int networkIndex);
|
||||
|
||||
/**
|
||||
* Without giving wifiChannel and BSSID, connection time is longer.
|
||||
*/
|
||||
TcpIpNetworkInfo(const String &SSID, int32_t wifiChannel = defaultWifiChannel, const uint8_t BSSID[6] = nullptr, uint8_t encryptionType = defaultEncryptionType,
|
||||
int32_t RSSI = defaultRSSI, bool isHidden = defaultIsHidden);
|
||||
};
|
||||
|
||||
#endif
|
36
libraries/ESP8266WiFiMesh/src/TransmissionOutcome.cpp
Normal file
36
libraries/ESP8266WiFiMesh/src/TransmissionOutcome.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 "TransmissionOutcome.h"
|
||||
|
||||
TransmissionOutcome::TransmissionOutcome(const NetworkInfoBase &origin, transmission_status_t 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)
|
||||
: 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; }
|
54
libraries/ESP8266WiFiMesh/src/TransmissionOutcome.h
Normal file
54
libraries/ESP8266WiFiMesh/src/TransmissionOutcome.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __TRANSMISSIONOUTCOME_H__
|
||||
#define __TRANSMISSIONOUTCOME_H__
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "NetworkInfoBase.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TS_CONNECTION_FAILED = -1,
|
||||
TS_TRANSMISSION_FAILED = 0,
|
||||
TS_TRANSMISSION_COMPLETE = 1
|
||||
} transmission_status_t;
|
||||
|
||||
class TransmissionOutcome : public NetworkInfoBase {
|
||||
|
||||
public:
|
||||
|
||||
TransmissionOutcome(const NetworkInfoBase &origin, transmission_status_t 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);
|
||||
|
||||
void setTransmissionStatus(transmission_status_t transmissionStatus);
|
||||
transmission_status_t transmissionStatus() const;
|
||||
|
||||
private:
|
||||
|
||||
transmission_status_t _transmissionStatus;
|
||||
};
|
||||
|
||||
#endif
|
@ -23,6 +23,29 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************
|
||||
* NOTE!
|
||||
*
|
||||
* This class is deprecated and will be removed in core version 3.0.0.
|
||||
* If you are still using this class, please consider migrating to the new API shown in
|
||||
* the EspnowNetworkInfo.h or TcpIpNetworkInfo.h source files.
|
||||
*
|
||||
* TODO: delete this file.
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "TransmissionResult.h"
|
||||
|
||||
TransmissionResult::TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill) :
|
||||
|
@ -23,18 +23,36 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************
|
||||
* NOTE!
|
||||
*
|
||||
* This class is deprecated and will be removed in core version 3.0.0.
|
||||
* If you are still using this class, please consider migrating to the new API shown in
|
||||
* the EspnowNetworkInfo.h or TcpIpNetworkInfo.h source files.
|
||||
*
|
||||
* TODO: delete this file.
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef __TRANSMISSIONRESULT_H__
|
||||
#define __TRANSMISSIONRESULT_H__
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "NetworkInfo.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TS_CONNECTION_FAILED = -1,
|
||||
TS_TRANSMISSION_FAILED = 0,
|
||||
TS_TRANSMISSION_COMPLETE = 1
|
||||
} transmission_status_t;
|
||||
#include "TransmissionOutcome.h"
|
||||
|
||||
class TransmissionResult : public NetworkInfo {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user