Skip to content

Commit

Permalink
Add RIOT examples (#63)
Browse files Browse the repository at this point in the history
* Add RIOT examples

* fixup! Add RIOT examples

Fix example makefiles

* fixup! Add RIOT examples

Add RIOT networking modules to example makefiles

* fixup! Add RIOT examples

Add RIOT pthread module to examples

* fixup! Add RIOT examples

Remove -Wcast-align CFLAG to make reactor-uc build for RIOT

* fixup! Add RIOT examples

Fix examples to build for all boards

* fixup! Add RIOT examples

Remove -Wstrict-prototypes and -Wold-style-definition CFLAG to make reactor-uc build for RIOT

* fixup! Add RIOT examples

Migrate blinky example to macros

* Automatically enable RIOT modules if NETWORK_POSIX_TCP is defined

* Update readme: Add RIOT examples tutorial

* Fix RIOT pthread wrapper compatibility

* Remove tcp test riot examples

* Fix riot blinky example

* Add RIOT hello example
  • Loading branch information
LasseRosenow authored Oct 22, 2024
1 parent fa23939 commit 0db8386
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 7 deletions.
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# reactor-uc

`reactor-uc` is a task scheduling runtime implementing the reactor
model-of-computation target at embedded and resource-constrained 32 bit systems.

Expand All @@ -8,21 +9,25 @@ NB: reactor-uc is still work-in-progress and many (most?) features are not suppo
yet. This only documents how to run a few example programs.

Setup the environment

```
source env.bash
```

Initialize submodules

```
git submodule update --init
```

Compile and run unit tests:

```
make test
```

Compile and run a simple timer test on Posix

```
cd examples/posix
cmake -Bbuild
Expand All @@ -45,10 +50,20 @@ west build -b frdm_k64f -p always
west flash
```

For more information on running LF programs using the reactor-uc runtime on
Zephyr take a look at this template: https://github.com/lf-lang/lf-west-template/tree/reactor-uc
Compile and run a simple blinky example on RIOT.
This requires a correctly configured RIOT environment.
Make sure that the environment variable `RIOTBASE` points to a `RIOT` codebase.

```
cd examples/riot/blinky
make BOARD=native all term
```

For more information on running LF programs using the reactor-uc runtime on
Zephyr take a look at this template: <https://github.com/lf-lang/lf-west-template/tree/reactor-uc>

## Lingua Franca

We have copied a very limited version of the Lingua Franca Compiler (lfc) into
`~/lfc` of this repo. In the future, the `reactor-uc` specific code-generation
will be merged back upstream. By sourcing `env.bash` or `env.fish` the Lingua
Expand All @@ -69,6 +84,7 @@ bin/HelloUc
```

## Goals

- Incorporate unit testing and test-driven development from the start
- Optimized for single-core 32-bit systems
- Backend for LF
Expand All @@ -80,13 +96,16 @@ which enable distributed embedded systems.
- Avoid malloc as much as possible (or entirely?)

## References

`reactor-uc` draws inspiration from the following existing open-source projects:

- [reactor-cpp](https://github.com/lf-lang/reactor-cpp)
- [reactor-c](https://github.com/lf-lang/reactor-c)
- [qpc](https://github.com/QuantumLeaps/qpc)
- [ssm-runtime](https://github.com/QuantumLeaps/qpc)

## TODO for the MVP:
## TODO for the MVP

- [x] Timers
- [x] Input/Output Ports
- [x] Logical Actions
Expand All @@ -99,8 +118,8 @@ which enable distributed embedded systems.
- [x] Posix Platform abstractions
- [x] Basic code-generation


## More advanced topics

- [x] More platform abstractions (Riot, Zephyr and FlexPRET/InterPRET)
- [x] Reconsider where to buffer data (outputs vs inputs)
- [x] Consider if we should have FIFOs of pending events, not just a single for a trigger.
Expand All @@ -111,20 +130,20 @@ which enable distributed embedded systems.
- [ ] Multiports and banks
- [ ] Modal reactors


## Troubleshooting

### Formatting

We are using `clang-format` version 18.1.3 which is default with Ubuntu 24.04 for formatting in CI.

### LFC

If you get the following CMake error when calling `lfc/bin/lfc-dev`

```
CMake Error at CMakeLists.txt:7 (message):
Environment variable REACTOR_UC_PATH is not set. Please source the
env.bash in reactor-uc.
```

Please source `env.bash` or `env.fish`.

Please source `env.bash` or `env.fish`.
18 changes: 18 additions & 0 deletions examples/riot/blinky/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# name of your application
APPLICATION = lf-test

# If no BOARD is found in the environment, use this default:
BOARD ?= native

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

# Enable reactor-uc features
# CFLAGS += -DNETWORK_POSIX_TCP

include $(CURDIR)/../../../make/riot/riot.mk
37 changes: 37 additions & 0 deletions examples/riot/blinky/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "board.h"
#include "reactor-uc/reactor-uc.h"
#include <inttypes.h>

DEFINE_TIMER(MyTimer, 1, MSEC(0), MSEC(100))
DEFINE_REACTION(MyReactor, 0, 0)

typedef struct {
Reactor super;
MyReactor_0 my_reaction;
MyTimer timer;
Reaction *_reactions[1];
Trigger *_triggers[1];
} MyReactor;

REACTION_BODY(MyReactor, 0, {
LED0_TOGGLE;
printf("Hello World @ %" PRId64 "\n", env->get_elapsed_physical_time(env));
})

void MyReactor_ctor(MyReactor *self, Environment *env) {
self->_reactions[0] = (Reaction *)&self->my_reaction;
self->_triggers[0] = (Trigger *)&self->timer;

Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 1, self->_triggers, 1);
MyReactor_0_ctor(&self->my_reaction, &self->super);
MyTimer_ctor(&self->timer, &self->super);

TIMER_REGISTER_EFFECT(self->timer, self->my_reaction);
}

ENTRY_POINT(MyReactor, FOREVER, true)

int main(void) {
lf_start();
return 0;
}
18 changes: 18 additions & 0 deletions examples/riot/hello/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# name of your application
APPLICATION = lf-test

# If no BOARD is found in the environment, use this default:
BOARD ?= native

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

# Enable reactor-uc features
# CFLAGS += -DNETWORK_POSIX_TCP

include $(CURDIR)/../../../make/riot/riot.mk
31 changes: 31 additions & 0 deletions examples/riot/hello/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "reactor-uc/reactor-uc.h"
#include <inttypes.h>

DEFINE_TIMER(MyTimer, 1, 0, MSEC(100))
DEFINE_REACTION(MyReactor, 0, 0)

typedef struct {
Reactor super;
MyReactor_0 my_reaction;
MyTimer timer;
Reaction *_reactions[1];
Trigger *_triggers[1];
} MyReactor;

REACTION_BODY(MyReactor, 0, { printf("Hello World @ %lld\n", env->get_elapsed_logical_time(env)); })

void MyReactor_ctor(MyReactor *self, Environment *env) {
self->_reactions[0] = (Reaction *)&self->my_reaction;
self->_triggers[0] = (Trigger *)&self->timer;
Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 1, self->_triggers, 1);
MyReactor_0_ctor(&self->my_reaction, &self->super);
Timer_ctor(&self->timer.super, &self->super, MSEC(0), MSEC(100), self->timer.effects, 1);
TIMER_REGISTER_EFFECT(self->timer, self->my_reaction);
}

ENTRY_POINT(MyReactor, FOREVER, true)

int main() {
lf_start();
return 0;
}
6 changes: 6 additions & 0 deletions make/riot/external_modules/nanopb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include $(RIOTBASE)/Makefile.base

SRC_DIR := $(realpath $(CURDIR)/../../../../external/nanopb)

all:
$(QQ)"$(MAKE)" -C $(SRC_DIR) -f $(CURDIR)/nanopb.mk
5 changes: 5 additions & 0 deletions make/riot/external_modules/nanopb/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CFLAGS += -DPLATFORM_RIOT=1

# Use an immediate variable to evaluate `MAKEFILE_LIST` now
USEMODULE_INCLUDES_nanopb := $(LAST_MAKEFILEDIR)/../../../../external
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_nanopb)
3 changes: 3 additions & 0 deletions make/riot/external_modules/nanopb/nanopb.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = nanopb

include $(RIOTBASE)/Makefile.base
6 changes: 6 additions & 0 deletions make/riot/external_modules/proto/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include $(RIOTBASE)/Makefile.base

SRC_DIR := $(realpath $(CURDIR)/../../../../external/proto)

all:
$(QQ)"$(MAKE)" -C $(SRC_DIR) -f $(CURDIR)/proto.mk
5 changes: 5 additions & 0 deletions make/riot/external_modules/proto/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CFLAGS += -DPLATFORM_RIOT=1

# Use an immediate variable to evaluate `MAKEFILE_LIST` now
USEMODULE_INCLUDES_proto := $(LAST_MAKEFILEDIR)/../../../../external
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_proto)
3 changes: 3 additions & 0 deletions make/riot/external_modules/proto/proto.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = proto

include $(RIOTBASE)/Makefile.base
6 changes: 6 additions & 0 deletions make/riot/external_modules/reactor-uc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include $(RIOTBASE)/Makefile.base

SRC_DIR := $(realpath $(CURDIR)/../../../../src)

all:
$(QQ)"$(MAKE)" -C $(SRC_DIR) -f $(CURDIR)/reactor-uc.mk
24 changes: 24 additions & 0 deletions make/riot/external_modules/reactor-uc/Makefile.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
USEMODULE += ztimer64
USEMODULE += ztimer64_usec
USEMODULE += nanopb
USEMODULE += proto

# If Feature NETWORK_POSIX_TCP is enabled
ifeq ($(filter -DNETWORK_POSIX_TCP, $(CFLAGS)), -DNETWORK_POSIX_TCP)
# Enable networking
USEMODULE += netdev_default
USEMODULE += auto_init_gnrc_netif

# Enable sockets
USEMODULE += gnrc_ipv6_default
USEMODULE += sock_tcp
USEMODULE += posix_sockets
USEMODULE += posix_sleep
USEMODULE += posix_inet

# Enable posix threads
ifneq ($(BOARD),native)
USEMODULE += pthread
endif
endif

15 changes: 15 additions & 0 deletions make/riot/external_modules/reactor-uc/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

CFLAGS += -DPLATFORM_RIOT=1

# Remove the -Wcast-align flag for this module
CFLAGS := $(filter-out -Wcast-align,$(CFLAGS))

# Remove the -Wstrict-prototypes flag for this module
CFLAGS := $(filter-out -Wstrict-prototypes,$(CFLAGS))

# Remove the -Wold-style-definition flag for this module
CFLAGS := $(filter-out -Wold-style-definition,$(CFLAGS))

# Use an immediate variable to evaluate `MAKEFILE_LIST` now
USEMODULE_INCLUDES_reactor-uc := $(LAST_MAKEFILEDIR)/../../../../include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_reactor-uc)
3 changes: 3 additions & 0 deletions make/riot/external_modules/reactor-uc/reactor-uc.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = reactor-uc

include $(RIOTBASE)/Makefile.base
23 changes: 23 additions & 0 deletions make/riot/riot.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
RIOT_MK_DIR := $(dir $(lastword $(MAKEFILE_LIST)))

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(RIOT_MK_DIR)/../../../RIOT

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

# Use a peripheral timer for the delay, if available
FEATURES_OPTIONAL += periph_timer

# External modules
EXTERNAL_MODULE_DIRS += $(RIOT_MK_DIR)/external_modules
USEMODULE += reactor-uc



include $(RIOTBASE)/Makefile.include
11 changes: 11 additions & 0 deletions src/platform/posix/tcp_ip_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,21 @@ void TcpIpChannel_register_callback(NetworkChannel *untyped_self,
if (pthread_attr_init(&self->receive_thread_attr) < 0) {
throw("pthread_attr_init failed");
}
/* TODO: RIOT posix-wrappers don't have pthread_attr_setstack yet */
#ifdef __USE_XOPEN2K
if (pthread_attr_setstack(&self->receive_thread_attr, &self->receive_thread_stack,
TCP_IP_CHANNEL_RECV_THREAD_STACK_SIZE - TCP_IP_CHANNEL_RECV_THREAD_STACK_GUARD_SIZE) < 0) {
throw("pthread_attr_setstack failed");
}
#else
if (pthread_attr_setstackaddr(&self->receive_thread_attr, self->receive_thread_stack) != 0) {
throw("pthread_attr_setstackaddr failed");
}
if (pthread_attr_setstacksize(&self->receive_thread_attr, TCP_IP_CHANNEL_RECV_THREAD_STACK_SIZE -
TCP_IP_CHANNEL_RECV_THREAD_STACK_GUARD_SIZE) != 0) {
throw("pthread_attr_setstacksize failed");
}
#endif
res = pthread_create(&self->receive_thread, &self->receive_thread_attr, TcpIpChannel_receive_thread, self);
if (res < 0) {
throw("pthread_create failed");
Expand Down

0 comments on commit 0db8386

Please sign in to comment.