Skip to content

Commit

Permalink
LFC federated RIOT fixes (#192)
Browse files Browse the repository at this point in the history
* Have LFC generate a main function that can optionally be included in the build

* CI

* CI

* CI

* Setup LFC in RIOT container

* Switch to riot master

* Fix

* Install LFC deps in zephyr CI also

* WIP

* WIP

* WIP: SimpleFederated.lf now compiles.
But invoking CMake correctly to generate two binaries and a shell script in `bin` is not working

* Generate a launch script for federated native

* Make federated launch script executable

* WIP

* Rework the handling of connections

* Various fixes to get all standalone tests to pass again

* Formatting

* More WIP

* Formatting

* More WIP

* Add @interface attr

* More WIP

* More WIP

* More WIP

* All tests are passing

* Refactor

* Formatting

* Refactorings

* More docs

* CI

* Fixes

* TcpIp fixes

* Revert more tcp stuff

* Avoid flooding log when a federate closes a socket

* Remove merge mistake

* Formatting

* Fix posix federated

* More minor fixes

* Format

* Minimum event queue of 2

* Remove some dead code

* Also close send_failed socketpair on reset

* Generate return 0 in main function

* Only generate launch script when we target native

* Set timeout of 1minute on our LF tests

* Add some info prints

* Add was_ever_connected API to network_channel

* Fix some warnings in unit-tests

* Avoid some unnecessary LF_INFO calls

* Do not timestamp logs for FlexPRET

* Format

* Make RIOT compile

* Fix makefile and missing comma

* Remove build.sh in riot Lf example

* Use global _lf_environment

* Fix missing _lf_environment in test

* Dont need environment arg to TcpIp and CoapUdp ctors

* Coap updates

* Remove stale ref

* Fix APPLICATION name

* Fix make clean

* Add all riot examples to the CI again

* Fix hello_lf example make clean command not working

* Rename FEDERATION -> FEDERATE

* Make build scripts more realistic

---------

Co-authored-by: erlingrj <[email protected]>
  • Loading branch information
LasseRosenow and erlingrj authored Jan 22, 2025
1 parent c592b89 commit 5144e03
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 40 deletions.
2 changes: 2 additions & 0 deletions examples/riot/blinky/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
make all
26 changes: 8 additions & 18 deletions examples/riot/buildAll.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,12 @@

set -e

# List of folders
FOLDERS=("blinky" "hello" "hello_lf")

# List of boards
BOARDS=("native" "nucleo-f429zi")

# Iterate over each board
for board in "${BOARDS[@]}"; do
# Command to execute in each folder
COMMAND="make BOARD=$board all"

# Iterate over each folder and execute the command
for dir in "${FOLDERS[@]}"; do
echo "Entering $dir"
pushd $dir
$COMMAND
popd
done
# Iterate over each folder and execute the command
for dir in ./*; do
if [ -d $dir ]; then
echo "Entering $dir"
pushd $dir
./build.sh
popd
fi
done
3 changes: 3 additions & 0 deletions examples/riot/coap_federated/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
REMOTE_ADDRESS=fe80::8cc3:33ff:febb:1b3 make all -C ./sender
REMOTE_ADDRESS=fe80::44e5:1bff:fee4:dac8 make all -C ./receiver
35 changes: 35 additions & 0 deletions examples/riot/coap_federated_lf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
REACTOR_UC_PATH ?= $(CURDIR)/../../../

# The name of the LF application inside "./src" to build/run/flash etc.
LF_MAIN ?= CoapFederatedLF
FEDERATE ?= r1

# Execute the LF compiler if build target is "all"
ifeq ($(firstword $(MAKECMDGOALS)),all)
_ := $(shell $(REACTOR_UC_PATH)/lfc/bin/lfc-dev src/$(LF_MAIN).lf)
endif

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

# 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_CHANNEL_COAP_RIOT

# Configure CoAP retransmission timeout
CFLAGS += -DCONFIG_GCOAP_NO_RETRANS_BACKOFF=1
CFLAGS += -DCONFIG_COAP_ACK_TIMEOUT_MS=400
CFLAGS += -DCONFIG_COAP_MAX_RETRANSMIT=4

include $(REACTOR_UC_PATH)/make/riot/riot-lfc.mk
3 changes: 3 additions & 0 deletions examples/riot/coap_federated_lf/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
FEDERATE=r1 PORT=tap0 make all
FEDERATE=r2 PORT=tap1 make all
41 changes: 41 additions & 0 deletions examples/riot/coap_federated_lf/src/CoapFederatedLF.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
target uC {
platform: RIOT,
timeout: 1sec
}

reactor Src(id: int = 0) {
output out: int
reaction(startup) -> out{=
printf("Hello from Src!\n");
lf_set(out, self->id);
=}
}

reactor Dst {
input in: int
state check: bool = false
reaction(startup) {=
printf("Hello from Dst!\n");
=}
reaction(in) {=
printf("Received %d from Src\n", in->value);
validate(in->value == 42);
self->check = true;
env->request_shutdown(env);
=}

reaction(shutdown) {=
validate(self->check);
=}
}

federated reactor {
@interface_coap(name="if1", address="fe80::44e5:1bff:fee4:dac8")
r1 = new Src(id=42)

@interface_coap(name="if1", address="fe80::8cc3:33ff:febb:1b3")
r2 = new Dst()

@link(left="if1", right="if1")
r1.out -> r2.in
}
2 changes: 2 additions & 0 deletions examples/riot/hello/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
make all
2 changes: 1 addition & 1 deletion examples/riot/hello_lf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ LF_MAIN ?= HelloLF
# CFLAGS += -DNETWORK_CHANNEL_COAP_RIOT

# Execute the LF compiler if build target is "all"
ifeq ($(MAKECMDGOALS),all)
ifeq ($(firstword $(MAKECMDGOALS)),all)
_ := $(shell $(REACTOR_UC_PATH)/lfc/bin/lfc-dev src/$(LF_MAIN).lf)
endif

Expand Down
2 changes: 2 additions & 0 deletions examples/riot/hello_lf/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
make all
21 changes: 14 additions & 7 deletions lfc/core/src/main/kotlin/org/lflang/generator/uc/UcIpAddress.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import org.lflang.AttributeUtils.getInterfaceAttributes
import org.lflang.lf.Attribute
import java.math.BigInteger
import java.util.concurrent.atomic.AtomicInteger
import java.net.InetAddress
import java.net.UnknownHostException


/** A class representing an IPAddress, either v4 or v6. */
Expand All @@ -22,10 +24,12 @@ sealed class IPAddress {
}

companion object {
fun isValidIPv4(address: String): Boolean {
val regex = Regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}$")
return regex.matches(address) &&
address.split(".").all { it.toIntOrNull() in 0..255 }
fun isValidIPv4(ip: String): Boolean {
return try {
InetAddress.getByName(ip) is java.net.Inet4Address
} catch (e: UnknownHostException) {
false
}
}
}
}
Expand All @@ -36,9 +40,12 @@ sealed class IPAddress {
}

companion object {
fun isValidIPv6(address: String): Boolean {
val regex = Regex("(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4})|(::)")
return regex.matches(address)
fun isValidIPv6(ip: String): Boolean {
return try {
InetAddress.getByName(ip) is java.net.Inet6Address
} catch (e: UnknownHostException) {
false
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ abstract class UcNetworkChannel(
COAP_UDP_IP -> {
val srcEp = (srcIf as UcCoapUdpIpInterface).createEndpoint()
val destEp = (destIf as UcCoapUdpIpInterface).createEndpoint()
channel = UcCoapUdpIpChannel(srcEp, destEp, serverLhs)
channel = UcCoapUdpIpChannel(srcEp, destEp)
}

CUSTOM -> {
Expand Down Expand Up @@ -242,17 +242,24 @@ class UcTcpIpChannel(
class UcCoapUdpIpChannel(
src: UcCoapUdpIpEndpoint,
dest: UcCoapUdpIpEndpoint,
serverLhs: Boolean = true,
) : UcNetworkChannel(COAP_UDP_IP, src, dest, serverLhs) {
private val srcAddr = src.ipAddress.address
private val destAddr = dest.ipAddress.address
// TODO: In CoAP every node is a server and a client => default server to false for now
) : UcNetworkChannel(COAP_UDP_IP, src, dest, false) {
private val srcAddr = src
private val destAddr = dest

private fun getIpProtocolFamily(ip: IPAddress): String {
return when (ip) {
is IPAddress.IPv4 -> "AF_INET"
is IPAddress.IPv6 -> "AF_INET6"
else -> throw IllegalArgumentException("Unknown IP address type")
}
}

override fun generateChannelCtorSrc() =
"CoapUdpIpChannel_ctor(&self->channel, \"${if (serverLhs) srcAddr else destAddr}\", AF_INET, ${serverLhs});"
"CoapUdpIpChannel_ctor(&self->channel, \"${destAddr.ipAddress.address}\", ${getIpProtocolFamily(destAddr.ipAddress)});"

override fun generateChannelCtorDest() =
"CoapUdpIpChannel_ctor(&self->channel, \"${if (serverLhs) srcAddr else destAddr}\" AF_INET, ${!serverLhs});"

"CoapUdpIpChannel_ctor(&self->channel, \"${srcAddr.ipAddress.address}\", ${getIpProtocolFamily(srcAddr.ipAddress)});"

override val codeType: String
get() = "CoapUdpIpChannel"
Expand Down
28 changes: 22 additions & 6 deletions make/riot/riot-lfc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,32 @@ ifndef LF_MAIN
$(error LF_MAIN is not defined. Please define it!)
endif

# Name of your RIOT application
APPLICATION ?= $(LF_MAIN)
ifndef RIOTBASE
$(error RIOTBASE is not defined. Please define it!)
endif

# Check if this is a federated program
ifdef FEDERATE
# Name of your RIOT application
APPLICATION ?= $(LF_MAIN)-$(FEDERATE)

# Path of generated lf c-code
LF_SRC_GEN_PATH ?= $(CURDIR)/src-gen/$(LF_MAIN)
# Path of generated lf c-code
LF_SRC_GEN_PATH ?= $(CURDIR)/src-gen/$(LF_MAIN)/$(FEDERATE)
else
# Name of your RIOT application
APPLICATION ?= $(LF_MAIN)

# Path of generated lf c-code
LF_SRC_GEN_PATH ?= $(CURDIR)/src-gen/$(LF_MAIN)
endif

# Only include generated files if build target is not "clean"
# In this case the src-gen folder was deleted
ifeq ($(MAKECMDGOALS),clean)
ifeq ($(firstword $(MAKECMDGOALS)),clean)
# Delete src-gen folder if build target is "clean"
_ := $(shell rm -rf $(LF_SRC_GEN_PATH))

include $(RIOTBASE)/Makefile.include
else
# Include the Makefile of the generated target application
include $(LF_SRC_GEN_PATH)/Makefile
Expand All @@ -28,6 +43,7 @@ else

# Include generated h files
CFLAGS += -I$(LF_SRC_GEN_PATH)

include $(RIOT_MK_DIR)/riot.mk
endif

include $(RIOT_MK_DIR)/riot.mk

0 comments on commit 5144e03

Please sign in to comment.