You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4762 lines
138 KiB
C
4762 lines
138 KiB
C
/*
|
|
* mms_client_connection.c
|
|
*
|
|
* Copyright 2013-2022 Michael Zillgith
|
|
*
|
|
* This file is part of libIEC61850.
|
|
*
|
|
* libIEC61850 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* libIEC61850 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* See COPYING file for the complete license text.
|
|
*/
|
|
|
|
#include "libiec61850_platform_includes.h"
|
|
|
|
#include "mms_client_connection.h"
|
|
#include "iso_client_connection.h"
|
|
#include "mms_client_internal.h"
|
|
#include "stack_config.h"
|
|
|
|
#include <MmsPdu.h>
|
|
|
|
#include "byte_buffer.h"
|
|
#include "ber_decode.h"
|
|
|
|
#include "tls_config.h"
|
|
|
|
#define CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT 5000
|
|
#define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000
|
|
#define OUTSTANDING_CALLS 10
|
|
|
|
static void
|
|
setConnectionState(MmsConnection self, MmsConnectionState newState)
|
|
{
|
|
Semaphore_wait(self->associationStateLock);
|
|
self->connectionState = newState;
|
|
Semaphore_post(self->associationStateLock);
|
|
|
|
if (self->stateChangedHandler)
|
|
self->stateChangedHandler(self, self->stateChangedHandlerParameter, newState);
|
|
}
|
|
|
|
static MmsConnectionState
|
|
getConnectionState(MmsConnection self)
|
|
{
|
|
MmsConnectionState state;
|
|
|
|
Semaphore_wait(self->associationStateLock);
|
|
state = self->connectionState;
|
|
Semaphore_post(self->associationStateLock);
|
|
|
|
return state;
|
|
}
|
|
|
|
static void
|
|
handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
|
|
{
|
|
if (self->reportHandler != NULL) {
|
|
MmsPdu_t* mmsPdu = NULL; /* allow asn1c to allocate structure */
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: report handler rcvd size:%i\n", ByteBuffer_getSize(message));
|
|
|
|
asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu,
|
|
(void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message));
|
|
|
|
if (rval.code == RC_OK) {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received report (size:%i)\n", (int) rval.consumed);
|
|
|
|
if (mmsPdu->present == MmsPdu_PR_unconfirmedPDU) {
|
|
|
|
if (mmsPdu->choice.unconfirmedPDU.unconfirmedService.present ==
|
|
UnconfirmedService_PR_informationReport)
|
|
{
|
|
char* domainId = NULL;
|
|
|
|
InformationReport_t* report =
|
|
&(mmsPdu->choice.unconfirmedPDU.unconfirmedService.choice.informationReport);
|
|
|
|
if (report->variableAccessSpecification.present ==
|
|
VariableAccessSpecification_PR_variableListName)
|
|
{
|
|
if (report->variableAccessSpecification.choice.variableListName.present
|
|
== ObjectName_PR_vmdspecific)
|
|
{
|
|
int nameSize =
|
|
report->variableAccessSpecification.choice.variableListName.choice.vmdspecific.size;
|
|
|
|
uint8_t* buffer =
|
|
report->variableAccessSpecification.choice.variableListName.choice.vmdspecific.buf;
|
|
|
|
char* variableListName = StringUtils_createStringFromBuffer(buffer, nameSize);
|
|
|
|
int listSize = report->listOfAccessResult.list.count;
|
|
|
|
MmsValue* values = mmsClient_parseListOfAccessResults(
|
|
report->listOfAccessResult.list.array, listSize, true);
|
|
|
|
self->reportHandler(self->reportHandlerParameter, domainId, variableListName, values, true);
|
|
|
|
GLOBAL_FREEMEM(variableListName);
|
|
}
|
|
else {
|
|
/* Ignore domain and association specific information reports (not used by IEC 61850) */
|
|
}
|
|
|
|
}
|
|
else if (report->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable)
|
|
{
|
|
int listSize = report->listOfAccessResult.list.count;
|
|
int variableSpecSize = report->variableAccessSpecification.choice.listOfVariable.list.count;
|
|
|
|
if (listSize != variableSpecSize) {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("report contains wrong number of access results\n");
|
|
return;
|
|
}
|
|
|
|
MmsValue* values = mmsClient_parseListOfAccessResults(
|
|
report->listOfAccessResult.list.array, listSize, false);
|
|
|
|
int i;
|
|
for (i = 0; i < variableSpecSize; i++) {
|
|
if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification.present
|
|
== VariableSpecification_PR_name)
|
|
{
|
|
if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific)
|
|
{
|
|
int nameSize =
|
|
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.choice.vmdspecific.size;
|
|
|
|
uint8_t* buffer =
|
|
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.choice.vmdspecific.buf;
|
|
|
|
if (nameSize < 129) {
|
|
char variableListName[129];
|
|
memcpy(variableListName, buffer, nameSize);
|
|
variableListName[nameSize] = 0;
|
|
|
|
MmsValue* value = values;
|
|
|
|
if (variableSpecSize != 1)
|
|
value = MmsValue_getElement(values, i);
|
|
|
|
self->reportHandler(self->reportHandlerParameter, domainId, variableListName,
|
|
value, false);
|
|
|
|
/* report handler is responsible to delete the MmsValue object */
|
|
if (variableSpecSize != 1)
|
|
MmsValue_setElement(values, i, NULL);
|
|
else
|
|
values = NULL;
|
|
}
|
|
}
|
|
else if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) {
|
|
|
|
int domainNameSize =
|
|
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.choice.domainspecific.domainId.size;
|
|
|
|
int itemNameSize =
|
|
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.choice.domainspecific.itemId.size;
|
|
|
|
if ((domainNameSize < 65) && (itemNameSize < 65)) {
|
|
char domainNameStr[65];
|
|
char itemNameStr[65];
|
|
|
|
uint8_t* domainNameBuffer =
|
|
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.choice.domainspecific.domainId.buf;
|
|
|
|
uint8_t* itemNamebuffer =
|
|
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
|
|
->variableSpecification.choice.name.choice.domainspecific.itemId.buf;
|
|
|
|
memcpy(domainNameStr, domainNameBuffer, domainNameSize);
|
|
domainNameStr[domainNameSize] = 0;
|
|
memcpy(itemNameStr, itemNamebuffer, itemNameSize);
|
|
itemNameStr[itemNameSize] = 0;
|
|
|
|
MmsValue* value = values;
|
|
|
|
if (variableSpecSize != 1)
|
|
value = MmsValue_getElement(values, i);
|
|
|
|
self->reportHandler(self->reportHandlerParameter, domainNameStr, itemNameStr,
|
|
value, false);
|
|
|
|
/* report handler is responsible to delete the MmsValue object */
|
|
if (variableSpecSize != 1)
|
|
MmsValue_setElement(values, i, NULL);
|
|
else
|
|
values = NULL;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (values != NULL)
|
|
MmsValue_delete(values);
|
|
}
|
|
else {
|
|
/* Ignore */
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("unrecognized information report\n");
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("handleUnconfirmedMmsPdu: error parsing PDU at %u\n", (uint32_t) rval.consumed);
|
|
}
|
|
|
|
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
getNextInvokeId(MmsConnection self)
|
|
{
|
|
uint32_t nextInvokeId;
|
|
|
|
Semaphore_wait(self->nextInvokeIdLock);
|
|
self->nextInvokeId++;
|
|
nextInvokeId = self->nextInvokeId;
|
|
Semaphore_post(self->nextInvokeIdLock);
|
|
|
|
return nextInvokeId;
|
|
}
|
|
|
|
static MmsOutstandingCall
|
|
checkForOutstandingCall(MmsConnection self, uint32_t invokeId)
|
|
{
|
|
int i = 0;
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
for (i = 0; i < OUTSTANDING_CALLS; i++) {
|
|
if (self->outstandingCalls[i].isUsed) {
|
|
if (self->outstandingCalls[i].invokeId == invokeId) {
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
return &(self->outstandingCalls[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool
|
|
addToOutstandingCalls(MmsConnection self, uint32_t invokeId, eMmsOutstandingCallType type, void* userCallback, void* userParameter, MmsClientInternalParameter internalParameter)
|
|
{
|
|
int i = 0;
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
for (i = 0; i < OUTSTANDING_CALLS; i++) {
|
|
if (self->outstandingCalls[i].isUsed == false) {
|
|
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;
|
|
self->outstandingCalls[i].internalParameter = internalParameter;
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
|
|
return false;
|
|
}
|
|
|
|
static void
|
|
removeFromOutstandingCalls(MmsConnection self, uint32_t invokeId)
|
|
{
|
|
int i = 0;
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
for (i = 0; i < OUTSTANDING_CALLS; i++) {
|
|
if (self->outstandingCalls[i].isUsed) {
|
|
if (self->outstandingCalls[i].invokeId == invokeId) {
|
|
self->outstandingCalls[i].isUsed = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
}
|
|
|
|
MmsOutstandingCall
|
|
mmsClient_getMatchingObtainFileRequest(MmsConnection self, const char* filename)
|
|
{
|
|
int i = 0;
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
for (i = 0; i < OUTSTANDING_CALLS; i++) {
|
|
if (self->outstandingCalls[i].isUsed) {
|
|
|
|
if (self->outstandingCalls[i].type == MMS_CALL_TYPE_OBTAIN_FILE) {
|
|
|
|
char* storedFilename = (char*) self->outstandingCalls[i].internalParameter.ptr;
|
|
|
|
if (storedFilename) {
|
|
|
|
if (!strcmp(filename, storedFilename)) {
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
return &(self->outstandingCalls[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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) */
|
|
|
|
#if (CONFIG_MMS_COLLECT_STATISTICS == 1)
|
|
self->statAplMessagesSent++;
|
|
#endif
|
|
|
|
IsoClientConnection_sendMessage(self->isoClient, message);
|
|
}
|
|
|
|
static MmsError
|
|
sendAsyncRequest(MmsConnection self, uint32_t invokeId, ByteBuffer* message, eMmsOutstandingCallType type,
|
|
void* userCallback, void* userParameter, MmsClientInternalParameter internalParameter)
|
|
{
|
|
if (addToOutstandingCalls(self, invokeId, type, userCallback, userParameter, internalParameter) == 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 MmsError
|
|
convertRejectCodesToMmsError(int rejectType, int rejectReason)
|
|
{
|
|
if ((rejectType == 1) && (rejectReason == 1))
|
|
return MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE;
|
|
else if ((rejectType == 5) && (rejectReason == 0))
|
|
return MMS_ERROR_REJECT_UNKNOWN_PDU_TYPE;
|
|
else if ((rejectType == 1) && (rejectReason == 4))
|
|
return MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT;
|
|
else if ((rejectType == 5) && (rejectReason == 1))
|
|
return MMS_ERROR_REJECT_INVALID_PDU;
|
|
else
|
|
return MMS_ERROR_REJECT_OTHER;
|
|
}
|
|
|
|
static MmsError
|
|
convertServiceErrorToMmsError(MmsServiceError serviceError)
|
|
{
|
|
MmsError mmsError;
|
|
|
|
switch (serviceError.errorClass)
|
|
{
|
|
case 0: /* class: vmd-state */
|
|
mmsError = MMS_ERROR_VMDSTATE_OTHER;
|
|
break;
|
|
|
|
case 1: /* class: application-reference */
|
|
mmsError = MMS_ERROR_APPLICATION_REFERENCE_OTHER;
|
|
break;
|
|
|
|
case 2: /* class: definition */
|
|
switch (serviceError.errorCode)
|
|
{
|
|
case 1:
|
|
mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED;
|
|
break;
|
|
case 2:
|
|
mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS;
|
|
break;
|
|
case 3:
|
|
mmsError = MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED;
|
|
break;
|
|
case 4:
|
|
mmsError = MMS_ERROR_DEFINITION_TYPE_INCONSISTENT;
|
|
break;
|
|
case 5:
|
|
mmsError = MMS_ERROR_DEFINITION_OBJECT_EXISTS;
|
|
break;
|
|
case 6:
|
|
mmsError = MMS_ERROR_DEFINITION_OBJECT_ATTRIBUTE_INCONSISTENT;
|
|
break;
|
|
default:
|
|
mmsError = MMS_ERROR_DEFINITION_OTHER;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3: /* class: resource */
|
|
mmsError = MMS_ERROR_RESOURCE_OTHER;
|
|
break;
|
|
|
|
case 4: /* class: service */
|
|
mmsError = MMS_ERROR_SERVICE_OTHER;
|
|
break;
|
|
|
|
case 5: /* class: service-preempt */
|
|
mmsError = MMS_ERROR_SERVICE_PREEMPT_OTHER;
|
|
break;
|
|
|
|
case 6: /* class: time-resolution */
|
|
mmsError = MMS_ERROR_TIME_RESOLUTION_OTHER;
|
|
break;
|
|
|
|
case 7: /* class: access */
|
|
switch (serviceError.errorCode)
|
|
{
|
|
case 1:
|
|
mmsError = MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED;
|
|
break;
|
|
case 2:
|
|
mmsError = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT;
|
|
break;
|
|
case 3:
|
|
mmsError = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED;
|
|
break;
|
|
case 4:
|
|
mmsError = MMS_ERROR_ACCESS_OBJECT_INVALIDATED;
|
|
break;
|
|
default:
|
|
mmsError = MMS_ERROR_ACCESS_OTHER;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 11: /* class: file */
|
|
switch (serviceError.errorCode)
|
|
{
|
|
case 1:
|
|
mmsError = MMS_ERROR_FILE_FILENAME_AMBIGUOUS;
|
|
break;
|
|
case 2:
|
|
mmsError = MMS_ERROR_FILE_FILE_BUSY;
|
|
break;
|
|
case 3:
|
|
mmsError = MMS_ERROR_FILE_FILENAME_SYNTAX_ERROR;
|
|
break;
|
|
case 4:
|
|
mmsError = MMS_ERROR_FILE_CONTENT_TYPE_INVALID;
|
|
break;
|
|
case 5:
|
|
mmsError = MMS_ERROR_FILE_POSITION_INVALID;
|
|
break;
|
|
case 6:
|
|
mmsError = MMS_ERROR_FILE_FILE_ACCESS_DENIED;
|
|
break;
|
|
case 7:
|
|
mmsError = MMS_ERROR_FILE_FILE_NON_EXISTENT;
|
|
break;
|
|
case 8:
|
|
mmsError = MMS_ERROR_FILE_DUPLICATE_FILENAME;
|
|
break;
|
|
case 9:
|
|
mmsError = MMS_ERROR_FILE_INSUFFICIENT_SPACE_IN_FILESTORE;
|
|
break;
|
|
default:
|
|
mmsError = MMS_ERROR_FILE_OTHER;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
mmsError = MMS_ERROR_OTHER;
|
|
}
|
|
|
|
return mmsError;
|
|
}
|
|
|
|
static int
|
|
parseServiceError(uint8_t* buffer, int bufPos, int maxLength, MmsServiceError* error)
|
|
{
|
|
int endPos = bufPos + maxLength;
|
|
int length;
|
|
|
|
while (bufPos < endPos) {
|
|
uint8_t tag = buffer[bufPos++];
|
|
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos);
|
|
|
|
if (bufPos < 0)
|
|
return -1;
|
|
|
|
switch (tag)
|
|
{
|
|
case 0xa0: /* errorClass */
|
|
{
|
|
uint8_t errorClassTag = buffer[bufPos++];
|
|
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos);
|
|
|
|
if (bufPos < 0)
|
|
return -1;
|
|
|
|
error->errorClass = errorClassTag - 0x80;
|
|
error->errorCode = BerDecoder_decodeUint32(buffer, length, bufPos);
|
|
|
|
bufPos += length;
|
|
}
|
|
break;
|
|
case 0x81: /* additionalCode */
|
|
bufPos += length; /* ignore */
|
|
break;
|
|
case 0x82: /* additionalDescription */
|
|
bufPos += length; /* ignore */
|
|
break;
|
|
case 0xa3: /* serviceSpecificInfo */
|
|
bufPos += length; /* ignore */
|
|
break;
|
|
case 0x00: /* indefinite length end tag -> ignore */
|
|
break;
|
|
default:
|
|
bufPos += length; /* ignore */
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bufPos;
|
|
}
|
|
|
|
int
|
|
mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, bool* hasInvokeId, MmsServiceError* serviceError)
|
|
{
|
|
int length;
|
|
|
|
if (hasInvokeId)
|
|
*hasInvokeId = false;
|
|
|
|
uint8_t tag = buffer[bufPos++];
|
|
if (tag != 0xa2)
|
|
goto exit_error;
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
|
|
if (bufPos < 0)
|
|
goto exit_error;
|
|
|
|
int endPos = bufPos + length;
|
|
|
|
while (bufPos < endPos) {
|
|
tag = buffer[bufPos++];
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
|
|
|
|
if (bufPos < 0)
|
|
goto exit_error;
|
|
|
|
switch (tag)
|
|
{
|
|
case 0x80: /* invoke Id */
|
|
if (hasInvokeId)
|
|
*hasInvokeId = true;
|
|
if (invokeId != NULL)
|
|
*invokeId = BerDecoder_decodeUint32(buffer, length, bufPos);
|
|
bufPos += length;
|
|
break;
|
|
case 0x81: /* modifierPosition */
|
|
bufPos += length; /* ignore */
|
|
break;
|
|
case 0xa2: /* serviceError */
|
|
bufPos = parseServiceError(buffer, bufPos, length, serviceError);
|
|
if (bufPos < 0)
|
|
goto exit_error;
|
|
break;
|
|
case 0x00: /* indefinite length end tag -> ignore */
|
|
break;
|
|
default:
|
|
bufPos += length; /* ignore */
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bufPos;
|
|
|
|
exit_error:
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: error parsing confirmed error PDU\n");
|
|
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, bool* hasInvokeId, int* rejectType, int* rejectReason)
|
|
{
|
|
int length;
|
|
|
|
if (hasInvokeId)
|
|
*hasInvokeId = false;
|
|
|
|
uint8_t tag = buffer[bufPos++];
|
|
|
|
if (tag != 0xa4)
|
|
goto exit_error;
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
|
|
if (bufPos < 0)
|
|
goto exit_error;
|
|
|
|
int endPos = bufPos + length;
|
|
|
|
while (bufPos < endPos) {
|
|
tag = buffer[bufPos++];
|
|
|
|
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
|
|
|
|
if (bufPos < 0)
|
|
goto exit_error;
|
|
|
|
if (tag == 0x80) { /* invoke id */
|
|
if (hasInvokeId)
|
|
*hasInvokeId = true;
|
|
if (invokeId != NULL)
|
|
*invokeId = BerDecoder_decodeUint32(buffer, length, bufPos);
|
|
}
|
|
else if (tag > 0x80 && tag < 0x8c) {
|
|
*rejectType = tag - 0x80;
|
|
*rejectReason = BerDecoder_decodeInt32(buffer, length, bufPos);
|
|
}
|
|
else {
|
|
/* unknown - ignore */
|
|
}
|
|
|
|
bufPos += length;
|
|
}
|
|
|
|
return bufPos;
|
|
|
|
exit_error:
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: error parsing reject PDU\n");
|
|
|
|
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);
|
|
|
|
if (value == NULL)
|
|
err = MMS_ERROR_PARSING_RESPONSE;
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, value);
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES) {
|
|
|
|
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, true);
|
|
|
|
if (value == NULL)
|
|
err = MMS_ERROR_PARSING_RESPONSE;
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, 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);
|
|
}
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_READ_NVL_DIRECTORY) {
|
|
MmsConnection_ReadNVLDirectoryHandler handler =
|
|
(MmsConnection_ReadNVLDirectoryHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false);
|
|
}
|
|
else {
|
|
if (response) {
|
|
bool deletable = false;
|
|
|
|
LinkedList accessSpec = mmsClient_parseGetNamedVariableListAttributesResponse(response, &deletable);
|
|
|
|
if (accessSpec == NULL)
|
|
err = MMS_ERROR_PARSING_RESPONSE;
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, accessSpec, deletable);
|
|
}
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_DEFINE_NVL) {
|
|
|
|
MmsConnection_GenericServiceHandler handler =
|
|
(MmsConnection_GenericServiceHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, false);
|
|
}
|
|
else {
|
|
bool success = false;
|
|
|
|
if (!mmsClient_parseDefineNamedVariableResponse(response, NULL))
|
|
err = MMS_ERROR_PARSING_RESPONSE;
|
|
else
|
|
success = true;
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, success);
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_DELETE_NVL) {
|
|
|
|
MmsConnection_GenericServiceHandler handler =
|
|
(MmsConnection_GenericServiceHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, false);
|
|
}
|
|
else {
|
|
bool success = false;
|
|
|
|
long numberMatched = 0;
|
|
long numberDeleted = 0;
|
|
|
|
if (mmsClient_parseDeleteNamedVariableListResponse(response, NULL, &numberDeleted, &numberMatched))
|
|
success = true;
|
|
|
|
if (numberMatched == 0)
|
|
err = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT;
|
|
else {
|
|
if (numberDeleted == 0)
|
|
err = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED;
|
|
}
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, success);
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_GET_VAR_ACCESS_ATTR) {
|
|
MmsConnection_GetVariableAccessAttributesHandler handler =
|
|
(MmsConnection_GetVariableAccessAttributesHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL);
|
|
}
|
|
else {
|
|
MmsVariableSpecification* typeSpec = mmsClient_parseGetVariableAccessAttributesResponse(response, NULL);
|
|
|
|
if (typeSpec == NULL)
|
|
err = MMS_ERROR_PARSING_RESPONSE;
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, typeSpec);
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_GET_SERVER_STATUS) {
|
|
MmsConnection_GetServerStatusHandler handler =
|
|
(MmsConnection_GetServerStatusHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, 0, 0);
|
|
}
|
|
else {
|
|
int vmdLogicalStatus;
|
|
int vmdPhysicalStatus;
|
|
|
|
if (mmsClient_parseStatusResponse(self, response, bufPos, &vmdLogicalStatus, &vmdPhysicalStatus) == false)
|
|
err = MMS_ERROR_PARSING_RESPONSE;
|
|
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, vmdLogicalStatus, vmdPhysicalStatus);
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_IDENTIFY) {
|
|
MmsConnection_IdentifyHandler handler =
|
|
(MmsConnection_IdentifyHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, NULL, NULL);
|
|
}
|
|
else {
|
|
|
|
if (mmsClient_parseIdentifyResponse(self, response, bufPos, outstandingCall->invokeId, handler,
|
|
outstandingCall->userParameter) == false)
|
|
{
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE,
|
|
NULL, NULL, NULL);
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_READ_JOURNAL) {
|
|
|
|
MmsConnection_ReadJournalHandler handler =
|
|
(MmsConnection_ReadJournalHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false);
|
|
}
|
|
else {
|
|
bool moreFollows = false;
|
|
LinkedList entries = NULL;
|
|
|
|
if (mmsClient_parseReadJournalResponse(response, bufPos, &moreFollows, &entries) == false) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, NULL, false);
|
|
}
|
|
else {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, entries, moreFollows);
|
|
}
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_GET_NAME_LIST) {
|
|
|
|
MmsConnection_GetNameListHandler handler =
|
|
(MmsConnection_GetNameListHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false);
|
|
}
|
|
else {
|
|
LinkedList nameList = (LinkedList) outstandingCall->internalParameter.ptr;
|
|
|
|
bool moreFollows = mmsClient_parseGetNameListResponse(&nameList, response);
|
|
|
|
if (nameList == NULL) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, NULL, false);
|
|
}
|
|
else {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, nameList, moreFollows);
|
|
}
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_FILE_OPEN) {
|
|
|
|
MmsConnection_FileOpenHandler handler =
|
|
(MmsConnection_FileOpenHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, 0, 0, 0);
|
|
}
|
|
else {
|
|
int32_t frsmId;
|
|
uint32_t fileSize;
|
|
uint64_t lastModified;
|
|
|
|
if (mmsMsg_parseFileOpenResponse(ByteBuffer_getBuffer(response), bufPos, ByteBuffer_getSize(response),
|
|
&frsmId, &fileSize, &lastModified) == false)
|
|
{
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, 0, 0, 0);
|
|
}
|
|
else {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, frsmId, fileSize, lastModified);
|
|
}
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_FILE_READ) {
|
|
MmsConnection_FileReadHandler handler =
|
|
(MmsConnection_FileReadHandler) outstandingCall->userCallback;
|
|
|
|
int32_t frsmId = outstandingCall->internalParameter.i32;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, frsmId, NULL, 0, false);
|
|
}
|
|
else {
|
|
bool moreFollows;
|
|
|
|
if (mmsMsg_parseFileReadResponse(ByteBuffer_getBuffer(response), bufPos, ByteBuffer_getSize(response), outstandingCall->invokeId, frsmId, &moreFollows,
|
|
handler, outstandingCall->userParameter) == false)
|
|
{
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, frsmId, NULL, 0, false);
|
|
}
|
|
}
|
|
}
|
|
else if ((outstandingCall->type == MMS_CALL_TYPE_FILE_CLOSE) ||
|
|
(outstandingCall->type == MMS_CALL_TYPE_FILE_DELETE) ||
|
|
(outstandingCall->type == MMS_CALL_TYPE_FILE_RENAME) ||
|
|
(outstandingCall->type == MMS_CALL_TYPE_OBTAIN_FILE))
|
|
{
|
|
MmsConnection_GenericServiceHandler handler =
|
|
(MmsConnection_GenericServiceHandler) outstandingCall->userCallback;
|
|
|
|
if (outstandingCall->type == MMS_CALL_TYPE_OBTAIN_FILE) {
|
|
if (outstandingCall->internalParameter.ptr)
|
|
GLOBAL_FREEMEM(outstandingCall->internalParameter.ptr);
|
|
}
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, false);
|
|
}
|
|
else {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, true);
|
|
}
|
|
}
|
|
else if (outstandingCall->type == MMS_CALL_TYPE_GET_FILE_DIR) {
|
|
MmsConnection_FileDirectoryHandler handler =
|
|
(MmsConnection_FileDirectoryHandler) outstandingCall->userCallback;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, 0, 0, false);
|
|
}
|
|
else {
|
|
if (mmsClient_parseFileDirectoryResponse(response, bufPos, outstandingCall->invokeId, handler, outstandingCall->userParameter) == false)
|
|
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, NULL, 0, 0, false);
|
|
}
|
|
}
|
|
|
|
if (err != MMS_ERROR_SERVICE_TIMEOUT)
|
|
removeFromOutstandingCalls(self, outstandingCall->invokeId);
|
|
}
|
|
|
|
static bool
|
|
mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
|
|
{
|
|
MmsConnection self = (MmsConnection) parameter;
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
if (indication != ISO_IND_TICK)
|
|
printf("MMS_CLIENT: mmsIsoCallback called with indication %i\n", indication);
|
|
|
|
if (indication == ISO_IND_TICK) {
|
|
|
|
/* check timeouts */
|
|
|
|
uint64_t currentTime = Hal_getTimeInMs();
|
|
|
|
int i = 0;
|
|
|
|
for (i = 0; i < OUTSTANDING_CALLS; i++) {
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
if (self->outstandingCalls[i].isUsed) {
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
|
|
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);
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
self->outstandingCalls[i].isUsed = false;
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
}
|
|
}
|
|
else {
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
}
|
|
}
|
|
|
|
if (self->concludeHandler) {
|
|
if (currentTime > self->concludeTimeout) {
|
|
self->concludeHandler(self->concludeHandlerParameter, MMS_ERROR_SERVICE_TIMEOUT, false);
|
|
self->concludeHandler = NULL;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (indication == ISO_IND_CLOSED) {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n");
|
|
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CLOSED);
|
|
|
|
/* Call user provided callback function */
|
|
if (self->connectionLostHandler != NULL)
|
|
self->connectionLostHandler(self, self->connectionLostHandlerParameter);
|
|
|
|
/* Cleanup outstanding calls */
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < OUTSTANDING_CALLS; i++) {
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
if (self->outstandingCalls[i].isUsed) {
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
|
|
if (self->outstandingCalls[i].type != MMS_CALL_TYPE_NONE)
|
|
handleAsyncResponse(self, NULL, 0, &(self->outstandingCalls[i]), MMS_ERROR_SERVICE_TIMEOUT);
|
|
|
|
Semaphore_wait(self->outstandingCallsLock);
|
|
|
|
self->outstandingCalls[i].isUsed = false;
|
|
}
|
|
|
|
Semaphore_post(self->outstandingCallsLock);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (indication == ISO_IND_ASSOCIATION_FAILED) {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: mmsIsoCallback: association failed!\n");
|
|
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CLOSING);
|
|
return false;
|
|
}
|
|
|
|
if (payload != NULL) {
|
|
if (ByteBuffer_getSize(payload) < 1) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
uint8_t* buf = ByteBuffer_getBuffer(payload);
|
|
|
|
#if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1)
|
|
if (self->rawMmsMessageHandler != NULL) {
|
|
MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler;
|
|
handler(self->rawMmsMessageHandlerParameter, buf, payload->size, true);
|
|
}
|
|
#endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */
|
|
|
|
uint8_t tag = buf[0];
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: MMS-PDU: %02x\n", tag);
|
|
|
|
if (tag == 0xa9) { /* initiate response PDU */
|
|
|
|
if (indication == ISO_IND_ASSOCIATION_SUCCESS) {
|
|
|
|
if (mmsClient_parseInitiateResponse(self, payload)) {
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CONNECTED);
|
|
}
|
|
else {
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CLOSING);
|
|
|
|
goto exit_with_error;
|
|
}
|
|
}
|
|
else {
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CLOSING);
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: Failed to parse initiate response!\n");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else if (tag == 0xaa) { /* initiate error PDU */
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received initiate error PDU\n");
|
|
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CLOSING);
|
|
|
|
return false;
|
|
}
|
|
else if (tag == 0xa3) { /* unconfirmed PDU */
|
|
handleUnconfirmedMmsPdu(self, payload);
|
|
}
|
|
else if (tag == 0x8b) { /* conclude request PDU */
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received conclude.request\n");
|
|
|
|
/* TODO block all new user requests? */
|
|
}
|
|
else if (tag == 0x8c) { /* conclude response PDU */
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received conclude.response+\n");
|
|
|
|
if (self->concludeHandler) {
|
|
self->concludeHandler(self->concludeHandlerParameter, MMS_ERROR_NONE, true);
|
|
self->concludeHandler = NULL;
|
|
}
|
|
|
|
IsoClientConnection_release(self->isoClient);
|
|
}
|
|
else if (tag == 0x8d) { /* conclude error PDU */
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received conclude.reponse-\n");
|
|
|
|
if (self->concludeHandler) {
|
|
self->concludeHandler(self->concludeHandlerParameter, MMS_ERROR_CONCLUDE_REJECTED, false);
|
|
self->concludeHandler = NULL;
|
|
}
|
|
}
|
|
else if (tag == 0xa2) { /* confirmed error PDU */
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: Confirmed error PDU!\n");
|
|
|
|
uint32_t invokeId;
|
|
bool hasInvokeId = false;
|
|
|
|
MmsServiceError serviceError = { 0, 0 };
|
|
|
|
if (mmsMsg_parseConfirmedErrorPDU(payload->buffer, 0, payload->size, &invokeId, &hasInvokeId, &serviceError) < 0) {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: Error parsing confirmedErrorPDU!\n");
|
|
|
|
goto exit_with_error;
|
|
}
|
|
else {
|
|
|
|
if (hasInvokeId) {
|
|
MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
|
|
|
|
if (call) {
|
|
|
|
MmsError err = convertServiceErrorToMmsError(serviceError);
|
|
|
|
if (call->type != MMS_CALL_TYPE_NONE) {
|
|
handleAsyncResponse(self, NULL, 0, call, err);
|
|
}
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: internal problem (unexpected call type - error PDU)\n");
|
|
}
|
|
}
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: server sent unexpected confirmed error PDU!\n");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: server sent confirmed error PDU without invoke ID!\n");
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (tag == 0xa4) { /* reject PDU */
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: reject PDU!\n");
|
|
|
|
bool hasInvokeId = false;
|
|
uint32_t invokeId = 0;
|
|
int rejectType;
|
|
int rejectReason;
|
|
|
|
if (mmsMsg_parseRejectPDU(payload->buffer, 0, payload->size, &invokeId, &hasInvokeId, &rejectType, &rejectReason) >= 0) {
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: reject PDU invokeID: %u type: %i reason: %i\n", invokeId, rejectType, rejectReason);
|
|
|
|
if (hasInvokeId) {
|
|
MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
|
|
|
|
if (call) {
|
|
|
|
MmsError err = convertRejectCodesToMmsError(rejectType, rejectReason);
|
|
|
|
if (call->type != MMS_CALL_TYPE_NONE) {
|
|
handleAsyncResponse(self, NULL, 0, call, err);
|
|
}
|
|
else {
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: internal problem (unexpected call type - reject PDU)\n");
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
}
|
|
else
|
|
goto exit_with_error;
|
|
}
|
|
else if (tag == 0xa1) { /* confirmed response PDU */
|
|
|
|
int length;
|
|
int bufPos = 1;
|
|
|
|
bufPos = BerDecoder_decodeLength(buf, &length, bufPos, payload->size);
|
|
if (bufPos < 0)
|
|
goto exit_with_error;
|
|
|
|
if (buf[bufPos++] == 0x02) {
|
|
int invokeIdLength;
|
|
|
|
bufPos = BerDecoder_decodeLength(buf, &invokeIdLength, bufPos, payload->size);
|
|
if (bufPos < 0)
|
|
goto exit_with_error;
|
|
|
|
uint32_t invokeId =
|
|
BerDecoder_decodeUint32(buf, invokeIdLength, bufPos);
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: mms_client_connection: rcvd confirmed resp - invokeId: %u length: %i bufLen: %i\n",
|
|
invokeId, length, payload->size);
|
|
|
|
bufPos += invokeIdLength;
|
|
|
|
MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
|
|
|
|
if (call) {
|
|
|
|
if (call->type != MMS_CALL_TYPE_NONE) {
|
|
handleAsyncResponse(self, payload, bufPos, call, MMS_ERROR_NONE);
|
|
}
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: internal problem (unexpected call type - confirmed response PDU)\n");
|
|
}
|
|
}
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: unexpected message from server!\n");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
goto exit_with_error;
|
|
}
|
|
#if (MMS_OBTAIN_FILE_SERVICE == 1)
|
|
else if (tag == 0xa0) {
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received confirmed request PDU (size=%i)\n", payload->size);
|
|
|
|
/* TODO extract function */
|
|
|
|
int bufPos = 1;
|
|
int length;
|
|
|
|
bufPos = BerDecoder_decodeLength(buf, &length, bufPos, payload->size);
|
|
if (bufPos < 0)
|
|
goto exit_with_error;
|
|
|
|
bool hasInvokeId = false;
|
|
uint32_t invokeId = 0;
|
|
|
|
while (bufPos < payload->size) {
|
|
|
|
uint8_t nestedTag = buf[bufPos++];
|
|
|
|
bool extendedTag = false;
|
|
|
|
if ((nestedTag & 0x1f) == 0x1f) {
|
|
extendedTag = true;
|
|
nestedTag = buf[bufPos++];
|
|
}
|
|
|
|
bufPos = BerDecoder_decodeLength(buf, &length, bufPos, payload->size);
|
|
if (bufPos < 0)
|
|
goto exit_with_error;
|
|
|
|
if (extendedTag) {
|
|
|
|
if (hasInvokeId == false) {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: invalid message received - missing invoke ID!\n");
|
|
|
|
goto exit_with_error;
|
|
}
|
|
|
|
switch (nestedTag)
|
|
{
|
|
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
case 0x48: /* file-open-request */
|
|
{
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received file-open-request\n");
|
|
|
|
ByteBuffer* response = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
mmsClient_handleFileOpenRequest(self, buf, bufPos, bufPos + length, invokeId, response);
|
|
|
|
IsoClientConnection_sendMessage(self->isoClient, response);
|
|
}
|
|
break;
|
|
|
|
case 0x49: /* file-read-request */
|
|
{
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received file-read-request\n");
|
|
|
|
ByteBuffer* response = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
mmsClient_handleFileReadRequest(self, buf, bufPos, bufPos + length, invokeId, response);
|
|
|
|
IsoClientConnection_sendMessage(self->isoClient, response);
|
|
}
|
|
break;
|
|
|
|
case 0x4a: /* file-close-request */
|
|
{
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received file-close-request\n");
|
|
|
|
ByteBuffer* response = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
mmsClient_handleFileCloseRequest(self, buf, bufPos, bufPos + length, invokeId, response);
|
|
|
|
IsoClientConnection_sendMessage(self->isoClient, response);
|
|
}
|
|
break;
|
|
#endif /* MMS_FILE_SERVICE == 1 */
|
|
|
|
default:
|
|
/* mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); */
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: unexpected message from server!\n");
|
|
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
switch (nestedTag)
|
|
{
|
|
case 0x02: /* invoke Id */
|
|
invokeId = BerDecoder_decodeUint32(buf, length, bufPos);
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received request with invokeId: %u\n", invokeId);
|
|
|
|
hasInvokeId = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
/* mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response); */
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: unexpected message from server!\n");
|
|
|
|
goto exit_with_error;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
bufPos += length;
|
|
}
|
|
|
|
}
|
|
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
|
|
else {
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: unknown message type\n");
|
|
|
|
goto exit_with_error;
|
|
}
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: LEAVE mmsIsoCallback - OK\n");
|
|
|
|
return true;
|
|
|
|
exit_with_error:
|
|
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: received malformed message from server!\n");
|
|
|
|
return false;
|
|
}
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
|
static void*
|
|
connectionHandlingThread(void* parameter)
|
|
{
|
|
MmsConnection self = (MmsConnection) parameter;
|
|
|
|
while (self->connectionThreadRunning) {
|
|
if (MmsConnection_tick(self))
|
|
Thread_sleep(10);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */
|
|
|
|
static MmsConnection
|
|
MmsConnection_createInternal(TLSConfiguration tlsConfig, bool createThread)
|
|
{
|
|
#if (CONFIG_MMS_THREADLESS_STACK == 1)
|
|
if (createThread)
|
|
return NULL;
|
|
#endif
|
|
|
|
MmsConnection self = (MmsConnection) GLOBAL_CALLOC(1, sizeof(struct sMmsConnection));
|
|
|
|
if (self) {
|
|
|
|
self->parameters.dataStructureNestingLevel = -1;
|
|
self->parameters.maxServOutstandingCalled = -1;
|
|
self->parameters.maxServOutstandingCalling = -1;
|
|
self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
|
|
|
|
self->requestTimeout = CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT;
|
|
|
|
self->nextInvokeIdLock = Semaphore_create(1);
|
|
self->outstandingCallsLock = Semaphore_create(1);
|
|
|
|
self->associationStateLock = Semaphore_create(1);
|
|
self->connectionState = MMS_CONNECTION_STATE_CLOSED;
|
|
|
|
self->concludeHandler = NULL;
|
|
self->concludeHandlerParameter = NULL;
|
|
self->concludeTimeout = 0;
|
|
|
|
self->outstandingCalls = (MmsOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sMmsOutstandingCall));
|
|
|
|
self->isoParameters = IsoConnectionParameters_create();
|
|
|
|
/* Load default values for connection parameters */
|
|
TSelector tSelector = { 2, { 0, 1 } };
|
|
SSelector sSelector = { 2, { 0, 1 } };
|
|
PSelector pSelector = { 4, { 0, 0, 0, 1 } };
|
|
|
|
IsoConnectionParameters_setLocalAddresses(self->isoParameters, pSelector, sSelector, tSelector);
|
|
IsoConnectionParameters_setLocalApTitle(self->isoParameters, "1.1.1.999", 12);
|
|
IsoConnectionParameters_setRemoteAddresses(self->isoParameters, pSelector, sSelector, tSelector);
|
|
IsoConnectionParameters_setRemoteApTitle(self->isoParameters, "1.1.1.999.1", 12);
|
|
|
|
self->connectTimeout = CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT;
|
|
|
|
self->isoClient = IsoClientConnection_create(self->isoParameters, (IsoIndicationCallback) mmsIsoCallback, (void*) self);
|
|
|
|
#if (CONFIG_MMS_SUPPORT_TLS == 1)
|
|
if (tlsConfig) {
|
|
IsoConnectionParameters_setTlsConfiguration(self->isoParameters, tlsConfig);
|
|
}
|
|
#else
|
|
(void)tlsConfig;
|
|
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
|
self->createThread = createThread;
|
|
self->connectionHandlingThread = NULL;
|
|
self->connectionThreadRunning = false;
|
|
#endif
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
MmsConnection
|
|
MmsConnection_create()
|
|
{
|
|
return MmsConnection_createInternal(NULL, true);
|
|
}
|
|
|
|
MmsConnection
|
|
MmsConnection_createSecure(TLSConfiguration tlsConfig)
|
|
{
|
|
return MmsConnection_createInternal(tlsConfig, true);
|
|
}
|
|
|
|
MmsConnection
|
|
MmsConnection_createNonThreaded(TLSConfiguration tlsConfig)
|
|
{
|
|
return MmsConnection_createInternal(tlsConfig, false);
|
|
}
|
|
|
|
void
|
|
MmsConnection_destroy(MmsConnection self)
|
|
{
|
|
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
|
if (self->createThread) {
|
|
if (self->connectionHandlingThread) {
|
|
if (self->connectionThreadRunning) {
|
|
self->connectionThreadRunning = false;
|
|
Thread_destroy(self->connectionHandlingThread);
|
|
self->connectionHandlingThread = NULL;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (self->isoClient != NULL)
|
|
IsoClientConnection_destroy(self->isoClient);
|
|
|
|
if (self->isoParameters != NULL)
|
|
IsoConnectionParameters_destroy(self->isoParameters);
|
|
|
|
Semaphore_destroy(self->nextInvokeIdLock);
|
|
|
|
Semaphore_destroy(self->outstandingCallsLock);
|
|
|
|
Semaphore_destroy(self->associationStateLock);
|
|
|
|
GLOBAL_FREEMEM(self->outstandingCalls);
|
|
|
|
#if (MMS_OBTAIN_FILE_SERVICE == 1)
|
|
#if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1)
|
|
if (self->filestoreBasepath != NULL)
|
|
GLOBAL_FREEMEM(self->filestoreBasepath);
|
|
#endif
|
|
|
|
/* Close outstanding open files */
|
|
mmsClient_closeOutstandingOpenFiles(self);
|
|
#endif
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
}
|
|
|
|
void
|
|
MmsConnection_setFilestoreBasepath(MmsConnection self, const char* basepath)
|
|
{
|
|
#if (MMS_OBTAIN_FILE_SERVICE == 1)
|
|
#if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1)
|
|
if (self->filestoreBasepath != NULL) {
|
|
GLOBAL_FREEMEM(self->filestoreBasepath);
|
|
self->filestoreBasepath = NULL;
|
|
}
|
|
|
|
if (basepath != NULL)
|
|
self->filestoreBasepath = StringUtils_copyString(basepath);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
char*
|
|
MmsConnection_getFilestoreBasepath(MmsConnection self)
|
|
{
|
|
#if (MMS_OBTAIN_FILE_SERVICE == 1)
|
|
#if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1)
|
|
if (self->filestoreBasepath != NULL)
|
|
return self->filestoreBasepath;
|
|
else
|
|
return CONFIG_VIRTUAL_FILESTORE_BASEPATH;
|
|
#else
|
|
return CONFIG_VIRTUAL_FILESTORE_BASEPATH;
|
|
#endif
|
|
|
|
#else
|
|
return CONFIG_VIRTUAL_FILESTORE_BASEPATH;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_setRawMessageHandler(MmsConnection self, MmsRawMessageHandler handler, void* parameter)
|
|
{
|
|
#if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1)
|
|
self->rawMmsMessageHandler = (void*) handler;
|
|
self->rawMmsMessageHandlerParameter = parameter;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_setConnectionLostHandler(MmsConnection self, MmsConnectionLostHandler handler, void* handlerParameter)
|
|
{
|
|
self->connectionLostHandler = handler;
|
|
self->connectionLostHandlerParameter = handlerParameter;
|
|
}
|
|
|
|
void
|
|
MmsConnection_setConnectionStateChangedHandler(MmsConnection self, MmsConnectionStateChangedHandler handler, void* parameter)
|
|
{
|
|
self->stateChangedHandler = handler;
|
|
self->stateChangedHandlerParameter = parameter;
|
|
}
|
|
|
|
void
|
|
MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs)
|
|
{
|
|
self->requestTimeout = timeoutInMs;
|
|
}
|
|
|
|
uint32_t
|
|
MmsConnection_getRequestTimeout(MmsConnection self)
|
|
{
|
|
return self->requestTimeout;
|
|
}
|
|
|
|
void
|
|
MmsConnection_setConnectTimeout(MmsConnection self, uint32_t timeoutInMs)
|
|
{
|
|
self->connectTimeout = timeoutInMs;
|
|
}
|
|
|
|
void
|
|
MmsConnection_setLocalDetail(MmsConnection self, int32_t localDetail)
|
|
{
|
|
self->parameters.maxPduSize = localDetail;
|
|
}
|
|
|
|
int32_t
|
|
MmsConnection_getLocalDetail(MmsConnection self)
|
|
{
|
|
return self->parameters.maxPduSize;
|
|
}
|
|
|
|
IsoConnectionParameters
|
|
MmsConnection_getIsoConnectionParameters(MmsConnection self)
|
|
{
|
|
return self->isoParameters;
|
|
}
|
|
|
|
MmsConnectionParameters
|
|
MmsConnection_getMmsConnectionParameters(MmsConnection self)
|
|
{
|
|
return self->parameters;
|
|
}
|
|
|
|
struct connectParameters
|
|
{
|
|
Semaphore sem;
|
|
MmsConnectionState state;
|
|
MmsConnectionStateChangedHandler originalHandler;
|
|
void* originalParameter;
|
|
};
|
|
|
|
static void
|
|
internalConnectionStateChangedHandler (MmsConnection connection, void* parameter, MmsConnectionState newState)
|
|
{
|
|
struct connectParameters* conParams = (struct connectParameters*) parameter;
|
|
|
|
if ((newState == MMS_CONNECTION_STATE_CLOSED) || (newState == MMS_CONNECTION_STATE_CONNECTED))
|
|
{
|
|
conParams->state = newState;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(conParams->sem);
|
|
}
|
|
else {
|
|
if (conParams->originalHandler)
|
|
conParams->originalHandler(connection, conParams->originalParameter, newState);
|
|
}
|
|
}
|
|
|
|
bool
|
|
MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort)
|
|
{
|
|
bool success = false;
|
|
|
|
struct connectParameters conParams;
|
|
|
|
conParams.sem = Semaphore_create(1);
|
|
conParams.state = MMS_CONNECTION_STATE_CONNECTING;
|
|
conParams.originalHandler = self->stateChangedHandler;
|
|
conParams.originalParameter = self->stateChangedHandlerParameter;
|
|
|
|
Semaphore_wait(conParams.sem);
|
|
|
|
self->stateChangedHandler = internalConnectionStateChangedHandler;
|
|
self->stateChangedHandlerParameter = &conParams;
|
|
|
|
MmsError err;
|
|
|
|
MmsConnection_connectAsync(self, &err, serverName, serverPort);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(conParams.sem);
|
|
|
|
if (conParams.state == MMS_CONNECTION_STATE_CONNECTED) {
|
|
*mmsError = MMS_ERROR_NONE;
|
|
success = true;
|
|
}
|
|
else {
|
|
*mmsError = MMS_ERROR_CONNECTION_REJECTED;
|
|
}
|
|
|
|
if (conParams.originalHandler)
|
|
conParams.originalHandler(self, conParams.originalParameter, conParams.state);
|
|
|
|
}
|
|
else {
|
|
*mmsError = err;
|
|
}
|
|
|
|
Semaphore_destroy(conParams.sem);
|
|
|
|
self->stateChangedHandler = conParams.originalHandler;
|
|
self->stateChangedHandlerParameter = conParams.originalParameter;
|
|
|
|
return success;
|
|
}
|
|
|
|
void
|
|
MmsConnection_connectAsync(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort)
|
|
{
|
|
if (serverPort == -1) {
|
|
#if (CONFIG_MMS_SUPPORT_TLS == 1)
|
|
if (self->isoParameters->tlsConfiguration)
|
|
serverPort = 3782;
|
|
else
|
|
serverPort = 102;
|
|
#else
|
|
serverPort = 102;
|
|
#endif
|
|
}
|
|
|
|
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
|
if (self->createThread) {
|
|
if (self->connectionHandlingThread == NULL) {
|
|
|
|
self->connectionHandlingThread = Thread_create(connectionHandlingThread, self, false);
|
|
self->connectionThreadRunning = true;
|
|
Thread_start(self->connectionHandlingThread);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
IsoConnectionParameters_setTcpParameters(self->isoParameters, serverName, serverPort);
|
|
|
|
if (self->parameters.maxPduSize == -1)
|
|
self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE;
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
mmsClient_createInitiateRequest(self, payload);
|
|
|
|
#if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1)
|
|
if (self->rawMmsMessageHandler != NULL) {
|
|
MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler;
|
|
handler(self->rawMmsMessageHandlerParameter, payload->buffer, payload->size, false);
|
|
}
|
|
#endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */
|
|
|
|
if (IsoClientConnection_associateAsync(self->isoClient, self->connectTimeout, self->requestTimeout)) {
|
|
setConnectionState(self, MMS_CONNECTION_STATE_CONNECTING);
|
|
*mmsError = MMS_ERROR_NONE;
|
|
}
|
|
else {
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
}
|
|
}
|
|
|
|
bool
|
|
MmsConnection_tick(MmsConnection self)
|
|
{
|
|
return IsoClientConnection_handleConnection(self->isoClient);
|
|
}
|
|
|
|
void
|
|
MmsConnection_close(MmsConnection self)
|
|
{
|
|
self->connectionLostHandler = NULL;
|
|
|
|
if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED)
|
|
IsoClientConnection_close(self->isoClient);
|
|
}
|
|
|
|
void
|
|
MmsConnection_abortAsync(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
self->connectionLostHandler = NULL;
|
|
|
|
if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED) {
|
|
IsoClientConnection_abortAsync(self->isoClient);
|
|
*mmsError = MMS_ERROR_NONE;
|
|
}
|
|
else {
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
}
|
|
}
|
|
|
|
void
|
|
MmsConnection_abort(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
*mmsError = MMS_ERROR_NONE;
|
|
|
|
self->connectionLostHandler = NULL;
|
|
|
|
bool success = false;
|
|
|
|
if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED) {
|
|
|
|
IsoClientConnection_abortAsync(self->isoClient);
|
|
|
|
uint64_t timeout = Hal_getTimeInMs() + self->requestTimeout;
|
|
|
|
while (Hal_getTimeInMs() < timeout) {
|
|
if (getConnectionState(self) == MMS_CONNECTION_STATE_CLOSED) {
|
|
success = true;
|
|
break;
|
|
}
|
|
else {
|
|
Thread_sleep(10);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (success == false) {
|
|
IsoClientConnection_close(self->isoClient);
|
|
*mmsError = MMS_ERROR_SERVICE_TIMEOUT;
|
|
}
|
|
|
|
IsoClientConnection_close(self->isoClient);
|
|
}
|
|
|
|
struct concludeParameters
|
|
{
|
|
Semaphore sem;
|
|
MmsError err;
|
|
bool success;
|
|
};
|
|
|
|
static void
|
|
concludeHandler(void* parameter, MmsError mmsError, bool success)
|
|
{
|
|
struct concludeParameters* parameters = (struct concludeParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->success = success;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->sem);
|
|
}
|
|
|
|
void
|
|
MmsConnection_conclude(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct concludeParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.success = false;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_concludeAsync(self, &err, concludeHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
}
|
|
|
|
void
|
|
MmsConnection_concludeAsync(MmsConnection self, MmsError* mmsError, MmsConnection_ConcludeAbortHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
*mmsError = MMS_ERROR_NONE;
|
|
|
|
ByteBuffer* concludeMessage = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
mmsClient_createConcludeRequest(self, concludeMessage);
|
|
|
|
self->concludeHandler = handler;
|
|
self->concludeHandlerParameter = parameter;
|
|
self->concludeTimeout = Hal_getTimeInMs() + self->requestTimeout;
|
|
|
|
IsoClientConnection_sendMessage(self->isoClient, concludeMessage);
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
void
|
|
MmsConnection_setInformationReportHandler(MmsConnection self, MmsInformationReportHandler handler,
|
|
void* parameter)
|
|
{
|
|
self->reportHandler = handler;
|
|
self->reportHandlerParameter = parameter;
|
|
}
|
|
|
|
static void
|
|
mmsClient_getNameListSingleRequestAsync(
|
|
MmsConnection self,
|
|
uint32_t* usedInvokeId,
|
|
MmsError* mmsError,
|
|
const char* domainId,
|
|
MmsObjectClass objectClass,
|
|
bool associationSpecific,
|
|
const char* continueAfter,
|
|
MmsConnection_GetNameListHandler handler,
|
|
void* parameter,
|
|
LinkedList nameList)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
if (associationSpecific)
|
|
mmsClient_createMmsGetNameListRequestAssociationSpecific(invokeId,
|
|
payload, continueAfter);
|
|
else {
|
|
|
|
if (objectClass == MMS_OBJECT_CLASS_DOMAIN)
|
|
mmsClient_createMmsGetNameListRequestVMDspecific(invokeId,
|
|
payload, continueAfter);
|
|
else
|
|
mmsClient_createGetNameListRequestDomainOrVMDSpecific(invokeId, domainId,
|
|
payload, objectClass, continueAfter);
|
|
}
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = nameList;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_NAME_LIST, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct getNameListParameters
|
|
{
|
|
Semaphore sem;
|
|
MmsError err;
|
|
LinkedList nameList;
|
|
bool moreFollows;
|
|
};
|
|
|
|
static void
|
|
getNameListHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList nameList, bool moreFollows)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct getNameListParameters* parameters = (struct getNameListParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->nameList = nameList;
|
|
parameters->moreFollows = moreFollows;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->sem);
|
|
}
|
|
|
|
|
|
static LinkedList /* <char*> */
|
|
mmsClient_getNameList(MmsConnection self, MmsError *mmsError,
|
|
const char* domainId,
|
|
MmsObjectClass objectClass,
|
|
bool associationSpecific)
|
|
{
|
|
LinkedList list = NULL;
|
|
bool moreFollows = false;
|
|
|
|
struct getNameListParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.moreFollows = false;
|
|
parameter.nameList = NULL;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
mmsClient_getNameListSingleRequestAsync(self, NULL, &err, domainId, objectClass, associationSpecific, NULL,
|
|
getNameListHandler, ¶meter, NULL);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
err = parameter.err;
|
|
list = parameter.nameList;
|
|
moreFollows = parameter.moreFollows;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
while (moreFollows) {
|
|
parameter.sem = Semaphore_create(1);
|
|
|
|
char* continueAfter = NULL;
|
|
|
|
if (list)
|
|
continueAfter = (char*) LinkedList_getLastElement(list)->data;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
mmsClient_getNameListSingleRequestAsync(self, NULL, &err, domainId, objectClass, associationSpecific, continueAfter,
|
|
getNameListHandler, ¶meter, list);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
err = parameter.err;
|
|
list = parameter.nameList;
|
|
moreFollows = parameter.moreFollows;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
}
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
if (err != MMS_ERROR_NONE) {
|
|
if (list) {
|
|
LinkedList_destroy(list);
|
|
list = NULL;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
LinkedList /* <char*> */
|
|
MmsConnection_getVMDVariableNames(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
return mmsClient_getNameList(self, mmsError, NULL, MMS_OBJECT_CLASS_NAMED_VARIABLE, false);
|
|
}
|
|
|
|
void
|
|
MmsConnection_getVMDVariableNamesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* continueAfter,
|
|
MmsConnection_GetNameListHandler handler, void* parameter)
|
|
{
|
|
mmsClient_getNameListSingleRequestAsync(self, usedInvokeId, mmsError, NULL, MMS_OBJECT_CLASS_NAMED_VARIABLE,
|
|
false, continueAfter, handler, parameter, NULL);
|
|
}
|
|
|
|
LinkedList /* <char*> */
|
|
MmsConnection_getDomainNames(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
return mmsClient_getNameList(self, mmsError, NULL, MMS_OBJECT_CLASS_DOMAIN, false);
|
|
}
|
|
|
|
void
|
|
MmsConnection_getDomainNamesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* continueAfter, LinkedList result,
|
|
MmsConnection_GetNameListHandler handler, void* parameter)
|
|
{
|
|
mmsClient_getNameListSingleRequestAsync(self, usedInvokeId, mmsError, NULL, MMS_OBJECT_CLASS_DOMAIN, false,
|
|
continueAfter, handler, parameter, result);
|
|
}
|
|
|
|
LinkedList /* <char*> */
|
|
MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, const char* domainId)
|
|
{
|
|
return mmsClient_getNameList(self, mmsError, domainId, MMS_OBJECT_CLASS_NAMED_VARIABLE, false);
|
|
}
|
|
|
|
void
|
|
MmsConnection_getDomainVariableNamesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId,
|
|
const char* continueAfter, LinkedList result, MmsConnection_GetNameListHandler handler, void* parameter)
|
|
{
|
|
mmsClient_getNameListSingleRequestAsync(self, usedInvokeId, mmsError, domainId, MMS_OBJECT_CLASS_NAMED_VARIABLE, false,
|
|
continueAfter, handler, parameter, result);
|
|
}
|
|
|
|
LinkedList /* <char*> */
|
|
MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, const char* domainId)
|
|
{
|
|
return mmsClient_getNameList(self, mmsError, domainId, MMS_OBJECT_CLASS_NAMED_VARIABLE_LIST, false);
|
|
}
|
|
|
|
void
|
|
MmsConnection_getDomainVariableListNamesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId,
|
|
const char* continueAfter, LinkedList result, MmsConnection_GetNameListHandler handler, void* parameter)
|
|
{
|
|
mmsClient_getNameListSingleRequestAsync(self, usedInvokeId, mmsError, domainId, MMS_OBJECT_CLASS_NAMED_VARIABLE_LIST, false,
|
|
continueAfter, handler, parameter, result);
|
|
}
|
|
|
|
LinkedList /* <char*> */
|
|
MmsConnection_getDomainJournals(MmsConnection self, MmsError* mmsError, const char* domainId)
|
|
{
|
|
return mmsClient_getNameList(self, mmsError, domainId, MMS_OBJECT_CLASS_JOURNAL, false);
|
|
}
|
|
|
|
void
|
|
MmsConnection_getDomainJournalsAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId,
|
|
const char* continueAfter, MmsConnection_GetNameListHandler handler, void* parameter)
|
|
{
|
|
mmsClient_getNameListSingleRequestAsync(self, usedInvokeId, mmsError, domainId, MMS_OBJECT_CLASS_JOURNAL, false,
|
|
continueAfter, handler, parameter, NULL);
|
|
}
|
|
|
|
LinkedList /* <char*> */
|
|
MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
return mmsClient_getNameList(self, mmsError, NULL, MMS_OBJECT_CLASS_NAMED_VARIABLE_LIST, true);
|
|
}
|
|
|
|
void
|
|
MmsConnection_getVariableListNamesAssociationSpecificAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* continueAfter, MmsConnection_GetNameListHandler handler, void* parameter)
|
|
{
|
|
mmsClient_getNameListSingleRequestAsync(self, usedInvokeId, mmsError, NULL, MMS_OBJECT_CLASS_NAMED_VARIABLE_LIST, true,
|
|
continueAfter, handler, parameter, NULL);
|
|
}
|
|
|
|
|
|
struct readNVParameters
|
|
{
|
|
Semaphore sem;
|
|
MmsError err;
|
|
MmsValue* value;
|
|
};
|
|
|
|
static void
|
|
readVariableHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsValue* value)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct readNVParameters* parameters = (struct readNVParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->value = value;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->sem);
|
|
}
|
|
|
|
void
|
|
MmsConnection_readVariableAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadRequest(invokeId, domainId, itemId, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readVariable(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readVariableAsync(self, NULL, &err, domainId, itemId, readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readVariableComponentAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, const char* componentId,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadRequestComponent(invokeId, domainId, itemId, componentId, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readVariableComponent(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, const char* componentId)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readVariableComponentAsync(self, NULL, &err, domainId, itemId, componentId, readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId,
|
|
uint32_t startIndex, uint32_t numberOfElements)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readArrayElementsAsync(self, NULL, &err, domainId, itemId, startIndex, numberOfElements,
|
|
readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readArrayElementsAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId,
|
|
uint32_t startIndex, uint32_t numberOfElements,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadRequestAlternateAccessIndex(invokeId, domainId, itemId, startIndex,
|
|
numberOfElements, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, uint32_t index, const char* componentId)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readSingleArrayElementWithComponentAsync(self, NULL, &err, domainId, itemId, index, componentId,
|
|
readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readSingleArrayElementWithComponentAsync(MmsConnection self, uint32_t* usedInvokeId,
|
|
MmsError* mmsError,
|
|
const char* domainId, const char* itemId,
|
|
uint32_t index, const char* componentId,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, index, componentId,
|
|
payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, LinkedList /*<char*>*/items)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readMultipleVariablesAsync(self, NULL, &err, domainId, items,
|
|
readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, LinkedList /*<char*>*/items,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
if (mmsClient_createReadRequestMultipleValues(invokeId, domainId, items, payload) > 0) {
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
}
|
|
else {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE;
|
|
}
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* listName,
|
|
bool specWithResult)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readNamedVariableListValuesAsync(self, NULL, &err, domainId, listName, specWithResult,
|
|
readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readNamedVariableListValuesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* listName, bool specWithResult,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadNamedVariableListRequest(invokeId, domainId, listName,
|
|
payload, specWithResult);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsConnection_readNamedVariableListValuesAssociationSpecific(
|
|
MmsConnection self, MmsError* mmsError,
|
|
const char* listName,
|
|
bool specWithResult)
|
|
{
|
|
MmsValue* value = NULL;
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct readNVParameters parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.value = NULL;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(self, NULL, &err, listName, specWithResult,
|
|
readVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
value = parameter.value;
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return value;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* listName, bool specWithResult,
|
|
MmsConnection_ReadVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadAssociationSpecificNamedVariableListRequest(invokeId, listName,
|
|
payload, specWithResult);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct readNVLDirectoryParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
LinkedList specs;
|
|
bool deletable;
|
|
};
|
|
|
|
static void
|
|
readNVLDirectoryHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsVariableAccessSpecification*> */ specs, bool deletable)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct readNVLDirectoryParameters* parameters = (struct readNVLDirectoryParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->deletable = deletable;
|
|
parameters->specs = specs;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
LinkedList /* <MmsVariableAccessSpecification*> */
|
|
MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* listName, bool* deletable)
|
|
{
|
|
LinkedList specs = NULL;
|
|
|
|
Semaphore waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(waitForResponse);
|
|
|
|
struct readNVLDirectoryParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = waitForResponse;
|
|
|
|
MmsConnection_readNamedVariableListDirectoryAsync(self, NULL, &err, domainId, listName,
|
|
readNVLDirectoryHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(waitForResponse);
|
|
err = parameter.err;
|
|
specs = parameter.specs;
|
|
|
|
if (deletable)
|
|
*deletable = parameter.deletable;
|
|
}
|
|
|
|
Semaphore_destroy(waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return specs;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readNamedVariableListDirectoryAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* listName,
|
|
MmsConnection_ReadNVLDirectoryHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createGetNamedVariableListAttributesRequest(invokeId, payload, domainId,
|
|
listName);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_NVL_DIRECTORY, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
LinkedList /* <MmsVariableAccessSpecification*> */
|
|
MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection self, MmsError* mmsError,
|
|
const char* listName, bool* deletable)
|
|
{
|
|
LinkedList specs = NULL;
|
|
|
|
Semaphore waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(waitForResponse);
|
|
|
|
struct readNVLDirectoryParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = waitForResponse;
|
|
|
|
MmsConnection_readNamedVariableListDirectoryAssociationSpecificAsync(self, NULL, &err, listName,
|
|
readNVLDirectoryHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(waitForResponse);
|
|
err = parameter.err;
|
|
specs = parameter.specs;
|
|
|
|
if (deletable)
|
|
*deletable = parameter.deletable;
|
|
}
|
|
|
|
Semaphore_destroy(waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return specs;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readNamedVariableListDirectoryAssociationSpecificAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* listName,
|
|
MmsConnection_ReadNVLDirectoryHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(invokeId, payload,
|
|
listName);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_NVL_DIRECTORY, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct defineNVLParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
bool success;
|
|
};
|
|
|
|
static void
|
|
defineNVLHandler(uint32_t invokeId, void* parameter, MmsError mmsError, bool success)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct defineNVLParameters* parameters = (struct defineNVLParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->success = success;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
|
|
void
|
|
MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* listName, LinkedList variableSpecs)
|
|
{
|
|
struct defineNVLParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_defineNamedVariableListAsync(self, NULL, &err, domainId, listName, variableSpecs,
|
|
defineNVLHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
}
|
|
|
|
void
|
|
MmsConnection_defineNamedVariableListAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId,
|
|
const char* listName, LinkedList variableSpecs,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createDefineNamedVariableListRequest(invokeId, payload, domainId,
|
|
listName, variableSpecs, false);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DEFINE_NVL, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
void
|
|
MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self,
|
|
MmsError* mmsError, const char* listName, LinkedList variableSpecs)
|
|
{
|
|
struct defineNVLParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_defineNamedVariableListAssociationSpecificAsync(self, NULL, &err, listName, variableSpecs,
|
|
defineNVLHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
}
|
|
|
|
void
|
|
MmsConnection_defineNamedVariableListAssociationSpecificAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* listName, LinkedList variableSpecs,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createDefineNamedVariableListRequest(invokeId, payload, NULL,
|
|
listName, variableSpecs, true);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DEFINE_NVL, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
bool
|
|
MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* listName)
|
|
{
|
|
bool isDeleted = false;
|
|
|
|
struct defineNVLParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_deleteNamedVariableListAsync(self, NULL, &err, domainId, listName, defineNVLHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
isDeleted = parameter.success;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return isDeleted;
|
|
}
|
|
|
|
void
|
|
MmsConnection_deleteNamedVariableListAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* listName,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createDeleteNamedVariableListRequest(invokeId, payload, domainId, listName);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DELETE_NVL, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
bool
|
|
MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self,
|
|
MmsError* mmsError, const char* listName)
|
|
{
|
|
bool isDeleted = false;
|
|
|
|
struct defineNVLParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_deleteAssociationSpecificNamedVariableListAsync(self, NULL, &err, listName, defineNVLHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
isDeleted = parameter.success;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return isDeleted;
|
|
}
|
|
|
|
void
|
|
MmsConnection_deleteAssociationSpecificNamedVariableListAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* listName,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createDeleteAssociationSpecificNamedVariableListRequest(
|
|
invokeId, payload, listName);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DELETE_NVL, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct getVarAccessAttrParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
MmsVariableSpecification* typeSpec;
|
|
};
|
|
|
|
static void
|
|
getAccessAttrHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsVariableSpecification* typeSpec)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct getVarAccessAttrParameters* parameters = (struct getVarAccessAttrParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->typeSpec = typeSpec;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
MmsVariableSpecification*
|
|
MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId)
|
|
{
|
|
MmsVariableSpecification* typeSpec = NULL;
|
|
|
|
struct getVarAccessAttrParameters parameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_getVariableAccessAttributesAsync(self, NULL, &err, domainId, itemId, getAccessAttrHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
typeSpec = parameter.typeSpec;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return typeSpec;
|
|
}
|
|
|
|
void
|
|
MmsConnection_getVariableAccessAttributesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* itemId,
|
|
MmsConnection_GetVariableAccessAttributesHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createGetVariableAccessAttributesRequest(invokeId, domainId, itemId, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_VAR_ACCESS_ATTR, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct identifyParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
MmsServerIdentity* identify;
|
|
};
|
|
|
|
static void
|
|
identifyHandler(uint32_t invokeId, void* parameter, MmsError mmsError, char* vendorName, char* modelName, char* revision)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct identifyParameters* parameters = (struct identifyParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
|
|
parameters->identify = (MmsServerIdentity*) GLOBAL_MALLOC(sizeof(MmsServerIdentity));
|
|
parameters->identify->vendorName = StringUtils_copyString(vendorName);
|
|
parameters->identify->modelName = StringUtils_copyString(modelName);
|
|
parameters->identify->revision = StringUtils_copyString(revision);
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
|
|
MmsServerIdentity*
|
|
MmsConnection_identify(MmsConnection self, MmsError* mmsError)
|
|
{
|
|
MmsServerIdentity* identity = NULL;
|
|
|
|
struct identifyParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.identify = NULL;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_identifyAsync(self, NULL, &err, identifyHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
identity = parameter.identify;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return identity;
|
|
}
|
|
|
|
void
|
|
MmsConnection_identifyAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
MmsConnection_IdentifyHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createIdentifyRequest(invokeId, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_IDENTIFY, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct getServerStatusParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
int vmdLogicalStatus;
|
|
int vmdPhysicalStatus;
|
|
};
|
|
|
|
static void
|
|
getServerStatusHandler(uint32_t invokeId, void* parameter, MmsError mmsError, int vmdLogicalStatus, int vmdPhysicalStatus)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct getServerStatusParameters* parameters = (struct getServerStatusParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->vmdLogicalStatus = vmdLogicalStatus;
|
|
parameters->vmdPhysicalStatus = vmdPhysicalStatus;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
|
|
void
|
|
MmsConnection_getServerStatus(MmsConnection self, MmsError* mmsError, int* vmdLogicalStatus, int* vmdPhysicalStatus,
|
|
bool extendedDerivation)
|
|
{
|
|
struct getServerStatusParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.vmdLogicalStatus = 0;
|
|
parameter.vmdPhysicalStatus = 0;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_getServerStatusAsync(self, NULL, &err, extendedDerivation, getServerStatusHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
|
|
if (vmdLogicalStatus)
|
|
*vmdLogicalStatus = parameter.vmdLogicalStatus;
|
|
|
|
if (vmdPhysicalStatus)
|
|
*vmdPhysicalStatus = parameter.vmdPhysicalStatus;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
}
|
|
|
|
void
|
|
MmsConnection_getServerStatusAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, bool extendedDerivation,
|
|
MmsConnection_GetServerStatusHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createStatusRequest(invokeId, payload, extendedDerivation);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_SERVER_STATUS, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
MmsJournalVariable_destroy(MmsJournalVariable self)
|
|
{
|
|
if (self != NULL) {
|
|
GLOBAL_FREEMEM(self->tag);
|
|
MmsValue_delete(self->value);
|
|
GLOBAL_FREEMEM(self);
|
|
}
|
|
}
|
|
|
|
void
|
|
MmsJournalEntry_destroy(MmsJournalEntry self)
|
|
{
|
|
if (self != NULL) {
|
|
MmsValue_delete(self->entryID);
|
|
MmsValue_delete(self->occurenceTime);
|
|
LinkedList_destroyDeep(self->journalVariables,
|
|
(LinkedListValueDeleteFunction) MmsJournalVariable_destroy);
|
|
GLOBAL_FREEMEM(self);
|
|
}
|
|
}
|
|
|
|
MmsValue*
|
|
MmsJournalEntry_getEntryID(MmsJournalEntry self)
|
|
{
|
|
return self->entryID;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsJournalEntry_getOccurenceTime(MmsJournalEntry self)
|
|
{
|
|
return self->occurenceTime;
|
|
}
|
|
|
|
LinkedList /* <MmsJournalVariable> */
|
|
MmsJournalEntry_getJournalVariables(MmsJournalEntry self)
|
|
{
|
|
return self->journalVariables;
|
|
}
|
|
|
|
const char*
|
|
MmsJournalVariable_getTag(MmsJournalVariable self)
|
|
{
|
|
return self->tag;
|
|
}
|
|
|
|
MmsValue*
|
|
MmsJournalVariable_getValue(MmsJournalVariable self)
|
|
{
|
|
return self->value;
|
|
}
|
|
|
|
struct readJournalParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
LinkedList entries;
|
|
bool moreFollows;
|
|
};
|
|
|
|
static void
|
|
readJournalHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList entries, bool moreFollows)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct readJournalParameters* parameters = (struct readJournalParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->entries = entries;
|
|
parameters->moreFollows = moreFollows;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
|
|
LinkedList
|
|
MmsConnection_readJournalTimeRange(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
|
|
MmsValue* startTime, MmsValue* endTime, bool* moreFollows)
|
|
{
|
|
struct readJournalParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.entries = NULL;
|
|
parameter.moreFollows = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_readJournalTimeRangeAsync(self, NULL, &err, domainId, itemId, startTime, endTime, readJournalHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
|
|
if (moreFollows)
|
|
*moreFollows = parameter.moreFollows;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.entries;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readJournalTimeRangeAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId,
|
|
MmsValue* startTime, MmsValue* endTime, MmsConnection_ReadJournalHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
if ((MmsValue_getType(startTime) != MMS_BINARY_TIME) ||
|
|
(MmsValue_getType(endTime) != MMS_BINARY_TIME)) {
|
|
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_INVALID_ARGUMENTS;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadJournalRequestWithTimeRange(invokeId, payload, domainId, itemId, startTime, endTime);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_JOURNAL, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
LinkedList
|
|
MmsConnection_readJournalStartAfter(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId,
|
|
MmsValue* timeSpecification, MmsValue* entrySpecification, bool* moreFollows)
|
|
{
|
|
struct readJournalParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.entries = NULL;
|
|
parameter.moreFollows = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_readJournalStartAfterAsync(self, NULL, &err, domainId, itemId, timeSpecification, entrySpecification, readJournalHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
|
|
if (moreFollows)
|
|
*moreFollows = parameter.moreFollows;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.entries;
|
|
}
|
|
|
|
void
|
|
MmsConnection_readJournalStartAfterAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId,
|
|
MmsValue* timeSpecification, MmsValue* entrySpecification, MmsConnection_ReadJournalHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
if ((MmsValue_getType(timeSpecification) != MMS_BINARY_TIME) ||
|
|
(MmsValue_getType(entrySpecification) != MMS_OCTET_STRING)) {
|
|
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_INVALID_ARGUMENTS;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createReadJournalRequestStartAfter(invokeId, payload, domainId, itemId, timeSpecification, entrySpecification);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_JOURNAL, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct fileOpenParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
int32_t frsmId;
|
|
uint32_t fileSize;
|
|
uint64_t lastModified;
|
|
};
|
|
|
|
static void
|
|
fileOpenHandler(uint32_t invokeId, void* parameter, MmsError mmsError, int32_t frsmId, uint32_t fileSize, uint64_t lastModified)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct fileOpenParameters* parameters = (struct fileOpenParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->frsmId = frsmId;
|
|
parameters->fileSize = fileSize;
|
|
parameters->lastModified = lastModified;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
|
|
int32_t
|
|
MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filename, uint32_t initialPosition,
|
|
uint32_t* fileSize, uint64_t* lastModified)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
struct fileOpenParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.frsmId = 0;
|
|
parameter.fileSize = 0;
|
|
parameter.lastModified = 0;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_fileOpenAsync(self, NULL, &err, filename, initialPosition, fileOpenHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (fileSize)
|
|
*fileSize = parameter.fileSize;
|
|
|
|
if (lastModified)
|
|
*lastModified = parameter.lastModified;
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.frsmId;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileOpenAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* filename, uint32_t initialPosition, MmsConnection_FileOpenHandler handler,
|
|
void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createFileOpenRequest(invokeId, payload, filename, initialPosition);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_OPEN, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
struct fileOperationParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
bool success;
|
|
};
|
|
|
|
static void
|
|
fileOperationHandler(uint32_t invokeId, void* parameter, MmsError mmsError, bool success)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct fileOperationParameters* parameters = (struct fileOperationParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->success = success;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileClose(MmsConnection self, MmsError* mmsError, int32_t frsmId)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
struct fileOperationParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.success = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_fileCloseAsync(self, NULL, &err, frsmId, fileOperationHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileCloseAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, uint32_t frsmId, MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createFileCloseRequest(invokeId, payload, frsmId);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_CLOSE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, const char* fileName)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
struct fileOperationParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.success = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_fileDeleteAsync(self, NULL, &err, fileName, fileOperationHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileDeleteAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* fileName,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createFileDeleteRequest(invokeId, payload, fileName);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_DELETE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
struct fileReadParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
MmsFileReadHandler handler;
|
|
void* handlerParameter;
|
|
bool moreFollows;
|
|
};
|
|
|
|
static void
|
|
fileReadHandler(uint32_t invokeId, void* parameter, MmsError mmsError, int frsmId, uint8_t* buffer, uint32_t byteReceived,
|
|
bool moreFollows)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct fileReadParameters* parameters = (struct fileReadParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
|
|
if (mmsError == MMS_ERROR_NONE)
|
|
parameters->handler(parameters->handlerParameter, frsmId, buffer, byteReceived);
|
|
|
|
parameters->moreFollows = moreFollows;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
bool
|
|
MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, MmsFileReadHandler handler,
|
|
void* handlerParameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
struct fileReadParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.handler = handler;
|
|
parameter.handlerParameter = handlerParameter;
|
|
parameter.moreFollows = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_fileReadAsync(self, NULL, &err, frsmId, fileReadHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.moreFollows;
|
|
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileReadAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, int32_t frsmId, MmsConnection_FileReadHandler handler, void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createFileReadRequest(invokeId, payload, frsmId);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.i32 = frsmId;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_READ, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
struct getFileDirParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
bool moreFollows;
|
|
MmsFileDirectoryHandler handler;
|
|
void* handlerParameter;
|
|
};
|
|
|
|
static void
|
|
getFileDirHandler(uint32_t invokeId, void* parameter, MmsError mmsError, char* filename, uint32_t size, uint64_t lastModified,
|
|
bool moreFollows)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct getFileDirParameters* parameters = (struct getFileDirParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
|
|
if ((mmsError != MMS_ERROR_NONE) || (filename == NULL)) {
|
|
parameters->moreFollows = moreFollows;
|
|
|
|
/* last call --> unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
else {
|
|
parameters->handler(parameters->handlerParameter, filename, size, lastModified);
|
|
}
|
|
}
|
|
|
|
bool
|
|
MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, const char* fileSpecification, const char* continueAfter,
|
|
MmsFileDirectoryHandler handler, void* handlerParameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
bool moreFollows = false;
|
|
|
|
struct getFileDirParameters parameter;
|
|
parameter.handler = handler;
|
|
parameter.handlerParameter = handlerParameter;
|
|
|
|
MmsError err;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_getFileDirectoryAsync(self, NULL, &err, fileSpecification, continueAfter, getFileDirHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
err = parameter.err;
|
|
moreFollows = parameter.moreFollows;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return moreFollows;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_getFileDirectoryAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* fileSpecification, const char* continueAfter,
|
|
MmsConnection_FileDirectoryHandler handler, void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createFileDirectoryRequest(invokeId, payload, fileSpecification, continueAfter);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_FILE_DIR, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, const char* currentFileName, const char* newFileName)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
struct fileOperationParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.success = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_fileRenameAsync(self, NULL, &err, currentFileName, newFileName, fileOperationHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_fileRenameAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* currentFileName, const char* newFileName,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createFileRenameRequest(invokeId, payload, currentFileName, newFileName);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_RENAME, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MmsConnection_obtainFile(MmsConnection self, MmsError* mmsError, const char* sourceFile, const char* destinationFile)
|
|
{
|
|
#if ((MMS_FILE_SERVICE == 1) && (MMS_OBTAIN_FILE_SERVICE == 1))
|
|
|
|
struct fileOperationParameters parameter;
|
|
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
parameter.waitForResponse = Semaphore_create(1);
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.success = false;
|
|
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
MmsConnection_obtainFileAsync(self, NULL, &err, sourceFile, destinationFile, fileOperationHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
#endif
|
|
}
|
|
|
|
struct writeVariableParameters
|
|
{
|
|
Semaphore waitForResponse;
|
|
MmsError err;
|
|
MmsDataAccessError accessError;
|
|
};
|
|
|
|
void
|
|
MmsConnection_obtainFileAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* sourceFile, const char* destinationFile,
|
|
MmsConnection_GenericServiceHandler handler, void* parameter)
|
|
{
|
|
#if (MMS_FILE_SERVICE == 1)
|
|
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createObtainFileRequest(invokeId, payload, sourceFile, destinationFile);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
|
|
if (sourceFile)
|
|
intParam.ptr = StringUtils_copyString(sourceFile);
|
|
else
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_OBTAIN_FILE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
#else
|
|
if (DEBUG_MMS_CLIENT)
|
|
printf("MMS_CLIENT: service not supported\n");
|
|
|
|
*mmsError = MMS_ERROR_OTHER;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
writeVariableHandler(uint32_t invokeId, void* parameter, MmsError mmsError, MmsDataAccessError accessError)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct writeVariableParameters* parameters = (struct writeVariableParameters*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->accessError = accessError;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->waitForResponse);
|
|
}
|
|
|
|
MmsDataAccessError
|
|
MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId,
|
|
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_writeVariableAsync(self, NULL, &err, domainId, itemId, value, writeVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.accessError;
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeVariableAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, MmsValue* value,
|
|
MmsConnection_WriteVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createWriteRequest(invokeId, domainId, itemId, value, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
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, NULL, &err, domainId, itemId, arrayIndex, componentId, value, writeVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.accessError;
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* itemId,
|
|
uint32_t arrayIndex, const char* componentId, MmsValue* value,
|
|
MmsConnection_WriteVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, arrayIndex,
|
|
componentId, value, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsDataAccessError
|
|
MmsConnection_writeVariableComponent(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId,
|
|
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_writeVariableComponentAsync(self, NULL, &err, domainId, itemId, componentId, value, writeVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.accessError;
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeVariableComponentAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, const char* componentId, MmsValue* value,
|
|
MmsConnection_WriteVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createWriteRequestComponent(invokeId, domainId, itemId, componentId, value, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
struct writeMultipleVariablesParameter
|
|
{
|
|
Semaphore sem;
|
|
MmsError err;
|
|
LinkedList result;
|
|
};
|
|
|
|
static void
|
|
writeMultipleVariablesHandler(uint32_t invokeId, void* parameter, MmsError mmsError, LinkedList /* <MmsValue*> */ accessResults)
|
|
{
|
|
(void)invokeId;
|
|
|
|
struct writeMultipleVariablesParameter* parameters = (struct writeMultipleVariablesParameter*) parameter;
|
|
|
|
parameters->err = mmsError;
|
|
parameters->result = accessResults;
|
|
|
|
/* unblock user thread */
|
|
Semaphore_post(parameters->sem);
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId,
|
|
LinkedList /*<char*>*/items,
|
|
LinkedList /* <MmsValue*> */values,
|
|
/* OUTPUT */LinkedList* /* <MmsValue*> */accessResults)
|
|
{
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct writeMultipleVariablesParameter parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.result = NULL;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_writeMultipleVariablesAsync(self, NULL, &err, domainId, items, values, writeMultipleVariablesHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
err = parameter.err;
|
|
|
|
if (accessResults)
|
|
*accessResults = parameter.result;
|
|
else
|
|
LinkedList_destroyDeep(parameter.result, (LinkedListValueDeleteFunction) MmsValue_delete);
|
|
}
|
|
else {
|
|
if (accessResults)
|
|
*accessResults = NULL;
|
|
}
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId,
|
|
LinkedList /*<char*>*/ items, LinkedList /* <MmsValue*> */ values,
|
|
MmsConnection_WriteMultipleVariablesHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
if (mmsClient_createWriteMultipleItemsRequest(invokeId, domainId, items, values, payload) != -1) {
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
}
|
|
else {
|
|
*mmsError = MMS_ERROR_RESOURCE_OTHER;
|
|
}
|
|
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
MmsDataAccessError
|
|
MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, int index, int numberOfElements,
|
|
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_writeArrayElementsAsync(self, NULL, &err, domainId, itemId, index, numberOfElements, value, writeVariableHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
Semaphore_wait(parameter.waitForResponse);
|
|
|
|
err = parameter.err;
|
|
}
|
|
|
|
Semaphore_destroy(parameter.waitForResponse);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
return parameter.accessError;
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeArrayElementsAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError,
|
|
const char* domainId, const char* itemId, int index, int numberOfElements,
|
|
MmsValue* value,
|
|
MmsConnection_WriteVariableHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createWriteRequestArray(invokeId, domainId, itemId, index, numberOfElements, value, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, bool isAssociationSpecific,
|
|
const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values,
|
|
/* OUTPUT */LinkedList* /* <MmsValue*> */accessResults)
|
|
{
|
|
MmsError err = MMS_ERROR_NONE;
|
|
|
|
struct writeMultipleVariablesParameter parameter;
|
|
|
|
parameter.sem = Semaphore_create(1);;
|
|
parameter.err = MMS_ERROR_NONE;
|
|
parameter.result = NULL;
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
MmsConnection_writeNamedVariableListAsync(self, NULL, &err, isAssociationSpecific, domainId, itemId, values, writeMultipleVariablesHandler, ¶meter);
|
|
|
|
if (err == MMS_ERROR_NONE) {
|
|
|
|
Semaphore_wait(parameter.sem);
|
|
|
|
err = parameter.err;
|
|
|
|
if (accessResults)
|
|
*accessResults = parameter.result;
|
|
else
|
|
LinkedList_destroyDeep(parameter.result, (LinkedListValueDeleteFunction) MmsValue_delete);
|
|
}
|
|
else {
|
|
if (accessResults)
|
|
*accessResults = NULL;
|
|
}
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
Semaphore_destroy(parameter.sem);
|
|
}
|
|
|
|
void
|
|
MmsConnection_writeNamedVariableListAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, bool isAssociationSpecific,
|
|
const char* domainId, const char* itemId, LinkedList /* <MmsValue*> */values,
|
|
MmsConnection_WriteMultipleVariablesHandler handler, void* parameter)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
uint32_t invokeId = getNextInvokeId(self);
|
|
|
|
if (usedInvokeId)
|
|
*usedInvokeId = invokeId;
|
|
|
|
mmsClient_createWriteRequestNamedVariableList(invokeId, isAssociationSpecific, domainId, itemId, values, payload);
|
|
|
|
MmsClientInternalParameter intParam;
|
|
intParam.ptr = NULL;
|
|
|
|
MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter, intParam);
|
|
|
|
if (mmsError)
|
|
*mmsError = err;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
void
|
|
MmsConnection_sendRawData(MmsConnection self, MmsError* mmsError, uint8_t* buffer, int bufSize)
|
|
{
|
|
if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) {
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_CONNECTION_LOST;
|
|
goto exit_function;
|
|
}
|
|
|
|
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
|
|
|
|
ByteBuffer_append(payload, buffer, bufSize);
|
|
|
|
sendMessage(self, payload);
|
|
|
|
if (mmsError)
|
|
*mmsError = MMS_ERROR_NONE;
|
|
|
|
exit_function:
|
|
return;
|
|
}
|
|
|
|
void
|
|
MmsServerIdentity_destroy(MmsServerIdentity* self)
|
|
{
|
|
if (self->modelName != NULL)
|
|
GLOBAL_FREEMEM(self->modelName);
|
|
|
|
if (self->vendorName != NULL)
|
|
GLOBAL_FREEMEM(self->vendorName);
|
|
|
|
if (self->revision != NULL)
|
|
GLOBAL_FREEMEM(self->revision);
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
}
|
|
|
|
MmsVariableAccessSpecification*
|
|
MmsVariableAccessSpecification_create(char* domainId, char* itemId)
|
|
{
|
|
MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*)
|
|
GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification));
|
|
|
|
self->domainId = domainId;
|
|
self->itemId = itemId;
|
|
self->arrayIndex = -1;
|
|
self->componentName = NULL;
|
|
|
|
return self;
|
|
}
|
|
|
|
MmsVariableAccessSpecification*
|
|
MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemId, int32_t index,
|
|
char* componentName)
|
|
{
|
|
MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*)
|
|
GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification));
|
|
|
|
self->domainId = domainId;
|
|
self->itemId = itemId;
|
|
self->arrayIndex = index;
|
|
self->componentName = componentName;
|
|
|
|
return self;
|
|
}
|
|
|
|
void
|
|
MmsVariableAccessSpecification_destroy(MmsVariableAccessSpecification* self)
|
|
{
|
|
if (self->domainId != NULL)
|
|
GLOBAL_FREEMEM((void*) self->domainId);
|
|
|
|
if (self->itemId != NULL)
|
|
GLOBAL_FREEMEM((void*) self->itemId);
|
|
|
|
if (self->componentName != NULL)
|
|
GLOBAL_FREEMEM((void*) self->componentName);
|
|
|
|
GLOBAL_FREEMEM(self);
|
|
}
|