Device: Add com keepalive
parent
c5bce795c6
commit
6b60804174
|
|
@ -533,6 +533,7 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
|
||||||
test/unit/ringbuffertest.cpp
|
test/unit/ringbuffertest.cpp
|
||||||
test/unit/apperrordecodertest.cpp
|
test/unit/apperrordecodertest.cpp
|
||||||
test/unit/windowsstrings.cpp
|
test/unit/windowsstrings.cpp
|
||||||
|
test/unit/periodictest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
|
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,8 @@ bool Device::disableLogData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::goOnline() {
|
bool Device::goOnline() {
|
||||||
if(!enableNetworkCommunication(true))
|
static constexpr uint32_t onlineTimeoutMs = 5000;
|
||||||
|
if(!enableNetworkCommunication(true, onlineTimeoutMs))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto startTime = std::chrono::system_clock::now();
|
auto startTime = std::chrono::system_clock::now();
|
||||||
|
|
@ -450,13 +451,19 @@ bool Device::goOnline() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (re)start the keeponline
|
||||||
|
keeponline = std::make_unique<Periodic>([this] { return enableNetworkCommunication(true, onlineTimeoutMs); }, std::chrono::milliseconds(onlineTimeoutMs / 4));
|
||||||
|
|
||||||
online = true;
|
online = true;
|
||||||
|
|
||||||
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; });
|
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::goOffline() {
|
bool Device::goOffline() {
|
||||||
|
keeponline.reset();
|
||||||
|
|
||||||
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; });
|
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; });
|
||||||
|
|
||||||
if(isDisconnected()) {
|
if(isDisconnected()) {
|
||||||
|
|
@ -3482,13 +3489,14 @@ bool Device::writeMACsecConfig(const MACsecMessage& message, uint16_t binaryInde
|
||||||
return writeBinaryFile(raw, binaryIndex);
|
return writeBinaryFile(raw, binaryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::enableNetworkCommunication(bool enable) {
|
bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) {
|
||||||
bool sendMsg = false;
|
bool sendMsg = false;
|
||||||
if(!com->driver->enableCommunication(enable, sendMsg)) {
|
if(!com->driver->enableCommunication(enable, sendMsg)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(sendMsg) {
|
if(sendMsg) {
|
||||||
if(!com->sendCommand(Command::EnableNetworkCommunication, enable)) {
|
const uint8_t* i = (uint8_t*)&timeout;
|
||||||
|
if(!com->sendCommand(Command::EnableNetworkCommunication, {enable, 0, 0, 0, i[0], i[1], i[2], i[3]})) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef __PERIODIC_H__
|
||||||
|
#define __PERIODIC_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <functional>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
class Periodic {
|
||||||
|
public:
|
||||||
|
using Callback = std::function<bool(void)>;
|
||||||
|
Periodic(Callback&& callback, const std::chrono::milliseconds& period) :
|
||||||
|
thread(&Periodic::loop, this, std::move(callback), period)
|
||||||
|
{}
|
||||||
|
~Periodic() {
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(mutex);
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
cv.notify_all();
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void loop(Callback&& callback, const std::chrono::milliseconds& period) {
|
||||||
|
while (true) {
|
||||||
|
{
|
||||||
|
std::unique_lock lk(mutex);
|
||||||
|
cv.wait_for(lk, period, [&]{ return stop; });
|
||||||
|
if(stop) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!callback()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool stop = false;
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::mutex mutex;
|
||||||
|
std::thread thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // icsneo
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // __PERIODIC_H__
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "icsneo/api/eventmanager.h"
|
#include "icsneo/api/eventmanager.h"
|
||||||
#include "icsneo/api/lifetime.h"
|
#include "icsneo/api/lifetime.h"
|
||||||
|
#include "icsneo/api/periodic.h"
|
||||||
#include "icsneo/device/neodevice.h"
|
#include "icsneo/device/neodevice.h"
|
||||||
#include "icsneo/device/idevicesettings.h"
|
#include "icsneo/device/idevicesettings.h"
|
||||||
#include "icsneo/device/nullsettings.h"
|
#include "icsneo/device/nullsettings.h"
|
||||||
|
|
@ -1037,7 +1038,10 @@ private:
|
||||||
*/
|
*/
|
||||||
std::optional<uint64_t> getVSADiskSize();
|
std::optional<uint64_t> getVSADiskSize();
|
||||||
|
|
||||||
bool enableNetworkCommunication(bool enable);
|
bool enableNetworkCommunication(bool enable, uint32_t timeout = 0);
|
||||||
|
|
||||||
|
// Keeponline (keepalive for online)
|
||||||
|
std::unique_ptr<Periodic> keeponline;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ bool Servd::Enabled() {
|
||||||
return enabled ? enabled[0] == '1' : false;
|
return enabled ? enabled[0] == '1' : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string_view& str, char delim = ' ')
|
std::vector<std::string> split(const std::string_view& str, char delim = ' ') {
|
||||||
{
|
if(str.empty())
|
||||||
|
return {};
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
size_t tail = 0;
|
size_t tail = 0;
|
||||||
size_t head = 0;
|
size_t head = 0;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include "icsneo/api/periodic.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
|
||||||
|
// no wait, make sure stop works
|
||||||
|
TEST(PeriodicTest, StartStop)
|
||||||
|
{
|
||||||
|
const auto start = std::chrono::steady_clock::now();
|
||||||
|
Periodic p([] { return true; }, std::chrono::milliseconds(1000));
|
||||||
|
const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
||||||
|
EXPECT_LT(delta.count(), 100); // hopefully enough
|
||||||
|
}
|
||||||
|
|
||||||
|
// time single cycle
|
||||||
|
TEST(PeriodicTest, OneCycle)
|
||||||
|
{
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::mutex mutex;
|
||||||
|
uint8_t cycles = 0;
|
||||||
|
const auto start = std::chrono::steady_clock::now();
|
||||||
|
{
|
||||||
|
Periodic p([&] {
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(mutex);
|
||||||
|
++cycles;
|
||||||
|
}
|
||||||
|
cv.notify_one();
|
||||||
|
return true;
|
||||||
|
}, std::chrono::seconds(1));
|
||||||
|
std::unique_lock<std::mutex> lk(mutex);
|
||||||
|
cv.wait_for(lk, std::chrono::seconds(2), [&]{ return cycles > 0; });
|
||||||
|
}
|
||||||
|
const auto delta = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start);
|
||||||
|
EXPECT_EQ(delta.count(), 1);
|
||||||
|
EXPECT_EQ(cycles, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PeriodicTest, TenCycles)
|
||||||
|
{
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::mutex mutex;
|
||||||
|
uint8_t cycles = 0;
|
||||||
|
const auto start = std::chrono::steady_clock::now();
|
||||||
|
{
|
||||||
|
Periodic p([&] {
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(mutex);
|
||||||
|
++cycles;
|
||||||
|
}
|
||||||
|
cv.notify_one();
|
||||||
|
return true;
|
||||||
|
}, std::chrono::milliseconds(100));
|
||||||
|
std::unique_lock<std::mutex> lk(mutex);
|
||||||
|
cv.wait_for(lk, std::chrono::seconds(2), [&]{ return cycles >= 10; });
|
||||||
|
}
|
||||||
|
const auto delta = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start);
|
||||||
|
EXPECT_EQ(delta.count(), 1);
|
||||||
|
EXPECT_EQ(cycles, 10);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue