1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-13 13:01:55 +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:
Anders
2019-09-18 22:26:37 +02:00
parent 2576a0912b
commit 86025c7884
19 changed files with 998 additions and 255 deletions

View File

@ -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,6 +1921,68 @@ uint8_t *EspnowMeshBackend::getEncryptedMac(const uint8_t *peerMac, uint8_t *res
}
}
void EspnowMeshBackend::prepareForTransmission(const String &message, bool scan, bool scanAllWiFiChannels)
{
setMessage(message);
latestTransmissionOutcomes().clear();
if(scan)
{
connectionQueue().clear();
scanForNetworks(scanAllWiFiChannels);
}
}
transmission_status_t EspnowMeshBackend::initiateTransmission(const String &message, const EspnowNetworkInfo &recipientInfo)
{
uint8_t targetBSSID[6] {0};
assert(recipientInfo.BSSID() != nullptr); // We need at least the BSSID to connect
recipientInfo.getBSSID(targetBSSID);
if(verboseMode()) // Avoid string generation if not required
{
printAPInfo(recipientInfo);
verboseModePrint(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(message, targetBSSID);
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;
}
}
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.");
verboseModePrint("Maximum duration of successful transmissions: " + String(maxTransmissionDuration_AT) + " ms.");
}
else
{
verboseModePrint("No successful transmission.");
}
}
void EspnowMeshBackend::attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels)
{
MutexTracker mutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
@ -1917,67 +1992,70 @@ void EspnowMeshBackend::attemptTransmission(const String &message, bool scan, bo
return;
}
setMessage(message);
latestTransmissionOutcomes.clear();
if(scan)
{
scanForNetworks(scanAllWiFiChannels);
}
for(NetworkInfo &currentNetwork : 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
{
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);
verboseModePrint(F(""));
}
prepareForTransmission(message, scan, scanAllWiFiChannels);
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});
}
if(verboseMode() && successfulTransmissions_AT > 0) // Avoid calculations if not required
for(EspnowNetworkInfo &currentNetwork : connectionQueue())
{
verboseModePrint("Average duration of successful transmissions: " + String(totalDurationWhenSuccessful_AT/successfulTransmissions_AT) + " ms.");
verboseModePrint("Maximum duration of successful transmissions: " + String(maxTransmissionDuration_AT) + " ms.");
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)
{
verboseModePrint("No successful transmission.");
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);
}
}
@ -1990,107 +2068,51 @@ void EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message,
return;
}
setMessage(message);
latestTransmissionOutcomes.clear();
if(scan)
{
scanForNetworks(scanAllWiFiChannels);
}
prepareForTransmission(message, scan, scanAllWiFiChannels);
outerMutexTracker.releaseMutex();
for(NetworkInfo &currentNetwork : connectionQueue)
{
for(EspnowNetworkInfo &currentNetwork : 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())
{
assert(false && "ERROR! Unable to recapture Mutex in attemptAutoEncryptingTransmission. Aborting.");
return;
}
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
{
currentSSID = WiFi.SSID(currentNetwork.networkIndex);
currentWiFiChannel = WiFi.channel(currentNetwork.networkIndex);
currentBSSID = WiFi.BSSID(currentNetwork.networkIndex);
}
transmission_status_t transmissionResult = initiateAutoEncryptingTransmission(getMessage(), currentBSSID, connectionStatus);
if(verboseMode()) // Avoid string generation if not required
{
printAPInfo(currentNetwork.networkIndex, currentSSID, currentWiFiChannel);
verboseModePrint(F(""));
}
latestTransmissionOutcomes().push_back(TransmissionOutcome{.origin = currentNetwork, .transmissionStatus = transmissionResult});
EncryptedConnectionLog *encryptedConnection = getEncryptedConnection(currentBSSID);
encrypted_connection_status_t connectionStatus = ECS_MAX_CONNECTIONS_REACHED_SELF;
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);
}
finalizeAutoEncryptingConnection(currentBSSID, encryptedConnection, createPermanentConnections);
}
if(verboseMode() && successfulTransmissions_AT > 0) // Avoid calculations if not required
printTransmissionStatistics();
}
transmission_status_t EspnowMeshBackend::attemptAutoEncryptingTransmission(const String &message, const EspnowNetworkInfo &recipientInfo, bool createPermanentConnection)
{
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())
{
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.");
assert(false && "ERROR! Transmission in progress. Don't call attemptTransmission from callbacks as this may corrupt program state! Aborting.");
return TS_CONNECTION_FAILED;
}
transmission_status_t transmissionResult = initiateAutoEncryptingTransmission(message, targetBSSID, connectionStatus);
finalizeAutoEncryptingConnection(targetBSSID, encryptedConnection, createPermanentConnection);
return transmissionResult;
}
void EspnowMeshBackend::broadcast(const String &message)

View File

@ -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.
*/
@ -177,6 +196,12 @@ public:
static bool deactivateEspnow();
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,
@ -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;

View 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)
{ }

View 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

View File

@ -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,22 +232,28 @@ 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;
}
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);
if(apNetworkIndex != NETWORK_INFO_DEFAULT_INT)
String mainNetworkIdentifier = apNetworkInfo.SSID();
if(mainNetworkIdentifier == NetworkInfoBase::defaultSSID) // If SSID not provided, use BSSID instead
{
verboseModePrint("(" + String(WiFi.RSSI(apNetworkIndex)) + String(F("dBm) ")) +
(WiFi.encryptionType(apNetworkIndex) == ENC_TYPE_NONE ? String(F("open")) : ""), false);
mainNetworkIdentifier = macToString(apNetworkInfo.BSSID());
}
verboseModePrint(String(F("AP acquired: ")) + mainNetworkIdentifier + String(F(", Ch:")) + String(apNetworkInfo.wifiChannel()) + " ", false);
if(apNetworkInfo.RSSI() != NetworkInfoBase::defaultRSSI)
{
verboseModePrint("(" + String(apNetworkInfo.RSSI()) + String(F("dBm) ")) +
(apNetworkInfo.encryptionType() == ENC_TYPE_NONE ? String(F("open")) : ""), false);
}
verboseModePrint(F("... "), false);

View File

@ -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;

View File

@ -22,6 +22,29 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* 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"
@ -74,4 +97,3 @@ NetworkInfo & NetworkInfo::operator=(const NetworkInfo &other)
networkIndex = other.networkIndex;
return *this;
}

View File

@ -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 {

View 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; }

View 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

View File

@ -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,7 +376,42 @@ transmission_status_t TcpIpMeshBackend::connectToNode(const String &targetSSID,
return attemptDataTransfer();
}
void TcpIpMeshBackend::attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels, bool concludingDisconnect, bool initialDisconnect )
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);
if(!mutexTracker.mutexCaptured())
@ -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 &currentNetwork : connectionQueue)
for(TcpIpNetworkInfo &currentNetwork : connectionQueue())
{
WiFi.disconnect();
yield();
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);
transmission_status_t transmissionResult = initiateTransmission(currentNetwork);
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);

View File

@ -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.
*/
@ -86,12 +104,26 @@ public:
void attemptTransmission(const String &message, bool scan, bool scanAllWiFiChannels, bool concludingDisconnect, bool initialDisconnect = false);
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

View 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)
{ }

View 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

View 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; }

View 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

View File

@ -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) :

View File

@ -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 {