- IEC 61850 client: add support for single array element access (with component specification)

pull/72/head
Michael Zillgith 7 years ago
parent eef34cf40e
commit 8b957b8f82

@ -694,6 +694,34 @@ IedConnection_readObject(IedConnection self, IedClientError* error, const char*
MmsError mmsError;
/* 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;
value = MmsConnection_readSingleArrayElementWithComponent(self->connection, &mmsError, domainId, itemId, index, component);
}
else
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
}
else
*error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT;
}
else
value = MmsConnection_readVariable(self->connection, &mmsError, domainId, itemId);
if (value != NULL)

@ -374,7 +374,7 @@ MmsValue*
MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId);
/**
* \brief Read an element of a single array variable from the server.
* \brief Read one or more elements of a single array variable from the server.
*
* \param self MmsConnection instance to operate on
* \param mmsError user provided variable to store error code
@ -391,6 +391,23 @@ MmsValue*
MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
uint32_t startIndex, uint32_t numberOfElements);
/**
* \brief Read a single element (with optional component specification) from the server
*
* \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 read
* \param itemId name of the variable to be read
* \param index array element index
* \param componentId array element component name
*
* \return Returns a MmsValue object or NULL if the request failed.
*/
MmsValue*
MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, uint32_t index, const char* componentId);
/**
* \brief Read multiple variables of a domain from the server with one request message.
*

@ -164,6 +164,10 @@ int
mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t index, uint32_t elementCount, ByteBuffer* writeBuffer);
int
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t index, const char* component, ByteBuffer* writeBuffer);
int
mmsClient_createReadRequestMultipleValues(uint32_t invokeId, const char* domainId, LinkedList /*<char*>*/ items,
ByteBuffer* writeBuffer);

@ -1619,6 +1619,35 @@ MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError,
return value;
}
MmsValue*
MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, uint32_t index, const char* componentId)
{
MmsValue* value = NULL;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
uint32_t invokeId = getNextInvokeId(self);
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, index, componentId,
payload);
ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload, mmsError);
if (responseMessage != NULL)
value = mmsClient_parseReadResponse(self->lastResponse, NULL, false);
releaseResponse(self);
exit_function:
return value;
}
MmsValue*
MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
const char* domainId, LinkedList /*<char*>*/items)

@ -461,6 +461,85 @@ createAlternateAccess(uint32_t index, uint32_t elementCount)
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));
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*) strndup(componentName, size);
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*) strndup(componentName, size);
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)
{
@ -511,6 +590,41 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* d
return rval.encoded;
}
int
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t index, const char* component, ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
ReadRequest_t* readRequest = createReadRequest(mmsPdu);
readRequest->specificationWithResult = NULL;
readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable;
readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*));
readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1;
ListOfVariableSeq_t* variableIdentifier = createVariableIdentifier(domainId, itemId);
readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier;
variableIdentifier->alternateAccess = createAlternateAccessIndexComponent(index, component);
asn_enc_rval_t rval;
rval = der_encode(&asn_DEF_MmsPdu, mmsPdu,
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
variableIdentifier->variableSpecification.choice.name.choice.domainspecific.domainId.buf = 0;
variableIdentifier->variableSpecification.choice.name.choice.domainspecific.domainId.size = 0;
variableIdentifier->variableSpecification.choice.name.choice.domainspecific.itemId.buf = 0;
variableIdentifier->variableSpecification.choice.name.choice.domainspecific.itemId.size = 0;
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
return rval.encoded;
}
static ListOfVariableSeq_t**
createListOfVariables(ReadRequest_t* readRequest, int valuesCount)
{

Loading…
Cancel
Save