From 725c0b1090d4181dc95287b269b5ae195e4b63fd Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 16 Jan 2024 17:25:25 +0000 Subject: [PATCH 1/7] - implemented function to create a forecast of the result schedule for a schedule controller - fixed some memory leaks --- examples/scheduler_example1.c | 38 ++- src/scheduler/der_scheduler.c | 76 ++++- src/scheduler/der_scheduler.h | 27 ++ src/scheduler/der_scheduler_internal.h | 26 ++ src/scheduler/schedule.c | 395 ++++++++++++++++++++++--- src/scheduler/schedule_controller.c | 223 ++++++++++++++ src/scheduler/storage/storage_json.c | 8 +- tests/test_client.c | 2 +- 8 files changed, 740 insertions(+), 55 deletions(-) diff --git a/examples/scheduler_example1.c b/examples/scheduler_example1.c index 3cf2b6f..2d6cc5c 100644 --- a/examples/scheduler_example1.c +++ b/examples/scheduler_example1.c @@ -138,14 +138,48 @@ main(int argc, char** argv) IedServer_start(server, 102); - if (IedServer_isRunning(server)) { + int count = 0; + if (IedServer_isRunning(server)) + { running = true; Thread_start(workerThread); - while (running) { + while (running) + { + if (count % 50 == 0) { + printf("Create forecast 24 h...\n"); + + uint64_t currentTime = Hal_getTimeInMs(); + + LinkedList forecast = Scheduler_createForecast(sched, "@Control/ActPow_FSCC1", currentTime, currentTime + 86400000); + + if (forecast) + { + LinkedList forecastElem = LinkedList_getNext(forecast); + + while (forecastElem) + { + ScheduleEvent event = (ScheduleEvent)LinkedList_getData(forecastElem); + + char valueBuf[50]; + if (ScheduleEvent_getValue(event)) + MmsValue_printToBuffer(ScheduleEvent_getValue(event), valueBuf, 50); + else + valueBuf[0] = 0; + + printf("time: %lu value: %s\n", ScheduleEvent_getTime(event), valueBuf); + + forecastElem = LinkedList_getNext(forecastElem); + } + + LinkedList_destroyDeep(forecast, (LinkedListValueDeleteFunction)ScheduleEvent_destroy); + } + } + Thread_sleep(100); + count++; } } else { diff --git a/src/scheduler/der_scheduler.c b/src/scheduler/der_scheduler.c index 6bc2e24..8cc4605 100644 --- a/src/scheduler/der_scheduler.c +++ b/src/scheduler/der_scheduler.c @@ -230,6 +230,10 @@ Scheduler_destroy(Scheduler self) LinkedList_destroyDeep(self->schedules, (LinkedListValueDeleteFunction)Schedule_destroy); + if (self->storage) { + SchedulerStorage_destroy(self->storage); + } + free(self); } } @@ -247,6 +251,38 @@ Scheduler_enableScheduleControl(Scheduler self, const char* scheduleRef, bool en } } +LinkedList +Scheduler_createScheduleForecast(Scheduler self, const char* scheduleRef, uint64_t startTime, uint64_t endTime) +{ + Schedule schedule = Scheduler_getScheduleByObjRef(self, scheduleRef); + + if (schedule) + { + return Schedule_runSchedule(schedule, startTime, endTime); + } + else { + printf("WARN: Schedule %s not found\n", scheduleRef); + + return NULL; + } +} + +LinkedList +Scheduler_createForecast(Scheduler self, const char* schedCtrRef, uint64_t startTime, uint64_t endTime) +{ + ScheduleController scc = Scheduler_getScheduleControllerByObjRef(self, schedCtrRef); + + if (scc) + { + return ScheduleController_createForecast(scc, startTime, endTime); + } + else { + printf("WARN: Schedule controller %s not found\n", schedCtrRef); + + return NULL; + } +} + bool Scheduler_enableSchedule(Scheduler self, const char* scheduleRef, bool enable) { @@ -316,8 +352,8 @@ Scheduler_getScheduleByObjRef(Scheduler self, const char* objRef) { Schedule matchingSchedule = NULL; - if (objRef && objRef[0] != 0) { - + if (objRef && objRef[0] != 0) + { bool withoutIedName = false; if (objRef[0] == '@') { @@ -345,3 +381,39 @@ Scheduler_getScheduleByObjRef(Scheduler self, const char* objRef) return matchingSchedule; } + +ScheduleController +Scheduler_getScheduleControllerByObjRef(Scheduler self, const char* objRef) +{ + ScheduleController matchingController = NULL; + + if (objRef && objRef[0] != 0) + { + bool withoutIedName = false; + + if (objRef[0] == '@') { + withoutIedName = true; + objRef = objRef + 1; + } + + LinkedList controllerElem = LinkedList_getNext(self->scheduleController); + + while (controllerElem) + { + ScheduleController controller = (ScheduleController)LinkedList_getData(controllerElem); + + char controllerObjRefBuf[130]; + + ModelNode_getObjectReferenceEx((ModelNode*)controller->controllerLn, controllerObjRefBuf, withoutIedName); + + if (!strcmp(objRef, controllerObjRefBuf)) { + matchingController = controller; + break; + } + + controllerElem = LinkedList_getNext(controllerElem); + } + } + + return matchingController; +} diff --git a/src/scheduler/der_scheduler.h b/src/scheduler/der_scheduler.h index 2b24848..1321329 100644 --- a/src/scheduler/der_scheduler.h +++ b/src/scheduler/der_scheduler.h @@ -89,6 +89,22 @@ Scheduler_getTargetValue(Scheduler self, const char* controllerRef, char* target void Scheduler_enableScheduleControl(Scheduler self, const char* scheduleRef, bool enable); +LinkedList /* */ +Scheduler_createScheduleForecast(Scheduler self, const char* scheduleRef, uint64_t startTime, uint64_t endTime); + +/** + * @brief Create a schedule forecast for the specified schedule controller and time period + * + * @param self the scheduler instance + * @param schedCtrRef the object reference of the ScheduleController (@LDInst/LN) + * @param startTime the start time of the forecast time period (in ms since Epoch) + * @param endTime the end time of the forecast time period (in ms since Epoch) + * + * @return the list of schedule events (value changes) during the time period + */ +LinkedList /* */ +Scheduler_createForecast(Scheduler self, const char* schedCtrRef, uint64_t startTime, uint64_t endTime); + /** * @brief Enable or disable a schedule * @@ -128,6 +144,17 @@ Scheduler_enableWriteAccessToParameter(Scheduler self, const char* scheduleRef, void Scheduler_destroy(Scheduler self); +typedef struct sScheduleEvent* ScheduleEvent; + +MmsValue* +ScheduleEvent_getValue(ScheduleEvent self); + +uint64_t +ScheduleEvent_getTime(ScheduleEvent self); + +void +ScheduleEvent_destroy(ScheduleEvent self); + #ifdef __cplusplus } #endif diff --git a/src/scheduler/der_scheduler_internal.h b/src/scheduler/der_scheduler_internal.h index 03380a1..5a7e0b7 100644 --- a/src/scheduler/der_scheduler_internal.h +++ b/src/scheduler/der_scheduler_internal.h @@ -114,6 +114,20 @@ struct sScheduler void* targetValueHandlerParameter; }; +struct sScheduleEvent +{ + uint64_t timestamp; + uint64_t lastStartTime; + MmsValue* value; + int priority; +}; + +ScheduleEvent +ScheduleEvent_create(uint64_t timestamp, MmsValue* value, int priority, uint64_t startTime); + +void +ScheduleEvent_destroy(ScheduleEvent self); + void scheduler_targetValueChanged(Scheduler self, ModelNode* targetAttr, MmsValue* value, Quality quality, uint64_t timestampMs); @@ -147,6 +161,9 @@ scheduleController_scheduleValueUpdated(ScheduleController self, Schedule sched, void ScheduleController_initialize(ScheduleController self); +LinkedList +ScheduleController_createForecast(ScheduleController self, uint64_t startTime, uint64_t endTime); + Schedule Schedule_create(LogicalNode* schedLn, IedServer server, IedModel* model); @@ -204,6 +221,9 @@ scheduler_checkIfMultiObjInst(const char* name, const char* multiName); Schedule Scheduler_getScheduleByObjRef(Scheduler self, const char* objRef); +ScheduleController +Scheduler_getScheduleControllerByObjRef(Scheduler self, const char* objRef); + void Schedule_setListeningController(Schedule self, ScheduleController controller); @@ -222,6 +242,12 @@ Schedule_enableWriteAccessToStrTm(Schedule self, bool enable); void Schedule_enableWriteAccessToSchdReuse(Schedule self, bool enable); +ScheduleEvent +Schedule_getValueAt(Schedule self, uint64_t timestamp); + +LinkedList +Schedule_runSchedule(Schedule self, uint64_t startTime, uint64_t endTime); + SchedulerStorage SchedulerStorage_init(const char* databaseUri, int numberOfParameters, const char** parameters); diff --git a/src/scheduler/schedule.c b/src/scheduler/schedule.c index 2481b4c..c45740b 100644 --- a/src/scheduler/schedule.c +++ b/src/scheduler/schedule.c @@ -422,23 +422,33 @@ schedule_updateNxtStrTm(Schedule self, uint64_t nextStartTime) } static uint64_t -updateNextStartTime(DataObject* dObj, uint64_t nextStartTime, uint64_t currentTime) +getStartTimeValue(DataObject* dObj) { + uint64_t strTmValue = 0; + DataAttribute* setTm = (DataAttribute*)ModelNode_getChild((ModelNode*)dObj, "setTm"); if (setTm && setTm->mmsValue) { - uint64_t strTmVal = MmsValue_getUtcTimeInMs(setTm->mmsValue); + strTmValue = MmsValue_getUtcTimeInMs(setTm->mmsValue); + } + + return strTmValue; +} + +static uint64_t +updateNextStartTime(DataObject* dObj, uint64_t nextStartTime, uint64_t currentTime) +{ + uint64_t strTmVal = getStartTimeValue(dObj); - if (strTmVal > currentTime) { + if (strTmVal > currentTime) { - if (nextStartTime == 0) { + if (nextStartTime == 0) { + nextStartTime = strTmVal; + } + else { + if (strTmVal <= nextStartTime) { nextStartTime = strTmVal; } - else { - if (strTmVal <= nextStartTime) { - nextStartTime = strTmVal; - } - } } } @@ -551,11 +561,157 @@ updateNextPeriodicStartTime(Schedule self, DataObject* dObj, uint64_t nextStartT } static uint64_t -schedule_getNextStartTime(Schedule self) +getClosestPeriodicStartTime(Schedule self, DataObject* dObj, uint64_t timestamp, SetCalValues setCalValues) { uint64_t nextStartTime = 0; - uint64_t currentTime = Hal_getTimeInMs(); + /* check if setCal values are supported */ + + if (setCalValues->occTypeVal != 0) { + printf("ERROR: Only occType = Time(0) is supported (is %i)\n", setCalValues->occTypeVal); + + return 0; + } + + if (setCalValues->occPerVal != 0 && setCalValues->occPerVal != 1) { + printf("ERROR: Only occPer = Hour(0) or Day(1) is supported\n"); + + return 0; + } + + /* convert current time to broken down time */ + + uint64_t msPart = timestamp % 1000; + + time_t curTm = timestamp / 1000; + + struct tm btTimeBuf; + + struct tm* brokenDownTime = localtime_r(&curTm, &btTimeBuf); + + if (brokenDownTime == NULL) { + printf("ERROR: Failed to convert timestamp to local time\n"); + + return 0; + } + + if (setCalValues->occPerVal == 1 /* Day */) + { + brokenDownTime->tm_hour = setCalValues->hrVal; + + /* convert to unix time and check if is in the future or past */ + uint64_t startTime = (timelocal(brokenDownTime) * 1000) + msPart; + + /* if this time is in the future then check if it is the new nextStartTime */ + if (startTime <= timestamp) + { + /* check if the periodic schedule is currently running */ + uint64_t lastExecutionEnd = startTime + (Schedule_getSchdIntvInMs(self) * Schedule_getNumEntr(self)); + + if (timestamp < lastExecutionEnd) { + nextStartTime = startTime; + } + } + + return nextStartTime; + } + else /* (setCalValues->occPerVal == 0 (Hour)) */ + { + brokenDownTime->tm_min = setCalValues->mnVal; + + /* convert to unix time and check if is in the future or past */ + uint64_t startTime = (timelocal(brokenDownTime) * 1000) + msPart; + + /* if this time is in the future then check if it is the new nextStartTime */ + if (startTime <= timestamp) + { + /* check if the periodic schedule is currently running */ + uint64_t lastExecutionEnd = startTime + (Schedule_getSchdIntvInMs(self) * Schedule_getNumEntr(self)); + + if (timestamp < lastExecutionEnd) { + nextStartTime = startTime; + } + } + + return nextStartTime; + } +} + +static uint64_t +schedule_getClosestStartTime(Schedule self, uint64_t timestamp) +{ + uint64_t nextStartTime = 0; + + //TODO move to object variable to avoid calling this function again and again? + LinkedList dataObjects = ModelNode_getChildren((ModelNode*)self->scheduleLn); + + LinkedList doElem = LinkedList_getNext(dataObjects); + + while (doElem) + { + DataObject* dObj = (DataObject*)LinkedList_getData(doElem); + + // check that data object name is "StrTmXXX" + if (checkIfStrTm(dObj->name)) + { + if (isPeriodic(self)) + { + struct sSetCalValues setCalValues; + + if (handleSetCal(self, dObj, &setCalValues)) + { + uint64_t strTmVal = getClosestPeriodicStartTime(self, dObj, timestamp, &setCalValues); + + if ((strTmVal <= timestamp) && (strTmVal > nextStartTime)) { + nextStartTime = strTmVal; + } + } + else { + printf("ERROR: Invalid setCal attribute\n"); + } + } + else + { + uint64_t strTmVal = getStartTimeValue(dObj); + + if (nextStartTime == 0) { + nextStartTime = strTmVal; + } + + if ((strTmVal <= timestamp) && (strTmVal > nextStartTime)) { + nextStartTime = strTmVal; + } + } + } + + doElem = LinkedList_getNext(doElem); + } + + uint64_t strTmVal = self->startTime; + + if (nextStartTime == 0) { + nextStartTime = strTmVal; + } + + if ((strTmVal <= timestamp) && (strTmVal > nextStartTime)) { + nextStartTime = strTmVal; + } + + LinkedList_destroyStatic(dataObjects); + + return nextStartTime; +} + +static uint64_t +schedule_getCurrentStartTime(Schedule self) +{ + return self->startTime; +} + +static uint64_t +schedule_getNextStartTime(Schedule self, uint64_t currentTime) +{ + uint64_t nextStartTime = 0; LinkedList dataObjects = ModelNode_getChildren((ModelNode*)self->scheduleLn); @@ -567,8 +723,8 @@ schedule_getNextStartTime(Schedule self) // check that data object name is "StrTmXXX" if (checkIfStrTm(dObj->name)) { - if (isPeriodic(self)) { - //TODO get the next periodic start time + if (isPeriodic(self)) + { struct sSetCalValues setCalValues; if (handleSetCal(self, dObj, &setCalValues)) { @@ -592,18 +748,6 @@ schedule_getNextStartTime(Schedule self) return nextStartTime; } -LinkedList -Schedule_getStartTimes(Schedule self) -{ - LogicalNode* schedLn = self->scheduleLn; - - DataObject* dobj = (DataObject*)(schedLn->firstChild); - - while (dobj) { - - } -} - /** * StrXX value has to be set to "00" when active */ @@ -1229,17 +1373,17 @@ getSchdIntvValueInMs(Schedule self) static int schedule_getNumEntrValue(Schedule self) { - int numEntrVal = -1; + int numEntry = 0; - DataAttribute* numEntr = (DataAttribute*)ModelNode_getChild((ModelNode*)self->scheduleLn, "NumEntr.setVal"); + DataAttribute* numEntry_setVal = (DataAttribute*)ModelNode_getChild((ModelNode*)(self->scheduleLn), "NumEntr.setVal"); - if (numEntr) { - if ((numEntr->mmsValue) && (MmsValue_getType(numEntr->mmsValue) == MMS_INTEGER)) { - numEntrVal = MmsValue_toInt32(numEntr->mmsValue); + if (numEntry_setVal) { + if (numEntry_setVal->mmsValue && MmsValue_getType(numEntry_setVal->mmsValue) == MMS_INTEGER) { + numEntry = MmsValue_toInt32(numEntry_setVal->mmsValue); } } - - return numEntrVal; + + return numEntry; } static bool @@ -1428,7 +1572,7 @@ enabledSchedule(Schedule self) schedule_udpateState(self, newState); if (newState == SCHD_STATE_READY) { - uint64_t nextStartTime = schedule_getNextStartTime(self); + uint64_t nextStartTime = schedule_getNextStartTime(self, Hal_getTimeInMs()); schedule_updateNxtStrTm(self, nextStartTime); @@ -1731,7 +1875,7 @@ schedule_thread(void* parameter) bool startSchedule = false; if (self->nextStartTime == 0) { - self->nextStartTime = schedule_getNextStartTime(self); + self->nextStartTime = schedule_getNextStartTime(self, Hal_getTimeInMs()); } if ((self->nextStartTime != 0) && (currentTime > self->nextStartTime)) { @@ -1753,7 +1897,7 @@ schedule_thread(void* parameter) eraseStartTime(self, self->startTime); - self->nextStartTime = schedule_getNextStartTime(self); + self->nextStartTime = schedule_getNextStartTime(self, Hal_getTimeInMs()); schedule_updateNxtStrTm(self, self->nextStartTime); @@ -1804,7 +1948,7 @@ schedule_thread(void* parameter) schedule_setActStrTmQualityInvalid(self, currentTime, true); /* check for next state */ - self->nextStartTime = schedule_getNextStartTime(self); + self->nextStartTime = schedule_getNextStartTime(self, Hal_getTimeInMs()); if (self->nextStartTime) { schedule_updateNxtStrTm(self, self->nextStartTime); @@ -1837,6 +1981,167 @@ schedule_thread(void* parameter) } } +ScheduleEvent +ScheduleEvent_create(uint64_t timestamp, MmsValue* value, int priority, uint64_t startTime) +{ + ScheduleEvent self = (ScheduleEvent)calloc(1, sizeof(struct sScheduleEvent)); + + if (self) { + self->timestamp = timestamp; + self->lastStartTime = startTime; + self->value = value; + self->priority = priority; + } + + return self; +} + +MmsValue* +ScheduleEvent_getValue(ScheduleEvent self) +{ + return self->value; +} + +uint64_t +ScheduleEvent_getTime(ScheduleEvent self) +{ + return self->timestamp; +} + +void +ScheduleEvent_destroy(ScheduleEvent self) +{ + if (self) + { + MmsValue_delete(self->value); + free(self); + } +} + +ScheduleEvent +Schedule_getValueAt(Schedule self, uint64_t timestamp) +{ + ScheduleEvent event = NULL; + + if ((Schedule_getState(self) == SCHD_STATE_RUNNING) || (Schedule_getState(self) == SCHD_STATE_READY)) + { + // 1. Get the latest start time before timestamp + uint64_t strTmVal = schedule_getClosestStartTime(self, timestamp); + + if (strTmVal > 0) + { + /* check if timestamp is inside the schedule execution */ + int noOfEntryValues = schedule_getNumEntrValue(self); + int intvInMs = Schedule_getSchdIntvInMs(self); + + uint64_t scheduleDuration = noOfEntryValues * intvInMs; + + if ((timestamp >= strTmVal) && (timestamp <= strTmVal + scheduleDuration)) { + uint64_t relTime = timestamp - strTmVal; + + int idx = relTime / intvInMs; + + //TODO printf("idx: %i relTime: %lu intvInMs: %i\n", idx, relTime, intvInMs); + + MmsValue* val = Schedule_getValueWithIdx(self, idx); + + event = ScheduleEvent_create(timestamp, MmsValue_clone(val), Schedule_getPrio(self), strTmVal); + } + } + } + + if (event == NULL) { + event = ScheduleEvent_create(timestamp, NULL, Schedule_getPrio(self), 0); + } + + return event; +} + +LinkedList +Schedule_runSchedule(Schedule self, uint64_t startTime, uint64_t endTime) +{ + LinkedList scheduleEvents = NULL; + + MmsValue* scheduleValueAtStartTime = NULL; + + int priority = Schedule_getPrio(self); + + if (schedule_getState(self) == SCHD_STATE_RUNNING) + { + uint64_t currentTime = Hal_getTimeInMs(); + + DataAttribute* curValue = schedule_getCurrentValueAttribute(self); + + scheduleValueAtStartTime = curValue->mmsValue; + + scheduleEvents = LinkedList_create(); + + ScheduleEvent event = ScheduleEvent_create(currentTime, MmsValue_clone(curValue->mmsValue), priority, self->startTime); + + LinkedList_add(scheduleEvents, event); + + int noOfEntryValues = schedule_getNumEntrValue(self); + int intvInMs = Schedule_getSchdIntvInMs(self); + + int idx = schedule_getCurrentIdx(self, currentTime); + + uint64_t currentStrTm = schedule_getCurrentStartTime(self); + + for (int i = idx + 1; i < noOfEntryValues; i++) + { + uint64_t eventTime = currentStrTm + (i * intvInMs); + + MmsValue* eventValue = Schedule_getValueWithIdx(self, i); + + event = ScheduleEvent_create(eventTime, MmsValue_clone(eventValue), priority, currentStrTm); + + LinkedList_add(scheduleEvents, event); + } + } + else + { + if (schedule_getState(self) != SCHD_STATE_READY) { + /* no schedule available */ + return scheduleEvents; + } + + //get next start time + uint64_t nextStrTm = schedule_getNextStartTime(self, Hal_getTimeInMs()); + + if (nextStrTm == 0) { + /* no schedule available */ + printf("WARNING: No valid next StrTm found\n"); + + return scheduleEvents; + } + else { + scheduleEvents = LinkedList_create(); + + MmsValue* val = Schedule_getValueWithIdx(self, 0); + + ScheduleEvent event = ScheduleEvent_create(nextStrTm, MmsValue_clone(val), priority, nextStrTm); + + int noOfEntryValues = schedule_getNumEntrValue(self); + int intvInMs = Schedule_getSchdIntvInMs(self); + + LinkedList_add(scheduleEvents, event); + + for (int i = 1; i < noOfEntryValues; i++) + { + uint64_t eventTime = nextStrTm + (i * intvInMs); + + MmsValue* eventValue = Schedule_getValueWithIdx(self, i); + + event = ScheduleEvent_create(eventTime, MmsValue_clone(eventValue), priority, nextStrTm); + + LinkedList_add(scheduleEvents, event); + } + } + } + + return scheduleEvents; +} + Schedule Schedule_create(LogicalNode* schedLn, IedServer server, IedModel* model) { @@ -1922,7 +2227,8 @@ Schedule_create(LogicalNode* schedLn, IedServer server, IedModel* model) self = (Schedule)calloc(1, sizeof(struct sSchedule)); - if (self && knownScheduleControllers) { + if (self && knownScheduleControllers) + { self->storage = NULL; self->scheduleLn = schedLn; self->server = server; @@ -2010,6 +2316,9 @@ Schedule_destroy(Schedule self) self->alive = false; Thread_destroy(self->thread); + if (self->knownScheduleControllers) + LinkedList_destroyStatic(self->knownScheduleControllers); + free(self); } } @@ -2072,17 +2381,7 @@ Schedule_setSchdReuse(Schedule self, bool reuse) int Schedule_getNumEntr(Schedule self) { - int numEntry = 0; - - DataAttribute* numEntry_setVal = (DataAttribute*)ModelNode_getChild((ModelNode*)(self->scheduleLn), "NumEntr.setVal"); - - if (numEntry_setVal) { - if (numEntry_setVal->mmsValue && MmsValue_getType(numEntry_setVal->mmsValue) == MMS_INTEGER) { - numEntry = MmsValue_toInt32(numEntry_setVal->mmsValue); - } - } - - return numEntry; + return schedule_getNumEntrValue(self); } void diff --git a/src/scheduler/schedule_controller.c b/src/scheduler/schedule_controller.c index 6f2df37..c6b8ec6 100644 --- a/src/scheduler/schedule_controller.c +++ b/src/scheduler/schedule_controller.c @@ -689,3 +689,226 @@ ScheduleController_initialize(ScheduleController self) Schedule activeSchedule = scheduleController_getActiveSchedule(self); scheduleController_updateActSchdRef(self, activeSchedule); } + +static int +compareUint64(const void* a, const void* b) +{ + uint64_t aVal = *((uint64_t*)a); + uint64_t bVal = *((uint64_t*)b); + + if (aVal == bVal) + return 0; + else if (aVal < bVal) + return -1; + else + return 1; +} + +LinkedList +ScheduleController_createForecast(ScheduleController self, uint64_t startTime, uint64_t endTime) +{ + LinkedList listOfSchedules = LinkedList_create(); + + /* 1. Calculate the forecasts for the individual schedules */ + + LinkedList schedulesElem = LinkedList_getNext(self->schedules); + + int numberOfSchedules = 0; + + while (schedulesElem) + { + Schedule sched = (Schedule)LinkedList_getData(schedulesElem); + + LinkedList scheduleForecast = Schedule_runSchedule(sched, startTime, endTime); + + if (scheduleForecast) { + LinkedList_add(listOfSchedules, scheduleForecast); + numberOfSchedules++; + } + + schedulesElem = LinkedList_getNext(schedulesElem); + } + + /* 2. get the relevant times */ + + uint64_t currentTime = 0; + + LinkedList timestamps = LinkedList_create(); + + LinkedList lastTimestamp = timestamps; + + schedulesElem = LinkedList_getNext(listOfSchedules); + + while (schedulesElem) + { + LinkedList scheduleForecast = LinkedList_getData(schedulesElem); + + LinkedList scheduleForecastElem = LinkedList_getNext(scheduleForecast); + + while (scheduleForecastElem) + { + ScheduleEvent event = (ScheduleEvent)LinkedList_getData(scheduleForecastElem); + + uint64_t* timestamp = (uint64_t*)calloc(1, sizeof(uint64_t)); + + if (timestamp) + { + *timestamp = event->timestamp; + + lastTimestamp = LinkedList_insertAfter(lastTimestamp, timestamp); + } + else { + printf("ERROR: Failed to allocate memory for timestamp\n"); + } + + scheduleForecastElem = LinkedList_getNext(scheduleForecastElem); + } + + LinkedList_destroyDeep(scheduleForecast, (LinkedListValueDeleteFunction)ScheduleEvent_destroy); + + schedulesElem = LinkedList_getNext(schedulesElem); + } + + LinkedList_destroyStatic(listOfSchedules); + + /* remove multiple occurences of timestamps from the list */ + + LinkedList timestampsElem = LinkedList_getNext(timestamps); + + uint64_t previousTimestamp = 0; + int numberOfDifferentTimestamps = 0; + + while (timestampsElem) + { + uint64_t* ts = (uint64_t*)LinkedList_getData(timestampsElem); + + if (*ts != previousTimestamp) { + numberOfDifferentTimestamps++; + previousTimestamp = *ts; + } + + timestampsElem = LinkedList_getNext(timestampsElem); + } + + LinkedList resultSchedule = NULL; + + uint64_t* tsList = (uint64_t*)calloc(numberOfDifferentTimestamps, sizeof(uint64_t)); + + if (tsList) + { + int idx = 0; + previousTimestamp = 0; + numberOfDifferentTimestamps = 0; + + timestampsElem = LinkedList_getNext(timestamps); + + while (timestampsElem) + { + uint64_t* ts = (uint64_t*)LinkedList_getData(timestampsElem); + + bool addToList = true; + + if (idx > 0) + { + for (int j = 0; j < idx; j++) { + if (tsList[j] == *ts) { + addToList = false; + break; + } + } + } + + if (addToList) { + tsList[idx++] = *ts; + numberOfDifferentTimestamps++; + } + + timestampsElem = LinkedList_getNext(timestampsElem); + } + + /* sort the list */ + qsort(tsList, idx, sizeof(uint64_t), compareUint64); + + /* create the result schedule */ + resultSchedule = LinkedList_create(); + + ScheduleEvent lastValue = NULL; + + for (int i = 0; i < numberOfDifferentTimestamps; i++) + { + schedulesElem = LinkedList_getNext(self->schedules); + + ScheduleEvent currentEvent = NULL; + + while (schedulesElem) + { + Schedule sched = (Schedule)LinkedList_getData(schedulesElem); + + ScheduleEvent event = Schedule_getValueAt(sched, tsList[i]); + + if (event) + { + if (event->value) + { + if (currentEvent == NULL) { + currentEvent = event; + } + else + { + if (event->priority > currentEvent->priority) { + ScheduleEvent_destroy(currentEvent); + currentEvent = event; + } + else if (event->priority == currentEvent->priority) { + if (event->lastStartTime > currentEvent->lastStartTime) { + ScheduleEvent_destroy(currentEvent); + currentEvent = event; + } + else { + ScheduleEvent_destroy(event); + } + } + else { + ScheduleEvent_destroy(event); + } + } + } + else { + ScheduleEvent_destroy(event); + } + } + + schedulesElem = LinkedList_getNext(schedulesElem); + } + + if (currentEvent) + { + /* check if value is equal to previous value */ + if ((lastValue != NULL) && + (MmsValue_equals(currentEvent->value, lastValue->value))) + { + ScheduleEvent_destroy(currentEvent); + } + else { + LinkedList_add(resultSchedule, currentEvent); + + char valueBuf[50]; + + MmsValue_printToBuffer(currentEvent->value, valueBuf, 50); + + lastValue = currentEvent; + } + + if (lastValue == NULL) { + lastValue = currentEvent; + } + } + } + + free(tsList); + } + + LinkedList_destroy(timestamps); + + return resultSchedule; +} diff --git a/src/scheduler/storage/storage_json.c b/src/scheduler/storage/storage_json.c index fc03907..ccc93b2 100644 --- a/src/scheduler/storage/storage_json.c +++ b/src/scheduler/storage/storage_json.c @@ -404,8 +404,6 @@ createSchedule(Schedule schedule) } cJSON_AddItemToObject(scheduleJson, "startTimes", startTimes); - - char* jsonStr = cJSON_PrintUnformatted(scheduleJson); exit: return scheduleJson; @@ -579,6 +577,8 @@ getScheduleControllerData(SchedulerStorage self, ScheduleController controller, } } + cJSON_Delete(json); + return true; } @@ -923,6 +923,8 @@ SchedulerStorage_restoreSchedule(SchedulerStorage self, Schedule schedule) getScheduleData(self, schedule, jsonStr); + free(jsonStr); + cJSON_Delete(scheduleJson); } @@ -963,6 +965,8 @@ SchedulerStorage_restoreScheduleController(SchedulerStorage self, ScheduleContro getScheduleControllerData(self, controller, jsonStr); + free(jsonStr); + cJSON_Delete(scheduleJson); } diff --git a/tests/test_client.c b/tests/test_client.c index a78b049..25791b7 100644 --- a/tests/test_client.c +++ b/tests/test_client.c @@ -38,7 +38,7 @@ main(int argc, char** argv) /* configure schedule */ - IedConnection_writeInt32Value(con, &err, "DER_Scheduler_Control/ActPow_FSCH01.SchdPrio.setVal", IEC61850_FC_SP, 10); + IedConnection_writeInt32Value(con, &err, "DER_Scheduler_Control/ActPow_FSCH01.SchdPrio.setVal", IEC61850_FC_SP, 20); if (err != IED_ERROR_OK) { printf("ERROR: failed to set schedule priority\n"); From 092cb6f48b43fd8c035c50446cc30bd1a5d00b1d Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Wed, 17 Jan 2024 11:00:07 +0000 Subject: [PATCH 2/7] - added function Scheduler_getCtlEntityRef --- examples/scheduler_example1.c | 2 ++ src/scheduler/der_scheduler.c | 22 +++++++++++++++++++--- src/scheduler/der_scheduler.h | 3 +++ src/scheduler/der_scheduler_internal.h | 3 +++ src/scheduler/schedule_controller.c | 13 +++++++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/examples/scheduler_example1.c b/examples/scheduler_example1.c index 2d6cc5c..6507769 100644 --- a/examples/scheduler_example1.c +++ b/examples/scheduler_example1.c @@ -136,6 +136,8 @@ main(int argc, char** argv) Thread workerThread = Thread_create(outputWorkerThread, NULL, false); + printf("Target for @Control/ActPow_FSCC1: %s\n", Scheduler_getCtlEntityRef(sched, "@Control/ActPow_FSCC1")); + IedServer_start(server, 102); int count = 0; diff --git a/src/scheduler/der_scheduler.c b/src/scheduler/der_scheduler.c index 8cc4605..26d73c7 100644 --- a/src/scheduler/der_scheduler.c +++ b/src/scheduler/der_scheduler.c @@ -268,16 +268,32 @@ Scheduler_createScheduleForecast(Scheduler self, const char* scheduleRef, uint64 } LinkedList -Scheduler_createForecast(Scheduler self, const char* schedCtrRef, uint64_t startTime, uint64_t endTime) +Scheduler_createForecast(Scheduler self, const char* schedCtrlRef, uint64_t startTime, uint64_t endTime) { - ScheduleController scc = Scheduler_getScheduleControllerByObjRef(self, schedCtrRef); + ScheduleController scc = Scheduler_getScheduleControllerByObjRef(self, schedCtrlRef); if (scc) { return ScheduleController_createForecast(scc, startTime, endTime); } else { - printf("WARN: Schedule controller %s not found\n", schedCtrRef); + printf("WARN: Schedule controller %s not found\n", schedCtrlRef); + + return NULL; + } +} + +const char* +Scheduler_getCtlEntityRef(Scheduler self, const char* schedCtrlRef) +{ + ScheduleController scc = Scheduler_getScheduleControllerByObjRef(self, schedCtrlRef); + + if (scc) + { + return ScheduleController_getCtlEntRef(scc); + } + else { + printf("WARN: Schedule controller %s not found\n", schedCtrlRef); return NULL; } diff --git a/src/scheduler/der_scheduler.h b/src/scheduler/der_scheduler.h index 1321329..38c4d75 100644 --- a/src/scheduler/der_scheduler.h +++ b/src/scheduler/der_scheduler.h @@ -105,6 +105,9 @@ Scheduler_createScheduleForecast(Scheduler self, const char* scheduleRef, uint64 LinkedList /* */ Scheduler_createForecast(Scheduler self, const char* schedCtrRef, uint64_t startTime, uint64_t endTime); +const char* +Scheduler_getCtlEntityRef(Scheduler self, const char* schedCtrlRef); + /** * @brief Enable or disable a schedule * diff --git a/src/scheduler/der_scheduler_internal.h b/src/scheduler/der_scheduler_internal.h index 5a7e0b7..6a4bcf6 100644 --- a/src/scheduler/der_scheduler_internal.h +++ b/src/scheduler/der_scheduler_internal.h @@ -146,6 +146,9 @@ ScheduleController_getScheduleReferenceWithIdx(ScheduleController self, int idx) void ScheduleController_setCtlEnt(ScheduleController self, const char* ctlEntValue); +const char* +ScheduleController_getCtlEntRef(ScheduleController self); + bool ScheduleController_setSchdRef(ScheduleController self, const char* id, const char* ref); diff --git a/src/scheduler/schedule_controller.c b/src/scheduler/schedule_controller.c index c6b8ec6..15a6d3a 100644 --- a/src/scheduler/schedule_controller.c +++ b/src/scheduler/schedule_controller.c @@ -490,7 +490,20 @@ ScheduleController_setCtlEnt(ScheduleController self, const char* ctlEntValue) else { printf("ERROR: ScheduleController_setCtlEnt - CtlEnt.setSrcRef not found!\n"); } +} + +const char* +ScheduleController_getCtlEntRef(ScheduleController self) +{ + const char* result = NULL; + + DataAttribute* ctlEnt_setSrcRef = (DataAttribute*)ModelNode_getChild((ModelNode*)self->controllerLn, "CtlEnt.setSrcRef"); + + if (ctlEnt_setSrcRef && ctlEnt_setSrcRef->mmsValue) { + result = MmsValue_toString(ctlEnt_setSrcRef->mmsValue); + } + return result; } bool From e88adc78e76b0414ced194dba706015f93dec99e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Thu, 18 Jan 2024 12:50:21 +0000 Subject: [PATCH 3/7] - remove outdated values from result schedule Signed-off-by: Michael Zillgith --- src/scheduler/schedule_controller.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/scheduler/schedule_controller.c b/src/scheduler/schedule_controller.c index 15a6d3a..6a9a49e 100644 --- a/src/scheduler/schedule_controller.c +++ b/src/scheduler/schedule_controller.c @@ -842,12 +842,21 @@ ScheduleController_createForecast(ScheduleController self, uint64_t startTime, u /* sort the list */ qsort(tsList, idx, sizeof(uint64_t), compareUint64); + /* remove outdated values (values in the past that are no longer active)*/ + int curIdx = 0; + while (tsList[curIdx] <= currentTime) { + curIdx++; + } + + if (curIdx > 0) + curIdx--; + /* create the result schedule */ resultSchedule = LinkedList_create(); ScheduleEvent lastValue = NULL; - for (int i = 0; i < numberOfDifferentTimestamps; i++) + for (int i = curIdx; i < numberOfDifferentTimestamps; i++) { schedulesElem = LinkedList_getNext(self->schedules); From 7ef6ecdb5100c11c2751f6166edf09ba71faf744 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Thu, 18 Jan 2024 17:42:19 +0000 Subject: [PATCH 4/7] - fixed code to remove outdated values from schedule forecast - append end event to schedules Signed-off-by: Michael Zillgith --- src/scheduler/schedule.c | 43 +++++++++++++++++++++++++++-- src/scheduler/schedule_controller.c | 15 +++++++--- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/scheduler/schedule.c b/src/scheduler/schedule.c index c45740b..38a1ea8 100644 --- a/src/scheduler/schedule.c +++ b/src/scheduler/schedule.c @@ -2076,6 +2076,13 @@ Schedule_runSchedule(Schedule self, uint64_t startTime, uint64_t endTime) scheduleEvents = LinkedList_create(); + char valBuf[100]; + valBuf[0] = 0; + + if (curValue->mmsValue) { + MmsValue_printToBuffer(curValue->mmsValue, valBuf, 100); + } + ScheduleEvent event = ScheduleEvent_create(currentTime, MmsValue_clone(curValue->mmsValue), priority, self->startTime); LinkedList_add(scheduleEvents, event); @@ -2087,16 +2094,32 @@ Schedule_runSchedule(Schedule self, uint64_t startTime, uint64_t endTime) uint64_t currentStrTm = schedule_getCurrentStartTime(self); - for (int i = idx + 1; i < noOfEntryValues; i++) + int i = 0; + + for (i = idx + 1; i < noOfEntryValues; i++) { uint64_t eventTime = currentStrTm + (i * intvInMs); MmsValue* eventValue = Schedule_getValueWithIdx(self, i); + char valBuf[100]; + valBuf[0] = 0; + + if (eventValue) { + MmsValue_printToBuffer(eventValue, valBuf, 100); + } + event = ScheduleEvent_create(eventTime, MmsValue_clone(eventValue), priority, currentStrTm); LinkedList_add(scheduleEvents, event); } + + /* add end event */ + uint64_t eventTime = currentStrTm + (i * intvInMs); + + event = ScheduleEvent_create(eventTime, NULL, priority, currentStrTm); + + LinkedList_add(scheduleEvents, event); } else { @@ -2126,16 +2149,32 @@ Schedule_runSchedule(Schedule self, uint64_t startTime, uint64_t endTime) LinkedList_add(scheduleEvents, event); - for (int i = 1; i < noOfEntryValues; i++) + int i = 0; + + for (i = 1; i < noOfEntryValues; i++) { uint64_t eventTime = nextStrTm + (i * intvInMs); MmsValue* eventValue = Schedule_getValueWithIdx(self, i); + char valBuf[100]; + valBuf[0] = 0; + + if (eventValue) { + MmsValue_printToBuffer(eventValue, valBuf, 100); + } + event = ScheduleEvent_create(eventTime, MmsValue_clone(eventValue), priority, nextStrTm); LinkedList_add(scheduleEvents, event); } + + /* add end event */ + uint64_t eventTime = nextStrTm + (i * intvInMs); + + event = ScheduleEvent_create(eventTime, NULL, priority, nextStrTm); + + LinkedList_add(scheduleEvents, event); } } diff --git a/src/scheduler/schedule_controller.c b/src/scheduler/schedule_controller.c index 6a9a49e..751bf7a 100644 --- a/src/scheduler/schedule_controller.c +++ b/src/scheduler/schedule_controller.c @@ -844,13 +844,10 @@ ScheduleController_createForecast(ScheduleController self, uint64_t startTime, u /* remove outdated values (values in the past that are no longer active)*/ int curIdx = 0; - while (tsList[curIdx] <= currentTime) { + while (tsList[curIdx] < startTime) { curIdx++; } - if (curIdx > 0) - curIdx--; - /* create the result schedule */ resultSchedule = LinkedList_create(); @@ -862,6 +859,8 @@ ScheduleController_createForecast(ScheduleController self, uint64_t startTime, u ScheduleEvent currentEvent = NULL; + //printf("Calculate value for ts %lu\n", tsList[i]); + while (schedulesElem) { Schedule sched = (Schedule)LinkedList_getData(schedulesElem); @@ -872,6 +871,12 @@ ScheduleController_createForecast(ScheduleController self, uint64_t startTime, u { if (event->value) { + char val[200]; + + MmsValue_printToBuffer(event->value, val, 200); + + //printf(" %s: %s\n", sched->scheduleLn->name, val); + if (currentEvent == NULL) { currentEvent = event; } @@ -896,6 +901,8 @@ ScheduleController_createForecast(ScheduleController self, uint64_t startTime, u } } else { + // printf(" %s: no value\n", sched->scheduleLn->name); + ScheduleEvent_destroy(event); } } From fe3d0c032cae7a0333b7ae9cb0be3ea4060c4541 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sun, 21 Jan 2024 17:55:06 +0000 Subject: [PATCH 5/7] - fixed missing return value --- models/model.cfg | 6 +++--- src/scheduler/der_scheduler.h | 30 ++++++++++++++++++++++++++++++ src/scheduler/schedule.c | 9 +++++++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/models/model.cfg b/models/model.cfg index 9d83ac5..a4b4260 100644 --- a/models/model.cfg +++ b/models/model.cfg @@ -148,7 +148,7 @@ DA(multiplier 0 12 4 1 0)=3; DA(d 0 20 5 0 0); } DO(CtlEnt 0){ -DA(setSrcRef 0 19 2 1 0)="@Control/ActPow_GGIO1.AnOut1.mxVal.f"; +DA(setSrcRef 0 19 2 1 0)="@Control/ActPow_GGIO1.AnOut1"; } DO(Schd01 0){ DA(setSrcRef 0 19 2 1 0)="@Control/ActPow_FSCH01"; @@ -208,7 +208,7 @@ DA(multiplier 0 12 4 1 0)=3; DA(d 0 20 5 0 0); } DO(CtlEnt 0){ -DA(setSrcRef 0 19 2 1 0)="@Control/MaxPow_GGIO1.AnOut1.mxVal.f"; +DA(setSrcRef 0 19 2 1 0)="@Control/MaxPow_GGIO1.AnOut1"; } DO(Schd01 0){ DA(setSrcRef 0 19 2 1 0)="@Control/MaxPow_FSCH01"; @@ -261,7 +261,7 @@ DA(q 0 23 0 2 0); DA(t 0 22 0 0 0); } DO(CtlEnt 0){ -DA(setSrcRef 0 19 2 1 0)="@Control/OnOff_GGIO1.SPCSO1.stVal"; +DA(setSrcRef 0 19 2 1 0)="@Control/OnOff_GGIO1.SPCSO1"; } DO(Schd01 0){ DA(setSrcRef 0 19 2 1 0)="@Control/OnOff_FSCH01"; diff --git a/src/scheduler/der_scheduler.h b/src/scheduler/der_scheduler.h index 38c4d75..a62a03d 100644 --- a/src/scheduler/der_scheduler.h +++ b/src/scheduler/der_scheduler.h @@ -22,6 +22,36 @@ extern "C" { typedef struct sScheduler* Scheduler; +/** + * \brief Specify the log level for the library internal logging + */ +typedef enum { + /** + * log level DEBUG - shows the most information (useful for debugging applications) + */ + SCHEDULER_LOG_DEBUG = 1, + + /** + * log level INFO - show informational messages (useful to trace communication problems) + */ + SCHEDULER__LOG_INFO = 2, + + /** + * log level WARNING - show only errors and warning message that indicate wrong configuration + */ + SCHEDULER__LOG_WARNING = 3, + + /** + * log level ERROR - show critical problems and communication errors + */ + SCHEDULER__LOG_ERROR = 4, + + /** + * log level NONE - don't show any log messages + */ + SCHEDULER_LOG_NONE = 5 +} Scheduler_LogLevel; + /** * @brief Create a new Scheduler instance * diff --git a/src/scheduler/schedule.c b/src/scheduler/schedule.c index 38a1ea8..76fb9fb 100644 --- a/src/scheduler/schedule.c +++ b/src/scheduler/schedule.c @@ -247,6 +247,8 @@ handleSetCal(Schedule self, DataObject* dObj, SetCalValues values) if (values) values->mnVal = mnVal; + + return true; } static void @@ -2043,9 +2045,12 @@ Schedule_getValueAt(Schedule self, uint64_t timestamp) //TODO printf("idx: %i relTime: %lu intvInMs: %i\n", idx, relTime, intvInMs); - MmsValue* val = Schedule_getValueWithIdx(self, idx); + if (idx < noOfEntryValues) + { + MmsValue* val = Schedule_getValueWithIdx(self, idx); - event = ScheduleEvent_create(timestamp, MmsValue_clone(val), Schedule_getPrio(self), strTmVal); + event = ScheduleEvent_create(timestamp, MmsValue_clone(val), Schedule_getPrio(self), strTmVal); + } } } } From 4c449fd3f16331fdc61e3342c404fa3aee9c80d7 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sun, 21 Jan 2024 19:00:43 +0000 Subject: [PATCH 6/7] - only call target value handler when value or quality changed --- src/scheduler/schedule_controller.c | 53 ++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/scheduler/schedule_controller.c b/src/scheduler/schedule_controller.c index 751bf7a..9ea4f98 100644 --- a/src/scheduler/schedule_controller.c +++ b/src/scheduler/schedule_controller.c @@ -168,9 +168,11 @@ scheduleController_updateTargetValue(ScheduleController self, ScheduleTargetType } } -static void +static bool scheduleController_updateCurrentValue(ScheduleController self, ScheduleTargetType targetType, MmsValue* val, uint64_t currentTime) { + bool updated = false; + DataAttribute* valueAttr = NULL; DataAttribute* qAttr = NULL; DataAttribute* tAttr = NULL; @@ -193,7 +195,7 @@ scheduleController_updateCurrentValue(ScheduleController self, ScheduleTargetTyp objNameStr = "ValSPS"; } else { - return; + return updated; } valueObj = (DataObject*)ModelNode_getChild((ModelNode*)self->controllerLn, objNameStr); @@ -209,8 +211,8 @@ scheduleController_updateCurrentValue(ScheduleController self, ScheduleTargetTyp valueObj = (DataObject*)ModelNode_getChild((ModelNode*)self->controllerLn, "ValSPS"); } - if (valueObj) { - + if (valueObj) + { char objRefBuf[130]; ModelNode_getObjectReference((ModelNode*)valueObj, objRefBuf); @@ -236,12 +238,20 @@ scheduleController_updateCurrentValue(ScheduleController self, ScheduleTargetTyp IedServer_lockDataModel(self->server); - if (valueAttr && val) { - IedServer_updateAttributeValue(self->server, valueAttr, val); - if (qAttr) IedServer_updateQuality(self->server, qAttr, QUALITY_VALIDITY_GOOD); + if (valueAttr && val) + { + if (MmsValue_equals(valueAttr->mmsValue, val) == false) { + IedServer_updateAttributeValue(self->server, valueAttr, val); + + if (qAttr) IedServer_updateQuality(self->server, qAttr, QUALITY_VALIDITY_GOOD); + + updated = true; + } } else { if (qAttr) IedServer_updateQuality(self->server, qAttr, QUALITY_VALIDITY_INVALID); + + updated = true; } if (tAttr) IedServer_updateUTCTimeAttributeValue(self->server, tAttr, currentTime); @@ -249,7 +259,7 @@ scheduleController_updateCurrentValue(ScheduleController self, ScheduleTargetTyp IedServer_unlockDataModel(self->server); } - return; + return updated; } @@ -295,6 +305,8 @@ scheduleController_scheduleStateUpdated(ScheduleController self, Schedule sched, { Schedule activeSchedule = scheduleController_getActiveSchedule(self); + uint64_t currentTime = Hal_getTimeInMs(); + if (activeSchedule) { if (activeSchedule != self->activeSchedule) { @@ -315,15 +327,21 @@ scheduleController_scheduleStateUpdated(ScheduleController self, Schedule sched, printf("INFO: New value %s\n", valueBuf); scheduleController_updateActSchdRef(self, self->activeSchedule); - scheduleController_updateCurrentValue(self, activeSchedule->targetType, outputValue, Hal_getTimeInMs()); - scheduleController_updateTargetValue(self, activeSchedule->targetType, outputValue, Hal_getTimeInMs()); + + if (scheduleController_updateCurrentValue(self, activeSchedule->targetType, outputValue, currentTime)) { + scheduleController_updateTargetValue(self, activeSchedule->targetType, outputValue, currentTime); + } } } - else { + else + { // there is no running schedule scheduleController_updateActSchdRef(self, NULL); - scheduleController_updateCurrentValue(self, SCHD_TYPE_UNKNOWN, NULL, Hal_getTimeInMs()); - scheduleController_updateTargetValue(self, SCHD_TYPE_UNKNOWN, NULL, Hal_getTimeInMs()); + + if (scheduleController_updateCurrentValue(self, SCHD_TYPE_UNKNOWN, NULL, currentTime)) { + scheduleController_updateTargetValue(self, SCHD_TYPE_UNKNOWN, NULL, currentTime); + } + self->activeSchedule = NULL; } } @@ -338,10 +356,11 @@ void scheduleController_scheduleValueUpdated(ScheduleController self, Schedule sched, MmsValue* val, uint64_t timestamp) { // check if the schedule is the actve schedule - - if (sched == self->activeSchedule) { - scheduleController_updateCurrentValue(self, sched->targetType, val, timestamp); - scheduleController_updateTargetValue(self, sched->targetType, val, timestamp); + if (sched == self->activeSchedule) + { + if (scheduleController_updateCurrentValue(self, sched->targetType, val, timestamp)) { + scheduleController_updateTargetValue(self, sched->targetType, val, timestamp); + } } else { //ignore new value From f479f2463be650f19f62ae62830e80fae9bf8172 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Wed, 24 Jan 2024 00:05:55 +0000 Subject: [PATCH 7/7] - fixed potential crash when forecast is empty Signed-off-by: Michael Zillgith --- src/scheduler/schedule_controller.c | 171 ++++++++++++++-------------- 1 file changed, 87 insertions(+), 84 deletions(-) diff --git a/src/scheduler/schedule_controller.c b/src/scheduler/schedule_controller.c index 9ea4f98..3b5aaeb 100644 --- a/src/scheduler/schedule_controller.c +++ b/src/scheduler/schedule_controller.c @@ -824,136 +824,139 @@ ScheduleController_createForecast(ScheduleController self, uint64_t startTime, u LinkedList resultSchedule = NULL; - uint64_t* tsList = (uint64_t*)calloc(numberOfDifferentTimestamps, sizeof(uint64_t)); - - if (tsList) + if (numberOfDifferentTimestamps > 0) { - int idx = 0; - previousTimestamp = 0; - numberOfDifferentTimestamps = 0; - - timestampsElem = LinkedList_getNext(timestamps); + uint64_t* tsList = (uint64_t*)calloc(numberOfDifferentTimestamps, sizeof(uint64_t)); - while (timestampsElem) + if (tsList) { - uint64_t* ts = (uint64_t*)LinkedList_getData(timestampsElem); + int idx = 0; + previousTimestamp = 0; + numberOfDifferentTimestamps = 0; - bool addToList = true; + timestampsElem = LinkedList_getNext(timestamps); - if (idx > 0) + while (timestampsElem) { - for (int j = 0; j < idx; j++) { - if (tsList[j] == *ts) { - addToList = false; - break; + uint64_t* ts = (uint64_t*)LinkedList_getData(timestampsElem); + + bool addToList = true; + + if (idx > 0) + { + for (int j = 0; j < idx; j++) { + if (tsList[j] == *ts) { + addToList = false; + break; + } } } - } - if (addToList) { - tsList[idx++] = *ts; - numberOfDifferentTimestamps++; - } + if (addToList) { + tsList[idx++] = *ts; + numberOfDifferentTimestamps++; + } - timestampsElem = LinkedList_getNext(timestampsElem); - } + timestampsElem = LinkedList_getNext(timestampsElem); + } - /* sort the list */ - qsort(tsList, idx, sizeof(uint64_t), compareUint64); + /* sort the list */ + qsort(tsList, idx, sizeof(uint64_t), compareUint64); - /* remove outdated values (values in the past that are no longer active)*/ - int curIdx = 0; - while (tsList[curIdx] < startTime) { - curIdx++; - } + /* remove outdated values (values in the past that are no longer active)*/ + int curIdx = 0; + while (tsList[curIdx] < startTime) { + curIdx++; + } - /* create the result schedule */ - resultSchedule = LinkedList_create(); + /* create the result schedule */ + resultSchedule = LinkedList_create(); - ScheduleEvent lastValue = NULL; + ScheduleEvent lastValue = NULL; - for (int i = curIdx; i < numberOfDifferentTimestamps; i++) - { - schedulesElem = LinkedList_getNext(self->schedules); + for (int i = curIdx; i < numberOfDifferentTimestamps; i++) + { + schedulesElem = LinkedList_getNext(self->schedules); - ScheduleEvent currentEvent = NULL; + ScheduleEvent currentEvent = NULL; - //printf("Calculate value for ts %lu\n", tsList[i]); + //printf("Calculate value for ts %lu\n", tsList[i]); - while (schedulesElem) - { - Schedule sched = (Schedule)LinkedList_getData(schedulesElem); + while (schedulesElem) + { + Schedule sched = (Schedule)LinkedList_getData(schedulesElem); - ScheduleEvent event = Schedule_getValueAt(sched, tsList[i]); + ScheduleEvent event = Schedule_getValueAt(sched, tsList[i]); - if (event) - { - if (event->value) + if (event) { - char val[200]; + if (event->value) + { + char val[200]; - MmsValue_printToBuffer(event->value, val, 200); + MmsValue_printToBuffer(event->value, val, 200); - //printf(" %s: %s\n", sched->scheduleLn->name, val); + //printf(" %s: %s\n", sched->scheduleLn->name, val); - if (currentEvent == NULL) { - currentEvent = event; - } - else - { - if (event->priority > currentEvent->priority) { - ScheduleEvent_destroy(currentEvent); + if (currentEvent == NULL) { currentEvent = event; } - else if (event->priority == currentEvent->priority) { - if (event->lastStartTime > currentEvent->lastStartTime) { + else + { + if (event->priority > currentEvent->priority) { ScheduleEvent_destroy(currentEvent); currentEvent = event; } + else if (event->priority == currentEvent->priority) { + if (event->lastStartTime > currentEvent->lastStartTime) { + ScheduleEvent_destroy(currentEvent); + currentEvent = event; + } + else { + ScheduleEvent_destroy(event); + } + } else { ScheduleEvent_destroy(event); } } - else { - ScheduleEvent_destroy(event); - } } - } - else { - // printf(" %s: no value\n", sched->scheduleLn->name); + else { + // printf(" %s: no value\n", sched->scheduleLn->name); - ScheduleEvent_destroy(event); + ScheduleEvent_destroy(event); + } } - } - schedulesElem = LinkedList_getNext(schedulesElem); - } + schedulesElem = LinkedList_getNext(schedulesElem); + } - if (currentEvent) - { - /* check if value is equal to previous value */ - if ((lastValue != NULL) && - (MmsValue_equals(currentEvent->value, lastValue->value))) + if (currentEvent) { - ScheduleEvent_destroy(currentEvent); - } - else { - LinkedList_add(resultSchedule, currentEvent); + /* check if value is equal to previous value */ + if ((lastValue != NULL) && + (MmsValue_equals(currentEvent->value, lastValue->value))) + { + ScheduleEvent_destroy(currentEvent); + } + else { + LinkedList_add(resultSchedule, currentEvent); - char valueBuf[50]; + char valueBuf[50]; - MmsValue_printToBuffer(currentEvent->value, valueBuf, 50); + MmsValue_printToBuffer(currentEvent->value, valueBuf, 50); - lastValue = currentEvent; - } + lastValue = currentEvent; + } - if (lastValue == NULL) { - lastValue = currentEvent; + if (lastValue == NULL) { + lastValue = currentEvent; + } } } - } - free(tsList); + free(tsList); + } } LinkedList_destroy(timestamps);