Skip to content

Commit

Permalink
Support for CAN via FMIMCL and FMI2 Strings.
Browse files Browse the repository at this point in the history
Signed-off-by: Timothy Rule (VM/EMT3) <[email protected]>
  • Loading branch information
timrulebosch committed Nov 11, 2024
1 parent 3aad17e commit d5617c2
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 36 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,16 @@ endif
test_e2e: do-test_testscript-e2e

do-test_testscript-e2e:
# Test debug; add '-v' to Testscript command (e.g. $(TESTSCRIPT_IMAGE) -v \).
# Test debug;
# Additional logging: add '-v' to Testscript command (e.g. $(TESTSCRIPT_IMAGE) -v \).
# Retain work folder: add '-work' to Testscript command (e.g. $(TESTSCRIPT_IMAGE) -work \).
ifeq ($(PACKAGE_ARCH), linux-amd64)
@-docker kill simer
@set -eu; for t in $(TESTSCRIPT_E2E_FILES) ;\
do \
echo "Running E2E Test: $$t" ;\
export ENTRYWORKDIR=$$(mktemp -d) ;\
echo "ENTRYWORKDIR: $${ENTRYWORKDIR}" ;\
docker run -i --rm \
-e ENTRYHOSTDIR=$(HOST_DOCKER_WORKSPACE) \
-e ENTRYWORKDIR=$${ENTRYWORKDIR} \
Expand Down
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,20 @@ $ export FMI_TAG=test
# Clear out previous Testscript artefacts.
$ sudo rm -rf /tmp/tmp.*

# Run testscript with -work option (see Makefile target "do-test_testscript-e2e").
# Run testscript with '-work' option (see Makefile target "do-test_testscript-e2e").
# Locate the "ENTRYWORKDIR" in the output for subsequent commands.
$ make test_e2e
$ ls /tmp/tmp.fM6mudCech
$ sudo mv /tmp/tmp.fM6mudCech/sim test_sim
$ make test_e2e
make: [Makefile:137: do-test_testscript-e2e] Error 1 (ignored)
Running E2E Test: tests/testscript/e2e/fmimcl_fmu2.txtar
ENTRYWORKDIR: /tmp/tmp.o37sWJbxKe
...
$ ls /tmp/tmp.o37sWJbxKe
$ sudo mv /tmp/tmp.o37sWJbxKe/sim test_sim

# Run Simer with GDB to debug a crashing FMIMCL.
$ cd test_sim
$ docker run --name simer -it --rm \
$ docker run --name simer -it --rm
-v $(pwd):/sim
ghcr.io/boschglobal/dse-simer:latest
-tmux
Expand All @@ -239,7 +245,11 @@ $ docker run --name simer -it --rm \
-stepsize 0.0005
-endtime 0.0010

# Tmux commands: Ctrl-b <n> (change window), Ctrl-b d (exit Tmux).
# Tmux commands:
# Ctrl-b <n> (change window)
# Ctrl-b d (exit Tmux)
# Ctrl+b [ (copy mode, VI movements)
# Ctrl+b PgUp (copy mode with scroll, VI movements)
```


Expand Down
Binary file modified doc/static/ki_fmigateway.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/static/ki_fmimcl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/static/ki_fmimodelc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions dse/fmimcl/examples/input/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(MODEL_PATH "${MODULE_LC}/examples")

add_library(input SHARED
model.c
../../../fmimodelc/ascii85.c
)
target_include_directories(input
PRIVATE
Expand Down
76 changes: 46 additions & 30 deletions dse/fmimcl/examples/input/model.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include <dse/logger.h>


extern char* ascii85_encode(const char* source, size_t source_len);
extern char* ascii85_decode(const char* source, size_t* len);


typedef struct {
SignalVector* sv;
uint32_t index;
Expand Down Expand Up @@ -88,57 +92,69 @@ ModelDesc* model_create(ModelDesc* model)
}


static inline int _format_message(
BinarySignalDesc* b, const char* prefix, int v)
static inline void _write_message(
BinarySignalDesc* b, const char* prefix, int v, bool encoded)
{
char buffer[50];
snprintf(buffer, sizeof(buffer), "%s %d", prefix, v);
if (encoded) {
char* msg = ascii85_encode(buffer, strlen(buffer));
signal_append(b->sv, b->index, (uint8_t*)msg, strlen(msg) + 1);
free(msg);
} else {
signal_append(b->sv, b->index, (uint8_t*)buffer, strlen(buffer) + 1);
}
}


static inline void _log_message(BinarySignalDesc* b, bool encoded)
{
return snprintf((char*)b->buffer, b->buffer_size, "%s %d", prefix, v);
uint8_t* buffer;
size_t len;

signal_read(b->sv, b->index, &buffer, &len);
if (len) {
if (encoded) {
char* msg = ascii85_decode((char*)buffer, &len);
log_info("String (%s) : %s", b->sv->signal[b->index], msg);
free(msg);
} else {
log_info("String (%s) : %s", b->sv->signal[b->index], buffer);
}
}
}


int model_step(ModelDesc* model, double* model_time, double stop_time)
{
ExtendedModelDesc* m = (ExtendedModelDesc*)model;

/* Print incomming strings. */
uint8_t* buffer;
size_t len;
signal_read(
m->binary.string_tx.sv, m->binary.string_tx.index, &buffer, &len);
if (len)
log_info("String (%s) : %s",
m->binary.string_tx.sv->signal[m->binary.string_tx.index], buffer);
signal_read(
m->binary.string_rx.sv, m->binary.string_rx.index, &buffer, &len);
if (len)
log_info("String (%s) : %s",
m->binary.string_rx.sv->signal[m->binary.string_rx.index], buffer);
_log_message(&(m->binary.string_tx), false);
_log_message(&(m->binary.string_rx), false);
_log_message(&(m->binary.string_ascii85_tx), true);
_log_message(&(m->binary.string_ascii85_rx), true);

/* Increment signals. */
*(m->signals.real_3_rx) = *(m->signals.real_3_rx) + 1;
*(m->signals.integer_3_rx) = *(m->signals.integer_3_rx) + 2;
*(m->signals.real_A_rx) = *(m->signals.real_A_rx) + 3;

/* Generate strings. */
len = _format_message(
&(m->binary.string_tx), "foo", (int)*(m->signals.real_3_rx));
if (len >= (m->binary.string_tx.buffer_size - 1)) {
m->binary.string_tx.buffer =
realloc(m->binary.string_tx.buffer, len + 1);
m->binary.string_tx.buffer_size = len + 1;
_format_message(
&(m->binary.string_tx), "foo", (int)*(m->signals.real_3_rx));
}
/* Reset binary signals. */
signal_reset(m->binary.string_tx.sv, m->binary.string_tx.index);
signal_append(m->binary.string_tx.sv, m->binary.string_tx.index,
m->binary.string_tx.buffer,
strlen((char*)m->binary.string_tx.buffer) + 1);


signal_reset(m->binary.string_rx.sv, m->binary.string_rx.index);
signal_reset(
m->binary.string_ascii85_tx.sv, m->binary.string_ascii85_tx.index);
signal_reset(
m->binary.string_ascii85_rx.sv, m->binary.string_ascii85_rx.index);

/* Generate strings. */
_write_message(
&(m->binary.string_tx), "foo", (int)*(m->signals.real_3_rx), false);
_write_message(&(m->binary.string_ascii85_tx), "bar",
(int)*(m->signals.real_A_rx), true);

/* Complete the step. */
*model_time = stop_time;
return 0;
}
220 changes: 220 additions & 0 deletions tests/testscript/e2e/fmimcl_fmu2.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# Operate from the WORKDIR (allocated by caller, i.e. docker command).
cd $WORKDIR
env SIM=sim
env NAME=fmu_inst
env SIM_YAML=$REPODIR/dse/build/_out/fmimcl/examples/data/simulation.yaml
env FMU=$REPODIR/dse/build/_out/fmimcl/examples/fmu
env MCL=$REPODIR/dse/build/_out/fmimcl/lib/libfmimcl.so


# Create the simulation folder (Simer layout)
exec ls -R $WORK
mkdir $SIM/data $SIM/lib
cp $WORK/simulation.yaml $SIM/data/simulation.yaml
cp $MCL $SIM/lib/libfmimcl.so

mkdir $SIM/fmu
exec cp -r $FMU $SIM/fmu/fmi2fmu
mkdir $SIM/fmu/fmi2fmu/resources

mkdir $SIM/model/input/data $SIM/model/input/lib
cp $WORK/input_model.yaml $SIM/model/input/data/model.yaml
cp $REPODIR/dse/build/_out/fmimcl/examples/lib/libinput.so $SIM/model/input/lib/libinput.so


# Run the toolchains
env
exec ls -R $SIM
exec sh -e $WORK/generate.sh

exists $SIM/model/fmi2fmu/data/model.yaml
exists $SIM/model/fmi2fmu/data/signalgroup.yaml


exec cat $SIM/data/simulation.yaml
exec cat $SIM/model/input/data/model.yaml
exec cat $SIM/model/fmi2fmu/data/model.yaml
exec cat $SIM/model/fmi2fmu/data/signalgroup.yaml


# TEST: FMI MCL with CoSim FMU using FMIv2
exec sh -e $WORK/test.sh

stdout 'Load YAML File: data/simulation.yaml'
stdout 'Load YAML File: model/fmi2fmu/data/model.yaml'
stdout 'Load YAML File: model/fmi2fmu/data/signalgroup.yaml'
stdout 'Loading symbol: model_create ... ok'
stdout 'Loading symbol: model_step ... ok'
stdout 'Run the Simulation ...'
stdout 'Controller exit ...'
stdout 'Transport: redis'
! stdout 'Transport: redispubsub'

stdout 'SignalVector <-> MCL mapping for: signal'
stdout 'Signal: integer_2_tx \(3\) <-> integer_2_tx \(0\)'
stdout 'Signal: integer_1_tx \(4\) <-> integer_1_tx \(1\)'
stdout 'Signal: integer_3_rx \(2\) <-> integer_3_rx \(2\)'
stdout 'Signal: real_1_tx \(1\) <-> real_1_tx \(4\)'
stdout 'Signal: real_A_tx \(10\) <-> real_A_tx \(5\)'
stdout 'Signal: real_B_tx \(11\) <-> real_B_tx \(6\)'
stdout 'Signal: real_3_rx \(0\) <-> real_3_rx \(7\)'
stdout 'Signal: real_2_rx \(5\) <-> real_2_rx \(8\)'
stdout 'Signal: real_A_rx \(8\) <-> real_A_rx \(9\)'
stdout 'Signal: real_B_rx \(9\) <-> real_B_rx \(10\)'
stdout 'Signal: bool_2_tx \(7\) <-> bool_2_tx \(11\)'
stdout 'Signal: bool_1_rx \(6\) <-> bool_1_rx \(12\)'

stdout 'SignalVector <-> MCL mapping for: network'
stdout 'Signal: string_rx \(1\) <-> integer_2_tx \(0\)'
stdout 'Signal: string_ascii85_rx \(3\) <-> integer_1_tx \(1\)'
stdout 'Signal: string_tx \(0\) <-> integer_3_rx \(2\)'
stdout 'Signal: string_ascii85_tx \(2\) <-> local_var \(3\)'

stdout 'uid=4130119698, val=54.000000, final_val=54.000000, name=real_1_tx'
stdout 'uid=2274494661, val=99.000000, final_val=99.000000, name=integer_2_tx'
stdout 'uid=2618602618, val=10.000000, final_val=10.000000, name=real_3_rx'
stdout 'uid=1459318059, val=0.000000, final_val=0.000000, name=real_2_rx'
stdout 'uid=490176922, val=9.000000, final_val=9.000000, name=integer_1_tx'
stdout 'uid=1343595106, val=20.000000, final_val=20.000000, name=integer_3_rx'
stdout 'uid=1955499220, val=0.000000, final_val=0.000000, name=bool_1_rx'
stdout 'uid=3382072605, val=0.000000, final_val=0.000000, name=bool_2_tx'
stdout 'uid=3194481060, val=30.000000, final_val=30.000000, name=real_A_rx'
stdout 'uid=3261297346, val=37.000000, final_val=37.000000, name=real_A_tx'
stdout 'uid=750647789, val=100.000000, final_val=100.000000, name=real_B_tx'
! stdout 'name=local_var'

stdout 'uid=750647789, val=100.000000, final_val=100.000000, name=real_B_tx'

stdout 'String \(string_tx\) : foo 2'
stdout 'String \(string_tx\) : foo 3'
stdout 'String \(string_tx\) : foo 4'
stdout 'String \(string_tx\) : foo 5'
stdout 'String \(string_rx\) : foo 2'
stdout 'String \(string_rx\) : foo 3'
stdout 'String \(string_rx\) : foo 4'

stdout 'String \(string_ascii85_tx\) : bar 6'
stdout 'String \(string_ascii85_tx\) : bar 9'
stdout 'String \(string_ascii85_rx\) : 6 rab'
stdout 'String \(string_ascii85_tx\) : bar 12'
stdout 'String \(string_ascii85_rx\) : 9 rab'
stdout 'String \(string_ascii85_tx\) : bar 15'
stdout 'String \(string_ascii85_rx\) : 21 rab'


-- generate.sh --
# All paths relative to $SIM (triggered by setting $SIM). See Taskfile for details.
task -t /$REPODIR/Taskfile.yml generate-fmimcl \
FMU_DIR=fmu/fmi2fmu \
MCL_PATH=lib/libfmimcl.so \
OUT_DIR=model/fmi2fmu/data

-- test.sh --
SIMER="${SIMER:-ghcr.io/boschglobal/dse-simer:latest}"
docker run --name simer -i --rm -v $ENTRYWORKDIR/$SIM:/sim \
$SIMER -valgrind $NAME \
-env simbus:SIMBUS_LOGLEVEL=2 \
-env input_inst:SIMBUS_LOGLEVEL=3 \
-env $NAME:SIMBUS_LOGLEVEL=4 \
-stepsize 0.0005 -endtime 0.0050

-- input_model.yaml --
---
kind: Model
metadata:
name: Input
spec:
runtime:
dynlib:
- os: linux
arch: amd64
path: model/input/lib/libinput.so
channels:
- alias: input_channel
selectors:
channel: input_vector
- alias: binary_channel
selectors:
channel: binary_vector
---
kind: SignalGroup
metadata:
name: VARIABLES
labels:
model: Input
channel: input_vector
spec:
signals:
- signal: real_3_rx
- signal: integer_3_rx
- signal: real_A_rx
---
kind: SignalGroup
metadata:
name: STRINGS
labels:
model: Input
channel: binary_vector
annotations:
vector_type: binary
spec:
signals:
- signal: string_tx
- signal: string_rx
- signal: string_ascii85_tx
- signal: string_ascii85_rx

-- simulation.yaml --
---
kind: Stack
metadata:
name: stack
spec:
runtime:
env:
SIMBUS_LOGLEVEL: 2
connection:
transport:
redis:
uri: redis://localhost:6379
timeout: 5
models:
- name: simbus
model:
name: simbus
channels:
- name: signal
expectedModelCount: 2
- name: network
expectedModelCount: 2
- name: fmu_inst
uid: 42
model:
name: fmi2fmu
runtime:
files:
- model/fmi2fmu/data/signalgroup.yaml
channels:
- name: signal
alias: signal_channel
selectors:
model: fmi2fmu
channel: signal_vector
- name: network
alias: network_channel
selectors:
model: fmi2fmu
channel: network_vector
- name: input_inst
uid: 21
model:
name: Input
channels:
- name: signal
alias: input_channel
- name: network
alias: binary_channel
---
kind: Model
metadata:
name: simbus

0 comments on commit d5617c2

Please sign in to comment.