- MMS client: added asynchronous read and write functions

pull/93/head
Michael Zillgith 7 years ago
parent 026357b5eb
commit 80ce9c8967

@ -373,6 +373,24 @@ MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsErr
MmsValue* MmsValue*
MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId); MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId);
typedef void
(*MmsConnection_ReadVariableHandler) (int invokeId, void* parameter, MmsError mmsError, MmsValue* value);
/**
* \brief Read a single variable from the server (asynchronous version)
*
* \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 or NULL to read a VMD specific named variable
* \param itemId name of the variable to be read
*
* \return invoke ID of the request when the request was sent successfully
*/
uint32_t
MmsConnection_readVariableAsync(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
MmsConnection_ReadVariableHandler handler, void* parameter);
/** /**
* \brief Read one or more elements of a single array variable from the server. * \brief Read one or more elements of a single array variable from the server.
* *
@ -391,6 +409,26 @@ MmsValue*
MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId, MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
uint32_t startIndex, uint32_t numberOfElements); uint32_t startIndex, uint32_t numberOfElements);
/**
* \brief Read one or more elements of a single array variable from the server (asynchronous version)
*
* NOTE: The MmsValue object received by the callback function is either a simple or complex type if numberOfElements is 0, or an array
* containing the selected array elements of numberOfElements > 0.
*
* \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 startIndex index of element to read or start index if a element range is to be read
* \param numberOfElements Number of elements to read or 0 if a single element is to be read
*
* \return invoke ID of the request when the request was sent successfully
*/
uint32_t
MmsConnection_readArrayElementsAsync(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
uint32_t startIndex, uint32_t numberOfElements,
MmsConnection_ReadVariableHandler handler, void* parameter);
/** /**
* \brief Read a single element (with optional component specification) from the server * \brief Read a single element (with optional component specification) from the server
@ -408,6 +446,12 @@ MmsValue*
MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError, MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, uint32_t index, const char* componentId); const char* domainId, const char* itemId, uint32_t index, const char* componentId);
uint32_t
MmsConnection_readSingleArrayElementWithComponentAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId,
uint32_t index, const char* componentId,
MmsConnection_ReadVariableHandler handler, void* parameter);
/** /**
* \brief Read multiple variables of a domain from the server with one request message. * \brief Read multiple variables of a domain from the server with one request message.
* *
@ -424,6 +468,11 @@ MmsValue*
MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId, MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId,
LinkedList /*<char*>*/ items); LinkedList /*<char*>*/ items);
uint32_t
MmsConnection_readMultipleVariablesAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, LinkedList /*<char*>*/items,
MmsConnection_ReadVariableHandler handler, void* parameter);
/** /**
* \brief Write a single variable to the server. * \brief Write a single variable to the server.
* *
@ -441,6 +490,14 @@ MmsDataAccessError
MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError, MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, MmsValue* value); const char* domainId, const char* itemId, MmsValue* value);
typedef void
(*MmsConnection_WriteVariableHandler) (int invokeId, void* parameter, MmsError mmsError, MmsDataAccessError accessError);
uint32_t
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 or a sub array to an array type variable * \brief Write a single array element or a sub array to an array type variable
* *
@ -464,6 +521,17 @@ MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, int index, int numberOfElements, const char* domainId, const char* itemId, int index, int numberOfElements,
MmsValue* value); MmsValue* value);
uint32_t
MmsConnection_writeArrayElementsAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, int index, int numberOfElements,
MmsValue* value,
MmsConnection_WriteVariableHandler handler, void* parameter);
typedef void
(*MmsConnection_WriteMultipleVariablesHandler) (int invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsValue*> */ accessResults);
/** /**
* \brief Write multiple variables to the server. * \brief Write multiple variables to the server.
* *
@ -473,12 +541,12 @@ MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError,
* object that contains the AccessResults of the single variable write attempts. It is up to the user to free this * object that contains the AccessResults of the single variable write attempts. It is up to the user to free this
* objects properly (e.g. with LinkedList_destroyDeep(accessResults, MmsValue_delete)). * objects properly (e.g. with LinkedList_destroyDeep(accessResults, MmsValue_delete)).
* *
* \param self MmsConnection instance to operate on * \param[in] self MmsConnection instance to operate on
* \param mmsError user provided variable to store error code * \param[out] mmsError user provided variable to store error code
* \param domainId the common domain name of all variables to be written * \param[in] domainId the common domain name of all variables to be written
* \param items a linked list containing the names of the variables to be written. The names are C strings. * \param[in] items a linked list containing the names of the variables to be written. The names are C strings.
* \param values values of the variables to be written * \param[out] values values of the variables to be written
* \param (OUTPUT) the MmsValue objects of type MMS_DATA_ACCESS_ERROR representing the write success of a single variable * \param[out] the MmsValue objects of type MMS_DATA_ACCESS_ERROR representing the write success of a single variable
* write. * write.
*/ */
void void
@ -486,6 +554,11 @@ MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, con
LinkedList /*<char*>*/ items, LinkedList /* <MmsValue*> */ values, LinkedList /*<char*>*/ items, LinkedList /* <MmsValue*> */ values,
LinkedList* /* <MmsValue*> */ accessResults); LinkedList* /* <MmsValue*> */ accessResults);
uint32_t
MmsConnection_writeMultipleVariablesAsync(MmsConnection self, MmsError* mmsError, const char* domainId,
LinkedList /*<char*>*/ items, LinkedList /* <MmsValue*> */ values,
MmsConnection_WriteMultipleVariablesHandler handler, void* parameter);
/** /**
* \brief Write named variable list values to the server. * \brief Write named variable list values to the server.
* *
@ -494,18 +567,24 @@ MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, con
* the user to free this objects properly (e.g. with LinkedList_destroyDeep(accessResults, MmsValue_delete)). * the user to free this objects properly (e.g. with LinkedList_destroyDeep(accessResults, MmsValue_delete)).
* If accessResult is the to NULL the result will not be stored. * If accessResult is the to NULL the result will not be stored.
* *
* \param self MmsConnection instance to operate on * \param[in] self MmsConnection instance to operate on
* \param mmsError user provided variable to store error code * \param[out] mmsError user provided variable to store error code
* \param isAssociationSpecifc true if the named variable list is an association specific named variable list * \param[in] isAssociationSpecifc true if the named variable list is an association specific named variable list
* \param domainId the common domain name of all variables to be written * \param[in] domainId the common domain name of all variables to be written
* \param values values of the variables to be written * \param[out] values values of the variables to be written
* \param (OUTPUT) the MmsValue objects of type MMS_DATA_ACCESS_ERROR representing the write success of a single variable * \param[out] the MmsValue objects of type MMS_DATA_ACCESS_ERROR representing the write success of a single variable
* write. * write.
*/ */
void void
MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific, MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific,
const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values, const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values,
/* OUTPUT */LinkedList* /* <MmsValue*> */accessResults); LinkedList* /* <MmsValue*> */accessResults);
uint32_t
MmsConnection_writeNamedVariableListAsync(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific,
const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values,
MmsConnection_WriteMultipleVariablesHandler handler, void* parameter);
/** /**
* \brief Get the variable access attributes of a MMS named variable of the server * \brief Get the variable access attributes of a MMS named variable of the server
@ -539,7 +618,12 @@ MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError
*/ */
MmsValue* MmsValue*
MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError, const char* domainId, MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError, const char* domainId,
const char* listName, bool specWithResult); const char* listName, bool specWithResult);
uint32_t
MmsConnection_readNamedVariableListValuesAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* listName, bool specWithResult,
MmsConnection_ReadVariableHandler handler, void* parameter);
/** /**
@ -556,7 +640,12 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError
*/ */
MmsValue* MmsValue*
MmsConnection_readNamedVariableListValuesAssociationSpecific(MmsConnection self, MmsError* mmsError, MmsConnection_readNamedVariableListValuesAssociationSpecific(MmsConnection self, MmsError* mmsError,
const char* listName, bool specWithResult); const char* listName, bool specWithResult);
uint32_t
MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(MmsConnection self, MmsError* mmsError,
const char* listName, bool specWithResult,
MmsConnection_ReadVariableHandler handler, void* parameter);
/** /**
* \brief Define a new VMD or domain scoped named variable list at the server. * \brief Define a new VMD or domain scoped named variable list at the server.

@ -5,7 +5,7 @@
* protocol stack. It is used as an abstraction layer to isolate the MMS code from the lower * protocol stack. It is used as an abstraction layer to isolate the MMS code from the lower
* protocol layers. * protocol layers.
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2018 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -40,7 +40,8 @@ typedef enum
ISO_IND_ASSOCIATION_SUCCESS, ISO_IND_ASSOCIATION_SUCCESS,
ISO_IND_ASSOCIATION_FAILED, ISO_IND_ASSOCIATION_FAILED,
ISO_IND_CLOSED, ISO_IND_CLOSED,
ISO_IND_DATA ISO_IND_DATA,
ISO_IND_TICK
} IsoIndication; } IsoIndication;
typedef void* typedef void*
@ -85,6 +86,13 @@ IsoClientConnection_close(IsoClientConnection self);
ByteBuffer* ByteBuffer*
IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self); IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self);
/**
* This function is used to release the transmit buffer in case a formerly allocated transmit buffer cannot
* be sent.
*/
void
IsoClientConnection_releaseTransmitBuffer(IsoClientConnection self);
/* /*
* The client should release the receive buffer in order for the IsoClientConnection to * The client should release the receive buffer in order for the IsoClientConnection to
* reuse the buffer! If this function is not called then the reception of messages is * reuse the buffer! If this function is not called then the reception of messages is

@ -61,6 +61,25 @@ typedef enum {
#define CONCLUDE_STATE_REJECTED 2 #define CONCLUDE_STATE_REJECTED 2
#define CONCLUDE_STATE_ACCEPTED 3 #define CONCLUDE_STATE_ACCEPTED 3
typedef enum {
MMS_CALL_TYPE_NONE,
MMS_CALL_TYPE_READ_VARIABLE,
MMS_CALL_TYPE_WRITE_VARIABLE,
MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES
} eMmsOutstandingCallType;
struct sMmsOutstandingCall
{
bool isUsed;
uint32_t invokeId;
eMmsOutstandingCallType type;
void* userCallback;
void* userParameter;
uint64_t timeout;
};
typedef struct sMmsOutstandingCall* MmsOutstandingCall;
/* private instance variables */ /* private instance variables */
struct sMmsConnection { struct sMmsConnection {
Semaphore lastInvokeIdLock; Semaphore lastInvokeIdLock;
@ -73,7 +92,7 @@ struct sMmsConnection {
volatile MmsError lastResponseError; volatile MmsError lastResponseError;
Semaphore outstandingCallsLock; Semaphore outstandingCallsLock;
uint32_t* outstandingCalls; MmsOutstandingCall outstandingCalls;
uint32_t requestTimeout; uint32_t requestTimeout;
uint32_t connectTimeout; uint32_t connectTimeout;

@ -144,6 +144,8 @@ connectionHandlingThread(IsoClientConnection self)
packetState = TPKT_ERROR; packetState = TPKT_ERROR;
break; break;
} }
self->callback(ISO_IND_TICK, self->callbackParameter, NULL);
} }
if (packetState == TPKT_ERROR) if (packetState == TPKT_ERROR)
@ -655,6 +657,12 @@ IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self)
return self->transmitPayloadBuffer; return self->transmitPayloadBuffer;
} }
void
IsoClientConnection_releaseTransmitBuffer(IsoClientConnection self)
{
Semaphore_post(self->transmitBufferMutex);
}
void void
IsoClientConnection_releaseReceiveBuffer(IsoClientConnection self) IsoClientConnection_releaseReceiveBuffer(IsoClientConnection self)
{ {

@ -285,7 +285,7 @@ getNextInvokeId(MmsConnection self)
return nextInvokeId; return nextInvokeId;
} }
static bool static MmsOutstandingCall
checkForOutstandingCall(MmsConnection self, uint32_t invokeId) checkForOutstandingCall(MmsConnection self, uint32_t invokeId)
{ {
int i = 0; int i = 0;
@ -293,27 +293,34 @@ checkForOutstandingCall(MmsConnection self, uint32_t invokeId)
Semaphore_wait(self->outstandingCallsLock); Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) { for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i] == invokeId) { if (self->outstandingCalls[i].isUsed) {
Semaphore_post(self->outstandingCallsLock); if (self->outstandingCalls[i].invokeId == invokeId) {
return true; Semaphore_post(self->outstandingCallsLock);
return &(self->outstandingCalls[i]);
}
} }
} }
Semaphore_post(self->outstandingCallsLock); Semaphore_post(self->outstandingCallsLock);
return false; return NULL;
} }
static bool static bool
addToOutstandingCalls(MmsConnection self, uint32_t invokeId) addToOutstandingCalls(MmsConnection self, uint32_t invokeId, eMmsOutstandingCallType type, void* userCallback, void* userParameter)
{ {
int i = 0; int i = 0;
Semaphore_wait(self->outstandingCallsLock); Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) { for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i] == 0) { if (self->outstandingCalls[i].isUsed == false) {
self->outstandingCalls[i] = invokeId; self->outstandingCalls[i].isUsed = true;
self->outstandingCalls[i].invokeId = invokeId;
self->outstandingCalls[i].timeout = Hal_getTimeInMs() + self->requestTimeout;
self->outstandingCalls[i].type = type;
self->outstandingCalls[i].userCallback = userCallback;
self->outstandingCalls[i].userParameter = userParameter;
Semaphore_post(self->outstandingCallsLock); Semaphore_post(self->outstandingCallsLock);
return true; return true;
} }
@ -332,18 +339,55 @@ removeFromOutstandingCalls(MmsConnection self, uint32_t invokeId)
Semaphore_wait(self->outstandingCallsLock); Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) { for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i] == invokeId) { if (self->outstandingCalls[i].isUsed) {
self->outstandingCalls[i] = 0; if (self->outstandingCalls[i].invokeId == invokeId) {
break; self->outstandingCalls[i].isUsed = false;
break;
}
} }
} }
Semaphore_post(self->outstandingCallsLock); Semaphore_post(self->outstandingCallsLock);
} }
static void
sendMessage(MmsConnection self, ByteBuffer* message)
{
#if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1)
if (self->rawMmsMessageHandler != NULL) {
MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler;
handler(self->rawMmsMessageHandlerParameter, message->buffer, message->size, false);
}
#endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */
IsoClientConnection_sendMessage(self->isoClient, message);
}
static MmsError
sendAsyncRequest(MmsConnection self, uint32_t invokeId, ByteBuffer* message, eMmsOutstandingCallType type,
void* userCallback, void* userParameter)
{
if (addToOutstandingCalls(self, invokeId, type, userCallback, userParameter) == false) {
/* message cannot be sent - release resources */
IsoClientConnection_releaseTransmitBuffer(self->isoClient);
return MMS_ERROR_OUTSTANDING_CALL_LIMIT;
}
sendMessage(self, message);
return MMS_ERROR_NONE;
}
static ByteBuffer* static ByteBuffer*
sendRequestAndWaitForResponse(MmsConnection self, uint32_t invokeId, ByteBuffer* message, MmsError* mmsError) sendRequestAndWaitForResponse(MmsConnection self, uint32_t invokeId, ByteBuffer* message, MmsError* mmsError)
{ {
if (addToOutstandingCalls(self, invokeId, MMS_CALL_TYPE_NONE, NULL, NULL) == false) {
*mmsError = MMS_ERROR_OUTSTANDING_CALL_LIMIT;
return NULL;
}
ByteBuffer* receivedMessage = NULL; ByteBuffer* receivedMessage = NULL;
uint64_t currentTime = Hal_getTimeInMs(); uint64_t currentTime = Hal_getTimeInMs();
@ -352,21 +396,9 @@ sendRequestAndWaitForResponse(MmsConnection self, uint32_t invokeId, ByteBuffer*
bool success = false; bool success = false;
if (addToOutstandingCalls(self, invokeId) == false) {
*mmsError = MMS_ERROR_OUTSTANDING_CALL_LIMIT;
return NULL;
}
*mmsError = MMS_ERROR_NONE; *mmsError = MMS_ERROR_NONE;
#if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) sendMessage(self, message);
if (self->rawMmsMessageHandler != NULL) {
MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler;
handler(self->rawMmsMessageHandlerParameter, message->buffer, message->size, false);
}
#endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */
IsoClientConnection_sendMessage(self->isoClient, message);
while (currentTime < waitUntilTime) { while (currentTime < waitUntilTime) {
uint32_t receivedInvokeId; uint32_t receivedInvokeId;
@ -742,6 +774,67 @@ mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invo
return -1; return -1;
} }
static void
handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, MmsOutstandingCall outstandingCall, MmsError err)
{
if (outstandingCall->type == MMS_CALL_TYPE_READ_VARIABLE) {
MmsConnection_ReadVariableHandler handler =
(MmsConnection_ReadVariableHandler) outstandingCall->userCallback;
if (err != MMS_ERROR_NONE)
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL);
else {
if (response) {
MmsValue* value = mmsClient_parseReadResponse(response, NULL, false);
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_NONE, value);
}
}
}
else if (outstandingCall->type == MMS_CALL_TYPE_WRITE_VARIABLE) {
MmsConnection_WriteVariableHandler handler =
(MmsConnection_WriteVariableHandler) outstandingCall->userCallback;
if (err != MMS_ERROR_NONE) {
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, DATA_ACCESS_ERROR_NO_RESPONSE);
}
else {
if (response) {
MmsDataAccessError daError = mmsClient_parseWriteResponse(response, bufPos, &err);
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, daError);
}
}
}
else if (outstandingCall->type == MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES) {
MmsConnection_WriteMultipleVariablesHandler handler =
(MmsConnection_WriteMultipleVariablesHandler) outstandingCall->userCallback;
if (err != MMS_ERROR_NONE) {
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL);
}
else {
if (response) {
LinkedList accessResults = NULL;
mmsClient_parseWriteMultipleItemsResponse(response, bufPos, &err, -1, &accessResults);
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, accessResults);
}
}
}
removeFromOutstandingCalls(self, outstandingCall->invokeId);
releaseResponse(self);
}
static void static void
mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
{ {
@ -750,6 +843,33 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsIsoCallback called with indication %i\n", indication); printf("MMS_CLIENT: mmsIsoCallback called with indication %i\n", indication);
if (indication == ISO_IND_TICK) {
//TODO check timeouts
uint64_t currentTime = Hal_getTimeInMs();
int i = 0;
Semaphore_wait(self->outstandingCallsLock);
for (i = 0; i < OUTSTANDING_CALLS; i++) {
if (self->outstandingCalls[i].isUsed) {
if (currentTime > self->outstandingCalls[i].timeout) {
if (self->outstandingCalls[i].type != MMS_CALL_TYPE_NONE)
handleAsyncResponse(self, NULL, 0, &(self->outstandingCalls[i]), MMS_ERROR_SERVICE_TIMEOUT);
self->outstandingCalls[i].isUsed = false;
break;
}
}
}
Semaphore_post(self->outstandingCallsLock);
return;
}
if (indication == ISO_IND_CLOSED) { if (indication == ISO_IND_CLOSED) {
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n"); printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n");
@ -849,15 +969,25 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
goto exit_with_error; goto exit_with_error;
} }
else { else {
if (checkForOutstandingCall(self, invokeId)) {
/* wait for application thread to handle last received response */ MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
waitUntilLastResponseHasBeenProcessed(self);
if (call) {
Semaphore_wait(self->lastResponseLock); MmsError err = convertServiceErrorToMmsError(serviceError);
self->lastResponseError = convertServiceErrorToMmsError(serviceError);
self->responseInvokeId = invokeId; if (call->type != MMS_CALL_TYPE_NONE) {
Semaphore_post(self->lastResponseLock); handleAsyncResponse(self, NULL, 0, call, err);
}
else {
/* wait for application thread to handle last received response */
waitUntilLastResponseHasBeenProcessed(self);
Semaphore_wait(self->lastResponseLock);
self->lastResponseError = err;
self->responseInvokeId = invokeId;
Semaphore_post(self->lastResponseLock);
}
} }
else { else {
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
@ -880,15 +1010,24 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: reject PDU invokeID: %i type: %i reason: %i\n", (int) invokeId, rejectType, rejectReason); printf("MMS_CLIENT: reject PDU invokeID: %i type: %i reason: %i\n", (int) invokeId, rejectType, rejectReason);
if (checkForOutstandingCall(self, invokeId)) { MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
if (call) {
/* wait for application thread to handle last received response */ MmsError err = convertRejectCodesToMmsError(rejectType, rejectReason);
waitUntilLastResponseHasBeenProcessed(self);
Semaphore_wait(self->lastResponseLock); if (call->type != MMS_CALL_TYPE_NONE) {
self->lastResponseError = convertRejectCodesToMmsError(rejectType, rejectReason); handleAsyncResponse(self, NULL, 0, call, err);
self->responseInvokeId = invokeId; }
Semaphore_post(self->lastResponseLock); else {
/* wait for application thread to handle last received response */
waitUntilLastResponseHasBeenProcessed(self);
Semaphore_wait(self->lastResponseLock);
self->lastResponseError = err;
self->responseInvokeId = invokeId;
Semaphore_post(self->lastResponseLock);
}
} }
else { else {
IsoClientConnection_releaseReceiveBuffer(self->isoClient); IsoClientConnection_releaseReceiveBuffer(self->isoClient);
@ -923,15 +1062,22 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
bufPos += invokeIdLength; bufPos += invokeIdLength;
if (checkForOutstandingCall(self, invokeId)) { MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
waitUntilLastResponseHasBeenProcessed(self); if (call) {
Semaphore_wait(self->lastResponseLock); if (call->type != MMS_CALL_TYPE_NONE) {
self->lastResponse = payload; handleAsyncResponse(self, payload, bufPos, call, MMS_ERROR_NONE);
self->lastResponseBufPos = bufPos; }
self->responseInvokeId = invokeId; else {
Semaphore_post(self->lastResponseLock); waitUntilLastResponseHasBeenProcessed(self);
Semaphore_wait(self->lastResponseLock);
self->lastResponse = payload;
self->lastResponseBufPos = bufPos;
self->responseInvokeId = invokeId;
Semaphore_post(self->lastResponseLock);
}
} }
else { else {
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
@ -1106,7 +1252,7 @@ MmsConnection_create()
self->lastResponseError = MMS_ERROR_NONE; self->lastResponseError = MMS_ERROR_NONE;
self->outstandingCalls = (uint32_t*) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(uint32_t)); self->outstandingCalls = (MmsOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sMmsOutstandingCall));
self->isoParameters = IsoConnectionParameters_create(); self->isoParameters = IsoConnectionParameters_create();
@ -1589,6 +1735,33 @@ MmsConnection_readVariable(MmsConnection self, MmsError* mmsError,
return value; return value;
} }
uint32_t
MmsConnection_readVariableAsync(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
MmsConnection_ReadVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createReadRequest(invokeId, domainId, itemId, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
MmsValue* MmsValue*
MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, const char* domainId, const char* itemId,
@ -1619,6 +1792,35 @@ exit_function:
return value; return value;
} }
uint32_t
MmsConnection_readArrayElementsAsync(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
uint32_t startIndex, uint32_t numberOfElements,
MmsConnection_ReadVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createReadRequestAlternateAccessIndex(invokeId, domainId, itemId, startIndex,
numberOfElements, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
MmsValue* MmsValue*
MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError, MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, uint32_t index, const char* componentId) const char* domainId, const char* itemId, uint32_t index, const char* componentId)
@ -1648,6 +1850,36 @@ exit_function:
return value; return value;
} }
uint32_t
MmsConnection_readSingleArrayElementWithComponentAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId,
uint32_t index, const char* componentId,
MmsConnection_ReadVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, index, componentId,
payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
MmsValue* MmsValue*
MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
const char* domainId, LinkedList /*<char*>*/items) const char* domainId, LinkedList /*<char*>*/items)
@ -1676,6 +1908,35 @@ MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
return value; return value;
} }
uint32_t
MmsConnection_readMultipleVariablesAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, LinkedList /*<char*>*/items,
MmsConnection_ReadVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createReadRequestMultipleValues(invokeId, domainId, items, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
MmsValue* MmsValue*
MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError, MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* listName, const char* domainId, const char* listName,
@ -1706,6 +1967,36 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError
return value; return value;
} }
uint32_t
MmsConnection_readNamedVariableListValuesAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* listName, bool specWithResult,
MmsConnection_ReadVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createReadNamedVariableListRequest(invokeId, domainId, listName,
payload, specWithResult);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
MmsValue* MmsValue*
MmsConnection_readNamedVariableListValuesAssociationSpecific( MmsConnection_readNamedVariableListValuesAssociationSpecific(
MmsConnection self, MmsError* mmsError, MmsConnection self, MmsError* mmsError,
@ -1737,6 +2028,35 @@ MmsConnection_readNamedVariableListValuesAssociationSpecific(
return value; return value;
} }
uint32_t
MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(MmsConnection self, MmsError* mmsError,
const char* listName, bool specWithResult,
MmsConnection_ReadVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createReadAssociationSpecificNamedVariableListRequest(invokeId, listName,
payload, specWithResult);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
LinkedList /* <MmsVariableAccessSpecification*> */ LinkedList /* <MmsVariableAccessSpecification*> */
MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError, MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* listName, bool* deletable) const char* domainId, const char* listName, bool* deletable)
@ -2317,6 +2637,34 @@ MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError,
return retVal; return retVal;
} }
uint32_t
MmsConnection_writeVariableAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, MmsValue* value,
MmsConnection_WriteVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createWriteRequest(invokeId, domainId, itemId, value, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
void void
MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId, MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId,
LinkedList /*<char*>*/items, LinkedList /*<char*>*/items,
@ -2342,6 +2690,34 @@ MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, con
releaseResponse(self); releaseResponse(self);
} }
uint32_t
MmsConnection_writeMultipleVariablesAsync(MmsConnection self, MmsError* mmsError, const char* domainId,
LinkedList /*<char*>*/ items, LinkedList /* <MmsValue*> */ values,
MmsConnection_WriteMultipleVariablesHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createWriteMultipleItemsRequest(invokeId, domainId, items, values, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
MmsDataAccessError MmsDataAccessError
MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError, MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, int index, int numberOfElements, const char* domainId, const char* itemId, int index, int numberOfElements,
@ -2365,6 +2741,35 @@ MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError,
return retVal; return retVal;
} }
uint32_t
MmsConnection_writeArrayElementsAsync(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* itemId, int index, int numberOfElements,
MmsValue* value,
MmsConnection_WriteVariableHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createWriteRequestArray(invokeId, domainId, itemId, index, numberOfElements, value, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
void void
MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific, MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific,
const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values, const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values,
@ -2389,6 +2794,34 @@ MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, boo
releaseResponse(self); releaseResponse(self);
} }
uint32_t
MmsConnection_writeNamedVariableListAsync(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific,
const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values,
MmsConnection_WriteMultipleVariablesHandler handler, void* parameter)
{
uint32_t invokeId = 0;
if (getAssociationState(self) != MMS_STATE_CONNECTED) {
if (mmsError)
*mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function;
}
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
invokeId = getNextInvokeId(self);
mmsClient_createWriteRequestNamedVariableList(invokeId, isAssociationSpecific, domainId, itemId, values, payload);
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter);
if (mmsError)
*mmsError = err;
exit_function:
return invokeId;
}
void void
MmsServerIdentity_destroy(MmsServerIdentity* self) MmsServerIdentity_destroy(MmsServerIdentity* self)
{ {

@ -119,8 +119,10 @@ mmsClient_parseWriteMultipleItemsResponse(ByteBuffer* message, int32_t bufPos, M
numberOfAccessResults++; numberOfAccessResults++;
} }
if (itemCount != numberOfAccessResults) if (itemCount != -1) {
goto exit_with_error; if (itemCount != numberOfAccessResults)
goto exit_with_error;
}
} }
else else
*mmsError = MMS_ERROR_PARSING_RESPONSE; *mmsError = MMS_ERROR_PARSING_RESPONSE;

Loading…
Cancel
Save