- IEC 61850 client: implemented IedConnection_writeDataSetValuesAsync

pull/93/head
Michael Zillgith 7 years ago
parent c04b4e928d
commit 1cc350ed4a

@ -3,7 +3,7 @@
* *
* Shows how to use the asynchronous client API * Shows how to use the asynchronous client API
* *
* This example is intended to be used with server_example_basic_io or server_example_goose. * This example is intended to be used with server_example_basic_io.
*/ */
#include "iec61850_client.h" #include "iec61850_client.h"
@ -16,56 +16,97 @@
static ClientDataSet clientDataSet = NULL; static ClientDataSet clientDataSet = NULL;
static void static void
readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet) printValue(char* name, MmsValue* value)
{
char buf[1000];
MmsValue_printToBuffer(value, buf, 1000);
printf("%s: %s\n", name, buf);
}
static void
readObjectHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value)
{ {
if (err == IED_ERROR_OK) { if (err == IED_ERROR_OK) {
clientDataSet = dataSet; printValue((char*) parameter, value);
printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet)); MmsValue_delete(value);
} }
else { else {
printf("Failed to read data set (err=%i)\n", err); printf("Failed to read object %s (err=%i)\n", (char*) parameter, err);
} }
} }
void static void
reportCallbackFunction(void* parameter, ClientReport report) readDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, ClientDataSet dataSet)
{ {
MmsValue* dataSetValues = ClientReport_getDataSetValues(report); if (err == IED_ERROR_OK) {
clientDataSet = dataSet;
printf("received report for %s\n", ClientReport_getRcbReference(report)); printf("Data set has %d entries\n", ClientDataSet_getDataSetSize(dataSet));
int i; MmsValue* values = ClientDataSet_getValues(dataSet);
for (i = 0; i < 4; i++) {
ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
if (reason != IEC61850_REASON_NOT_INCLUDED) { if (MmsValue_getType(values) == MMS_ARRAY) {
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i, int i;
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason); for (i = 0; i < MmsValue_getArraySize(values); i++) {
printf(" [%i]", i);
printValue("", MmsValue_getElement(values, i));
}
} }
} }
else {
printf("Failed to read data set (err=%i)\n", err);
}
} }
static void static void
printValue(char* name, MmsValue* value) writeDataSetHandler(uint32_t invokeId, void* parameter, IedClientError err, LinkedList /* <MmsValue*> */accessResults)
{ {
char buf[1000]; if (err == IED_ERROR_OK) {
MmsValue_printToBuffer(value, buf, 1000); if (accessResults) {
int i = 0;
LinkedList element = LinkedList_getNext(accessResults);
while (element) {
MmsValue* accessResultValue = LinkedList_getData(element);
printf(" access-result[%i]", i);
printValue("", accessResultValue);
element = LinkedList_getNext(element);
i++;
}
printf("Received value for %s: %s\n", name, buf); LinkedList_destroyDeep(accessResults, (LinkedListValueDeleteFunction) MmsValue_delete);
}
}
else {
printf("Failed to write data set (err=%i)\n", err);
}
} }
static void static void
readObjectHandler (uint32_t invokeId, void* parameter, IedClientError err, MmsValue* value) reportCallbackFunction(void* parameter, ClientReport report)
{ {
if (err == IED_ERROR_OK) { MmsValue* dataSetValues = ClientReport_getDataSetValues(report);
printValue((char*) parameter, value);
MmsValue_delete(value); printf("received report for %s\n", ClientReport_getRcbReference(report));
int i;
for (i = 0; i < 4; i++) {
ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
if (reason != IEC61850_REASON_NOT_INCLUDED) {
printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
} }
else {
printf("Failed to read object %s (err=%i)\n", (char*) parameter, err);
} }
} }
@ -204,6 +245,20 @@ int main(int argc, char** argv) {
if (error != IED_ERROR_OK) { if (error != IED_ERROR_OK) {
printf("read data set error %i\n", error); printf("read data set error %i\n", error);
} }
LinkedList values = LinkedList_create();
LinkedList_add(values, MmsValue_newBoolean(true));
LinkedList_add(values, MmsValue_newBoolean(false));
LinkedList_add(values, MmsValue_newBoolean(true));
LinkedList_add(values, MmsValue_newBoolean(false));
IedConnection_writeDataSetValuesAsync(con, &error, "simpleIOGenericIO/LLN0.Events", values, writeDataSetHandler, NULL);
if (error != IED_ERROR_OK) {
printf("write data set error %i\n", error);
}
LinkedList_destroyDeep(values, (LinkedListValueDeleteFunction) MmsValue_delete);
} }
Thread_sleep(1000); Thread_sleep(1000);

@ -3121,6 +3121,102 @@ exit_function:
return; return;
} }
static void
writeDataSetHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, LinkedList /* <MmsValue*> */ accessResults)
{
IedConnection self = (IedConnection) parameter;
IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId);
if (call) {
IedConnection_WriteDataSetHandler handler = (IedConnection_WriteDataSetHandler) call->callback;
handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), accessResults);
iedConnection_releaseOutstandingCall(self, call);
}
else {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: internal error - no matching outstanding call!\n");
}
}
LIB61850_API uint32_t
IedConnection_writeDataSetValuesAsync(IedConnection self, IedClientError* error, const char* dataSetReference,
LinkedList/*<MmsValue*>*/ values, IedConnection_WriteDataSetHandler handler, void* parameter)
{
char domainIdBuffer[65];
char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1];
const char* domainId = NULL;
const char* itemId = NULL;
bool isAssociationSpecific = false;
if (dataSetReference[0] != '@') {
if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) {
domainId = NULL;
if (dataSetReference[0] == '/')
itemId = dataSetReference + 1;
else
itemId = dataSetReference;
}
else {
domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer);
if (domainId == NULL) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1;
if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) {
*error = IED_ERROR_OBJECT_REFERENCE_INVALID;
return 0;
}
char* itemIdRef = StringUtils_copyStringToBuffer(itemIdRefOrig, itemIdBuffer);
StringUtils_replace(itemIdRef, '.', '$');
itemId = itemIdRef;
}
}
else {
itemId = dataSetReference + 1;
isAssociationSpecific = true;
}
IedConnectionOutstandingCall call = iedConnection_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;
call->invokeId = MmsConnection_writeNamedVariableListAsync(self->connection, &err, isAssociationSpecific, domainId, itemId, values, writeDataSetHandlerInternal, self);
if ((err != MMS_ERROR_NONE) || (*error != IED_ERROR_OK)) {
if (err != MMS_ERROR_NONE)
*error = iedConnection_mapMmsErrorToIedError(err);
iedConnection_releaseOutstandingCall(self, call);
return 0;
}
return call->invokeId;
}
LinkedList /* <MmsJournalEntry> */ LinkedList /* <MmsJournalEntry> */
IedConnection_queryLogByTime(IedConnection self, IedClientError* error, const char* logReference, IedConnection_queryLogByTime(IedConnection self, IedClientError* error, const char* logReference,
uint64_t startTime, uint64_t endTime, bool* moreFollows) uint64_t startTime, uint64_t endTime, bool* moreFollows)

@ -1585,11 +1585,11 @@ typedef void
* \param dataSetReference object reference of the data set * \param dataSetReference object reference of the data set
* \param dataSet a data set instance where to store the retrieved values or NULL if a new instance * \param dataSet a data set instance where to store the retrieved values or NULL if a new instance
* shall be created. * shall be created.
* \param handler the user provided callback handler * \param handler the user provided callback handler
* \param parameter user provided parameter that is passed to the callback handler * \param parameter user provided parameter that is passed to the callback handler
* *
* \return the invoke ID of the request * \return the invoke ID of the request
*/ */
LIB61850_API uint32_t LIB61850_API uint32_t
IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error, const char* dataSetReference, ClientDataSet dataSet, IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error, const char* dataSetReference, ClientDataSet dataSet,
IedConnection_ReadDataSetHandler handler, void* parameter); IedConnection_ReadDataSetHandler handler, void* parameter);
@ -1638,9 +1638,9 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha
* this object references is LDName/LNodeName.item(arrayIndex)component[FC]. * this object references is LDName/LNodeName.item(arrayIndex)component[FC].
* *
* \param connection the connection object * \param connection the connection object
* \param error the error code if an error occurs * \param[out] error the error code if an error occurs
* \param dataSetReference object reference of the data set * \param dataSetReference object reference of the data set
* \param isDeletable this is an output parameter indicating that the requested data set is deletable by clients. * \param[out] isDeletable this is an output parameter indicating that the requested data set is deletable by clients.
* If this information is not required a NULL pointer can be used. * If this information is not required a NULL pointer can be used.
* *
* \return LinkedList containing the data set elements as char* strings. * \return LinkedList containing the data set elements as char* strings.
@ -1658,15 +1658,51 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con
* contains a value for each data set member. * contains a value for each data set member.
* *
* \param connection the connection object * \param connection the connection object
* \param error the error code if an error occurs * \param[out] error the error code if an error occurs
* \param dataSetReference object reference of the data set * \param dataSetReference object reference of the data set
* \param values the new data set values * \param values the new data set values
* \param accessResults the access results for each data set member * \param[out] accessResults the access results for each data set member
*/ */
LIB61850_API void LIB61850_API void
IedConnection_writeDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference, IedConnection_writeDataSetValues(IedConnection self, IedClientError* error, const char* dataSetReference,
LinkedList/*<MmsValue*>*/ values, /* OUTPUT */LinkedList* /* <MmsValue*> */accessResults); LinkedList/*<MmsValue*>*/ values, /* OUTPUT */LinkedList* /* <MmsValue*> */accessResults);
/**
* \brief Callback handler for asynchronous write data set values services (set data set)
*
* \param invokeId the invoke ID of the service request
* \param parameter used provided parameter
* \param err the error code if an error occurs
* \param accessResults the list of access results for the data set entries.
*/
typedef void
(*IedConnection_WriteDataSetHandler) (uint32_t invokeId, void* parameter, IedClientError err, LinkedList /* <MmsValue*> */accessResults);
/**
* \brief Write the data set values to the server - async version
*
* The parameter dataSetReference is the name of the data set to write. It is either in the form LDName/LNodeName.dataSetName
* for permanent domain or VMD scope data sets or @dataSetName for an association specific data set.
* If the LDName part of the reference is missing the resulting data set will be of VMD scope.
* The values parameter has to be the same number of elements as are members in the data set.
*
* When the service call had been successful the \ref IedConnection_WriteDataSetHandler is called with an error value of
* IED_ERROR_OK and a list of MmsValue instances of type data access error. These describe the access results of the individual
* data set entries.
*
* \param connection the connection object
* \param[out] error the error code if an error occurs
* \param dataSetReference object reference of the data set
* \param values the new data set values
* \param handler the user provided callback handler
* \param parameter user provided parameter that is passed to the callback handler
*
* \return the invoke ID of the request
*/
LIB61850_API uint32_t
IedConnection_writeDataSetValuesAsync(IedConnection self, IedClientError* error, const char* dataSetReference,
LinkedList/*<MmsValue*>*/ values, IedConnection_WriteDataSetHandler handler, void* parameter);
/******************************************************** /********************************************************
* Data set object (local representation of a data set) * Data set object (local representation of a data set)

Loading…
Cancel
Save