diff --git a/device/device.cpp b/device/device.cpp index 6594fa5..10f5570 100644 --- a/device/device.cpp +++ b/device/device.cpp @@ -240,13 +240,13 @@ bool Device::open() { while(!stopHeartbeatThread) { // Wait for 110ms for a possible heartbeat std::this_thread::sleep_for(std::chrono::milliseconds(110)); - if(!receivedMessage) { + if(!receivedMessage && !heartbeatSuppressed()) { // No heartbeat received, request a status com->sendCommand(Command::RequestStatusUpdate); // The response should come back quickly if the com is quiet std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Check if we got a message, and if not, if settings are being applied - if(!receivedMessage && !settings->applyingSettings) { + if(!receivedMessage && !heartbeatSuppressed()) { if(!stopHeartbeatThread && !isDisconnected()) report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error); break; @@ -630,6 +630,11 @@ optional Device::getAnalogIO(IO type, size_t number /* = 1 */) { return nullopt; } +Lifetime Device::suppressDisconnects() { + heartbeatSuppressedByUser++; + return Lifetime([this] { heartbeatSuppressedByUser--; }); +} + void Device::addExtension(std::shared_ptr&& extension) { std::lock_guard lk(extensionsLock); extensions.push_back(extension); diff --git a/include/icsneo/api/lifetime.h b/include/icsneo/api/lifetime.h new file mode 100644 index 0000000..702a259 --- /dev/null +++ b/include/icsneo/api/lifetime.h @@ -0,0 +1,34 @@ +#ifndef __ICSNEO_LIFETIME_H_ +#define __ICSNEO_LIFETIME_H_ + +#include + +namespace icsneo { + +class Lifetime { +public: + Lifetime() = default; + Lifetime(std::function onDeath) : fnOnDeath(onDeath) {} + ~Lifetime() { + if(fnOnDeath) + fnOnDeath(); + } + + // Disallow copies so the fnOnDeath only happens once + Lifetime(const Lifetime&) = delete; + Lifetime& operator=(const Lifetime&) = delete; + + // Explicitly allow moves + Lifetime(Lifetime&& moved) { *this = std::move(moved); } + Lifetime& operator=(Lifetime&& rhs) { + fnOnDeath = std::move(rhs.fnOnDeath); + rhs.fnOnDeath = std::function(); + return *this; + } +private: + std::function fnOnDeath; +}; + +} + +#endif \ No newline at end of file diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index 91c8e15..21a2d17 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -9,6 +9,7 @@ #include #include #include "icsneo/api/eventmanager.h" +#include "icsneo/api/lifetime.h" #include "icsneo/device/neodevice.h" #include "icsneo/device/idevicesettings.h" #include "icsneo/device/nullsettings.h" @@ -24,6 +25,7 @@ #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/third-party/concurrentqueue/concurrentqueue.h" #include "icsneo/platform/optional.h" +#include "icsneo/platform/nodiscard.h" namespace icsneo { @@ -155,6 +157,12 @@ public: virtual std::vector> getFlexRayControllers() const { return {}; } + /** + * For use by extensions only. + */ + NODISCARD("If the Lifetime is not held, disconnects will be immediately unsuppressed") + Lifetime suppressDisconnects(); + const device_eventhandler_t& getEventHandler() const { return report; } std::shared_ptr com; @@ -275,6 +283,10 @@ private: std::vector supportedTXNetworks; std::vector supportedRXNetworks; + // Use heartbeatSuppressed instead when reading + std::atomic heartbeatSuppressedByUser{0}; + bool heartbeatSuppressed() const { return heartbeatSuppressedByUser > 0 || (settings && settings->applyingSettings); } + void handleNeoVIMessage(std::shared_ptr message); enum class LEDState : uint8_t { diff --git a/include/icsneo/platform/nodiscard.h b/include/icsneo/platform/nodiscard.h new file mode 100644 index 0000000..432cdee --- /dev/null +++ b/include/icsneo/platform/nodiscard.h @@ -0,0 +1,15 @@ +#ifndef __ICSNEO_NODISCARD_H_ +#define __ICSNEO_NODISCARD_H_ + +/** + * Allow the use of the nodiscard attribute where it is supported. + */ +#if __cplusplus > 201703L // C++20 and above +#define NODISCARD(str) [[nodiscard(str)]] +#elif __cplusplus > 201402L // C++17 and above +#define NODISCARD(str) [[nodiscard]] +#else +#define NODISCARD(str) +#endif + +#endif \ No newline at end of file