Tests: Add time emulation feature for tests with BEREMIZ_TEST_CYCLES CFLAG.
Adding BEREMIZ_TEST_CYCLES=1000 in a project's CFLAGS will:
- run 1000 cycles with no pause
- emulate time flowing normaly for PLC code
- exit PLC thread
This allows:
- testing standard library blocks that deal with time without having to wait
- unit testing and code coverage with POUs that uses time
--- a/targets/Linux/plc_Linux_main.c Sun Mar 12 00:55:19 2023 +0100
+++ b/targets/Linux/plc_Linux_main.c Mon Mar 27 10:12:20 2023 +0200
@@ -117,6 +117,11 @@
struct timespec plc_start_time;
#endif
+// BEREMIZ_TEST_CYCLES is defined in tests that need to emulate time:
+// - all BEREMIZ_TEST_CYCLES cycles are executed in a row with no pause
+// - __CURRENT_TIME is incremented each cycle according to emulated cycle period
+
+#ifndef BEREMIZ_TEST_CYCLES
// Sleep until next PLC run
res = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle_time, NULL);
if(res==EINTR){
@@ -126,6 +131,7 @@
_LogError("PLC thread timer returned error %d \n", res);
return;
}
+#endif // BEREMIZ_TEST_CYCLES
#ifdef REALTIME_LINUX
// timer overrun detection
@@ -137,12 +143,30 @@
}
#endif
+#ifdef BEREMIZ_TEST_CYCLES
+#define xstr(s) str(s)
+#define str(arg) #arg
+ // fake current time
+ __CURRENT_TIME.tv_sec = next_cycle_time.tv_sec;
+ __CURRENT_TIME.tv_nsec = next_cycle_time.tv_nsec;
+ // exit loop when enough cycles
+ if(__tick >= BEREMIZ_TEST_CYCLES) {
+ _LogWarning("TEST PLC thread ended after "xstr(BEREMIZ_TEST_CYCLES)" cycles.\n");
+ // After pre-defined test cycles count, PLC thread exits.
+ // Remaining PLC runtime is expected to be cleaned-up/killed by test script
+ return;
+ }
+#else
PLC_GetTime(&__CURRENT_TIME);
+#endif
__run();
+#ifndef BEREMIZ_TEST_CYCLES
// ensure next PLC cycle occurence is in the future
clock_gettime(CLOCK_MONOTONIC, &plc_end_time);
- while(timespec_gt(plc_end_time, next_cycle_time)){
+ while(timespec_gt(plc_end_time, next_cycle_time))
+#endif
+ {
periods += 1;
inc_timespec(&next_cycle_time, period_ns);
}