jthoene 8 лет назад
Родитель
Сommit
e137ecd4e2
100 измененных файлов с 11095 добавлено и 502 удалено
  1. 23 16
      test-plugins/org.yakindu.sct.generator.c.test/gtests/AlwaysOncycle/AlwaysOncycleTest.cc
  2. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/AlwaysOncycle/sc_timer_service.c
  3. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/AlwaysOncycle/sc_timer_service.h
  4. 27 20
      test-plugins/org.yakindu.sct.generator.c.test/gtests/AssignmentAsExpression/AssignmentAsExpressionTest.cc
  5. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/AssignmentAsExpression/sc_timer_service.c
  6. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/AssignmentAsExpression/sc_timer_service.h
  7. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/BitExpressions/BitExpressionsTest.cc
  8. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/BitExpressions/sc_timer_service.c
  9. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/BitExpressions/sc_timer_service.h
  10. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/BooleanExpressions/BooleanExpressionsTest.cc
  11. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/BooleanExpressions/sc_timer_service.c
  12. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/BooleanExpressions/sc_timer_service.h
  13. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/CKeywords/CKeywordsTest.cc
  14. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/CKeywords/sc_timer_service.c
  15. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/CKeywords/sc_timer_service.h
  16. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/CastExpressions/CastExpressionsTest.cc
  17. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/CastExpressions/sc_timer_service.c
  18. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/CastExpressions/sc_timer_service.h
  19. 29 22
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Choice/ChoiceTest.cc
  20. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Choice/sc_timer_service.c
  21. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Choice/sc_timer_service.h
  22. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConditionalExpression/ConditionalExpression.cc
  23. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConditionalExpression/sc_timer_service.c
  24. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConditionalExpression/sc_timer_service.h
  25. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyDefaultScope/ConstOnlyDefaultScopeTest.cc
  26. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyDefaultScope/sc_timer_service.c
  27. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyDefaultScope/sc_timer_service.h
  28. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyInternalScope/ConstOnlyInternalScopeTest.cc
  29. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyInternalScope/sc_timer_service.c
  30. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyInternalScope/sc_timer_service.h
  31. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyNamedScope/ConstOnlyNamedScopeTest.cc
  32. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyNamedScope/sc_timer_service.c
  33. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyNamedScope/sc_timer_service.h
  34. 22 15
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstantsTests/ConstantsTests.cc
  35. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstantsTests/sc_timer_service.c
  36. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstantsTests/sc_timer_service.h
  37. 19 12
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Declarations/DeclarationsTest.cc
  38. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Declarations/sc_timer_service.c
  39. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Declarations/sc_timer_service.h
  40. 19 12
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepEntry/DeepEntryTest.cc
  41. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepEntry/sc_timer_service.c
  42. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepEntry/sc_timer_service.h
  43. 25 18
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepHistory/DeepHistoryTest.cc
  44. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepHistory/sc_timer_service.c
  45. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepHistory/sc_timer_service.h
  46. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DynamicChoice/DynamicChoiceTest.cc
  47. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DynamicChoice/sc_timer_service.c
  48. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/DynamicChoice/sc_timer_service.h
  49. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EmptyTransition/EmptyTransitionTest.cc
  50. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EmptyTransition/sc_timer_service.c
  51. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EmptyTransition/sc_timer_service.h
  52. 24 17
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EnterState/EnterStateTest.cc
  53. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EnterState/sc_timer_service.c
  54. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EnterState/sc_timer_service.h
  55. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryChoice/EntryChoiceTest.cc
  56. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryChoice/sc_timer_service.c
  57. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryChoice/sc_timer_service.h
  58. 24 17
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryExitSelfTransition/EntryExitSelfTransitionTest.cc
  59. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryExitSelfTransition/sc_timer_service.c
  60. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryExitSelfTransition/sc_timer_service.h
  61. 25 18
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryReactionAction/EntryReactionActionTest.cc
  62. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryReactionAction/sc_timer_service.c
  63. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryReactionAction/sc_timer_service.h
  64. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitOnSelfTransition/ExitOnSelfTransitionTest.cc
  65. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitOnSelfTransition/sc_timer_service.c
  66. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitOnSelfTransition/sc_timer_service.h
  67. 26 19
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitState/ExitStateTest.cc
  68. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitState/sc_timer_service.c
  69. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitState/sc_timer_service.h
  70. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/FeatureCalls/FeatureCallsTest.cc
  71. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/FeatureCalls/sc_timer_service.c
  72. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/FeatureCalls/sc_timer_service.h
  73. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/FinalState/FinalStateTest.cc
  74. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/FinalState/sc_timer_service.c
  75. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/FinalState/sc_timer_service.h
  76. 24 17
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Guard/GuardTest.cc
  77. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Guard/sc_timer_service.c
  78. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/Guard/sc_timer_service.h
  79. 24 17
      test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedEntry/GuardedEntryTest.cc
  80. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedEntry/sc_timer_service.c
  81. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedEntry/sc_timer_service.h
  82. 21 14
      test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedExit/GuardedExitTest.cc
  83. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedExit/sc_timer_service.c
  84. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedExit/sc_timer_service.h
  85. 24 17
      test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithExitPoint/HistoryWithExitPointTest.cc
  86. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithExitPoint/sc_timer_service.c
  87. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithExitPoint/sc_timer_service.h
  88. 28 21
      test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithoutInitialStep/HistoryWithoutInitialStepTest.cc
  89. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithoutInitialStep/sc_timer_service.c
  90. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithoutInitialStep/sc_timer_service.h
  91. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/InEventLifeCycle/InEventLifeCycleTest.cc
  92. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/InEventLifeCycle/sc_timer_service.c
  93. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/InEventLifeCycle/sc_timer_service.h
  94. 20 13
      test-plugins/org.yakindu.sct.generator.c.test/gtests/IntegerExpressions/IntegerExpressionsTest.cc
  95. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/IntegerExpressions/sc_timer_service.c
  96. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/IntegerExpressions/sc_timer_service.h
  97. 23 16
      test-plugins/org.yakindu.sct.generator.c.test/gtests/InternalEventLifeCycle/InternalEventLifeCycleTest.cc
  98. 233 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/InternalEventLifeCycle/sc_timer_service.c
  99. 81 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/InternalEventLifeCycle/sc_timer_service.h
  100. 0 0
      test-plugins/org.yakindu.sct.generator.c.test/gtests/LocalReactions/LocalReactionsTest.cc

+ 23 - 16
test-plugins/org.yakindu.sct.generator.c.test/gtests/AlwaysOncycle/AlwaysOncycleTest.cc

@@ -1,40 +1,47 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "AlwaysOncycle.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static AlwaysOncycle statechart;
 
-class StatemachineTest : public ::testing::Test{
+class AlwaysOncycleTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		alwaysOncycle_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &alwaysOncycle_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, alwaysOnCycleTest) {					
+TEST_F(AlwaysOncycleTest, alwaysOnCycleTest) {
 	alwaysOncycle_enter(&statechart);
 	EXPECT_TRUE(alwaysOncycle_isStateActive(&statechart, AlwaysOncycle_main_region_StateA));
 	while (alwaysOncycleIface_get_value(&statechart)< 5l) {
-		alwaysOncycle_runCycle(&statechart);
+		sc_timer_service_proceed_cycles(&timer_service, 1);
 		EXPECT_TRUE(alwaysOncycle_isStateActive(&statechart, AlwaysOncycle_main_region_StateA));
 	}
-	alwaysOncycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(alwaysOncycle_isStateActive(&statechart, AlwaysOncycle_main_region_StateB));
 	while (alwaysOncycleIface_get_value(&statechart)< 5l) {
-		alwaysOncycle_runCycle(&statechart);
+		sc_timer_service_proceed_cycles(&timer_service, 1);
 		EXPECT_TRUE(alwaysOncycle_isStateActive(&statechart, AlwaysOncycle_main_region_StateB));
 	}
-	alwaysOncycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(alwaysOncycle_isStateActive(&statechart, AlwaysOncycle_main_region_StateA));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/AlwaysOncycle/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/AlwaysOncycle/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 27 - 20
test-plugins/org.yakindu.sct.generator.c.test/gtests/AssignmentAsExpression/AssignmentAsExpressionTest.cc

@@ -1,54 +1,61 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "AssignmentAsExpression.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static AssignmentAsExpression statechart;
 
-class StatemachineTest : public ::testing::Test{
+class AssignmentAsExpressionTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		assignmentAsExpression_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &assignmentAsExpression_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, simpleAssignment) {					
+TEST_F(AssignmentAsExpressionTest, simpleAssignment) {
 	assignmentAsExpression_enter(&statechart);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_Add));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_b(&statechart)== 5l);
 	EXPECT_TRUE(assignmentAsExpressionIface_get_a(&statechart)== 9l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_Subtract));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_d(&statechart)== 6l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_Multiply));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_e(&statechart)== 15l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_Divide));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_g(&statechart)== 1l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_Modulo));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_i(&statechart)== 1l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_Shift));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_j(&statechart)== 16l);
 	EXPECT_TRUE(assignmentAsExpressionIface_get_k(&statechart)== 4l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_boolean_And));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_l(&statechart)== 1l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_boolean_Or));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_p(&statechart)== 15l);
-	assignmentAsExpression_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(assignmentAsExpression_isStateActive(&statechart, AssignmentAsExpression_main_region_boolean_Xor));
 	EXPECT_TRUE(assignmentAsExpressionIface_get_u(&statechart)== 12l);
 	assignmentAsExpression_exit(&statechart);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/AssignmentAsExpression/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/AssignmentAsExpression/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/BitExpressions/BitExpressionsTest.cc

@@ -1,33 +1,40 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "BitExpressions.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static BitExpressions statechart;
 
-class StatemachineTest : public ::testing::Test{
+class BitExpressionsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		bitExpressions_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &bitExpressions_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, BitExpressions) {					
+TEST_F(BitExpressionsTest, BitExpressions) {
 	bitExpressions_enter(&statechart);
 	EXPECT_TRUE(bitExpressions_isStateActive(&statechart, BitExpressions_main_region_StateA));
 	EXPECT_TRUE(bitExpressionsIface_get_myBit1(&statechart)== 5l);
 	EXPECT_TRUE(bitExpressionsIface_get_myBit2(&statechart)== 7l);
 	bitExpressionsIface_raise_e1(&statechart);
-	bitExpressions_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(bitExpressions_isStateActive(&statechart, BitExpressions_main_region_StateB));
 	EXPECT_TRUE(bitExpressionsIface_get_leftBitshift(&statechart)== 10l);
 	EXPECT_TRUE(bitExpressionsIface_get_rightBitshift(&statechart)== 2l);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/BitExpressions/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/BitExpressions/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/BooleanExpressions/BooleanExpressionsTest.cc

@@ -1,33 +1,40 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "BooleanExpressions.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static BooleanExpressions statechart;
 
-class StatemachineTest : public ::testing::Test{
+class BooleanExpressionsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		booleanExpressions_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &booleanExpressions_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, booleanExpressions) {					
+TEST_F(BooleanExpressionsTest, booleanExpressions) {
 	booleanExpressions_enter(&statechart);
 	EXPECT_TRUE(booleanExpressions_isStateActive(&statechart, BooleanExpressions_main_region_StateA));
 	EXPECT_TRUE(booleanExpressionsIface_get_myBool1(&statechart)== true);
 	EXPECT_TRUE(booleanExpressionsIface_get_myBool2(&statechart)== false);
 	booleanExpressionsIface_raise_e1(&statechart);
-	booleanExpressions_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(booleanExpressions_isStateActive(&statechart, BooleanExpressions_main_region_StateB));
 	EXPECT_TRUE(booleanExpressionsIface_get_and(&statechart)== false);
 	EXPECT_TRUE(booleanExpressionsIface_get_or(&statechart)== true);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/BooleanExpressions/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/BooleanExpressions/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/CKeywords/CKeywordsTest.cc

@@ -1,31 +1,38 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "CKeywords.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static CKeywords statechart;
 
-class StatemachineTest : public ::testing::Test{
+class CKeywordsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		cKeywords_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &cKeywords_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, CKeywordsTest) {					
+TEST_F(CKeywordsTest, CKeywordsTest) {
 	cKeywords_enter(&statechart);
 	EXPECT_TRUE(cKeywords_isStateActive(&statechart, CKeywords_auto_char));
 	cKeywordsIface_raise_auto(&statechart);
-	cKeywords_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(cKeywords_isStateActive(&statechart, CKeywords_auto_loop));
 	EXPECT_TRUE(cKeywords_isStateActive(&statechart, CKeywords_auto_loop_switch_case));
 	EXPECT_TRUE(cKeywords_isStateActive(&statechart, CKeywords_auto_loop_switch_case_enum_asm));

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/CKeywords/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/CKeywords/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/CastExpressions/CastExpressionsTest.cc

@@ -1,33 +1,40 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "CastExpressions.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static CastExpressions statechart;
 
-class StatemachineTest : public ::testing::Test{
+class CastExpressionsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		castExpressions_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &castExpressions_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, CastExpressionTest) {					
+TEST_F(CastExpressionsTest, CastExpressionTest) {
 	castExpressions_enter(&statechart);
 	EXPECT_TRUE(castExpressionsIface_get_realValue(&statechart)== 5l);
 	EXPECT_TRUE(castExpressionsIface_get_intValue(&statechart)== 5l);
-	castExpressions_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(castExpressionsIface_get_realValue(&statechart)== 15l);
-	castExpressions_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(castExpressions_isStateActive(&statechart, CastExpressions_main_region_C));
 	EXPECT_TRUE(castExpressionsIface_get_realValue(&statechart)== 757l);
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/CastExpressions/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/CastExpressions/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 29 - 22
test-plugins/org.yakindu.sct.generator.c.test/gtests/Choice/ChoiceTest.cc

@@ -1,22 +1,29 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "Choice.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static Choice statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ChoiceTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		choice_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &choice_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
@@ -25,55 +32,55 @@ void initForEventE(bool valueForC){
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_A));
 	choiceIface_set_c(&statechart,valueForC);
 	choiceIface_raise_e(&statechart);
-	choice_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 }
 void initForEventF(bool valueForC){
 	choice_enter(&statechart);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_A));
 	choiceIface_set_c(&statechart,valueForC);
 	choiceIface_raise_f(&statechart);
-	choice_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 }
 void initForEventG(bool valueForC){
 	choice_enter(&statechart);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_A));
 	choiceIface_set_c(&statechart,valueForC);
 	choiceIface_raise_g(&statechart);
-	choice_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 }
 void initForEventH(bool valueForC){
 	choice_enter(&statechart);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_A));
 	choiceIface_set_c(&statechart,valueForC);
 	choiceIface_raise_h(&statechart);
-	choice_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 }
 
-TEST_F(StatemachineTest, elseChoiceUsingNonDefaultTransition) {					
+TEST_F(ChoiceTest, elseChoiceUsingNonDefaultTransition) {
 	initForEventE(true);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_C));
 }
-TEST_F(StatemachineTest, elseChoiceUsingDefaultTransition) {					
+TEST_F(ChoiceTest, elseChoiceUsingDefaultTransition) {
 	initForEventE(false);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_B));
 }
-TEST_F(StatemachineTest, defaultChoiceUsingNonDefaultTransition) {					
+TEST_F(ChoiceTest, defaultChoiceUsingNonDefaultTransition) {
 	initForEventG(true);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_C));
 }
-TEST_F(StatemachineTest, defaultChoiceUsingDefaultTransition) {					
+TEST_F(ChoiceTest, defaultChoiceUsingDefaultTransition) {
 	initForEventG(false);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_B));
 }
-TEST_F(StatemachineTest, uncheckedChoiceUsingNonDefaultTransition) {					
+TEST_F(ChoiceTest, uncheckedChoiceUsingNonDefaultTransition) {
 	initForEventF(true);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_C));
 }
-TEST_F(StatemachineTest, uncheckedChoiceUsingDefaultTransition) {					
+TEST_F(ChoiceTest, uncheckedChoiceUsingDefaultTransition) {
 	initForEventF(false);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_B));
 }
-TEST_F(StatemachineTest, alwaysTrueTransitionInChoice) {					
+TEST_F(ChoiceTest, alwaysTrueTransitionInChoice) {
 	initForEventH(true);
 	EXPECT_TRUE(choice_isStateActive(&statechart, Choice_main_region_C));
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/Choice/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/Choice/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConditionalExpression/ConditionalExpression.cc

@@ -1,32 +1,39 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "ConditionalExpressions.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static ConditionalExpressions statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ConditionalExpression : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		conditionalExpressions_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &conditionalExpressions_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, ConditionalExpressionTest) {					
+TEST_F(ConditionalExpression, ConditionalExpressionTest) {
 	conditionalExpressions_enter(&statechart);
 	EXPECT_TRUE(conditionalExpressions_isStateActive(&statechart, ConditionalExpressions_main_region_A));
 	EXPECT_TRUE(conditionalExpressionsIface_get_condition(&statechart)== 1l);
 	conditionalExpressionsIface_raise_e(&statechart);
-	conditionalExpressions_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(conditionalExpressions_isStateActive(&statechart, ConditionalExpressions_main_region_B));
 	EXPECT_TRUE(conditionalExpressionsIface_get_condition(&statechart)== 2l);
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConditionalExpression/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConditionalExpression/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyDefaultScope/ConstOnlyDefaultScopeTest.cc

@@ -1,34 +1,41 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "ConstOnlyDefaultScope.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static ConstOnlyDefaultScope statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ConstOnlyDefaultScopeTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		constOnlyDefaultScope_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &constOnlyDefaultScope_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, statechartEntry) {					
+TEST_F(ConstOnlyDefaultScopeTest, statechartEntry) {
 	constOnlyDefaultScope_enter(&statechart);
 	EXPECT_TRUE(constOnlyDefaultScope_isStateActive(&statechart, ConstOnlyDefaultScope_ConstOnlyDefaultScope_main_region_A));
 }
-TEST_F(StatemachineTest, stateTransition) {					
+TEST_F(ConstOnlyDefaultScopeTest, stateTransition) {
 	constOnlyDefaultScope_enter(&statechart);
 	constOnlyDefaultScopeIfaceA_raise_e(&statechart, 1l);
-	constOnlyDefaultScope_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(constOnlyDefaultScope_isStateActive(&statechart, ConstOnlyDefaultScope_ConstOnlyDefaultScope_main_region_B));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyDefaultScope/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyDefaultScope/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyInternalScope/ConstOnlyInternalScopeTest.cc

@@ -1,34 +1,41 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "ConstOnlyInternalScope.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static ConstOnlyInternalScope statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ConstOnlyInternalScopeTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		constOnlyInternalScope_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &constOnlyInternalScope_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, statechartEntry) {					
+TEST_F(ConstOnlyInternalScopeTest, statechartEntry) {
 	constOnlyInternalScope_enter(&statechart);
 	EXPECT_TRUE(constOnlyInternalScope_isStateActive(&statechart, ConstOnlyInternalScope_ConstOnlyInternalScope_main_region_A));
 }
-TEST_F(StatemachineTest, stateTransition) {					
+TEST_F(ConstOnlyInternalScopeTest, stateTransition) {
 	constOnlyInternalScope_enter(&statechart);
 	constOnlyInternalScopeIface_raise_e(&statechart, 1l);
-	constOnlyInternalScope_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(constOnlyInternalScope_isStateActive(&statechart, ConstOnlyInternalScope_ConstOnlyInternalScope_main_region_B));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyInternalScope/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyInternalScope/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyNamedScope/ConstOnlyNamedScopeTest.cc

@@ -1,34 +1,41 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "ConstOnlyNamedScope.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static ConstOnlyNamedScope statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ConstOnlyNamedScopeTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		constOnlyNamedScope_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &constOnlyNamedScope_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, statechartEntry) {					
+TEST_F(ConstOnlyNamedScopeTest, statechartEntry) {
 	constOnlyNamedScope_enter(&statechart);
 	EXPECT_TRUE(constOnlyNamedScope_isStateActive(&statechart, ConstOnlyNamedScope_ConstOnlyNamedScope_main_region_A));
 }
-TEST_F(StatemachineTest, stateTransition) {					
+TEST_F(ConstOnlyNamedScopeTest, stateTransition) {
 	constOnlyNamedScope_enter(&statechart);
 	constOnlyNamedScopeIface_raise_e(&statechart, 1l);
-	constOnlyNamedScope_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(constOnlyNamedScope_isStateActive(&statechart, ConstOnlyNamedScope_ConstOnlyNamedScope_main_region_B));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyNamedScope/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstOnlyNamedScope/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 22 - 15
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstantsTests/ConstantsTests.cc

@@ -1,41 +1,48 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "Constants.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static Constants statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ConstantsTests : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		constants_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &constants_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, constantDefinition) {					
+TEST_F(ConstantsTests, constantDefinition) {
 	constants_enter(&statechart);
 	EXPECT_TRUE(constants_isStateActive(&statechart, Constants_main_region_A));
 	EXPECT_TRUE(constantsIface_get_x(&statechart)== 10l);
 	EXPECT_TRUE(constantsIface_get_y(&statechart)== 20l);
 	EXPECT_TRUE(strcmp(constantsIfaceNamed_get_y(&statechart) , "Hello World") == 0);
 	constantsIface_raise_e(&statechart);
-	constants_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(constantsIface_get_result(&statechart)== 20l);
 	constantsIface_raise_e(&statechart);
-	constants_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(constants_isStateActive(&statechart, Constants_main_region_C));
 	EXPECT_TRUE(constantsIface_get_result(&statechart)== 100l);
 	constantsIface_raise_e2(&statechart, constantsIface_get_x(&statechart));
-	constants_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(constantsIface_get_result(&statechart)== 1000l);
 	EXPECT_TRUE(constants_isStateActive(&statechart, Constants_main_region_A));
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstantsTests/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ConstantsTests/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 19 - 12
test-plugins/org.yakindu.sct.generator.c.test/gtests/Declarations/DeclarationsTest.cc

@@ -1,27 +1,34 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "Declarations.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static Declarations statechart;
 
-class StatemachineTest : public ::testing::Test{
+class DeclarationsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		declarations_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &declarations_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, declarationsTest) {					
+TEST_F(DeclarationsTest, declarationsTest) {
 	declarations_enter(&statechart);
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/Declarations/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/Declarations/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 19 - 12
test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepEntry/DeepEntryTest.cc

@@ -1,27 +1,34 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "DeepEntry.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static DeepEntry statechart;
 
-class StatemachineTest : public ::testing::Test{
+class DeepEntryTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		deepEntry_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &deepEntry_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, enterToSubstate) {					
+TEST_F(DeepEntryTest, enterToSubstate) {
 	deepEntry_enter(&statechart);
 	long vergleich = 4l;
 	EXPECT_TRUE(vergleich== 4l);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepEntry/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepEntry/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 25 - 18
test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepHistory/DeepHistoryTest.cc

@@ -1,44 +1,51 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "DeepHistory.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static DeepHistory statechart;
 
-class StatemachineTest : public ::testing::Test{
+class DeepHistoryTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		deepHistory_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &deepHistory_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, deepHistoryTest) {					
+TEST_F(DeepHistoryTest, deepHistoryTest) {
 	deepHistory_enter(&statechart);
 	deepHistoryIface_raise_event1(&statechart);
-	deepHistory_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	deepHistoryIface_raise_event3(&statechart);
-	deepHistory_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	deepHistoryIface_raise_event5(&statechart);
-	deepHistory_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	deepHistoryIface_raise_event7(&statechart);
-	deepHistory_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(!deepHistory_isStateActive(&statechart, DeepHistory_mainRegion_State1));
 	EXPECT_TRUE(deepHistory_isStateActive(&statechart, DeepHistory_mainRegion_State2__region0_State4__region0_State7__region0_State9));
 	deepHistoryIface_raise_event2(&statechart);
-	deepHistory_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(deepHistory_isStateActive(&statechart, DeepHistory_mainRegion_State1));
 	EXPECT_TRUE(!deepHistory_isStateActive(&statechart, DeepHistory_mainRegion_State2__region0_State4__region0_State7__region0_State9));
 	deepHistoryIface_raise_event1(&statechart);
-	deepHistory_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(!deepHistory_isStateActive(&statechart, DeepHistory_mainRegion_State1));
 	EXPECT_TRUE(deepHistory_isStateActive(&statechart, DeepHistory_mainRegion_State2__region0_State4__region0_State7__region0_State9));
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepHistory/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/DeepHistory/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/DynamicChoice/DynamicChoiceTest.cc

@@ -1,30 +1,37 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "DynamicChoice.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static DynamicChoice statechart;
 
-class StatemachineTest : public ::testing::Test{
+class DynamicChoiceTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		dynamicChoice_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &dynamicChoice_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, DynamicChoiceTest) {					
+TEST_F(DynamicChoiceTest, DynamicChoiceTest) {
 	dynamicChoice_enter(&statechart);
 	EXPECT_TRUE(dynamicChoice_isStateActive(&statechart, DynamicChoice_main_region_Start));
-	dynamicChoice_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(dynamicChoice_isStateActive(&statechart, DynamicChoice_main_region_A));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/DynamicChoice/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/DynamicChoice/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/EmptyTransition/EmptyTransitionTest.cc

@@ -1,29 +1,36 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "EmptyTransition.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static EmptyTransition statechart;
 
-class StatemachineTest : public ::testing::Test{
+class EmptyTransitionTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		emptyTransition_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &emptyTransition_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, EmptyTransitionTest) {					
+TEST_F(EmptyTransitionTest, EmptyTransitionTest) {
 	emptyTransition_enter(&statechart);
-	emptyTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(!emptyTransition_isStateActive(&statechart, EmptyTransition_main_region_B));
 	EXPECT_TRUE(emptyTransition_isStateActive(&statechart, EmptyTransition_main_region_A));
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EmptyTransition/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EmptyTransition/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 24 - 17
test-plugins/org.yakindu.sct.generator.c.test/gtests/EnterState/EnterStateTest.cc

@@ -1,45 +1,52 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "EnterState.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static EnterState statechart;
 
-class StatemachineTest : public ::testing::Test{
+class EnterStateTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		enterState_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &enterState_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, defaultEntry) {					
+TEST_F(EnterStateTest, defaultEntry) {
 	enterState_enter(&statechart);
 	EXPECT_TRUE(enterState_isStateActive(&statechart, EnterState_r_A));
 	enterStateIface_raise_e(&statechart);
-	enterState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(enterState_isStateActive(&statechart, EnterState_r_B_r_E));
 }
-TEST_F(StatemachineTest, namedEntryThroughNamedTransition) {					
+TEST_F(EnterStateTest, namedEntryThroughNamedTransition) {
 	enterState_enter(&statechart);
 	EXPECT_TRUE(enterState_isStateActive(&statechart, EnterState_r_A));
 	enterStateIface_raise_f(&statechart);
-	enterState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(enterState_isStateActive(&statechart, EnterState_r_B_r_F));
 }
-TEST_F(StatemachineTest, namedEntryThroughDefaultTransition) {					
+TEST_F(EnterStateTest, namedEntryThroughDefaultTransition) {
 	enterState_enter(&statechart);
 	EXPECT_TRUE(enterState_isStateActive(&statechart, EnterState_r_A));
 	enterStateIface_raise_g(&statechart);
-	enterState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(enterState_isStateActive(&statechart, EnterState_r_B_r_E));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EnterState/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EnterState/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryChoice/EntryChoiceTest.cc

@@ -1,30 +1,37 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "EntryChoice.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static EntryChoice statechart;
 
-class StatemachineTest : public ::testing::Test{
+class EntryChoiceTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		entryChoice_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &entryChoice_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, EntryChoiceTest) {					
+TEST_F(EntryChoiceTest, EntryChoiceTest) {
 	entryChoice_enter(&statechart);
-	entryChoice_runCycle(&statechart);
-	entryChoice_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(entryChoice_isStateActive(&statechart, EntryChoice_main_region_A));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryChoice/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryChoice/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 24 - 17
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryExitSelfTransition/EntryExitSelfTransitionTest.cc

@@ -1,51 +1,58 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "EntryExitSelfTransition.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static EntryExitSelfTransition statechart;
 
-class StatemachineTest : public ::testing::Test{
+class EntryExitSelfTransitionTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		entryExitSelfTransition_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &entryExitSelfTransition_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 void init(){
 	entryExitSelfTransition_enter(&statechart);
-	entryExitSelfTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_entries(&statechart)== 1l);
 	EXPECT_TRUE(entryExitSelfTransition_isStateActive(&statechart, EntryExitSelfTransition_main_region_A__region0_B));
 	entryExitSelfTransitionIface_set_entries(&statechart,0l);
 }
 
-TEST_F(StatemachineTest, SelfTransitionToChildState) {					
+TEST_F(EntryExitSelfTransitionTest, SelfTransitionToChildState) {
 	init();
 	entryExitSelfTransitionIface_raise_e(&statechart);
-	entryExitSelfTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_entries(&statechart)== 1l);
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_exits(&statechart)== 1l);
 	EXPECT_TRUE(entryExitSelfTransition_isStateActive(&statechart, EntryExitSelfTransition_main_region_A__region0_C));
 	entryExitSelfTransition_exit(&statechart);
 }
-TEST_F(StatemachineTest, SelfTransitionFromChildState) {					
+TEST_F(EntryExitSelfTransitionTest, SelfTransitionFromChildState) {
 	init();
 	entryExitSelfTransitionIface_raise_e1(&statechart);
-	entryExitSelfTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_entries(&statechart)== 0l);
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_exits(&statechart)== 0l);
 	EXPECT_TRUE(entryExitSelfTransition_isStateActive(&statechart, EntryExitSelfTransition_main_region_A__region0_C));
 	entryExitSelfTransitionIface_raise_e1(&statechart);
-	entryExitSelfTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(entryExitSelfTransition_isStateActive(&statechart, EntryExitSelfTransition_main_region_A__region0_B));
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_entries(&statechart)== 1l);
 	EXPECT_TRUE(entryExitSelfTransitionIface_get_exits(&statechart)== 1l);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryExitSelfTransition/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryExitSelfTransition/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 25 - 18
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryReactionAction/EntryReactionActionTest.cc

@@ -1,57 +1,64 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "EntryReactionAction.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static EntryReactionAction statechart;
 
-class StatemachineTest : public ::testing::Test{
+class EntryReactionActionTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		entryReactionAction_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &entryReactionAction_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 void init(){
 	entryReactionAction_enter(&statechart);
 	entryReactionActionIface_raise_b(&statechart);
-	entryReactionAction_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	entryReactionActionIface_raise_d(&statechart);
-	entryReactionAction_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	entryReactionActionIface_set_enteredR1(&statechart,false);
 	entryReactionActionIface_set_enteredR2(&statechart,false);
 	entryReactionActionIface_set_enteredBdefault(&statechart,false);
 	entryReactionActionIface_set_enteredBother(&statechart,false);
 }
 
-TEST_F(StatemachineTest, entryTransitionActionOnStatechartEnter) {					
+TEST_F(EntryReactionActionTest, entryTransitionActionOnStatechartEnter) {
 	entryReactionAction_enter(&statechart);
 	EXPECT_TRUE(entryReactionActionIface_get_enteredR1(&statechart));
 	EXPECT_TRUE(entryReactionActionIface_get_enteredR2(&statechart));
 	EXPECT_TRUE(entryReactionActionIface_get_enteredBdefault(&statechart));
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredBother(&statechart));
 }
-TEST_F(StatemachineTest, entryOnRTS) {					
+TEST_F(EntryReactionActionTest, entryOnRTS) {
 	init();
 	entryReactionActionIface_raise_b(&statechart);
-	entryReactionAction_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredR1(&statechart));
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredR2(&statechart));
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredBdefault(&statechart));
 	EXPECT_TRUE(entryReactionActionIface_get_enteredBother(&statechart));
 }
-TEST_F(StatemachineTest, noEntryTransitionActionOnHistory) {					
+TEST_F(EntryReactionActionTest, noEntryTransitionActionOnHistory) {
 	init();
 	entryReactionActionIface_raise_d(&statechart);
-	entryReactionAction_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredR1(&statechart));
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredR2(&statechart));
 	EXPECT_TRUE(!entryReactionActionIface_get_enteredBdefault(&statechart));

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryReactionAction/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/EntryReactionAction/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitOnSelfTransition/ExitOnSelfTransitionTest.cc

@@ -1,37 +1,44 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "ExitOnSelfTransition.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static ExitOnSelfTransition statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ExitOnSelfTransitionTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		exitOnSelfTransition_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &exitOnSelfTransition_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, ExitOnSelfTransitionTest) {					
+TEST_F(ExitOnSelfTransitionTest, ExitOnSelfTransitionTest) {
 	exitOnSelfTransition_enter(&statechart);
 	EXPECT_TRUE(exitOnSelfTransition_isStateActive(&statechart, ExitOnSelfTransition_main_region_A));
 	EXPECT_TRUE(exitOnSelfTransitionIface_get_entryCount(&statechart)== 1l);
 	EXPECT_TRUE(exitOnSelfTransitionIface_get_exitCount(&statechart)== 0l);
 	exitOnSelfTransitionIface_raise_e(&statechart);
-	exitOnSelfTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(exitOnSelfTransitionIface_get_entryCount(&statechart)== 2l);
 	EXPECT_TRUE(exitOnSelfTransitionIface_get_exitCount(&statechart)== 1l);
 	exitOnSelfTransitionIface_raise_f(&statechart);
-	exitOnSelfTransition_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(exitOnSelfTransitionIface_get_entryCount(&statechart)== 2l);
 	EXPECT_TRUE(exitOnSelfTransitionIface_get_exitCount(&statechart)== 2l);
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitOnSelfTransition/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitOnSelfTransition/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 26 - 19
test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitState/ExitStateTest.cc

@@ -1,51 +1,58 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "ExitState.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static ExitState statechart;
 
-class StatemachineTest : public ::testing::Test{
+class ExitStateTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		exitState_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &exitState_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, defaultExit) {					
+TEST_F(ExitStateTest, defaultExit) {
 	exitState_enter(&statechart);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_A));
 	exitStateIface_raise_e(&statechart);
-	exitState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_E));
 }
-TEST_F(StatemachineTest, namedExitThroughNamedTransition) {					
+TEST_F(ExitStateTest, namedExitThroughNamedTransition) {
 	exitState_enter(&statechart);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_A));
 	exitStateIface_raise_f(&statechart);
-	exitState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_F));
 }
-TEST_F(StatemachineTest, namedExitThroughDefaultTransition) {					
+TEST_F(ExitStateTest, namedExitThroughDefaultTransition) {
 	exitState_enter(&statechart);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_A));
 	exitStateIface_raise_g(&statechart);
-	exitState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_E));
 }
-TEST_F(StatemachineTest, remainInA) {					
+TEST_F(ExitStateTest, remainInA) {
 	exitState_enter(&statechart);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_A));
-	exitState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(exitState_isStateActive(&statechart, ExitState_r_A));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitState/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/ExitState/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/FeatureCalls/FeatureCallsTest.cc

@@ -1,30 +1,37 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "FeatureCalls.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static FeatureCalls statechart;
 
-class StatemachineTest : public ::testing::Test{
+class FeatureCallsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		featureCalls_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &featureCalls_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, FeatureCalls) {					
+TEST_F(FeatureCallsTest, FeatureCalls) {
 	featureCalls_enter(&statechart);
 	EXPECT_TRUE(featureCalls_isStateActive(&statechart, FeatureCalls_main_region_A));
-	featureCalls_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(featureCalls_isStateActive(&statechart, FeatureCalls_main_region_A));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/FeatureCalls/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/FeatureCalls/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/FinalState/FinalStateTest.cc

@@ -1,29 +1,36 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "FinalState.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static FinalState statechart;
 
-class StatemachineTest : public ::testing::Test{
+class FinalStateTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		finalState_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &finalState_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, StatechartNameTest) {					
+TEST_F(FinalStateTest, StatechartNameTest) {
 	finalState_enter(&statechart);
-	finalState_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(finalState_isFinal(&statechart));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/FinalState/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/FinalState/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 24 - 17
test-plugins/org.yakindu.sct.generator.c.test/gtests/Guard/GuardTest.cc

@@ -1,43 +1,50 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "Guard.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static Guard statechart;
 
-class StatemachineTest : public ::testing::Test{
+class GuardTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		guard_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &guard_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, guardTest) {					
+TEST_F(GuardTest, guardTest) {
 	guard_enter(&statechart);
 	EXPECT_TRUE(guard_isStateActive(&statechart, Guard_main_region_A));
 	guardIface_raise_event1(&statechart);
-	guard_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guard_isStateActive(&statechart, Guard_main_region_A));
 	guardIface_raise_event2(&statechart);
-	guard_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guard_isStateActive(&statechart, Guard_main_region_B));
 	guardIface_raise_return(&statechart);
-	guard_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guard_isStateActive(&statechart, Guard_main_region_A));
 	guardIface_raise_event1(&statechart);
-	guard_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guard_isStateActive(&statechart, Guard_main_region_B));
 	guardIface_raise_return(&statechart);
-	guard_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guard_isStateActive(&statechart, Guard_main_region_A));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/Guard/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/Guard/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 24 - 17
test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedEntry/GuardedEntryTest.cc

@@ -1,22 +1,29 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "GuardedEntry.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static GuardedEntry statechart;
 
-class StatemachineTest : public ::testing::Test{
+class GuardedEntryTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		guardedEntry_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &guardedEntry_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
@@ -24,32 +31,32 @@ void initEntryInTransition(bool guardVar, bool doneVar){
 	guardedEntry_enter(&statechart);
 	EXPECT_TRUE(guardedEntry_isStateActive(&statechart, GuardedEntry_main_region_A));
 	guardedEntryIface_raise_e(&statechart);
-	guardedEntry_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guardedEntry_isStateActive(&statechart, GuardedEntry_main_region_B));
 	guardedEntryIface_set_guard(&statechart,guardVar);
 	guardedEntryIface_set_done(&statechart,doneVar);
 	guardedEntryIface_raise_e(&statechart);
-	guardedEntry_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guardedEntry_isStateActive(&statechart, GuardedEntry_main_region_A));
 }
 
-TEST_F(StatemachineTest, EntryNotTakenOnStatechartEnter) {					
+TEST_F(GuardedEntryTest, EntryNotTakenOnStatechartEnter) {
 	EXPECT_TRUE(guardedEntryIface_get_guard(&statechart)== false);
 	guardedEntry_enter(&statechart);
 	EXPECT_TRUE(guardedEntry_isStateActive(&statechart, GuardedEntry_main_region_A));
 	EXPECT_TRUE(guardedEntryIface_get_done(&statechart)== false);
 }
-TEST_F(StatemachineTest, EntryTakenOnStatechartEnter) {					
+TEST_F(GuardedEntryTest, EntryTakenOnStatechartEnter) {
 	guardedEntryIface_set_guard(&statechart,true);
 	guardedEntry_enter(&statechart);
 	EXPECT_TRUE(guardedEntry_isStateActive(&statechart, GuardedEntry_main_region_A));
 	EXPECT_TRUE(guardedEntryIface_get_done(&statechart)== true);
 }
-TEST_F(StatemachineTest, EntryTakenInTransition) {					
+TEST_F(GuardedEntryTest, EntryTakenInTransition) {
 	initEntryInTransition(true,false);
 	EXPECT_TRUE(guardedEntryIface_get_done(&statechart));
 }
-TEST_F(StatemachineTest, EntryNotTakenInTransition) {					
+TEST_F(GuardedEntryTest, EntryNotTakenInTransition) {
 	initEntryInTransition(false,false);
 	EXPECT_TRUE(!guardedEntryIface_get_done(&statechart));
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedEntry/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedEntry/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 21 - 14
test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedExit/GuardedExitTest.cc

@@ -1,39 +1,46 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "GuardedExit.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static GuardedExit statechart;
 
-class StatemachineTest : public ::testing::Test{
+class GuardedExitTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		guardedExit_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &guardedExit_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 void checkDone(bool shouldBeDone){
 	guardedExitIface_raise_e(&statechart);
-	guardedExit_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(guardedExit_isStateActive(&statechart, GuardedExit_main_region_B));
 	EXPECT_TRUE(shouldBeDone ? guardedExitIface_get_done(&statechart)  : !guardedExitIface_get_done(&statechart));
 }
 
-TEST_F(StatemachineTest, ExitTaken) {					
+TEST_F(GuardedExitTest, ExitTaken) {
 	guardedExit_enter(&statechart);
 	EXPECT_TRUE(guardedExit_isStateActive(&statechart, GuardedExit_main_region_A));
 	EXPECT_TRUE(!guardedExitIface_get_guard(&statechart));
 	checkDone(false);
 }
-TEST_F(StatemachineTest, ExitNotTaken) {					
+TEST_F(GuardedExitTest, ExitNotTaken) {
 	guardedExit_enter(&statechart);
 	EXPECT_TRUE(guardedExit_isStateActive(&statechart, GuardedExit_main_region_A));
 	guardedExitIface_set_guard(&statechart,true);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedExit/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/GuardedExit/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 24 - 17
test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithExitPoint/HistoryWithExitPointTest.cc

@@ -1,43 +1,50 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "HistoryWithExitPoint.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static HistoryWithExitPoint statechart;
 
-class StatemachineTest : public ::testing::Test{
+class HistoryWithExitPointTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		historyWithExitPoint_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &historyWithExitPoint_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, historyEntryAfterExit) {					
+TEST_F(HistoryWithExitPointTest, historyEntryAfterExit) {
 	historyWithExitPoint_enter(&statechart);
 	EXPECT_TRUE(historyWithExitPoint_isStateActive(&statechart, HistoryWithExitPoint_mr_A_r_X1));
 	historyWithExitPointIface_raise_push(&statechart);
-	historyWithExitPoint_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithExitPoint_isStateActive(&statechart, HistoryWithExitPoint_mr_B));
 	historyWithExitPointIface_raise_back(&statechart);
-	historyWithExitPoint_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithExitPoint_isStateActive(&statechart, HistoryWithExitPoint_mr_A_r_X1));
 	historyWithExitPointIface_raise_next(&statechart);
-	historyWithExitPoint_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithExitPoint_isStateActive(&statechart, HistoryWithExitPoint_mr_A_r_X2));
 	historyWithExitPointIface_raise_push(&statechart);
-	historyWithExitPoint_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithExitPoint_isStateActive(&statechart, HistoryWithExitPoint_mr_B));
 	historyWithExitPointIface_raise_back(&statechart);
-	historyWithExitPoint_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithExitPoint_isStateActive(&statechart, HistoryWithExitPoint_mr_A_r_X2));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithExitPoint/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithExitPoint/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 28 - 21
test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithoutInitialStep/HistoryWithoutInitialStepTest.cc

@@ -1,22 +1,29 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "HistoryWithoutInitialStep.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static HistoryWithoutInitialStep statechart;
 
-class StatemachineTest : public ::testing::Test{
+class HistoryWithoutInitialStepTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		historyWithoutInitialStep_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &historyWithoutInitialStep_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
@@ -24,36 +31,36 @@ void init(){
 	historyWithoutInitialStep_enter(&statechart);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_A));
 	historyWithoutInitialStepIface_raise_toB(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 }
 
-TEST_F(StatemachineTest, enterThroughInitialEntry) {					
+TEST_F(HistoryWithoutInitialStepTest, enterThroughInitialEntry) {
 	init();
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_B_r1_C));
 	historyWithoutInitialStepIface_raise_next(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_B_r1_D));
 }
-TEST_F(StatemachineTest, enterCThroughHistory) {					
+TEST_F(HistoryWithoutInitialStepTest, enterCThroughHistory) {
 	init();
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_B_r1_C));
 	historyWithoutInitialStepIface_raise_toA(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_A));
 	historyWithoutInitialStepIface_raise_toHistory(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_B_r1_C));
 }
-TEST_F(StatemachineTest, enterDThroughHistory) {					
+TEST_F(HistoryWithoutInitialStepTest, enterDThroughHistory) {
 	init();
 	historyWithoutInitialStepIface_raise_next(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_B_r1_D));
 	historyWithoutInitialStepIface_raise_toA(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_A));
 	historyWithoutInitialStepIface_raise_toHistory(&statechart);
-	historyWithoutInitialStep_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(historyWithoutInitialStep_isStateActive(&statechart, HistoryWithoutInitialStep_main_region_B_r1_D));
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithoutInitialStep/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/HistoryWithoutInitialStep/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/InEventLifeCycle/InEventLifeCycleTest.cc

@@ -1,31 +1,38 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "InEventLifeCycle.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static InEventLifeCycle statechart;
 
-class StatemachineTest : public ::testing::Test{
+class InEventLifeCycleTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		inEventLifeCycle_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &inEventLifeCycle_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, eventLifeCycle) {					
+TEST_F(InEventLifeCycleTest, eventLifeCycle) {
 	inEventLifeCycle_enter(&statechart);
 	inEventLifeCycleIface_raise_e(&statechart);
 	EXPECT_TRUE(inEventLifeCycleIface_get_i(&statechart)== 0l);
-	inEventLifeCycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(inEventLifeCycleIface_get_i(&statechart)== 1l);
 }
 

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/InEventLifeCycle/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/InEventLifeCycle/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 20 - 13
test-plugins/org.yakindu.sct.generator.c.test/gtests/IntegerExpressions/IntegerExpressionsTest.cc

@@ -1,33 +1,40 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "IntegerExpressions.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static IntegerExpressions statechart;
 
-class StatemachineTest : public ::testing::Test{
+class IntegerExpressionsTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		integerExpressions_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &integerExpressions_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, integerExpressions) {					
+TEST_F(IntegerExpressionsTest, integerExpressions) {
 	integerExpressions_enter(&statechart);
 	EXPECT_TRUE(integerExpressions_isStateActive(&statechart, IntegerExpressions_main_region_StateA));
 	EXPECT_TRUE(integerExpressionsIface_get_myInt1(&statechart)== 10l);
 	EXPECT_TRUE(integerExpressionsIface_get_myInt2(&statechart)== 5l);
 	integerExpressionsIface_raise_e1(&statechart);
-	integerExpressions_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(integerExpressionsIface_get_less(&statechart)== false);
 	EXPECT_TRUE(integerExpressionsIface_get_greater(&statechart)== true);
 	EXPECT_TRUE(integerExpressionsIface_get_equalOrLess(&statechart)== false);

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/IntegerExpressions/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/IntegerExpressions/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 23 - 16
test-plugins/org.yakindu.sct.generator.c.test/gtests/InternalEventLifeCycle/InternalEventLifeCycleTest.cc

@@ -1,42 +1,49 @@
-/**
-* Copyright (c) 2017 committers of YAKINDU and others.
-* All rights reserved. This program and the accompanying materials
-* are made available under the terms of the Eclipse Public License v1.0
-* which accompanies this distribution, and is available at
-* http://www.eclipse.org/legal/epl-v10.html
-*
-* Contributors:
-*     committers of YAKINDU - initial API and implementation
-*/
+/* Generated by YAKINDU Statechart Tools code generator. */
+
 #include "gtest/gtest.h"
 #include "InternalEventLifeCycle.h"
 
+#include "sc_timer_service.h"
+
+
+
+//! The timers are managed by a timer service. */
+static sc_unit_timer_service_t timer_service;
+
 static InternalEventLifeCycle statechart;
 
-class StatemachineTest : public ::testing::Test{
+class InternalEventLifeCycleTest : public ::testing::Test{
 	protected:
 	virtual void SetUp() {
 		internalEventLifeCycle_init(&statechart);
+		sc_timer_service_init(
+			&timer_service,
+			0,
+			(sc_run_cycle_fp) &internalEventLifeCycle_runCycle,
+			false,
+			200,
+			&statechart
+		);
 	}
 };
 
 
-TEST_F(StatemachineTest, InternalEventLifeCycleTest) {					
+TEST_F(InternalEventLifeCycleTest, InternalEventLifeCycleTest) {
 	internalEventLifeCycle_enter(&statechart);
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r1_A));
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r2_C));
 	internalEventLifeCycleIface_raise_e(&statechart);
-	internalEventLifeCycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r1_A));
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r2_D));
-	internalEventLifeCycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r1_A));
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r2_D));
 	internalEventLifeCycleIface_raise_f(&statechart);
-	internalEventLifeCycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r1_A));
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r2_C));
-	internalEventLifeCycle_runCycle(&statechart);
+	sc_timer_service_proceed_cycles(&timer_service, 1);
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r1_A));
 	EXPECT_TRUE(internalEventLifeCycle_isStateActive(&statechart, InternalEventLifeCycle_r2_C));
 }

+ 233 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/InternalEventLifeCycle/sc_timer_service.c

@@ -0,0 +1,233 @@
+/*
+ * Timer Service Implementation for SCTUnit
+ */
+
+#include "sc_timer_service.h"
+
+#include <stdlib.h>
+
+/**
+ * Implementation of a timer service that uses _virtual_ time to raise time events.
+ * It is solely meant for use with sctunit.
+ */
+
+void sc_timer_service_init(
+		sc_unit_timer_service_t * ts,
+		sc_raise_time_event_fp raise_event_func,
+		sc_run_cycle_fp run_cycle_func,
+		sc_boolean event_driven,
+		sc_integer cycle_period,
+		void* handle
+		)
+{
+	ts->raise_event_func = raise_event_func;
+	ts->tasks = 0;
+	ts->run_cycle_func = run_cycle_func;
+	ts->event_driven = event_driven;
+	ts->cycle_period = cycle_period;
+	ts->handle = handle;
+	ts->current_time_ms = 0;
+	
+	if(!ts->event_driven) {
+		sc_timer_t run_cycle;
+		sc_timer_init(
+			&run_cycle,
+			ts->cycle_period,
+			true,
+			0);
+		run_cycle.isRunCycle = true;
+		run_cycle.priority = -1;
+		insert_timer(ts, run_cycle);
+	}
+}
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+)
+{
+	t->rel_time_ms = time_ms;
+	t->abs_time_ms = 0;
+	t->periodic = periodic;
+	t->pt_evid = evid;
+	t->priority = 0;
+	t->isRunCycle = false;
+}
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
+{
+	sc_integer stop_time_ms = ts->current_time_ms + time_ms;
+	sc_boolean processed_timer = false;
+	
+	do {
+		// first assume we won't process a timer
+		processed_timer = false;
+	
+		// and then check if there is a timer to process
+		if( ts->tasks > 0) {
+			if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
+	
+				sc_timer_task_t * next_task = pop_task(ts);
+				sc_timer_t next = next_task->timer;
+				free(next_task);
+	
+				// shift time to the timer absolute time
+				ts->current_time_ms = next.abs_time_ms;
+	
+				// reschedule periodic timer
+				if(next.periodic) {
+					insert_timer(ts, next);
+				}
+	
+				// process timer ...
+				if(next.isRunCycle) {
+					ts->run_cycle_func(ts->handle);
+				} else {
+					ts->raise_event_func(ts->handle, next.pt_evid);
+				}
+	
+				processed_timer = true;
+			}
+		}
+	
+	} while ( processed_timer );
+	
+	// As a postcondition the current time is the time after proceeding the specified period.
+	ts->current_time_ms = stop_time_ms;
+}
+
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
+{
+	sc_integer elapsed_cycles = 0;
+	
+	while(elapsed_cycles < cycles) {
+		if(ts->tasks == 0) {
+			return;
+		}
+		sc_timer_task_t * next_task = pop_task(ts);
+		sc_timer_t next = next_task->timer;
+		free(next_task);
+		
+		ts->current_time_ms = next.abs_time_ms;
+		
+		// Repeat the event?
+		if(next.periodic) {
+			insert_timer(ts, next);
+		}
+
+		// Process event
+		if(next.isRunCycle) {
+			ts->run_cycle_func(ts->handle);
+			elapsed_cycles++;
+		} else {
+			ts->raise_event_func(ts->handle, next.pt_evid);
+		}
+	}
+}
+
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
+{
+	sc_timer_task_t * next_task = pop_task(ts);
+	sc_timer_t next = next_task->timer;
+	free(next_task);
+	
+	ts->current_time_ms = next.abs_time_ms;
+	
+	// Repeat the event?
+	if(next.periodic) {
+		insert_timer(ts, next);
+	}
+	
+	return next;
+}
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
+{
+	if(!task) {
+		return;
+	}
+	if(ts->tasks == task) {
+		ts->tasks = ts->tasks->next;
+
+	} else {
+		sc_timer_task_t * this = ts->tasks->next;
+		sc_timer_task_t * last = ts->tasks;
+		while(this) {
+			if(this == task) {
+				last->next = this->next;
+			}
+			else {
+				last = last->next;
+			}
+			this = this->next;
+		}
+	}
+	free(task);
+}
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
+{
+	sc_timer_task_t * this = ts->tasks;
+	while(this && this->timer.pt_evid != evid) {
+		this = this->next;
+	}
+	return this;
+}
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
+{
+	sc_timer_task_t * head = ts->tasks;
+	sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
+	te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
+	new->timer = te;
+	new->next = 0;
+	if(head == 0) {
+		ts->tasks = new;
+		return;
+	}
+
+	// Check if we should put it in as first element
+	if(compare(&te, &(head->timer)) < 0) {
+		new->next = head;
+		ts->tasks = new;
+		return;
+	}
+
+	sc_timer_task_t * last = head;
+	head = head->next;
+	while(head != 0) {
+		if(compare(&te, &(head->timer)) < 0) {
+			new->next = head;
+			last->next = new;
+			return;
+		}
+		last = head;
+		head = head->next;
+	}
+
+	// put it in last position
+	last->next = new;
+}
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
+	sc_timer_task_t * head = ts->tasks;
+	if(head != 0) {
+		ts->tasks = head->next;
+	}
+	return head;
+}
+
+/* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
+sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
+	// smaller time_ms needs to be raised first
+	sc_integer result = a->abs_time_ms - b->abs_time_ms;
+	if(result != 0) {
+		return result;
+	} else {
+		// bigger priority needs to be raised first
+		result = b->priority - a->priority;
+		return result;
+	}
+}

+ 81 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/InternalEventLifeCycle/sc_timer_service.h

@@ -0,0 +1,81 @@
+/*
+ * Timer Service for SCTUnit
+ */
+
+#ifndef SC_TIMER_SERVICE_H_
+#define SC_TIMER_SERVICE_H_
+
+#include "sc_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! file/ Interface definition of a POSIX thread based timer service for YAKINDU SCT stet machines. */
+
+typedef struct {
+	sc_integer rel_time_ms;
+	sc_integer abs_time_ms;
+	sc_boolean periodic;
+	sc_eventid pt_evid;
+	sc_integer priority;
+	sc_boolean isRunCycle;
+} sc_timer_t;
+
+typedef struct sc_timer_task_s {
+	sc_timer_t timer;
+	struct sc_timer_task_s * next;
+} sc_timer_task_t;
+
+/*! Function pointer type for state machines raiseEvent function. */
+typedef void (*sc_raise_time_event_fp)(void *handle, sc_eventid evid);
+typedef void (*sc_run_cycle_fp)(void *handle);
+
+typedef struct {
+	sc_timer_task_t * tasks;
+	sc_raise_time_event_fp raise_event_func;
+	sc_run_cycle_fp run_cycle_func;
+	sc_boolean event_driven;
+	sc_integer cycle_period;
+	void* handle;
+	sc_integer current_time_ms;
+
+} sc_unit_timer_service_t;
+
+void sc_timer_service_init(
+	sc_unit_timer_service_t * ts,
+	sc_raise_time_event_fp raise_event_func,
+	sc_run_cycle_fp run_cycle_func,
+	sc_boolean event_driven,
+	sc_integer cycle_period,
+	void* handle
+);
+
+void sc_timer_init(
+	sc_timer_t * t,
+	sc_integer time_ms,
+	sc_boolean periodic,
+	sc_eventid evid
+);
+
+
+void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms);
+void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles);
+sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts);
+
+void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te);
+
+void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t* task);
+
+sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid);
+
+sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts);
+
+sc_integer compare(sc_timer_t * a, sc_timer_t * b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SC_TIMER_SERVICE_H_ */
+

+ 0 - 0
test-plugins/org.yakindu.sct.generator.c.test/gtests/LocalReactions/LocalReactionsTest.cc


Некоторые файлы не были показаны из-за большого количества измененных файлов