static MmsValue* newEmptyPhyCommAddress(void) { MmsValue* self = MmsValue_createEmptyStructure(4); MmsValue_setElement(self, 0, MmsValue_newOctetString(6, 6)); MmsValue_setElement(self, 1, MmsValue_newUnsigned(8)); MmsValue_setElement(self, 2, MmsValue_newUnsigned(16)); MmsValue_setElement(self, 3, MmsValue_newUnsigned(16)); return self; }
int main(int argc, char** argv) { MmsValue* dataSetValues = MmsValue_createEmtpyArray(4); int i; for (i = 0; i < 4; i++) { MmsValue* dataSetEntry = MmsValue_newBoolean(false); MmsValue_setElement(dataSetValues, i, dataSetEntry); } // GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbEvents", dataSetValues); GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL); if (argc > 1) { printf("Set interface id: %s\n", argv[1]); GooseSubscriber_setInterfaceId(subscriber, argv[1]); } GooseSubscriber_setAppId(subscriber, 1000); GooseSubscriber_setListener(subscriber, gooseListener, NULL); GooseSubscriber_subscribe(subscriber); signal(SIGINT, sigint_handler); while (running) { Thread_sleep(100); } GooseSubscriber_destroy(subscriber); }
void ControlObject_sendLastApplError(ControlObject* self, MmsServerConnection connection, char* ctlVariable, int error, ControlAddCause addCause, MmsValue* ctlNum, MmsValue* origin, bool handlerMode) { MmsValue lastApplErrorMemory; MmsValue* lastApplError = &lastApplErrorMemory; lastApplError->type = MMS_STRUCTURE; lastApplError->value.structure.size = 5; MmsValue* componentContainer[5]; lastApplError->value.structure.components =componentContainer; char ctlObj[130]; StringUtils_createStringInBuffer(ctlObj, 3, self->ctlObjectName, "$", ctlVariable); if (DEBUG_IED_SERVER) { printf("IED_SERVER: sendLastApplError:\n"); printf("IED_SERVER: control object: %s\n", ctlObj); printf("IED_SERVER: ctlNum: %u\n", MmsValue_toUint32(ctlNum)); } MmsValue ctlObjValueMemory; MmsValue* ctlObjValue = &ctlObjValueMemory; ctlObjValue->type = MMS_VISIBLE_STRING; ctlObjValue->value.visibleString.buf = ctlObj; ctlObjValue->value.visibleString.size = sizeof(ctlObj); MmsValue_setElement(lastApplError, 0, ctlObjValue); MmsValue_setInt32(self->error, error); MmsValue_setInt32(self->addCause, addCause); MmsValue_setElement(lastApplError, 1, self->error); MmsValue_setElement(lastApplError, 2, origin); MmsValue_setElement(lastApplError, 3, ctlNum); MmsValue_setElement(lastApplError, 4, self->addCause); MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(connection, "LastApplError", lastApplError, handlerMode); }
static MmsValue* createOriginValue(ControlObjectClient self) { MmsValue* origin = MmsValue_createEmptyStructure(2); if (origin == NULL) goto exit_function; MmsValue* orCat = MmsValue_newIntegerFromInt16(self->orCat); if (orCat == NULL) goto cleanup_on_error; MmsValue_setElement(origin, 0, orCat); MmsValue* orIdent; if (self->orIdent != NULL) { int octetStringLen = strlen(self->orIdent); orIdent = MmsValue_newOctetString(0, octetStringLen); if (orIdent == NULL) goto cleanup_on_error; MmsValue_setOctetString(orIdent, (uint8_t*) self->orIdent, octetStringLen); } else orIdent = MmsValue_newOctetString(0, 0); if (orIdent == NULL) goto cleanup_on_error; MmsValue_setElement(origin, 1, orIdent); goto exit_function; cleanup_on_error: MmsValue_delete(origin); origin = NULL; exit_function: return origin; }
static MmsValue* addNamedVariableValue(MmsTypeSpecification* namedVariable, MmsServerConnection* connection, MmsDomain* domain, char* itemId, LinkedList typedValues) { MmsValue* value = NULL; if (namedVariable->type == MMS_STRUCTURE) { value = mmsServer_getValue(connection->server, domain, itemId); if (value != NULL) { LinkedList_add(typedValues, value); } else { int componentCount = namedVariable->typeSpec.structure.elementCount; MmsValue* value = MmsValue_createEmptyStructure(componentCount); int i; for (i = 0; i < componentCount; i++) { char* newNameIdStr = createString(3, itemId, "$", namedVariable->typeSpec.structure.elements[i]->name); MmsValue* element = addNamedVariableValue(namedVariable->typeSpec.structure.elements[i], connection, domain, newNameIdStr, typedValues); MmsValue_setElement(value, i, element); free(newNameIdStr); } } } else { value = mmsServer_getValue(connection->server, domain, itemId); //TODO add checks??? if (value != NULL) LinkedList_add(typedValues, value); else { //TODO remove printf printf("Error getting element %s\n", itemId); } } return value; }
static MmsValue* addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnection connection, MmsDomain* domain, char* itemId) { MmsValue* value = NULL; if (namedVariable->type == MMS_STRUCTURE) { value = mmsServer_getValue(connection->server, domain, itemId, connection); if (value != NULL) goto exit_function; else { int componentCount = namedVariable->typeSpec.structure.elementCount; value = MmsValue_createEmptyStructure(componentCount); value->deleteValue = 1; int i; for (i = 0; i < componentCount; i++) { char newNameIdStr[65]; StringUtils_createStringInBuffer(newNameIdStr, 3, itemId, "$", namedVariable->typeSpec.structure.elements[i]->name); MmsValue* element = addNamedVariableValue(namedVariable->typeSpec.structure.elements[i], connection, domain, newNameIdStr); if (element == NULL) { MmsValue_delete(value); value = NULL; break; } MmsValue_setElement(value, i, element); } } } else { value = mmsServer_getValue(connection->server, domain, itemId, connection); } exit_function: return value; }
static void alternateArrayAccess(MmsServerConnection* connection, AlternateAccess_t* alternateAccess, MmsDomain* domain, char* itemId, LinkedList values, MmsTypeSpecification* namedVariable) { if (mmsServer_isIndexAccess(alternateAccess)) { int lowIndex = mmsServer_getLowIndex(alternateAccess); int numberOfElements = mmsServer_getNumberOfElements(alternateAccess); if (DEBUG) printf("Alternate access index: %i elements %i\n", lowIndex, numberOfElements); int index = lowIndex; MmsValue* value = NULL; MmsValue* arrayValue = mmsServer_getValue(connection->server, domain, itemId); if (arrayValue != NULL) { if (numberOfElements == 0) if (isAccessToArrayComponent(alternateAccess)) { if (namedVariable->typeSpec.array.elementTypeSpec->type == MMS_STRUCTURE) { MmsValue* structValue = MmsValue_getElement(arrayValue, index); if (structValue != NULL) value = getComponentOfArrayElement(alternateAccess, namedVariable, structValue); } } else value = MmsValue_getElement(arrayValue, index); else { value = MmsValue_createEmtpyArray(numberOfElements); MmsValue_setDeletable(value); int resultIndex = 0; while (index < lowIndex + numberOfElements) { MmsValue* elementValue = NULL; elementValue = MmsValue_getElement(arrayValue, index); if (!MmsValue_isDeletable(elementValue)) elementValue = MmsValue_clone(elementValue); MmsValue_setElement(value, resultIndex, elementValue); index++; resultIndex++; } } appendValueToResultList(value, values); if (MmsValue_isDeletable(arrayValue)) MmsValue_delete(arrayValue); } else /* access error */ appendErrorToResultList(values, 10 /* object-non-existant*/); } else { // invalid access if (DEBUG) printf("Invalid alternate access\n"); appendErrorToResultList(values, 10 /* object-non-existant*/); } }
bool ControlObjectClient_cancel(ControlObjectClient self) { resetLastApplError(self); MmsValue* cancelParameters; if (self->hasTimeActivatedMode) cancelParameters = MmsValue_createEmptyStructure(6); else cancelParameters = MmsValue_createEmptyStructure(5); MmsValue_setElement(cancelParameters, 0, self->ctlVal); int index = 1; if (self->hasTimeActivatedMode) { MmsValue* operTm = MmsValue_newUtcTimeByMsTime(self->opertime); MmsValue_setElement(cancelParameters, index++, operTm); } MmsValue* origin = createOriginValue(self); MmsValue_setElement(cancelParameters, index++, origin); MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue_setElement(cancelParameters, index++, ctlNum); uint64_t timestamp = Hal_getTimeInMs(); MmsValue* ctlTime; if (self->edition == 2) ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); } MmsValue_setElement(cancelParameters, index++, ctlTime); MmsValue* ctlTest = MmsValue_newBoolean(self->test); MmsValue_setElement(cancelParameters, index++, ctlTest); char domainId[65]; char itemId[65]; MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); strncat(itemId, "$Cancel", 64); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: cancel: %s/%s\n", domainId, itemId); MmsError mmsError; MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), &mmsError, domainId, itemId, cancelParameters); MmsValue_setElement(cancelParameters, 0, NULL); MmsValue_delete(cancelParameters); if (mmsError != MMS_ERROR_NONE) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: cancel failed!\n"); return false; } return true; }
bool ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t operTime) { bool success = false; if (ctlVal == NULL) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate - (ctlVal == NULL)!\n"); goto exit_function; } resetLastApplError(self); MmsValue* operParameters; if (self->hasTimeActivatedMode) operParameters = MmsValue_createEmptyStructure(7); else operParameters = MmsValue_createEmptyStructure(6); MmsValue_setElement(operParameters, 0, ctlVal); int index = 1; if (self->hasTimeActivatedMode) { MmsValue* operTm = MmsValue_newUtcTimeByMsTime(operTime); MmsValue_setElement(operParameters, index++, operTm); } MmsValue* origin = createOriginValue(self); MmsValue_setElement(operParameters, index++, origin); if (!((self->ctlModel == CONTROL_MODEL_SBO_NORMAL) || (self->ctlModel == CONTROL_MODEL_SBO_ENHANCED))) { self->ctlNum++; } MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue_setElement(operParameters, index++, ctlNum); uint64_t timestamp = Hal_getTimeInMs(); MmsValue* ctlTime; if (self->edition == 2) ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); } MmsValue_setElement(operParameters, index++, ctlTime); MmsValue* ctlTest = MmsValue_newBoolean(self->test); MmsValue_setElement(operParameters, index++, ctlTest); MmsValue* check = MmsValue_newBitString(2); MmsValue_setBitStringBit(check, 1, self->interlockCheck); MmsValue_setBitStringBit(check, 0, self->synchroCheck); MmsValue_setElement(operParameters, index++, check); char domainId[65]; char itemId[65]; MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId); convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO"); int controlObjectItemIdLen = strlen(itemId); strncat(itemId, "$Oper", 64 - controlObjectItemIdLen); if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId); MmsError mmsError; MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), &mmsError, domainId, itemId, operParameters); MmsValue_setElement(operParameters, 0, NULL); MmsValue_delete(operParameters); if (mmsError != MMS_ERROR_NONE) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: operate failed!\n"); goto exit_function; } MmsValue_update(self->ctlVal, ctlVal); self->opertime = operTime; success = true; exit_function: return success; }
ControlObjectClient ControlObjectClient_create(const char* objectReference, IedConnection connection) { ControlObjectClient self = NULL; /* request control model from server */ char domainId[65]; char itemId[65]; char* domainName = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainId); if (domainName == NULL) goto exit_function; convertToMmsAndInsertFC(itemId, objectReference + strlen(domainId) + 1, "CF"); int controlObjectItemIdLen = strlen(itemId); strncat(itemId, "$ctlModel", 64 - controlObjectItemIdLen); MmsError mmsError; MmsValue* ctlModel = MmsConnection_readVariable(IedConnection_getMmsConnection(connection), &mmsError, domainId, itemId); if (ctlModel == NULL) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: ControlObjectClient_create: failed to get ctlModel from server\n"); goto exit_function; } int ctlModelVal = MmsValue_toUint32(ctlModel); MmsValue_delete(ctlModel); IedClientError error; LinkedList dataDirectory = IedConnection_getDataDirectory(connection, &error, objectReference); if (dataDirectory == NULL) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: ControlObjectClient_create: failed to get data directory of control object\n"); goto exit_function; } /* check what control elements are available */ bool hasOper = false; LinkedList element = LinkedList_getNext(dataDirectory); while (element != NULL) { char* objectName = (char*) element->data; if (strcmp(objectName, "Oper") == 0) hasOper = true; element = LinkedList_getNext(element); } LinkedList_destroy(dataDirectory); if (hasOper == false) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: control is missing required element \"Oper\"\n"); goto exit_function; } /* check for time activated control */ bool hasTimeActivatedControl = false; strcpy(itemId, objectReference); strcat(itemId, ".Oper"); dataDirectory = IedConnection_getDataDirectory(connection, &error, itemId); if (dataDirectory == NULL) goto exit_function; element = LinkedList_getNext(dataDirectory); while (element != NULL) { char* objectName = (char*) element->data; if (strcmp(objectName, "operTm") == 0) { hasTimeActivatedControl = true; break; } element = LinkedList_getNext(element); } LinkedList_destroy(dataDirectory); /* get default parameters for Oper control variable */ MmsValue* oper = IedConnection_readObject(connection, &error, itemId, IEC61850_FC_CO); if (oper == NULL) { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: reading \"Oper\" failed!\n"); goto exit_function; } self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient)); if (self == NULL) goto exit_function; self->objectReference = copyString(objectReference); self->connection = connection; self->ctlModel = (ControlModel) ctlModelVal; self->hasTimeActivatedMode = hasTimeActivatedControl; self->ctlVal = MmsValue_getElement(oper, 0); /* Check for T element type (EntryTime -> Ed.1, Timestamp -> Ed.2) */ MmsValue* t; if (hasTimeActivatedControl) t = MmsValue_getElement(oper, 4); else t = MmsValue_getElement(oper, 3); if (MmsValue_getType(t) == MMS_BINARY_TIME) self->edition = 1; else self->edition = 2; if (DEBUG_IED_CLIENT) printf("IED_CLIENT: Detected edition %i control\n", self->edition); MmsValue_setElement(oper, 0, NULL); MmsValue_delete(oper); private_IedConnection_addControlClient(connection, self); exit_function: return self; }
MmsValue* mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSize, bool createArray) { MmsValue* valueList = NULL; MmsValue* value = NULL; int elementCount = listSize; if ((elementCount > 1) || createArray) valueList = MmsValue_createEmptyArray(elementCount); int i = 0; for (i = 0; i < elementCount; i++) { AccessResult_PR presentType = accessResultList[i]->present; if (presentType == AccessResult_PR_failure) { if (DEBUG_MMS_CLIENT) printf("access error!\n"); if (accessResultList[i]->choice.failure.size > 0) { int errorCode = (int) accessResultList[i]->choice.failure.buf[0]; MmsDataAccessError dataAccessError = DATA_ACCESS_ERROR_UNKNOWN; if ((errorCode >= 0) && (errorCode < 12)) dataAccessError = (MmsDataAccessError) errorCode; value = MmsValue_newDataAccessError(dataAccessError); } else value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); } else if (presentType == AccessResult_PR_array) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_ARRAY; int arrayElementCount = accessResultList[i]->choice.array.list.count; value->value.structure.size = arrayElementCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); int j; for (j = 0; j < arrayElementCount; j++) { value->value.structure.components[j] = mmsMsg_parseDataElement( accessResultList[i]->choice.array.list.array[j]); } } else if (presentType == AccessResult_PR_structure) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_STRUCTURE; int componentCount = accessResultList[i]->choice.structure.list.count; value->value.structure.size = componentCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int j; for (j = 0; j < componentCount; j++) { value->value.structure.components[j] = mmsMsg_parseDataElement( accessResultList[i]->choice.structure.list.array[j]); } } else if (presentType == AccessResult_PR_bitstring) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BIT_STRING; int size = accessResultList[i]->choice.bitstring.size; value->value.bitString.size = (size * 8) - accessResultList[i]->choice.bitstring.bits_unused; value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.bitString.buf, accessResultList[i]->choice.bitstring.buf, size); } else if (presentType == AccessResult_PR_integer) { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, accessResultList[i]->choice.integer.size); value = MmsValue_newIntegerFromBerInteger(berInteger); } else if (presentType == AccessResult_PR_unsigned) { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, accessResultList[i]->choice.Unsigned.size); value = MmsValue_newUnsignedFromBerInteger(berInteger); } else if (presentType == AccessResult_PR_floatingpoint) { int size = accessResultList[i]->choice.floatingpoint.size; value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_FLOAT; if (size == 5) { /* FLOAT32 */ value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); #else memcpy(value->value.floatingPoint.buf, floatBuf, 4); #endif } if (size == 9) { /* FLOAT64 */ value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1); value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); #else memcpy(value->value.floatingPoint.buf, floatBuf, 8); #endif } } else if (presentType == AccessResult_PR_visiblestring) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_VISIBLE_STRING; int strSize = accessResultList[i]->choice.visiblestring.size; value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); value->value.visibleString.size = strSize; memcpy(value->value.visibleString.buf, accessResultList[i]->choice.visiblestring.buf, strSize); value->value.visibleString.buf[strSize] = 0; } else if (presentType == AccessResult_PR_mMSString) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_STRING; int strSize = accessResultList[i]->choice.mMSString.size; value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); value->value.visibleString.size = strSize; memcpy(value->value.visibleString.buf, accessResultList[i]->choice.mMSString.buf, strSize); value->value.visibleString.buf[strSize] = 0; } else if (presentType == AccessResult_PR_utctime) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; memcpy(value->value.utcTime, accessResultList[i]->choice.utctime.buf, 8); } else if (presentType == AccessResult_PR_boolean) { value = MmsValue_newBoolean(accessResultList[i]->choice.boolean); } else if (presentType == AccessResult_PR_binarytime) { int size = accessResultList[i]->choice.binarytime.size; if (size <= 6) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; value->value.binaryTime.size = size; memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); } } else if (presentType == AccessResult_PR_octetstring) { int size = accessResultList[i]->choice.octetstring.size; value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; value->value.octetString.maxSize = size; value->value.octetString.size = size; value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); } else { printf("unknown type %i\n", presentType); value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID); } if ((elementCount > 1) || createArray) MmsValue_setElement(valueList, i, value); } if (valueList == NULL) valueList = value; return valueList; }
void ControlObject_sendCommandTerminationNegative(ControlObject* self) { /* create LastApplError */ MmsValue lastApplErrorMemory; MmsValue* lastApplError = &lastApplErrorMemory; lastApplError->type = MMS_STRUCTURE; lastApplError->value.structure.size = 5; MmsValue* componentContainer[5]; lastApplError->value.structure.components = componentContainer; char ctlObj[130]; StringUtils_createStringInBuffer(ctlObj, 2, self->ctlObjectName, "$Oper"); MmsValue ctlObjValueMemory; MmsValue* ctlObjValue = &ctlObjValueMemory; ctlObjValue->type = MMS_VISIBLE_STRING; ctlObjValue->value.visibleString.buf = ctlObj; ctlObjValue->value.visibleString.size = sizeof(ctlObj); MmsValue_setElement(lastApplError, 0, ctlObjValue); MmsValue_setInt32(self->error, CONTROL_ERROR_UNKOWN); MmsValue_setInt32(self->addCause, ADD_CAUSE_UNKNOWN); MmsValue_setElement(lastApplError, 1, self->error); MmsValue_setElement(lastApplError, 2, self->origin); MmsValue_setElement(lastApplError, 3, self->ctlNum); MmsValue_setElement(lastApplError, 4, self->addCause); MmsVariableAccessSpecification lastApplErrorVarSpec; lastApplErrorVarSpec.itemId = "LastApplError"; lastApplErrorVarSpec.domainId = NULL; /* create oper variable */ char itemId[130]; StringUtils_createStringInBuffer(itemId, 4, self->lnName, "$CO$", self->name, "$Oper"); char* domainId = MmsDomain_getName(self->mmsDomain); MmsVariableAccessSpecification operVarSpec; operVarSpec.itemId = itemId; operVarSpec.domainId = domainId; /* create response */ if (DEBUG_IED_SERVER) printf("IED_SERVER: send CommandTermination-: %s\n", itemId); LinkedList varSpecList = LinkedList_create(); LinkedList values = LinkedList_create(); LinkedList_add(varSpecList, &lastApplErrorVarSpec); LinkedList_add(varSpecList, &operVarSpec); LinkedList_add(values, lastApplError); LinkedList_add(values, self->oper); MmsServerConnection_sendInformationReportListOfVariables(self->mmsConnection, varSpecList, values, false); LinkedList_destroyStatic(varSpecList); LinkedList_destroyStatic(values); } /* ControlObject_sendCommandTerminationNegative() */
static MmsValue* parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure) { int bufPos = 0; int elementLength = 0; int elementIndex = 0; MmsValue* dataSetValues = NULL; while (bufPos < allDataLength) { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); goto exit_with_error; } switch (tag) { case 0x80: /* reserved for access result */ break; case 0xa1: /* array */ break; case 0xa2: /* structure */ break; case 0x83: /* boolean */ break; case 0x84: /* BIT STRING */ break; case 0x85: /* integer */ break; case 0x86: /* unsigned integer */ break; case 0x87: /* Float */ break; case 0x89: /* octet string */ break; case 0x8a: /* visible string */ break; case 0x8c: /* binary time */ break; case 0x91: /* Utctime */ break; default: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unknown tag %02x\n", tag); goto exit_with_error; } bufPos += elementLength; elementIndex++; } if (isStructure) dataSetValues = MmsValue_createEmptyStructure(elementIndex); else dataSetValues = MmsValue_createEmptyArray(elementIndex); elementIndex = 0; bufPos = 0; while (bufPos < allDataLength) { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); goto exit_with_error; } MmsValue* value = NULL; switch (tag) { case 0xa1: /* array */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false); if (value == NULL) goto exit_with_error; break; case 0xa2: /* structure */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true); if (value == NULL) goto exit_with_error; break; case 0x83: /* boolean */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n"); value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos)); break; case 0x84: /* BIT STRING */ { int padding = buffer[bufPos]; int bitStringLength = (8 * (elementLength - 1)) - padding; value = MmsValue_newBitString(bitStringLength); memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); } break; case 0x85: /* integer */ value = MmsValue_newInteger(elementLength * 8); memcpy(value->value.integer->octets, buffer + bufPos, elementLength); value->value.integer->size = elementLength; break; case 0x86: /* unsigned integer */ value = MmsValue_newUnsigned(elementLength * 8); memcpy(value->value.integer->octets, buffer + bufPos, elementLength); value->value.integer->size = elementLength; break; case 0x87: /* Float */ if (elementLength == 9) value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos)); else if (elementLength == 5) value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos)); break; case 0x89: /* octet string */ value = MmsValue_newOctetString(elementLength, elementLength); memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); break; case 0x8a: /* visible string */ value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength); break; case 0x8c: /* binary time */ if (elementLength == 4) value = MmsValue_newBinaryTime(true); else if (elementLength == 6) value = MmsValue_newBinaryTime(false); if ((elementLength == 4) || (elementLength == 6)) memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); break; case 0x91: /* Utctime */ if (elementLength == 8) { value = MmsValue_newUtcTime(0); MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); } else if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); break; default: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag); goto exit_with_error; } bufPos += elementLength; if (value != NULL) { MmsValue_setElement(dataSetValues, elementIndex, value); elementIndex++; } } self->dataSetValuesSelfAllocated = true; return dataSetValues; exit_with_error: if (dataSetValues != NULL) MmsValue_delete(dataSetValues); return NULL; }