|
|
|
@ -33,6 +33,8 @@
|
|
|
|
|
#include "ied_connection_private.h"
|
|
|
|
|
#include "mms_value_internal.h"
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_CONNECTION_TIMEOUT 10000
|
|
|
|
|
|
|
|
|
|
typedef struct sICLogicalDevice
|
|
|
|
|
{
|
|
|
|
|
char* name;
|
|
|
|
@ -107,7 +109,7 @@ iedConnection_mapDataAccessErrorToIedError(MmsDataAccessError mmsError)
|
|
|
|
|
static ICLogicalDevice*
|
|
|
|
|
ICLogicalDevice_create(char* name)
|
|
|
|
|
{
|
|
|
|
|
ICLogicalDevice* self = (ICLogicalDevice*) calloc(1, sizeof(struct sICLogicalDevice));
|
|
|
|
|
ICLogicalDevice* self = (ICLogicalDevice*) GLOBAL_CALLOC(1, sizeof(struct sICLogicalDevice));
|
|
|
|
|
|
|
|
|
|
self->name = copyString(name);
|
|
|
|
|
|
|
|
|
@ -129,7 +131,7 @@ ICLogicalDevice_setDataSetList(ICLogicalDevice* self, LinkedList dataSets)
|
|
|
|
|
static void
|
|
|
|
|
ICLogicalDevice_destroy(ICLogicalDevice* self)
|
|
|
|
|
{
|
|
|
|
|
free(self->name);
|
|
|
|
|
GLOBAL_FREEMEM(self->name);
|
|
|
|
|
|
|
|
|
|
if (self->variables != NULL)
|
|
|
|
|
LinkedList_destroy(self->variables);
|
|
|
|
@ -137,13 +139,13 @@ ICLogicalDevice_destroy(ICLogicalDevice* self)
|
|
|
|
|
if (self->dataSets != NULL)
|
|
|
|
|
LinkedList_destroy(self->dataSets);
|
|
|
|
|
|
|
|
|
|
free(self);
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ClientDataSet
|
|
|
|
|
ClientDataSet_create(char* dataSetReference)
|
|
|
|
|
ClientDataSet_create(const char* dataSetReference)
|
|
|
|
|
{
|
|
|
|
|
ClientDataSet self = (ClientDataSet) calloc(1, sizeof(struct sClientDataSet));
|
|
|
|
|
ClientDataSet self = (ClientDataSet) GLOBAL_CALLOC(1, sizeof(struct sClientDataSet));
|
|
|
|
|
|
|
|
|
|
self->dataSetReference = copyString(dataSetReference);
|
|
|
|
|
StringUtils_replace(self->dataSetReference, '.', '$');
|
|
|
|
@ -159,9 +161,9 @@ ClientDataSet_destroy(ClientDataSet self)
|
|
|
|
|
if (self->dataSetValues != NULL)
|
|
|
|
|
MmsValue_delete(self->dataSetValues);
|
|
|
|
|
|
|
|
|
|
free(self->dataSetReference);
|
|
|
|
|
GLOBAL_FREEMEM(self->dataSetReference);
|
|
|
|
|
|
|
|
|
|
free(self);
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
@ -315,31 +317,38 @@ doesReportMatchControlObject(char* domainName, char* itemName, char* objectRef)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handleLastApplErrorMessage(IedConnection self, MmsValue* value)
|
|
|
|
|
handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError)
|
|
|
|
|
{
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("DEBUG_IED_CLIENT: received LastApplError\n");
|
|
|
|
|
printf("IED_CLIENT: received LastApplError\n");
|
|
|
|
|
|
|
|
|
|
if ((MmsValue_getType(lastApplError) != MMS_STRUCTURE) || (MmsValue_getArraySize(lastApplError) != 5))
|
|
|
|
|
{
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("IED_CLIENT: LastApplError has wrong type!\n");
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MmsValue* lastApplError = value;
|
|
|
|
|
MmsValue* cntrlObj = MmsValue_getElement(lastApplError, 0);
|
|
|
|
|
MmsValue* error = MmsValue_getElement(lastApplError, 1);
|
|
|
|
|
//MmsValue* origin = MmsValue_getElement(lastApplError, 2);
|
|
|
|
|
MmsValue* ctlNum = MmsValue_getElement(lastApplError, 3);
|
|
|
|
|
MmsValue* addCause = MmsValue_getElement(lastApplError, 4);
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("DEBUG_IED_CLIENT: CntrlObj: %s\n", MmsValue_toString(cntrlObj));
|
|
|
|
|
printf("IED_CLIENT: CntrlObj: %s\n", MmsValue_toString(cntrlObj));
|
|
|
|
|
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("DEBUG_IED_CLIENT: ctlNum: %u\n", MmsValue_toUint32(ctlNum));
|
|
|
|
|
printf("IED_CLIENT: ctlNum: %u\n", MmsValue_toUint32(ctlNum));
|
|
|
|
|
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("DEBUG_IED_CLIENT: addCause: %i\n", MmsValue_toInt32(addCause));
|
|
|
|
|
printf("IED_CLIENT: addCause: %i\n", MmsValue_toInt32(addCause));
|
|
|
|
|
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("DEBUG_IED_CLIENT: error: %i\n", MmsValue_toInt32(error));
|
|
|
|
|
printf("IED_CLIENT: error: %i\n", MmsValue_toInt32(error));
|
|
|
|
|
|
|
|
|
|
self->lastApplError.ctlNum = MmsValue_toUint32(ctlNum);
|
|
|
|
|
self->lastApplError.addCause = MmsValue_toInt32(addCause);
|
|
|
|
|
self->lastApplError.addCause = (ControlAddCause) MmsValue_toInt32(addCause);
|
|
|
|
|
self->lastApplError.error = MmsValue_toInt32(error);
|
|
|
|
|
LinkedList control = LinkedList_getNext(self->clientControls);
|
|
|
|
|
while (control != NULL) {
|
|
|
|
@ -347,8 +356,9 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* value)
|
|
|
|
|
|
|
|
|
|
char* objectRef = ControlObjectClient_getObjectReference(object);
|
|
|
|
|
|
|
|
|
|
if (doesControlObjectMatch(objectRef, MmsValue_toString(cntrlObj)))
|
|
|
|
|
if (doesControlObjectMatch(objectRef, MmsValue_toString(cntrlObj))) {
|
|
|
|
|
ControlObjectClient_setLastApplError(object, self->lastApplError);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
control = LinkedList_getNext(control);
|
|
|
|
|
}
|
|
|
|
@ -366,7 +376,6 @@ informationReportHandler(void* parameter, char* domainName,
|
|
|
|
|
if (domainName == NULL) {
|
|
|
|
|
|
|
|
|
|
if (isVariableListName) {
|
|
|
|
|
|
|
|
|
|
private_IedConnection_handleReport(self, value);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
@ -402,7 +411,7 @@ informationReportHandler(void* parameter, char* domainName,
|
|
|
|
|
IedConnection
|
|
|
|
|
IedConnection_create()
|
|
|
|
|
{
|
|
|
|
|
IedConnection self = (IedConnection) calloc(1, sizeof(struct sIedConnection));
|
|
|
|
|
IedConnection self = (IedConnection) GLOBAL_CALLOC(1, sizeof(struct sIedConnection));
|
|
|
|
|
|
|
|
|
|
self->enabledReports = LinkedList_create();
|
|
|
|
|
self->logicalDevices = NULL;
|
|
|
|
@ -414,9 +423,17 @@ IedConnection_create()
|
|
|
|
|
|
|
|
|
|
self->stateMutex = Semaphore_create(1);
|
|
|
|
|
|
|
|
|
|
self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs)
|
|
|
|
|
{
|
|
|
|
|
self->connectionTimeout = timeoutInMs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IedConnectionState
|
|
|
|
|
IedConnection_getState(IedConnection self)
|
|
|
|
|
{
|
|
|
|
@ -469,15 +486,14 @@ IedConnection_connect(IedConnection self, IedClientError* error, char* hostname,
|
|
|
|
|
MmsConnection_setConnectionLostHandler(self->connection, connectionLostHandler, (void*) self);
|
|
|
|
|
MmsConnection_setInformationReportHandler(self->connection, informationReportHandler, self);
|
|
|
|
|
|
|
|
|
|
MmsConnection_setConnectTimeout(self->connection, self->connectionTimeout);
|
|
|
|
|
|
|
|
|
|
if (MmsConnection_connect(self->connection, &mmsError, hostname, tcpPort)) {
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
IedConnection_setState(self, IED_STATE_CONNECTED);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
else
|
|
|
|
|
*error = iedConnection_mapMmsErrorToIedError(mmsError);
|
|
|
|
|
MmsConnection_destroy(self->connection);
|
|
|
|
|
self->connection = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*error = IED_ERROR_ALREADY_CONNECTED;
|
|
|
|
@ -493,9 +509,6 @@ IedConnection_abort(IedConnection self, IedClientError* error)
|
|
|
|
|
|
|
|
|
|
MmsConnection_abort(self->connection, &mmsError);
|
|
|
|
|
|
|
|
|
|
MmsConnection_destroy(self->connection);
|
|
|
|
|
self->connection = NULL;
|
|
|
|
|
|
|
|
|
|
*error = iedConnection_mapMmsErrorToIedError(mmsError);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -520,13 +533,9 @@ void
|
|
|
|
|
IedConnection_close(IedConnection self)
|
|
|
|
|
{
|
|
|
|
|
if (IedConnection_getState(self) == IED_STATE_CONNECTED) {
|
|
|
|
|
MmsConnection_close(self->connection);
|
|
|
|
|
IedConnection_setState(self, IED_STATE_CLOSED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->connection != NULL) {
|
|
|
|
|
MmsConnection_destroy(self->connection);
|
|
|
|
|
self->connection = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
@ -534,6 +543,8 @@ IedConnection_destroy(IedConnection self)
|
|
|
|
|
{
|
|
|
|
|
IedConnection_close(self);
|
|
|
|
|
|
|
|
|
|
MmsConnection_destroy(self->connection);
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices != NULL)
|
|
|
|
|
LinkedList_destroyDeep(self->logicalDevices, (LinkedListValueDeleteFunction) ICLogicalDevice_destroy);
|
|
|
|
|
|
|
|
|
@ -544,11 +555,11 @@ IedConnection_destroy(IedConnection self)
|
|
|
|
|
|
|
|
|
|
Semaphore_destroy(self->stateMutex);
|
|
|
|
|
|
|
|
|
|
free(self);
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MmsVariableSpecification*
|
|
|
|
|
IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
char domainIdBuffer[65];
|
|
|
|
@ -582,11 +593,11 @@ IedConnection_getVariableSpecification(IedConnection self, IedClientError* error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MmsValue*
|
|
|
|
|
IedConnection_readObject(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_readObject(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
char domainIdBuffer[65];
|
|
|
|
|
char itemIdBuffer[129];
|
|
|
|
|
char itemIdBuffer[65];
|
|
|
|
|
MmsValue* value = NULL;
|
|
|
|
|
|
|
|
|
|
char* domainId;
|
|
|
|
@ -613,7 +624,7 @@ IedConnection_readObject(IedConnection self, IedClientError* error, char* object
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
IedConnection_readBooleanValue(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
IedConnection_readBooleanValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
@ -636,7 +647,7 @@ IedConnection_readBooleanValue(IedConnection self, IedClientError* error, char*
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
IedConnection_readFloatValue(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
IedConnection_readFloatValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
@ -659,7 +670,7 @@ IedConnection_readFloatValue(IedConnection self, IedClientError* error, char* ob
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char*
|
|
|
|
|
IedConnection_readStringValue(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
IedConnection_readStringValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
@ -682,7 +693,7 @@ IedConnection_readStringValue(IedConnection self, IedClientError* error, char* o
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t
|
|
|
|
|
IedConnection_readInt32Value(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
IedConnection_readInt32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
@ -705,7 +716,7 @@ IedConnection_readInt32Value(IedConnection self, IedClientError* error, char* ob
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
|
IedConnection_readUnsigned32Value(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
IedConnection_readUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
@ -728,18 +739,19 @@ IedConnection_readUnsigned32Value(IedConnection self, IedClientError* error, cha
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Timestamp*
|
|
|
|
|
IedConnection_readTimestampValue(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc,
|
|
|
|
|
IedConnection_readTimestampValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc,
|
|
|
|
|
Timestamp* timeStamp)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
|
Timestamp* retVal = timeStamp;
|
|
|
|
|
|
|
|
|
|
if (retVal == NULL)
|
|
|
|
|
retVal = (Timestamp*) malloc(sizeof(Timestamp));
|
|
|
|
|
|
|
|
|
|
if (value != NULL) {
|
|
|
|
|
if (MmsValue_getType(value) == MMS_UTC_TIME) {
|
|
|
|
|
|
|
|
|
|
if (retVal == NULL)
|
|
|
|
|
retVal = (Timestamp*) GLOBAL_MALLOC(sizeof(Timestamp));
|
|
|
|
|
|
|
|
|
|
memcpy(retVal->val, value->value.utcTime, 8);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
@ -757,33 +769,37 @@ IedConnection_readTimestampValue(IedConnection self, IedClientError* error, char
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Quality
|
|
|
|
|
IedConnection_readQualityValue(IedConnection self, IedClientError* error, char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
IedConnection_readQualityValue(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
MmsValue* value = IedConnection_readObject(self, error, objectReference, fc);
|
|
|
|
|
|
|
|
|
|
Quality quality = QUALITY_VALIDITY_GOOD;
|
|
|
|
|
|
|
|
|
|
if ((MmsValue_getType(value) == MMS_BIT_STRING) && (MmsValue_getBitStringSize(value) == 13)) {
|
|
|
|
|
quality = Quality_fromMmsValue(value);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR)
|
|
|
|
|
*error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value));
|
|
|
|
|
else
|
|
|
|
|
*error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED;
|
|
|
|
|
}
|
|
|
|
|
if (value != NULL) {
|
|
|
|
|
|
|
|
|
|
MmsValue_delete(value);
|
|
|
|
|
if ((MmsValue_getType(value) == MMS_BIT_STRING) && (MmsValue_getBitStringSize(value) == 13)) {
|
|
|
|
|
quality = Quality_fromMmsValue(value);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR)
|
|
|
|
|
*error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value));
|
|
|
|
|
else
|
|
|
|
|
*error = IED_ERROR_UNEXPECTED_VALUE_RECEIVED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MmsValue_delete(value);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return quality;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeObject(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeObject(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, MmsValue* value)
|
|
|
|
|
{
|
|
|
|
|
char domainIdBuffer[65];
|
|
|
|
|
char itemIdBuffer[129];
|
|
|
|
|
char itemIdBuffer[65];
|
|
|
|
|
|
|
|
|
|
char* domainId;
|
|
|
|
|
char* itemId;
|
|
|
|
@ -804,7 +820,7 @@ IedConnection_writeObject(IedConnection self, IedClientError* error, char* objec
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeBooleanValue(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeBooleanValue(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, bool value)
|
|
|
|
|
{
|
|
|
|
|
MmsValue mmsValue;
|
|
|
|
@ -816,7 +832,7 @@ IedConnection_writeBooleanValue(IedConnection self, IedClientError* error, char*
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeInt32Value(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeInt32Value(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, int32_t value)
|
|
|
|
|
{
|
|
|
|
|
uint8_t valueBuffer[4];
|
|
|
|
@ -838,7 +854,7 @@ IedConnection_writeInt32Value(IedConnection self, IedClientError* error, char* o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeUnsigned32Value(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, uint32_t value)
|
|
|
|
|
{
|
|
|
|
|
uint8_t valueBuffer[4];
|
|
|
|
@ -859,7 +875,7 @@ IedConnection_writeUnsigned32Value(IedConnection self, IedClientError* error, ch
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeFloatValue(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeFloatValue(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, float value)
|
|
|
|
|
{
|
|
|
|
|
MmsValue mmsValue;
|
|
|
|
@ -872,7 +888,7 @@ IedConnection_writeFloatValue(IedConnection self, IedClientError* error, char* o
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeOctetString(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeOctetString(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, uint8_t* value, int valueLength)
|
|
|
|
|
{
|
|
|
|
|
MmsValue mmsValue;
|
|
|
|
@ -885,7 +901,7 @@ IedConnection_writeOctetString(IedConnection self, IedClientError* error, char*
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_writeVisibleStringValue(IedConnection self, IedClientError* error, char* objectReference,
|
|
|
|
|
IedConnection_writeVisibleStringValue(IedConnection self, IedClientError* error, const char* objectReference,
|
|
|
|
|
FunctionalConstraint fc, char* value)
|
|
|
|
|
{
|
|
|
|
|
MmsValue mmsValue;
|
|
|
|
@ -1002,7 +1018,7 @@ mmsFileDirectoryHandler(void* parameter, char* filename, uint32_t size, uint64_t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList /*<FileDirectoryEntry>*/
|
|
|
|
|
IedConnection_getFileDirectory(IedConnection self, IedClientError* error, char* directoryName)
|
|
|
|
|
IedConnection_getFileDirectory(IedConnection self, IedClientError* error, const char* directoryName)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
@ -1058,7 +1074,7 @@ mmsFileReadHandler(void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t by
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
|
IedConnection_getFile(IedConnection self, IedClientError* error, char* fileName, IedClientGetFileHandler handler,
|
|
|
|
|
IedConnection_getFile(IedConnection self, IedClientError* error, const char* fileName, IedClientGetFileHandler handler,
|
|
|
|
|
void* handlerParameter)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
@ -1093,7 +1109,7 @@ IedConnection_getFile(IedConnection self, IedClientError* error, char* fileName,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (clientFileReadHandler.retVal == true) {
|
|
|
|
|
if (clientFileReadHandler.retVal == false) {
|
|
|
|
|
*error = IED_ERROR_UNKNOWN;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -1110,7 +1126,7 @@ IedConnection_getFile(IedConnection self, IedClientError* error, char* fileName,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_deleteFile(IedConnection self, IedClientError* error, char* fileName)
|
|
|
|
|
IedConnection_deleteFile(IedConnection self, IedClientError* error, const char* fileName)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
@ -1133,12 +1149,14 @@ IedConnection_getServerDirectory(IedConnection self, IedClientError* error, bool
|
|
|
|
|
|
|
|
|
|
LinkedList /*<char*>*/
|
|
|
|
|
IedConnection_getLogicalDeviceDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
char* logicalDeviceName)
|
|
|
|
|
const char* logicalDeviceName)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices == NULL)
|
|
|
|
|
IedConnection_getDeviceModelFromServer(self, error);
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices == NULL)
|
|
|
|
|
if (*error != IED_ERROR_OK)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
LinkedList logicalDevice = LinkedList_getNext(self->logicalDevices);
|
|
|
|
@ -1223,15 +1241,25 @@ addVariablesWithFc(char* fc, char* lnName, LinkedList variables, LinkedList lnDi
|
|
|
|
|
|
|
|
|
|
LinkedList /*<char*>*/
|
|
|
|
|
IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
char* logicalNodeReference, ACSIClass acsiClass)
|
|
|
|
|
const char* logicalNodeReference, ACSIClass acsiClass)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
|
if (strlen(logicalNodeReference) > 129) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices == NULL)
|
|
|
|
|
IedConnection_getDeviceModelFromServer(self, error);
|
|
|
|
|
|
|
|
|
|
char lnRefCopy[193];
|
|
|
|
|
if (*error != IED_ERROR_OK)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
char lnRefCopy[130];
|
|
|
|
|
|
|
|
|
|
strncpy(lnRefCopy, logicalNodeReference, 192);
|
|
|
|
|
lnRefCopy[192] = 0;
|
|
|
|
|
strncpy(lnRefCopy, logicalNodeReference, 129);
|
|
|
|
|
lnRefCopy[129] = 0;
|
|
|
|
|
|
|
|
|
|
char* ldSep = strchr(lnRefCopy, '/');
|
|
|
|
|
|
|
|
|
@ -1246,7 +1274,7 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
|
|
|
|
|
char* logicalNodeName = ldSep + 1;
|
|
|
|
|
|
|
|
|
|
// search for logical device
|
|
|
|
|
/* search for logical device */
|
|
|
|
|
|
|
|
|
|
LinkedList device = LinkedList_getNext(self->logicalDevices);
|
|
|
|
|
|
|
|
|
@ -1305,7 +1333,7 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
char* dataObjectName = copyString(fcEndPos + 1);
|
|
|
|
|
|
|
|
|
|
if (!addToStringSet(lnDirectory, dataObjectName))
|
|
|
|
|
free(dataObjectName);
|
|
|
|
|
GLOBAL_FREEMEM(dataObjectName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1318,6 +1346,21 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACSI_CLASS_SGCB:
|
|
|
|
|
{
|
|
|
|
|
LinkedList variable = LinkedList_getNext(ld->variables);
|
|
|
|
|
|
|
|
|
|
while (variable != NULL) {
|
|
|
|
|
char* variableName = (char*) variable->data;
|
|
|
|
|
|
|
|
|
|
if (strcmp(variableName, "LLN0$SP$SGCB") == 0)
|
|
|
|
|
LinkedList_add(lnDirectory, (void*) copyString("SGCB"));
|
|
|
|
|
|
|
|
|
|
variable = LinkedList_getNext(variable);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACSI_CLASS_BRCB:
|
|
|
|
|
addVariablesWithFc("BR", logicalNodeName, ld->variables, lnDirectory);
|
|
|
|
|
break;
|
|
|
|
@ -1360,7 +1403,8 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("ACSI class not yet supported!\n");
|
|
|
|
|
if (DEBUG_IED_CLIENT)
|
|
|
|
|
printf("IED_CLIENT: ACSI class not yet supported!\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1370,18 +1414,33 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
|
|
|
|
|
LinkedList /*<char*>*/
|
|
|
|
|
IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error,
|
|
|
|
|
char* logicalNodeReference)
|
|
|
|
|
const char* logicalNodeReference)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
|
if (strlen(logicalNodeReference) > 129) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices == NULL)
|
|
|
|
|
IedConnection_getDeviceModelFromServer(self, error);
|
|
|
|
|
|
|
|
|
|
char lnRefCopy[193];
|
|
|
|
|
if (*error != IED_ERROR_OK)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
char lnRefCopy[130];
|
|
|
|
|
|
|
|
|
|
strncpy(lnRefCopy, logicalNodeReference, 192);
|
|
|
|
|
lnRefCopy[192] = 0;
|
|
|
|
|
strncpy(lnRefCopy, logicalNodeReference, 129);
|
|
|
|
|
lnRefCopy[129] = 0;
|
|
|
|
|
|
|
|
|
|
char* ldSep = strchr(lnRefCopy, '/');
|
|
|
|
|
|
|
|
|
|
if (ldSep == NULL) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*ldSep = 0;
|
|
|
|
|
|
|
|
|
|
char* logicalDeviceName = lnRefCopy;
|
|
|
|
@ -1441,15 +1500,25 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error,
|
|
|
|
|
|
|
|
|
|
static LinkedList
|
|
|
|
|
getDataDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
char* dataReference, bool withFc)
|
|
|
|
|
const char* dataReference, bool withFc)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
|
if (strlen(dataReference) > 129) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices == NULL)
|
|
|
|
|
IedConnection_getDeviceModelFromServer(self, error);
|
|
|
|
|
|
|
|
|
|
char dataRefCopy[193];
|
|
|
|
|
if (*error != IED_ERROR_OK)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
char dataRefCopy[130];
|
|
|
|
|
|
|
|
|
|
strncpy(dataRefCopy, dataReference, 192);
|
|
|
|
|
dataRefCopy[192] = 0;
|
|
|
|
|
strncpy(dataRefCopy, dataReference, 129);
|
|
|
|
|
dataRefCopy[129] = 0;
|
|
|
|
|
|
|
|
|
|
char* ldSep = strchr(dataRefCopy, '/');
|
|
|
|
|
|
|
|
|
@ -1550,7 +1619,7 @@ getDataDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
if (withFc) {
|
|
|
|
|
int elementNameLen = strlen(subElementName);
|
|
|
|
|
|
|
|
|
|
elementName = (char*) malloc(elementNameLen + 5);
|
|
|
|
|
elementName = (char*) GLOBAL_MALLOC(elementNameLen + 5);
|
|
|
|
|
memcpy(elementName, subElementName, elementNameLen);
|
|
|
|
|
elementName[elementNameLen] = '[';
|
|
|
|
|
elementName[elementNameLen + 1] = *(fcPos + 1);
|
|
|
|
@ -1562,7 +1631,7 @@ getDataDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
elementName = copyString(subElementName);
|
|
|
|
|
|
|
|
|
|
if (!addToStringSet(dataDirectory, elementName))
|
|
|
|
|
free(elementName);
|
|
|
|
|
GLOBAL_FREEMEM(elementName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1580,38 +1649,211 @@ getDataDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList
|
|
|
|
|
IedConnection_getDataDirectory(IedConnection self, IedClientError* error,
|
|
|
|
|
char* dataReference)
|
|
|
|
|
IedConnection_getDataDirectory(IedConnection self, IedClientError* error, const char* dataReference)
|
|
|
|
|
{
|
|
|
|
|
return getDataDirectory(self, error, dataReference, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList
|
|
|
|
|
IedConnection_getDataDirectoryFC(IedConnection self, IedClientError* error,
|
|
|
|
|
char* dataReference)
|
|
|
|
|
IedConnection_getDataDirectoryFC(IedConnection self, IedClientError* error, const char* dataReference)
|
|
|
|
|
{
|
|
|
|
|
return getDataDirectory(self, error, dataReference, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static LinkedList
|
|
|
|
|
getDataDirectoryByFc(IedConnection self, IedClientError* error,
|
|
|
|
|
const char* dataReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
|
|
|
|
|
if (strlen(dataReference) > 129) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* fcString = FunctionalConstraint_toString(fc);
|
|
|
|
|
|
|
|
|
|
if (fcString == NULL) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->logicalDevices == NULL)
|
|
|
|
|
IedConnection_getDeviceModelFromServer(self, error);
|
|
|
|
|
|
|
|
|
|
if (*error != IED_ERROR_OK)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
char dataRefCopy[130];
|
|
|
|
|
|
|
|
|
|
strncpy(dataRefCopy, dataReference, 129);
|
|
|
|
|
dataRefCopy[129] = 0;
|
|
|
|
|
|
|
|
|
|
char* ldSep = strchr(dataRefCopy, '/');
|
|
|
|
|
|
|
|
|
|
*ldSep = 0;
|
|
|
|
|
|
|
|
|
|
char* logicalDeviceName = dataRefCopy;
|
|
|
|
|
|
|
|
|
|
char* logicalNodeName = ldSep + 1;
|
|
|
|
|
|
|
|
|
|
char* logicalNodeNameEnd = strchr(logicalNodeName, '.');
|
|
|
|
|
|
|
|
|
|
if (logicalNodeNameEnd == NULL) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int logicalNodeNameLen = logicalNodeNameEnd - logicalNodeName;
|
|
|
|
|
|
|
|
|
|
char* dataNamePart = logicalNodeNameEnd + 1;
|
|
|
|
|
|
|
|
|
|
int dataNamePartLen = strlen(dataNamePart);
|
|
|
|
|
|
|
|
|
|
if (dataNamePartLen < 1) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StringUtils_replace(dataNamePart, '.', '$');
|
|
|
|
|
|
|
|
|
|
// search for logical device
|
|
|
|
|
|
|
|
|
|
LinkedList device = LinkedList_getNext(self->logicalDevices);
|
|
|
|
|
|
|
|
|
|
bool deviceFound = false;
|
|
|
|
|
|
|
|
|
|
ICLogicalDevice* ld;
|
|
|
|
|
|
|
|
|
|
while (device != NULL) {
|
|
|
|
|
ld = (ICLogicalDevice*) device->data;
|
|
|
|
|
|
|
|
|
|
if (strcmp(logicalDeviceName, ld->name) == 0) {
|
|
|
|
|
deviceFound = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
device = LinkedList_getNext(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!deviceFound) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList variable = LinkedList_getNext(ld->variables);
|
|
|
|
|
|
|
|
|
|
LinkedList dataDirectory = LinkedList_create();
|
|
|
|
|
|
|
|
|
|
while (variable != NULL) {
|
|
|
|
|
char* variableName = (char*) variable->data;
|
|
|
|
|
|
|
|
|
|
char* fcPos = strchr(variableName, '$');
|
|
|
|
|
|
|
|
|
|
if (fcPos != NULL) {
|
|
|
|
|
int lnNameLen = fcPos - variableName;
|
|
|
|
|
|
|
|
|
|
if (logicalNodeNameLen == lnNameLen) {
|
|
|
|
|
|
|
|
|
|
if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) {
|
|
|
|
|
|
|
|
|
|
/* ok we are in the correct logical node */
|
|
|
|
|
|
|
|
|
|
/* skip FC */
|
|
|
|
|
char* fcEnd = strchr(fcPos + 1, '$');
|
|
|
|
|
|
|
|
|
|
if (fcEnd == NULL)
|
|
|
|
|
goto next_variable;
|
|
|
|
|
|
|
|
|
|
if ((fcPos[1] != fcString[0]) || (fcPos[2] != fcString[1]))
|
|
|
|
|
goto next_variable;
|
|
|
|
|
|
|
|
|
|
char* remainingPart = fcEnd + 1;
|
|
|
|
|
|
|
|
|
|
int remainingLen = strlen(remainingPart);
|
|
|
|
|
|
|
|
|
|
if (remainingLen <= dataNamePartLen)
|
|
|
|
|
goto next_variable;
|
|
|
|
|
|
|
|
|
|
if (remainingPart[dataNamePartLen] == '$') {
|
|
|
|
|
|
|
|
|
|
if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) {
|
|
|
|
|
|
|
|
|
|
char* subElementName = remainingPart + dataNamePartLen + 1;
|
|
|
|
|
|
|
|
|
|
char* subElementNameSep = strchr(subElementName, '$');
|
|
|
|
|
|
|
|
|
|
if (subElementNameSep != NULL)
|
|
|
|
|
goto next_variable;
|
|
|
|
|
|
|
|
|
|
int elementNameLen = strlen(subElementName);
|
|
|
|
|
|
|
|
|
|
char* elementName = (char*) GLOBAL_MALLOC(elementNameLen + 5);
|
|
|
|
|
memcpy(elementName, subElementName, elementNameLen);
|
|
|
|
|
elementName[elementNameLen] = '[';
|
|
|
|
|
elementName[elementNameLen + 1] = *(fcPos + 1);
|
|
|
|
|
elementName[elementNameLen + 2] = *(fcPos + 2);
|
|
|
|
|
elementName[elementNameLen + 3] = ']';
|
|
|
|
|
elementName[elementNameLen + 4] = 0;
|
|
|
|
|
|
|
|
|
|
if (!addToStringSet(dataDirectory, elementName))
|
|
|
|
|
GLOBAL_FREEMEM(elementName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_variable:
|
|
|
|
|
|
|
|
|
|
variable = LinkedList_getNext(variable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*error = IED_ERROR_OK;
|
|
|
|
|
return dataDirectory;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LinkedList
|
|
|
|
|
IedConnection_getDataDirectoryByFC(IedConnection self, IedClientError* error, const char* dataReference, FunctionalConstraint fc)
|
|
|
|
|
{
|
|
|
|
|
return getDataDirectoryByFc(self, error, dataReference, fc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_createDataSet(IedConnection self, IedClientError* error, char* dataSetReference,
|
|
|
|
|
IedConnection_createDataSet(IedConnection self, IedClientError* error, const char* dataSetReference,
|
|
|
|
|
LinkedList /* <char*> */dataSetElements)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
char domainIdBuffer[65];
|
|
|
|
|
char itemIdBuffer[129];
|
|
|
|
|
char itemIdBuffer[33]; /* maximum data set name = 32 chars */
|
|
|
|
|
|
|
|
|
|
char* domainId;
|
|
|
|
|
char* itemId;
|
|
|
|
|
const char* domainId;
|
|
|
|
|
const char* itemId;
|
|
|
|
|
bool isAssociationSpecific = false;
|
|
|
|
|
|
|
|
|
|
if (dataSetReference[0] != '@') {
|
|
|
|
|
domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer);
|
|
|
|
|
itemId = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer);
|
|
|
|
|
StringUtils_replace(itemId, '.', '$');
|
|
|
|
|
|
|
|
|
|
if (domainId == NULL) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int domainIdLength = strlen(domainId);
|
|
|
|
|
|
|
|
|
|
if ((strlen(dataSetReference) - domainIdLength - 1) > 32) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* itemIdRef = copyStringToBuffer(dataSetReference + domainIdLength + 1, itemIdBuffer);
|
|
|
|
|
StringUtils_replace(itemIdRef, '.', '$');
|
|
|
|
|
itemId = itemIdRef;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
itemId = dataSetReference;
|
|
|
|
|
itemId = dataSetReference + 1;
|
|
|
|
|
isAssociationSpecific = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1645,20 +1887,39 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, char* dat
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
IedConnection_deleteDataSet(IedConnection self, IedClientError* error, char* dataSetReference)
|
|
|
|
|
IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const char* dataSetReference)
|
|
|
|
|
{
|
|
|
|
|
char domainId[65];
|
|
|
|
|
char itemId[129];
|
|
|
|
|
char itemId[33];
|
|
|
|
|
bool isAssociationSpecific = false;
|
|
|
|
|
|
|
|
|
|
int dataSetReferenceLength = strlen(dataSetReference);
|
|
|
|
|
|
|
|
|
|
if (dataSetReference[0] != '@') {
|
|
|
|
|
MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainId);
|
|
|
|
|
copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemId);
|
|
|
|
|
if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainId) == NULL) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* itemIdString = dataSetReference + strlen(domainId) + 1;
|
|
|
|
|
|
|
|
|
|
if (strlen(itemIdString) > 32) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copyStringToBuffer(itemIdString, itemId);
|
|
|
|
|
|
|
|
|
|
StringUtils_replace(itemId, '.', '$');
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
strncpy(itemId, dataSetReference, 128);
|
|
|
|
|
itemId[128] = 0;
|
|
|
|
|
if (dataSetReferenceLength > 33) {
|
|
|
|
|
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcpy(itemId, dataSetReference + 1);
|
|
|
|
|
|
|
|
|
|
isAssociationSpecific = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1673,7 +1934,7 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, char* dat
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinkedList /* <char*> */
|
|
|
|
|
IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, char* dataSetReference, bool* isDeletable)
|
|
|
|
|
IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, const char* dataSetReference, bool* isDeletable)
|
|
|
|
|
{
|
|
|
|
|
bool deletable = false;
|
|
|
|
|
|
|
|
|
@ -1682,18 +1943,19 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, cha
|
|
|
|
|
char domainIdBuffer[65];
|
|
|
|
|
char itemIdBuffer[129];
|
|
|
|
|
|
|
|
|
|
char* domainId = NULL;
|
|
|
|
|
char* itemId = NULL;
|
|
|
|
|
const char* domainId = NULL;
|
|
|
|
|
const char* itemId = NULL;
|
|
|
|
|
|
|
|
|
|
bool isAssociationSpecific = false;
|
|
|
|
|
|
|
|
|
|
if (dataSetReference[0] != '@') {
|
|
|
|
|
domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer);
|
|
|
|
|
itemId = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer);
|
|
|
|
|
StringUtils_replace(itemId, '.', '$');
|
|
|
|
|
char* itemIdRef = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer);
|
|
|
|
|
StringUtils_replace(itemIdRef, '.', '$');
|
|
|
|
|
itemId = itemIdRef;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
itemId = dataSetReference;
|
|
|
|
|
itemId = dataSetReference + 1;
|
|
|
|
|
isAssociationSpecific = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1736,25 +1998,25 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, cha
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClientDataSet
|
|
|
|
|
IedConnection_readDataSetValues(IedConnection self, IedClientError* error, char* dataSetReference,
|
|
|
|
|
IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference,
|
|
|
|
|
ClientDataSet dataSet)
|
|
|
|
|
{
|
|
|
|
|
char domainIdBuffer[65];
|
|
|
|
|
char itemIdBuffer[129];
|
|
|
|
|
|
|
|
|
|
char* domainId = NULL;
|
|
|
|
|
char* itemId = NULL;
|
|
|
|
|
|
|
|
|
|
const char* domainId = NULL;
|
|
|
|
|
const char* itemId = NULL;
|
|
|
|
|
|
|
|
|
|
bool isAssociationSpecific = false;
|
|
|
|
|
|
|
|
|
|
if (dataSetReference[0] != '@') {
|
|
|
|
|
domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer);
|
|
|
|
|
itemId = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer);
|
|
|
|
|
StringUtils_replace(itemId, '.', '$');
|
|
|
|
|
char* itemIdRef = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer);
|
|
|
|
|
StringUtils_replace(itemIdRef, '.', '$');
|
|
|
|
|
itemId = itemIdRef;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
itemId = dataSetReference;
|
|
|
|
|
itemId = dataSetReference + 1;
|
|
|
|
|
isAssociationSpecific = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1815,9 +2077,9 @@ private_IedConnection_removeControlClient(IedConnection self, ControlObjectClien
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileDirectoryEntry
|
|
|
|
|
FileDirectoryEntry_create(char* fileName, uint32_t fileSize, uint64_t lastModified)
|
|
|
|
|
FileDirectoryEntry_create(const char* fileName, uint32_t fileSize, uint64_t lastModified)
|
|
|
|
|
{
|
|
|
|
|
FileDirectoryEntry self = (FileDirectoryEntry) calloc(1, sizeof(struct sFileDirectoryEntry));
|
|
|
|
|
FileDirectoryEntry self = (FileDirectoryEntry) GLOBAL_CALLOC(1, sizeof(struct sFileDirectoryEntry));
|
|
|
|
|
|
|
|
|
|
self->fileName = copyString(fileName);
|
|
|
|
|
self->fileSize = fileSize;
|
|
|
|
@ -1829,8 +2091,8 @@ FileDirectoryEntry_create(char* fileName, uint32_t fileSize, uint64_t lastModifi
|
|
|
|
|
void
|
|
|
|
|
FileDirectoryEntry_destroy(FileDirectoryEntry self)
|
|
|
|
|
{
|
|
|
|
|
free(self->fileName);
|
|
|
|
|
free(self);
|
|
|
|
|
GLOBAL_FREEMEM(self->fileName);
|
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char*
|