1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00
esp8266/libraries/ESP8266WiFiMesh/src/MeshBackendBase.cpp
Anders f059e57322 - Use the new Crypto, TypeConversion and random() functionality added to the Arduino core, instead of the versions local to the mesh library.
- Rearrange class variables to minimize storage padding.

- Add protected getters for EspnowMeshBackend and MeshBackendBase components.

- Partially update README.md
2020-05-18 22:09:34 +02:00

329 lines
10 KiB
C++

/*
MeshBackendBase
Copyright (c) 2015 Julian Fell and 2019 Anders Löfgren. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "MeshBackendBase.h"
#include "TypeConversionFunctions.h"
#include "MutexTracker.h"
#include <assert.h>
namespace
{
namespace TypeCast = MeshTypeConversionFunctions;
MeshBackendBase *apController = nullptr;
}
std::shared_ptr<bool> MeshBackendBase::_scanMutex = std::make_shared<bool>(false);
MeshBackendBase::MeshBackendBase(const requestHandlerType requestHandler, const responseHandlerType responseHandler, const networkFilterType networkFilter, const MeshBackendType classType)
{
setRequestHandler(requestHandler);
setResponseHandler(responseHandler);
setNetworkFilter(networkFilter);
setClassType(classType);
}
MeshBackendBase::~MeshBackendBase()
{
deactivateControlledAP();
}
void MeshBackendBase::setClassType(const MeshBackendType classType)
{
_classType = classType;
}
MeshBackendType MeshBackendBase::getClassType() const {return _classType;}
void MeshBackendBase::setVerboseModeState(const bool enabled) { _conditionalPrinter.setVerboseModeState(enabled); }
bool MeshBackendBase::verboseMode() const { return _conditionalPrinter.verboseMode(); }
void MeshBackendBase::verboseModePrint(const String &stringToPrint, const bool newline) const
{
_conditionalPrinter.verboseModePrint(stringToPrint, newline);
}
void MeshBackendBase::setPrintWarnings(const bool printEnabled) { ConditionalPrinter::setPrintWarnings(printEnabled); }
bool MeshBackendBase::printWarnings() {return ConditionalPrinter::printWarnings();}
void MeshBackendBase::warningPrint(const String &stringToPrint, const bool newline)
{
ConditionalPrinter::warningPrint(stringToPrint, newline);
}
void MeshBackendBase::activateAP()
{
// Deactivate active AP to avoid two servers using the same port, which can lead to crashes.
deactivateAP();
activateAPHook();
WiFi.mode(WIFI_AP_STA);
apController = this;
}
void MeshBackendBase::activateAPHook()
{
WiFi.softAP( getSSID().c_str(), getMeshPassword().c_str(), getWiFiChannel(), getAPHidden() ); // Note that a maximum of 8 TCP/IP stations can be connected at a time to each AP, max 4 by default.
}
void MeshBackendBase::deactivateAP()
{
if(MeshBackendBase *currentAPController = MeshBackendBase::getAPController())
currentAPController->deactivateControlledAP();
}
bool MeshBackendBase::deactivateControlledAP()
{
if(isAPController())
{
deactivateAPHook();
WiFi.softAPdisconnect();
WiFi.mode(WIFI_STA);
// Since there is no active AP controller now, make the apController variable point to nothing.
apController = nullptr;
return true;
}
return false;
}
void MeshBackendBase::deactivateAPHook()
{
}
void MeshBackendBase::restartAP()
{
deactivateAP();
yield();
activateAP();
yield();
}
MeshBackendBase *MeshBackendBase::getAPController()
{
return apController;
}
bool MeshBackendBase::isAPController() const
{
return (this == getAPController());
}
void MeshBackendBase::setWiFiChannel(const uint8 newWiFiChannel)
{
wifi_country_t wifiCountry;
wifi_get_country(&wifiCountry); // Note: Should return 0 on success and -1 on failure, but always seems to return 1. Possibly broken API. Channels 1 to 13 are the default limits.
assert(wifiCountry.schan <= newWiFiChannel && newWiFiChannel <= wifiCountry.schan + wifiCountry.nchan - 1);
_meshWiFiChannel = newWiFiChannel;
// WiFi.channel() will change if this node connects to an AP with another channel,
// so there is no guarantee we are using _meshWiFiChannel.
// Also, we cannot change the WiFi channel while we are still connected to the other AP.
if(WiFi.channel() != getWiFiChannel() && WiFi.status() != WL_CONNECTED)
{
// Apply changes to active AP.
if(isAPController())
restartAP();
}
}
uint8 MeshBackendBase::getWiFiChannel() const
{
return _meshWiFiChannel;
}
void MeshBackendBase::setSSID(const String &newSSIDPrefix, const String &newSSIDRoot, const String &newSSIDSuffix)
{
if(!newSSIDPrefix.isEmpty())
_SSIDPrefix = newSSIDPrefix;
if(!newSSIDRoot.isEmpty())
_SSIDRoot = newSSIDRoot;
if(!newSSIDSuffix.isEmpty())
_SSIDSuffix = newSSIDSuffix;
String newSSID = _SSIDPrefix + _SSIDRoot + _SSIDSuffix;
assert(newSSID.length() <= 31);
if(getSSID() != newSSID)
{
_SSID = newSSID;
// Apply SSID changes to active AP.
if(isAPController())
restartAP();
}
}
String MeshBackendBase::getSSID() const {return _SSID;}
void MeshBackendBase::setSSIDPrefix(const String &newSSIDPrefix)
{
setSSID(newSSIDPrefix);
}
String MeshBackendBase::getSSIDPrefix() const {return _SSIDPrefix;}
void MeshBackendBase::setSSIDRoot(const String &newSSIDRoot)
{
setSSID(emptyString, newSSIDRoot);
}
String MeshBackendBase::getSSIDRoot() const {return _SSIDRoot;}
void MeshBackendBase::setSSIDSuffix(const String &newSSIDSuffix)
{
setSSID(emptyString, emptyString, newSSIDSuffix);
}
String MeshBackendBase::getSSIDSuffix() const {return _SSIDSuffix;}
void MeshBackendBase::setMeshName(const String &newMeshName)
{
setSSIDPrefix(newMeshName);
}
String MeshBackendBase::getMeshName() const {return getSSIDPrefix();}
void MeshBackendBase::setNodeID(const String &newNodeID)
{
setSSIDSuffix(newNodeID);
}
String MeshBackendBase::getNodeID() const {return getSSIDSuffix();}
void MeshBackendBase::setMeshPassword(const String &newMeshPassword)
{
assert(8 <= newMeshPassword.length() && newMeshPassword.length() <= 64); // Limited by the ESP8266 API.
assert(newMeshPassword.indexOf('"') == -1); // " is not allowed in passwords to allow for easier JSON parsing and predictable password length (no need for extra escape characters).
_meshPassword = newMeshPassword;
// Apply changes to active AP.
if(isAPController())
restartAP();
}
String MeshBackendBase::getMeshPassword() const {return _meshPassword;}
void MeshBackendBase::setMessage(const String &newMessage) {_message = newMessage;}
String MeshBackendBase::getMessage() const {return _message;}
void MeshBackendBase::setRequestHandler(const MeshBackendBase::requestHandlerType requestHandler) {_requestHandler = requestHandler;}
MeshBackendBase::requestHandlerType MeshBackendBase::getRequestHandler() const {return _requestHandler;}
void MeshBackendBase::setResponseHandler(const MeshBackendBase::responseHandlerType responseHandler) {_responseHandler = responseHandler;}
MeshBackendBase::responseHandlerType MeshBackendBase::getResponseHandler() const {return _responseHandler;}
void MeshBackendBase::setNetworkFilter(const MeshBackendBase::networkFilterType networkFilter) {_networkFilter = networkFilter;}
MeshBackendBase::networkFilterType MeshBackendBase::getNetworkFilter() const {return _networkFilter;}
void MeshBackendBase::setTransmissionOutcomesUpdateHook(const MeshBackendBase::transmissionOutcomesUpdateHookType transmissionOutcomesUpdateHook) {_transmissionOutcomesUpdateHook = transmissionOutcomesUpdateHook;}
MeshBackendBase::transmissionOutcomesUpdateHookType MeshBackendBase::getTransmissionOutcomesUpdateHook() const {return _transmissionOutcomesUpdateHook;}
void MeshBackendBase::setScanHidden(const bool scanHidden)
{
_scanHidden = scanHidden;
}
bool MeshBackendBase::getScanHidden() const {return _scanHidden;}
void MeshBackendBase::setAPHidden(const bool apHidden)
{
if(getAPHidden() != apHidden)
{
_apHidden = apHidden;
// Apply changes to active AP.
if(isAPController())
restartAP();
}
}
bool MeshBackendBase::getAPHidden() const {return _apHidden;}
ConditionalPrinter *MeshBackendBase::getConditionalPrinter() {return &_conditionalPrinter;}
const ConditionalPrinter *MeshBackendBase::getConditionalPrinterConst() const {return &_conditionalPrinter;}
bool MeshBackendBase::latestTransmissionSuccessfulBase(const std::vector<TransmissionOutcome> &latestTransmissionOutcomes)
{
if(latestTransmissionOutcomes.empty())
return false;
for(const TransmissionOutcome &transmissionOutcome : latestTransmissionOutcomes)
if(transmissionOutcome.transmissionStatus() != TransmissionStatusType::TRANSMISSION_COMPLETE)
return false;
return true;
}
void MeshBackendBase::scanForNetworks(const bool scanAllWiFiChannels)
{
MutexTracker mutexTracker(_scanMutex);
if(!mutexTracker.mutexCaptured())
{
assert(false && String(F("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 */
// 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.
int n = 0;
if(scanAllWiFiChannels)
{
n = WiFi.scanNetworks(false, getScanHidden());
}
else
{
// Scan function argument overview: scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL)
n = WiFi.scanNetworks(false, getScanHidden(), getWiFiChannel());
}
getNetworkFilter()(n, *this); // Update the connectionQueue.
}
void MeshBackendBase::printAPInfo(const NetworkInfoBase &apNetworkInfo)
{
String mainNetworkIdentifier = apNetworkInfo.SSID();
if(mainNetworkIdentifier == NetworkInfoBase::defaultSSID) // If SSID not provided, use BSSID instead
{
mainNetworkIdentifier = TypeCast::macToString(apNetworkInfo.BSSID());
}
verboseModePrint(String(F("AP acquired: ")) + mainNetworkIdentifier + String(F(", Ch:")) + String(apNetworkInfo.wifiChannel()) + ' ', false);
if(apNetworkInfo.RSSI() != NetworkInfoBase::defaultRSSI)
{
verboseModePrint(String('(') + String(apNetworkInfo.RSSI()) + String(F("dBm) ")) +
(apNetworkInfo.encryptionType() == ENC_TYPE_NONE ? String(F("open")) : emptyString), false);
}
verboseModePrint(F("... "), false);
}