static ControlHandlerResult controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) { uint64_t timestamp = Hal_getTimeInMs(); if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); } else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); } else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); } else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); } else return CONTROL_RESULT_FAILED; return CONTROL_RESULT_OK; }
int ByteStream_readUint8(ByteStream self, uint8_t* byte) { int bytes_read; uint64_t start = Hal_getTimeInMs(); do { bytes_read = Socket_read(self->socket, byte, 1); } while ((bytes_read == 0) && ((Hal_getTimeInMs() - start) < CONFIG_TCP_READ_TIMEOUT_MS)); if (bytes_read != 1) { return -1; } return 1; }
void controlHandler(void* parameter, MmsValue* value, bool test) { printf("received control command %i %i: ", value->type, value->value.boolean); if (value->value.boolean) printf("on\n"); else printf("off\n"); MmsValue* timeStamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs()); if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp); } MmsValue_delete(timeStamp); }
void controlHandlerForBinaryOutput(void* parameter, MmsValue* value) { uint64_t timestamp = Hal_getTimeInMs(); if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timestamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); } }
int ByteStream_readUint16(ByteStream self, uint16_t* value) { uint8_t byte[2]; int bytes_read; uint64_t start = Hal_getTimeInMs(); do { bytes_read = Socket_read(self->socket, byte, 2); } while ((bytes_read == 0) && ((Hal_getTimeInMs() - start) < CONFIG_TCP_READ_TIMEOUT_MS)); if (bytes_read != 2) { return -1; } *value = (byte[0] * 0x100) + byte[1]; return 2; }
int ByteStream_skipBytes(ByteStream self, int number) { int c = 0; uint8_t byte; uint64_t start = Hal_getTimeInMs(); do { int readBytes = Socket_read(self->socket, &byte, 1); if (readBytes < 0) return -1; else c = c + readBytes; } while ((c < number) && ((Hal_getTimeInMs() - start) < CONFIG_TCP_READ_TIMEOUT_MS)); return c; }
int ByteStream_readOctets(ByteStream self, uint8_t* buffer, int size) { int readBytes = 0; int remainingSize = size; uint64_t start = Hal_getTimeInMs(); do { int chunkSize = Socket_read(self->socket, buffer + readBytes, remainingSize); if (chunkSize < 0) return -1; else { readBytes += chunkSize; remainingSize = size - readBytes; } } while ((readBytes < size) && ((Hal_getTimeInMs() - start) < CONFIG_TCP_READ_TIMEOUT_MS)); return readBytes; }
bool ControlObject_select(ControlObject* self) { initialize(self); uint64_t currentTime = Hal_getTimeInMs(); if (isSelected(self, currentTime)) return false; else selectObject(self, currentTime); return true; }
int main(int argc, char** argv) { IedServer iedServer = IedServer_create(&iedModel); // TODO get stored values from persistent storage // TODO set initial measurement and status values from process /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, 102); if (!IedServer_isRunning(iedServer)) { printf("Starting server failed! Exit.\n"); IedServer_destroy(iedServer); exit(-1); } running = 1; signal(SIGINT, sigint_handler); float power = 500.f; while (running) { uint64_t timeval = Hal_getTimeInMs(); IedServer_lockDataModel(iedServer); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_Inverter_MMXU1_TotW_mag_f, power); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_Inverter_MMXU1_TotW_t, timeval); IedServer_unlockDataModel(iedServer); power += 0.1f; Thread_sleep(500); } /* stop MMS server - close TCP server socket and all client sockets */ IedServer_stop(iedServer); /* Cleanup - free all resources */ IedServer_destroy(iedServer); return 0; } /* main() */
void ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, ReportInclusionFlag flag) { self->inclusionFlags[dataSetEntryIndex] = flag; if (self->triggered == false) { uint64_t currentTime = Hal_getTimeInMs(); MmsValue* timeOfEntry = self->timeOfEntry; MmsValue_setBinaryTime(timeOfEntry, currentTime); self->reportTime = currentTime + self->bufTm; } self->triggered = true; }
bool controlHandlerForIntegerOutput(void* parameter, MmsValue* value, bool test) { if (MmsValue_getType(value) != MMS_INTEGER) return false; printf("Received integer control value: %i\n", MmsValue_toInt32(value)); uint64_t timeStamp = Hal_getTimeInMs(); if (parameter == IEDMODEL_WTG_WTUR1_SetTurOp_actSt) { IedServer_updateAttributeValue(iedServer, IEDMODEL_WTG_WTUR1_SetTurOp_actSt_stVal, value); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_WTG_WTUR1_SetTurOp_actSt_t, timeStamp); } return true; }
bool ControlObject_operate(ControlObject* self, MmsValue* value) { initialize(self); uint64_t currentTime = Hal_getTimeInMs(); if (isSelected(self, currentTime)) { self->selectTime = currentTime; if (self->listener != NULL) { self->listener(self->listenerParameter, value); } return true; } return false; }
static ControlHandlerResult controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) { if (test) return CONTROL_RESULT_FAILED; if (MmsValue_getType(value) == MMS_BOOLEAN) { printf("received binary control command: "); if (MmsValue_getBoolean(value)) printf("on\n"); else printf("off\n"); } else return CONTROL_RESULT_FAILED; uint64_t timeStamp = Hal_getTimeInMs(); if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value); } if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp); IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value); } return CONTROL_RESULT_OK; }
int main(int argc, char** argv) { printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString()); iedServer = IedServer_create(&iedModel); /* Install handler for operate command */ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO1); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO2); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO3); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO4); IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, 102); if (!IedServer_isRunning(iedServer)) { printf("Starting server failed! Exit.\n"); IedServer_destroy(iedServer); exit(-1); } running = 1; signal(SIGINT, sigint_handler); float t = 0.f; while (running) { uint64_t timestamp = Hal_getTimeInMs(); t += 0.1f; float an1 = sinf(t); float an2 = sinf(t + 1.f); float an3 = sinf(t + 2.f); float an4 = sinf(t + 3.f); IedServer_lockDataModel(iedServer); Timestamp iecTimestamp; Timestamp_clearFlags(&iecTimestamp); Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp); Timestamp_setLeapSecondKnown(&iecTimestamp, true); /* toggle clock-not-synchronized flag in timestamp */ if (((int) t % 2) == 0) Timestamp_setClockNotSynchronized(&iecTimestamp, true); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, &iecTimestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, &iecTimestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, &iecTimestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4); IedServer_unlockDataModel(iedServer); Thread_sleep(100); } /* stop MMS server - close TCP server socket and all client sockets */ IedServer_stop(iedServer); /* Cleanup - free all resources */ IedServer_destroy(iedServer); } /* main() */
int main(int argc, char** argv) { iedServer = IedServer_create(&iedModel); /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, 102); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO1); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO2); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO3); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO4); if (!IedServer_isRunning(iedServer)) { printf("Starting server failed! Exit.\n"); IedServer_destroy(iedServer); exit(-1); } /* Start GOOSE publishing */ IedServer_enableGoosePublishing(iedServer); running = 1; signal(SIGINT, sigint_handler); float anIn1 = 0.f; while (running) { IedServer_lockDataModel(iedServer); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, Hal_getTimeInMs()); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, anIn1); IedServer_unlockDataModel(iedServer); anIn1 += 0.1; Thread_sleep(1000); } /* stop MMS server - close TCP server socket and all client sockets */ IedServer_stop(iedServer); /* Cleanup - free all resources */ IedServer_destroy(iedServer); } /* main() */
MmsValue* Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection) { MmsValue* value = NULL; if (DEBUG_IED_SERVER) printf("IED_SERVER: readAccessControlObject: %s\n", variableIdOrig); char variableId[129]; strncpy(variableId, variableIdOrig, 128); variableId[128] = 0; char* separator = strchr(variableId, '$'); if (separator == NULL) return NULL; *separator = 0; char* lnName = variableId; if (lnName == NULL) return NULL; char* objectName = MmsMapping_getNextNameElement(separator + 1); if (objectName == NULL) return NULL; char* varName = MmsMapping_getNextNameElement(objectName); if (varName != NULL) { bool foundVar = false; char* nextVarName = varName; do { if (doesElementEquals(varName, "Oper") || doesElementEquals(varName, "SBO") || doesElementEquals(varName, "SBOw") || doesElementEquals(varName, "Cancel")) { *(varName - 1) = 0; foundVar = true; break; } nextVarName = MmsMapping_getNextNameElement(varName); if (nextVarName != NULL) varName = nextVarName; } while (nextVarName != NULL); if (foundVar == false) varName = NULL; } if (DEBUG_IED_SERVER) printf("IED_SERVER: read_access control object: objectName: (%s) varName: (%s)\n", objectName, varName); ControlObject* controlObject = Control_lookupControlObject(self, domain, lnName, objectName); if (controlObject != NULL) { initialize(controlObject); if (varName != NULL) { if (strcmp(varName, "Oper") == 0) value = ControlObject_getOper(controlObject); else if (strcmp(varName, "SBOw") == 0) value = ControlObject_getSBOw(controlObject); else if (strcmp(varName, "SBO") == 0) { if (controlObject->ctlModel == 2) { uint64_t currentTime = Hal_getTimeInMs(); value = controlObject->emptyString; checkSelectTimeout(controlObject, currentTime); if (getState(controlObject) == STATE_UNSELECTED) { CheckHandlerResult checkResult = CONTROL_ACCEPTED; if (controlObject->checkHandler != NULL) { /* perform operative tests */ checkResult = controlObject->checkHandler( controlObject->checkHandlerParameter, NULL, false, false, (ClientConnection) connection); } if (checkResult == CONTROL_ACCEPTED) { selectObject(controlObject, currentTime, connection); value = ControlObject_getSBO(controlObject); } } } else { if (DEBUG_IED_SERVER) printf("IED_SERVER: select not applicable for control model %i\n", controlObject->ctlModel); value = ControlObject_getSBO(controlObject); } } else if (strcmp(varName, "Cancel") == 0) value = ControlObject_getCancel(controlObject); else { value = MmsValue_getSubElement(ControlObject_getMmsValue(controlObject), ControlObject_getTypeSpec(controlObject), varName); } } else value = ControlObject_getMmsValue(controlObject); } return value; }
int main(int argc, char** argv) { iedServer = IedServer_create(&iedModel); /* Install handler for operate command */ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO1); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO2); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO3); IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, (ControlHandler) controlHandlerForBinaryOutput, IEDMODEL_GenericIO_GGIO1_SPCSO4); /* MMS server will be instructed to start listening to client connections. */ IedServer_startThreadless(iedServer, 102); if (!IedServer_isRunning(iedServer)) { printf("Starting server failed! Exit.\n"); IedServer_destroy(iedServer); exit(-1); } running = 1; signal(SIGINT, sigint_handler); float t = 0.f; uint64_t lastTimestamp = Hal_getTimeInMs(); while (running) { uint64_t timestamp = Hal_getTimeInMs(); if (timestamp - lastTimestamp >= 100) { t += 0.1f; float an1 = sinf(t); float an2 = sinf(t + 1.f); float an3 = sinf(t + 2.f); float an4 = sinf(t + 3.f); IedServer_lockDataModel(iedServer); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, timestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, timestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, timestamp); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4); IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, timestamp); IedServer_unlockDataModel(iedServer); lastTimestamp = timestamp; } /* Has to be called whenever the TCP stack receives data */ IedServer_processIncomingData(iedServer); /* Has to be called periodically */ IedServer_performPeriodicTasks(iedServer); Thread_sleep(1); } /* stop MMS server - close TCP server socket and all client sockets */ IedServer_stopThreadless(iedServer); /* Cleanup - free all resources */ IedServer_destroy(iedServer); } /* main() */
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; }
MmsDataAccessError Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsValue* value, MmsServerConnection connection) { MmsDataAccessError indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; if (DEBUG_IED_SERVER) printf("IED_SERVER: writeAccessControlObject: %s\n", variableIdOrig); char variableId[65]; strncpy(variableId, variableIdOrig, 64); variableId[64] = 0; char* separator = strchr(variableId, '$'); if (separator == NULL) goto free_and_return; *separator = 0; char* lnName = variableId; if (lnName == NULL) goto free_and_return; char* objectName = MmsMapping_getNextNameElement(separator + 1); if (objectName == NULL) goto free_and_return; char* varName = MmsMapping_getNextNameElement(objectName); if (varName != NULL) { bool foundVar = false; char* nextVarName = varName; do { if (doesElementEquals(varName, "Oper") || doesElementEquals(varName, "SBO") || doesElementEquals(varName, "SBOw") || doesElementEquals(varName, "Cancel")) { *(varName - 1) = 0; foundVar = true; break; } nextVarName = MmsMapping_getNextNameElement(varName); if (nextVarName != NULL) varName = nextVarName; } while (nextVarName != NULL); if (foundVar == false) varName = NULL; } if (DEBUG_IED_SERVER) printf("IED_SERVER: write access control: objectName: (%s) varName: (%s)\n", objectName, varName); if (varName == NULL) { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } ControlObject* controlObject = Control_lookupControlObject(self, domain, lnName, objectName); if (controlObject == NULL) { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } initialize(controlObject); if (strcmp(varName, "SBOw") == 0) { /* select with value */ if (controlObject->ctlModel == 4) { MmsValue* ctlVal = getCtlVal(value); if (ctlVal != NULL) { MmsValue* ctlNum = getOperParameterCtlNum(value); MmsValue* origin = getOperParameterOrigin(value); MmsValue* check = getOperParameterCheck(value); MmsValue* test = getOperParameterTest(value); if (checkValidityOfOriginParameter(origin) == false) { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto free_and_return; } uint64_t currentTime = Hal_getTimeInMs(); checkSelectTimeout(controlObject, currentTime); int state = getState(controlObject); if (state != STATE_UNSELECTED) { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (connection != controlObject->mmsConnection) ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); else ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ADD_CAUSE_OBJECT_ALREADY_SELECTED, ctlNum, origin, true); if (DEBUG_IED_SERVER) printf("SBOw: select failed!\n"); } else { CheckHandlerResult checkResult = CONTROL_ACCEPTED; bool interlockCheck = MmsValue_getBitStringBit(check, 1); bool testCondition = MmsValue_getBoolean(test); if (controlObject->checkHandler != NULL) { /* perform operative tests */ ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); checkResult = controlObject->checkHandler( controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, clientConnection); } if (checkResult == CONTROL_ACCEPTED) { selectObject(controlObject, currentTime, connection); updateControlParameters(controlObject, ctlVal, ctlNum, origin); indication = DATA_ACCESS_ERROR_SUCCESS; if (DEBUG_IED_SERVER) printf("SBOw: selected successful\n"); } else { indication = getDataAccessErrorFromCheckHandlerResult(checkResult); ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ADD_CAUSE_SELECT_FAILED, ctlNum, origin, true); if (DEBUG_IED_SERVER) printf("SBOw: select rejected by application!\n"); } } } else { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } } else { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } } else if (strcmp(varName, "Oper") == 0) { MmsValue* ctlVal = getCtlVal(value); MmsValue* test = getOperParameterTest(value); MmsValue* ctlNum = getOperParameterCtlNum(value); MmsValue* origin = getOperParameterOrigin(value); MmsValue* check = getOperParameterCheck(value); MmsValue* timeParameter = getOperParameterTime(value); if ((ctlVal == NULL) || (test == NULL) || (ctlNum == NULL) || (origin == NULL) || (check == NULL) || (timeParameter == NULL)) { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto free_and_return; } if (checkValidityOfOriginParameter(origin) == false) { indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto free_and_return; } uint64_t currentTime = Hal_getTimeInMs(); checkSelectTimeout(controlObject, currentTime); int state = getState(controlObject); if (state == STATE_WAIT_FOR_ACTIVATION_TIME) { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION, ctlNum, origin, true); goto free_and_return; } else if (state == STATE_READY) { bool interlockCheck = MmsValue_getBitStringBit(check, 1); bool synchroCheck = MmsValue_getBitStringBit(check, 0); bool testCondition = MmsValue_getBoolean(test); controlObject->testMode = testCondition; if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { if (controlObject->mmsConnection != connection) { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (DEBUG_IED_SERVER) printf("Oper: operate from wrong client connection!\n"); goto free_and_return; } if (controlObject->ctlModel == 4) { /* select-before-operate with enhanced security */ if ((MmsValue_equals(ctlVal, controlObject->ctlVal) && MmsValue_equals(origin, controlObject->origin) && MmsValue_equals(ctlNum, controlObject->ctlNum)) == false) { indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_INCONSISTENT_PARAMETERS, ctlNum, origin, true); goto free_and_return; } } } updateControlParameters(controlObject, ctlVal, ctlNum, origin); MmsValue* operTm = getOperParameterOperTime(value); if (operTm != NULL) { controlObject->operateTime = MmsValue_getUtcTimeInMs(operTm); if (controlObject->operateTime != 0) { controlObject->timeActivatedOperate = true; controlObject->synchroCheck = synchroCheck; controlObject->interlockCheck = interlockCheck; controlObject->mmsConnection = connection; initiateControlTask(controlObject); setState(controlObject, STATE_WAIT_FOR_ACTIVATION_TIME); if (DEBUG_IED_SERVER) printf("Oper: activate time activated control\n"); indication = DATA_ACCESS_ERROR_SUCCESS; } } MmsValue_update(controlObject->oper, value); if (controlObject->timeActivatedOperate == false) { CheckHandlerResult checkResult = CONTROL_ACCEPTED; if (controlObject->checkHandler != NULL) { /* perform operative tests */ ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); checkResult = controlObject->checkHandler( controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, clientConnection); } if (checkResult == CONTROL_ACCEPTED) { indication = DATA_ACCESS_ERROR_NO_RESPONSE; controlObject->mmsConnection = connection; controlObject->operateInvokeId = MmsServerConnection_getLastInvokeId(connection); setState(controlObject, STATE_WAIT_FOR_EXECUTION); initiateControlTask(controlObject); #if (CONFIG_MMS_THREADLESS_STACK == 1) //TODO call this in single threaded version to increase response time!? //executeControlTask(controlObject); #endif } else { indication = getDataAccessErrorFromCheckHandlerResult(checkResult); abortControlOperation(controlObject); } } } else if (state == STATE_UNSELECTED) { if (DEBUG_IED_SERVER) printf("IED_SERVER: Oper failed - control not selected!\n"); indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_OBJECT_NOT_SELECTED, ctlNum, origin, true); goto free_and_return; } } else if (strcmp(varName, "Cancel") == 0) { if (DEBUG_IED_SERVER) printf("IED_SERVER: control received cancel!\n"); int state = getState(controlObject); MmsValue* ctlNum = getCancelParameterCtlNum(value); MmsValue* origin = getCancelParameterOrigin(value); if ((ctlNum == NULL) || (origin == NULL)) { indication = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; if (DEBUG_IED_SERVER) printf("IED_SERVER: Invalid cancel message!\n"); goto free_and_return; } if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { if (state != STATE_UNSELECTED) { if (controlObject->mmsConnection == connection) { indication = DATA_ACCESS_ERROR_SUCCESS; setState(controlObject, STATE_UNSELECTED); goto free_and_return; } else { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Cancel", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); } } } if (controlObject->timeActivatedOperate) { controlObject->timeActivatedOperate = false; abortControlOperation(controlObject); indication = DATA_ACCESS_ERROR_SUCCESS; goto free_and_return; } } free_and_return: return indication; }
static int parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) { int bufPos = 0; uint32_t timeAllowedToLive = 0; uint32_t stNum = 0; uint32_t sqNum = 0; uint32_t confRev; bool simulation = false; bool ndsCom = false; GooseSubscriber matchingSubscriber = NULL; uint8_t* timestampBufPos = NULL; uint8_t* dataSetBufferAddress = NULL; int dataSetBufferLength = 0; uint32_t numberOfDatSetEntries = 0; if (buffer[bufPos++] == 0x61) { int gooseLength; bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); int gooseEnd = bufPos + gooseLength; while (bufPos < gooseEnd) { int elementLength; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); if (bufPos + elementLength > apduLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); goto exit_with_fault; } if (bufPos == -1) goto exit_with_fault; switch(tag) { case 0x80: /* gocbRef */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found gocbRef\n"); { LinkedList element = LinkedList_getNext(self->subscriberList); while (element != NULL) { GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); if (subscriber->goCBRefLen == elementLength) { if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n"); matchingSubscriber = subscriber; break; } } element = LinkedList_getNext(element); } if (matchingSubscriber == NULL) return 0; } break; case 0x81: /* timeAllowedToLive */ timeAllowedToLive = BerDecoder_decodeUint32(buffer, elementLength, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timeAllowedToLive %u\n", timeAllowedToLive); break; case 0x82: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found dataSet\n"); break; case 0x83: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found goId\n"); break; case 0x84: timestampBufPos = buffer + bufPos; if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timestamp\n"); break; case 0x85: stNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found stNum: %u\n", stNum); break; case 0x86: sqNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found sqNum: %u\n", sqNum); break; case 0x87: simulation = BerDecoder_decodeBoolean(buffer, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found simulation: %i\n", simulation); break; case 0x88: confRev = BerDecoder_decodeUint32(buffer, elementLength, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found confRev: %u\n", confRev); break; case 0x89: ndsCom = BerDecoder_decodeBoolean(buffer, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found ndsCom: %i\n", ndsCom); break; case 0x8a: numberOfDatSetEntries = BerDecoder_decodeUint32(buffer, elementLength, bufPos); if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found number of entries: %u\n", numberOfDatSetEntries); break; case 0xab: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found all data with length: %i\n", elementLength); dataSetBufferAddress = buffer + bufPos; dataSetBufferLength = elementLength; break; default: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Unknown tag %02x\n", tag); break; } bufPos += elementLength; } if (matchingSubscriber != NULL) { matchingSubscriber->timeAllowedToLive = timeAllowedToLive; matchingSubscriber->confRev = confRev; matchingSubscriber->ndsCom = ndsCom; matchingSubscriber->simulation = simulation; MmsValue_setUtcTimeByBuffer(matchingSubscriber->timestamp, timestampBufPos); if (matchingSubscriber->dataSetValues == NULL) matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false); else parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues); bool isValid = true; if (matchingSubscriber->stNum == stNum) { if (matchingSubscriber->sqNum >= sqNum) { isValid = false; } } matchingSubscriber->stateValid = isValid; matchingSubscriber->stNum = stNum; matchingSubscriber->sqNum = sqNum; matchingSubscriber->invalidityTime = Hal_getTimeInMs() + timeAllowedToLive; if (matchingSubscriber->listener != NULL) matchingSubscriber->listener(matchingSubscriber, matchingSubscriber->listenerParameter); return 1; } return 0; } exit_with_fault: if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Invalid goose payload\n"); return -1; }
static void executeControlTask(ControlObject* self) { int state; executeStateMachine: state = getState(self); switch (state) { case STATE_WAIT_FOR_ACTIVATION_TIME: case STATE_WAIT_FOR_EXECUTION: { ControlHandlerResult dynamicCheckResult = CONTROL_RESULT_OK; bool isTimeActivatedControl = false; if (state == STATE_WAIT_FOR_ACTIVATION_TIME) isTimeActivatedControl = true; if (self->waitForExecutionHandler != NULL) { dynamicCheckResult = self->waitForExecutionHandler(self->waitForExecutionHandlerParameter, self->ctlVal, self->testMode, self->synchroCheck); } if (dynamicCheckResult == CONTROL_RESULT_FAILED) { if (isTimeActivatedControl) { ControlObject_sendLastApplError(self, self->mmsConnection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK, self->ctlNum, self->origin, false); } else MmsServerConnection_sendWriteResponse(self->mmsConnection, self->operateInvokeId, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED, true); abortControlOperation(self); exitControlTask(self); } else if (dynamicCheckResult == CONTROL_RESULT_OK) { if (isTimeActivatedControl) { ControlObject_sendCommandTerminationPositive(self); MmsValue* operTm = getOperParameterOperTime(self->oper); MmsValue_setUtcTime(operTm, 0); } else MmsServerConnection_sendWriteResponse(self->mmsConnection, self->operateInvokeId, DATA_ACCESS_ERROR_SUCCESS, true); setState(self, STATE_OPERATE); goto executeStateMachine; } } break; case STATE_OPERATE: { uint64_t currentTime = Hal_getTimeInMs(); ControlHandlerResult result = operateControl(self, self->ctlVal, currentTime, self->testMode); if (result != CONTROL_RESULT_WAITING) { if (result == CONTROL_RESULT_OK) { if ((self->ctlModel == 4) || (self->ctlModel == 3)) { ControlObject_sendCommandTerminationPositive(self); } } else { if ((self->ctlModel == 4) || (self->ctlModel == 3)) { if (DEBUG_IED_SERVER) printf("IED_SERVER: operate failed!\n"); ControlObject_sendCommandTerminationNegative(self); } } abortControlOperation(self); exitControlTask(self); } } break; } }