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 ClientReportControlBlock_setGI(ClientReportControlBlock self, bool gi) { if (self->gi == NULL) self->gi = MmsValue_newBoolean(gi); else MmsValue_setBoolean(self->gi, gi); }
void ClientReportControlBlock_setPurgeBuf(ClientReportControlBlock self, bool purgeBuf) { if (self->purgeBuf == NULL) self->purgeBuf = MmsValue_newBoolean(purgeBuf); else MmsValue_setBoolean(self->purgeBuf, purgeBuf); }
void ClientReportControlBlock_setResv(ClientReportControlBlock self, bool resv) { if (self->resv == NULL) self->resv = MmsValue_newBoolean(resv); else MmsValue_setBoolean(self->resv, resv); }
void ClientReportControlBlock_setRptEna(ClientReportControlBlock self, bool rptEna) { if (self->rptEna == NULL) self->rptEna = MmsValue_newBoolean(rptEna); else MmsValue_setBoolean(self->rptEna, rptEna); }
void ClientGooseControlBlock_setGoEna(ClientGooseControlBlock self, bool goEna) { if (self->goEna == NULL) self->goEna = MmsValue_newBoolean(goEna); else MmsValue_setBoolean(self->goEna, goEna); }
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; }
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; }
MmsValue* mmsMsg_parseDataElement(Data_t* dataElement) { MmsValue* value = NULL; if (dataElement->present == Data_PR_structure) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int componentCount = dataElement->choice.structure->list.count; value->type = MMS_STRUCTURE; value->value.structure.size = componentCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; for (i = 0; i < componentCount; i++) { value->value.structure.components[i] = mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); } } else if (dataElement->present == Data_PR_array) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int componentCount = dataElement->choice.array->list.count; value->type = MMS_ARRAY; value->value.structure.size = componentCount; value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); int i; for (i = 0; i < componentCount; i++) { value->value.structure.components[i] = mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); } } else { if (dataElement->present == Data_PR_integer) { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( dataElement->choice.integer.buf, dataElement->choice.integer.size); value = MmsValue_newIntegerFromBerInteger(berInteger); } else if (dataElement->present == Data_PR_unsigned) { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); value = MmsValue_newUnsignedFromBerInteger(berInteger); } else if (dataElement->present == Data_PR_visiblestring) { value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, dataElement->choice.visiblestring.size); } else if (dataElement->present == Data_PR_mMSString) { value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, dataElement->choice.mMSString.size); } else if (dataElement->present == Data_PR_bitstring) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BIT_STRING; int size = dataElement->choice.bitstring.size; value->value.bitString.size = (size * 8) - dataElement->choice.bitstring.bits_unused; value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.bitString.buf, dataElement->choice.bitstring.buf, size); } else if (dataElement->present == Data_PR_floatingpoint) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); int size = dataElement->choice.floatingpoint.size; value->type = MMS_FLOAT; if (size == 5) { /* FLOAT32 */ value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; uint8_t* floatBuf = (dataElement->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 = dataElement->choice.floatingpoint.buf[0]; uint8_t* floatBuf = (dataElement->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 (dataElement->present == Data_PR_utctime) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); } else if (dataElement->present == Data_PR_octetstring) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; int size = dataElement->choice.octetstring.size; value->value.octetString.size = size; value->value.octetString.maxSize = size; value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); } else if (dataElement->present == Data_PR_binarytime) { int size = dataElement->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, dataElement->choice.binarytime.buf, size); } } else if (dataElement->present == Data_PR_boolean) { value = MmsValue_newBoolean(dataElement->choice.boolean); } } return value; }
static MmsVariableSpecification* createBufferedReportControlBlock(ReportControlBlock* reportControlBlock, ReportControl* reportControl) { MmsVariableSpecification* rcb = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); rcb->name = copyString(reportControlBlock->name); rcb->type = MMS_STRUCTURE; MmsValue* mmsValue = (MmsValue*) calloc(1, sizeof(MmsValue)); mmsValue->deleteValue = false; mmsValue->type = MMS_STRUCTURE; mmsValue->value.structure.size = 15; mmsValue->value.structure.components = (MmsValue**) calloc(15, sizeof(MmsValue*)); rcb->typeSpec.structure.elementCount = 15; rcb->typeSpec.structure.elements = (MmsVariableSpecification**) calloc(15, sizeof(MmsVariableSpecification*)); MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("RptID"); namedVariable->typeSpec.visibleString = -129; namedVariable->type = MMS_VISIBLE_STRING; rcb->typeSpec.structure.elements[0] = namedVariable; mmsValue->value.structure.components[0] = MmsValue_newVisibleString( reportControlBlock->rptId); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("RptEna"); namedVariable->type = MMS_BOOLEAN; rcb->typeSpec.structure.elements[1] = namedVariable; mmsValue->value.structure.components[1] = MmsValue_newBoolean(false); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("DatSet"); namedVariable->typeSpec.visibleString = -129; namedVariable->type = MMS_VISIBLE_STRING; rcb->typeSpec.structure.elements[2] = namedVariable; if (reportControlBlock->dataSetName != NULL) { char* dataSetReference = createDataSetReferencForDefaultDataSet(reportControlBlock, reportControl); mmsValue->value.structure.components[2] = MmsValue_newVisibleString(dataSetReference); free(dataSetReference); } else mmsValue->value.structure.components[2] = MmsValue_newVisibleString(""); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("ConfRev"); namedVariable->type = MMS_UNSIGNED; namedVariable->typeSpec.unsignedInteger = 32; rcb->typeSpec.structure.elements[3] = namedVariable; mmsValue->value.structure.components[3] = MmsValue_newUnsignedFromUint32(reportControlBlock->confRef); reportControl->confRev = mmsValue->value.structure.components[3]; namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("OptFlds"); namedVariable->type = MMS_BIT_STRING; namedVariable->typeSpec.bitString = 10; rcb->typeSpec.structure.elements[4] = namedVariable; mmsValue->value.structure.components[4] = createOptFlds(reportControlBlock); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("BufTm"); namedVariable->type = MMS_UNSIGNED; namedVariable->typeSpec.unsignedInteger = 32; rcb->typeSpec.structure.elements[5] = namedVariable; mmsValue->value.structure.components[5] = MmsValue_newUnsignedFromUint32(reportControlBlock->bufferTime); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("SqNum"); namedVariable->type = MMS_UNSIGNED; namedVariable->typeSpec.unsignedInteger = 16; rcb->typeSpec.structure.elements[6] = namedVariable; mmsValue->value.structure.components[6] = MmsValue_newUnsigned(16); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("TrgOps"); namedVariable->type = MMS_BIT_STRING; namedVariable->typeSpec.bitString = 6; rcb->typeSpec.structure.elements[7] = namedVariable; mmsValue->value.structure.components[7] = createTrgOps(reportControlBlock); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("IntgPd"); namedVariable->type = MMS_UNSIGNED; namedVariable->typeSpec.unsignedInteger = 32; rcb->typeSpec.structure.elements[8] = namedVariable; mmsValue->value.structure.components[8] = MmsValue_newUnsignedFromUint32(reportControlBlock->intPeriod); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("GI"); namedVariable->type = MMS_BOOLEAN; rcb->typeSpec.structure.elements[9] = namedVariable; mmsValue->value.structure.components[9] = MmsValue_newBoolean(false); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("PurgeBuf"); namedVariable->type = MMS_BOOLEAN; rcb->typeSpec.structure.elements[10] = namedVariable; mmsValue->value.structure.components[10] = MmsValue_newBoolean(false); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("EntryID"); namedVariable->type = MMS_OCTET_STRING; namedVariable->typeSpec.octetString = 8; rcb->typeSpec.structure.elements[11] = namedVariable; mmsValue->value.structure.components[11] = MmsValue_newOctetString(8, 8); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("TimeOfEntry"); namedVariable->type = MMS_BINARY_TIME; rcb->typeSpec.structure.elements[12] = namedVariable; mmsValue->value.structure.components[12] = MmsValue_newBinaryTime(false); reportControl->timeOfEntry = mmsValue->value.structure.components[12]; namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("ResvTms"); namedVariable->type = MMS_UNSIGNED; namedVariable->typeSpec.unsignedInteger = 32; rcb->typeSpec.structure.elements[13] = namedVariable; mmsValue->value.structure.components[13] = MmsValue_newUnsigned(32); namedVariable = (MmsVariableSpecification*) calloc(1, sizeof(MmsVariableSpecification)); namedVariable->name = copyString("Owner"); namedVariable->type = MMS_OCTET_STRING; namedVariable->typeSpec.octetString = -128; rcb->typeSpec.structure.elements[14] = namedVariable; mmsValue->value.structure.components[14] = MmsValue_newOctetString(0, 128); reportControl->rcbValues = mmsValue; return rcb; }
static void sendReport(ReportControl* self, bool isIntegrity, bool isGI) { LinkedList reportElements = LinkedList_create(); LinkedList deletableElements = LinkedList_create(); MmsValue* rptId = ReportControl_getRCBValue(self, "RptID"); MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds"); MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet"); LinkedList_add(reportElements, rptId); LinkedList_add(reportElements, optFlds); /* delete option fields for unsupported options */ MmsValue_setBitStringBit(optFlds, 5, false); /* data-reference */ MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */ MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */ MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum"); if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */ LinkedList_add(reportElements, sqNum); if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */ LinkedList_add(reportElements, self->timeOfEntry); } if (MmsValue_getBitStringBit(optFlds, 4)) /* data set reference */ LinkedList_add(reportElements, datSet); if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */ MmsValue* bufOvfl = MmsValue_newBoolean(false); LinkedList_add(reportElements, bufOvfl); LinkedList_add(deletableElements, bufOvfl); } if (MmsValue_getBitStringBit(optFlds, 8)) LinkedList_add(reportElements, self->confRev); if (isGI || isIntegrity) MmsValue_setAllBitStringBits(self->inclusionField); else MmsValue_deleteAllBitStringBits(self->inclusionField); LinkedList_add(reportElements, self->inclusionField); /* add data set value elements */ int i = 0; for (i = 0; i < self->dataSet->elementCount; i++) { if (isGI || isIntegrity) LinkedList_add(reportElements, self->dataSet->fcda[i]->value); else { if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { LinkedList_add(reportElements, self->dataSet->fcda[i]->value); MmsValue_setBitStringBit(self->inclusionField, i, true); } } } /* add reason code to report if requested */ if (MmsValue_getBitStringBit(optFlds, 3)) { for (i = 0; i < self->dataSet->elementCount; i++) { if (isGI || isIntegrity) { MmsValue* reason = MmsValue_newBitString(6); if (isGI) MmsValue_setBitStringBit(reason, 5, true); if (isIntegrity) MmsValue_setBitStringBit(reason, 4, true); LinkedList_add(reportElements, reason); LinkedList_add(deletableElements, reason); } else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) { MmsValue* reason = MmsValue_newBitString(6); switch(self->inclusionFlags[i]) { case REPORT_CONTROL_QUALITY_CHANGED: MmsValue_setBitStringBit(reason, 2, true); break; case REPORT_CONTROL_VALUE_CHANGED: MmsValue_setBitStringBit(reason, 1, true); break; case REPORT_CONTROL_VALUE_UPDATE: MmsValue_setBitStringBit(reason, 3, true); break; } LinkedList_add(reportElements, reason); LinkedList_add(deletableElements, reason); } } } /* clear inclusion flags */ for (i = 0; i < self->dataSet->elementCount; i++) { self->inclusionFlags[i] = REPORT_CONTROL_NONE; } MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", reportElements); /* Increase sequence number */ self->sqNum++; MmsValue_setUint16(sqNum, self->sqNum); LinkedList_destroyDeep(deletableElements, (LinkedListValueDeleteFunction) MmsValue_delete); LinkedList_destroyStatic(reportElements); /* clear GI flag */ if (isGI) { MmsValue* gi = ReportControl_getRCBValue(self, "GI"); self->gi = false; MmsValue_setBoolean(gi, false); } }
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; }
IedModel* ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) { int bytesRead = 1; bool stateInModel = false; int indendation = 0; IedModel* model = NULL; LogicalDevice* currentLD = NULL; LogicalNode* currentLN = NULL; ModelNode* currentModelNode = NULL; DataSet* currentDataSet = NULL; GSEControlBlock* currentGoCB = NULL; char nameString[130]; char nameString2[130]; char nameString3[130]; int currentLine = 0; while (bytesRead > 0) { bytesRead = readLine(fileHandle, lineBuffer, READ_BUFFER_MAX_SIZE); currentLine++; if (bytesRead > 0) { lineBuffer[bytesRead] = 0; if (stateInModel) { if (StringUtils_startsWith((char*) lineBuffer, "}")) { if (indendation == 1) { stateInModel = false; indendation = 0; } else if (indendation == 2) { indendation = 1; } else if (indendation == 3) { indendation = 2; } else if (indendation == 4) { indendation = 3; } else if (indendation > 4) { currentModelNode = currentModelNode->parent; indendation--; } } else if (indendation == 1) { if (StringUtils_startsWith((char*) lineBuffer, "LD")) { indendation = 2; if (sscanf((char*) lineBuffer, "LD(%s)", nameString) < 1) goto exit_error; terminateString(nameString, ')'); currentLD = LogicalDevice_create(nameString, model); } else goto exit_error; } else if (indendation == 2) { if (StringUtils_startsWith((char*) lineBuffer, "LN")) { indendation = 3; if (sscanf((char*) lineBuffer, "LN(%s)", nameString) < 1) goto exit_error; terminateString(nameString, ')'); currentLN = LogicalNode_create(nameString, currentLD); } else goto exit_error; } else if (indendation == 3) { if (StringUtils_startsWith((char*) lineBuffer, "DO")) { indendation = 4; int arrayElements = 0; sscanf((char*) lineBuffer, "DO(%s %i)", nameString, &arrayElements); currentModelNode = (ModelNode*) DataObject_create(nameString, (ModelNode*) currentLN, arrayElements); } else if (StringUtils_startsWith((char*) lineBuffer, "DS")) { indendation = 4; sscanf((char*) lineBuffer, "DS(%s)", nameString); terminateString(nameString, ')'); currentDataSet = DataSet_create(nameString, currentLN); } else if (StringUtils_startsWith((char*) lineBuffer, "RC")) { int isBuffered; uint32_t confRef; int trgOps; int options; uint32_t bufTm; uint32_t intgPd; int matchedItems = sscanf((char*) lineBuffer, "RC(%s %s %i %s %u %i %i %u %u)", nameString, nameString2, &isBuffered, nameString3, &confRef, &trgOps, &options, &bufTm, &intgPd); if (matchedItems < 9) goto exit_error; char* rptId = NULL; if (strcmp(nameString2, "-") != 0) rptId = nameString2; char* dataSetName = NULL; if (strcmp(nameString3, "-") != 0) dataSetName = nameString3; ReportControlBlock_create(nameString, currentLN, rptId, (bool) isBuffered, dataSetName, confRef, trgOps, options, bufTm, intgPd); } else if (StringUtils_startsWith((char*) lineBuffer, "LC")) { uint32_t trgOps; uint32_t intgPd; int logEna; int withReasonCode; int matchedItems = sscanf((char*) lineBuffer, "LC(%s %s %s %u %u %i %i)", nameString, nameString2, nameString3, &trgOps, &intgPd, &logEna, &withReasonCode); if (matchedItems < 7) goto exit_error; char* dataSet = NULL; if (strcmp(nameString2, "-") != 0) dataSet = nameString2; char* logRef = NULL; if (strcmp(nameString3, "-") != 0) logRef = nameString3; LogControlBlock_create(nameString, currentLN, dataSet, logRef, trgOps, intgPd, logEna, withReasonCode); } else if (StringUtils_startsWith((char*) lineBuffer, "LOG")) { int matchedItems = sscanf((char*) lineBuffer, "LOG(%s)", nameString); if (matchedItems < 1) goto exit_error; /* remove trailing ')' character */ int nameLen = strlen(nameString); nameString[nameLen - 1] = 0; Log_create(nameString, currentLN); } else if (StringUtils_startsWith((char*) lineBuffer, "GC")) { uint32_t confRef; int fixedOffs; int minTime = -1; int maxTime = -1; int matchedItems = sscanf((char*) lineBuffer, "GC(%s %s %s %u %i %i %i)", nameString, nameString2, nameString3, &confRef, &fixedOffs, &minTime, &maxTime); if (matchedItems < 5) goto exit_error; currentGoCB = GSEControlBlock_create(nameString, currentLN, nameString2, nameString3, confRef, fixedOffs, minTime, maxTime); indendation = 4; } #if (CONFIG_IEC61850_SETTING_GROUPS == 1) else if (StringUtils_startsWith((char*) lineBuffer, "SG")) { if (strcmp(currentLN->name, "LLN0") != 0) { if (DEBUG_IED_SERVER) printf("Setting group control is not defined in LLN0\n"); goto exit_error; } int actSG; int numOfSGs; int matchedItems = sscanf((char*) lineBuffer, "SG(%i %i)", &actSG, &numOfSGs); if (matchedItems < 2) goto exit_error; SettingGroupControlBlock_create(currentLN, actSG, numOfSGs); } #endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ else { if (DEBUG_IED_SERVER) printf("IED_SERVER: Unknown identifier (%s)\n", lineBuffer); goto exit_error; } } else if (indendation > 3) { if (StringUtils_startsWith((char*) lineBuffer, "DO")) { indendation++; int arrayElements = 0; int matchedItems = sscanf((char*) lineBuffer, "DO(%s %i)", nameString, &arrayElements); if (matchedItems != 2) goto exit_error; currentModelNode = (ModelNode*) DataObject_create(nameString, currentModelNode, arrayElements); } else if (StringUtils_startsWith((char*) lineBuffer, "DA")) { int arrayElements = 0; int attributeType = 0; int functionalConstraint = 0; int triggerOptions = 0; uint32_t sAddr = 0; sscanf((char*) lineBuffer, "DA(%s %i %i %i %i %u)", nameString, &arrayElements, &attributeType, &functionalConstraint, &triggerOptions, &sAddr); DataAttribute* dataAttribute = DataAttribute_create(nameString, currentModelNode, (DataAttributeType) attributeType, (FunctionalConstraint) functionalConstraint, triggerOptions, arrayElements, sAddr); char* valueIndicator = strchr((char*) lineBuffer, '='); if (valueIndicator != NULL) { switch (dataAttribute->type) { case IEC61850_UNICODE_STRING_255: { char* stringStart = valueIndicator + 2; terminateString(stringStart, '"'); dataAttribute->mmsValue = MmsValue_newMmsString(stringStart); } break; case IEC61850_VISIBLE_STRING_255: case IEC61850_VISIBLE_STRING_129: case IEC61850_VISIBLE_STRING_65: case IEC61850_VISIBLE_STRING_64: case IEC61850_VISIBLE_STRING_32: { char* stringStart = valueIndicator + 2; terminateString(stringStart, '"'); dataAttribute->mmsValue = MmsValue_newVisibleString(stringStart); } break; case IEC61850_INT8: case IEC61850_INT16: case IEC61850_INT32: case IEC61850_INT64: case IEC61850_INT128: case IEC61850_ENUMERATED: { int32_t intValue; if (sscanf(valueIndicator + 1, "%i", &intValue) != 1) goto exit_error; dataAttribute->mmsValue = MmsValue_newIntegerFromInt32(intValue); } break; case IEC61850_INT8U: case IEC61850_INT16U: case IEC61850_INT24U: case IEC61850_INT32U: { uint32_t uintValue; if (sscanf(valueIndicator + 1, "%u", &uintValue) != 1) goto exit_error; dataAttribute->mmsValue = MmsValue_newUnsignedFromUint32(uintValue); } break; case IEC61850_FLOAT32: { float floatValue; if (sscanf(valueIndicator + 1, "%f", &floatValue) != 1) goto exit_error; dataAttribute->mmsValue = MmsValue_newFloat(floatValue); } break; case IEC61850_FLOAT64: { double doubleValue; if (sscanf(valueIndicator + 1, "%lf", &doubleValue) != 1) goto exit_error; dataAttribute->mmsValue = MmsValue_newDouble(doubleValue); } break; case IEC61850_BOOLEAN: { int boolean; if (sscanf(valueIndicator + 1, "%i", &boolean) != 1) goto exit_error; dataAttribute->mmsValue = MmsValue_newBoolean((bool) boolean); } break; default: break; } } int lineLength = strlen((char*) lineBuffer); if (lineBuffer[lineLength - 1] == '{') { indendation++; currentModelNode = (ModelNode*) dataAttribute; } } else if (StringUtils_startsWith((char*) lineBuffer, "DE")) { sscanf((char*) lineBuffer, "DE(%s)", nameString); terminateString(nameString, ')'); DataSetEntry_create(currentDataSet, nameString, -1, NULL); } else if (StringUtils_startsWith((char*) lineBuffer, "PA")) { uint32_t vlanPrio; uint32_t vlanId; uint32_t appId; int matchedItems = sscanf((char*) lineBuffer, "PA(%u %u %u %s)", &vlanPrio, &vlanId, &appId, nameString); if ((matchedItems != 4) || (currentGoCB == NULL)) goto exit_error; terminateString(nameString, ')'); if (strlen(nameString) != 12) goto exit_error; if (StringUtils_createBufferFromHexString(nameString, (uint8_t*) nameString2) != 6) goto exit_error; PhyComAddress* dstAddress = PhyComAddress_create((uint8_t) vlanPrio, (uint16_t) vlanId, (uint16_t) appId, (uint8_t*) nameString2); GSEControlBlock_addPhyComAddress(currentGoCB, dstAddress); } else goto exit_error; } } else { if (StringUtils_startsWith((char*) lineBuffer, "MODEL{")) { model = IedModel_create(""); stateInModel = true; indendation = 1; } else if (StringUtils_startsWith((char*) lineBuffer, "MODEL(")) { sscanf((char*) lineBuffer, "MODEL(%s)", nameString); terminateString(nameString, ')'); model = IedModel_create(nameString); stateInModel = true; indendation = 1; } else goto exit_error; } } } return model; exit_error: if (DEBUG_IED_SERVER) printf("IED_SERVER: error parsing line %i (indendation level = %i)\n", currentLine, indendation); IedModel_destroy(model); return NULL; }