From 218648ae5a6188691e4ebd19124e66a56f8504d7 Mon Sep 17 00:00:00 2001 From: Paul Hollinsky Date: Fri, 23 Apr 2021 22:32:42 -0400 Subject: [PATCH] Extensions: Offer an opportunity to communicate with a dead device --- device/device.cpp | 82 +++++++++++++------ include/icsneo/device/device.h | 2 + .../device/extensions/deviceextension.h | 7 +- 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/device/device.cpp b/device/device.cpp index 10f5570..2bed917 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -174,34 +174,36 @@ bool Device::open() { return false; } - if(!afterCommunicationOpen()) { - // Very unlikely, at the time of writing this only fails if rawWrite does. - // If you're looking for this error, you're probably looking for if(!serial) below. - report(APIEvent::Type::NoSerialNumber, APIEvent::Severity::Error); // Communication could not be established with the device. Perhaps it is not powered with 12 volts? - com->close(); - return false; + APIEvent::Type attemptErr = attemptToBeginCommunication(); + if(attemptErr != APIEvent::Type::NoErrorFound) { + // We could not communicate with the device, let's see if an extension can + bool tryAgain = false; + forEachExtension([&tryAgain](const std::shared_ptr& ext) -> bool { + if(ext->onDeviceCommunicationDead()) + tryAgain = true; + return true; + }); + if(!tryAgain) { + report(attemptErr, APIEvent::Severity::Error); + return false; // Extensions couldn't save us + } + attemptErr = attemptToBeginCommunication(); + if(attemptErr != APIEvent::Type::NoErrorFound) { + report(attemptErr, APIEvent::Severity::Error); + return false; + } } - auto serial = com->getSerialNumberSync(); - int i = 0; - while(!serial) { - serial = com->getSerialNumberSync(); - if(i++ > 5) - break; - } - if(!serial) { - report(APIEvent::Type::NoSerialNumber, APIEvent::Severity::Error); // Communication could not be established with the device. Perhaps it is not powered with 12 volts? - com->close(); + bool block = false; + forEachExtension([&block](const std::shared_ptr& ext) { + if(ext->onDeviceOpen()) + return true; + block = true; return false; - } - - std::string currentSerial = getNeoDevice().serial; - if(currentSerial != serial->deviceSerial) { - report(APIEvent::Type::IncorrectSerialNumber, APIEvent::Severity::Error); - com->close(); + }); + if(block) // Extensions say no return false; - } - + if(!settings->disabled) { // Since we will not fail the open if a settings read fails, // downgrade any errors to warnings. Otherwise the error will @@ -258,10 +260,40 @@ bool Device::open() { com->removeMessageCallback(messageReceivedCallbackID); }); - forEachExtension([](const std::shared_ptr& ext) { ext->onDeviceOpen(); return true; }); return true; } +APIEvent::Type Device::attemptToBeginCommunication() { + if(!afterCommunicationOpen()) { + // Very unlikely, at the time of writing this only fails if rawWrite does. + // If you're looking for this error, you're probably looking for if(!serial) below. + com->close(); + // "Communication could not be established with the device. Perhaps it is not powered with 12 volts?" + return APIEvent::Type::NoSerialNumber; + } + + auto serial = com->getSerialNumberSync(); + int i = 0; + while(!serial) { + serial = com->getSerialNumberSync(); + if(i++ > 5) + break; + } + if(!serial) { + com->close(); + // "Communication could not be established with the device. Perhaps it is not powered with 12 volts?" + return APIEvent::Type::NoSerialNumber; + } + + std::string currentSerial = getNeoDevice().serial; + if(currentSerial != serial->deviceSerial) { + com->close(); + return APIEvent::Type::IncorrectSerialNumber; + } + + return APIEvent::Type::NoErrorFound; +} + bool Device::close() { if(!com) { report(APIEvent::Type::Unknown, APIEvent::Severity::Error); diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index 21a2d17..0cb78ad 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -283,6 +283,8 @@ private: std::vector supportedTXNetworks; std::vector supportedRXNetworks; + APIEvent::Type attemptToBeginCommunication(); + // Use heartbeatSuppressed instead when reading std::atomic heartbeatSuppressedByUser{0}; bool heartbeatSuppressed() const { return heartbeatSuppressedByUser > 0 || (settings && settings->applyingSettings); } diff --git a/include/icsneo/device/extensions/deviceextension.h b/include/icsneo/device/extensions/deviceextension.h index 7fb6150..0a4684e 100644 --- a/include/icsneo/device/extensions/deviceextension.h +++ b/include/icsneo/device/extensions/deviceextension.h @@ -17,7 +17,12 @@ public: virtual ~DeviceExtension() = default; virtual const char* getName() const = 0; - virtual void onDeviceOpen() {} + // Return false to block opening + virtual bool onDeviceOpen() { return true; } + + // Return true to indicate that communication should now be back + virtual bool onDeviceCommunicationDead() { return false; } + virtual void onGoOnline() {} virtual void onGoOffline() {} virtual void onDeviceClose() {}