Skip to content

Commit

Permalink
Merge pull request #34 from fledge-power/develop_mz
Browse files Browse the repository at this point in the history
Develop mz
  • Loading branch information
aklira authored Jun 13, 2024
2 parents ee8dd70 + 31d017f commit 0b30b56
Show file tree
Hide file tree
Showing 10 changed files with 851 additions and 147 deletions.
6 changes: 5 additions & 1 deletion include/iec61850.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,17 @@ class IEC61850Client
void sendCommandAck (const std::string& label, ControlModel mode,
bool terminated);

bool firstTimeConnect = true;
MmsValue* lastEntryId = nullptr;

private:
std::shared_ptr<std::vector<IEC61850ClientConnection*> > m_connections
= nullptr;

IEC61850ClientConnection* m_active_connection = nullptr;
std::mutex m_activeConnectionMtx;


enum class ConnectionStatus
{
STARTED,
Expand All @@ -176,7 +180,7 @@ class IEC61850Client
template <class T>
Datapoint* m_createDatapoint (const std::string& label,
const std::string& objRef, T value,
Quality quality, uint64_t timestampMs);
Quality quality, uint64_t timestampMs, bool hasValue);
static int getRootFromCDC (const CDCTYPE cdc);

void addQualityDp (Datapoint* cdcDp, Quality quality) const;
Expand Down
8 changes: 8 additions & 0 deletions include/iec61850_client_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
FRIEND_TEST (ReportingTest, ReportingUpdateQuality); \
FRIEND_TEST (ReportingTest, ReportingGI); \
FRIEND_TEST (ReportingTest, ReportingSetpointCommand); \
FRIEND_TEST (ReportingTest, ReconfigureDynamicDataset); \
FRIEND_TEST (ReportingTest, ReportingChangeValueMultipleTimes); \
FRIEND_TEST (ReportingTest, ReportingIndividualAttributes); \
FRIEND_TEST (SpontDataTest, Polling); \
FRIEND_TEST (SpontDataTest, PollingAllCDC); \
FRIEND_TEST (ControlTest, AnalogueCommandDirectNormal); \
Expand Down Expand Up @@ -115,6 +117,12 @@ struct DataExchangeDefinition
std::string label;
std::string id;
MmsVariableSpecification* spec;
bool hasIntValue = true;
union{
int intVal;
float floatVal;
} lastValue;
bool valueSet = false;
};

struct ReportSubscription
Expand Down
17 changes: 0 additions & 17 deletions src/iec61850.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,6 @@ void
IEC61850::start ()
{
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;
}
// LCOV_EXCL_STOP

m_client = new IEC61850Client (this, m_config);

Expand Down
86 changes: 57 additions & 29 deletions src/iec61850_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,6 @@ isCommandCdcType (CDCTYPE type)
return type >= SPC && type < SPG;
}

static uint64_t
getMonotonicTimeInMs ()
{
uint64_t timeVal = 0;

struct timespec ts;

if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
{
timeVal = ((uint64_t)ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000);
}

return timeVal;
}

static long
getValueInt (Datapoint* dp)
Expand Down Expand Up @@ -221,19 +207,20 @@ const std::map<CDCTYPE, std::string> cdcToStrMap
= { { SPS, "SpsTyp" }, { DPS, "DpsTyp" }, { BSC, "BscTyp" },
{ MV, "MvTyp" }, { SPC, "SpcTyp" }, { DPC, "DpcTyp" },
{ APC, "ApcTyp" }, { INC, "IncTyp" }, { INS, "InsTyp" },
{ ENS, "EnsTyp" }, { SPG, "SpgTyp" }, { ASG, "AsgType" },
{ ENS, "EnsTyp" }, { SPG, "SpgTyp" }, { ASG, "AsgTyp" },
{ ING, "IngTyp" } };
const std::map<CDCTYPE, PIVOTROOT> rootMap
= { { SPS, GTIS }, { DPS, GTIS }, { BSC, GTIC }, { INS, GTIS },
{ ENS, GTIS }, { MV, GTIM }, { SPC, GTIC }, { DPC, GTIC },
{ APC, GTIC }, { INC, GTIC } };
= { { SPS, GTIS }, { DPS, GTIS }, { BSC, GTIS }, { INS, GTIS },
{ ENS, GTIS }, { MV, GTIM }, { SPC, GTIS }, { DPC, GTIS },
{ APC, GTIM }, { INC, GTIS }, { ASG, GTIM }, { SPG, GTIS },
{ ING, GTIS} };

const std::map<PIVOTROOT, std::string> rootToStrMap
= { { GTIM, "GTIM" }, { GTIS, "GTIS" }, { GTIC, "GTIC" } };

IEC61850Client::IEC61850Client (IEC61850* iec61850,
IEC61850ClientConfig* iec61850_client_config)
: m_config (iec61850_client_config), m_iec61850 (iec61850)
: m_config (iec61850_client_config), m_iec61850 (iec61850), firstTimeConnect(true)
{
}

Expand All @@ -255,6 +242,11 @@ IEC61850Client::stop ()
delete m_monitoringThread;
m_monitoringThread = nullptr;
}

if(lastEntryId){
MmsValue_delete(lastEntryId);
lastEntryId = nullptr;
}
}

int
Expand Down Expand Up @@ -809,12 +801,25 @@ IEC61850Client::m_handleMonitoringData (

Quality quality = extractQuality (mmsvalue, def->spec, attribute);
uint64_t ts;

if (!mmsVal)
ts = extractTimestamp (mmsvalue, def->spec, attribute);
else
ts = timestamp;

if(attribute == "q"){
if(!def->valueSet){
Iec61850Utility::log_debug("Value for %s not yet set, sending only quality", objRef.c_str());
datapoints.push_back (m_createDatapoint (label, objRef, 0, quality, timestamp, false));
cleanUpMmsValue (mmsVal, mmsvalue);
return;
}
else{
datapoints.push_back (m_createDatapoint (label, objRef, def->hasIntValue ? def->lastValue.intVal : def->lastValue.floatVal, quality, timestamp, true));
cleanUpMmsValue (mmsVal, mmsvalue);
return;
}
}
if (!processDatapoint (type, datapoints, label, objRef, mmsvalue,
def->spec, quality, ts, attribute))
{
Expand All @@ -834,7 +839,7 @@ IEC61850Client::extractQuality (MmsValue* mmsvalue,
= MmsValue_getSubElement (mmsvalue, varSpec, (char*)"q");
return (!qualityMms && attribute != "q")
? QUALITY_VALIDITY_GOOD
: Quality_fromMmsValue (qualityMms);
: Quality_fromMmsValue ( attribute == "q" ? mmsvalue : qualityMms);
}

uint64_t
Expand All @@ -855,7 +860,7 @@ IEC61850Client::processDatapoint (
const std::string& label, const std::string& objRef, MmsValue* mmsvalue,
MmsVariableSpecification* varSpec, Quality quality, uint64_t timestamp,
const std::string& attribute)
{
{
switch (type)
{
case SPC:
Expand Down Expand Up @@ -916,8 +921,12 @@ IEC61850Client::processBooleanType (
}
}
bool value = MmsValue_getBoolean (element);
auto def = m_config->getExchangeDefinitionByObjRef (objRef);
def->lastValue.intVal = (long)value;
def->valueSet = true;

datapoints.push_back (
m_createDatapoint (label, objRef, (long)value, quality, timestamp));
m_createDatapoint (label, objRef, (long)value, quality, timestamp, true));
return true;
}

Expand Down Expand Up @@ -963,8 +972,12 @@ IEC61850Client::processBSCType (std::vector<Datapoint*>& datapoints,
long value = MmsValue_toInt32 (posVal);
bool transIndVal = MmsValue_getBoolean (transInd);
long combinedValue = (value << 1) | (long)transIndVal;
auto def = m_config->getExchangeDefinitionByObjRef (objRef);
def->lastValue.intVal = (long)combinedValue;
def->valueSet = true;

datapoints.push_back (
m_createDatapoint (label, objRef, combinedValue, quality, timestamp));
m_createDatapoint (label, objRef, combinedValue, quality, timestamp, true));
return true;
}

Expand All @@ -991,24 +1004,32 @@ IEC61850Client::processAnalogType (
}
}

auto def = m_config->getExchangeDefinitionByObjRef (objRef);
varSpec = MmsVariableSpecification_getChildSpecificationByName (
varSpec, elementName, nullptr);
MmsValue* f = MmsValue_getSubElement (element, varSpec, (char*)"f");

if (f)
{
double value = MmsValue_toFloat (f);
def->lastValue.floatVal = value;
def->valueSet = true;

datapoints.push_back (
m_createDatapoint (label, objRef, value, quality, timestamp));
m_createDatapoint (label, objRef, value, quality, timestamp, true));
return true;
}

MmsValue* i = MmsValue_getSubElement (element, varSpec, (char*)"i");
if (i)
{
long value = MmsValue_toInt32 (i);
def->hasIntValue = true;
def->lastValue.intVal = value;
def->valueSet = true;

datapoints.push_back (
m_createDatapoint (label, objRef, value, quality, timestamp));
m_createDatapoint (label, objRef, value, quality, timestamp, true));
return true;
}

Expand Down Expand Up @@ -1039,16 +1060,21 @@ IEC61850Client::processIntegerType (
}
}
long value = MmsValue_toInt32 (element);
auto def = m_config->getExchangeDefinitionByObjRef (objRef);

def->lastValue.intVal = (long) value;
def->valueSet = true;

datapoints.push_back (
m_createDatapoint (label, objRef, value, quality, timestamp));
m_createDatapoint (label, objRef, value, quality, timestamp,true));
return true;
}

template <class T>
Datapoint*
IEC61850Client::m_createDatapoint (const std::string& label,
const std::string& objRef, T value,
Quality quality, uint64_t timestamp)
Quality quality, uint64_t timestamp, bool hasValue)
{
auto def = m_config->getExchangeDefinitionByLabel (label);

Expand All @@ -1061,7 +1087,9 @@ IEC61850Client::m_createDatapoint (const std::string& label,
addElementWithValue (rootDp, "Identifier", (std::string)def->label);
Datapoint* cdcDp = addElement (rootDp, cdcToStrMap.at (def->cdcType));

addValueDp (cdcDp, def->cdcType, value);
if(hasValue){
addValueDp (cdcDp, def->cdcType, value);
}
addQualityDp (cdcDp, quality);
addTimestampDp (cdcDp, timestamp);

Expand Down
Loading

0 comments on commit 0b30b56

Please sign in to comment.