Initial commit
This commit is contained in:
parent
385367879f
commit
ff408db8de
21
ConditionMonitoring/CustomStringUtilities.cpp
Normal file
21
ConditionMonitoring/CustomStringUtilities.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "CustomStringUtilities.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
const char* CustomStringUtilities::typeOfWhitespacesReturn = " \t\n\r\f\v";
|
||||||
|
const char* CustomStringUtilities::typeOfWhitespaces = " \t\r\f\v";
|
||||||
|
|
||||||
|
void CustomStringUtilities::removeAllWhitespaces(std::string& str, bool trimReturn) {
|
||||||
|
const char* whitespaces = trimReturn ? typeOfWhitespacesReturn : typeOfWhitespaces;
|
||||||
|
size_t pos, offset = 0;
|
||||||
|
while ((pos = str.find_first_of(whitespaces, offset)) != std::string::npos) {
|
||||||
|
str.erase(pos, 1);
|
||||||
|
offset = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomStringUtilities::trim(std::string& str) {
|
||||||
|
str.erase(str.find_last_not_of(typeOfWhitespaces) + 1);
|
||||||
|
str.erase(0, str.find_first_not_of(typeOfWhitespaces));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
14
ConditionMonitoring/CustomStringUtilities.h
Normal file
14
ConditionMonitoring/CustomStringUtilities.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CustomStringUtilities
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const char* typeOfWhitespaces;
|
||||||
|
static const char* typeOfWhitespacesReturn;
|
||||||
|
public:
|
||||||
|
//remove whitespaces from the passed string
|
||||||
|
static void removeAllWhitespaces(std::string& str, bool trimReturn = true);
|
||||||
|
static void trim(std::string&);
|
||||||
|
};
|
||||||
|
|
163
ConditionMonitoring/DataAcquisition.cpp
Normal file
163
ConditionMonitoring/DataAcquisition.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include "DataAcquisition.h"
|
||||||
|
#include "easylogging++.h"
|
||||||
|
#include <iomanip>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
std::atomic_bool modbusThreadRunning = false;
|
||||||
|
std::atomic_bool modbusThreadCancelled = false;
|
||||||
|
|
||||||
|
//Modbus worker thread, lock and notification variable
|
||||||
|
std::condition_variable cvar_modbus_queue;
|
||||||
|
std::mutex mux_modbus_queue;
|
||||||
|
|
||||||
|
DataAcquisition::DataAcquisition() : dataModel(DataModel::Instance())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DataAcquisition::~DataAcquisition()
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Wait until modbus worker queue finishes...";
|
||||||
|
modbusThreadCancelled = true;
|
||||||
|
cvar_modbus_queue.notify_one();
|
||||||
|
if(modbusThread.size() != 0 && modbusThread[0].joinable()){
|
||||||
|
modbusThread[0].join();
|
||||||
|
modbusThread.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Modbus thread
|
||||||
|
//Execute the enqueued modbus register requests
|
||||||
|
void modbusWorkerThread(DataAcquisition* this_p) {
|
||||||
|
LOG(INFO) << "Modbus Worker Thread started";
|
||||||
|
auto& queue = this_p->getModbusQueue();
|
||||||
|
auto& publishers = this_p->getPublishers();
|
||||||
|
bool first = true;
|
||||||
|
try {
|
||||||
|
//vector of connections which failed to open
|
||||||
|
std::vector<u_int> failedConnections;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
if (modbusThreadCancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
//If this is the first execution or the thread has
|
||||||
|
//been notified after being in sleep mode
|
||||||
|
if (queue.size() == 0 || first){
|
||||||
|
first = false;
|
||||||
|
failedConnections.clear();
|
||||||
|
//No work to do, wait for something to be enqueued
|
||||||
|
std::unique_lock<std::mutex> threadLock(mux_modbus_queue);
|
||||||
|
|
||||||
|
//Wait till notification (happens when some registers are enqueued
|
||||||
|
cvar_modbus_queue.wait(threadLock);
|
||||||
|
|
||||||
|
if (modbusThreadCancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//open all of the registered connections
|
||||||
|
for(unsigned int i = 0; i < publishers.size(); i++){
|
||||||
|
if(!publishers[i]->open()){
|
||||||
|
//write id to list if connection failed
|
||||||
|
failedConnections.push_back(publishers[i]->getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modbusThreadCancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Get next parameter from the queue
|
||||||
|
ParameterSpecification modbusParameter = queue.pop_front();
|
||||||
|
|
||||||
|
//Look if the connection is in the list of the failed connections, if so , skip this parameter
|
||||||
|
if(std::find(failedConnections.begin(), failedConnections.end(), modbusParameter.connection->getID()) != failedConnections.end()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Skip parameter if not a reading parameter or connection is not open
|
||||||
|
if(!modbusParameter.isReadable())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (modbusParameter.length) {
|
||||||
|
case 1:
|
||||||
|
modbusParameter.connection->readBit(modbusParameter);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
modbusParameter.connection->readByte(modbusParameter);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
modbusParameter.connection->readRegister(modbusParameter);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
modbusParameter.connection->readDRegister(modbusParameter);
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
modbusParameter.connection->readQRegister(modbusParameter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
modbusParameter.connection->readBits(modbusParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modbusParameter.error){
|
||||||
|
//Rading of Modbus Parameter was not successful
|
||||||
|
LOG(WARNING) << std::dec
|
||||||
|
<< "[Modbus " << modbusParameter.connection->getID() << ": " << modbusParameter.connection->getConnectionType() << "] "
|
||||||
|
<< "Failed reading parameter "<< (int)modbusParameter.description
|
||||||
|
<< " at 0x"
|
||||||
|
<< std::hex << std::setfill('0') << std::setw(4)
|
||||||
|
<< modbusParameter.address;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
|
||||||
|
//LOG(INFO) << std::dec
|
||||||
|
// << "[Modbus " << modbusParameter.connection->getConnectionType() << " "<<
|
||||||
|
// modbusParameter.connection->getID() << "]" << " Readed param " << (int)modbusParameter.description
|
||||||
|
// << " value: " << value;
|
||||||
|
|
||||||
|
DataModel::Instance()->saveModbusParameter(std::move(modbusParameter));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (std::exception& e) {
|
||||||
|
LOG(FATAL) << "Error in modbus access, shutting down modbus thread: " << e.what();
|
||||||
|
}
|
||||||
|
modbusThreadRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DataAcquisition::startModbusThread() {
|
||||||
|
if (modbusThreadRunning == false)
|
||||||
|
{
|
||||||
|
modbusThreadRunning = true;
|
||||||
|
modbusThread.push_back(std::thread(modbusWorkerThread, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Registers publisher and moves ownership to DataAcquisition class
|
||||||
|
void DataAcquisition::registerPublisher(std::unique_ptr<PublisherInterface> publisher) {
|
||||||
|
publishers.push_back(std::move(publisher));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataAcquisition::enqueuePublisherRegister(){
|
||||||
|
for (size_t i = 0; i < publishers.size(); i++) {
|
||||||
|
//Collects the alert modbus registers and enqueue them
|
||||||
|
publishers[i]->enqueueReadingRegisters(modbusAccessQueue, Category::Alert);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < publishers.size(); i++) {
|
||||||
|
//Collects the condition modbus registers and enqueue them
|
||||||
|
publishers[i]->enqueueReadingRegisters(modbusAccessQueue, Category::Condition);
|
||||||
|
}
|
||||||
|
cvar_modbus_queue.notify_one();
|
||||||
|
}
|
||||||
|
|
38
ConditionMonitoring/DataAcquisition.h
Normal file
38
ConditionMonitoring/DataAcquisition.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "DataModel.h"
|
||||||
|
#include "PublisherInterface.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include "ts_queue.h"
|
||||||
|
#include "modbus_interface_lib.h"
|
||||||
|
|
||||||
|
class DataAcquisition
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::unique_ptr<DataModel>& dataModel;
|
||||||
|
|
||||||
|
//Modbus Connections for POC and Bender, can be serial or IP
|
||||||
|
std::vector<std::unique_ptr<PublisherInterface>> publishers;
|
||||||
|
|
||||||
|
//Modbus thread
|
||||||
|
std::vector<std::thread> modbusThread;
|
||||||
|
|
||||||
|
ts_queue<ParameterSpecification> modbusAccessQueue;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
DataAcquisition();
|
||||||
|
~DataAcquisition();
|
||||||
|
|
||||||
|
|
||||||
|
void startModbusThread();
|
||||||
|
ts_queue<ParameterSpecification>& getModbusQueue() { return modbusAccessQueue; }
|
||||||
|
|
||||||
|
//void registerPublisher(Publisher* publisher);
|
||||||
|
void registerPublisher(std::unique_ptr<PublisherInterface> publisher);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<PublisherInterface>>& getPublishers() { return publishers; }
|
||||||
|
|
||||||
|
void enqueuePublisherRegister();
|
||||||
|
};
|
364
ConditionMonitoring/DataModel.cpp
Normal file
364
ConditionMonitoring/DataModel.cpp
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
#include "DataModel.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
#include <charconv>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "PublisherPowercenter.h"
|
||||||
|
#include "PublisherBenderRcm.h"
|
||||||
|
|
||||||
|
std::chrono::milliseconds timeoutMS = std::chrono::milliseconds(10'000);
|
||||||
|
|
||||||
|
long DataModel::permanentParamHistory = 0;
|
||||||
|
int DataModel::narrowBlock = 0;
|
||||||
|
|
||||||
|
//Initialization of static member
|
||||||
|
std::unique_ptr<DataModel> DataModel::instance = nullptr;
|
||||||
|
|
||||||
|
//Read file locker
|
||||||
|
std::timed_mutex accessFilesMTX;
|
||||||
|
|
||||||
|
|
||||||
|
constexpr unsigned long long DataModel::timepoint_to_sec_long(const std::chrono::system_clock::time_point& t) {
|
||||||
|
return duration_to_sec_long(t.time_since_epoch());
|
||||||
|
}
|
||||||
|
|
||||||
|
const ts_map<ModbusRegister, SavedData> &DataModel::getPublisherData() const
|
||||||
|
{
|
||||||
|
return temporaryStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
CappedStorage* DataModel::getPermanentData(ModbusRegister reg){
|
||||||
|
auto it = permanentStorage.find(reg);
|
||||||
|
if(it != permanentStorage.end()){
|
||||||
|
return &(it->second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr unsigned long long DataModel::duration_to_sec_long(const std::chrono::system_clock::duration& t) {
|
||||||
|
return std::chrono::duration_cast<std::chrono::seconds>(t).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DataModel::Create() {
|
||||||
|
instance = std::make_unique<DataModel>();
|
||||||
|
|
||||||
|
permanentParamHistory = SystemConfig::getIntConfigParameter("permanent_param_history");
|
||||||
|
narrowBlock = SystemConfig::getIntConfigParameter("narrow_block");
|
||||||
|
}
|
||||||
|
|
||||||
|
DataModel::~DataModel()
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Save locally stored permanent data to permanent storage...";
|
||||||
|
//Save permanent data to storage
|
||||||
|
long long time = std::chrono::system_clock::now().time_since_epoch().count();
|
||||||
|
std::fstream file;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << dataDir << "data_" << time;
|
||||||
|
std::string filename = ss.str();
|
||||||
|
file.open(filename, std::ios::out);
|
||||||
|
|
||||||
|
if (file.is_open()) {
|
||||||
|
for(auto &storage : permanentStorage){
|
||||||
|
if(storage.second.size() == 0)
|
||||||
|
continue;
|
||||||
|
file << (int)storage.first << ":" << std::endl;
|
||||||
|
file << storage.second << std::endl;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG(ERROR) << "Could not access file to store permanent data...";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<DataModel>& DataModel::Instance() {
|
||||||
|
if (!instance)
|
||||||
|
Create();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataModel::Destroy() {
|
||||||
|
if (instance)
|
||||||
|
instance.reset();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DataModel::makePermanent(ModbusRegister reg, bool biased)
|
||||||
|
{
|
||||||
|
permanentStorage.emplace(reg, CappedStorage(biased));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DataModel::saveModbusParameter(ParameterSpecification param)
|
||||||
|
{
|
||||||
|
if(param.cat == Category::Alert){
|
||||||
|
short bitmask = 0;
|
||||||
|
std::memcpy(&bitmask, param.readedBytes.data(), param.length);
|
||||||
|
//Found an alert here
|
||||||
|
if(bitmask != 0)
|
||||||
|
LOG(WARNING) << "Received an alert from Modbus " << param.connection->getConnectionType() << ", ID " << param.connection->getID();
|
||||||
|
alerts.push(param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Temporary storage of last value
|
||||||
|
temporaryStorage.emplaceOrOverwrite(param.description, SavedData(param.cat, param.readedBytes));
|
||||||
|
|
||||||
|
//If parameter is listet to be stored permanently
|
||||||
|
auto res = permanentStorage.find(param.description);
|
||||||
|
if(res != permanentStorage.end()){
|
||||||
|
checkForFlushData();
|
||||||
|
res->second.store(param.readedBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataModel::checkForFlushData() {
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
auto permStorageIter = permanentStorage.begin();
|
||||||
|
auto storageIter = permanentStorage.find(permStorageIter->first);
|
||||||
|
auto& X = storageIter->second.getX();
|
||||||
|
auto& y = storageIter->second.getY();
|
||||||
|
//Rescale Matrix if data exceeds time limit
|
||||||
|
storageIter->second.lock();
|
||||||
|
if(X.size() > 1 && (X(0,1) <= (X(X.rows()-1, 1) - DataModel::permanentParamHistory))){
|
||||||
|
if(X.size() <= narrowBlock)
|
||||||
|
return;
|
||||||
|
LOG(INFO) << "Shrink permanent storage of parameter " << std::dec << (int)permStorageIter->first;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << (int)storageIter->first << "(X);";
|
||||||
|
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> temp(X.rows()-narrowBlock, X.cols());
|
||||||
|
temp = X.block(narrowBlock, 0, X.rows() - narrowBlock, X.cols());
|
||||||
|
//backup capped data to flush to file
|
||||||
|
for(int i = 0; i < narrowBlock-1; i++){
|
||||||
|
ss << std::fixed << std::setprecision(0) << X(i, X.cols()-1) << ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
X.resize(X.rows() - narrowBlock, X.cols());
|
||||||
|
X = std::move(temp);
|
||||||
|
|
||||||
|
ss << std::fixed << std::setprecision(0) << std::endl << (int)storageIter->first << "(y);";
|
||||||
|
|
||||||
|
temp.resize(y.rows()-narrowBlock, 1);
|
||||||
|
temp = y.block(narrowBlock, 0, y.rows() - narrowBlock, 1);
|
||||||
|
//backup capped data to flush to file
|
||||||
|
for(int i = 0; i < narrowBlock-1; i++){
|
||||||
|
ss << std::fixed << std::setprecision(5) << y(i) << ";";
|
||||||
|
}
|
||||||
|
ss << std::endl;
|
||||||
|
y.resize(y.rows() - narrowBlock, 1);
|
||||||
|
y = std::move(temp);
|
||||||
|
|
||||||
|
flush(ss);
|
||||||
|
}
|
||||||
|
storageIter->second.unlock();
|
||||||
|
if((++permStorageIter) == permanentStorage.end())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DataModel::flush(std::stringstream& ss)
|
||||||
|
{
|
||||||
|
//Data file lock condition
|
||||||
|
if (!accessFilesMTX.try_lock_for(timeoutMS)) {
|
||||||
|
LOG(ERROR) << "Timeout after waiting " << (long long)timeoutMS.count() << " for reading data files";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Flush data to local file";
|
||||||
|
std::fstream file;
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << dataDir << "data_" << now.time_since_epoch().count();
|
||||||
|
file.open(filename.str(), std::ios_base::out);
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << ss.str();
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG(ERROR) << "Could not open file for writing";
|
||||||
|
accessFilesMTX.unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reads in the log file to the supplied stringstream
|
||||||
|
//define fromTime to get only logs older than fromTime (seconds after epoch)
|
||||||
|
uintmax_t DataModel::readLogFile(std::stringstream& ss, long long fromTime) {
|
||||||
|
el::Loggers::flushAll();
|
||||||
|
|
||||||
|
uintmax_t sizeRead = 0;
|
||||||
|
|
||||||
|
std::filesystem::path p{ logDir };
|
||||||
|
std::ifstream file;
|
||||||
|
std::string lineBuffer;
|
||||||
|
std::filesystem::directory_iterator iterator(p);
|
||||||
|
for (auto& currentFile : std::filesystem::directory_iterator(p))
|
||||||
|
if (currentFile.is_regular_file()) {
|
||||||
|
if (logFileName.compare(currentFile.path().filename().string()) == 0) {
|
||||||
|
file.open(currentFile.path());
|
||||||
|
if (file.is_open()) {
|
||||||
|
sizeRead += currentFile.file_size();
|
||||||
|
bool foundTimePoint = false;
|
||||||
|
while (std::getline(file, lineBuffer)) {
|
||||||
|
if (lineBuffer.size() == 0)
|
||||||
|
continue;
|
||||||
|
if (fromTime != 0 && foundTimePoint == false) {
|
||||||
|
std::stringstream temp;
|
||||||
|
temp << lineBuffer;
|
||||||
|
std::tm tm{};
|
||||||
|
temp >> std::get_time(&tm, dateFormatLogger.c_str());
|
||||||
|
auto timePoint = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||||
|
if (timePoint.time_since_epoch().count() >= fromTime) {
|
||||||
|
foundTimePoint = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ss << lineBuffer << std::endl;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
LOG(INFO) << "Readed log file";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG(WARNING) << "Couldn't open LOG file for writing";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//If size read is 0, no tile at specified index found or file was empty
|
||||||
|
return sizeRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uintmax_t DataModel::readAllDataFiles(std::stringstream& ss) {
|
||||||
|
uintmax_t sizeRead = 0;
|
||||||
|
|
||||||
|
if (!accessFilesMTX.try_lock_for(timeoutMS)) {
|
||||||
|
LOG(ERROR) << "Timeout after waiting " << (long long)timeoutMS.count() << " for reading data files - blocked by another thread";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::filesystem::path p{ dataDir };
|
||||||
|
std::ifstream file;
|
||||||
|
std::string lineBuffer;
|
||||||
|
std::filesystem::directory_iterator iterator(p);
|
||||||
|
for (auto& currentFile : std::filesystem::directory_iterator(p)){
|
||||||
|
if (currentFile.is_regular_file() && std::regex_match(currentFile.path().filename().string(), regexPatternFile)) {
|
||||||
|
//look for a valid file with the specified index
|
||||||
|
file.open(currentFile.path());
|
||||||
|
if (file.is_open()) {
|
||||||
|
sizeRead += currentFile.file_size();
|
||||||
|
while (std::getline(file, lineBuffer)) {
|
||||||
|
ss << lineBuffer << std::endl;
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
std::filesystem::remove(currentFile.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accessFilesMTX.unlock();
|
||||||
|
//If size read is 0, no tile at specified index found or file was empty
|
||||||
|
return sizeRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream& DataModel::readPermanentData(std::stringstream& buffer, bool retain){
|
||||||
|
for(auto &e: permanentStorage){
|
||||||
|
buffer << (int)e.first << ":" << std::endl;
|
||||||
|
buffer << e.second;
|
||||||
|
}
|
||||||
|
if(!retain)
|
||||||
|
permanentStorage.clear();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts_queue<ParameterSpecification>& DataModel::getAlerts()
|
||||||
|
{
|
||||||
|
return alerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream& DataModel::readTemporaryData(std::stringstream& buffer){
|
||||||
|
for(auto &e: temporaryStorage){
|
||||||
|
buffer << (int)e.first << ":";
|
||||||
|
buffer << e.second;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//olderThan: files which are older than this specified time are deleted
|
||||||
|
unsigned long DataModel::removeStoredData(seconds olderThan) {
|
||||||
|
using namespace std::filesystem;
|
||||||
|
auto timeNow = duration_cast<seconds>(system_clock::now().time_since_epoch());
|
||||||
|
u_int filesDeleted = 0;
|
||||||
|
for (auto& file : directory_iterator(path("data/"))) {
|
||||||
|
if (file.is_regular_file()) {
|
||||||
|
if (std::regex_match(file.path().stem().string(), regexPatternFile)) {
|
||||||
|
std::string str = file.path().stem().string();
|
||||||
|
str = str.substr(str.find_first_of("0123456789", 0));
|
||||||
|
//time of file in seconds after 01/01/1970
|
||||||
|
long long timeOfFile = 0;
|
||||||
|
//if (auto [p, ec] = std::from_chars(str.data(), str.data() + str.length(), timeOfFile); ec == std::errc())
|
||||||
|
timeOfFile = std::stoll(str, 0);
|
||||||
|
if ((timeOfFile + olderThan.count()) < timeNow.count())
|
||||||
|
if(remove(file))
|
||||||
|
filesDeleted++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Deleted data files (" << filesDeleted << ") that were older than " << (long long)olderThan.count() <<"seconds on local storage";
|
||||||
|
return filesDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove every file that are stored locally
|
||||||
|
unsigned long DataModel::removeStoredData() {
|
||||||
|
using namespace std::filesystem;
|
||||||
|
create_directory("data/");
|
||||||
|
unsigned long filesDeleted = 0;
|
||||||
|
try{
|
||||||
|
|
||||||
|
for (auto& file : directory_iterator(path("data/"))) {
|
||||||
|
if (file.is_regular_file()) {
|
||||||
|
if (std::regex_match(file.path().stem().string(), regexPatternFile)) {
|
||||||
|
std::string str = file.path().stem().string();
|
||||||
|
str = str.substr(str.find_first_of("0123456789", 0));
|
||||||
|
filesDeleted++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(std::exception& e){
|
||||||
|
LOG(ERROR) << "Can't access data directory";
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Deleted all data files (" << filesDeleted << ") on local storage";
|
||||||
|
return filesDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const PublisherType type) {
|
||||||
|
switch (type) {
|
||||||
|
case PublisherType::RCMS_BENDER:
|
||||||
|
os << "Bender RCMS";
|
||||||
|
break;
|
||||||
|
case PublisherType::POWERCENTER:
|
||||||
|
os << "Siemens Powercenter";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
os << "<Unknown Publisher Type>";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const SavedData& savedData){
|
||||||
|
float value = 0;
|
||||||
|
std::memcpy(&value, savedData.data.data(), 4);
|
||||||
|
os << value << std::endl;
|
||||||
|
return os;
|
||||||
|
}
|
129
ConditionMonitoring/DataModel.h
Normal file
129
ConditionMonitoring/DataModel.h
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include "PublisherData.h"
|
||||||
|
#include <map>
|
||||||
|
#include <chrono>
|
||||||
|
#include <optional>
|
||||||
|
#include <regex>
|
||||||
|
#include <atomic>
|
||||||
|
#include "ModbusDataPOC.h"
|
||||||
|
#include "ModbusDataBender.h"
|
||||||
|
#include "ts_map.h"
|
||||||
|
#include "cappedstorage.h"
|
||||||
|
|
||||||
|
const Eigen::MatrixXd dummyMat(0,0);
|
||||||
|
const Eigen::VectorXd dummyVec(0);
|
||||||
|
|
||||||
|
|
||||||
|
struct SavedData{
|
||||||
|
Category cat;
|
||||||
|
std::vector<uint16_t> data;
|
||||||
|
|
||||||
|
SavedData(const Category c, const std::vector<uint16_t> d){
|
||||||
|
cat = c;
|
||||||
|
data = d;
|
||||||
|
}
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const SavedData& savedData);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PublisherInterface;
|
||||||
|
|
||||||
|
constexpr auto READ_BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
|
typedef std::vector<std::vector<float>> float_matrix;
|
||||||
|
//Type for one dimensional permanent double values
|
||||||
|
typedef ts_map<ModbusRegister, CappedStorage> permanent_data;
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
class DataModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Sigleton Methods
|
||||||
|
static std::unique_ptr<DataModel>& Instance();
|
||||||
|
static void Destroy();
|
||||||
|
static void Create();
|
||||||
|
|
||||||
|
~DataModel();
|
||||||
|
|
||||||
|
//save Data inside application
|
||||||
|
void savePublishedData(PublisherData&&);
|
||||||
|
|
||||||
|
void makePermanent(ModbusRegister reg, bool biased);
|
||||||
|
|
||||||
|
void saveModbusParameter(ParameterSpecification param);
|
||||||
|
|
||||||
|
//getter
|
||||||
|
std::vector<u_int> getSavedPublishedDataIndexes(const u_int id, const seconds newerThan);
|
||||||
|
|
||||||
|
|
||||||
|
//---local file storage methods---
|
||||||
|
//Stores in-programm data to local file system
|
||||||
|
bool flush(std::stringstream &ss);
|
||||||
|
|
||||||
|
uintmax_t readLogFile(std::stringstream& ss, long long fromTime);
|
||||||
|
|
||||||
|
//Reads in from all files their content to ss, or a certain file, specified by its index
|
||||||
|
//TODO: define readSince to read al data after that time point
|
||||||
|
//size_t readSingleFile(std::stringstream& ss, const size_t index);
|
||||||
|
uintmax_t readFromAllFiles(std::stringstream& ss, std::chrono::system_clock::time_point readSince = std::chrono::system_clock::from_time_t(0));
|
||||||
|
uintmax_t readAllDataFiles(std::stringstream& ss);
|
||||||
|
|
||||||
|
unsigned long removeStoredData(seconds olderThan);
|
||||||
|
unsigned long removeStoredData();
|
||||||
|
|
||||||
|
//saves collected data after a certain amount of time points
|
||||||
|
void checkForFlushData();
|
||||||
|
|
||||||
|
unsigned long long getStartTime(const unsigned int id);
|
||||||
|
unsigned long long getStartTime();
|
||||||
|
const char* getDataDir() { return dataDir; }
|
||||||
|
const std::regex& getRegexPatternFile() { return regexPatternFile; }
|
||||||
|
|
||||||
|
constexpr unsigned long long duration_to_sec_long(const std::chrono::system_clock::duration& t);
|
||||||
|
constexpr unsigned long long timepoint_to_sec_long(const std::chrono::system_clock::time_point& t);
|
||||||
|
|
||||||
|
const ts_map<ModbusRegister, SavedData> &getPublisherData() const;
|
||||||
|
CappedStorage* getPermanentData(ModbusRegister reg);
|
||||||
|
|
||||||
|
std::stringstream &readTemporaryData(std::stringstream &buffer);
|
||||||
|
std::stringstream &readPermanentData(std::stringstream &buffer, bool retain);
|
||||||
|
ts_queue<ParameterSpecification> &getAlerts();
|
||||||
|
|
||||||
|
private:
|
||||||
|
//Register to enqueue data wich are stored permanently
|
||||||
|
permanent_data permanentStorage;
|
||||||
|
//Temporary storage of the last readed parameter
|
||||||
|
ts_map<ModbusRegister, SavedData> temporaryStorage;
|
||||||
|
//Temporary saved alerts
|
||||||
|
ts_queue<ParameterSpecification> alerts;
|
||||||
|
|
||||||
|
static long permanentParamHistory;
|
||||||
|
static int narrowBlock;
|
||||||
|
|
||||||
|
const std::regex regexPatternFile = std::regex("data_\\w+");
|
||||||
|
const std::string logFileName = "data_analysis.log";
|
||||||
|
const std::string dateFormatLogger = "%Y-%m-%d %H:%M:%S";
|
||||||
|
u_int nrOfDataPoints = 0;
|
||||||
|
|
||||||
|
//static instance which can be accessed by calling DataModel::Instance()
|
||||||
|
static std::unique_ptr<DataModel> instance;
|
||||||
|
|
||||||
|
//local directory path to the data storage
|
||||||
|
const char* dataDir = "data/";
|
||||||
|
const char* logDir = "log/";
|
||||||
|
|
||||||
|
|
||||||
|
//Data from publishers, one elemt in outer vector for one id
|
||||||
|
//Each id consists of a vector of PublisherData (use map to make the id become a unique key)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//ostream operators (read and write dataModel data from streams)
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, DataModel& dataModel);
|
||||||
|
friend std::istream& operator>>(std::istream& is, DataModel& dataModel);
|
||||||
|
};
|
37
ConditionMonitoring/Evaluator.cpp
Normal file
37
ConditionMonitoring/Evaluator.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "Evaluator.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
|
||||||
|
|
||||||
|
Evaluator::Evaluator()
|
||||||
|
{
|
||||||
|
//initialize Linear Regression Analysis on Residual Current Register
|
||||||
|
CappedStorage* storageP = DataModel::Instance()->getPermanentData(ModbusRegister::BENDER_Residual_current);
|
||||||
|
if(storageP != nullptr){
|
||||||
|
MLAlgorithms.push_back(std::make_unique<MLLinReg>(storageP));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG(ERROR) << "Tried to invoke ML-Algorithm on non permanent or non existing parameter storage";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, std::vector<float>& vec) {
|
||||||
|
std::for_each(vec.begin(), vec.end(), [&os](float a) {os << a << " "; });
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//update all registered models
|
||||||
|
std::vector<MLAlert> Evaluator::evaluate()
|
||||||
|
{
|
||||||
|
std::vector<MLAlert> alerts;
|
||||||
|
for(auto &a: MLAlgorithms){
|
||||||
|
MLAlert alert = a->updateModel();
|
||||||
|
if(alert.type != CustomAlertTypes::NO_ALERT)
|
||||||
|
alerts.push_back(alert);
|
||||||
|
}
|
||||||
|
for(auto &a: alerts)
|
||||||
|
LOG(WARNING) << a.message;
|
||||||
|
return alerts;
|
||||||
|
}
|
||||||
|
|
25
ConditionMonitoring/Evaluator.h
Normal file
25
ConditionMonitoring/Evaluator.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include "MLAnalyzer.h"
|
||||||
|
#include "MLLinReg.h"
|
||||||
|
#include "MLAlert.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Evaluator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
//Enqueued Algorithms to perform data analysis
|
||||||
|
std::vector<std::unique_ptr<MLAnalyzer>> MLAlgorithms;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
Evaluator();
|
||||||
|
|
||||||
|
//Gets called if new data is available
|
||||||
|
std::vector<MLAlert> evaluate();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
17
ConditionMonitoring/MLAlert.h
Normal file
17
ConditionMonitoring/MLAlert.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef MLALERT_H
|
||||||
|
#define MLALERT_H
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum CustomAlertTypes{
|
||||||
|
NO_ALERT,
|
||||||
|
CRIT_RCM_TENDENCY,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MLAlert{
|
||||||
|
CustomAlertTypes type;
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
MLAlert(CustomAlertTypes type, std::string message): type(type), message(message){}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MLALERT_H
|
42
ConditionMonitoring/MLAnalyzer.cpp
Normal file
42
ConditionMonitoring/MLAnalyzer.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "MLAnalyzer.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include "DataModel.h"
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
|
||||||
|
MLAnalyzer::MLAnalyzer(CappedStorage *storage) :
|
||||||
|
n(storage->getN()), m(storage->getM()), data(storage), updateRate(SystemConfig::getIntConfigParameter("update_model_rate"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MLAnalyzer::addData(Eigen::VectorXd Px, double Py)
|
||||||
|
{
|
||||||
|
Eigen::Matrix<double, 1, 1> temp;
|
||||||
|
temp << Py;
|
||||||
|
addData(Px, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MLAnalyzer::addData(Eigen::MatrixXd Px, Eigen::VectorXd Py)
|
||||||
|
{
|
||||||
|
//if(Px.cols() != n || (Px.rows() != Py.rows())){
|
||||||
|
// std::stringstream ss;
|
||||||
|
// ss << "Invalid Matrix dimensions: ";
|
||||||
|
// throw ss.str();
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//X.conservativeResize(X.rows()+Px.rows(), Eigen::NoChange_t());
|
||||||
|
//y.conservativeResize(y.rows()+Py.rows(), Eigen::NoChange_t());
|
||||||
|
//
|
||||||
|
//X.block(m, 0, Px.rows(), 1) = Eigen::MatrixXd::Ones(Px.rows(), 1);
|
||||||
|
//X.block(m, 1, Px.rows(), Px.cols()) = Px;
|
||||||
|
//
|
||||||
|
//m += X.rows();
|
||||||
|
//
|
||||||
|
//if(++currentBatch >= trainAfterNPoints){
|
||||||
|
// updateModel();
|
||||||
|
// currentBatch = 0;
|
||||||
|
//}
|
||||||
|
}
|
37
ConditionMonitoring/MLAnalyzer.h
Normal file
37
ConditionMonitoring/MLAnalyzer.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef MLANALYZER_H
|
||||||
|
#define MLANALYZER_H
|
||||||
|
#include <chrono>
|
||||||
|
#include <vector>
|
||||||
|
#include <eigen3/Eigen/Dense>
|
||||||
|
#include "DataModel.h"
|
||||||
|
#include "MLAlert.h"
|
||||||
|
|
||||||
|
//Interface for Machine Learning algorithms
|
||||||
|
class MLAnalyzer
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::chrono::milliseconds updateTime;
|
||||||
|
|
||||||
|
const long long n;
|
||||||
|
long long m;
|
||||||
|
unsigned short currentBatch = 0;
|
||||||
|
const unsigned short trainAfterNPoints = 10;
|
||||||
|
|
||||||
|
//Data references
|
||||||
|
CappedStorage* data;
|
||||||
|
|
||||||
|
const int updateRate;
|
||||||
|
int updateCounter = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MLAnalyzer(CappedStorage *storage);
|
||||||
|
|
||||||
|
void addData(Eigen::VectorXd Px, double Py);
|
||||||
|
void addData(Eigen::MatrixXd Px, Eigen::VectorXd Py);
|
||||||
|
|
||||||
|
virtual MLAlert updateModel() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MLANALYZER_H
|
74
ConditionMonitoring/MLLinReg.cpp
Normal file
74
ConditionMonitoring/MLLinReg.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "MLLinReg.h"
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
MLLinReg::MLLinReg(CappedStorage *storage) : MLAnalyzer(storage)
|
||||||
|
{
|
||||||
|
criticalResidualCurrent = SystemConfig::getFloatConfigParameter("crit_residual_current");
|
||||||
|
criticalTimeRangeSec = SystemConfig::getIntConfigParameter("crit_residual_timerange") * SECONDS_IN_WEEK;
|
||||||
|
|
||||||
|
Theta.resize(2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MLAlert MLLinReg::updateModel()
|
||||||
|
{
|
||||||
|
if(t0 == 0 && data->getX().rows() != 0) {LOG(INFO) << std::setprecision(12) << std::fixed << "t_0 = " << (data->getX())(0, 1); t0 = (data->getX())(0, 1);}
|
||||||
|
if(++updateCounter < updateRate)
|
||||||
|
return MLAlert(CustomAlertTypes::NO_ALERT, "");
|
||||||
|
updateCounter = 0;
|
||||||
|
LOG(INFO) << "Update Linear Regression Model";
|
||||||
|
normalEquation();
|
||||||
|
bool error = checkCritical();
|
||||||
|
|
||||||
|
if(error){
|
||||||
|
//Return an alert object if tendency is critical
|
||||||
|
std::stringstream ans;
|
||||||
|
ans << "Received critical tendency in the next " << std::round(criticalTimeRangeSec/SECONDS_IN_WEEK) << " seconds";
|
||||||
|
|
||||||
|
//LOG(INFO) << "Theta values: " << Theta(0) << " " << Theta(1);
|
||||||
|
//if(first){
|
||||||
|
// std::ofstream file;
|
||||||
|
// std::stringstream ss;
|
||||||
|
// file.open("debug_lin_reg.txt", std::ios::out);
|
||||||
|
// if(file.is_open()){
|
||||||
|
// file << std::setprecision(12) << std::fixed << "Theta: " << Theta(0) << " " << Theta(1) << std::endl;
|
||||||
|
// file << std::setprecision(12) << std::fixed << "X: " << data->getX()(data->getX().rows()-1, 1) << std::endl;
|
||||||
|
// file << std::setprecision(12) << std::fixed << "y: " << data->getY()(data->getY().rows()-1) << std::endl;
|
||||||
|
// file << std::setprecision(12) << std::fixed << "t0: " << t0 << std::endl;
|
||||||
|
// file << std::setprecision(12) << std::fixed << std::endl;
|
||||||
|
// file.close();
|
||||||
|
// }
|
||||||
|
// first = false;
|
||||||
|
//}
|
||||||
|
return MLAlert(CustomAlertTypes::CRIT_RCM_TENDENCY, ans.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return MLAlert(CustomAlertTypes::NO_ALERT, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MLLinReg::checkCritical(){
|
||||||
|
//Check, if the critical value is reached within the specified time range
|
||||||
|
if(data->getM() == 0)
|
||||||
|
return false;
|
||||||
|
//Offset, to avoid checking with little data and receive faulty results
|
||||||
|
if(data->getM() < 100)
|
||||||
|
return false;
|
||||||
|
return (Theta(0) + Theta(1) * ((data->getX())((data->getX()).rows()-1, 1) + criticalTimeRangeSec))
|
||||||
|
>= criticalResidualCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Numerical approach to solve univariate Linear Regression Model
|
||||||
|
void MLLinReg::normalEquation() {
|
||||||
|
Theta = Eigen::MatrixXd::Zero(2, 1);
|
||||||
|
Theta = (data->getX().transpose() * data->getX()).inverse() * data->getX().transpose() * data->getY();
|
||||||
|
if(data->getX().rows() > 500){
|
||||||
|
LOG(INFO) << Theta(0) << " " << Theta(1);
|
||||||
|
LOG(INFO) << data->getX().rows();
|
||||||
|
}
|
||||||
|
}
|
23
ConditionMonitoring/MLLinReg.h
Normal file
23
ConditionMonitoring/MLLinReg.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef MLLINREG_H
|
||||||
|
#define MLLINREG_H
|
||||||
|
#include "MLAnalyzer.h"
|
||||||
|
|
||||||
|
constexpr int SECONDS_IN_WEEK = 7*24*60*60;
|
||||||
|
|
||||||
|
class MLLinReg: public MLAnalyzer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Eigen::MatrixXd Theta;
|
||||||
|
void normalEquation();
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
long t0 = 0;
|
||||||
|
float criticalResidualCurrent;
|
||||||
|
int criticalTimeRangeSec;
|
||||||
|
public:
|
||||||
|
MLLinReg(CappedStorage*);
|
||||||
|
MLAlert updateModel() override;
|
||||||
|
bool checkCritical();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MLLINREG_H
|
10
ConditionMonitoring/ModbusDataBender.cpp
Normal file
10
ConditionMonitoring/ModbusDataBender.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "ModbusDataBender.h"
|
||||||
|
|
||||||
|
ModbusDataBender::ModbusDataBender(const unsigned int id) : ModbusDataInterface(id)
|
||||||
|
{
|
||||||
|
//Store Modbus reading registers
|
||||||
|
//Identification
|
||||||
|
//Dummy parameter to simulate continous reading
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::BENDER_Residual_current, 100, Access::R, Category::Condition);
|
||||||
|
|
||||||
|
}
|
11
ConditionMonitoring/ModbusDataBender.h
Normal file
11
ConditionMonitoring/ModbusDataBender.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ModbusDataInterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ModbusDataBender : public ModbusDataInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModbusDataBender(const unsigned int id);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
20
ConditionMonitoring/ModbusDataInterface.cpp
Normal file
20
ConditionMonitoring/ModbusDataInterface.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "ModbusDataInterface.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Collects all ModbusRegister which fulfill the specified category
|
||||||
|
cat: specified category to look for
|
||||||
|
queue: reference to a thread safe queue, which contains the readable registers
|
||||||
|
return: the queue with the enqueued values
|
||||||
|
*/
|
||||||
|
ts_queue<ParameterSpecification>& ModbusDataInterface::modbusRegisterCat(const Category cat, ts_queue<ParameterSpecification>& queue, std::unique_ptr<ModbusInterface>& connection)
|
||||||
|
{
|
||||||
|
std::for_each(modbusParamFP32.begin(), modbusParamFP32.end(), [&queue, cat, &connection](const auto& p) { if (cat == p.getCategory()) queue.push(p.getSpecification(connection)); });
|
||||||
|
std::for_each(modbusParamFP64.begin(), modbusParamFP64.end(), [&queue, cat, &connection](const auto& p) { if (cat == p.getCategory()) queue.push(p.getSpecification(connection)); });
|
||||||
|
std::for_each(modbusParamU16.begin(), modbusParamU16.end(), [&queue, cat, &connection](const auto& p) { if (cat == p.getCategory()) queue.push(p.getSpecification(connection)); });
|
||||||
|
std::for_each(modbusParamU32.begin(), modbusParamU32.end(), [&queue, cat, &connection](const auto& p) { if (cat == p.getCategory()) queue.push(p.getSpecification(connection)); });
|
||||||
|
std::for_each(modbusParamS16.begin(), modbusParamS16.end(), [&queue, cat, &connection](const auto& p) { if (cat == p.getCategory()) queue.push(p.getSpecification(connection)); });
|
||||||
|
std::for_each(modbusParamString.begin(), modbusParamString.end(), [&queue, cat, &connection](const auto& p) { if (cat == p.getCategory()) queue.push(p.getSpecification(connection)); });
|
||||||
|
|
||||||
|
return queue;
|
||||||
|
}
|
34
ConditionMonitoring/ModbusDataInterface.h
Normal file
34
ConditionMonitoring/ModbusDataInterface.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <any>
|
||||||
|
#include <sstream>
|
||||||
|
#include <optional>
|
||||||
|
#include "ts_queue.h"
|
||||||
|
#include "ParameterDouble.h"
|
||||||
|
#include "ParameterFloat.h"
|
||||||
|
#include "ParameterUInt16.h"
|
||||||
|
#include "ParameterUInt32.h"
|
||||||
|
#include "ParameterCharP.h"
|
||||||
|
#include "ParameterS16.h"
|
||||||
|
|
||||||
|
class ModbusInterface;
|
||||||
|
|
||||||
|
class ModbusDataInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const unsigned int id;
|
||||||
|
protected:
|
||||||
|
std::vector<ParameterFloat> modbusParamFP32;
|
||||||
|
std::vector<ParameterDouble> modbusParamFP64;
|
||||||
|
std::vector<ParameterUInt16> modbusParamU16;
|
||||||
|
std::vector<ParameterUInt32> modbusParamU32;
|
||||||
|
std::vector<ParameterS16> modbusParamS16;
|
||||||
|
std::vector<ParameterCharP> modbusParamString;
|
||||||
|
public:
|
||||||
|
ModbusDataInterface(const unsigned int id) : id(id) { }
|
||||||
|
|
||||||
|
ts_queue<ParameterSpecification>& modbusRegisterCat(const Category cat, ts_queue<ParameterSpecification>& queue, std::unique_ptr<ModbusInterface> &connection);
|
||||||
|
|
||||||
|
void readAll();
|
||||||
|
};
|
247
ConditionMonitoring/ModbusDataPOC.cpp
Normal file
247
ConditionMonitoring/ModbusDataPOC.cpp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
#include "ModbusDataPOC.h"
|
||||||
|
|
||||||
|
|
||||||
|
std::string ModbusDataPOC::getStatusMessage(unsigned short statusID)
|
||||||
|
{
|
||||||
|
switch (statusID)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return "Breaker off (without realeasing)";
|
||||||
|
case 2:
|
||||||
|
return "Breaker normal (on)";
|
||||||
|
case 3:
|
||||||
|
return "Breaker released (off)";
|
||||||
|
case 4:
|
||||||
|
return "Breaker released (Lever on and blocked)";
|
||||||
|
default:
|
||||||
|
return "Status unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ModbusDataPOC::ModbusDataPOC(const unsigned int id) : ModbusDataInterface(id){
|
||||||
|
|
||||||
|
//Store Modbus reading registers
|
||||||
|
//Identification
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Manufacturer, 0x0002, Access::R);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Ordernumber, 0x0003, 20, Access::R);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Seriesnumber, 0x000D, 16, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Hardware_Version, 0x0015, Access::R);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Software_Version, 0x0016, 4, Access::R);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Plant_identification_code, 0x001D, 32, Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Installation_site, 0x002D, 22, Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Installation_date, 0x0038, 16, Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_Firmware_Applicationcontroller, 0x0045, 10, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Market, 0x005E, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Main_device_rated_current, 0x005F, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Tripping_curve_characteristic, 0x0060, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Installation_place_fuse, 0x0062, Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Ident_MLFB_fuse, 0x0063, 20, Access::RW);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_Hardware_Electronics, 0x006D, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Ident_rated_current_melting_part, 0x006E, Access::RW);
|
||||||
|
|
||||||
|
//IP
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_IP_Ethernet_MAC, 0x0200, 6, Access::R);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Status_DHCP, 0x0203, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_SNTP_server_ip, 0x0205, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_SNTP_client_mode, 0x0207, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Status_firewall, 0x0209, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_port_number, 0x020D, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Static_IP, 0x020F, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Subnetmask, 0x0211, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Gateway, 0x029D, Access::RW);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Current_IP, 0x029F, Access::R);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Current_Subnet, 0x02A1, Access::R);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_IP_Current_Gateway, 0x02A3, Access::R);
|
||||||
|
|
||||||
|
//Bluetooth
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_BT_Status, 0x0301, Access::R);
|
||||||
|
modbusParamS16.emplace_back(ModbusRegister::POC_BT_send_power, 0x0302, Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_BT_device_address, 0x0303, 6, Access::R);
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_BT_passkey, 0x0306, Access::RW);
|
||||||
|
|
||||||
|
//Radio
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_Radio_Date_time_utc, 0x02A3, Access::RW);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_1, 0x0402, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_2, 0x0403, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_3, 0x0404, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_4, 0x0405, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_5, 0x0406, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_6, 0x0407, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_7, 0x0408, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_8, 0x0409, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_9, 0x040A, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_10, 0x040B, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_11, 0x040C, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_12, 0x040D, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_13, 0x040E, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_14, 0x040F, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_15, 0x0410, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_16, 0x0411, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_17, 0x0412, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_18, 0x0413, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_19, 0x0414, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_20, 0x0415, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_21, 0x0416, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_22, 0x0417, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_23, 0x0418, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Paring_status_24, 0x0419, Access::R);
|
||||||
|
modbusParamS16.emplace_back(ModbusRegister::POC_Radio_transmit_power, 0x041A, Access::RW);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_1, 0x041B, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_2, 0x041C, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_3, 0x041D, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_4, 0x041E, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_5, 0x041F, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_6, 0x0420, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_7, 0x0421, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_8, 0x0422, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_9, 0x0423, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_10, 0x0424, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_11, 0x0425, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_12, 0x0426, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_13, 0x0427, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_14, 0x0428, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_15, 0x0429, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_16, 0x042A, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_17, 0x042B, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_18, 0x042C, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_19, 0x042D, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_20, 0x042E, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_21, 0x042F, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_22, 0x0430, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_23, 0x0431, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Device_status_24, 0x0432, Access::R);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Radio_Time_sync_to_POC, 0x0433, Access::R);
|
||||||
|
|
||||||
|
//Radio Communication
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_1, 0x0609, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_2, 0x0616, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_3, 0x0623, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_4, 0x0630, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_5, 0x063D, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_6, 0x064A, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_7, 0x0657, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_8, 0x0664, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_9, 0x0671, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_10, 0x067E, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_11, 0x068B, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_12, 0x0698, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_13, 0x06A5, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_14, 0x06B2, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_15, 0x06BF, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_16, 0x06CC, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_17, 0x06D9, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_18, 0x06E6, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_19, 0x06F3, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_20, 0x0700, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_21, 0x070D, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_22, 0x071A, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_23, 0x0727, 8 , Access::RW);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Mac_address_device_24, 0x0734, 8 , Access::RW);
|
||||||
|
|
||||||
|
//Measurement and Condition
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_Temp, 0x0C00 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_Temp_avg, 0x0C02 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_I_Phase, 0x0C04 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_I_Phase_avg, 0x0C06 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_I_Phase_max, 0x0C08 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_U_L_N, 0x0C0A ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_Freq, 0x0C0C ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_P, 0x0C0E ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_S, 0x0C10 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_Q, 0x0C12 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Cond_Cos_phi, 0x0C14 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Cond_P_in, 0x0C16 ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Cond_P_ab, 0x0C1A ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Cond_S_in, 0x0C1E ,Access::R, Category::Condition);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Cond_S_ab, 0x0C22 ,Access::R, Category::Condition);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Cond_Status, 0x0C26 ,Access::R, Category::Condition);
|
||||||
|
|
||||||
|
//Measurement settings
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_Measurement_Time_period_temperature, 0x0E02 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_Activate_temp_alert, 0x0E04 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_Limit_temperature_alert, 0x0E05 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_Hysteresis_temperature_alert, 0x0E07 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_I_Averaging_interval_s, 0x0E0D ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_I_alert1_over_on_off, 0x0E0E ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert1_over_limit_percentage, 0x0E0F ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert1_over_hysteresis, 0x0E11 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_I_alert2_over_on_off, 0x0E17 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert2_over_limit_percentage, 0x0E18 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert2_over_hysteresis, 0x0E1A ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_I_alert1_under_on_off, 0x0E20 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert1_under_limit_percentage, 0x0E21 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert1_under_hysteresis, 0x0E23 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_I_alert2_under_on_off, 0x0E29 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert2_under_limit_percentage, 0x0E2A ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_I_alert2_under_hysteresis, 0x0E2C ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_U_alert1_over_on_off, 0x0E32 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert1_over_limit_percentage, 0x0E33 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert1_over_hysteresis, 0x0E35 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_U_alert2_over_on_off, 0x0E3B ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert2_over_limit_percentage, 0x0E3C ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert2_over_hysteresis, 0x0E3E ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_U_alert1_under_on_off, 0x0E44 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert1_under_limit_percentage, 0x0E45 ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert1_under_hysteresis, 0x0E47 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_U_alert2_under_on_off, 0x0E4D ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert2_under_limit_percentage, 0x0E4E ,Access::RW );
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Measurement_U_alert2_under_hysteresis, 0x0E50 ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_Energy_flow_direction, 0x0E5A ,Access::RW );
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Measurement_Alert_on_off_AFDD_threshold_shortfall, 0x0E5C ,Access::RW );
|
||||||
|
|
||||||
|
|
||||||
|
//Diagnosis
|
||||||
|
modbusParamU32.emplace_back(ModbusRegister::POC_Diag_Alert, 0x0A00 ,Access::R , Category::Alert);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Diag_H_run_with_I, 0x0A02 ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Diag_Alert_on_off_run_total_with_I, 0x0A06 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Diag_Min_load_current, 0x0A07 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Diag_Limit_run_hours_with_I_alert, 0x0A08 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Diag_H_run_total, 0x0A12 ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Diag_Alert_on_off_run_total, 0x0A16 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP64.emplace_back(ModbusRegister::POC_Diag_Limit_run_hours_total_alert, 0x0A17 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Diag_Nr_of_mechanical_switchings, 0x0A21 ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Diag_Alert_on_off_nr_mechanical_switchings, 0x0A23 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Diag_Limit_mechanical_switchings, 0x0A24 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Diag_Nr_of_triggered_switches, 0x0A2A ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Diag_Alert_on_off_nr_triggered_switchings, 0x0A2C ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Diag_Limit_triggered_switchings, 0x0A2D ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamS16.emplace_back(ModbusRegister::POC_Diag_RSSI_BLE, 0x0A3D ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamS16.emplace_back(ModbusRegister::POC_Diag_RSSI_radio, 0x0A3E ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Diag_Nr_of_short_circuit_triggers, 0x0A40 ,Access::R , Category::Diagnosis);
|
||||||
|
modbusParamU16.emplace_back(ModbusRegister::POC_Diag_Alert_on_off_nr_short_circuit_triggers, 0x0A42 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamFP32.emplace_back(ModbusRegister::POC_Diag_Nr_of_short_circuit_triggers, 0x0A43 ,Access::RW , Category::Diagnosis);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_Diag_Time_and_sync_status, 0x0A45, 8 ,Access::R , Category::Diagnosis);
|
||||||
|
|
||||||
|
|
||||||
|
//Radio Communication
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_1, 0x0600, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_2, 0x060D, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_3, 0x061A, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_4, 0x0627, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_5, 0x0634, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_6, 0x0641, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_7, 0x064E, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_8, 0x065B, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_9, 0x0668, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_10, 0x0675, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_11, 0x0682, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_12, 0x068F, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_13, 0x069C, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_14, 0x06A9, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_15, 0x06B6, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_16, 0x06C3, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_17, 0x06D0, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_18, 0x06DD, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_19, 0x06EA, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_20, 0x06F7, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_21, 0x0704, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_22, 0x0711, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_23, 0x071E, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Installation_Code_24, 0x072B, 18, Access::W);
|
||||||
|
modbusParamString.emplace_back(ModbusRegister::POC_RadioCom_Paring_Device, 0x0738, 18, Access::W);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
20
ConditionMonitoring/ModbusDataPOC.h
Normal file
20
ConditionMonitoring/ModbusDataPOC.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <any>
|
||||||
|
#include <map>
|
||||||
|
#include "ModbusDataInterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ModbusDataPOC : public ModbusDataInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModbusDataPOC(const unsigned int id);
|
||||||
|
|
||||||
|
static std::string getStatusMessage(unsigned short statusID);
|
||||||
|
};
|
213
ConditionMonitoring/ModbusInterface.cpp
Normal file
213
ConditionMonitoring/ModbusInterface.cpp
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
#include "ModbusInterface.h"
|
||||||
|
#include "ModbusInterface.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <easylogging++.h>
|
||||||
|
|
||||||
|
void ModbusInterface::assignSlave() {
|
||||||
|
my_modbus->addSlave(slaveAddressID);
|
||||||
|
my_slave = my_modbus->slavePtr(slaveAddressID);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModbusInterface::~ModbusInterface() {
|
||||||
|
if(my_modbus != nullptr){
|
||||||
|
my_modbus->close();
|
||||||
|
delete my_modbus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::openConnection() {
|
||||||
|
modbus_init();
|
||||||
|
//if(!(my_modbus->isOpen()))
|
||||||
|
open = my_modbus->open();
|
||||||
|
if(!open){
|
||||||
|
LOG(ERROR) << "Couldn't open Modbus " << getConnectionType() <<
|
||||||
|
" connection at " << device;
|
||||||
|
LOG(ERROR) << my_modbus->lastError();
|
||||||
|
}
|
||||||
|
return open;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusInterface::disconnect() {
|
||||||
|
if(my_modbus != nullptr)
|
||||||
|
my_modbus->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::readBit(ParameterSpecification ¶m) {
|
||||||
|
if(!param.connection->getIsOpen()){
|
||||||
|
param.error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool buf;
|
||||||
|
if (my_slave->readCoil(param.address, buf) != 1) {
|
||||||
|
param.error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param.readedBytes.push_back(buf);
|
||||||
|
param.error = false;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ModbusInterface::readBits(ParameterSpecification ¶m) {
|
||||||
|
if(!param.connection->getIsOpen()){
|
||||||
|
param.error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool bufBool[param.length*8];
|
||||||
|
int ans = my_slave->readCoils(param.address, bufBool, param.length*8);
|
||||||
|
if (ans != param.length*8) {
|
||||||
|
param.error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//Big Endian decryption
|
||||||
|
for(unsigned int i = 0; i < param.length; i++){
|
||||||
|
uint8_t byte = 0;
|
||||||
|
for(unsigned int j = 0; j < 8; j++){
|
||||||
|
byte += bufBool[i*8 +j] << j;
|
||||||
|
}
|
||||||
|
param.readedBytes.push_back(byte);
|
||||||
|
}
|
||||||
|
param.error = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ModbusInterface::readByte(ParameterSpecification ¶m) {
|
||||||
|
if(!param.connection->getIsOpen()){
|
||||||
|
param.error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint16_t buf;
|
||||||
|
if (my_slave->readRegister(param.address, buf) != 1) {
|
||||||
|
param.error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param.readedBytes.push_back(buf & 0x00FF);
|
||||||
|
param.error = false;
|
||||||
|
return static_cast<uint8_t>(buf & 0x00FF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ModbusInterface::readRegister(ParameterSpecification ¶m) {
|
||||||
|
if(!param.connection->getIsOpen()){
|
||||||
|
param.error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint16_t buf;
|
||||||
|
if (my_slave->readRegister(param.address, buf) != 1) {
|
||||||
|
param.error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param.readedBytes.push_back(buf);
|
||||||
|
param.error = false;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ModbusInterface::readDRegister(ParameterSpecification ¶m) {
|
||||||
|
if(!param.connection->getIsOpen()){
|
||||||
|
param.error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint16_t buf[2];
|
||||||
|
|
||||||
|
if (my_slave->readRegisters(param.address, buf, 2) != 2) {
|
||||||
|
param.error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param.readedBytes.push_back(*buf);
|
||||||
|
param.readedBytes.push_back(*(buf+1));
|
||||||
|
param.error = false;
|
||||||
|
return _MODBUS_GET_INT32_FROM_INT16(buf, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ModbusInterface::readQRegister(ParameterSpecification ¶m) {
|
||||||
|
if(!param.connection->getIsOpen()){
|
||||||
|
param.error = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t buf[4];
|
||||||
|
int ans = my_slave->readRegisters(param.address, buf, 4);
|
||||||
|
if (ans != 4) {
|
||||||
|
param.error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param.readedBytes.push_back(*buf);
|
||||||
|
param.readedBytes.push_back(*(buf+1));
|
||||||
|
param.readedBytes.push_back(*(buf+2));
|
||||||
|
param.readedBytes.push_back(*(buf+3));
|
||||||
|
param.error = false;
|
||||||
|
return _MODBUS_GET_INT64_FROM_INT16(buf, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::writeBit(const uint16_t address, bool bit)
|
||||||
|
{
|
||||||
|
if(my_slave->writeCoil(address, bit) != 1){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::writeByte(const uint16_t address, uint8_t byte)
|
||||||
|
{
|
||||||
|
bool buf[8];
|
||||||
|
for(int i = 0; i < 8; i++){
|
||||||
|
buf[i] = byte & 0x01;
|
||||||
|
byte = byte > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(my_slave->writeCoils(address, buf, 8) != 1){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::writeRegister(const uint16_t address, uint16_t word)
|
||||||
|
{
|
||||||
|
if(my_slave->writeRegister(address, word) != 1){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::writeDRegister(const uint16_t address, uint32_t dword)
|
||||||
|
{
|
||||||
|
uint16_t data[2];
|
||||||
|
data[0] = (dword & 0x0000FFFF);
|
||||||
|
data[0] = (dword & 0xFFFF0000)>>16;
|
||||||
|
|
||||||
|
if(my_slave->writeRegisters(address, data, 2) != 1){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModbusInterface::writeQRegister(const uint16_t address, uint64_t qword)
|
||||||
|
{
|
||||||
|
uint16_t data[4];
|
||||||
|
|
||||||
|
data[0] = (qword & 0x0000'0000'0000'FFFF);
|
||||||
|
data[1] = (qword & 0x0000'0000'FFFF'0000) >> 16;
|
||||||
|
data[2] = (qword & 0x0000'FFFF'0000'0000) >> 32;
|
||||||
|
data[3] = (qword & 0xFFFF'0000'0000'0000) >> 48;
|
||||||
|
|
||||||
|
if(my_slave->writeRegisters(address, data, 4) != 1){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
54
ConditionMonitoring/ModbusInterface.h
Normal file
54
ConditionMonitoring/ModbusInterface.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <modbuspp.h>
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
|
||||||
|
class ModbusInterface {
|
||||||
|
private:
|
||||||
|
unsigned int slaveAddressID;
|
||||||
|
bool open;
|
||||||
|
protected:
|
||||||
|
Modbus::Master* my_modbus = nullptr;
|
||||||
|
Modbus::Slave* my_slave = nullptr;
|
||||||
|
|
||||||
|
//IP (TCP) or serial port (RTU)
|
||||||
|
std::string device;
|
||||||
|
|
||||||
|
void assignSlave();
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModbusInterface(u_int _id, std::string _device) : slaveAddressID(_id), device(_device) { };
|
||||||
|
virtual ~ModbusInterface();
|
||||||
|
virtual void modbus_init() = 0;
|
||||||
|
virtual std::string getConnectionType() = 0;
|
||||||
|
|
||||||
|
bool openConnection();
|
||||||
|
void disconnect();
|
||||||
|
bool getIsOpen() const { return open; }
|
||||||
|
|
||||||
|
unsigned int getID(){ return slaveAddressID; }
|
||||||
|
|
||||||
|
//Read and write functions
|
||||||
|
bool readBit(ParameterSpecification ¶m);
|
||||||
|
bool readBits(ParameterSpecification ¶m);
|
||||||
|
uint8_t readByte(ParameterSpecification ¶m);
|
||||||
|
uint16_t readRegister(ParameterSpecification ¶m);
|
||||||
|
uint32_t readDRegister(ParameterSpecification ¶m);
|
||||||
|
uint64_t readQRegister(ParameterSpecification ¶m);
|
||||||
|
|
||||||
|
bool writeBit(const uint16_t address, bool bit);
|
||||||
|
bool writeByte(const uint16_t address, uint8_t byte);
|
||||||
|
bool writeRegister(const uint16_t address, uint16_t word);
|
||||||
|
bool writeDRegister(const uint16_t address, uint32_t dword);
|
||||||
|
bool writeQRegister(const uint16_t address, uint64_t qword);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define _MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
|
||||||
|
(((int64_t)tab_int16[(index) ] << 48) + \
|
||||||
|
((int64_t)tab_int16[(index) + 1] << 32) + \
|
||||||
|
((int64_t)tab_int16[(index) + 2] << 16) + \
|
||||||
|
(int64_t)tab_int16[(index) + 3])
|
||||||
|
#define _MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
|
||||||
|
#define _MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
|
283
ConditionMonitoring/ModbusRegister.h
Normal file
283
ConditionMonitoring/ModbusRegister.h
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
enum class Category {
|
||||||
|
//Category for collective reading accesses
|
||||||
|
NONE,
|
||||||
|
Condition,
|
||||||
|
Diagnosis,
|
||||||
|
Alert
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum class ModbusRegister {
|
||||||
|
//---------------------Powercenter----------------------------
|
||||||
|
//Information for identification
|
||||||
|
POC_Ident_Manufacturer,
|
||||||
|
POC_Ident_Ordernumber,
|
||||||
|
POC_Ident_Seriesnumber,
|
||||||
|
POC_Ident_Hardware_Version,
|
||||||
|
POC_Ident_Software_Version,
|
||||||
|
POC_Ident_Plant_identification_code,
|
||||||
|
POC_Ident_Installation_site,
|
||||||
|
POC_Ident_Installation_date,
|
||||||
|
POC_Ident_Firmware_Applicationcontroller,
|
||||||
|
POC_Ident_Market,
|
||||||
|
POC_Ident_Main_device_rated_current,
|
||||||
|
POC_Ident_Tripping_curve_characteristic,
|
||||||
|
POC_Ident_Installation_place_fuse,
|
||||||
|
POC_Ident_MLFB_fuse,
|
||||||
|
POC_Ident_Hardware_Electronics,
|
||||||
|
POC_Ident_rated_current_melting_part,
|
||||||
|
//IP Information
|
||||||
|
POC_IP_Ethernet_MAC,
|
||||||
|
POC_IP_Status_DHCP,
|
||||||
|
POC_IP_SNTP_server_ip,
|
||||||
|
POC_IP_SNTP_client_mode,
|
||||||
|
POC_IP_Status_firewall,
|
||||||
|
POC_IP_port_number,
|
||||||
|
POC_IP_Static_IP,
|
||||||
|
POC_IP_Subnetmask,
|
||||||
|
POC_IP_Gateway,
|
||||||
|
POC_IP_Current_IP,
|
||||||
|
POC_IP_Current_Subnet,
|
||||||
|
POC_IP_Current_Gateway,
|
||||||
|
//Bluetooth Information
|
||||||
|
POC_BT_Status,
|
||||||
|
POC_BT_send_power,
|
||||||
|
POC_BT_device_address,
|
||||||
|
POC_BT_passkey,
|
||||||
|
//Radio Information
|
||||||
|
POC_Radio_Date_time_utc,
|
||||||
|
POC_Radio_Paring_status_1,
|
||||||
|
POC_Radio_Paring_status_2,
|
||||||
|
POC_Radio_Paring_status_3,
|
||||||
|
POC_Radio_Paring_status_4,
|
||||||
|
POC_Radio_Paring_status_5,
|
||||||
|
POC_Radio_Paring_status_6,
|
||||||
|
POC_Radio_Paring_status_7,
|
||||||
|
POC_Radio_Paring_status_8,
|
||||||
|
POC_Radio_Paring_status_9,
|
||||||
|
POC_Radio_Paring_status_10,
|
||||||
|
POC_Radio_Paring_status_11,
|
||||||
|
POC_Radio_Paring_status_12,
|
||||||
|
POC_Radio_Paring_status_13,
|
||||||
|
POC_Radio_Paring_status_14,
|
||||||
|
POC_Radio_Paring_status_15,
|
||||||
|
POC_Radio_Paring_status_16,
|
||||||
|
POC_Radio_Paring_status_17,
|
||||||
|
POC_Radio_Paring_status_18,
|
||||||
|
POC_Radio_Paring_status_19,
|
||||||
|
POC_Radio_Paring_status_20,
|
||||||
|
POC_Radio_Paring_status_21,
|
||||||
|
POC_Radio_Paring_status_22,
|
||||||
|
POC_Radio_Paring_status_23,
|
||||||
|
POC_Radio_Paring_status_24,
|
||||||
|
POC_Radio_transmit_power,
|
||||||
|
POC_Radio_Device_status_1,
|
||||||
|
POC_Radio_Device_status_2,
|
||||||
|
POC_Radio_Device_status_3,
|
||||||
|
POC_Radio_Device_status_4,
|
||||||
|
POC_Radio_Device_status_5,
|
||||||
|
POC_Radio_Device_status_6,
|
||||||
|
POC_Radio_Device_status_7,
|
||||||
|
POC_Radio_Device_status_8,
|
||||||
|
POC_Radio_Device_status_9,
|
||||||
|
POC_Radio_Device_status_10,
|
||||||
|
POC_Radio_Device_status_11,
|
||||||
|
POC_Radio_Device_status_12,
|
||||||
|
POC_Radio_Device_status_13,
|
||||||
|
POC_Radio_Device_status_14,
|
||||||
|
POC_Radio_Device_status_15,
|
||||||
|
POC_Radio_Device_status_16,
|
||||||
|
POC_Radio_Device_status_17,
|
||||||
|
POC_Radio_Device_status_18,
|
||||||
|
POC_Radio_Device_status_19,
|
||||||
|
POC_Radio_Device_status_20,
|
||||||
|
POC_Radio_Device_status_21,
|
||||||
|
POC_Radio_Device_status_22,
|
||||||
|
POC_Radio_Device_status_23,
|
||||||
|
POC_Radio_Device_status_24,
|
||||||
|
POC_Radio_Time_sync_to_POC,
|
||||||
|
//Radio Communication Information
|
||||||
|
POC_RadioCom_Mac_address_device_1,
|
||||||
|
POC_RadioCom_Mac_address_device_2,
|
||||||
|
POC_RadioCom_Mac_address_device_3,
|
||||||
|
POC_RadioCom_Mac_address_device_4,
|
||||||
|
POC_RadioCom_Mac_address_device_5,
|
||||||
|
POC_RadioCom_Mac_address_device_6,
|
||||||
|
POC_RadioCom_Mac_address_device_7,
|
||||||
|
POC_RadioCom_Mac_address_device_8,
|
||||||
|
POC_RadioCom_Mac_address_device_9,
|
||||||
|
POC_RadioCom_Mac_address_device_10,
|
||||||
|
POC_RadioCom_Mac_address_device_11,
|
||||||
|
POC_RadioCom_Mac_address_device_12,
|
||||||
|
POC_RadioCom_Mac_address_device_13,
|
||||||
|
POC_RadioCom_Mac_address_device_14,
|
||||||
|
POC_RadioCom_Mac_address_device_15,
|
||||||
|
POC_RadioCom_Mac_address_device_16,
|
||||||
|
POC_RadioCom_Mac_address_device_17,
|
||||||
|
POC_RadioCom_Mac_address_device_18,
|
||||||
|
POC_RadioCom_Mac_address_device_19,
|
||||||
|
POC_RadioCom_Mac_address_device_20,
|
||||||
|
POC_RadioCom_Mac_address_device_21,
|
||||||
|
POC_RadioCom_Mac_address_device_22,
|
||||||
|
POC_RadioCom_Mac_address_device_23,
|
||||||
|
POC_RadioCom_Mac_address_device_24,
|
||||||
|
|
||||||
|
//Measurement Settings
|
||||||
|
POC_Measurement_Time_period_temperature,
|
||||||
|
POC_Measurement_Activate_temp_alert,
|
||||||
|
POC_Measurement_Limit_temperature_alert,
|
||||||
|
POC_Measurement_Hysteresis_temperature_alert,
|
||||||
|
POC_Measurement_I_Averaging_interval_s,
|
||||||
|
//Current Alerts
|
||||||
|
POC_Measurement_I_alert1_over_on_off,
|
||||||
|
POC_Measurement_I_alert1_over_limit_percentage,
|
||||||
|
POC_Measurement_I_alert1_over_hysteresis,
|
||||||
|
POC_Measurement_I_alert2_over_on_off,
|
||||||
|
POC_Measurement_I_alert2_over_limit_percentage,
|
||||||
|
POC_Measurement_I_alert2_over_hysteresis,
|
||||||
|
POC_Measurement_I_alert1_under_on_off,
|
||||||
|
POC_Measurement_I_alert1_under_limit_percentage,
|
||||||
|
POC_Measurement_I_alert1_under_hysteresis,
|
||||||
|
POC_Measurement_I_alert2_under_on_off,
|
||||||
|
POC_Measurement_I_alert2_under_limit_percentage,
|
||||||
|
POC_Measurement_I_alert2_under_hysteresis,
|
||||||
|
//Voltage Alerts
|
||||||
|
POC_Measurement_U_alert1_over_on_off,
|
||||||
|
POC_Measurement_U_alert1_over_limit_percentage,
|
||||||
|
POC_Measurement_U_alert1_over_hysteresis,
|
||||||
|
POC_Measurement_U_alert2_over_on_off,
|
||||||
|
POC_Measurement_U_alert2_over_limit_percentage,
|
||||||
|
POC_Measurement_U_alert2_over_hysteresis,
|
||||||
|
POC_Measurement_U_alert1_under_on_off,
|
||||||
|
POC_Measurement_U_alert1_under_limit_percentage,
|
||||||
|
POC_Measurement_U_alert1_under_hysteresis,
|
||||||
|
POC_Measurement_U_alert2_under_on_off,
|
||||||
|
POC_Measurement_U_alert2_under_limit_percentage,
|
||||||
|
POC_Measurement_U_alert2_under_hysteresis,
|
||||||
|
|
||||||
|
POC_Measurement_Energy_flow_direction,
|
||||||
|
POC_Measurement_Alert_on_off_AFDD_threshold_shortfall,
|
||||||
|
|
||||||
|
//Switch gears condition
|
||||||
|
POC_Cond_Temp, //°C
|
||||||
|
POC_Cond_Temp_avg, //°C
|
||||||
|
POC_Cond_I_Phase, //A
|
||||||
|
POC_Cond_I_Phase_avg, //A
|
||||||
|
POC_Cond_I_Phase_max, //A
|
||||||
|
POC_Cond_U_L_N, //V
|
||||||
|
POC_Cond_Freq, //Hz
|
||||||
|
POC_Cond_P, //W
|
||||||
|
POC_Cond_S, //W
|
||||||
|
POC_Cond_Q, //Var
|
||||||
|
POC_Cond_Cos_phi,
|
||||||
|
POC_Cond_P_in, //Wh
|
||||||
|
POC_Cond_P_ab, //Wh
|
||||||
|
POC_Cond_S_in, //Varh
|
||||||
|
POC_Cond_S_ab, //Varh
|
||||||
|
POC_Cond_Status,
|
||||||
|
|
||||||
|
//Powercenter Diagnosis
|
||||||
|
POC_Diag_Alert,
|
||||||
|
//Hours run with current flow
|
||||||
|
POC_Diag_H_run_with_I, //s
|
||||||
|
POC_Diag_Alert_on_off_run_total_with_I,
|
||||||
|
POC_Diag_Min_load_current,
|
||||||
|
POC_Diag_Limit_run_hours_with_I_alert,
|
||||||
|
POC_Diag_H_run_total, //s
|
||||||
|
POC_Diag_Alert_on_off_run_total,
|
||||||
|
POC_Diag_Limit_run_hours_total_alert,
|
||||||
|
POC_Diag_Nr_of_mechanical_switchings,
|
||||||
|
POC_Diag_Alert_on_off_nr_mechanical_switchings,
|
||||||
|
POC_Diag_Limit_mechanical_switchings,
|
||||||
|
POC_Diag_Nr_of_triggered_switches,
|
||||||
|
POC_Diag_Alert_on_off_nr_triggered_switchings,
|
||||||
|
POC_Diag_Limit_triggered_switchings,
|
||||||
|
//Received Signal Strength Indicator in dbm
|
||||||
|
POC_Diag_RSSI_BLE,
|
||||||
|
POC_Diag_RSSI_radio,
|
||||||
|
POC_Diag_Nr_of_short_circuit_triggers,
|
||||||
|
POC_Diag_Alert_on_off_nr_short_circuit_triggers,
|
||||||
|
POC_Diag_Limit_shoer_circuit_triggers,
|
||||||
|
POC_Diag_Time_and_sync_status,
|
||||||
|
|
||||||
|
//Radio communication settings
|
||||||
|
POC_RadioCom_Installation_Code_1,
|
||||||
|
POC_RadioCom_Installation_Code_2,
|
||||||
|
POC_RadioCom_Installation_Code_3,
|
||||||
|
POC_RadioCom_Installation_Code_4,
|
||||||
|
POC_RadioCom_Installation_Code_5,
|
||||||
|
POC_RadioCom_Installation_Code_6,
|
||||||
|
POC_RadioCom_Installation_Code_7,
|
||||||
|
POC_RadioCom_Installation_Code_8,
|
||||||
|
POC_RadioCom_Installation_Code_9,
|
||||||
|
POC_RadioCom_Installation_Code_10,
|
||||||
|
POC_RadioCom_Installation_Code_11,
|
||||||
|
POC_RadioCom_Installation_Code_12,
|
||||||
|
POC_RadioCom_Installation_Code_13,
|
||||||
|
POC_RadioCom_Installation_Code_14,
|
||||||
|
POC_RadioCom_Installation_Code_15,
|
||||||
|
POC_RadioCom_Installation_Code_16,
|
||||||
|
POC_RadioCom_Installation_Code_17,
|
||||||
|
POC_RadioCom_Installation_Code_18,
|
||||||
|
POC_RadioCom_Installation_Code_19,
|
||||||
|
POC_RadioCom_Installation_Code_20,
|
||||||
|
POC_RadioCom_Installation_Code_21,
|
||||||
|
POC_RadioCom_Installation_Code_22,
|
||||||
|
POC_RadioCom_Installation_Code_23,
|
||||||
|
POC_RadioCom_Installation_Code_24,
|
||||||
|
|
||||||
|
POC_RadioCom_Paring_Device,
|
||||||
|
|
||||||
|
POC_RadioCom_Paring_device_1,
|
||||||
|
POC_RadioCom_Paring_device_2,
|
||||||
|
POC_RadioCom_Paring_device_3,
|
||||||
|
POC_RadioCom_Paring_device_4,
|
||||||
|
POC_RadioCom_Paring_device_5,
|
||||||
|
POC_RadioCom_Paring_device_6,
|
||||||
|
POC_RadioCom_Paring_device_7,
|
||||||
|
POC_RadioCom_Paring_device_8,
|
||||||
|
POC_RadioCom_Paring_device_9,
|
||||||
|
POC_RadioCom_Paring_device_10,
|
||||||
|
POC_RadioCom_Paring_device_11,
|
||||||
|
POC_RadioCom_Paring_device_12,
|
||||||
|
POC_RadioCom_Paring_device_13,
|
||||||
|
POC_RadioCom_Paring_device_14,
|
||||||
|
POC_RadioCom_Paring_device_15,
|
||||||
|
POC_RadioCom_Paring_device_16,
|
||||||
|
POC_RadioCom_Paring_device_17,
|
||||||
|
POC_RadioCom_Paring_device_18,
|
||||||
|
POC_RadioCom_Paring_device_19,
|
||||||
|
POC_RadioCom_Paring_device_20,
|
||||||
|
POC_RadioCom_Paring_device_21,
|
||||||
|
POC_RadioCom_Paring_device_22,
|
||||||
|
POC_RadioCom_Paring_device_23,
|
||||||
|
POC_RadioCom_Paring_device_24,
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------Bender----------------------------
|
||||||
|
//Test variable to be read from virtual RCM device
|
||||||
|
BENDER_Residual_current,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace CMD {
|
||||||
|
enum class Identification {
|
||||||
|
Trigger_flash_light,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class IP {
|
||||||
|
Apply_ethernet_configuration_changes,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Bluetooth {
|
||||||
|
Switch_on_off_BT_Reset_passkey,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MeasurementSettings {
|
||||||
|
Reset_energy_counter,
|
||||||
|
Reset_extrem_values,
|
||||||
|
};
|
||||||
|
}
|
31
ConditionMonitoring/ModbusRtu.cpp
Normal file
31
ConditionMonitoring/ModbusRtu.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "ModbusRtu.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
inline std::string ModbusRTU::getSettingsString() const
|
||||||
|
{
|
||||||
|
return std::to_string(baud) + pairity + std::to_string(stopBit);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModbusRTU::~ModbusRTU()
|
||||||
|
{
|
||||||
|
//if(my_slave != nullptr){
|
||||||
|
// delete my_slave;
|
||||||
|
//}
|
||||||
|
//if(my_modbus != nullptr){
|
||||||
|
// my_modbus->close();
|
||||||
|
// delete my_modbus;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModbusRTU::ModbusRTU(const u_int id, const std::string _device, const unsigned int _baud, const char _pairity, const unsigned int _stopBit)
|
||||||
|
: ModbusInterface(id, _device), baud(_baud), pairity(_pairity), stopBit(_stopBit)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusRTU::modbus_init() {
|
||||||
|
if(my_modbus == nullptr){
|
||||||
|
my_modbus = new Modbus::Master(Modbus::Rtu, device, getSettingsString());
|
||||||
|
assignSlave();
|
||||||
|
}
|
||||||
|
}
|
26
ConditionMonitoring/ModbusRtu.h
Normal file
26
ConditionMonitoring/ModbusRtu.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <modbuspp.h>
|
||||||
|
#include "ModbusInterface.h"
|
||||||
|
|
||||||
|
class ModbusRTU :
|
||||||
|
public ModbusInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
unsigned int baud;
|
||||||
|
char pairity;
|
||||||
|
unsigned int stopBit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Create settings string
|
||||||
|
std::string getSettingsString() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModbusRTU(const u_int id, const std::string _device, const u_int _baud, const char _pairity, const u_int _stopBit);
|
||||||
|
virtual ~ModbusRTU();
|
||||||
|
virtual void modbus_init() override;
|
||||||
|
|
||||||
|
std::string getConnectionType()override { return "Rtu"; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
25
ConditionMonitoring/ModbusTcp.cpp
Normal file
25
ConditionMonitoring/ModbusTcp.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "ModbusTcp.h"
|
||||||
|
|
||||||
|
ModbusTCP::ModbusTCP(const u_int id, const std::string _ip, const unsigned int _port)
|
||||||
|
: ModbusInterface(id, _ip), port(std::to_string(_port))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ModbusTCP::~ModbusTCP()
|
||||||
|
{
|
||||||
|
//if(my_slave != nullptr){
|
||||||
|
// delete my_slave;
|
||||||
|
//}
|
||||||
|
//if(my_modbus != nullptr){
|
||||||
|
// my_modbus->close();
|
||||||
|
// delete my_modbus;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModbusTCP::modbus_init() {
|
||||||
|
if (my_modbus == nullptr){
|
||||||
|
my_modbus = new Modbus::Master(Modbus::Tcp, device, port);
|
||||||
|
assignSlave();
|
||||||
|
}
|
||||||
|
}
|
20
ConditionMonitoring/ModbusTcp.h
Normal file
20
ConditionMonitoring/ModbusTcp.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <modbuspp.h>
|
||||||
|
#include "ModbusInterface.h"
|
||||||
|
|
||||||
|
class ModbusTCP :
|
||||||
|
public ModbusInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string port = "502";
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModbusTCP(const u_int id, const std::string _ip, const u_int _port);
|
||||||
|
virtual ~ModbusTCP();
|
||||||
|
virtual void modbus_init() override;
|
||||||
|
|
||||||
|
std::string getConnectionType()override { return "Tcp"; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
128
ConditionMonitoring/NetServer.cpp
Normal file
128
ConditionMonitoring/NetServer.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include "NetServer.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include "DataModel.h"
|
||||||
|
|
||||||
|
void NetServer::Stop()
|
||||||
|
{
|
||||||
|
net::ServerInterface<net::MessageTypes>::Stop();
|
||||||
|
LOG(INFO) << "[SERVER] Stopped Server";
|
||||||
|
serverRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetServer::Start()
|
||||||
|
{
|
||||||
|
if(serverRunning){
|
||||||
|
LOG(WARNING) << "[SERVER] tried to start ip tcp server, but it is already running";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = net::ServerInterface<net::MessageTypes>::Start();
|
||||||
|
if(res){
|
||||||
|
LOG(INFO) << "[SERVER] Started Server";
|
||||||
|
serverRunning = true;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "[SERVER] Couldn't start Server";
|
||||||
|
serverRunning = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetServer::OnClientConnect(std::shared_ptr<net::Connection<net::MessageTypes>> client)
|
||||||
|
{
|
||||||
|
//Decide whether to accept or deny connection (always accept in this case)
|
||||||
|
net::Message<net::MessageTypes> msg;
|
||||||
|
msg.header.id = net::MessageTypes::ServerAccept;
|
||||||
|
client->Send(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called when a client appears to have disconnected
|
||||||
|
void NetServer::OnClientDisconnect(std::shared_ptr<net::Connection<net::MessageTypes>> client)
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Removing client [" << client->GetID() << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called when a message arrives
|
||||||
|
void NetServer::OnMessage(std::shared_ptr<net::Connection<net::MessageTypes>> client, net::Message<net::MessageTypes>& msgRcv)
|
||||||
|
{
|
||||||
|
net::Message<net::MessageTypes> msgSend;
|
||||||
|
std::stringstream body;
|
||||||
|
|
||||||
|
switch (msgRcv.header.id)
|
||||||
|
{
|
||||||
|
case net::MessageTypes::ServerData:
|
||||||
|
LOG(INFO) << "[Client " << client->GetID() << "]: Request Server Data";
|
||||||
|
msgSend.header.id = net::MessageTypes::ServerData;
|
||||||
|
getBodyData(body);
|
||||||
|
msgSend << body.str();
|
||||||
|
client->Send(msgSend);
|
||||||
|
break;
|
||||||
|
case net::MessageTypes::ServerCondition:
|
||||||
|
LOG(INFO) << "[Client " << client->GetID() << "]: Request temporary Condition Data";
|
||||||
|
msgSend.header.id = net::MessageTypes::ServerCondition;
|
||||||
|
getBodyCondition(body);
|
||||||
|
msgSend << body.str();
|
||||||
|
client->Send(msgSend);
|
||||||
|
break;
|
||||||
|
case net::MessageTypes::ServerAlert:
|
||||||
|
LOG(INFO) << "[Client " << client->GetID() << "]: Request Alert Data";
|
||||||
|
msgSend.header.id = net::MessageTypes::ServerAlert;
|
||||||
|
client->Send(msgSend);
|
||||||
|
break;
|
||||||
|
case net::MessageTypes::ServerLog:
|
||||||
|
LOG(INFO) << "[Client " << client->GetID() << "]: Request Log Files";
|
||||||
|
msgSend.header.id = net::MessageTypes::ServerLog;
|
||||||
|
getBodyLog(body, msgRcv);
|
||||||
|
msgSend << body.str();
|
||||||
|
client->Send(msgSend);
|
||||||
|
break;
|
||||||
|
case net::MessageTypes::ServerCloseConnection:
|
||||||
|
LOG(INFO) << "[Client " << client->GetID() << "]: Request disconnection";
|
||||||
|
client->Disconnect();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(ERROR) << "[Client " << client->GetID() << "]: Invaild reuqest code";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetServer::notifyAllConnections(net::Message<net::MessageTypes> &message)
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Sent broadcast to ";
|
||||||
|
unsigned int counter = 0;
|
||||||
|
//Send message to all listed active connections
|
||||||
|
for(auto &connection: m_deqConnections){
|
||||||
|
connection->Send(message);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Sent broadcast to " << counter << " devices";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::stringstream& NetServer::getBodyData(std::stringstream& buffer)
|
||||||
|
{
|
||||||
|
DataModel::Instance()->readAllDataFiles(buffer);
|
||||||
|
DataModel::Instance()->readPermanentData(buffer, false);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream& NetServer::getBodyLog(std::stringstream& buffer, net::Message<net::MessageTypes> msgRcv)
|
||||||
|
{
|
||||||
|
unsigned long long fromTime;
|
||||||
|
if (msgRcv.header.size == 0)
|
||||||
|
fromTime = 0;
|
||||||
|
else
|
||||||
|
msgRcv >> fromTime;
|
||||||
|
DataModel::Instance()->readLogFile(buffer, fromTime);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream& NetServer::getBodyCondition(std::stringstream& buffer)
|
||||||
|
{
|
||||||
|
DataModel::Instance()->readTemporaryData(buffer);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
54
ConditionMonitoring/NetServer.h
Normal file
54
ConditionMonitoring/NetServer.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include "net_server_client.h"
|
||||||
|
|
||||||
|
namespace net {
|
||||||
|
enum class MessageTypes : uint32_t
|
||||||
|
{
|
||||||
|
ServerAccept,
|
||||||
|
ServerDeny,
|
||||||
|
ServerData,
|
||||||
|
ServerLog,
|
||||||
|
ServerCondition,
|
||||||
|
ServerAlert,
|
||||||
|
ServerCloseConnection,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class NetServer : public net::ServerInterface<net::MessageTypes>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NetServer(uint16_t nPort) : net::ServerInterface<net::MessageTypes>(nPort) {}
|
||||||
|
NetServer() = delete;
|
||||||
|
NetServer(NetServer&) = delete;
|
||||||
|
|
||||||
|
void Stop() override;
|
||||||
|
bool Start() override;
|
||||||
|
|
||||||
|
bool isRunning(){return serverRunning;}
|
||||||
|
|
||||||
|
void notifyAllConnections(net::Message<net::MessageTypes>& message);
|
||||||
|
|
||||||
|
bool serverRunning = false;
|
||||||
|
protected:
|
||||||
|
virtual bool OnClientConnect(std::shared_ptr<net::Connection<net::MessageTypes>> client) override;
|
||||||
|
|
||||||
|
// Called when a client appears to have disconnected
|
||||||
|
virtual void OnClientDisconnect(std::shared_ptr<net::Connection<net::MessageTypes>> client) override;
|
||||||
|
|
||||||
|
// Called when a message arrives
|
||||||
|
virtual void OnMessage(std::shared_ptr<net::Connection<net::MessageTypes>> client, net::Message<net::MessageTypes>& msg) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//Functions to collect the data for response message body
|
||||||
|
|
||||||
|
//Collects Data message body
|
||||||
|
std::stringstream& getBodyData(std::stringstream& buffer);
|
||||||
|
//Collects Lof files message body
|
||||||
|
std::stringstream& getBodyLog(std::stringstream& buffer, net::Message<net::MessageTypes> msgRcv);
|
||||||
|
//Collects Electrical Condition values message body
|
||||||
|
std::stringstream& getBodyCondition(std::stringstream& buffer);
|
||||||
|
|
||||||
|
};
|
1
ConditionMonitoring/ParameterCharP.cpp
Normal file
1
ConditionMonitoring/ParameterCharP.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "ParameterCharP.h"
|
15
ConditionMonitoring/ParameterCharP.h
Normal file
15
ConditionMonitoring/ParameterCharP.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
|
||||||
|
class ParameterCharP : public ParameterInterface<char*>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
char* param = nullptr;
|
||||||
|
const uint8_t length;
|
||||||
|
public:
|
||||||
|
ParameterCharP(const ModbusRegister description, const uint16_t address, const uint8_t _length, const Access access) : ParameterInterface(description, address, access), length(_length) {};
|
||||||
|
ParameterCharP(const ModbusRegister description, const unsigned short address, const uint8_t _length, const Access access, const Category cat) : ParameterInterface(description, address, access, cat), length(_length) {};
|
||||||
|
virtual ~ParameterCharP(){}
|
||||||
|
|
||||||
|
uint8_t getSize() const override { return length; }
|
||||||
|
};
|
2
ConditionMonitoring/ParameterDouble.cpp
Normal file
2
ConditionMonitoring/ParameterDouble.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "ParameterDouble.h"
|
||||||
|
|
16
ConditionMonitoring/ParameterDouble.h
Normal file
16
ConditionMonitoring/ParameterDouble.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
typedef double FP64;
|
||||||
|
|
||||||
|
class ParameterDouble : public ParameterInterface<FP64>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
FP64 param = 0.0;
|
||||||
|
public:
|
||||||
|
ParameterDouble(const ModbusRegister description, uint16_t address, Access access) : ParameterInterface(description, address, access) {};
|
||||||
|
ParameterDouble(const ModbusRegister description, const unsigned short address, const Access access, const Category cat) : ParameterInterface(description, address, access, cat) {};
|
||||||
|
virtual ~ParameterDouble(){}
|
||||||
|
|
||||||
|
uint8_t getSize() const override { return 64; }
|
||||||
|
|
||||||
|
};
|
2
ConditionMonitoring/ParameterFloat.cpp
Normal file
2
ConditionMonitoring/ParameterFloat.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "ParameterFloat.h"
|
||||||
|
|
17
ConditionMonitoring/ParameterFloat.h
Normal file
17
ConditionMonitoring/ParameterFloat.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
|
||||||
|
typedef float FP32;
|
||||||
|
|
||||||
|
class ParameterFloat : public ParameterInterface<FP32>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
ParameterFloat(const ModbusRegister description, uint16_t address, Access access) : ParameterInterface(description, address, access) {};
|
||||||
|
ParameterFloat(const ModbusRegister description, const unsigned short address, const Access access, const Category cat) : ParameterInterface(description, address, access, cat) {};
|
||||||
|
virtual ~ParameterFloat(){}
|
||||||
|
|
||||||
|
uint8_t getSize() const override { return 32; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
58
ConditionMonitoring/ParameterInterface.h
Normal file
58
ConditionMonitoring/ParameterInterface.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ModbusRegister.h"
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
class ModbusInterface;
|
||||||
|
|
||||||
|
enum class Access {
|
||||||
|
//Access Permission of a given MODBUS Parameter
|
||||||
|
R,
|
||||||
|
W,
|
||||||
|
RW,
|
||||||
|
CMD
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParameterSpecification {
|
||||||
|
ModbusRegister description;
|
||||||
|
Category cat;
|
||||||
|
uint16_t address;
|
||||||
|
uint8_t length;
|
||||||
|
Access access;
|
||||||
|
std::vector<uint16_t> readedBytes;
|
||||||
|
bool error = true;
|
||||||
|
std::unique_ptr<ModbusInterface>& connection;
|
||||||
|
|
||||||
|
ParameterSpecification(ModbusRegister d, Category c, uint16_t ad, uint8_t l, std::unique_ptr<ModbusInterface>& i, Access ac) :
|
||||||
|
description(d), cat(c), address(ad), length(l), access(ac), connection(i) {}
|
||||||
|
|
||||||
|
bool isReadable(){ return access == Access::R || access == Access::RW;}
|
||||||
|
bool isWritable(){ return access == Access::W || access == Access::RW || access == Access::CMD;}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
class ParameterInterface
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
S currentParam{};
|
||||||
|
|
||||||
|
const ModbusRegister valueDescription;
|
||||||
|
const uint16_t modbusAddress;
|
||||||
|
const Access access;
|
||||||
|
const Category cat = Category::NONE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ParameterInterface(const ModbusRegister description, const unsigned short address, const Access access) : valueDescription(description), modbusAddress(address), access(access) {};
|
||||||
|
ParameterInterface(const ModbusRegister description, const unsigned short address, const Access access, const Category _cat) : valueDescription(description), modbusAddress(address), access(access), cat(_cat) {};
|
||||||
|
virtual ~ParameterInterface(){}
|
||||||
|
|
||||||
|
bool isReadable() { return (access == Access::R || access == Access::RW); }
|
||||||
|
S getParam()const { return currentParam; };
|
||||||
|
uint16_t getModbusAddress() { return modbusAddress; }
|
||||||
|
ModbusRegister getValueDescription() { return valueDescription; };
|
||||||
|
Category getCategory()const {return cat;}
|
||||||
|
virtual uint8_t getSize() const = 0;
|
||||||
|
|
||||||
|
ParameterSpecification getSpecification(std::unique_ptr<ModbusInterface>& connection) const { return ParameterSpecification(valueDescription, cat, modbusAddress, getSize(), connection, access); }
|
||||||
|
};
|
2
ConditionMonitoring/ParameterS16.cpp
Normal file
2
ConditionMonitoring/ParameterS16.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "ParameterS16.h"
|
||||||
|
|
15
ConditionMonitoring/ParameterS16.h
Normal file
15
ConditionMonitoring/ParameterS16.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
|
||||||
|
class ParameterS16 : public ParameterInterface<int16_t>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int16_t param = 0;
|
||||||
|
public:
|
||||||
|
ParameterS16(const ModbusRegister description, uint16_t address, Access access) : ParameterInterface(description, address, access) {};
|
||||||
|
ParameterS16(const ModbusRegister description, const unsigned short address, const Access access, const Category cat) : ParameterInterface(description, address, access, cat) {};
|
||||||
|
virtual ~ParameterS16(){}
|
||||||
|
|
||||||
|
uint8_t getSize() const override { return 16; }
|
||||||
|
|
||||||
|
};
|
2
ConditionMonitoring/ParameterUInt16.cpp
Normal file
2
ConditionMonitoring/ParameterUInt16.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "ParameterUInt16.h"
|
||||||
|
|
15
ConditionMonitoring/ParameterUInt16.h
Normal file
15
ConditionMonitoring/ParameterUInt16.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
|
||||||
|
class ParameterUInt16 : public ParameterInterface<uint16_t>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint16_t param = 0;
|
||||||
|
public:
|
||||||
|
ParameterUInt16(const ModbusRegister description, uint16_t address, Access access) : ParameterInterface(description, address, access) {};
|
||||||
|
ParameterUInt16(const ModbusRegister description, const unsigned short address, const Access access, const Category cat) : ParameterInterface(description, address, access, cat) {};
|
||||||
|
virtual ~ParameterUInt16(){}
|
||||||
|
|
||||||
|
uint8_t getSize() const override { return 16; }
|
||||||
|
|
||||||
|
};
|
2
ConditionMonitoring/ParameterUInt32.cpp
Normal file
2
ConditionMonitoring/ParameterUInt32.cpp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "ParameterUInt32.h"
|
||||||
|
|
14
ConditionMonitoring/ParameterUInt32.h
Normal file
14
ConditionMonitoring/ParameterUInt32.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ParameterInterface.h"
|
||||||
|
class ParameterUInt32 : public ParameterInterface<uint32_t>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint32_t param = 0;
|
||||||
|
public:
|
||||||
|
ParameterUInt32(const ModbusRegister description, uint16_t address, Access access) : ParameterInterface(description, address, access) {};
|
||||||
|
ParameterUInt32(const ModbusRegister description, const unsigned short address, const Access access, const Category cat) : ParameterInterface(description, address, access, cat) {};
|
||||||
|
virtual ~ParameterUInt32(){}
|
||||||
|
|
||||||
|
uint8_t getSize() const override { return 32; }
|
||||||
|
|
||||||
|
};
|
20
ConditionMonitoring/PublisherBenderRcm.cpp
Normal file
20
ConditionMonitoring/PublisherBenderRcm.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "PublisherBenderRcm.h"
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
|
||||||
|
PublisherBenderRcm::PublisherBenderRcm() : PublisherInterface(PublisherType::RCMS_BENDER)
|
||||||
|
{
|
||||||
|
connection = std::make_unique<ModbusRTU>(SystemConfig::getIntConfigParameter("modbus_rtu_slave_address"),
|
||||||
|
SystemConfig::getStringConfigParameter("modbus_rtu_device"),
|
||||||
|
SystemConfig::getIntConfigParameter("modbus_rtu_baud"),
|
||||||
|
SystemConfig::getStringConfigParameter("modbus_rtu_pairity").at(0),
|
||||||
|
SystemConfig::getIntConfigParameter("modbus_rtu_stop_bits"));
|
||||||
|
|
||||||
|
modbusData = std::make_unique<ModbusDataBender>(this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PublisherBenderRcm::getName() const
|
||||||
|
{
|
||||||
|
std::stringstream name;
|
||||||
|
name << "RCM - Bender (ID: " << id << ")";
|
||||||
|
return name.str();
|
||||||
|
}
|
18
ConditionMonitoring/PublisherBenderRcm.h
Normal file
18
ConditionMonitoring/PublisherBenderRcm.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "PublisherType.h"
|
||||||
|
#include "ModbusDataBender.h"
|
||||||
|
#include "PublisherInterface.h"
|
||||||
|
#include "modbus_interface_lib.h"
|
||||||
|
|
||||||
|
class PublisherBenderRcm :
|
||||||
|
public PublisherInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
PublisherBenderRcm();
|
||||||
|
|
||||||
|
std::string getName()const override;
|
||||||
|
};
|
||||||
|
|
30
ConditionMonitoring/PublisherData.cpp
Normal file
30
ConditionMonitoring/PublisherData.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "PublisherData.h"
|
||||||
|
|
||||||
|
PublisherData::PublisherData(const int _publisherID, PublisherType pubType, float _value) :
|
||||||
|
publisherID(_publisherID), publisherType(pubType), values(std::vector<float>())
|
||||||
|
{
|
||||||
|
values.push_back(_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
PublisherData::PublisherData(const int _publisherID, PublisherType pubType, std::vector<float> _values) :
|
||||||
|
publisherID(_publisherID), publisherType(pubType), values(_values)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PublisherData::PublisherData() :
|
||||||
|
publisherID(0), publisherType(PublisherType::NA), values({ 0.0 })
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const PublisherData& data){
|
||||||
|
for (u_int i = 0; i < data.values.size()-1; i++) {
|
||||||
|
os << data.values[i] << ",";
|
||||||
|
}
|
||||||
|
os << data.values[data.values.size()-1] << ";";
|
||||||
|
return os;
|
||||||
|
}
|
42
ConditionMonitoring/PublisherData.h
Normal file
42
ConditionMonitoring/PublisherData.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <chrono>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include "PublisherType.h"
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
typedef unsigned int u_int;
|
||||||
|
|
||||||
|
class PublisherData
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
u_int publisherID;
|
||||||
|
const PublisherType publisherType;
|
||||||
|
system_clock::time_point time_generated;
|
||||||
|
std::vector<float> values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//constructors
|
||||||
|
PublisherData(const int _publisherID, PublisherType pubType, float value);
|
||||||
|
PublisherData(const int _publisherID, PublisherType pubType, std::vector<float> _values);
|
||||||
|
PublisherData();
|
||||||
|
|
||||||
|
//void updateTime() { this->time_generated = system_clock::now(); }
|
||||||
|
inline void addData(const float data) { values.push_back(data); }
|
||||||
|
|
||||||
|
u_int getID() { return publisherID; }
|
||||||
|
std::vector<float>& getValues() { return values; };
|
||||||
|
|
||||||
|
//getter/setter
|
||||||
|
PublisherType getType()const { return publisherType; }
|
||||||
|
system_clock::time_point getTimeGenerated()const { return time_generated; }
|
||||||
|
void setTimeGenerated(const std::chrono::system_clock::time_point t) { time_generated = t; }
|
||||||
|
|
||||||
|
|
||||||
|
bool hasData()const { return values.size() == 0 ? false : true; }
|
||||||
|
|
||||||
|
//operator
|
||||||
|
friend std::ostream& operator<<(std::ostream&, const PublisherData&);
|
||||||
|
friend std::istream& operator>>(std::istream&, PublisherData&);
|
||||||
|
};
|
||||||
|
|
19
ConditionMonitoring/PublisherInterface.cpp
Normal file
19
ConditionMonitoring/PublisherInterface.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "PublisherInterface.h"
|
||||||
|
|
||||||
|
#include <easylogging++.h>
|
||||||
|
|
||||||
|
u_int PublisherInterface::id_static = 0;
|
||||||
|
|
||||||
|
PublisherInterface::PublisherInterface(const PublisherType type)
|
||||||
|
: id(id_static++), type(type)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
bool PublisherInterface::operator==(const PublisherInterface& p2) const{
|
||||||
|
return this->id == p2.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts_queue<ParameterSpecification>& PublisherInterface::enqueueReadingRegisters(ts_queue< ParameterSpecification>& queue, Category cat){
|
||||||
|
modbusData->modbusRegisterCat(cat, queue, connection);
|
||||||
|
return queue;
|
||||||
|
}
|
35
ConditionMonitoring/PublisherInterface.h
Normal file
35
ConditionMonitoring/PublisherInterface.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include "PublisherData.h"
|
||||||
|
#include "ModbusDataInterface.h"
|
||||||
|
#include "modbus_interface_lib.h"
|
||||||
|
#include "ts_queue.h"
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
|
||||||
|
|
||||||
|
class PublisherInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static u_int id_static;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const u_int id;
|
||||||
|
const PublisherType type;
|
||||||
|
std::unique_ptr<ModbusInterface> connection;
|
||||||
|
std::unique_ptr<ModbusDataInterface> modbusData;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PublisherInterface(const PublisherType type);
|
||||||
|
virtual ~PublisherInterface(){}
|
||||||
|
|
||||||
|
ts_queue<ParameterSpecification>& enqueueReadingRegisters(ts_queue<ParameterSpecification>& queue, Category cat);
|
||||||
|
|
||||||
|
virtual std::string getName()const = 0;
|
||||||
|
|
||||||
|
bool open(){ return connection->openConnection(); }
|
||||||
|
bool isOpen() const { return connection->getIsOpen(); }
|
||||||
|
|
||||||
|
u_int getID()const { return id; }
|
||||||
|
//operator overloading
|
||||||
|
inline bool operator==(const PublisherInterface& p2)const;
|
||||||
|
};
|
26
ConditionMonitoring/PublisherPowercenter.cpp
Normal file
26
ConditionMonitoring/PublisherPowercenter.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "PublisherPowercenter.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
|
||||||
|
|
||||||
|
PublisherPowercenter::PublisherPowercenter() : PublisherInterface(PublisherType::POWERCENTER)
|
||||||
|
{
|
||||||
|
connection = std::make_unique<ModbusTCP>(SystemConfig::getIntConfigParameter("modbus_tcp_slave_address"),
|
||||||
|
SystemConfig::getStringConfigParameter("modbus_poc_ip"),
|
||||||
|
SystemConfig::getIntConfigParameter("modbus_poc_port"));
|
||||||
|
|
||||||
|
modbusData = std::make_unique<ModbusDataPOC>(this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
PublisherPowercenter::~PublisherPowercenter() {
|
||||||
|
//modbus->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string PublisherPowercenter::getName() const
|
||||||
|
{
|
||||||
|
std::stringstream name;
|
||||||
|
name << "Powercenter - Siemens (ID: " << id << ")";
|
||||||
|
return name.str();
|
||||||
|
}
|
16
ConditionMonitoring/PublisherPowercenter.h
Normal file
16
ConditionMonitoring/PublisherPowercenter.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "PublisherInterface.h"
|
||||||
|
#include "ModbusDataPOC.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class PublisherPowercenter :
|
||||||
|
public PublisherInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
PublisherPowercenter();
|
||||||
|
virtual ~PublisherPowercenter();
|
||||||
|
|
||||||
|
std::string getName()const override;
|
||||||
|
};
|
7
ConditionMonitoring/PublisherType.h
Normal file
7
ConditionMonitoring/PublisherType.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class PublisherType{
|
||||||
|
NA = 0,
|
||||||
|
RCMS_BENDER,
|
||||||
|
POWERCENTER
|
||||||
|
};
|
137
ConditionMonitoring/SystemConfig.cpp
Normal file
137
ConditionMonitoring/SystemConfig.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include <sstream>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
#include "CustomStringUtilities.h"
|
||||||
|
|
||||||
|
std::map<std::string, int> SystemConfig::intParameter;
|
||||||
|
std::map<std::string, float> SystemConfig::floatParameter;
|
||||||
|
std::map<std::string, std::string> SystemConfig::stringParameter;
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, SystemConfig& config) {
|
||||||
|
os << "System Configuration: " << std::endl;
|
||||||
|
std::for_each(config.intParameter.begin(), config.intParameter.end(),
|
||||||
|
[&config, &os](auto& param) { os << "\t"<< param.first << ":\t" << param.second << std::endl; });
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Read in the data from the config file
|
||||||
|
void SystemConfig::readStandardConfig()
|
||||||
|
{
|
||||||
|
std::fstream fileStream(filePath, std::ios::in);
|
||||||
|
if (fileStream.is_open()) {
|
||||||
|
std::stringstream buf;
|
||||||
|
while (std::getline(fileStream, fileContent))
|
||||||
|
buf << fileContent << '\n';
|
||||||
|
fileContent = buf.str();
|
||||||
|
fileStream.close();
|
||||||
|
parseConfFile();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(ERROR) << "Couldn't open " << filePath << " for reading -> using standard configuration instead";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Place parameters to read in here
|
||||||
|
SystemConfig::SystemConfig()
|
||||||
|
{
|
||||||
|
//define name and default value here
|
||||||
|
intParameter.emplace("read_data_interval_s", 60);
|
||||||
|
intParameter.emplace("tcp_server_port", 7777);
|
||||||
|
stringParameter.emplace("modbus_poc_ip", "127.0.0.1");
|
||||||
|
intParameter.emplace("modbus_poc_port", 502);
|
||||||
|
intParameter.emplace("alert_read_interval", 5);
|
||||||
|
stringParameter.emplace("modbus_rtu_device", "dev/tty0");
|
||||||
|
intParameter.emplace("modbus_rtu_baud", 9800);
|
||||||
|
intParameter.emplace("modbus_rtu_stop_bits", 1);
|
||||||
|
stringParameter.emplace("modbus_rtu_pairity", "E");
|
||||||
|
intParameter.emplace("modbus_rtu_slave_address", 1);
|
||||||
|
intParameter.emplace("modbus_tcp_slave_address", 1);
|
||||||
|
intParameter.emplace("permanent_param_history", 1000);
|
||||||
|
floatParameter.emplace("crit_residual_current", 30.0);
|
||||||
|
intParameter.emplace("crit_residual_timerange", 12);
|
||||||
|
intParameter.emplace("update_model_rate", 100);
|
||||||
|
intParameter.emplace("narrow_block", 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SystemConfig::parseConfFile()
|
||||||
|
{
|
||||||
|
//remove comments
|
||||||
|
std::regex patternComment("#(\\w|\\s)*\n+");
|
||||||
|
fileContent = std::regex_replace(fileContent, patternComment, "\n");
|
||||||
|
|
||||||
|
auto posHeader = fileContent.find("SystemConfig:");
|
||||||
|
if (posHeader == std::string::npos){
|
||||||
|
LOG(ERROR) << "Found no Header for the configuration file -> using standard configuration instead";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto& param : intParameter) {
|
||||||
|
std::regex pattern{ param.first + "\\s*=\\s*\\w+" };
|
||||||
|
std::smatch match;
|
||||||
|
if (std::regex_search(fileContent, match, pattern)) {
|
||||||
|
std::string numberString = match.str();
|
||||||
|
CustomStringUtilities::removeAllWhitespaces(numberString);
|
||||||
|
param.second = std::stoi(numberString.substr(numberString.find('=') + 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << "No specified config paramter (int) for " << param.first << ", using the default value " << param.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& param : floatParameter) {
|
||||||
|
std::regex pattern{ param.first + "\\s*=\\s*\\d+\\.\\d*" };
|
||||||
|
std::smatch match;
|
||||||
|
if (std::regex_search(fileContent, match, pattern)) {
|
||||||
|
std::string numberString = match.str();
|
||||||
|
CustomStringUtilities::removeAllWhitespaces(numberString);
|
||||||
|
param.second = std::stof(numberString.substr(numberString.find('=') + 1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << "No specified config paramter (float) for " << param.first << ", using the default value " << param.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& param : stringParameter) {
|
||||||
|
std::regex pattern{ param.first + "\\s*=\\s*(\\w|.)*" };
|
||||||
|
std::smatch match;
|
||||||
|
if (std::regex_search(fileContent, match, pattern)) {
|
||||||
|
std::string paramString = match.str();
|
||||||
|
CustomStringUtilities::removeAllWhitespaces(paramString);
|
||||||
|
param.second = paramString.substr(paramString.find('=') + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(INFO) << "No specified config paramter (float) for " << param.first << ", using the default value " << param.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SystemConfig::getIntConfigParameter(std::string paramName){
|
||||||
|
auto it = intParameter.find(paramName.data());
|
||||||
|
if (it != intParameter.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "Tried to read non existant int config parameter " << paramName;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SystemConfig::getFloatConfigParameter(std::string paramName){
|
||||||
|
auto it = floatParameter.find(paramName.data());
|
||||||
|
if (it != floatParameter.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "Tried to read non existant float config parameter " << paramName;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SystemConfig::getStringConfigParameter(std::string paramName)
|
||||||
|
{
|
||||||
|
auto it = stringParameter.find(paramName.data());
|
||||||
|
if (it != stringParameter.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "Tried to read non existant float config parameter " << paramName;
|
||||||
|
return "";
|
||||||
|
}
|
28
ConditionMonitoring/SystemConfig.h
Normal file
28
ConditionMonitoring/SystemConfig.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class SystemConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void readStandardConfig();
|
||||||
|
SystemConfig();
|
||||||
|
static int getIntConfigParameter(std::string paramName);
|
||||||
|
static float getFloatConfigParameter(std::string paramName);
|
||||||
|
static std::string getStringConfigParameter(std::string paramName);
|
||||||
|
private:
|
||||||
|
//Parameters to read from the file (name and default value)
|
||||||
|
static std::map<std::string, int> intParameter;
|
||||||
|
static std::map<std::string, float> floatParameter;
|
||||||
|
static std::map<std::string, std::string> stringParameter;
|
||||||
|
|
||||||
|
const std::string filePath = "system_conf.conf";
|
||||||
|
std::string fileContent;
|
||||||
|
void parseConfFile();
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, SystemConfig& config);
|
||||||
|
};
|
203
ConditionMonitoring/SystemControler.cpp
Normal file
203
ConditionMonitoring/SystemControler.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#include "SystemControler.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
std::atomic<bool> dataReadingCancelled = false;
|
||||||
|
std::atomic<bool> updateServerCancelled = false;
|
||||||
|
std::atomic<bool> threadRunning = false;
|
||||||
|
std::thread* readDataThread = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
SystemControler::SystemControler() :
|
||||||
|
dataModel(DataModel::Instance()), dataAcquire(std::make_shared<DataAcquisition>())
|
||||||
|
{
|
||||||
|
this->alertReadInterval = SystemConfig::getIntConfigParameter("alert_read_interval");
|
||||||
|
this->serverPort = SystemConfig::getIntConfigParameter("tcp_server_port");
|
||||||
|
|
||||||
|
initializePermanentStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemControler::~SystemControler()
|
||||||
|
{
|
||||||
|
LOG(INFO) << "Wait until continous modbus reading thread finishes...";
|
||||||
|
if(readDataThread != nullptr && threadRunning){
|
||||||
|
dataReadingCancelled = true;
|
||||||
|
if(readDataThread->joinable())
|
||||||
|
readDataThread->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Wait until server update thread finishes...";
|
||||||
|
if(serverUpdateThread != nullptr){
|
||||||
|
updateServerCancelled = true;
|
||||||
|
if(serverUpdateThread->joinable())
|
||||||
|
serverUpdateThread->join();
|
||||||
|
}
|
||||||
|
server.reset();
|
||||||
|
|
||||||
|
if(readDataThread != nullptr)
|
||||||
|
delete readDataThread;
|
||||||
|
if(serverUpdateThread != nullptr)
|
||||||
|
delete serverUpdateThread;
|
||||||
|
|
||||||
|
DataModel::Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void updateServer(std::shared_ptr<NetServer> server, std::chrono::milliseconds ms) {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
//Run as long as server exists and is not stopped
|
||||||
|
while (server != nullptr && !server->isStopped()) {
|
||||||
|
if(updateServerCancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Check for alerts
|
||||||
|
auto& alerts = DataModel::Instance()->getAlerts();
|
||||||
|
while(alerts.size() > 0){
|
||||||
|
net::Message<net::MessageTypes> msg;
|
||||||
|
auto a = alerts.pop_front();
|
||||||
|
msg.header.id = net::MessageTypes::ServerAlert;
|
||||||
|
short bitmask = 0;
|
||||||
|
std::memcpy(&bitmask, a.readedBytes.data(), 2);
|
||||||
|
std::stringstream tmp;
|
||||||
|
tmp << "Modbus " << a.connection->getConnectionType() << " alert: " << ModbusDataPOC::getStatusMessage(bitmask);
|
||||||
|
msg << tmp.str();
|
||||||
|
server->MessageAllClients(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//check for messages, specify no max message count
|
||||||
|
//return if no message is available
|
||||||
|
server->Update(-1, false);
|
||||||
|
std::this_thread::sleep_until(now + ms);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SystemControler::startIpTcpServer() {
|
||||||
|
try {
|
||||||
|
//start server
|
||||||
|
if(server == nullptr)
|
||||||
|
server = std::make_shared<NetServer>(serverPort);
|
||||||
|
|
||||||
|
if(server->isRunning()){
|
||||||
|
LOG(WARNING) << "Invoked server start, but server is already running";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->Start();
|
||||||
|
|
||||||
|
//Continous running update thread, that checks for incomming messages
|
||||||
|
serverUpdateThread = new std::thread(updateServer, server, serverTickRateMs);
|
||||||
|
}
|
||||||
|
catch (asio::system_error& e) {
|
||||||
|
LOG(FATAL) << "[SERVER]: Error "
|
||||||
|
<< e.code() << " >> "
|
||||||
|
<< e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
thread whhich acquires data from all registered publishers
|
||||||
|
->pointer to dataAcquisition, which handles the readiong requests
|
||||||
|
->intervalSec: # of seconds
|
||||||
|
*/
|
||||||
|
void enqueueRegisterThread(std::shared_ptr<DataAcquisition> dataAcquisition, SystemControler* controler, const u_int intervalSec)
|
||||||
|
{
|
||||||
|
threadRunning = true;
|
||||||
|
dataReadingCancelled = false;
|
||||||
|
LOG(INFO) << "Started continous data reading";
|
||||||
|
while (!dataReadingCancelled) {
|
||||||
|
const auto currentTime = system_clock::now();
|
||||||
|
|
||||||
|
//read in the data from the publishers
|
||||||
|
dataAcquisition->enqueuePublisherRegister();
|
||||||
|
|
||||||
|
controler->evaluate();
|
||||||
|
for (u_int i = 1; i <= intervalSec; i++)
|
||||||
|
{
|
||||||
|
if (dataReadingCancelled) {
|
||||||
|
LOG(INFO) << "Stopped continous data reading";
|
||||||
|
threadRunning = false;
|
||||||
|
dataReadingCancelled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Wait for 1 additional second and then check for cancelled thread
|
||||||
|
std::this_thread::sleep_until(currentTime + std::chrono::seconds(1) * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Stopped continous data reading";
|
||||||
|
dataReadingCancelled = false;
|
||||||
|
threadRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Invokes continous modbus alert reading
|
||||||
|
void SystemControler::startEnqueuingRegister()
|
||||||
|
{
|
||||||
|
if (threadRunning && !dataReadingCancelled) {
|
||||||
|
LOG(ERROR) << "ILLEGAL STATE: Invoked starting readDataThread while thread is already running (Thread ID: " << readDataThread->get_id() << ")";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Continue thread if it is already cancelled but still running
|
||||||
|
else if (threadRunning && dataReadingCancelled) {
|
||||||
|
dataReadingCancelled = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(readDataThread != nullptr)
|
||||||
|
delete readDataThread;
|
||||||
|
readDataThread = new std::thread(enqueueRegisterThread, dataAcquire, this, alertReadInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cancels continous modbus alert reading
|
||||||
|
void SystemControler::cancelReadingModbusAlerts()
|
||||||
|
{
|
||||||
|
if (dataReadingCancelled){
|
||||||
|
LOG(INFO) << "Thread is already cancelled, waiting for thread to stop";
|
||||||
|
}
|
||||||
|
else if (!threadRunning || readDataThread == nullptr){
|
||||||
|
LOG(ERROR) << "ILLEGAL STATE: Invoke cancelling of readDataThread while thread is not running";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
dataReadingCancelled = true;
|
||||||
|
if(readDataThread->joinable())
|
||||||
|
readDataThread->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check wether to flush or not, else counts up
|
||||||
|
void SystemControler::flushAfterNData()
|
||||||
|
{
|
||||||
|
dataModel->checkForFlushData();
|
||||||
|
}
|
||||||
|
|
||||||
|
//delegate register Publisher
|
||||||
|
void SystemControler::registerPublisher(std::unique_ptr<PublisherInterface> publisher)
|
||||||
|
{
|
||||||
|
dataAcquire->registerPublisher(std::move(publisher));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemControler::evaluate(){
|
||||||
|
if(evaluator == nullptr)
|
||||||
|
return;
|
||||||
|
auto alerts = evaluator->evaluate();
|
||||||
|
for(auto &a : alerts){
|
||||||
|
net::Message<net::MessageTypes> msg;
|
||||||
|
msg.header.id = net::MessageTypes::ServerAlert;
|
||||||
|
msg << a.message;
|
||||||
|
server->MessageAllClients(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SystemControler::initializePermanentStorage(){
|
||||||
|
//register Residual Current (dummy) to perform linear regression
|
||||||
|
//set biased fo ML Algorithm
|
||||||
|
dataModel->makePermanent(ModbusRegister::BENDER_Residual_current, true);
|
||||||
|
|
||||||
|
evaluator = std::make_unique<Evaluator>();
|
||||||
|
}
|
60
ConditionMonitoring/SystemControler.h
Normal file
60
ConditionMonitoring/SystemControler.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include "DataAcquisition.h"
|
||||||
|
#include "PublisherType.h"
|
||||||
|
#include "Evaluator.h"
|
||||||
|
#include "NetServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
class SystemControler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
u_int serverPort;
|
||||||
|
u_int alertReadInterval;
|
||||||
|
|
||||||
|
std::unique_ptr<DataModel>& dataModel;
|
||||||
|
std::shared_ptr<DataAcquisition> dataAcquire;
|
||||||
|
std::shared_ptr<Evaluator> evaluator;
|
||||||
|
|
||||||
|
//Estimated raw data which are collected over one hour of continous running in Bytes
|
||||||
|
size_t dataSizePerHour = 0;
|
||||||
|
std::shared_ptr<NetServer> server;
|
||||||
|
|
||||||
|
//Continous server updating with fixed tick rate, spcified in ms
|
||||||
|
std::thread* serverUpdateThread = nullptr;
|
||||||
|
std::chrono::milliseconds serverTickRateMs { 100 };
|
||||||
|
|
||||||
|
void initializePermanentStorage();
|
||||||
|
|
||||||
|
public:
|
||||||
|
SystemControler();
|
||||||
|
~SystemControler();
|
||||||
|
|
||||||
|
void startIpTcpServer();
|
||||||
|
|
||||||
|
//getter
|
||||||
|
std::shared_ptr<DataAcquisition>& getDataAcquisitionRef() { return dataAcquire; }
|
||||||
|
|
||||||
|
//Delegate read requests threaded to to acquire unit
|
||||||
|
void startEnqueuingRegister();
|
||||||
|
|
||||||
|
size_t getDataSizePerHour()const { return dataSizePerHour; };
|
||||||
|
|
||||||
|
void cancelReadingModbusAlerts();
|
||||||
|
|
||||||
|
void flushAfterNData();
|
||||||
|
|
||||||
|
void startModbusWorkerThread(){ dataAcquire->startModbusThread(); }
|
||||||
|
|
||||||
|
void test(){ }
|
||||||
|
|
||||||
|
//delegate register Publisher
|
||||||
|
void registerPublisher(std::unique_ptr<PublisherInterface> publisher);
|
||||||
|
|
||||||
|
//call evaluation manually, delegates call
|
||||||
|
void evaluate();
|
||||||
|
|
||||||
|
unsigned long deleteFiles(std::chrono::seconds olderThan) { return (olderThan == seconds(0)) ? dataModel->removeStoredData() : dataModel->removeStoredData(olderThan); }
|
||||||
|
};
|
88
ConditionMonitoring/baConditionMonitoring.pro
Normal file
88
ConditionMonitoring/baConditionMonitoring.pro
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console c++17
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
CONFIG -= qt
|
||||||
|
|
||||||
|
#INCLUDEPATH += ../AsioNetClientServer
|
||||||
|
#LIBS += -L../AsioNetClientServer/debug -lasio_inet_client_server
|
||||||
|
#LIBS += -pthread
|
||||||
|
|
||||||
|
unix: CONFIG += link_pkgconfig
|
||||||
|
unix: PKGCONFIG += libmodbuspp
|
||||||
|
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
CustomStringUtilities.cpp \
|
||||||
|
DataAcquisition.cpp \
|
||||||
|
DataModel.cpp \
|
||||||
|
Evaluator.cpp \
|
||||||
|
MLAnalyzer.cpp \
|
||||||
|
MLLinReg.cpp \
|
||||||
|
ModbusDataBender.cpp \
|
||||||
|
ModbusDataInterface.cpp \
|
||||||
|
ModbusDataPOC.cpp \
|
||||||
|
ModbusInterface.cpp \
|
||||||
|
ModbusRtu.cpp \
|
||||||
|
ModbusTcp.cpp \
|
||||||
|
NetServer.cpp \
|
||||||
|
ParameterCharP.cpp \
|
||||||
|
ParameterDouble.cpp \
|
||||||
|
ParameterFloat.cpp \
|
||||||
|
ParameterS16.cpp \
|
||||||
|
ParameterUInt16.cpp \
|
||||||
|
ParameterUInt32.cpp \
|
||||||
|
PublisherBenderRcm.cpp \
|
||||||
|
PublisherInterface.cpp \
|
||||||
|
PublisherPowercenter.cpp \
|
||||||
|
SystemConfig.cpp \
|
||||||
|
SystemControler.cpp \
|
||||||
|
cappedstorage.cpp \
|
||||||
|
easylogging++.cc \
|
||||||
|
main.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
CustomStringUtilities.h \
|
||||||
|
DataAcquisition.h \
|
||||||
|
DataModel.h \
|
||||||
|
Evaluator.h \
|
||||||
|
MLAlert.h \
|
||||||
|
MLAnalyzer.h \
|
||||||
|
MLLinReg.h \
|
||||||
|
ModbusDataBender.h \
|
||||||
|
ModbusDataInterface.h \
|
||||||
|
ModbusDataPOC.h \
|
||||||
|
ModbusInterface.h \
|
||||||
|
ModbusRegister.h \
|
||||||
|
ModbusRtu.h \
|
||||||
|
ModbusTcp.h \
|
||||||
|
NetServer.h \
|
||||||
|
ParameterCharP.h \
|
||||||
|
ParameterDouble.h \
|
||||||
|
ParameterFloat.h \
|
||||||
|
ParameterInterface.h \
|
||||||
|
ParameterS16.h \
|
||||||
|
ParameterUInt16.h \
|
||||||
|
ParameterUInt32.h \
|
||||||
|
PublisherBenderRcm.h \
|
||||||
|
PublisherInterface.h \
|
||||||
|
PublisherPowercenter.h \
|
||||||
|
PublisherType.h \
|
||||||
|
SystemConfig.h \
|
||||||
|
SystemControler.h \
|
||||||
|
asioClientServer/net_client.h \
|
||||||
|
asioClientServer/net_common.h \
|
||||||
|
asioClientServer/net_connection.h \
|
||||||
|
asioClientServer/net_dequeue_ts.h \
|
||||||
|
asioClientServer/net_message.h \
|
||||||
|
asioClientServer/net_server.h \
|
||||||
|
cappedstorage.h \
|
||||||
|
modbus_interface_lib.h \
|
||||||
|
net_server_client.h \
|
||||||
|
ts_map.h \
|
||||||
|
ts_queue.h \
|
||||||
|
easylogging++.h
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
build_baConditionMonitoring/system_conf.conf
|
||||||
|
|
||||||
|
|
70
ConditionMonitoring/cappedstorage.cpp
Normal file
70
ConditionMonitoring/cappedstorage.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "cappedstorage.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
|
||||||
|
CappedStorage::CappedStorage(bool _biased): biased(_biased)
|
||||||
|
{
|
||||||
|
if(biased){
|
||||||
|
X.resize(0, 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
X.resize(0, 1);
|
||||||
|
accessMtx = std::make_unique<std::mutex>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CappedStorage::lock(){
|
||||||
|
accessMtx->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CappedStorage::unlock(){
|
||||||
|
accessMtx->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CappedStorage::store(const std::vector<uint16_t>& d)
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(*accessMtx);
|
||||||
|
float value = 0;
|
||||||
|
std::memcpy(&value, d.data(), 4);
|
||||||
|
|
||||||
|
const double time = c::time_point_cast<c::seconds>(c::system_clock::now()).time_since_epoch().count();
|
||||||
|
|
||||||
|
X.conservativeResize(X.rows()+1, X.cols());
|
||||||
|
y.conservativeResize(y.rows()+1, 1);
|
||||||
|
y(y.rows()-1, 0) = value;
|
||||||
|
|
||||||
|
if(biased){
|
||||||
|
X(X.rows()-1, 0) = 1;
|
||||||
|
X(X.rows()-1, 1) = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
X(X.rows()-1, 0) = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CappedStorage::clear()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(*accessMtx);
|
||||||
|
X.resize(0, Eigen::NoChange_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Stream operator for 1 dimensional X Matrix
|
||||||
|
std::ostream& operator<<(std::ostream& os, const CappedStorage& c){
|
||||||
|
std::scoped_lock lock(*(c.accessMtx));
|
||||||
|
int col =0;
|
||||||
|
if(c.biased){
|
||||||
|
col = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < c.X.rows(); i++) {
|
||||||
|
os << c.X(i, col) << ",";
|
||||||
|
}
|
||||||
|
os << std::endl;
|
||||||
|
for (int i = 0; i < c.y.size(); i++) {
|
||||||
|
os << c.y(i, 0) << ",";
|
||||||
|
}
|
||||||
|
os << std::endl;
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
49
ConditionMonitoring/cappedstorage.h
Normal file
49
ConditionMonitoring/cappedstorage.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef CAPPEDSTORAGE_H
|
||||||
|
#define CAPPEDSTORAGE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <eigen3/Eigen/Core>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <memory>
|
||||||
|
namespace c = std::chrono;
|
||||||
|
|
||||||
|
//Class for one dimensional double values
|
||||||
|
class CappedStorage
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//Stored values
|
||||||
|
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> X;
|
||||||
|
Eigen::Matrix<double, Eigen::Dynamic, 1> y;
|
||||||
|
|
||||||
|
std::unique_ptr<std::mutex> accessMtx;
|
||||||
|
|
||||||
|
//If set, storage is extended by bias column (X(:, 1))
|
||||||
|
//to perform ML Algorithms
|
||||||
|
const bool biased;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CappedStorage(bool _biased);
|
||||||
|
|
||||||
|
void store(const std::vector<uint16_t> &d);
|
||||||
|
|
||||||
|
long size() const{ return X.rows(); };
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>& getX(){return X;}
|
||||||
|
Eigen::Matrix<double, Eigen::Dynamic, 1>& getY(){return y;}
|
||||||
|
long long getN(){return X.cols();}
|
||||||
|
long long getM(){return X.rows();}
|
||||||
|
|
||||||
|
friend std::ostream &operator<<(std::ostream& os, const CappedStorage& c);
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CAPPEDSTORAGE_H
|
4569
ConditionMonitoring/easylogging++.h
Normal file
4569
ConditionMonitoring/easylogging++.h
Normal file
File diff suppressed because it is too large
Load Diff
84
ConditionMonitoring/main.cpp
Normal file
84
ConditionMonitoring/main.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//Entry point of application, crates central controller class and initializes the publishers
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "SystemControler.h"
|
||||||
|
#include "SystemConfig.h"
|
||||||
|
#include <easylogging++.h>
|
||||||
|
#include "PublisherBenderRcm.h"
|
||||||
|
#include "PublisherPowercenter.h"
|
||||||
|
INITIALIZE_EASYLOGGINGPP
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef std::unique_ptr<PublisherInterface> unique_publisher_ptr;
|
||||||
|
typedef unsigned int u_int;
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
//Load global System configuration for parameters
|
||||||
|
SystemConfig configuration;
|
||||||
|
configuration.readStandardConfig();
|
||||||
|
|
||||||
|
|
||||||
|
//Load config file and apply on all loggers
|
||||||
|
std::filesystem::create_directory("log");
|
||||||
|
el::Configurations conf("log/logger_config.conf");
|
||||||
|
el::Loggers::reconfigureAllLoggers(conf);
|
||||||
|
|
||||||
|
LOG(INFO) << "Started execution";
|
||||||
|
|
||||||
|
//Create the System Controller
|
||||||
|
SystemControler controler;
|
||||||
|
|
||||||
|
//register publisher at controler
|
||||||
|
auto poc = std::make_unique<PublisherPowercenter>();
|
||||||
|
auto bender = std::make_unique<PublisherBenderRcm>();
|
||||||
|
|
||||||
|
//controler.registerPublisher(std::move(poc));
|
||||||
|
controler.registerPublisher(std::move(bender));
|
||||||
|
|
||||||
|
//Opens port for tcp/ip client connection
|
||||||
|
controler.startIpTcpServer();
|
||||||
|
|
||||||
|
//Modbus Worker Thread, processes the modbus register queue
|
||||||
|
controler.startModbusWorkerThread();
|
||||||
|
|
||||||
|
//Frequently enqueing of modbus register
|
||||||
|
controler.startEnqueuingRegister();
|
||||||
|
|
||||||
|
|
||||||
|
//Test environment on main thread
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
char key = cin.get();
|
||||||
|
switch (key) {
|
||||||
|
case 'l':
|
||||||
|
controler.deleteFiles(std::chrono::seconds(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
controler.cancelReadingModbusAlerts();
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
controler.evaluate();
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
return 0;
|
||||||
|
case 'p':
|
||||||
|
std::cout << configuration << std::endl;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
controler.flushAfterNData();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "End of execution\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
6
ConditionMonitoring/mltimeseries.cpp
Normal file
6
ConditionMonitoring/mltimeseries.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "mltimeseries.h"
|
||||||
|
|
||||||
|
MLtimeSeries::MLtimeSeries()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
12
ConditionMonitoring/mltimeseries.h
Normal file
12
ConditionMonitoring/mltimeseries.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef MLTIMESERIES_H
|
||||||
|
#define MLTIMESERIES_H
|
||||||
|
#include "MLAnalyzer.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class MLtimeSeries : public MLAnalyzer<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MLtimeSeries();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MLTIMESERIES_H
|
7
ConditionMonitoring/modbus_interface_lib.h
Normal file
7
ConditionMonitoring/modbus_interface_lib.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ModbusInterface.h"
|
||||||
|
#include "ModbusRtu.h"
|
||||||
|
#include "ModbusTcp.h"
|
||||||
|
|
||||||
|
#include <modbuspp/modbuspp.h>
|
64
ConditionMonitoring/net_server_client.h
Normal file
64
ConditionMonitoring/net_server_client.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
MMO Client/Server Framework using ASIO
|
||||||
|
"Happy Birthday Mrs Javidx9!" - javidx9
|
||||||
|
|
||||||
|
Videos:
|
||||||
|
Part #1: https://youtu.be/2hNdkYInj4g
|
||||||
|
Part #2: https://youtu.be/UbjxGvrDrbw
|
||||||
|
|
||||||
|
License (OLC-3)
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Copyright 2018 - 2020 OneLoneCoder.com
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce
|
||||||
|
the above copyright notice. This list of conditions and the following
|
||||||
|
disclaimer must be reproduced in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Links
|
||||||
|
~~~~~
|
||||||
|
YouTube: https://www.youtube.com/javidx9
|
||||||
|
Discord: https://discord.gg/WhwHUMV
|
||||||
|
Twitter: https://www.twitter.com/javidx9
|
||||||
|
Twitch: https://www.twitch.tv/javidx9
|
||||||
|
GitHub: https://www.github.com/onelonecoder
|
||||||
|
Homepage: https://www.onelonecoder.com
|
||||||
|
|
||||||
|
Author
|
||||||
|
~~~~~~
|
||||||
|
David Barr, aka javidx9, ©OneLoneCoder 2019, 2020
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "asioClientServer/net_common.h"
|
||||||
|
#include "asioClientServer/net_dequeue_ts.h"
|
||||||
|
#include "asioClientServer/net_message.h"
|
||||||
|
#include "asioClientServer/net_client.h"
|
||||||
|
#include "asioClientServer/net_server.h"
|
||||||
|
#include "asioClientServer/net_connection.h"
|
90
ConditionMonitoring/ts_map.h
Normal file
90
ConditionMonitoring/ts_map.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#ifndef TS_MAP_H
|
||||||
|
#define TS_MAP_H
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
template <typename KEY, typename VALUE>
|
||||||
|
class ts_map
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ts_map() = default;
|
||||||
|
ts_map(const ts_map<KEY, VALUE>&) = delete;
|
||||||
|
virtual ~ts_map() { clear(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void emplaceOrOverwrite(KEY key, VALUE value){
|
||||||
|
std::scoped_lock lock(muxMap);
|
||||||
|
auto it = map.find(key);
|
||||||
|
if(it != map.end()){
|
||||||
|
it->second = value;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
map.emplace(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void emplace(KEY key, VALUE&& value){
|
||||||
|
std::scoped_lock lock(muxMap);
|
||||||
|
map.emplace(key, std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto find(KEY key){
|
||||||
|
std::scoped_lock lock(muxMap);
|
||||||
|
|
||||||
|
return map.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if Queue has no items
|
||||||
|
bool empty()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxMap);
|
||||||
|
return map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns number of items in Queue
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxMap);
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears Queue
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxMap);
|
||||||
|
std::map<KEY, VALUE> empty;
|
||||||
|
std::swap(map, empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait()
|
||||||
|
{
|
||||||
|
while (empty())
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> ul(muxBlocking);
|
||||||
|
cvBlocking.wait(ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto begin() const{
|
||||||
|
return map.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto end() const{
|
||||||
|
return map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::mutex muxMap;
|
||||||
|
std::map<KEY, VALUE> map;
|
||||||
|
std::condition_variable cvBlocking;
|
||||||
|
std::mutex muxBlocking;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TS_MAP_H
|
143
ConditionMonitoring/ts_queue.h
Normal file
143
ConditionMonitoring/ts_queue.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
MMO Client/Server Framework using ASIO
|
||||||
|
"Happy Birthday Mrs Javidx9!" - javidx9
|
||||||
|
|
||||||
|
Videos:
|
||||||
|
Part #1: https://youtu.be/2hNdkYInj4g
|
||||||
|
Part #2: https://youtu.be/UbjxGvrDrbw
|
||||||
|
|
||||||
|
License (OLC-3)
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Copyright 2018 - 2020 OneLoneCoder.com
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce
|
||||||
|
the above copyright notice. This list of conditions and the following
|
||||||
|
disclaimer must be reproduced in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Links
|
||||||
|
~~~~~
|
||||||
|
YouTube: https://www.youtube.com/javidx9
|
||||||
|
Discord: https://discord.gg/WhwHUMV
|
||||||
|
Twitter: https://www.twitter.com/javidx9
|
||||||
|
Twitch: https://www.twitch.tv/javidx9
|
||||||
|
GitHub: https://www.github.com/onelonecoder
|
||||||
|
Homepage: https://www.onelonecoder.com
|
||||||
|
|
||||||
|
Author
|
||||||
|
~~~~~~
|
||||||
|
David Barr, aka javidx9, <EFBFBD>OneLoneCoder 2019, 2020
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <queue>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
/*
|
||||||
|
Threadsafe Queue to be accessed from different threads
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
class ts_queue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ts_queue() = default;
|
||||||
|
ts_queue(const ts_queue<T>&) = delete;
|
||||||
|
virtual ~ts_queue() { clear(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Returns and maintains item at front of Queue
|
||||||
|
const T& front()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
return queue.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns and maintains item at back of Queue
|
||||||
|
const T& back()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
return queue.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes and returns the first item from Queue
|
||||||
|
T pop_front()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
auto t = std::move(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an item to front of Queue
|
||||||
|
void push(const T& item)
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
queue.push(std::move(item));
|
||||||
|
std::unique_lock<std::mutex> ul(muxBlocking);
|
||||||
|
cvBlocking.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if Queue has no items
|
||||||
|
bool empty()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
return queue.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns number of items in Queue
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
return queue.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears Queue
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(muxQueue);
|
||||||
|
std::queue<T> empty;
|
||||||
|
std::swap(queue, empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait()
|
||||||
|
{
|
||||||
|
while (empty())
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> ul(muxBlocking);
|
||||||
|
cvBlocking.wait(ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::mutex muxQueue;
|
||||||
|
std::queue<T> queue;
|
||||||
|
std::condition_variable cvBlocking;
|
||||||
|
std::mutex muxBlocking;
|
||||||
|
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user