- added server examples logging

- added logging API
- added sqlite3 driver for logging
pull/6/head
Michael Zillgith 9 years ago
parent fd4261cd2d
commit 0c042f2ba4

@ -0,0 +1,30 @@
LIBIEC_HOME=../..
PROJECT_BINARY_NAME = server_example_logging
PROJECT_SOURCES = server_example_logging.c
PROJECT_SOURCES += static_model.c
PROJECT_SOURCES += $(LIBIEC_HOME)/src/logging/drivers/sqlite/log_storage_sqlite.c
PROJECT_ICD_FILE = simpleIO_direct_control.icd
include $(LIBIEC_HOME)/make/target_system.mk
include $(LIBIEC_HOME)/make/stack_includes.mk
all: $(PROJECT_BINARY_NAME)
include $(LIBIEC_HOME)/make/common_targets.mk
LDLIBS += -lm -lsqlite3
CP = cp
model: $(PROJECT_ICD_FILE)
java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE)
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
clean:
rm -f $(PROJECT_BINARY_NAME)

@ -0,0 +1,232 @@
/*
* server_example_logging.c
*
* - How to use a server with logging service
* - How to store arbitrary data in a log
*
*/
#include "iec61850_server.h"
#include "hal_thread.h"
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "static_model.h"
#include "logging_api.h"
/* import IEC 61850 device model created from SCL-File */
extern IedModel iedModel;
static int running = 0;
static IedServer iedServer = NULL;
void
sigint_handler(int signalId)
{
running = 0;
}
static ControlHandlerResult
controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test)
{
if (test)
return CONTROL_RESULT_FAILED;
if (MmsValue_getType(value) == MMS_BOOLEAN) {
printf("received binary control command: ");
if (MmsValue_getBoolean(value))
printf("on\n");
else
printf("off\n");
}
else
return CONTROL_RESULT_FAILED;
uint64_t timeStamp = Hal_getTimeInMs();
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value);
}
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value);
}
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value);
}
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) {
IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp);
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value);
}
return CONTROL_RESULT_OK;
}
static void
connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
{
if (connected)
printf("Connection opened\n");
else
printf("Connection closed\n");
}
static bool
entryCallback(void* parameter, uint64_t timestamp, uint64_t entryID, bool moreFollow)
{
#if 0
if (moreFollow)
printf("Found entry ID:%llu timestamp:%llu\n", entryID, timestamp);
#endif
return true;
}
static bool
entryDataCallback (void* parameter, const char* dataRef, const uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow)
{
#if 0
if (moreFollow) {
printf(" EntryData: ref: %s\n", dataRef);
MmsValue* value = MmsValue_decodeMmsData(data, 0, dataSize);
char buffer[256];
MmsValue_printToBuffer(value, buffer, 256);
printf(" value: %s\n", buffer);
MmsValue_delete(value);
}
#endif
return true;
}
int
main(int argc, char** argv)
{
printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
iedServer = IedServer_create(&iedModel);
/* Install handler for operate command */
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO2);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO3);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO4);
IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db");
IedServer_setLogStorage(iedServer, "GenericIO/LLN0$EventLog", statusLog);
uint64_t entryID = LogStorage_addEntry(statusLog, Hal_getTimeInMs());
MmsValue* value = MmsValue_newIntegerFromInt32(123);
uint8_t blob[256];
int blobSize = MmsValue_encodeMmsData(value, blob, 0, true);
LogStorage_addEntryData(statusLog, entryID, "simpleIOGenerioIO/GPIO1$ST$SPCSO1$stVal", blob, blobSize, 0);
MmsValue_delete(value);
value = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs());
blobSize = MmsValue_encodeMmsData(value, blob, 0, true);
MmsValue_delete(value);
LogStorage_addEntryData(statusLog, entryID, "simpleIOGenerioIO/GPIO1$ST$SPCSO1$t", blob, blobSize, 0);
LogStorage_getEntries(statusLog, 0, Hal_getTimeInMs(), entryCallback, entryDataCallback, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
if (!IedServer_isRunning(iedServer)) {
printf("Starting server failed! Exit.\n");
IedServer_destroy(iedServer);
exit(-1);
}
running = 1;
signal(SIGINT, sigint_handler);
float t = 0.f;
while (running) {
uint64_t timestamp = Hal_getTimeInMs();
t += 0.1f;
float an1 = sinf(t);
float an2 = sinf(t + 1.f);
float an3 = sinf(t + 2.f);
float an4 = sinf(t + 3.f);
IedServer_lockDataModel(iedServer);
Timestamp iecTimestamp;
Timestamp_clearFlags(&iecTimestamp);
Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp);
Timestamp_setLeapSecondKnown(&iecTimestamp, true);
/* toggle clock-not-synchronized flag in timestamp */
if (((int) t % 2) == 0)
Timestamp_setClockNotSynchronized(&iecTimestamp, true);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3);
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, &iecTimestamp);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4);
IedServer_unlockDataModel(iedServer);
Thread_sleep(100);
}
/* stop MMS server - close TCP server socket and all client sockets */
IedServer_stop(iedServer);
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
/* Release connection to database and free resources */
LogStorage_destroy(statusLog);
} /* main() */

@ -0,0 +1,281 @@
<?xml version="1.0" encoding="UTF-8"?>
<SCL xmlns="http://www.iec.ch/61850/2003/SCL">
<Header id="" nameStructure="IEDName">
</Header>
<Communication>
<SubNetwork name="subnetwork1" type="8-MMS">
<Text>Station bus</Text>
<BitRate unit="b/s">10</BitRate>
<ConnectedAP iedName="simpleIO" apName="accessPoint1">
<Address>
<P type="IP">10.0.0.2</P>
<P type="IP-SUBNET">255.255.255.0</P>
<P type="IP-GATEWAY">10.0.0.1</P>
<P type="OSI-TSEL">0001</P>
<P type="OSI-PSEL">00000001</P>
<P type="OSI-SSEL">0001</P>
</Address>
</ConnectedAP>
</SubNetwork>
</Communication>
<IED name="simpleIO">
<Services>
<DynAssociation />
<GetDirectory />
<GetDataObjectDefinition />
<GetDataSetValue />
<DataSetDirectory />
<ReadWrite />
<GetCBValues />
<ConfLNs fixPrefix="true" fixLnInst="true" />
<GOOSE max="5" />
<GSSE max="5" />
<FileHandling />
<GSEDir />
<TimerActivatedControl />
</Services>
<AccessPoint name="accessPoint1">
<Server>
<Authentication />
<LDevice inst="GenericIO">
<LN0 lnClass="LLN0" lnType="LLN01" inst="">
<DataSet name="Events" desc="Events">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO1" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO2" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO3" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO4" daName="stVal" />
</DataSet>
<DataSet name="Events2" desc="Events2">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO1" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO2" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO3" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO4" />
</DataSet>
<DataSet name="Measurements" desc="Measurements">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn1" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn1" daName="q" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn2" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn2" daName="q" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn3" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn3" daName="q" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn4" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn4" daName="q" />
</DataSet>
<ReportControl name="EventsRCB" confRev="4294967295" datSet="Events" rptID="Events1" buffered="false" intgPd="1000" bufTime="50">
<TrgOps period="true" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" entryID="true" configRef="true" />
<RptEnabled max="1" />
</ReportControl>
<ReportControl name="EventsIndexed" indexed="true" confRev="1" datSet="Events" rptID="Events2" buffered="false" intgPd="1000" bufTime="50">
<TrgOps period="true" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" entryID="true" configRef="true" />
<RptEnabled max="3" />
</ReportControl>
<ReportControl name="Measurements" indexed="true" confRev="1" datSet="Measurements" rptID="Measurements" buffered="true" intgPd="1000" bufTime="50">
<TrgOps period="false" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" entryID="true" configRef="true" />
<RptEnabled max="3" />
</ReportControl>
<LogControl name="EventLog" datSet="Events" logName="EventLog">
<TrgOps dchg="true" qchg="true"/>
</LogControl>
<LogControl name="GeneralLog" datSet="" logName="">
<TrgOps dchg="true" qchg="true"/>
</LogControl>
<Log />
<Log name="EventLog" />
<DOI name="Mod">
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
<DOI name="NamPlt">
<DAI name="vendor">
<Val>MZ Automation</Val>
</DAI>
<DAI name="swRev">
<Val>0.7.3</Val>
</DAI>
<DAI name="d">
<Val>libiec61850 server example</Val>
</DAI>
</DOI>
</LN0>
<LN lnClass="LPHD" lnType="LPHD1" inst="1" prefix="" />
<LN lnClass="GGIO" lnType="GGIO1" inst="1" prefix="">
<DOI name="Mod">
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
<DOI name="SPCSO1">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
<DOI name="SPCSO2">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
<DOI name="SPCSO3">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
<DOI name="SPCSO4">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
</LN>
</LDevice>
</Server>
</AccessPoint>
</IED>
<DataTypeTemplates>
<LNodeType id="LLN01" lnClass="LLN0">
<DO name="Mod" type="INC_1_Mod" />
<DO name="Beh" type="INS_1_Beh" />
<DO name="Health" type="INS_1_Beh" />
<DO name="NamPlt" type="LPL_1_NamPlt" />
</LNodeType>
<LNodeType id="LPHD1" lnClass="LPHD">
<DO name="PhyNam" type="DPL_1_PhyNam" />
<DO name="PhyHealth" type="INS_1_Beh" />
<DO name="Proxy" type="SPS_1_Proxy" />
</LNodeType>
<LNodeType id="GGIO1" lnClass="GGIO">
<DO name="Mod" type="INC_2_Mod" />
<DO name="Beh" type="INS_1_Beh" />
<DO name="Health" type="INS_1_Beh" />
<DO name="NamPlt" type="LPL_2_NamPlt" />
<DO name="AnIn1" type="MV_1_AnIn1" />
<DO name="AnIn2" type="MV_1_AnIn1" />
<DO name="AnIn3" type="MV_1_AnIn1" />
<DO name="AnIn4" type="MV_1_AnIn1" />
<DO name="SPCSO1" type="SPC_2_SPCSO1" />
<DO name="SPCSO2" type="SPC_1_SPCSO2" />
<DO name="SPCSO3" type="SPC_1_SPCSO3" />
<DO name="SPCSO4" type="SPC_1_SPCSO1" />
<DO name="Ind1" type="SPS_1_Proxy" />
<DO name="Ind2" type="SPS_1_Proxy" />
<DO name="Ind3" type="SPS_1_Proxy" />
<DO name="Ind4" type="SPS_1_Proxy" />
</LNodeType>
<DOType id="INC_1_Mod" cdc="INC">
<DA name="stVal" bType="INT32" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
</DOType>
<DOType id="INS_1_Beh" cdc="INS">
<DA name="stVal" bType="INT32" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="LPL_1_NamPlt" cdc="LPL">
<DA name="vendor" bType="VisString255" fc="DC" />
<DA name="swRev" bType="VisString255" fc="DC" />
<DA name="d" bType="VisString255" fc="DC" />
<DA name="configRev" bType="VisString255" fc="DC" />
<DA name="ldNs" bType="VisString255" fc="EX" />
</DOType>
<DOType id="DPL_1_PhyNam" cdc="DPL">
<DA name="vendor" bType="VisString255" fc="DC" />
</DOType>
<DOType id="SPS_1_Proxy" cdc="SPS">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="LPL_2_NamPlt" cdc="LPL">
<DA name="vendor" bType="VisString255" fc="DC" />
<DA name="swRev" bType="VisString255" fc="DC" />
<DA name="d" bType="VisString255" fc="DC" />
</DOType>
<DOType id="MV_1_AnIn1" cdc="MV">
<DA name="mag" type="AnalogueValue_1" bType="Struct" fc="MX" dchg="true" />
<DA name="q" bType="Quality" fc="MX" qchg="true" />
<DA name="t" bType="Timestamp" fc="MX" />
</DOType>
<DOType id="SPC_1_SPCSO1" cdc="SPC">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="Oper" type="SPCOperate_1" bType="Struct" fc="CO" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="INC_2_Mod" cdc="INC">
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
</DOType>
<DOType id="SPC_2_SPCSO1" cdc="SPC">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="Oper" type="SPCOperate_1" bType="Struct" fc="CO" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="SPC_1_SPCSO2" cdc="SPC">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="Oper" type="SPCOperate_1" bType="Struct" fc="CO" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="SPC_1_SPCSO3" cdc="SPC">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="Oper" type="SPCOperate_1" bType="Struct" fc="CO" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DAType id="AnalogueValue_1">
<BDA name="f" bType="FLOAT32" />
</DAType>
<DAType id="Originator_1">
<BDA name="orCat" type="OrCat" bType="Enum" />
<BDA name="orIdent" bType="Octet64" />
</DAType>
<DAType id="SPCOperate_1">
<BDA name="ctlVal" bType="BOOLEAN" />
<BDA name="origin" type="Originator_1" bType="Struct" />
<BDA name="ctlNum" bType="INT8U" />
<BDA name="T" bType="Timestamp" />
<BDA name="Test" bType="BOOLEAN" />
<BDA name="Check" bType="Check" />
</DAType>
<EnumType id="CtlModels">
<EnumVal ord="0">status-only</EnumVal>
<EnumVal ord="1">direct-with-normal-security</EnumVal>
<EnumVal ord="2">sbo-with-normal-security</EnumVal>
<EnumVal ord="3">direct-with-enhanced-security</EnumVal>
<EnumVal ord="4">sbo-with-enhanced-security</EnumVal>
</EnumType>
<EnumType id="OrCat">
<EnumVal ord="0">not-supported</EnumVal>
<EnumVal ord="1">bay-control</EnumVal>
<EnumVal ord="2">station-control</EnumVal>
<EnumVal ord="3">remote-control</EnumVal>
<EnumVal ord="4">automatic-bay</EnumVal>
<EnumVal ord="5">automatic-station</EnumVal>
<EnumVal ord="6">automatic-remote</EnumVal>
<EnumVal ord="7">maintenance</EnumVal>
<EnumVal ord="8">process</EnumVal>
</EnumType>
</DataTypeTemplates>
</SCL>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,301 @@
/*
* static_model.h
*
* automatically generated from simpleIO_direct_control.icd
*/
#ifndef STATIC_MODEL_H_
#define STATIC_MODEL_H_
#include <stdlib.h>
#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
extern LogicalNode iedModel_GenericIO_LLN0;
extern DataObject iedModel_GenericIO_LLN0_Mod;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_q;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_t;
extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel;
extern DataObject iedModel_GenericIO_LLN0_Beh;
extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal;
extern DataAttribute iedModel_GenericIO_LLN0_Beh_q;
extern DataAttribute iedModel_GenericIO_LLN0_Beh_t;
extern DataObject iedModel_GenericIO_LLN0_Health;
extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal;
extern DataAttribute iedModel_GenericIO_LLN0_Health_q;
extern DataAttribute iedModel_GenericIO_LLN0_Health_t;
extern DataObject iedModel_GenericIO_LLN0_NamPlt;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev;
extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs;
extern LogicalNode iedModel_GenericIO_LPHD1;
extern DataObject iedModel_GenericIO_LPHD1_PhyNam;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor;
extern DataObject iedModel_GenericIO_LPHD1_PhyHealth;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q;
extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t;
extern DataObject iedModel_GenericIO_LPHD1_Proxy;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t;
extern LogicalNode iedModel_GenericIO_GGIO1;
extern DataObject iedModel_GenericIO_GGIO1_Mod;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel;
extern DataObject iedModel_GenericIO_GGIO1_Beh;
extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t;
extern DataObject iedModel_GenericIO_GGIO1_Health;
extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Health_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Health_t;
extern DataObject iedModel_GenericIO_GGIO1_NamPlt;
extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor;
extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev;
extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d;
extern DataObject iedModel_GenericIO_GGIO1_AnIn1;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t;
extern DataObject iedModel_GenericIO_GGIO1_AnIn2;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t;
extern DataObject iedModel_GenericIO_GGIO1_AnIn3;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t;
extern DataObject iedModel_GenericIO_GGIO1_AnIn4;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO1;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO2;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO3;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO4;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind1;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind2;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind3;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind4;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO (&iedModel_GenericIO)
#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0)
#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod)
#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal)
#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q)
#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t)
#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel)
#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh)
#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal)
#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q)
#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t)
#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health)
#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal)
#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q)
#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t)
#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt)
#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor)
#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev)
#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d)
#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev)
#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs)
#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1)
#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam)
#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q)
#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t)
#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy)
#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal)
#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q)
#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t)
#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1)
#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod)
#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q)
#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t)
#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh)
#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal)
#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q)
#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t)
#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health)
#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal)
#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q)
#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t)
#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt)
#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor)
#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev)
#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d)
#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t)
#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t)
#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t)
#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t)
#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1)
#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q)
#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t)
#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2)
#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q)
#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t)
#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3)
#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q)
#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t)
#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4)
#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q)
#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t)
#endif /* STATIC_MODEL_H_ */

@ -1440,6 +1440,10 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
addVariablesWithFc("GO", logicalNodeName, ld->variables, lnDirectory);
break;
case ACSI_CLASS_LCB:
addVariablesWithFc("LG", logicalNodeName, ld->variables, lnDirectory);
break;
case ACSI_CLASS_DATA_SET:
{
LinkedList dataSet = LinkedList_getNext(ld->dataSets);

@ -133,6 +133,8 @@ FunctionalConstraint_toString(FunctionalConstraint fc) {
return "RP";
case IEC61850_FC_BR:
return "BR";
case IEC61850_FC_LG:
return "LG";
default:
return NULL;
}
@ -212,6 +214,12 @@ FunctionalConstraint_fromString(const char* fcString)
return IEC61850_FC_NONE;
}
if (fcString[0] == 'L') {
if (fcString[1] == 'G')
return IEC61850_FC_LG;
return IEC61850_FC_NONE;
}
return IEC61850_FC_NONE;
}

@ -234,6 +234,8 @@ typedef enum eFunctionalConstraint {
IEC61850_FC_RP = 15,
/** Buffered report */
IEC61850_FC_BR = 16,
/** Log control blocks */
IEC61850_FC_LG = 17,
/** All FCs - wildcard value */
IEC61850_FC_ALL = 99,

@ -29,6 +29,8 @@ typedef struct {
char* name;
LogicalNode* parentLN;
bool locked;
LogStorage logStorage;
uint64_t newEntryId;
@ -62,7 +64,10 @@ typedef struct {
bool enabled;
uint64_t nextIntegrityScan;
int triggerOps;
uint32_t intgPd;
} LogControl;
@ -76,12 +81,24 @@ LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage);
void
LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* value, uint8_t flag);
uint64_t
LogInstance_logEntryStart(LogInstance* self);
void
LogInstance_logEntryData(LogInstance* self, uint64_t entryID, const char* dataRef, MmsValue* value, uint8_t flag);
void
LogInstance_logEntryFinished(LogInstance* self, uint64_t entryID);
void
LogInstance_destroy(LogInstance* self);
LogControl*
LogControl_create(LogicalNode* parentLN, MmsMapping* mmsMapping);
void
LogControl_setLog(LogControl* self, LogInstance* logInstance);
void
LogControl_destroy(LogControl* self);
@ -92,7 +109,14 @@ MmsVariableSpecification*
Logging_createLCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode,
int lcbCount);
void
Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs);
MmsValue*
LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig);
MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection);
#endif /* LIBIEC61850_SRC_IEC61850_INC_PRIVATE_LOGGING_H_ */

@ -447,6 +447,19 @@ IedServer_destroy(IedServer self)
{
MmsServer_destroy(self->mmsServer);
IsoServer_destroy(self->isoServer);
#if (CONFIG_MMS_SINGLE_THREADED == 1)
/* trigger stopping background task thread */
self->mmsMapping->reportThreadRunning = false;
/* waiting for thread to finish */
while (self->mmsMapping->reportThreadFinished == false) {
Thread_sleep(10);
}
#endif
MmsMapping_destroy(self->mmsMapping);
LinkedList_destroyDeep(self->clientConnections, (LinkedListValueDeleteFunction) private_ClientConnection_destroy);

@ -35,6 +35,7 @@
#include "mms_mapping_internal.h"
#include "mms_value_internal.h"
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
LogInstance*
LogInstance_create(LogicalNode* parentLN, const char* name)
@ -44,6 +45,7 @@ LogInstance_create(LogicalNode* parentLN, const char* name)
self->name = copyString(name);
self->parentLN = parentLN;
self->logStorage = NULL;
self->locked = false;
self->oldEntryId = 0;
self->oldEntryTime = 0;
@ -67,7 +69,13 @@ LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* valu
if (logStorage != NULL) {
printf("Log value - dataRef: %s flag: %i\n", dataRef, flag);
while (self->locked)
Thread_sleep(1);
self->locked = true;
//if (DEBUG_IED_SERVER)
printf("IED_SERVER: Log value - dataRef: %s flag: %i\n", dataRef, flag);
uint64_t timestamp = Hal_getTimeInMs();
@ -81,6 +89,8 @@ LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* valu
LogStorage_addEntryData(logStorage, entryID, dataRef, data, dataSize, flag);
self->locked = false;
GLOBAL_FREEMEM(data);
self->newEntryId = entryID;
@ -88,9 +98,62 @@ LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* valu
}
else
printf("no log storage available!\n");
if (DEBUG_IED_SERVER)
printf("IED_SERVER: no log storage available for logging!\n");
}
uint64_t
LogInstance_logEntryStart(LogInstance* self)
{
LogStorage logStorage = self->logStorage;
if (logStorage != NULL) {
while (self->locked)
Thread_sleep(1);
self->locked = true;
uint64_t timestamp = Hal_getTimeInMs();
uint64_t entryID = LogStorage_addEntry(logStorage, timestamp);
return entryID;
}
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: no log storage available for logging!\n");
return 0;
}
}
void
LogInstance_logEntryData(LogInstance* self, uint64_t entryID, const char* dataRef, MmsValue* value, uint8_t flag)
{
LogStorage logStorage = self->logStorage;
if (logStorage != NULL) {
int dataSize = MmsValue_encodeMmsData(value, NULL, 0, false);
uint8_t* data = GLOBAL_MALLOC(dataSize);
MmsValue_encodeMmsData(value, data, 0, true);
LogStorage_addEntryData(logStorage, entryID, dataRef, data, dataSize, flag);
self->locked = false;
GLOBAL_FREEMEM(data);
}
}
void
LogInstance_logEntryFinished(LogInstance* self, uint64_t entryID)
{
self->locked = false;
}
void
LogInstance_setLogStorage(LogInstance* self, LogStorage logStorage)
@ -113,6 +176,7 @@ LogControl_create(LogicalNode* parentLN, MmsMapping* mmsMapping)
self->mmsMapping = mmsMapping;
self->dataSetRef = NULL;
self->logInstance = NULL;
self->intgPd = 0;
return self;
}
@ -138,6 +202,45 @@ LogControl_setLog(LogControl* self, LogInstance* logInstance)
self->logInstance = logInstance;
}
static void
prepareLogControl(LogControl* logControl)
{
if (logControl->dataSetRef == NULL) {
printf(" no data set specified!\n");
return;
}
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, logControl->dataSetRef);
if (dataSet == NULL) {
printf(" data set (%s) not found!\n", logControl->dataSetRef);
return;
}
else
logControl->dataSet = dataSet;
}
static bool
enableLogging(LogControl* self)
{
if ((self->dataSet != NULL) && (self->logInstance != NULL)) {
self->enabled = true;
if ((self->triggerOps & TRG_OPT_INTEGRITY) && (self->intgPd != 0))
self->nextIntegrityScan = Hal_getTimeInMs();
else
self->nextIntegrityScan = 0;
MmsValue* enabled = MmsValue_getSubElement(self->mmsValue, self->mmsType, "LogEna");
MmsValue_setBoolean(enabled, true);
return true;
}
else
return false;
}
static LogControlBlock*
getLCBForLogicalNodeWithIndex(MmsMapping* self, LogicalNode* logicalNode, int index)
{
@ -183,6 +286,59 @@ lookupLogControl(MmsMapping* self, MmsDomain* domain, char* lnName, char* object
return NULL;
}
static LogInstance*
getLogInstanceByLogRef(MmsMapping* self, const char* logRef)
{
char refStr[130];
char* domainName;
char* lnName;
char* logName;
strncpy(refStr, logRef, 129);
domainName = refStr;
lnName = strchr(refStr, '/');
if (lnName == NULL)
return NULL;
if ((lnName - domainName) > 64)
return NULL;
lnName[0] = 0;
lnName++;
logName = strchr(lnName, '$');
if (logName == NULL)
return NULL;
logName[0] = 0;
logName++;
LinkedList instance = LinkedList_getNext(self->logInstances);
while (instance != NULL) {
LogInstance* logInstance = LinkedList_getData(instance);
if (strcmp(logInstance->name, logName) == 0) {
if (strcmp(lnName, logInstance->parentLN->name) == 0) {
LogicalDevice* ld = (LogicalDevice*) logInstance->parentLN->parent;
if (strcmp(ld->name, domainName) == 0)
return logInstance;
}
}
instance = LinkedList_getNext(instance);
}
return NULL;
}
static void
updateLogStatusInLCB(LogControl* self)
{
@ -199,13 +355,168 @@ updateLogStatusInLCB(LogControl* self)
}
MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
{
bool updateValue = false;
char variableId[130];
strncpy(variableId, variableIdOrig, 129);
char* separator = strchr(variableId, '$');
*separator = 0;
char* lnName = variableId;
if (lnName == NULL)
return DATA_ACCESS_ERROR_INVALID_ADDRESS;
char* objectName = MmsMapping_getNextNameElement(separator + 1);
if (objectName == NULL)
return DATA_ACCESS_ERROR_INVALID_ADDRESS;
char* varName = MmsMapping_getNextNameElement(objectName);
if (varName != NULL)
*(varName - 1) = 0;
LogControl* logControl = lookupLogControl(self, domain, lnName, objectName);
if (logControl == NULL) {
return DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT;
}
if (strcmp(varName, "LogEna") == 0) {
bool logEna = MmsValue_getBoolean(value);
if (logEna == false) {
logControl->enabled = false;
}
else {
if (enableLogging(logControl)) {
logControl->enabled = true;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: enabled log control %s\n", logControl->name);
}
else
return DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
}
updateValue = true;
}
else if (strcmp(varName, "LogRef") == 0) {
if (logControl->enabled == false) {
/* check if logRef is valid or NULL */
const char* logRef = MmsValue_toString(value);
if (logRef == NULL) {
logControl->logInstance = NULL;
updateValue = true;
}
else {
if (strcmp(logRef, "") == 0) {
logControl->logInstance = NULL;
updateValue = true;
}
else {
/* remove IED name from logRef */
char* iedName = self->mmsDevice->deviceName;
uint32_t iedNameLen = strlen(iedName);
if (iedNameLen < strlen(logRef)) {
if (memcmp(iedName, logRef, iedNameLen) == 0) {
logRef = logRef + iedNameLen;
}
}
LogInstance* logInstance = getLogInstanceByLogRef(self, logRef);
if (logInstance != NULL) {
logControl->logInstance = logInstance;
updateValue = true;
}
else
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
}
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else if (strcmp(varName, "DatSet") == 0) {
if (logControl->enabled == false) {
/* check if datSet is valid or NULL/empty */
const char* dataSetRef = MmsValue_toString(value);
if (strlen(dataSetRef) == 0) {
logControl->dataSet = NULL;
updateValue = true;
}
else {
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, dataSetRef);
if (dataSet == NULL) {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: data set (%s) not found!\n", logControl->dataSetRef);
return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
}
else {
logControl->dataSet = dataSet;
updateValue = true;
}
}
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else if (strcmp(varName, "IntgPd") == 0) {
if (logControl->enabled == false) {
logControl->intgPd = MmsValue_toUint32(value);
updateValue = true;
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else if (strcmp(varName, "TrgOps") == 0) {
if (logControl->enabled == false) {
logControl->triggerOps = (MmsValue_getBitStringAsInteger(value) / 2);
updateValue = true;
}
else
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
if (updateValue) {
MmsValue* element = MmsValue_getSubElement(logControl->mmsValue, logControl->mmsType, varName);
MmsValue_update(element, value);
return DATA_ACCESS_ERROR_SUCCESS;
}
return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
MmsValue*
LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig)
{
MmsValue* value = NULL;
printf("READ ACCESS LOG CB\n");
char variableId[130];
strncpy(variableId, variableIdOrig, 129);
@ -261,10 +572,10 @@ createDataSetReferenceForDefaultDataSet(LogControlBlock* lcb, LogControl* logCon
}
static MmsValue*
createTrgOps(LogControlBlock* reportControlBlock) {
createTrgOps(LogControlBlock* logControlBlock) {
MmsValue* trgOps = MmsValue_newBitString(-6);
uint8_t triggerOps = reportControlBlock->trgOps;
uint8_t triggerOps = logControlBlock->trgOps;
if (triggerOps & TRG_OPT_DATA_CHANGED)
MmsValue_setBitStringBit(trgOps, 1, true);
@ -278,29 +589,7 @@ createTrgOps(LogControlBlock* reportControlBlock) {
return trgOps;
}
static bool
enableLogging(LogControl* logControl)
{
printf("Enable LCB %s...\n", logControl->name);
if (logControl->dataSetRef == NULL) {
printf(" no data set specified!\n");
return false;
}
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, logControl->dataSetRef);
if (dataSet == NULL) {
printf(" data set (%s) not found!\n", logControl->dataSetRef);
return false;
}
else
logControl->dataSet = dataSet;
printf(" enabled\n");
return true;
}
static MmsVariableSpecification*
createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
@ -440,6 +729,7 @@ createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
mmsValue->value.structure.components[8] =
MmsValue_newUnsignedFromUint32(logControlBlock->intPeriod);
logControl->intgPd = logControlBlock->intPeriod;
logControl->mmsType = lcb;
logControl->mmsValue = mmsValue;
@ -448,138 +738,109 @@ createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
logControl->enabled = logControlBlock->logEna;
if (logControl->enabled) {
prepareLogControl(logControl);
if (logControl->enabled)
enableLogging(logControl);
}
return lcb;
}
static LogInstance*
getLogInstanceByLogRef(MmsMapping* self, const char* logRef)
MmsVariableSpecification*
Logging_createLCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode,
int lcbCount)
{
char refStr[130];
char* domainName;
char* lnName;
char* logName;
strncpy(refStr, logRef, 129);
printf("getLogInst... %s\n", refStr);
domainName = refStr;
lnName = strchr(refStr, '/');
MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1,
sizeof(MmsVariableSpecification));
namedVariable->name = copyString("LG");
namedVariable->type = MMS_STRUCTURE;
if (lnName == NULL)
return NULL;
namedVariable->typeSpec.structure.elementCount = lcbCount;
namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(lcbCount,
sizeof(MmsVariableSpecification*));
if ((lnName - domainName) > 64)
return NULL;
int currentLcb = 0;
lnName[0] = 0;
lnName++;
while (currentLcb < lcbCount) {
logName = strchr(lnName, '$');
LogControl* logControl = LogControl_create(logicalNode, self);
if (logName == NULL)
return NULL;
LogControlBlock* logControlBlock = getLCBForLogicalNodeWithIndex(self, logicalNode, currentLcb);
logName[0] = 0;
logName++;
logControl->name = createString(3, logicalNode->name, "$LG$", logControlBlock->name);
logControl->domain = domain;
printf("LOG: dn: %s ln: %s name: %s\n", domainName, lnName, logName);
namedVariable->typeSpec.structure.elements[currentLcb] =
createLogControlBlock(self, logControlBlock, logControl);
LinkedList instance = LinkedList_getNext(self->logInstances);
if (logControlBlock->logRef != NULL)
logControl->logInstance = getLogInstanceByLogRef(self, logControlBlock->logRef);
while (instance != NULL) {
LinkedList_add(self->logControls, logControl);
LogInstance* logInstance = LinkedList_getData(instance);
currentLcb++;
}
printf("logInstance: %s\n", logInstance->name);
return namedVariable;
}
if (strcmp(logInstance->name, logName) == 0) {
printf (" lnName: %s\n", logInstance->parentLN->name);
static void
LogControl_logAllDatasetEntries(LogControl* self, const char* iedName)
{
if (self->dataSet == NULL)
return;
if (strcmp(lnName, logInstance->parentLN->name) == 0) {
LogicalDevice* ld = (LogicalDevice*) logInstance->parentLN->parent;
if (self->logInstance != NULL) {
printf(" ldName: %s\n", ld->name);
char dataRef[130];
if (strcmp(ld->name, domainName) == 0)
return logInstance;
}
}
LogInstance* log = self->logInstance;
instance = LinkedList_getNext(instance);
}
uint64_t entryID = LogInstance_logEntryStart(log);
return NULL;
}
DataSetEntry* dataSetEntry = self->dataSet->fcdas;
#if 0
static LogInstance*
getLogInstance(MmsMapping* self, LogicalNode* logicalNode, const char* logName)
{
if (logName == NULL)
return NULL;
while (dataSetEntry != NULL) {
LinkedList logInstance = LinkedList_getNext(self->logInstances);
sprintf(dataRef, "%s%s/%s", iedName, dataSetEntry->logicalDeviceName, dataSetEntry->variableName);
while (logInstance != NULL) {
LogInstance* instance = (LogInstance*) LinkedList_getData(logInstance);
LogInstance_logEntryData(log, entryID, dataRef, dataSetEntry->value, TRG_OPT_INTEGRITY * 2);
printf("LOG: %s (%s)\n", instance->name, logName);
dataSetEntry = dataSetEntry->sibling;
}
if ((strcmp(instance->name, logName) == 0) && (logicalNode == instance->parentLN))
return instance;
LogInstance_logEntryFinished(log, entryID);
logInstance = LinkedList_getNext(logInstance);
}
return NULL;
}
#endif
MmsVariableSpecification*
Logging_createLCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode,
int lcbCount)
void
Logging_processIntegrityLogs(MmsMapping* self, uint64_t currentTimeInMs)
{
MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1,
sizeof(MmsVariableSpecification));
namedVariable->name = copyString("LG");
namedVariable->type = MMS_STRUCTURE;
namedVariable->typeSpec.structure.elementCount = lcbCount;
namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(lcbCount,
sizeof(MmsVariableSpecification*));
LinkedList logControlElem = LinkedList_getNext(self->logControls);
int currentLcb = 0;
while (logControlElem != NULL) {
while (currentLcb < lcbCount) {
LogControl* logControl = LogControl_create(logicalNode, self);
LogControl* logControl = (LogControl*) LinkedList_getData(logControlElem);
LogControlBlock* logControlBlock = getLCBForLogicalNodeWithIndex(self, logicalNode, currentLcb);
if (logControl->enabled) {
logControl->name = createString(3, logicalNode->name, "$LG$", logControlBlock->name);
logControl->domain = domain;
if (logControl->nextIntegrityScan != 0) {
namedVariable->typeSpec.structure.elements[currentLcb] =
createLogControlBlock(self, logControlBlock, logControl);
if (currentTimeInMs >= logControl->nextIntegrityScan) {
//getLogInstanceByLogRef(self, logControlBlock->logRef);
//logControl->logInstance = getLogInstance(self, logicalNode, logControlBlock->logRef);
if (DEBUG_IED_SERVER)
printf("IED_SERVER: INTEGRITY SCAN for log %s\n", logControl->name);
if (logControlBlock->logRef != NULL)
logControl->logInstance = getLogInstanceByLogRef(self, logControlBlock->logRef);
LogControl_logAllDatasetEntries(logControl, self->mmsDevice->deviceName);
LinkedList_add(self->logControls, logControl);
logControl->nextIntegrityScan += logControl->intgPd;
}
}
}
currentLcb++;
logControlElem = LinkedList_getNext(logControlElem);
}
return namedVariable;
}
void
@ -590,29 +851,23 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto
if (logInstance != NULL) {
LogInstance_setLogStorage(logInstance, logStorage);
#if 1
char domainName[65];
MmsMapping_getMmsDomainFromObjectReference(logRef, domainName);
char domainName2[65];
char domainNameWithIEDName[65];
strcpy(domainName2, self->model->name);
strcat(domainName2, domainName);
strcpy(domainNameWithIEDName, self->model->name);
strcat(domainNameWithIEDName, domainName);
MmsDomain* mmsDomain = MmsDevice_getDomain(self->mmsDevice, domainName2);
MmsDomain* mmsDomain = MmsDevice_getDomain(self->mmsDevice, domainNameWithIEDName);
if (mmsDomain == NULL) {
printf("IED_SERVER: MmsMapping_setLogStorage: domain %s not found!\n", domainName2);
}
#if 0
char journalName[65];
strcpy(journalName, self->parentLN->name);
strcat(journalName, "$");
strcat(journalName, self->name);
#endif
if (DEBUG_IED_SERVER)
printf("IED_SERVER: MmsMapping_setLogStorage: domain %s not found!\n", domainNameWithIEDName);
return;
}
MmsJournal mmsJournal = NULL;
@ -626,12 +881,14 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto
if (mmsJournal != NULL)
mmsJournal->logStorage = logStorage;
else
printf("IED_SERVER: Failed to retrieve MMS journal for log!\n");
#endif
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Failed to retrieve MMS journal for log!\n");
}
//if (DEBUG_IED_SERVER)
if (DEBUG_IED_SERVER)
if (logInstance == NULL)
printf("IED_SERVER: MmsMapping_setLogStorage no matching log for %s found!\n", logRef);
}
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */

@ -1799,6 +1799,13 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
#endif /* (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) */
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
/* Log control block - LG */
if (isLogControlBlock(separator))
return LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(self, domain, variableId, value, connection);
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
#if (CONFIG_IEC61850_REPORT_SERVICE == 1)
/* Report control blocks - BR, RP */
@ -2625,51 +2632,6 @@ DataSet_isMemberValueWithRef(DataSet* dataSet, MmsValue* value, char* dataRef, c
return false;
}
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
#if (CONFIG_IEC61850_REPORT_SERVICE == 1)
void
MmsMapping_triggerReportObservers(MmsMapping* self, MmsValue* value, ReportInclusionFlag flag)
{
LinkedList element = self->reportControls;
while ((element = LinkedList_getNext(element)) != NULL) {
ReportControl* rc = (ReportControl*) element->data;
if (rc->enabled || (rc->buffered && rc->dataSet != NULL)) {
int index;
switch (flag) {
case REPORT_CONTROL_VALUE_UPDATE:
if ((rc->triggerOps & TRG_OPT_DATA_UPDATE) == 0)
continue;
break;
case REPORT_CONTROL_VALUE_CHANGED:
if (((rc->triggerOps & TRG_OPT_DATA_CHANGED) == 0) &&
((rc->triggerOps & TRG_OPT_DATA_UPDATE) == 0))
continue;
break;
case REPORT_CONTROL_QUALITY_CHANGED:
if ((rc->triggerOps & TRG_OPT_QUALITY_CHANGED) == 0)
continue;
break;
default:
continue;
}
if (DataSet_isMemberValue(rc->dataSet, value, &index)) {
ReportControl_valueUpdated(rc, index, flag);
}
}
}
}
#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
void
MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag flag)
{
@ -2680,12 +2642,16 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
if ((lc->enabled) && (lc->dataSet != NULL)) {
uint8_t reasonCode;
switch (flag) {
case LOG_CONTROL_VALUE_UPDATE:
if ((lc->triggerOps & TRG_OPT_DATA_UPDATE) == 0)
continue;
reasonCode = TRG_OPT_DATA_UPDATE * 2;
break;
case LOG_CONTROL_VALUE_CHANGED:
@ -2693,12 +2659,16 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
((lc->triggerOps & TRG_OPT_DATA_UPDATE) == 0))
continue;
reasonCode = TRG_OPT_DATA_CHANGED * 2;
break;
case LOG_CONTROL_QUALITY_CHANGED:
if ((lc->triggerOps & TRG_OPT_QUALITY_CHANGED) == 0)
continue;
reasonCode = TRG_OPT_QUALITY_CHANGED * 2;
break;
default:
@ -2710,7 +2680,7 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
if (DataSet_isMemberValueWithRef(lc->dataSet, value, dataRef, self->model->name)) {
if (lc->logInstance != NULL) {
LogInstance_logSingleData(lc->logInstance, dataRef, value, flag);
LogInstance_logSingleData(lc->logInstance, dataRef, value, reasonCode);
}
else
printf("No log instance available!\n");
@ -2723,6 +2693,46 @@ MmsMapping_triggerLogging(MmsMapping* self, MmsValue* value, LogInclusionFlag fl
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
#if (CONFIG_IEC61850_REPORT_SERVICE == 1)
void
MmsMapping_triggerReportObservers(MmsMapping* self, MmsValue* value, ReportInclusionFlag flag)
{
LinkedList element = self->reportControls;
while ((element = LinkedList_getNext(element)) != NULL) {
ReportControl* rc = (ReportControl*) element->data;
if (rc->enabled || (rc->buffered && rc->dataSet != NULL)) {
int index;
switch (flag) {
case REPORT_CONTROL_VALUE_UPDATE:
if ((rc->triggerOps & TRG_OPT_DATA_UPDATE) == 0)
continue;
break;
case REPORT_CONTROL_VALUE_CHANGED:
if (((rc->triggerOps & TRG_OPT_DATA_CHANGED) == 0) &&
((rc->triggerOps & TRG_OPT_DATA_UPDATE) == 0))
continue;
break;
case REPORT_CONTROL_QUALITY_CHANGED:
if ((rc->triggerOps & TRG_OPT_QUALITY_CHANGED) == 0)
continue;
break;
default:
continue;
}
if (DataSet_isMemberValue(rc->dataSet, value, &index)) {
ReportControl_valueUpdated(rc, index, flag);
}
}
}
}
#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
void
MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value)
@ -2950,6 +2960,10 @@ processPeriodicTasks(MmsMapping* self)
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
MmsMapping_checkForSettingGroupReservationTimeouts(self, currentTimeInMs);
#endif
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
Logging_processIntegrityLogs(self, currentTimeInMs);
#endif
}
void

@ -0,0 +1,3 @@
This directory contains the log driver implementation that implements the logging API. The logging API is a service provider interface that has to be implemented by the log driver.
An application can use different log drivers at the same time.
Each log driver provides a public constructor for the driver specific implementation of the LogStorage class. The constructor has to fill the virtual function table of the LogStorage instance with its own implementation functions.

@ -0,0 +1,455 @@
/*
* log_storage_sqlite.c
*
* Copyright 2016 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
#include "logging_api.h"
#include "libiec61850_platform_includes.h"
#include <sqlite3.h>
#ifndef DEBUG_LOG_STORAGE_DRIVER
#define DEBUG_LOG_STORAGE_DRIVER 0
#endif
static uint64_t
SqliteLogStorage_addEntry(LogStorage self, uint64_t timestamp);
static bool
SqliteLogStorage_addEntryData(LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode);
static bool
SqliteLogStorage_getEntries(LogStorage self, uint64_t startingTime, uint64_t endingTime,
LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter);
static bool
SqliteLogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_t entryID,
LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter);
static bool
SqliteLogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime,
uint64_t* oldEntry, uint64_t* oldEntryTime);
static void
SqliteLogStorage_destroy(LogStorage self);
typedef struct sSqliteLogStorage {
char* filename;
sqlite3* db;
sqlite3_stmt* insertEntryStmt;
sqlite3_stmt* insertEntryDataStmt;
sqlite3_stmt* getEntriesWithRange;
sqlite3_stmt* getEntriesAfter;
sqlite3_stmt* getEntryData;
sqlite3_stmt* getOldEntry;
sqlite3_stmt* getNewEntry;
} SqliteLogStorage;
static const char* CREATE_TABLE_ENTRYS = "create table if not exists Entries (entryID integer primary key, timeOfEntry integer)";
static const char* CREATE_TABLE_ENTRY_DATA = "create table if not exists EntryData (entryID integer, dataRef text, value blob, reasonCode integer)";
static const char* INSERT_ENTRY = "insert into Entries (timeOfEntry) values (?)";
static const char* INSERT_ENTRY_DATA = "insert into EntryData (entryID, dataRef, value, reasonCode) values (?,?,?,?)";
static const char* GET_ENTRIES_WITH_RANGE = "select entryID, timeOfEntry from Entries where timeOfEntry >= ? and timeOfEntry <= ?";
static const char* GET_ENTRIES_AFTER = "select entryID, timeOfEntry from Entries where entryID > ?";
static const char* GET_ENTRY_DATA = "select dataRef, value, reasonCode from EntryData where entryID = ?";
static const char* GET_OLD_ENTRY = "select * from Entries where entryID = (select min(entryID) from Entries where timeOfEntry = (select min(timeOfEntry) from Entries))";
static const char* GET_NEW_ENTRY = "select * from Entries where entryID = (select max(entryID) from Entries where timeOfEntry = (select max(timeOfEntry) from Entries))";
LogStorage
SqliteLogStorage_createInstance(const char* filename)
{
sqlite3* db = NULL;
sqlite3_stmt* insertEntryStmt = NULL;
sqlite3_stmt* insertEntryDataStmt = NULL;
sqlite3_stmt* getEntriesWithRange = NULL;
sqlite3_stmt* getEntriesAfter = NULL;
sqlite3_stmt* getEntryData = NULL;
sqlite3_stmt* getOldEntry = NULL;
sqlite3_stmt* getNewEntry = NULL;
char *zErrMsg = 0;
int rc = sqlite3_open(filename, &db);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_exec(db, CREATE_TABLE_ENTRYS, NULL, 0, &zErrMsg);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_exec(db, CREATE_TABLE_ENTRY_DATA, NULL, 0, &zErrMsg);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare(db, INSERT_ENTRY, -1, &insertEntryStmt, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare(db, INSERT_ENTRY_DATA, -1, &insertEntryDataStmt, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare_v2(db, GET_ENTRIES_WITH_RANGE, -1, &getEntriesWithRange, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare_v2(db, GET_ENTRIES_AFTER, -1, &getEntriesAfter, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare_v2(db, GET_ENTRY_DATA, -1, &getEntryData, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare_v2(db, GET_OLD_ENTRY, -1, &getOldEntry, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_prepare_v2(db, GET_NEW_ENTRY, -1, &getNewEntry, NULL);
if (rc != SQLITE_OK)
goto exit_with_error;
LogStorage self = (LogStorage) GLOBAL_CALLOC(1, sizeof(struct sLogStorage));
SqliteLogStorage* instanceData = (SqliteLogStorage*) GLOBAL_CALLOC(1, sizeof(struct sSqliteLogStorage));
instanceData->filename = copyString(filename);
instanceData->db = db;
instanceData->insertEntryStmt = insertEntryStmt;
instanceData->insertEntryDataStmt = insertEntryDataStmt;
instanceData->getEntriesWithRange = getEntriesWithRange;
instanceData->getEntriesAfter = getEntriesAfter;
instanceData->getEntryData = getEntryData;
instanceData->getOldEntry = getOldEntry;
instanceData->getNewEntry = getNewEntry;
self->instanceData = (void*) instanceData;
self->addEntry = SqliteLogStorage_addEntry;
self->addEntryData = SqliteLogStorage_addEntryData;
self->getEntries = SqliteLogStorage_getEntries;
self->getEntriesAfter = SqliteLogStorage_getEntriesAfter;
self->getOldestAndNewestEntries = SqliteLogStorage_getOldestAndNewestEntries;
self->destroy = SqliteLogStorage_destroy;
return self;
exit_with_error:
if (DEBUG_LOG_STORAGE_DRIVER)
printf("LOG_STORAGE_DRIVER: sqlite - failed to create LogStorage instance!\n");
return NULL;
}
static uint64_t
SqliteLogStorage_addEntry(LogStorage self, uint64_t timestamp)
{
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
sqlite3* db = instanceData->db;
int rc;
char *zErrMsg = 0;
rc = sqlite3_bind_int64(instanceData->insertEntryStmt, 1, (sqlite_int64) timestamp);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_step(instanceData->insertEntryStmt);
if (rc != SQLITE_DONE)
goto exit_with_error;
uint64_t id = sqlite3_last_insert_rowid(db);
if (DEBUG_LOG_STORAGE_DRIVER)
printf("LOG_STORAGE_DRIVER: sqlite - new entry with ID = %lu\n", id);
rc = sqlite3_reset(instanceData->insertEntryStmt);
if (rc != SQLITE_OK)
goto exit_with_error;
return id;
exit_with_error:
if (DEBUG_LOG_STORAGE_DRIVER)
printf("LOG_STORAGE_DRIVER: sqlite - failed to add entry to log!\n");
return 0;
}
static bool
SqliteLogStorage_addEntryData(LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode)
{
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
sqlite3* db = instanceData->db;
int rc;
char *zErrMsg = 0;
rc = sqlite3_bind_int64(instanceData->insertEntryDataStmt, 1, (sqlite_int64) entryID);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_bind_text(instanceData->insertEntryDataStmt, 2, dataRef, -1, SQLITE_STATIC);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_bind_blob(instanceData->insertEntryDataStmt, 3, data, dataSize, SQLITE_STATIC);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_bind_int(instanceData->insertEntryDataStmt, 4, reasonCode);
if (rc != SQLITE_OK)
goto exit_with_error;
rc = sqlite3_step(instanceData->insertEntryDataStmt);
if (rc != SQLITE_DONE)
goto exit_with_error;
rc = sqlite3_reset(instanceData->insertEntryDataStmt);
if (rc != SQLITE_OK)
goto exit_with_error;
return true;
exit_with_error:
if (DEBUG_LOG_STORAGE_DRIVER)
printf("LOG_STORAGE_DRIVER: sqlite - failed to add entry data!\n");
return false;
}
static void
getEntryData(LogStorage self, uint64_t entryID, LogEntryDataCallback entryDataCallback, void* parameter)
{
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
int rc;
rc = sqlite3_bind_int64(instanceData->getEntryData, 1, entryID);
if (rc != SQLITE_OK)
printf("getEntryData 1 rc:%i\n", rc);
bool sendFinalEvent = true;
while ((rc = sqlite3_step(instanceData->getEntryData)) == SQLITE_ROW) {
const char* dataRef = sqlite3_column_text(instanceData->getEntryData, 0);
const uint8_t* data = sqlite3_column_blob(instanceData->getEntryData, 1);
int dataSize = sqlite3_column_bytes(instanceData->getEntryData, 1);
int reasonCode = sqlite3_column_int(instanceData->getEntryData, 2);
if (entryDataCallback != NULL) {
if (entryDataCallback(parameter, dataRef, data, dataSize, (uint8_t) reasonCode, true) == false) {
sendFinalEvent = false;
break;
}
}
}
if (sendFinalEvent) {
if (entryDataCallback != NULL)
entryDataCallback(parameter, NULL, NULL, 0, (uint8_t) 0, false);
}
rc = sqlite3_reset(instanceData->getEntryData);
if (rc != SQLITE_OK)
printf("getEntryData reset rc:%i\n", rc);
}
static bool
SqliteLogStorage_getEntries(LogStorage self, uint64_t startingTime, uint64_t endingTime,
LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter)
{
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
sqlite3* db = instanceData->db;
int rc;
rc = sqlite3_bind_int64(instanceData->getEntriesWithRange, 1, startingTime);
if (rc != SQLITE_OK)
printf("SqliteLogStorage_getEntries 1 rc:%i\n", rc);
rc = sqlite3_bind_int64(instanceData->getEntriesWithRange, 2, endingTime);
if (rc != SQLITE_OK)
printf("SqliteLogStorage_getEntries 2 rc:%i\n", rc);
bool sendFinalEvent = true;
while((rc = sqlite3_step(instanceData->getEntriesWithRange)) == SQLITE_ROW) {
int col;
uint64_t entryID = sqlite3_column_int64(instanceData->getEntriesWithRange, 0);
uint64_t timestamp = sqlite3_column_int64(instanceData->getEntriesWithRange, 1);
if (entryCallback != NULL) {
if (entryCallback(parameter, timestamp, entryID, true) == false) {
sendFinalEvent = false;
break;
}
}
getEntryData(self, entryID, entryDataCallback, parameter);
}
if (sendFinalEvent)
if (entryCallback != NULL)
entryCallback(parameter, 0, 0, false);
rc = sqlite3_reset(instanceData->getEntriesWithRange);
if (rc != SQLITE_OK)
printf("SqliteLogStorage_getEntries reset rc:%i\n", rc);
return true;
}
static bool
SqliteLogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry, uint64_t* newEntryTime,
uint64_t* oldEntry, uint64_t* oldEntryTime)
{
bool validOldEntry = false;
bool validNewEntry = false;
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
sqlite3* db = instanceData->db;
int rc;
/* Get oldest entry */
rc = sqlite3_step(instanceData->getOldEntry);
if (rc == SQLITE_ROW) {
*oldEntry = sqlite3_column_int64(instanceData->getOldEntry, 0);
*oldEntryTime = sqlite3_column_int64(instanceData->getOldEntry, 1);
validNewEntry = true;
}
sqlite3_reset(instanceData->getOldEntry);
/* Get newest entry */
rc = sqlite3_step(instanceData->getNewEntry);
if (rc == SQLITE_ROW) {
*newEntry = sqlite3_column_int64(instanceData->getNewEntry, 0);
*newEntryTime = sqlite3_column_int64(instanceData->getNewEntry, 1);
validOldEntry = true;
}
sqlite3_reset(instanceData->getNewEntry);
return (validOldEntry && validNewEntry);
}
static bool
SqliteLogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_t entryID,
LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter)
{
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
sqlite3* db = instanceData->db;
int rc;
rc = sqlite3_bind_int64(instanceData->getEntriesAfter, 1, entryID);
if (rc != SQLITE_OK)
printf("SqliteLogStorage_getEntriesAfter 1 rc:%i\n", rc);
bool sendFinalEvent = true;
while ((rc = sqlite3_step(instanceData->getEntriesAfter)) == SQLITE_ROW) {
int col;
uint64_t entryID = sqlite3_column_int64(instanceData->getEntriesAfter, 0);
uint64_t timestamp = sqlite3_column_int64(instanceData->getEntriesAfter, 1);
if (entryCallback != NULL) {
if (entryCallback(parameter, timestamp, entryID, true) == false) {
sendFinalEvent = false;
break;
}
}
getEntryData(self, entryID, entryDataCallback, parameter);
}
if (sendFinalEvent)
if (entryCallback != NULL)
entryCallback(parameter, 0, 0, false);
rc = sqlite3_reset(instanceData->getEntriesAfter);
if (rc != SQLITE_OK)
printf("SqliteLogStorage_getEntriesAfter reset rc:%i\n", rc);
return true;
}
static void
SqliteLogStorage_destroy(LogStorage self)
{
SqliteLogStorage* instanceData = (SqliteLogStorage*) self->instanceData;
sqlite3_finalize(instanceData->insertEntryStmt);
sqlite3_finalize(instanceData->insertEntryDataStmt);
sqlite3_finalize(instanceData->getEntriesWithRange);
sqlite3_finalize(instanceData->getEntriesAfter);
sqlite3_finalize(instanceData->getEntryData);
sqlite3_finalize(instanceData->getOldEntry);
sqlite3_finalize(instanceData->getNewEntry);
if (sqlite3_close(instanceData->db) != SQLITE_OK)
printf("SqliteLogStorage: failed to close database %s!\n", instanceData->filename);
GLOBAL_FREEMEM(instanceData->filename);
GLOBAL_FREEMEM(instanceData);
GLOBAL_FREEMEM(self);
}

@ -37,7 +37,7 @@ typedef struct sLogStorage* LogStorage;
*/
typedef bool (*LogEntryCallback) (void* parameter, uint64_t timestamp, uint64_t entryID, bool moreFollow);
typedef bool (*LogEntryDataCallback) (void* parameter, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow);
typedef bool (*LogEntryDataCallback) (void* parameter, const char* dataRef, const uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow);
struct sLogStorage {

@ -1172,7 +1172,6 @@ public class StaticModelGenerator {
else
lcbString += "NULL, ";
String logRef;
if (lcb.getLdInst() == null)
@ -1190,11 +1189,14 @@ public class StaticModelGenerator {
else
lcbString += "NULL, ";
int triggerOps = 16;
int triggerOps = 0;
if (lcb.getTriggerOptions() != null)
triggerOps = lcb.getTriggerOptions().getIntValue();
if (triggerOps >= 16)
triggerOps = triggerOps - 16;
lcbString += triggerOps + ", ";
if (lcb.getIntgPd() != 0)

Loading…
Cancel
Save