- added cmake support to build sqlite log driver

- made logging ready to be compiled with Visual Studio
- added functions to create LCBs and LOGs to dynamic model API
- client: added GetLogicalNodeDirectory(LOG) ACSI function
This commit is contained in:
Michael Zillgith 2016-06-09 00:00:02 +02:00
parent 23e695dae8
commit 2b28c0fed3
43 changed files with 596 additions and 93 deletions

View file

@ -14,6 +14,8 @@ set(LIB_VERSION_MAJOR "0")
set(LIB_VERSION_MINOR "9")
set(LIB_VERSION_PATCH "2")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/")
# feature checks
include(CheckLibraryExists)
check_library_exists(rt clock_gettime "time.h" CONFIG_SYSTEM_HAS_CLOCK_GETTIME)
@ -28,7 +30,7 @@ set(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 CACHE STRING "Configure the maximum
option(BUILD_EXAMPLES "Build the examples" ON)
option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)
option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" OFF)
option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" ON)
option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF)
# choose the library features which shall be included
@ -38,6 +40,8 @@ option(CONFIG_IEC61850_CONTROL_SERVICE "Build with support for IEC 61850 control
option(CONFIG_IEC61850_REPORT_SERVICE "Build with support for IEC 61850 reporting services" ON)
option(CONFIG_IEC61850_LOG_SERVICE "Build with support for IEC 61850 logging services" ON)
option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON)
option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON)
@ -68,6 +72,7 @@ include_directories(
src/mms/inc
src/mms/inc_private
src/mms/iso_mms/asn1c
src/logging
)
set(API_HEADERS
@ -102,6 +107,7 @@ set(API_HEADERS
src/goose/goose_publisher.h
src/sampled_values/sv_subscriber.h
src/sampled_values/sv_publisher.h
src/logging/logging_api.h
)
IF(MSVC)

View file

@ -156,10 +156,10 @@
/* include support for IEC 61850 log services */
#define CONFIG_IEC61850_LOG_SERVICE 1
/* default results for MMS identify service */
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
#define CONFIG_DEFAULT_MMS_REVISION "0.9.2"
/* overwrite default results for MMS identify service */
//#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
//#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
//#define CONFIG_DEFAULT_MMS_REVISION "0.9.2"
/* MMS virtual file store base path - where file services are looking for files */
#define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/"

View file

@ -142,6 +142,9 @@
/* default reservation time of a setting group control block in s */
#define CONFIG_IEC61850_SG_RESVTMS 100
/* include support for IEC 61850 log services */
#cmakedefine01 CONFIG_IEC61850_LOG_SERVICE
/* default results for MMS identify service */
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"

View file

@ -10,6 +10,7 @@ add_subdirectory(server_example_complex_array)
add_subdirectory(server_example_threadless)
add_subdirectory(server_example_61400_25)
add_subdirectory(server_example_setting_groups)
add_subdirectory(server_example_logging)
add_subdirectory(iec61850_client_example1)
add_subdirectory(iec61850_client_example2)
add_subdirectory(iec61850_client_example3)

View file

@ -12,7 +12,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <inttypes.h>
static int running = 1;
@ -28,7 +28,7 @@ gooseListener(GooseSubscriber subscriber, void* parameter)
printf(" stNum: %u sqNum: %u\n", GooseSubscriber_getStNum(subscriber),
GooseSubscriber_getSqNum(subscriber));
printf(" timeToLive: %u\n", GooseSubscriber_getTimeAllowedToLive(subscriber));
printf(" timestamp: %llu\n", GooseSubscriber_getTimestamp(subscriber));
printf(" timestamp: %"PRIu64"\n", GooseSubscriber_getTimestamp(subscriber));
MmsValue* values = GooseSubscriber_getDataSetValues(subscriber);

View file

@ -947,6 +947,8 @@ SVControlBlock iedModel_MUnn_LLN0_smv0 = {&iedModel_MUnn_LLN0, "MSVCB01", "xxxxM
IedModel iedModel = {
"TEMPLATE",
&iedModel_MUnn,
@ -955,6 +957,8 @@ IedModel iedModel = {
NULL,
&iedModel_MUnn_LLN0_smv0,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -212,21 +212,6 @@ int main(int argc, char** argv) {
char* name = (char*) element->data;
printf(" %s\n", name);
#if 0
uint64_t timestamp = Hal_getTimeInMs();
MmsValue* startTime = MmsValue_newBinaryTime(false);
MmsValue_setBinaryTime(startTime, timestamp - 60000);
MmsValue* entrySpec = MmsValue_newOctetString(8, 8);
MmsConnection_readJournalStartAfter(con, &error, domainName, name, startTime, entrySpec);
#endif
}
LinkedList_destroy(variableList);

View file

@ -1596,6 +1596,8 @@ ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN
IedModel iedModel = {
"SampleIED",
&iedModel_Device1,
@ -1604,6 +1606,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -3586,6 +3586,8 @@ ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "r
IedModel iedModel = {
"ied1",
&iedModel_Inverter,
@ -3594,6 +3596,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -1957,8 +1957,8 @@ ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0,
extern LogControlBlock iedModel_GenericIO_LLN0_lcb0;
extern LogControlBlock iedModel_GenericIO_LLN0_lcb1;
LogControlBlock iedModel_GenericIO_LLN0_lcb0 = {&iedModel_GenericIO_LLN0, "EventLog", "Events", "EventLog", 19, 0, true, true, &iedModel_GenericIO_LLN0_lcb1};
LogControlBlock iedModel_GenericIO_LLN0_lcb1 = {&iedModel_GenericIO_LLN0, "GeneralLog", "", "", 19, 0, true, true, NULL};
LogControlBlock iedModel_GenericIO_LLN0_lcb0 = {&iedModel_GenericIO_LLN0, "EventLog", "Events", "GenericIO/LLN0$EventLog", 3, 0, true, true, &iedModel_GenericIO_LLN0_lcb1};
LogControlBlock iedModel_GenericIO_LLN0_lcb1 = {&iedModel_GenericIO_LLN0, "GeneralLog", NULL, NULL, 3, 0, true, true, NULL};
extern Log iedModel_GenericIO_LLN0_log0;
extern Log iedModel_GenericIO_LLN0_log1;

View file

@ -1779,6 +1779,8 @@ ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0,
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
@ -1787,6 +1789,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -3586,6 +3586,8 @@ ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "r
IedModel iedModel = {
"ied1",
&iedModel_Inverter,
@ -3594,6 +3596,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -4134,6 +4134,8 @@ DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs = {
IedModel iedModel = {
"WIND",
&iedModel_WTG,
@ -4142,6 +4144,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -544,6 +544,8 @@ DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency = {
IedModel iedModel = {
"test",
&iedModel_ComplexArray,
@ -552,6 +554,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -3874,6 +3874,8 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
@ -3882,6 +3884,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -1909,6 +1909,8 @@ GSEControlBlock iedModel_GenericIO_LLN0_gse1 = {&iedModel_GenericIO_LLN0, "gcbAn
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
@ -1917,6 +1919,8 @@ IedModel iedModel = {
&iedModel_GenericIO_LLN0_gse0,
NULL,
NULL,
NULL,
NULL,
initializeValues
};

View file

@ -0,0 +1,34 @@
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_SOURCES += $(LIBIEC_HOME)/third_party/sqlite/sqlite3.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
CFLAGS += -I$(LIBIEC_HOME)/third_party/sqlite
CFLAGS += -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DHAVE_USLEEP
LDLIBS += -lm
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)

View file

@ -0,0 +1,8 @@
BUILD THE EXAMPLE:
To build the logging example it is required to have sqlite present!
If you have sqlite installed on the system (including the header files) e.g. in an Ubuntu installation with the sqlite3 package installed, you can simply use the Makefile.
If you don't have sqlite installed you have to download the sqlite amalgamation package and install the files sqlite3.c, sqlite3.h in the libiec61850/third_party/sqlite folder and use the Makefile.sqliteStatic instead. This will build a version of the example with the sqlite code statically linked.

View file

@ -17,6 +17,8 @@
#include "logging_api.h"
LogStorage SqliteLogStorage_createInstance(const char*);
/* import IEC 61850 device model created from SCL-File */
extern IedModel iedModel;
@ -164,7 +166,7 @@ main(int argc, char** argv)
LogStorage_addEntryData(statusLog, entryID, "simpleIOGenerioIO/GPIO1$ST$SPCSO1$t", blob, blobSize, 0);
LogStorage_getEntries(statusLog, 0, Hal_getTimeInMs(), entryCallback, entryDataCallback, NULL);
LogStorage_getEntries(statusLog, 0, Hal_getTimeInMs(), entryCallback, (LogEntryDataCallback) entryDataCallback, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);

View file

@ -1108,6 +1108,8 @@ extern SettingGroupControlBlock iedModel_PROT_LLN0_sgcb;
SettingGroupControlBlock iedModel_PROT_LLN0_sgcb = {&iedModel_PROT_LLN0, 1, 5, 0, false, 0, 0, NULL};
IedModel iedModel = {
"DEMO",
&iedModel_PROT,
@ -1116,6 +1118,8 @@ IedModel iedModel = {
NULL,
NULL,
&iedModel_PROT_LLN0_sgcb,
NULL,
NULL,
initializeValues
};

View file

@ -1851,6 +1851,10 @@ ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0,
extern LogControlBlock iedModel_GenericIO_LLN0_lcb0;
LogControlBlock iedModel_GenericIO_LLN0_lcb0 = {&iedModel_GenericIO_LLN0, "EventLog", "Events", "GenericIO/LLN0$EventLog", 3, 0, true, true, NULL};
IedModel iedModel = {
"simpleIO",
@ -1860,6 +1864,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
&iedModel_GenericIO_LLN0_lcb0,
NULL,
initializeValues
};

View file

@ -76,6 +76,8 @@ set (lib_common_SRCS
./iec61850/server/mms_mapping/reporting.c
./iec61850/server/mms_mapping/mms_goose.c
./iec61850/server/mms_mapping/mms_sv.c
./iec61850/server/mms_mapping/logging.c
./logging/log_storage.c
)
set (lib_asn1c_SRCS

View file

@ -15,7 +15,7 @@
#include "platform_endian.h"
#define LIBIEC61850_VERSION "0.9.1"
#define LIBIEC61850_VERSION "0.9.2"
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"

View file

@ -31,6 +31,8 @@
#include "libiec61850_platform_includes.h"
#include <inttypes.h>
struct sClientReport
{
ReportCallbackFunction callback;
@ -405,7 +407,7 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value)
matchingReport->timestamp = MmsValue_getBinaryTimeAsUtcMs(timeStampValue);
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: report has timestamp %llu\n", matchingReport->timestamp);
printf("DEBUG_IED_CLIENT: report has timestamp %" PRIu64 "\n", matchingReport->timestamp);
}
inclusionIndex++;

View file

@ -1306,6 +1306,56 @@ addVariablesWithFc(char* fc, char* lnName, LinkedList variables, LinkedList lnDi
}
}
static LinkedList
getLogicalNodeDirectoryLogs(IedConnection self, IedClientError* error, const char* logicalDeviceName,
const char* logicalNodeName)
{
MmsConnection mmsCon = self->connection;
MmsError mmsError;
LinkedList journals = MmsConnection_getDomainJournals(mmsCon, &mmsError, logicalDeviceName);
if (mmsError != MMS_ERROR_NONE) {
*error = iedConnection_mapMmsErrorToIedError(mmsError);
return NULL;
}
LinkedList logs = LinkedList_create();
LinkedList journal = LinkedList_getNext(journals);
while (journal != NULL) {
char* journalName = (char*) LinkedList_getData(journal);
char* logName = strchr(journalName, '$');
if (logName != NULL) {
logName[0] = 0;
logName += 1;
if (strcmp(journalName, logicalNodeName) == 0) {
char* log = copyString(logName);
LinkedList_add(logs, (void*) log);
}
}
journal = LinkedList_getNext(journal);
}
LinkedList_destroy(journals);
return logs;
}
static LinkedList
getLogicalNodeDirectoryDataSets(IedConnection self, IedClientError* error, const char* logicalDeviceName,
const char* logicalNodeName)
{
MmsConnection mmsCon = self->connection;
}
LinkedList /*<char*>*/
IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
const char* logicalNodeReference, ACSIClass acsiClass)
@ -1317,12 +1367,6 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
return NULL;
}
if (self->logicalDevices == NULL)
IedConnection_getDeviceModelFromServer(self, error);
if (*error != IED_ERROR_OK)
return NULL;
char lnRefCopy[130];
strncpy(lnRefCopy, logicalNodeReference, 129);
@ -1341,6 +1385,16 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
char* logicalNodeName = ldSep + 1;
if (acsiClass == ACSI_CLASS_LOG) {
return getLogicalNodeDirectoryLogs(self, error, logicalDeviceName, logicalNodeName);
}
if (self->logicalDevices == NULL)
IedConnection_getDeviceModelFromServer(self, error);
if (*error != IED_ERROR_OK)
return NULL;
/* search for logical device */
LinkedList device = LinkedList_getNext(self->logicalDevices);

View file

@ -146,7 +146,7 @@ DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type
* \param parent the parent LN.
* \param rptId of the report. If NULL the default report ID (object reference) is used.
* \param isBuffered true for a buffered RCB - false for unbuffered RCB
* \param dataSetName name (object reference) of the default data set or NULL if no data
* \param dataSetName name (object reference) of the default data set or NULL if no data set
* is set by default
* \param confRef the configuration revision
* \param trgOps the trigger options supported by this RCB (bit set)
@ -160,6 +160,38 @@ ReportControlBlock*
ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bool isBuffered, char*
dataSetName, uint32_t confRef, uint8_t trgOps, uint8_t options, uint32_t bufTm, uint32_t intgPd);
/**
* \brief create a new log control block (LCB)
*
* Create a new log control block (LCB) and add it to the given logical node (LN).
*
* \param name name of the LCB relative to the parent LN
* \param parent the parent LN.
* \param dataSetName name (object reference) of the default data set or NULL if no data set
* is set by default
* \param logRef name (object reference) of the default log or NULL if no log is set by default
* \param trgOps the trigger options supported by this LCB (bit set)
* \param intgPd integrity period in milliseconds
* \param logEna if true the log will be enabled by default, false otherwise
* \param reasonCode if true the reasonCode will be included in the log (this is always true in MMS mapping)
*
* \return the new LCB instance
*/
LogControlBlock*
LogControlBlock_create(const char* name, LogicalNode* parent, char* dataSetName, char* logRef, uint8_t trgOps,
uint32_t intgPd, bool logEna, bool reasonCode);
/**
* \brief create a log (used by the IEC 61850 log service)
*
* \param name name of the LOG relative to the parent LN
* \param parent the parent LN
*
* \return the new LOG instance
*/
Log*
Log_create(const char* name, LogicalNode* parent);
/**
* \brief create a setting group control block (SGCB)
*

View file

@ -517,9 +517,6 @@ LogicalNode_hasUnbufferedReports(LogicalNode* node);
DataSet*
LogicalNode_getDataSet(LogicalNode* self, const char* dataSetName);
void
LogicalNode_setLogStorage(LogicalNode* self, const char* logName, LogStorage logStorage);
bool
DataObject_hasFCData(DataObject* dataObject, FunctionalConstraint fc);

View file

@ -42,6 +42,7 @@ struct sIedServer
MmsMapping* mmsMapping;
LinkedList clientConnections;
uint8_t writeAccessPolicies;
bool running;
};

View file

@ -48,6 +48,7 @@ typedef struct {
DataSet* dataSet;
char* dataSetRef;
bool isDynamicDataSet;
LogicalNode* logicalNode;
MmsDomain* domain;

View file

@ -404,6 +404,8 @@ IedServer_create(IedModel* iedModel)
self->model = iedModel;
// self->running = false; /* not required due to CALLOC */
self->mmsMapping = MmsMapping_create(iedModel);
self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping);
@ -445,6 +447,16 @@ IedServer_create(IedModel* iedModel)
void
IedServer_destroy(IedServer self)
{
/* Stop server if running */
if (self->running) {
#if (CONFIG_MMS_THREADLESS_STACK == 1)
IedServer_stopThreadless(self);
#else
IedServer_stop(self);
#endif
}
MmsServer_destroy(self->mmsServer);
IsoServer_destroy(self->isoServer);
@ -525,17 +537,22 @@ singleThreadedServerThread(void* parameter)
void
IedServer_start(IedServer self, int tcpPort)
{
if (self->running == false) {
#if (CONFIG_MMS_SINGLE_THREADED == 1)
MmsServer_startListeningThreadless(self->mmsServer, tcpPort);
MmsServer_startListeningThreadless(self->mmsServer, tcpPort);
Thread serverThread = Thread_create((ThreadExecutionFunction) singleThreadedServerThread, (void*) self, true);
Thread serverThread = Thread_create((ThreadExecutionFunction) singleThreadedServerThread, (void*) self, true);
Thread_start(serverThread);
Thread_start(serverThread);
#else
MmsServer_startListening(self->mmsServer, tcpPort);
MmsMapping_startEventWorkerThread(self->mmsMapping);
MmsServer_startListening(self->mmsServer, tcpPort);
MmsMapping_startEventWorkerThread(self->mmsMapping);
#endif
self->running = true;
}
}
#endif
@ -558,13 +575,17 @@ IedServer_getDataModel(IedServer self)
void
IedServer_stop(IedServer self)
{
MmsMapping_stopEventWorkerThread(self->mmsMapping);
if (self->running) {
self->running = false;
MmsMapping_stopEventWorkerThread(self->mmsMapping);
#if (CONFIG_MMS_SINGLE_THREADED == 1)
MmsServer_stopListeningThreadless(self->mmsServer);
MmsServer_stopListeningThreadless(self->mmsServer);
#else
MmsServer_stopListening(self->mmsServer);
MmsServer_stopListening(self->mmsServer);
#endif
}
}
#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */
@ -572,7 +593,10 @@ IedServer_stop(IedServer self)
void
IedServer_startThreadless(IedServer self, int tcpPort)
{
MmsServer_startListeningThreadless(self->mmsServer, tcpPort);
if (self->running == false) {
MmsServer_startListeningThreadless(self->mmsServer, tcpPort);
self->running = true;
}
}
int
@ -590,7 +614,11 @@ IedServer_processIncomingData(IedServer self)
void
IedServer_stopThreadless(IedServer self)
{
MmsServer_stopListeningThreadless(self->mmsServer);
if (self->running) {
self->running = false;
MmsServer_stopListeningThreadless(self->mmsServer);
}
}
void

View file

@ -35,6 +35,8 @@
#include "mms_mapping_internal.h"
#include "mms_value_internal.h"
#include "logging_api.h"
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
LogInstance*
@ -74,7 +76,7 @@ LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* valu
self->locked = true;
//if (DEBUG_IED_SERVER)
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Log value - dataRef: %s flag: %i\n", dataRef, flag);
uint64_t timestamp = Hal_getTimeInMs();
@ -83,7 +85,7 @@ LogInstance_logSingleData(LogInstance* self, const char* dataRef, MmsValue* valu
int dataSize = MmsValue_encodeMmsData(value, NULL, 0, false);
uint8_t* data = GLOBAL_MALLOC(dataSize);
uint8_t* data = (uint8_t*) GLOBAL_MALLOC(dataSize);
MmsValue_encodeMmsData(value, data, 0, true);
@ -137,7 +139,7 @@ LogInstance_logEntryData(LogInstance* self, uint64_t entryID, const char* dataRe
int dataSize = MmsValue_encodeMmsData(value, NULL, 0, false);
uint8_t* data = GLOBAL_MALLOC(dataSize);
uint8_t* data = (uint8_t*) GLOBAL_MALLOC(dataSize);
MmsValue_encodeMmsData(value, data, 0, true);
@ -171,6 +173,7 @@ LogControl_create(LogicalNode* parentLN, MmsMapping* mmsMapping)
self->enabled = false;
self->dataSet = NULL;
self->isDynamicDataSet = false;
self->triggerOps = 0;
self->logicalNode = parentLN;
self->mmsMapping = mmsMapping;
@ -207,16 +210,14 @@ static void
prepareLogControl(LogControl* logControl)
{
if (logControl->dataSetRef == NULL) {
printf(" no data set specified!\n");
logControl->enabled = false;
return;
}
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, logControl->dataSetRef);
if (dataSet == NULL) {
printf(" data set (%s) not found!\n", logControl->dataSetRef);
if (dataSet == NULL)
return;
}
else
logControl->dataSet = dataSet;
}
@ -322,7 +323,7 @@ getLogInstanceByLogRef(MmsMapping* self, const char* logRef)
while (instance != NULL) {
LogInstance* logInstance = LinkedList_getData(instance);
LogInstance* logInstance = (LogInstance*) LinkedList_getData(instance);
if (strcmp(logInstance->name, logName) == 0) {
@ -355,6 +356,18 @@ updateLogStatusInLCB(LogControl* self)
}
static void
freeDynamicDataSet(LogControl* self)
{
if (self->isDynamicDataSet) {
if (self->dataSet != NULL) {
MmsMapping_freeDynamicallyCreatedDataSet(self->dataSet);
self->isDynamicDataSet = false;
self->dataSet = NULL;
}
}
}
MmsDataAccessError
LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig,
MmsValue* value, MmsServerConnection connection)
@ -460,7 +473,6 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma
if (logControl->enabled == false) {
/* check if datSet is valid or NULL/empty */
const char* dataSetRef = MmsValue_toString(value);
if (strlen(dataSetRef) == 0) {
@ -470,16 +482,51 @@ LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* doma
else {
DataSet* dataSet = IedModel_lookupDataSet(logControl->mmsMapping->model, dataSetRef);
if (dataSet != NULL) {
freeDynamicDataSet(logControl);
logControl->dataSet = dataSet;
updateValue = true;
}
#if (MMS_DYNAMIC_DATA_SETS == 1)
if (dataSet == NULL) {
dataSet = MmsMapping_getDomainSpecificDataSet(self, dataSetRef);
if (dataSet == NULL) {
if (dataSetRef[0] == '/') { /* check for VMD specific data set */
MmsNamedVariableList mmsVariableList =
MmsDevice_getNamedVariableListWithName(self->mmsDevice, dataSetRef + 1);
if (mmsVariableList != NULL)
dataSet = MmsMapping_createDataSetByNamedVariableList(self, mmsVariableList);
}
}
if (dataSet != NULL) {
freeDynamicDataSet(logControl);
logControl->dataSet = dataSet;
logControl->isDynamicDataSet = true;
updateValue = true;
}
}
#endif /*(MMS_DYNAMIC_DATA_SETS == 1) */
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;
@ -589,7 +636,11 @@ createTrgOps(LogControlBlock* logControlBlock) {
return trgOps;
}
static void
LogControl_updateLogEna(LogControl* self)
{
MmsValue_setBoolean(MmsValue_getElement(self->mmsValue, 0), self->enabled);
}
static MmsVariableSpecification*
createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
@ -743,6 +794,8 @@ createLogControlBlock(MmsMapping* self, LogControlBlock* logControlBlock,
if (logControl->enabled)
enableLogging(logControl);
LogControl_updateLogEna(logControl);
return lcb;
}
@ -871,7 +924,7 @@ MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logSto
MmsJournal mmsJournal = NULL;
char* logName = strchr(logRef, '/');
const char* logName = strchr(logRef, '/');
if (logName != NULL) {
logName += 1;

View file

@ -2501,6 +2501,14 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li
}
}
}
else if (listType == MMS_VMD_SPECIFIC) {
if (rc->dataSet->logicalDeviceName == NULL) {
if (strcmp(rc->dataSet->name, listName) == 0) {
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
else if (listType == MMS_ASSOCIATION_SPECIFIC) {
if (rc->dataSet->logicalDeviceName == NULL) {
if (strcmp(rc->dataSet->name, listName) == 0) {
@ -2514,7 +2522,41 @@ variableListChangedHandler (void* parameter, bool create, MmsVariableListType li
}
}
//TODO check if data set is referenced in a log control block
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
/* check if data set is referenced in a log control block*/
LinkedList logElement = self->logControls;
while ((logElement = LinkedList_getNext(logElement)) != NULL) {
LogControl* lc = (LogControl*) logElement->data;
if (lc->isDynamicDataSet) {
if (lc->dataSet != NULL) {
if (listType == MMS_DOMAIN_SPECIFIC) {
if (lc->dataSet->logicalDeviceName != NULL) {
if (strcmp(lc->dataSet->name, listName) == 0) {
if (strcmp(lc->dataSet->logicalDeviceName, MmsDomain_getName(domain)) == 0) {
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
}
else if (listType == MMS_VMD_SPECIFIC) {
if (lc->dataSet->logicalDeviceName == NULL) {
if (strcmp(lc->dataSet->name, listName) == 0) {
allow = MMS_ERROR_SERVICE_OBJECT_CONSTRAINT_CONFLICT;
break;
}
}
}
}
}
}
#endif /* (CONFIG_IEC61850_LOG_SERVICE == 1) */
}
return allow;

View file

@ -58,6 +58,10 @@ IedModel_create(const char* name/*, MemoryAllocator allocator*/)
self->sgcbs = NULL;
self->lcbs = NULL;
self->logs = NULL;
self->initializer = iedModel_emptyVariableInitializer;
return self;
@ -97,6 +101,36 @@ IedModel_addLogicalDevice(IedModel* self, LogicalDevice* lDevice)
}
}
static void
IedModel_addLog(IedModel* self, Log* log)
{
if (self->logs == NULL)
self->logs = log;
else {
Log* lastLog = self->logs;
while (lastLog->sibling != NULL)
lastLog = lastLog->sibling;
lastLog->sibling = log;
}
}
static void
IedModel_addLogControlBlock(IedModel* self, LogControlBlock* lcb)
{
if (self->lcbs == NULL)
self->lcbs = lcb;
else {
LogControlBlock* lastLcb = self->lcbs;
while (lastLcb->sibling != NULL)
lastLcb = lastLcb->sibling;
lastLcb->sibling = lcb;
}
}
static void
IedModel_addReportControlBlock(IedModel* self, ReportControlBlock* rcb)
{
@ -231,6 +265,65 @@ LogicalNode_addDataObject(LogicalNode* self, DataObject* dataObject)
}
}
static void
LogicalNode_addLog(LogicalNode* self, Log* log)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addLog(model, log);
}
Log*
Log_create(const char* name, LogicalNode* parent)
{
Log* self = (Log*) GLOBAL_MALLOC(sizeof(Log));
self->name = copyString(name);
self->parent = parent;
self->sibling = NULL;
LogicalNode_addLog(parent, self);
return self;
}
static void
LogicalNode_addLogControlBlock(LogicalNode* self, LogControlBlock* lcb)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addLogControlBlock(model, lcb);
}
LogControlBlock*
LogControlBlock_create(const char* name, LogicalNode* parent, char* dataSetName, char* logRef, uint8_t trgOps,
uint32_t intPeriod, bool logEna, bool reasonCode)
{
LogControlBlock* self = (LogControlBlock*) GLOBAL_MALLOC(sizeof(LogControlBlock));
self->name = copyString(name);
self->parent = parent;
if (dataSetName)
self->dataSetName = copyString(dataSetName);
else
dataSetName = NULL;
if (logRef)
self->logRef = copyString(logRef);
else
logRef = NULL;
self->trgOps = trgOps;
self->intPeriod = intPeriod;
self->logEna = logEna;
self->reasonCode = reasonCode;
LogicalNode_addLogControlBlock(parent, self);
return self;
}
static void
LogicalNode_addReportControlBlock(LogicalNode* self, ReportControlBlock* rcb)
{
@ -743,6 +836,28 @@ IedModel_destroy(IedModel* model)
sgcb = nextSgcb;
}
/* delete all LCBs */
LogControlBlock* lcb = model->lcbs;
while (lcb != NULL) {
LogControlBlock* nextLcb = lcb->sibling;
GLOBAL_FREEMEM(lcb);
lcb = nextLcb;
}
/* delete all LOGs */
Log* log = model->logs;
while (log != NULL) {
Log* nextLog = log->sibling;
GLOBAL_FREEMEM(log);
log = nextLog;
}
/* delete generic model parts */

View file

@ -409,20 +409,6 @@ exit_error:
return NULL;
}
void
LogicalNode_setLogStorage(LogicalNode* self, const char* logName, LogStorage logStorage)
{
assert(self->modelType == LogicalNodeModelType);
assert(logName != NULL);
LogicalDevice* ld = (LogicalDevice*) self->parent;
IedModel* iedModel = (IedModel*) ld->parent;
}
int
LogicalDevice_getLogicalNodeCount(LogicalDevice* logicalDevice)
{

View file

@ -166,7 +166,8 @@ exit_with_error:
static uint64_t
SqliteLogStorage_addEntry(LogStorage self, uint64_t timestamp)
{
printf("SQLITE-DRIVER: add entry\n");
if (DEBUG_LOG_STORAGE_DRIVER)
printf("LOG_STORAGE_DRIVER: sqlite - add entry\n");
SqliteLogStorage* instanceData = (SqliteLogStorage*) (self->instanceData);
@ -269,8 +270,8 @@ getEntryData(LogStorage self, uint64_t entryID, LogEntryDataCallback entryDataCa
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);
const char* dataRef = (const char*) sqlite3_column_text(instanceData->getEntryData, 0);
uint8_t* data = (uint8_t*) sqlite3_column_blob(instanceData->getEntryData, 1);
int dataSize = sqlite3_column_bytes(instanceData->getEntryData, 1);
int reasonCode = sqlite3_column_int(instanceData->getEntryData, 2);
@ -317,7 +318,6 @@ SqliteLogStorage_getEntries(LogStorage self, uint64_t startingTime, uint64_t end
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);
@ -412,7 +412,6 @@ SqliteLogStorage_getEntriesAfter(LogStorage self, uint64_t startingTime, uint64_
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);

View file

@ -24,6 +24,10 @@
#ifndef LIBIEC61850_SRC_LOGGING_LOGGING_API_H_
#define LIBIEC61850_SRC_LOGGING_LOGGING_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
@ -37,7 +41,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, const uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow);
typedef bool (*LogEntryDataCallback) (void* parameter, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode, bool moreFollow);
struct sLogStorage {
@ -82,4 +86,8 @@ LogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry, uint64
void
LogStorage_destroy(LogStorage self);
#ifdef __cplusplus
}
#endif
#endif /* LIBIEC61850_SRC_LOGGING_LOGGING_API_H_ */

View file

@ -76,8 +76,6 @@ MmsDomain_getName(MmsDomain* self)
void
MmsDomain_addJournal(MmsDomain* self, const char* name)
{
printf("CREATE JOURNAL\n");
if (self->journals == NULL)
self->journals = LinkedList_create();
@ -96,8 +94,6 @@ MmsDomain_getJournal(MmsDomain* self, const char* name)
MmsJournal mmsJournal = (MmsJournal) LinkedList_getData(journal);
printf(" MMS journal: %s (%s)\n", mmsJournal->name, name);
if (strcmp(mmsJournal->name, name) == 0)
return mmsJournal;

View file

@ -538,6 +538,10 @@ mmsServer_handleGetNameListRequest(
if (nameList == NULL)
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
else {
#if (CONFIG_MMS_SORT_NAME_LIST == 1)
StringUtils_sortList(nameList);
#endif
createNameListResponse(connection, invokeId, nameList, response, continueAfterId);
LinkedList_destroyStatic(nameList);
}

View file

@ -68,7 +68,7 @@ entryCallback(void* parameter, uint64_t timestamp, uint64_t entryID, bool moreFo
JournalEncoder encoder = (JournalEncoder) parameter;
if (moreFollow) {
//printf("Encode entry ID:%" PRIu64 " timestamp:%" PRIu64 "\n", entryID, timestamp);
if (encoder->moreFollows) {
printf("entryCallback return false\n");
return false;
@ -128,7 +128,7 @@ entryDataCallback (void* parameter, const char* dataRef, uint8_t* data, int data
uint32_t totalLen = firstVariableLen + secondVariableLen;
if ((bufPos + totalLen) > encoder->maxSize) {
if ((int) (bufPos + totalLen) > encoder->maxSize) {
encoder->moreFollows = true;
encoder->bufPos = encoder->currentEntryBufPos; /* remove last entry */
return false;
@ -241,8 +241,6 @@ mmsServer_handleReadJournalRequest(
uint32_t invokeId,
ByteBuffer* response)
{
printf("READ-JOURNAL\n");
char domainId[65];
char logName[65];
uint8_t entryIdBuf[64]; /* maximum size of entry id is 64 bytes! */
@ -276,7 +274,6 @@ mmsServer_handleReadJournalRequest(
case 0xa0: /* journalName */
{
uint8_t objectIdTag = requestBuffer[bufPos++];
bufPos = BerDecoder_decodeLength(requestBuffer, &length, bufPos, maxBufPos);

20
src/version.rc.in Normal file
View file

@ -0,0 +1,20 @@
1 VERSIONINFO
FILEVERSION @LIB_VERSION_MAJOR@,@LIB_VERSION_MINOR@,@LIB_VERSION_PATCH@,0
PRODUCTVERSION @LIB_VERSION_MAJOR@,@LIB_VERSION_MINOR@,@LIB_VERSION_PATCH@,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "FileVersion", "@LIB_VERSION_MAJOR@.@LIB_VERSION_MINOR@.@LIB_VERSION_PATCH@.0"
VALUE "ProductVersion", "@LIB_VERSION_MAJOR@.@LIB_VERSION_MINOR@.@LIB_VERSION_PATCH@.0"
VALUE "ProductName", "libIEC61850"
VALUE "FileDescription", "libIEC61850 - open source library for IEC 61850"
VALUE "LegalCopyright", "Dual license : Commercial or GPLv3"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x400, 1252
END
END

View file

@ -528,4 +528,20 @@ EXPORTS
MmsValue_encodeMmsData
ControlObjectClient_setInterlockCheck
ControlObjectClient_setSynchroCheck
LogStorage_addEntry
LogStorage_addEntryData
LogStorage_getEntries
LogStorage_getEntriesAfter
LogStorage_getOldestAndNewestEntries
LogStorage_destroy
IedServer_setLogStorage
MmsJournalEntry_destroy
MmsJournalEntry_getEntryID
MmsJournalEntry_getOccurenceTime
MmsJournalEntry_getJournalVariables
MmsJournalVariable_getTag
MmsJournalVariable_getValue
MmsConnection_readJournalTimeRange
MmsConnection_readJournalStartAfter
LogControlBlock_create
Log_create

View file

@ -604,3 +604,20 @@ EXPORTS
IedServer_updateVisibleStringAttributeValue
ControlObjectClient_setInterlockCheck
ControlObjectClient_setSynchroCheck
LogStorage_addEntry
LogStorage_addEntryData
LogStorage_getEntries
LogStorage_getEntriesAfter
LogStorage_getOldestAndNewestEntries
LogStorage_destroy
IedServer_setLogStorage
MmsJournalEntry_destroy
MmsJournalEntry_getEntryID
MmsJournalEntry_getOccurenceTime
MmsJournalEntry_getJournalVariables
MmsJournalVariable_getTag
MmsJournalVariable_getValue
MmsConnection_readJournalTimeRange
MmsConnection_readJournalStartAfter
LogControlBlock_create
Log_create

View file

@ -0,0 +1,48 @@
# - Try to find the sqlite library
# Once done this will define
#
# SQLITE_FOUND - system has sqlite
# SQLITE_INCLUDE_DIRS - the sqlite include directory
# SQLITE_LIBRARIES - Link these to use sqlite
#
# Define SQLITE_MIN_VERSION for which version desired.
#
INCLUDE(FindPkgConfig)
IF(Sqlite_FIND_REQUIRED)
SET(_pkgconfig_REQUIRED "REQUIRED")
ELSE(Sqlite_FIND_REQUIRED)
SET(_pkgconfig_REQUIRED "")
ENDIF(Sqlite_FIND_REQUIRED)
IF(SQLITE_MIN_VERSION)
PKG_SEARCH_MODULE(SQLITE ${_pkgconfig_REQUIRED} sqlite>=${SQLITE_MIN_VERSION} sqlite${SQLITE_MIN_VERSION})
ELSE(SQLITE_MIN_VERSION)
PKG_SEARCH_MODULE(SQLITE ${_pkgconfig_REQUIRED} sqlite)
ENDIF(SQLITE_MIN_VERSION)
IF(NOT SQLITE_FOUND AND NOT PKG_CONFIG_FOUND)
FIND_PATH(SQLITE_INCLUDE_DIRS sqlite${SQLITE_MIN_VERSION}.h)
FIND_LIBRARY(SQLITE_LIBRARIES sqlite${SQLITE_MIN_VERSION})
# Report results
IF(SQLITE_LIBRARIES AND SQLITE_INCLUDE_DIRS)
SET(SQLITE_FOUND 1)
IF(NOT Sqlite_FIND_QUIETLY)
MESSAGE(STATUS "Found Sqlite: ${SQLITE_LIBRARIES}")
ENDIF(NOT Sqlite_FIND_QUIETLY)
ELSE(SQLITE_LIBRARIES AND SQLITE_INCLUDE_DIRS)
IF(Sqlite_FIND_REQUIRED)
MESSAGE(SEND_ERROR "Could not find Sqlite")
ELSE(Sqlite_FIND_REQUIRED)
IF(NOT Sqlite_FIND_QUIETLY)
MESSAGE(STATUS "Could not find Sqlite")
ENDIF(NOT Sqlite_FIND_QUIETLY)
ENDIF(Sqlite_FIND_REQUIRED)
ENDIF(SQLITE_LIBRARIES AND SQLITE_INCLUDE_DIRS)
ENDIF(NOT SQLITE_FOUND AND NOT PKG_CONFIG_FOUND)
# Hide advanced variables from CMake GUIs
MARK_AS_ADVANCED(SQLITE_LIBRARIES SQLITE_INCLUDE_DIRS)