Browse Source

Initial commit

master
Michael Stuffer 2 years ago
parent
commit
ff408db8de
65 changed files with 8144 additions and 0 deletions
  1. 21
    0
      ConditionMonitoring/CustomStringUtilities.cpp
  2. 14
    0
      ConditionMonitoring/CustomStringUtilities.h
  3. 163
    0
      ConditionMonitoring/DataAcquisition.cpp
  4. 38
    0
      ConditionMonitoring/DataAcquisition.h
  5. 364
    0
      ConditionMonitoring/DataModel.cpp
  6. 129
    0
      ConditionMonitoring/DataModel.h
  7. 37
    0
      ConditionMonitoring/Evaluator.cpp
  8. 25
    0
      ConditionMonitoring/Evaluator.h
  9. 17
    0
      ConditionMonitoring/MLAlert.h
  10. 42
    0
      ConditionMonitoring/MLAnalyzer.cpp
  11. 37
    0
      ConditionMonitoring/MLAnalyzer.h
  12. 74
    0
      ConditionMonitoring/MLLinReg.cpp
  13. 23
    0
      ConditionMonitoring/MLLinReg.h
  14. 10
    0
      ConditionMonitoring/ModbusDataBender.cpp
  15. 11
    0
      ConditionMonitoring/ModbusDataBender.h
  16. 20
    0
      ConditionMonitoring/ModbusDataInterface.cpp
  17. 34
    0
      ConditionMonitoring/ModbusDataInterface.h
  18. 247
    0
      ConditionMonitoring/ModbusDataPOC.cpp
  19. 20
    0
      ConditionMonitoring/ModbusDataPOC.h
  20. 213
    0
      ConditionMonitoring/ModbusInterface.cpp
  21. 54
    0
      ConditionMonitoring/ModbusInterface.h
  22. 283
    0
      ConditionMonitoring/ModbusRegister.h
  23. 31
    0
      ConditionMonitoring/ModbusRtu.cpp
  24. 26
    0
      ConditionMonitoring/ModbusRtu.h
  25. 25
    0
      ConditionMonitoring/ModbusTcp.cpp
  26. 20
    0
      ConditionMonitoring/ModbusTcp.h
  27. 128
    0
      ConditionMonitoring/NetServer.cpp
  28. 54
    0
      ConditionMonitoring/NetServer.h
  29. 1
    0
      ConditionMonitoring/ParameterCharP.cpp
  30. 15
    0
      ConditionMonitoring/ParameterCharP.h
  31. 2
    0
      ConditionMonitoring/ParameterDouble.cpp
  32. 16
    0
      ConditionMonitoring/ParameterDouble.h
  33. 2
    0
      ConditionMonitoring/ParameterFloat.cpp
  34. 17
    0
      ConditionMonitoring/ParameterFloat.h
  35. 58
    0
      ConditionMonitoring/ParameterInterface.h
  36. 2
    0
      ConditionMonitoring/ParameterS16.cpp
  37. 15
    0
      ConditionMonitoring/ParameterS16.h
  38. 2
    0
      ConditionMonitoring/ParameterUInt16.cpp
  39. 15
    0
      ConditionMonitoring/ParameterUInt16.h
  40. 2
    0
      ConditionMonitoring/ParameterUInt32.cpp
  41. 14
    0
      ConditionMonitoring/ParameterUInt32.h
  42. 20
    0
      ConditionMonitoring/PublisherBenderRcm.cpp
  43. 18
    0
      ConditionMonitoring/PublisherBenderRcm.h
  44. 30
    0
      ConditionMonitoring/PublisherData.cpp
  45. 42
    0
      ConditionMonitoring/PublisherData.h
  46. 19
    0
      ConditionMonitoring/PublisherInterface.cpp
  47. 35
    0
      ConditionMonitoring/PublisherInterface.h
  48. 26
    0
      ConditionMonitoring/PublisherPowercenter.cpp
  49. 16
    0
      ConditionMonitoring/PublisherPowercenter.h
  50. 7
    0
      ConditionMonitoring/PublisherType.h
  51. 137
    0
      ConditionMonitoring/SystemConfig.cpp
  52. 28
    0
      ConditionMonitoring/SystemConfig.h
  53. 203
    0
      ConditionMonitoring/SystemControler.cpp
  54. 60
    0
      ConditionMonitoring/SystemControler.h
  55. 88
    0
      ConditionMonitoring/baConditionMonitoring.pro
  56. 70
    0
      ConditionMonitoring/cappedstorage.cpp
  57. 49
    0
      ConditionMonitoring/cappedstorage.h
  58. 4569
    0
      ConditionMonitoring/easylogging++.h
  59. 84
    0
      ConditionMonitoring/main.cpp
  60. 6
    0
      ConditionMonitoring/mltimeseries.cpp
  61. 12
    0
      ConditionMonitoring/mltimeseries.h
  62. 7
    0
      ConditionMonitoring/modbus_interface_lib.h
  63. 64
    0
      ConditionMonitoring/net_server_client.h
  64. 90
    0
      ConditionMonitoring/ts_map.h
  65. 143
    0
      ConditionMonitoring/ts_queue.h

+ 21
- 0
ConditionMonitoring/CustomStringUtilities.cpp View 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
- 0
ConditionMonitoring/CustomStringUtilities.h View 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
- 0
ConditionMonitoring/DataAcquisition.cpp View 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
- 0
ConditionMonitoring/DataAcquisition.h View 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
- 0
ConditionMonitoring/DataModel.cpp View 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
- 0
ConditionMonitoring/DataModel.h View 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
- 0
ConditionMonitoring/Evaluator.cpp View 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
- 0
ConditionMonitoring/Evaluator.h View 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
- 0
ConditionMonitoring/MLAlert.h View 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
- 0
ConditionMonitoring/MLAnalyzer.cpp View 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
- 0
ConditionMonitoring/MLAnalyzer.h View 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
- 0
ConditionMonitoring/MLLinReg.cpp View 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
- 0
ConditionMonitoring/MLLinReg.h View 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
- 0
ConditionMonitoring/ModbusDataBender.cpp View 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
- 0
ConditionMonitoring/ModbusDataBender.h View File

@@ -0,0 +1,11 @@
#pragma once
#include "ModbusDataInterface.h"


class ModbusDataBender : public ModbusDataInterface
{
public:
ModbusDataBender(const unsigned int id);

};


+ 20
- 0
ConditionMonitoring/ModbusDataInterface.cpp View 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
- 0
ConditionMonitoring/ModbusDataInterface.h View 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
- 0
ConditionMonitoring/ModbusDataPOC.cpp View 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
- 0
ConditionMonitoring/ModbusDataPOC.h View 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
- 0
ConditionMonitoring/ModbusInterface.cpp View 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 &param) {
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 &param) {
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 &param) {
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 &param) {
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 &param) {
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 &param) {
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
- 0
ConditionMonitoring/ModbusInterface.h View 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 &param);
bool readBits(ParameterSpecification &param);
uint8_t readByte(ParameterSpecification &param);
uint16_t readRegister(ParameterSpecification &param);
uint32_t readDRegister(ParameterSpecification &param);
uint64_t readQRegister(ParameterSpecification &param);

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
- 0
ConditionMonitoring/ModbusRegister.h View 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
- 0
ConditionMonitoring/ModbusRtu.cpp View 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
- 0
ConditionMonitoring/ModbusRtu.h View 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
- 0
ConditionMonitoring/ModbusTcp.cpp View 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
- 0
ConditionMonitoring/ModbusTcp.h View 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
- 0
ConditionMonitoring/NetServer.cpp View 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
- 0
ConditionMonitoring/NetServer.h View 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
- 0
ConditionMonitoring/ParameterCharP.cpp View File

@@ -0,0 +1 @@
#include "ParameterCharP.h"

+ 15
- 0
ConditionMonitoring/ParameterCharP.h View 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
- 0
ConditionMonitoring/ParameterDouble.cpp View File

@@ -0,0 +1,2 @@
#include "ParameterDouble.h"


+ 16
- 0
ConditionMonitoring/ParameterDouble.h View 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
- 0
ConditionMonitoring/ParameterFloat.cpp View File

@@ -0,0 +1,2 @@
#include "ParameterFloat.h"


+ 17
- 0
ConditionMonitoring/ParameterFloat.h View 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
- 0
ConditionMonitoring/ParameterInterface.h View 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
- 0
ConditionMonitoring/ParameterS16.cpp View File

@@ -0,0 +1,2 @@
#include "ParameterS16.h"


+ 15
- 0
ConditionMonitoring/ParameterS16.h View 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
- 0
ConditionMonitoring/ParameterUInt16.cpp View File

@@ -0,0 +1,2 @@
#include "ParameterUInt16.h"


+ 15
- 0
ConditionMonitoring/ParameterUInt16.h View 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
- 0
ConditionMonitoring/ParameterUInt32.cpp View File

@@ -0,0 +1,2 @@
#include "ParameterUInt32.h"


+ 14
- 0
ConditionMonitoring/ParameterUInt32.h View 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
- 0
ConditionMonitoring/PublisherBenderRcm.cpp View 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
- 0
ConditionMonitoring/PublisherBenderRcm.h View 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
- 0
ConditionMonitoring/PublisherData.cpp View 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
- 0
ConditionMonitoring/PublisherData.h View 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
- 0
ConditionMonitoring/PublisherInterface.cpp View 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
- 0
ConditionMonitoring/PublisherInterface.h View 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
- 0
ConditionMonitoring/PublisherPowercenter.cpp View 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
- 0
ConditionMonitoring/PublisherPowercenter.h View 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
- 0
ConditionMonitoring/PublisherType.h View File

@@ -0,0 +1,7 @@
#pragma once

enum class PublisherType{
NA = 0,
RCMS_BENDER,
POWERCENTER
};

+ 137
- 0
ConditionMonitoring/SystemConfig.cpp View 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
- 0
ConditionMonitoring/SystemConfig.h View 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
- 0
ConditionMonitoring/SystemControler.cpp View 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
- 0
ConditionMonitoring/SystemControler.h View 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
- 0
ConditionMonitoring/baConditionMonitoring.pro View 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
- 0
ConditionMonitoring/cappedstorage.cpp View 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
- 0
ConditionMonitoring/cappedstorage.h View 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
- 0
ConditionMonitoring/easylogging++.h
File diff suppressed because it is too large
View File


+ 84
- 0
ConditionMonitoring/main.cpp View 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
- 0
ConditionMonitoring/mltimeseries.cpp View File

@@ -0,0 +1,6 @@
#include "mltimeseries.h"

MLtimeSeries::MLtimeSeries()
{

}

+ 12
- 0
ConditionMonitoring/mltimeseries.h View 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
- 0
ConditionMonitoring/modbus_interface_lib.h View File

@@ -0,0 +1,7 @@
#pragma once

#include "ModbusInterface.h"
#include "ModbusRtu.h"
#include "ModbusTcp.h"

#include <modbuspp/modbuspp.h>

+ 64
- 0
ConditionMonitoring/net_server_client.h View 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
- 0
ConditionMonitoring/ts_map.h View 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
- 0
ConditionMonitoring/ts_queue.h View 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, �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…
Cancel
Save