Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop mz #30

Merged
merged 12 commits into from
Jan 23, 2024
35 changes: 33 additions & 2 deletions include/iec61850_client_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
FRIEND_TEST (ControlTest, DoubleCommandDirectNormal); \
FRIEND_TEST (ControlTest, SingleCommandDirectEnhanced); \
FRIEND_TEST (ControlTest, SingleCommandSetValue); \
FRIEND_TEST (ControlTest, WriteOperations); \
FRIEND_TEST (ReportingTest, ReportingWithStaticDataset); \
FRIEND_TEST (ReportingTest, ReportingWithDynamicDataset); \
FRIEND_TEST (ReportingTest, ReportingUpdateQuality); \
Expand All @@ -29,7 +30,26 @@
FRIEND_TEST (SpontDataTest, Polling); \
FRIEND_TEST (SpontDataTest, PollingAllCDC); \
FRIEND_TEST (ControlTest, AnalogueCommandDirectNormal); \
FRIEND_TEST (ControlTest, StepCommandDirectNormal);
FRIEND_TEST (ControlTest, StepCommandDirectNormal); \
FRIEND_TEST (ConfigTest, ProtocolConfigParseError); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoJsonProtocolStack); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoTransportLayer); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoConnections); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoConnectionIP); \
FRIEND_TEST (ConfigTest, ProtocolConfigInvalidConnectionPort); \
FRIEND_TEST (ConfigTest, ProtocolConfigWithOsi); \
FRIEND_TEST (ConfigTest, ProtocolConfigTlsNotBoolean); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoAppLayer); \
FRIEND_TEST (ConfigTest, ProtocolConfigPollingIntervalNotInt); \
FRIEND_TEST (ConfigTest, ProtocolConfigWrongPollingInterval); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoDatasets); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoDynamicValue); \
FRIEND_TEST (ConfigTest, ProtocolConfigReportSubscriptionsNotString); \
FRIEND_TEST (ConfigTest, ProtocolConfigReportSubscriptionsNotObject); \
FRIEND_TEST (ConfigTest, ProtocolConfigReportNoDataref); \
FRIEND_TEST (ConfigTest, ProtocolConfigNoTrgroups); \
FRIEND_TEST (ConfigTest, ProtocolConfigBuftmIntgpd); \
FRIEND_TEST (ConnectionHandlingTest, TwoConnectionsBackup);

typedef enum
{
Expand All @@ -49,7 +69,10 @@ typedef enum
DPC,
APC,
INC,
BSC
BSC,
SPG,
ASG,
ING
} CDCTYPE;

class ConfigurationException : public std::logic_error
Expand Down Expand Up @@ -212,6 +235,12 @@ class IEC61850ClientConfig
return pollingInterval;
}

uint64_t
backupConnectionTimeout ()
{
return m_backupConnectionTimeout;
};

private:
static bool isMessageTypeMatching (int expectedType, int rcvdType);

Expand Down Expand Up @@ -240,6 +269,8 @@ class IEC61850ClientConfig
std::vector<std::string> m_remoteCertificates;
std::vector<std::string> m_caCertificates;

uint64_t m_backupConnectionTimeout = 5000;

long pollingInterval = 0;
FRIEND_TESTS
};
Expand Down
21 changes: 21 additions & 0 deletions include/iec61850_client_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,23 @@ class IEC61850ClientConnection

bool operate (const std::string& objRef, DatapointValue value);

static void writeHandler (uint32_t invokeId, void* parameter,
IedClientError err);

bool writeValue (Datapoint* operation, const std::string& objRef, DatapointValue value,
CDCTYPE type);

const std::string&
IP ()
{
return m_serverIp;
};
int
Port ()
{
return m_tcpPort;
};

private:
bool prepareConnection ();
bool
Expand All @@ -80,6 +97,10 @@ class IEC61850ClientConnection

static void reportCallbackFunction (void* parameter, ClientReport report);

static void writeVariableHandler (uint32_t invokeId, void* parameter,
MmsError err,
MmsDataAccessError accessError);

using ConState = enum {
CON_STATE_IDLE,
CON_STATE_CONNECTING,
Expand Down
211 changes: 119 additions & 92 deletions src/iec61850.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,160 +2,187 @@
#include "plugin_api.h"
#include <iec61850.hpp>

bool
isCommandType(CDCTYPE type){
return type>=SPC;
static bool
isCommandType (CDCTYPE type)
{
return type >= SPC && type < SPG;
}


IEC61850::~IEC61850(){
delete m_config;
static bool
isWriteType (CDCTYPE type)
{
return type >= SPG;
}

IEC61850::~IEC61850 () { delete m_config; }

void
IEC61850::registerIngest(void* data, INGEST_CB cb)
IEC61850::registerIngest (void* data, INGEST_CB cb)
{
m_ingest = cb;
m_data = data;
}


void
IEC61850::setJsonConfig(const std::string& protocol_stack,
const std::string& exchanged_data,
const std::string& tls_configuration)
IEC61850::setJsonConfig (const std::string& protocol_stack,
const std::string& exchanged_data,
const std::string& tls_configuration)
{
if(m_config) delete m_config;
if (m_config)
delete m_config;

m_config = new IEC61850ClientConfig();
m_config->importExchangeConfig(exchanged_data);
m_config->importProtocolConfig(protocol_stack);
m_config->importTlsConfig(tls_configuration);
}
m_config = new IEC61850ClientConfig ();
m_config->importExchangeConfig (exchanged_data);
m_config->importProtocolConfig (protocol_stack);
m_config->importTlsConfig (tls_configuration);
}

void
IEC61850::start()
void
IEC61850::start ()
{
Iec61850Utility::log_info("Starting iec61850");
//LCOV_EXCL_START
switch (m_config->LogLevel())
Iec61850Utility::log_info ("Starting iec61850");
// LCOV_EXCL_START
switch (m_config->LogLevel ())
{
case 1:
Logger::getLogger()->setMinLevel("debug");
break;
case 2:
Logger::getLogger()->setMinLevel("info");
break;
case 3:
Logger::getLogger()->setMinLevel("warning");
break;
default:
Logger::getLogger()->setMinLevel("error");
break;
case 1:
Logger::getLogger ()->setMinLevel ("debug");
break;
case 2:
Logger::getLogger ()->setMinLevel ("info");
break;
case 3:
Logger::getLogger ()->setMinLevel ("warning");
break;
default:
Logger::getLogger ()->setMinLevel ("error");
break;
}
//LCOV_EXCL_STOP
// LCOV_EXCL_STOP

m_client = new IEC61850Client(this, m_config);
m_client = new IEC61850Client (this, m_config);

//LCOV_EXCL_START
if(!m_client){
Iec61850Utility::log_error("Can't start, client is null");
// LCOV_EXCL_START
if (!m_client)
{
Iec61850Utility::log_error ("Can't start, client is null");
return;
}
//LCOV_EXCL_STOP
// LCOV_EXCL_STOP

m_client->start();
m_client->start ();
}

void IEC61850::stop()
void
IEC61850::stop ()
{
if(!m_client) return;
if (!m_client)
return;

m_client->stop();
m_client->stop ();

delete m_client;
m_client = nullptr;
delete m_client;
m_client = nullptr;
}

void IEC61850::ingest(const std::string& assetName, const std::vector<Datapoint*>& points)
void
IEC61850::ingest (const std::string& assetName,
const std::vector<Datapoint*>& points)
{
if (m_ingest){
m_ingest(m_data, Reading(assetName, points));
}
if (m_ingest)
{
m_ingest (m_data, Reading (assetName, points));
}
}

static Datapoint*
getCdc(Datapoint* dp)
getCdc (Datapoint* dp)
{
DatapointValue& dpv = dp->getData();
DatapointValue& dpv = dp->getData ();

if (dpv.getType() != DatapointValue::T_DP_DICT) {
Iec61850Utility::log_error("Datapoint is not a dictionary %s", dp->getName().c_str());
if (dpv.getType () != DatapointValue::T_DP_DICT)
{
Iec61850Utility::log_error ("Datapoint is not a dictionary %s",
dp->getName ().c_str ());
}

std::vector<Datapoint*> const* datapoints = dpv.getDpVec();
std::vector<Datapoint*> const* datapoints = dpv.getDpVec ();

for (Datapoint* child : *datapoints) {
if(IEC61850ClientConfig::getCdcTypeFromString(child->getName()) != -1){
return child;
}
for (Datapoint* child : *datapoints)
{
if (IEC61850ClientConfig::getCdcTypeFromString (child->getName ())
!= -1)
{
return child;
}
}

return nullptr;
}

bool
IEC61850::operation(const std::string& operation, int count,
PLUGIN_PARAMETER** params)
IEC61850::operation (const std::string& operation, int count,
PLUGIN_PARAMETER** params)
{
if (m_client == nullptr) {
Iec61850Utility::log_error("operation called but plugin is not yet initialized");
if (m_client == nullptr)
{
Iec61850Utility::log_error (
"operation called but plugin is not yet initialized");

return false;
}

if (operation == "PivotCommand"){
if (operation == "PivotCommand")
{
std::string commandContentJSON = params[0]->value;
Datapoint* commandContent = nullptr;

DatapointValue temp((long)1);
std::unique_ptr<Datapoint> parserDp (new Datapoint("Parser", temp));

std::vector<Datapoint *>* jsonValues = parserDp->parseJson(commandContentJSON);
DatapointValue temp ((long)1);
std::unique_ptr<Datapoint> parserDp (new Datapoint ("Parser", temp));

std::vector<Datapoint*>* jsonValues
= parserDp->parseJson (commandContentJSON);

if(jsonValues){
commandContent = jsonValues->at(0);
jsonValues->clear();
if (jsonValues)
{
commandContent = jsonValues->at (0);
jsonValues->clear ();
delete jsonValues;
}
}

if(!commandContent) {
Iec61850Utility::log_error("Failed to parse command content");
return false;
if (!commandContent)
{
Iec61850Utility::log_error ("Failed to parse command content");
return false;
}

Iec61850Utility::log_debug("Received command: %s", commandContent->toJSONProperty().c_str());

Datapoint* cdc = getCdc(commandContent);

if(!cdc){
Iec61850Utility::log_warn("Received pivot object has no cdc");
return false;

Iec61850Utility::log_debug (
"Received command: %s",
commandContent->toJSONProperty ().c_str ());

Datapoint* cdc = getCdc (commandContent);

if (!cdc)
{
Iec61850Utility::log_warn ("Received pivot object has no cdc");
return false;
}

int type = IEC61850ClientConfig::getCdcTypeFromString(cdc->getName());
int type
= IEC61850ClientConfig::getCdcTypeFromString (cdc->getName ());

if(type == -1 || !isCommandType((CDCTYPE)type)){
Iec61850Utility::log_warn("Not a command object %s -> ignore", cdc->toJSONProperty().c_str());
return false;
if (type == -1 || !isCommandType ((CDCTYPE)type) && !isWriteType((CDCTYPE)type))
{
Iec61850Utility::log_warn ("Not a command object %s -> ignore",
cdc->toJSONProperty ().c_str ());
return false;
}

bool res = m_client->handleOperation(commandContent);
bool res = m_client->handleOperation (commandContent);
return res;
}
}

Iec61850Utility::log_error("Unrecognised operation %s", operation.c_str());
Iec61850Utility::log_error ("Unrecognised operation %s",
operation.c_str ());

return false;
}

Loading
Loading