Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ endif()
target_compile_definitions(reactor-uc PUBLIC "PLATFORM_${PLATFORM}")

# Add compile definition for scheduler used
target_compile_definitions(reactor-uc PRIVATE "SCHEDULER_${SCHEDULER}")
target_compile_definitions(reactor-uc PUBLIC "SCHEDULER_${SCHEDULER}")

# Add compile definitions for event and reaction queue sizes. Has to be PUBLIC because they are used in the header files.
message(STATUS "Setting event queue size to ${EVENT_QUEUE_SIZE} and reaction queue size to ${REACTION_QUEUE_SIZE}")
Expand Down
47 changes: 47 additions & 0 deletions examples/posix/static-connection/src/SimpleConnection.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
target uC

preamble {=
#define EXPECTED -9
=}

reactor Source {
output out:int
timer t(0, 1 sec)
state s:int = 0
reaction(t) -> out {=
lf_set(out, self->s);
lf_print("Sent %d @ %lld", self->s++, lf_time_logical_elapsed());
=}
reaction(t) -> out {=
int v = -1 * self->s;
lf_set(out, v);
=}
}

reactor Sink {
input in:int
state last_received:int = 0
reaction(in) {=
self->last_received = in->value;
=}
// FIXME: Multiple reactions triggered by the same port does not yet work.
reaction(in) {=
lf_print("Received %d @ %lld", in->value, lf_time_logical_elapsed());
=}
reaction(shutdown) {=
if (self->last_received != EXPECTED) {
fprintf(stderr, "FAILURE: Expected %d, Received %d\n", EXPECTED, self->last_received);
exit(1);
} else {
lf_print("Successfully received %d", self->last_received);
}
=}
}

main reactor {
source = new Source()
sink = new Sink()
source.out -> sink.in after 2 sec
// source.out -> sink.in after 500 msec
// source.out -> sink.in
}
99 changes: 99 additions & 0 deletions examples/posix/static-connection/src/lf_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include "reactor-uc/macros.h"
#include "SimpleConnection/SimpleConnection.h"
#include "reactor-uc/schedulers/static/scheduler.h"
#include "reactor-uc/schedulers/static/instructions.h"
#include "reactor-uc/schedulers/static/circular_buffer.h"

#define WORKER_0_SYNC_BLOCK 0LL
#define WORKER_0_INIT 4LL
#define WORKER_0_CLEANUP_0 7LL
#define WORKER_0_END 14LL


Reactor_SimpleConnection main_reactor;
Environment env;
Environment *_lf_environment = &env;
void lf_exit(void) { Environment_free(&env); }
void lf_start() {
Environment_ctor(&env, (Reactor *)&main_reactor);
Reactor_SimpleConnection_ctor(&main_reactor, NULL, &env);
env.scheduler->duration = NEVER;
env.scheduler->keep_alive = false;
env.fast_mode = false;
env.assemble(&env);
}
void lf_execute() {
env.start(&env);
lf_exit();
}

void conn_0_pop_event_and_prepare_port(TriggerBuffer *trigger_buffer) {
CircularBuffer buffer = trigger_buffer->buffer;
Event e;
cb_pop_front(&buffer, &e);
main_reactor.conn_source_out_0[0][0].super.super.super.prepare(&main_reactor.conn_source_out_0[0][0], &e);
}

int main() {
lf_start();
StaticSchedulerState* state = &((StaticScheduler*)_lf_environment->scheduler)->state;
const size_t reactor_tags_size = 3;
ReactorTagPair reactor_tags[reactor_tags_size] = {{&main_reactor, 0}, {&main_reactor.source, 0}, {&main_reactor.sink, 0}};
size_t trigger_buffers_size = 1;
TriggerBuffer trigger_buffers[trigger_buffers_size];
cb_init(&trigger_buffers[0].buffer, 10, sizeof(Event));
trigger_buffers[0].trigger = &main_reactor.conn_source_out_0[0][0];
inst_t schedule_0[] = {
// WORKER_0_PREAMBLE:
// Line 0: Increment OFFSET by adding START_TIME and 0LL
{.func=execute_inst_ADDI, .opcode=ADDI, .op1.reg=(reg_t*)&(state->time_offset), .op2.reg=(reg_t*)&(state->start_time), .op3.imm=0LL},
// Line 1: Increment TIMEOUT by adding START_TIME and 10000000000LL
{.func=execute_inst_ADDI, .opcode=ADDI, .op1.reg=(reg_t*)&(state->timeout), .op2.reg=(reg_t*)&(state->start_time), .op3.imm=10000000000LL},
// Line 2: Increment OFFSET_INC by adding ZERO and 0LL
{.func=execute_inst_ADDI, .opcode=ADDI, .op1.reg=(reg_t*)&(state->offset_inc), .op2.reg=(reg_t*)&(state->zero), .op3.imm=0LL},
// Line 3: JAL: store return address in ZERO and jump to INIT
{.func=execute_inst_JAL, .opcode=JAL, .op1.reg=(reg_t*)&(state->zero), .op2.imm=WORKER_0_INIT, .op3.imm=0},
// WORKER_0_EXECUTE_SimpleConnection_source_reaction_1_6570d54d:
// WORKER_0_INIT:
// Line 4: Execute function envs[simpleconnection_main].reaction_array[0]->function with argument envs[simpleconnection_main].reactor_self_array[1]
// IMPORTANT NOTE: To let reaction body and DelayConnection_cleanup both use scheduler->current_tag, which needs to access the reactor's pointer, pass the reactor pointer from op3, which can be accessed from current_tag to identify the reactor.
{.func=execute_inst_EXE, .opcode=EXE, .op1.reg=(reg_t*)(main_reactor.source->reaction0.super.body), .op2.reg=(reg_t*)&(main_reactor.source->reaction0.super), .op3.reg=(reg_t*)&(main_reactor.source)},
// Line 5: Increment Worker 0's COUNTER by adding Worker 0's COUNTER and 1LL
{.func=execute_inst_ADDI, .opcode=ADDI, .op1.reg=(reg_t*)&(state->counter), .op2.reg=(reg_t*)&(state->counter), .op3.imm=1LL},

// Line 6: Check if the port is being set by the reaction. If so, invoke the cleanup function to push the payload into the buffer. Otherwise, skip the cleanup, which is not supposed to be called when the out port is not set.
{.func=execute_inst_BEQ, .opcode=BEQ, .op1.reg=(reg_t*)&(main_reactor.source->out->super.super.is_present), .op2.reg=(reg_t*)&(state->zero), .op3.imm=WORKER_0_CLEANUP_0 + 1},

// Line 7: Call DelayConnection_cleanup to get to the schedule_at in StaticScheduler.
{.func=execute_inst_EXE, .opcode=EXE, .op1.reg=(reg_t*)(main_reactor.conn_source_out_0[0][0].super.super.super.cleanup), .op2.reg=(reg_t*)&(main_reactor.conn_source_out_0[0][0]), .op3.reg=(reg_t*)&(main_reactor.source)},

// Line 8: Advance time for sink = reactor_tags[2].tag.time
{.func=execute_inst_ADDI, .opcode=ADDI, .op1.reg=(reg_t*)&(reactor_tags[2].tag.time), .op2.reg=(reg_t*)&(reactor_tags[2].tag.time), .op3.imm=2000000000LL},

// Line 9: Check if the current count of the connection buffer is 0.
{.func=execute_inst_BEQ, .opcode=BEQ, .op1.reg=(reg_t*)&(trigger_buffers[0].buffer.count), .op2.reg=(reg_t*)&(state->zero), .op3.imm=WORKER_0_END},

// Line 10: If not null, check if the time field of the current head matches the time of sink. If they don't, skip the reaction.
{.func=execute_inst_BNE, .opcode=BEQ, .op1.reg=(reg_t*)&(((Event*)trigger_buffers[0].buffer.head)->tag.time), .op2.reg=(reg_t*)&(reactor_tags[2].tag.time), .op3.imm=WORKER_0_END},

// Line 11: Pop the event from the connection buffer and prepare the downstream port.
{.func=execute_inst_EXE, .opcode=EXE, .op1.reg=(reg_t*)conn_0_pop_event_and_prepare_port, .op2.reg=(reg_t*)&trigger_buffers[0]},

// WORKER_0_EXECUTE_SimpleConnection_sink_reaction_1_7ed46f7f:
// Line 12: Execute function envs[simpleconnection_main].reaction_array[2]->function with argument envs[simpleconnection_main].reactor_self_array[2]
{.func=execute_inst_EXE, .opcode=EXE, .op1.reg=(reg_t*)(main_reactor.sink->reaction0.super.body), .op2.reg=(reg_t*)&((main_reactor.sink->reaction0.super)), .op3.reg=(reg_t*)&(main_reactor.sink)},

// WORKER_0_EXECUTE_SimpleConnection_sink_reaction_2_f52ba644:
// Line 13: Execute function envs[simpleconnection_main].reaction_array[3]->function with argument envs[simpleconnection_main].reactor_self_array[2]
{.func=execute_inst_EXE, .opcode=EXE, .op1.reg=(reg_t*)(main_reactor.sink->reaction1.super.body), .op2.reg=(reg_t*)&((main_reactor.sink->reaction1.super)), .op3.reg=(reg_t*)&(main_reactor.sink)},

// Line 14
{.func=execute_inst_STP, .opcode=STP},
};
((StaticScheduler*)_lf_environment->scheduler)->static_schedule = schedule_0;
((StaticScheduler*)_lf_environment->scheduler)->reactor_tags = reactor_tags;
((StaticScheduler*)_lf_environment->scheduler)->reactor_tags_size = reactor_tags_size;
((StaticScheduler*)_lf_environment->scheduler)->trigger_buffers = trigger_buffers;
((StaticScheduler*)_lf_environment->scheduler)->trigger_buffers_size = trigger_buffers_size;
lf_execute();
}
9 changes: 9 additions & 0 deletions examples/posix/static/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.20.0)
project(reactor-uc-posix-hello)

set(PLATFORM "POSIX" CACHE STRING "Platform to target")
set(SCHEDULER "STATIC" CACHE STRING "Scheduler to use")
add_subdirectory(reactor-uc)

add_executable(app R1.c R2.c static_schedule.c Connections.c)
target_link_libraries(app PRIVATE reactor-uc)
51 changes: 51 additions & 0 deletions examples/posix/static/Connections.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "Connections.h"
// Private preambles

// Reaction bodies

// Reaction deadline handlers

// Reaction constructors


// Timer constructors

// Port constructors

// Connection constructors
LF_DEFINE_LOGICAL_CONNECTION_CTOR(Reactor_Connections, conn_r1_out_0, 1);
LF_DEFINE_DELAYED_CONNECTION_CTOR(Reactor_Connections, conn_r3_out_1, 1, int, 1, MSEC(10), false);
LF_REACTOR_CTOR_SIGNATURE(Reactor_Connections) {
LF_REACTOR_CTOR_PREAMBLE();
LF_REACTOR_CTOR(Reactor_Connections);
// Initialize Reactor parameters

// Initialize State variables
LF_DEFINE_CHILD_OUTPUT_ARGS(r1, out, 1, 1);

LF_INITIALIZE_CHILD_REACTOR_WITH_PARAMETERS(Reactor_R1, r1, 1 , _r1_out_args[i] );


LF_DEFINE_CHILD_INPUT_ARGS(r2, in, 1, 1);
LF_INITIALIZE_CHILD_REACTOR_WITH_PARAMETERS(Reactor_R2, r2, 1 , _r2_in_args[i] , 11);

LF_DEFINE_CHILD_OUTPUT_ARGS(r3, out, 1, 1);

LF_INITIALIZE_CHILD_REACTOR_WITH_PARAMETERS(Reactor_R1, r3, 1 , _r3_out_args[i] );


LF_DEFINE_CHILD_INPUT_ARGS(r4, in, 1, 1);
LF_INITIALIZE_CHILD_REACTOR_WITH_PARAMETERS(Reactor_R2, r4, 1 , _r4_in_args[i] , 10);
// Initialize Timers
// Initialize actions and builtin triggers

// Initialize ports

// Initialize connections
LF_INITIALIZE_LOGICAL_CONNECTION(Reactor_Connections, conn_r1_out_0, 1, 1);
LF_INITIALIZE_DELAYED_CONNECTION(Reactor_Connections, conn_r3_out_1, 1, 1);
// Do connections
lf_connect((Connection *) &self->conn_r1_out_0[0][0], (Port *) &self->r1[0].out[0], (Port *) &self->r2[0].in[0]);
lf_connect((Connection *) &self->conn_r3_out_1[0][0], (Port *) &self->r3[0].out[0], (Port *) &self->r4[0].in[0]);
// Initialize Reactions
}
66 changes: 66 additions & 0 deletions examples/posix/static/Connections.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef LFC_GEN_CONNECTIONS_H
#define LFC_GEN_CONNECTIONS_H

#include "reactor-uc/reactor-uc.h"
#include "_lf_preamble.h"

// Include instantiated reactors
#include "R1.h"
#include "R2.h"
// Reaction structs

// Timer structs


// Port structs

// Connection structs
LF_DEFINE_LOGICAL_CONNECTION_STRUCT(Reactor_Connections, conn_r1_out_0, 1);
LF_DEFINE_DELAYED_CONNECTION_STRUCT(Reactor_Connections, conn_r3_out_1, 1, int, 1, MSEC(10));
//The reactor self struct
typedef struct {
Reactor super;
// Child reactor fields

LF_CHILD_REACTOR_INSTANCE(Reactor_R1, r1, 1);

LF_CHILD_OUTPUT_CONNECTIONS(r1, out, 1, 1, 1);
LF_CHILD_OUTPUT_EFFECTS(r1, out, 1, 1, 0);
LF_CHILD_OUTPUT_OBSERVERS(r1, out, 1, 1, 0);


LF_CHILD_REACTOR_INSTANCE(Reactor_R2, r2, 1);


LF_CHILD_INPUT_SOURCES(r2, in, 1, 1, 0);

LF_CHILD_REACTOR_INSTANCE(Reactor_R1, r3, 1);

LF_CHILD_OUTPUT_CONNECTIONS(r3, out, 1, 1, 1);
LF_CHILD_OUTPUT_EFFECTS(r3, out, 1, 1, 0);
LF_CHILD_OUTPUT_OBSERVERS(r3, out, 1, 1, 0);


LF_CHILD_REACTOR_INSTANCE(Reactor_R2, r4, 1);


LF_CHILD_INPUT_SOURCES(r4, in, 1, 1, 0);

// Timers

// Actions and builtin triggers

// Connections
LF_LOGICAL_CONNECTION_INSTANCE(Reactor_Connections, conn_r1_out_0, 1, 1);
LF_DELAYED_CONNECTION_INSTANCE(Reactor_Connections, conn_r3_out_1, 1, 1);
// Ports

// State variables
// Reactor parameters

LF_REACTOR_BOOKKEEPING_INSTANCES(0, 0, 4);
} Reactor_Connections;

LF_REACTOR_CTOR_SIGNATURE(Reactor_Connections);

#endif // LFC_GEN_CONNECTIONS_H
62 changes: 62 additions & 0 deletions examples/posix/static/R1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "R1.h"
// Private preambles

// Reaction bodies
LF_DEFINE_REACTION_BODY(Reactor_R1, reaction0) {
// Bring self struct, environment, triggers, effects and sources into scope.
LF_SCOPE_SELF(Reactor_R1);
LF_SCOPE_ENV();
LF_SCOPE_STARTUP(Reactor_R1);
// Start of user-witten reaction deadline handler
printf("Startup!\n");
}
LF_DEFINE_REACTION_BODY(Reactor_R1, reaction1) {
// Bring self struct, environment, triggers, effects and sources into scope.
LF_SCOPE_SELF(Reactor_R1);
LF_SCOPE_ENV();
LF_SCOPE_TIMER(Reactor_R1, t);
LF_SCOPE_PORT(Reactor_R1, out);
// Start of user-witten reaction deadline handler
printf("Hello from R1 at %ld\n", env->get_elapsed_logical_time(env));
lf_set(out, self->cnt++);
}
// Reaction deadline handlers

// Reaction constructors
LF_DEFINE_REACTION_CTOR(Reactor_R1, reaction0, 0 );
LF_DEFINE_REACTION_CTOR(Reactor_R1, reaction1, 1 );
LF_DEFINE_STARTUP_CTOR(Reactor_R1);
// Timer constructors
LF_DEFINE_TIMER_CTOR(Reactor_R1, t, 1, 0);
// Port constructors
LF_DEFINE_OUTPUT_CTOR(Reactor_R1, out, 1);
// Connection constructors

LF_REACTOR_CTOR_SIGNATURE_WITH_PARAMETERS(Reactor_R1 , OutputExternalCtorArgs *_out_external ) {
LF_REACTOR_CTOR_PREAMBLE();
LF_REACTOR_CTOR(Reactor_R1);
// Initialize Reactor parameters

// Initialize State variables
self->cnt = 0;

// Initialize Timers
LF_INITIALIZE_TIMER(Reactor_R1, t, 0, MSEC(10));
// Initialize actions and builtin triggers

LF_INITIALIZE_STARTUP(Reactor_R1);
// Initialize ports
LF_INITIALIZE_OUTPUT(Reactor_R1, out, 1, _out_external);
// Initialize connections

// Do connections

// Initialize Reactions
LF_INITIALIZE_REACTION(Reactor_R1, reaction0);
LF_STARTUP_REGISTER_EFFECT(self->reaction0);


LF_INITIALIZE_REACTION(Reactor_R1, reaction1);
LF_TIMER_REGISTER_EFFECT(self->t, self->reaction1);
LF_PORT_REGISTER_SOURCE(self->out, self->reaction1, 1);
}
43 changes: 43 additions & 0 deletions examples/posix/static/R1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef LFC_GEN_R1_H
#define LFC_GEN_R1_H

#include "reactor-uc/reactor-uc.h"
#include "_lf_preamble.h"

// Include instantiated reactors
// Reaction structs
LF_DEFINE_REACTION_STRUCT(Reactor_R1, reaction0, 0);
LF_DEFINE_REACTION_STRUCT(Reactor_R1, reaction1, 1);
// Timer structs
LF_DEFINE_TIMER_STRUCT(Reactor_R1, t, 1, 0);
LF_DEFINE_STARTUP_STRUCT(Reactor_R1, 1, 0);
// Port structs
LF_DEFINE_OUTPUT_STRUCT(Reactor_R1, out, 1, int);
// Connection structs

//The reactor self struct
typedef struct {
Reactor super;
// Child reactor fields

LF_REACTION_INSTANCE(Reactor_R1, reaction0);
LF_REACTION_INSTANCE(Reactor_R1, reaction1);
// Timers
LF_TIMER_INSTANCE(Reactor_R1, t);
// Actions and builtin triggers

LF_STARTUP_INSTANCE(Reactor_R1);
// Connections

// Ports
LF_PORT_INSTANCE(Reactor_R1, out, 1);
// State variables
int cnt;
// Reactor parameters

LF_REACTOR_BOOKKEEPING_INSTANCES(2, 3, 0);
} Reactor_R1;

LF_REACTOR_CTOR_SIGNATURE_WITH_PARAMETERS(Reactor_R1 , OutputExternalCtorArgs *_out_external );

#endif // LFC_GEN_R1_H
Loading