- IEC 61850/MMS client: Add support for write variable for array element with component

- added lost README file for winpcap
pull/93/head
Michael Zillgith 7 years ago
parent 70c1cd691d
commit 56d7ee4f0b

@ -33,6 +33,7 @@
#define DEFAULT_CONNECTION_TIMEOUT 10000
#define DATA_SET_MAX_NAME_LENGTH 64 /* is 32 according to standard! */
#define OUTSTANDING_CALLS 12
typedef struct sICLogicalDevice
{
@ -489,6 +490,9 @@ createNewConnectionObject(TLSConfiguration tlsConfig)
self->stateMutex = Semaphore_create(1);
self->reportHandlerMutex = Semaphore_create(1);
self->outstandingCallsLock = Semaphore_create(1);
self->outstandingCalls = (IedConnectionOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sIedConnectionOutstandingCall));
self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
}
@ -633,8 +637,11 @@ IedConnection_destroy(IedConnection self)
if (self->enabledReports != NULL)
LinkedList_destroyDeep(self->enabledReports, (LinkedListValueDeleteFunction) ClientReport_destroy);
GLOBAL_FREEMEM(self->outstandingCalls);
LinkedList_destroyStatic(self->clientControls);
Semaphore_destroy(self->outstandingCallsLock);
Semaphore_destroy(self->stateMutex);
Semaphore_destroy(self->reportHandlerMutex);
@ -676,6 +683,161 @@ IedConnection_getVariableSpecification(IedConnection self, IedClientError* error
return varSpec;
}
static IedConnectionOutstandingCall
allocateOutstandingCall(IedConnection self)
{
Semaphore_wait(self->outstandingCallsLock);
IedConnectionOutstandingCall call = NULL;
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].used == false) {
self->outstandingCalls[i].used = true;
call = &(self->outstandingCalls[i]);
break;
}
}
Semaphore_post(self->outstandingCallsLock);
return call;
}
static void
releaseOutstandingCall(IedConnection self, IedConnectionOutstandingCall call)
{
Semaphore_wait(self->outstandingCallsLock);
call->used = false;
Semaphore_post(self->outstandingCallsLock);
}
static IedConnectionOutstandingCall
lookupOutstandingCall(IedConnection self, uint32_t invokeId)
{
Semaphore_wait(self->outstandingCallsLock);
IedConnectionOutstandingCall call = NULL;
int i = 0;
for (i = 0; i < OUTSTANDING_CALLS; i++) {
printf("%d: used: %d invokeId: %d\n", i, self->outstandingCalls[i].used, self->outstandingCalls[i].invokeId);
if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) {
call = &(self->outstandingCalls[i]);
break;
}
}
Semaphore_post(self->outstandingCallsLock);
return call;
}
static void
readObjectHandlerInternal(int invokeId, void* parameter, MmsError err, MmsValue* value)
{
printf("readObjectHandlerInternal %i\n", invokeId);
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_ReadObjectHandler handler = (IedConnection_ReadObjectHandler) call->callback;
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), value);
releaseOutstandingCall(self, call);
}
else {
// if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
uint32_t
IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const char* objRef, FunctionalConstraint fc,
IedConnection_ReadObjectHandler handler, void* parameter)
{
*error = IED_ERROR_OK;
char domainIdBuffer[65];
char itemIdBuffer[65];
char* domainId;
char* itemId;
domainId = MmsMapping_getMmsDomainFromObjectReference(objRef, domainIdBuffer);
itemId = MmsMapping_createMmsVariableNameFromObjectReference(objRef, fc, itemIdBuffer);
if ((domainId == NULL) || (itemId == NULL)) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
IedConnectionOutstandingCall call = allocateOutstandingCall(self);
if (call == NULL) {
*error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED;
return 0;
}
call->callback = handler;
call->callbackParameter = parameter;
MmsError err = MMS_ERROR_NONE;
/* check if item ID contains an array "(..)" */
char* brace = strchr(itemId, '(');
if (brace) {
char* secondBrace = strchr(brace, ')');
if (secondBrace) {
char* endPtr;
int index = (int) strtol(brace + 1, &endPtr, 10);
if (endPtr == secondBrace) {
char* component = NULL;
if (strlen(secondBrace + 1) > 1)
component = secondBrace + 2; /* skip "." after array element specifier */
*brace = 0;
call->invokeId = MmsConnection_readSingleArrayElementWithComponentAsync(self->connection, &err, domainId, itemId, index, component, readObjectHandlerInternal, self);
}
else
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
}
else
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
}
else
call->invokeId = MmsConnection_readVariableAsync(self->connection, &err, domainId, itemId, readObjectHandlerInternal, self);
if ((err != MMS_ERROR_NONE) || (*error != IED_ERROR_OK)) {
if (err != MMS_ERROR_NONE)
*error = iedConnection_mapMmsErrorToIedError(err);
releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId;
}
MmsValue*
IedConnection_readObject(IedConnection self, IedClientError* error, const char* objectReference,
FunctionalConstraint fc)
@ -949,7 +1111,35 @@ IedConnection_writeObject(IedConnection self, IedClientError* error, const char*
MmsError mmsError;
MmsConnection_writeVariable(self->connection, &mmsError, domainId, itemId, value);
/* check if item ID contains an array "(..)" */
char* brace = strchr(itemId, '(');
if (brace) {
char* secondBrace = strchr(brace, ')');
if (secondBrace) {
char* endPtr;
int index = (int) strtol(brace + 1, &endPtr, 10);
if (endPtr == secondBrace) {
char* component = NULL;
if (strlen(secondBrace + 1) > 1)
component = secondBrace + 2; /* skip "." after array element specifier */
*brace = 0;
MmsConnection_writeSingleArrayElementWithComponent(self->connection, &mmsError, domainId, itemId, index, component, value);
}
else
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
}
else
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
}
else
MmsConnection_writeVariable(self->connection, &mmsError, domainId, itemId, value);
*error = iedConnection_mapMmsErrorToIedError(mmsError);
}

@ -106,6 +106,9 @@ typedef enum {
/** Connection rejected by server */
IED_ERROR_CONNECTION_REJECTED = 5,
/** Cannot send request because outstanding call limit is reached */
IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED = 6,
/* client side errors */
/** API function has been called with an invalid argument */
@ -303,7 +306,8 @@ LastApplError
IedConnection_getLastApplError(IedConnection self);
typedef void (*IedConnectionClosedHandler) (void* parameter, IedConnection connection);
typedef void
(*IedConnectionClosedHandler) (void* parameter, IedConnection connection);
/**
* \brief Install a handler function that will be called when the connection is lost.
@ -316,6 +320,12 @@ void
IedConnection_installConnectionClosedHandler(IedConnection self, IedConnectionClosedHandler handler,
void* parameter);
typedef void
(*IedConnectionStateChangedHandler) (void* parameter, IedConnection connection, IedConnectionState newState);
void
IedConnection_installStateChangedHandler(IedConnection self, IedConnectionStateChangedHandler handler, void* parameter);
/**
* \brief get a handle to the underlying MmsConnection
*
@ -1209,6 +1219,13 @@ ClientReportControlBlock_getOwner(ClientReportControlBlock self);
MmsValue*
IedConnection_readObject(IedConnection self, IedClientError* error, const char* dataAttributeReference, FunctionalConstraint fc);
typedef void
(*IedConnection_ReadObjectHandler) (int invokeId, void* parameter, IedClientError err, MmsValue* value);
uint32_t
IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const char* objRef, FunctionalConstraint fc,
IedConnection_ReadObjectHandler handler, void* parameter);
/**
* \brief write a functional constrained data attribute (FCDA) or functional constrained data (FCD).
*

@ -30,6 +30,15 @@
#include "hal_thread.h"
typedef struct sIedConnectionOutstandingCall* IedConnectionOutstandingCall;
struct sIedConnectionOutstandingCall {
bool used;
uint32_t invokeId;
void* callback;
void* callbackParameter;
};
struct sIedConnection
{
MmsConnection connection;
@ -42,6 +51,9 @@ struct sIedConnection
Semaphore stateMutex;
Semaphore reportHandlerMutex;
Semaphore outstandingCallsLock;
IedConnectionOutstandingCall outstandingCalls;
IedConnectionClosedHandler connectionCloseHandler;
void* connectionClosedParameter;
uint32_t connectionTimeout;

@ -579,10 +579,35 @@ MmsConnection_writeVariableAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, MmsValue* value,
MmsConnection_WriteVariableHandler handler, void* parameter);
/**
* \brief Write a single array element with a component to an array type variable
*
* \param self MmsConnection instance to operate on
* \param mmsError user provided variable to store error code
* \param domainId the domain name of the variable to be written
* \param itemId name of the variable to be written
* \param arrayIndex the index of the array element.
* \param componentId the name of the component of the array element
* \param value value of the array element component to be written.
*
* \return when successful, the data access error value returned by the server
*/
MmsDataAccessError
MmsConnection_writeSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId,
uint32_t arrayIndex, const char* componentId, MmsValue* value);
uint32_t
MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId,
uint32_t arrayIndex, const char* componentId, MmsValue* value,
MmsConnection_WriteVariableHandler handler, void* parameter);
/**
* \brief Write a single array element or a sub array to an array type variable
*
* When a single array element is address the MmsValue object value has to be of the type
* When a single array element is addressed the MmsValue object value has to be of the type
* of the array elements. When multiple array elements have to be written (index range) the
* MmsValue object value has to be of type MMS_ARRAY containing "numberOfElements" elements.
*

@ -176,6 +176,18 @@ mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* writeBuffer);
MmsPdu_t*
mmsClient_createConfirmedRequestPdu(uint32_t invokeId);
AlternateAccess_t*
mmsClient_createAlternateAccess(uint32_t index, uint32_t elementCount);
void
mmsClient_deleteAlternateAccess(AlternateAccess_t* alternateAccess);
void
mmsClient_deleteAlternateAccessIndexComponent(AlternateAccess_t* alternateAccess);
AlternateAccess_t*
mmsClient_createAlternateAccessIndexComponent(uint32_t index, const char* componentName);
int
mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writeBuffer, const char* continueAfter);
@ -260,6 +272,12 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const
int startIndex, int elementCount,
MmsValue* value, ByteBuffer* writeBuffer);
int
mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t arrayIndex, const char* component,
MmsValue* value,
ByteBuffer* writeBuffer);
void
mmsClient_createDefineNamedVariableListRequest(uint32_t invokeId, ByteBuffer* writeBuffer,
const char* domainId, const char* listNameId, LinkedList /*<char*>*/ listOfVariables,

@ -1,7 +1,7 @@
/*
* mms_client_common.c
*
* Copyright 2013 Michael Zillgith
* Copyright 2013-2018 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -58,3 +58,154 @@ mmsClient_createConfirmedRequestPdu(uint32_t invokeId)
return mmsPdu;
}
AlternateAccess_t*
mmsClient_createAlternateAccess(uint32_t index, uint32_t elementCount)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
if (elementCount > 0) {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_indexRange;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex);
asn_long2INTEGER(asnIndex, index);
asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements);
asn_long2INTEGER(asnIndex, elementCount);
}
else {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
}
return alternateAccess;
}
void
mmsClient_deleteAlternateAccess(AlternateAccess_t* alternateAccess)
{
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf != NULL) {
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf = NULL;
}
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf != NULL) {
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf = NULL;
}
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf != NULL) {
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf = NULL;
}
if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) {
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess != NULL) {
mmsClient_deleteAlternateAccess(alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess);
}
}
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed);
GLOBAL_FREEMEM(alternateAccess->list.array[0]);
GLOBAL_FREEMEM(alternateAccess->list.array);
GLOBAL_FREEMEM(alternateAccess);
}
static AlternateAccess_t*
createAlternateAccessComponent(const char* componentName)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
const char* separator = strchr(componentName, '$');
if (separator) {
int size = separator - componentName;
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present =
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.buf =
(uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1);
}
else {
int size = strlen(componentName);
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_component;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.buf =
(uint8_t*) StringUtils_copyString(componentName);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.size = size;
}
return alternateAccess;
}
AlternateAccess_t*
mmsClient_createAlternateAccessIndexComponent(uint32_t index, const char* componentName)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
if (componentName) {
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present =
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(componentName);
}
else {
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
}
return alternateAccess;
}

@ -3953,6 +3953,67 @@ exit_function:
return invokeId;
}
MmsDataAccessError
MmsConnection_writeSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId,
uint32_t arrayIndex, const char* componentId, MmsValue* value)
{
struct writeVariableParameters parameter;
MmsError err = MMS_ERROR_NONE;
parameter.waitForResponse = Semaphore_create(1);
parameter.err = MMS_ERROR_NONE;
parameter.accessError = DATA_ACCESS_ERROR_SUCCESS;
Semaphore_wait(parameter.waitForResponse);
MmsConnection_writeSingleArrayElementWithComponentAsync(self, &err, domainId, itemId, arrayIndex, componentId, value, writeVariableHandler, &parameter);
if (err == MMS_ERROR_NONE) {
Semaphore_wait(parameter.waitForResponse);
err = parameter.err;
}
Semaphore_destroy(parameter.waitForResponse);
if (mmsError)
*mmsError = err;
return parameter.accessError;
}
uint32_t
MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId,
uint32_t arrayIndex, const char* componentId, MmsValue* value,
MmsConnection_WriteVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, arrayIndex,
componentId, value, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, NULL);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
struct writeMultipleVariablesParameter
{
Semaphore sem;

@ -421,127 +421,6 @@ mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char*
return rval.encoded;
}
static AlternateAccess_t*
createAlternateAccess(uint32_t index, uint32_t elementCount)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
if (elementCount > 0) {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_indexRange;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex);
asn_long2INTEGER(asnIndex, index);
asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements);
asn_long2INTEGER(asnIndex, elementCount);
}
else {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
}
return alternateAccess;
}
static AlternateAccess_t*
createAlternateAccessComponent(const char* componentName)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
const char* separator = strchr(componentName, '$');
if (separator) {
int size = separator - componentName;
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present =
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.buf =
(uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1);
}
else {
int size = strlen(componentName);
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_component;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.buf =
(uint8_t*) StringUtils_copyString(componentName);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.size = size;
}
return alternateAccess;
}
static AlternateAccess_t*
createAlternateAccessIndexComponent(uint32_t index, const char* componentName)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
if (componentName) {
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present =
AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(componentName);
}
else {
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
}
return alternateAccess;
}
static ListOfVariableSeq_t*
createVariableIdentifier(const char* domainId, const char* itemId)
{
@ -575,7 +454,7 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* d
readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier;
variableIdentifier->alternateAccess = createAlternateAccess(index, elementCount);
variableIdentifier->alternateAccess = mmsClient_createAlternateAccess(index, elementCount);
asn_enc_rval_t rval;
@ -594,7 +473,7 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* d
int
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t index, const char* component, ByteBuffer* writeBuffer)
uint32_t arrayIndex, const char* component, ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
ReadRequest_t* readRequest = createReadRequest(mmsPdu);
@ -610,7 +489,7 @@ mmsClient_createReadRequestAlternateAccessSingleIndexComponent(uint32_t invokeId
readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier;
variableIdentifier->alternateAccess = createAlternateAccessIndexComponent(index, component);
variableIdentifier->alternateAccess = mmsClient_createAlternateAccessIndexComponent(arrayIndex, component);
asn_enc_rval_t rval;

@ -197,74 +197,6 @@ exit_function:
return retVal;
}
//TODO remove redundant code (see mms_client_read.c)
static AlternateAccess_t*
createAlternateAccess(uint32_t index, uint32_t elementCount)
{
AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
if (elementCount > 0) {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_indexRange;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex);
asn_long2INTEGER(asnIndex, index);
asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements);
asn_long2INTEGER(asnIndex, elementCount);
}
else {
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present =
AlternateAccessSelection__selectAccess_PR_index;
INTEGER_t* asnIndex =
&(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index);
asn_long2INTEGER(asnIndex, index);
}
return alternateAccess;
}
static void
deleteAlternateAccess(AlternateAccess_t* alternateAccess)
{
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf != NULL) {
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf = NULL;
}
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf != NULL) {
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf = NULL;
}
if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf != NULL) {
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf);
alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf = NULL;
}
GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed);
GLOBAL_FREEMEM(alternateAccess->list.array[0]);
GLOBAL_FREEMEM(alternateAccess->list.array);
GLOBAL_FREEMEM(alternateAccess);
}
static ListOfVariableSeq_t*
createNewDomainVariableSpecification(const char* domainId, const char* itemId)
{
@ -556,7 +488,7 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const
(ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*));
ListOfVariableSeq_t* variableIdentifier = createNewDomainVariableSpecification(domainId, itemId);
variableIdentifier->alternateAccess = createAlternateAccess(startIndex, elementCount);
variableIdentifier->alternateAccess = mmsClient_createAlternateAccess(startIndex, elementCount);
request->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier;
/* Create list of typed data values */
@ -573,7 +505,7 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
/* Free ASN structure */
deleteAlternateAccess(variableIdentifier->alternateAccess);
mmsClient_deleteAlternateAccess(variableIdentifier->alternateAccess);
request->variableAccessSpecification.choice.listOfVariable.list.count = 0;
@ -582,6 +514,67 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const
request->variableAccessSpecification.choice.listOfVariable.list.array = 0;
request->listOfData.list.count = 0;
deleteDataElement(request->listOfData.list.array[0]);
GLOBAL_FREEMEM(request->listOfData.list.array);
request->listOfData.list.array = 0;
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
return rval.encoded;
}
int
mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t arrayIndex, const char* component,
MmsValue* value,
ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present =
ConfirmedServiceRequest_PR_write;
WriteRequest_t* request =
&(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.write);
/* Create list of variable specifications */
request->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable;
request->variableAccessSpecification.choice.listOfVariable.list.count = 1;
//request->variableAccessSpecification.choice.listOfVariable.list.size = 1;
request->variableAccessSpecification.choice.listOfVariable.list.array =
(ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*));
ListOfVariableSeq_t* variableIdentifier = createNewDomainVariableSpecification(domainId, itemId);
request->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier;
variableIdentifier->alternateAccess = mmsClient_createAlternateAccessIndexComponent(arrayIndex, component);
/* Create list of typed data values */
request->listOfData.list.count = 1;
request->listOfData.list.size = 1;
request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(1, sizeof(struct Data*));
request->listOfData.list.array[0] = mmsMsg_createBasicDataElement(value);
/* Encode complete ASN1 structure */
asn_enc_rval_t rval;
rval = der_encode(&asn_DEF_MmsPdu, mmsPdu,
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
/* Free ASN structure */
// mmsClient_deleteAlternateAccessIndexComponent(variableIdentifier->alternateAccess);
mmsClient_deleteAlternateAccess(variableIdentifier->alternateAccess);
request->variableAccessSpecification.choice.listOfVariable.list.count = 0;
GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[0]);
GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array);
request->variableAccessSpecification.choice.listOfVariable.list.array = 0;
request->listOfData.list.count = 0;
deleteDataElement(request->listOfData.list.array[0]);

@ -0,0 +1,2 @@
For GOOSE support add winpcap source and headers here. Rerun cmake to configure the build system for GOOSE support.
Loading…
Cancel
Save