Skip to content

Commit

Permalink
Factor out action test into an action lib
Browse files Browse the repository at this point in the history
  • Loading branch information
erlingrj committed Nov 9, 2024
1 parent cd5ed60 commit 42c9247
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 177 deletions.
97 changes: 62 additions & 35 deletions include/reactor-uc/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,28 @@
*/
#define lf_is_present(trigger) (((Trigger *)(trigger))->is_present)

// TODO: We need to handle the case when action already has been scheduled.
// then we need a runtime error and NOT overwrite the scheduled value.
/**
* @brief Schedule an event on an action
*
*/
#define lf_schedule(action, val, offset) \
#define lf_schedule_with_val(action, offset, val) \
do { \
__typeof__(val) __val = (val); \
(action)->super.schedule(&(action)->super, (offset), (const void *)&__val); \
lf_ret_t ret = (action)->super.schedule(&(action)->super, (offset), (const void *)&__val); \
if (ret == LF_FATAL) { \
LF_ERR(TRIG, "Scheduling an value, that doesn't have value!"); \
Scheduler *sched = &(action)->super.super.parent->env->scheduler; \
sched->do_shutdown(sched, sched->current_tag); \
throw("Tried to schedule a value onto an action without a type!"); \
} \
} while (0)

#define lf_schedule_without_val(action, offset) \
do { \
(action)->super.schedule(&(action)->super, (offset), NULL); \
} while (0)

#define GET_ARG4(arg1, arg2, arg3, arg4, ...) arg4
#define LF_SCHEDULE_CHOOSER(...) GET_ARG4(__VA_ARGS__, lf_schedule_with_val, lf_schedule_without_val)

#define lf_schedule(...) LF_SCHEDULE_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

/**
* @brief Convenience macro for registering a reaction as an effect of a trigger.
* The input must be a pointer to a derived Trigger type with an effects field.
Expand All @@ -56,7 +66,6 @@
(trigger)->sources.reactions[(trigger)->sources.num_registered++] = (source); \
} while (0)


// The following macros casts the inputs into the correct types before calling TRIGGER_REGISTER_EFFECTs
#define ACTION_REGISTER_EFFECT(TheAction, TheEffect) \
TRIGGER_REGISTER_EFFECT((Action *)&self->TheAction, (Reaction *)&self->TheEffect)
Expand All @@ -76,9 +85,9 @@
*/
#define REACTION_REGISTER_EFFECT(_Reaction, _Effect) \
do { \
Reaction *__reaction = (Reaction *)&self->_Reaction; \
Reaction *__reaction = (Reaction *)&self->_Reaction; \
assert((__reaction)->effects_registered < (__reaction)->effects_size); \
(__reaction)->effects[(__reaction)->effects_registered++] = (Trigger *)&self->_Effect; \
(__reaction)->effects[(__reaction)->effects_registered++] = (Trigger *)&self->_Effect; \
} while (0)

// Convenient translation from a user trigger to a pointer to the derived Trigger type.
Expand Down Expand Up @@ -125,12 +134,12 @@

#define PORT_INSTANCE(ReactorName, PortName) ReactorName##_##PortName PortName;

#define INITIALIZE_OUTPUT(ReactorName, PortName, Conns, ConnSize) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->PortName; \
#define INITIALIZE_OUTPUT(ReactorName, PortName, Conns, ConnSize) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->PortName; \
ReactorName##_##PortName##_ctor(&self->PortName, &self->super, Conns, ConnSize)

#define INITIALIZE_INPUT(ReactorName, PortName) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->PortName; \
#define INITIALIZE_INPUT(ReactorName, PortName) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->PortName; \
ReactorName##_##PortName##_ctor(&self->PortName, &self->super)

#define DEFINE_INPUT_STRUCT(ReactorName, PortName, EffectSize, BufferType, NumConnsOut) \
Expand All @@ -147,14 +156,15 @@
&self->value, sizeof(BufferType)); \
}

#define DEFINE_TIMER_STRUCT(ReactorName, TimerName, EffectSize) \
#define DEFINE_TIMER_STRUCT(ReactorName, TimerName, EffectSize) \
typedef struct { \
Timer super; \
Reaction *effects[(EffectSize)]; \
} ReactorName##_##TimerName;

#define DEFINE_TIMER_CTOR(TimerName, EffectSize) \
void ReactorName##_##TimerName##_ctor(ReactorName##_##TimerName *self, Reactor *parent, interval_t offset, interval_t period) { \
void ReactorName##_##TimerName##_ctor(ReactorName##_##TimerName *self, Reactor *parent, interval_t offset, \
interval_t period) { \
Timer_ctor(&self->super, parent, offset, period, self->effects, EffectSize); \
}

Expand All @@ -168,8 +178,8 @@

#define REACTION_INSTANCE(ReactorName, ReactionName) ReactorName##_Reaction_##ReactionName ReactionName;

#define INITIALIZE_REACTION(ReactorName, ReactionName) \
self->_reactions[_reactions_idx++] = (Reaction *)&self->ReactionName; \
#define INITIALIZE_REACTION(ReactorName, ReactionName) \
self->_reactions[_reactions_idx++] = (Reaction *)&self->ReactionName; \
ReactorName##_Reaction_##ReactionName##_ctor(&self->ReactionName, &self->super)

#define DEFINE_REACTION_BODY(ReactorName, ReactionName) \
Expand All @@ -188,51 +198,68 @@
Reaction *effects[(EffectSize)]; \
} ReactorName##_Startup;

#define DEFINE_STARTUP_CTOR(ReactorName) \
void ReactorName##_Startup_ctor(ReactorName##_Startup *self, Reactor *parent) { \
#define DEFINE_STARTUP_CTOR(ReactorName) \
void ReactorName##_Startup_ctor(ReactorName##_Startup *self, Reactor *parent) { \
BuiltinTrigger_ctor(&self->super, TRIG_STARTUP, parent, self->effects, \
sizeof(self->effects) / sizeof(self->effects[0])); \
}

#define STARTUP_INSTANCE(ReactorName) ReactorName##_Startup startup;
#define INITIALIZE_STARTUP(ReactorName) \
#define INITIALIZE_STARTUP(ReactorName) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->startup; \
ReactorName##_Startup_ctor(&self->startup, &self->super)

#define DEFINE_SHUTDOWN_STRUCT(ReactorName, EffectSize) \
#define DEFINE_SHUTDOWN_STRUCT(ReactorName, EffectSize) \
typedef struct { \
BuiltinTrigger super; \
Reaction *effects[(EffectSize)]; \
} ReactorName##_Shutdown;

#define DEFINE_SHUTDOWN_CTOR(ReactorName) \
void ReactorName##_Shutdown_ctor(ReactorName##_Shutdown *self, Reactor *parent) { \
#define DEFINE_SHUTDOWN_CTOR(ReactorName) \
void ReactorName##_Shutdown_ctor(ReactorName##_Shutdown *self, Reactor *parent) { \
BuiltinTrigger_ctor(&self->super, TRIG_SHUTDOWN, parent, self->effects, \
sizeof(self->effects) / sizeof(self->effects[0])); \
}

#define SHUTDOWN_INSTANCE(ReactorName) ReactorName##_Shutdown shutdown;

#define DEFINE_ACTION_STRUCT(ReactorName, ActionName, ActionType, EffectSize, SourceSize, BufferSize, BufferType) \
#define DEFINE_ACTION_STRUCT(ReactorName, ActionName, ActionType, EffectSize, SourceSize, MaxPendingEvents, \
BufferType) \
typedef struct { \
Action super; \
BufferType value; \
BufferType payload_buf[(BufferSize)]; \
bool payload_used_buf[(BufferSize)]; \
BufferType payload_buf[(MaxPendingEvents)]; \
bool payload_used_buf[(MaxPendingEvents)]; \
Reaction *sources[(SourceSize)]; \
Reaction *effects[(EffectSize)]; \
} ReactorName##_##ActionName
} ReactorName##_##ActionName;

#define DEFINE_ACTION_STRUCT_VOID(ReactorName, ActionName, ActionType, EffectSize, SourceSize, MaxPendingEvents) \
typedef struct { \
Action super; \
Reaction *sources[(SourceSize)]; \
Reaction *effects[(EffectSize)]; \
} ReactorName##_##ActionName;

#define DEFINE_ACTION_CTOR(ReactorName, ActionName, ActionType, EffectSize, SourceSize, MaxPendingEvents, \
BufferType) \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay) { \
Action_ctor(&self->super, ActionType, min_delay, parent, self->sources, (SourceSize), self->effects, (EffectSize), \
&self->value, sizeof(BufferType), (void *)&self->payload_buf, self->payload_used_buf, \
(MaxPendingEvents)); \
}

#define DEFINE_ACTION_CTOR(ReactorName, ActionName, ActionType, EffectSize, SourceSize, BufferSize, BufferType) \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay) { \
Action_ctor(&self->super, ActionType, min_delay, parent, self->sources, SourceSize, self->effects, EffectSize, \
&self->value, sizeof(BufferType), (void *)&self->payload_buf, self->payload_used_buf, BufferSize); \
#define DEFINE_ACTION_CTOR_VOID(ReactorName, ActionName, ActionType, EffectSize, SourceSize, \
MaxPendingEvents) \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay) { \
Action_ctor(&self->super, ActionType, min_delay, parent, self->sources, (SourceSize), self->effects, \
(EffectSize), NULL, 0, NULL, NULL, (MaxPendingEvents)); \
}

#define ACTION_INSTANCE(ReactorName, ActionName) ReactorName##_##ActionName ActionName;

#define INITIALIZE_ACTION(ReactorName, ActionName, MinDelay) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->ActionName; \
#define INITIALIZE_ACTION(ReactorName, ActionName, MinDelay) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->ActionName; \
ReactorName##_##ActionName##_ctor(&self->ActionName, &self->super, MinDelay)

#define SCOPE_ACTION(ReactorName, ActionName) ReactorName##_##ActionName *ActionName = &self->ActionName
Expand Down
23 changes: 23 additions & 0 deletions test/unit/action_empty_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "unity.h"

#define ACTION_LIB_VOID_TYPE
#include "action_lib.h"

DEFINE_REACTION_BODY(ActionLib, reaction) {
SCOPE_SELF(ActionLib);
SCOPE_ENV();
SCOPE_ACTION(ActionLib, act);
TEST_ASSERT_EQUAL(env->get_elapsed_logical_time(env)/MSEC(1), self->cnt);
lf_schedule(act, MSEC(1));
self->cnt++;
}

void test_run() {
action_int_lib_start(MSEC(100));
}

int main() {
UNITY_BEGIN();
RUN_TEST(test_run);
return UNITY_END();
}
46 changes: 28 additions & 18 deletions test/unit/action_lib.h
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
#ifndef ACTION_LIB_H
#define ACTION_LIB_H
#include "reactor-uc/reactor-uc.h"

DEFINE_ACTION_STRUCT(ActionTest, act, LOGICAL_ACTION, 1, 1, 2, int);
DEFINE_ACTION_CTOR(ActionTest, act, LOGICAL_ACTION, 1, 1, 2, int);
DEFINE_STARTUP_STRUCT(ActionTest, 1);
DEFINE_STARTUP_CTOR(ActionTest);
DEFINE_REACTION_STRUCT(ActionTest, reaction, 1);
DEFINE_REACTION_CTOR(ActionTest, reaction, 0);
#ifdef ACTION_LIB_VOID_TYPE
DEFINE_ACTION_STRUCT_VOID(ActionLib, act, LOGICAL_ACTION, 1, 1, 2);
DEFINE_ACTION_CTOR_VOID(ActionLib, act, LOGICAL_ACTION, 1, 1, 2);
#else
DEFINE_ACTION_STRUCT(ActionLib, act, LOGICAL_ACTION, 1, 1, 2, int);
DEFINE_ACTION_CTOR(ActionLib, act, LOGICAL_ACTION, 1, 1, 2, int);
#endif

DEFINE_STARTUP_STRUCT(ActionLib, 1);
DEFINE_STARTUP_CTOR(ActionLib);
DEFINE_REACTION_STRUCT(ActionLib, reaction, 1);
DEFINE_REACTION_CTOR(ActionLib, reaction, 0);

typedef struct {
Reactor super;
REACTION_INSTANCE(ActionTest, reaction);
ACTION_INSTANCE(ActionTest, act);
STARTUP_INSTANCE(ActionTest);
REACTION_INSTANCE(ActionLib, reaction);
ACTION_INSTANCE(ActionLib, act);
STARTUP_INSTANCE(ActionLib);
Reaction *_reactions[1];
Trigger *_triggers[2];
int cnt;
} ActionTest;
} ActionLib;


void ActionTest_ctor(ActionTest *self, Environment *env) {
Reactor_ctor(&self->super, "ActionTest", env, NULL, NULL, 0, self->_reactions,
void ActionIntLib_ctor(ActionLib *self, Environment *env) {
Reactor_ctor(&self->super, "ActionLib", env, NULL, NULL, 0, self->_reactions,
sizeof(self->_reactions) / sizeof(self->_reactions[0]), self->_triggers,
sizeof(self->_triggers) / sizeof(self->_triggers[0]));
size_t _triggers_idx = 0;
size_t _reactions_idx = 0;

INITIALIZE_REACTION(ActionTest, reaction);
INITIALIZE_ACTION(ActionTest, act, MSEC(0));
INITIALIZE_STARTUP(ActionTest);
INITIALIZE_REACTION(ActionLib, reaction);
INITIALIZE_ACTION(ActionLib, act, MSEC(0));
INITIALIZE_STARTUP(ActionLib);
ACTION_REGISTER_EFFECT(act, reaction);
REACTION_REGISTER_EFFECT(reaction, act);
ACTION_REGISTER_SOURCE(act, reaction);
Expand All @@ -36,13 +44,15 @@ void ActionTest_ctor(ActionTest *self, Environment *env) {
self->cnt = 0;
}

void action_lib_start(interval_t duration) {
ActionTest my_reactor;
void action_int_lib_start(interval_t duration) {
ActionLib my_reactor;
Environment env;
Environment_ctor(&env, (Reactor *)&my_reactor);
ActionTest_ctor(&my_reactor, &env);
ActionIntLib_ctor(&my_reactor, &env);
env.scheduler.duration = duration;
env.assemble(&env);
env.start(&env);
Environment_free(&env);
}

#endif
12 changes: 7 additions & 5 deletions test/unit/action_microstep_test.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "unity.h"

#define ACTION_LIB_TYPE int
#include "action_lib.h"

DEFINE_REACTION_BODY(ActionTest, reaction) {
SCOPE_SELF(ActionTest);
DEFINE_REACTION_BODY(ActionLib, reaction) {
SCOPE_SELF(ActionLib);
SCOPE_ENV();
SCOPE_ACTION(ActionTest, act);
SCOPE_ACTION(ActionLib, act);

if (self->cnt == 0) {
TEST_ASSERT_EQUAL(lf_is_present(act), false);
Expand All @@ -25,12 +27,12 @@ DEFINE_REACTION_BODY(ActionTest, reaction) {
TEST_ASSERT_EQUAL(0, env->get_elapsed_logical_time(env));

if (self->cnt < 100) {
lf_schedule(act, ++self->cnt, MSEC(0));
lf_schedule(act, MSEC(0), ++self->cnt);
}
}

void test_run() {
action_lib_start(MSEC(100));
action_int_lib_start(MSEC(100));
}
int main() {
UNITY_BEGIN();
Expand Down
Loading

0 comments on commit 42c9247

Please sign in to comment.