From 06519f2a4c9d8a9f4aab8c7e81b967938d68c6cf Mon Sep 17 00:00:00 2001 From: Rule Timothy Date: Fri, 26 Jan 2024 09:02:15 +0100 Subject: [PATCH] New model API. Signed-off-by: Rule Timothy (VM/EMT3) --- Makefile | 2 +- doc/Makefile | 13 +- doc/content/apis/modelc/examples/gateway.c | 1 + .../apis/modelc/examples/model_create.c | 44 ++ .../apis/modelc/examples/model_interface.c | 47 +- .../apis/modelc/examples/model_sv_create.c | 13 - .../modelc/examples/signalvector_annotation.c | 15 + ...ignalvector.c => signalvector_interface.c} | 12 +- .../apis/modelc/examples/simmock_configure.c | 4 +- .../modelc/examples/simmock_frame_check.c | 2 +- .../modelc/examples/simmock_signal_check.c | 2 +- doc/content/apis/modelc/mcl/index.md | 2 +- doc/content/apis/modelc/model/index.md | 469 +++++++++++------- .../apis/modelc/model/model-interface.png | Bin 12112 -> 11648 bytes .../apis/modelc/model/model-signal-vector.png | Bin 19464 -> 0 bytes doc/content/apis/modelc/runtime/index.md | 127 +++++ doc/content/apis/modelc/simmock/index.md | 73 ++- dse/mocks/simmock.c | 234 +++++++-- dse/mocks/simmock.h | 18 +- dse/modelc/CMakeLists.txt | 1 + dse/modelc/controller/controller.c | 17 +- dse/modelc/controller/controller.h | 20 +- dse/modelc/controller/loader.c | 60 +-- dse/modelc/controller/modelc.c | 146 +++++- dse/modelc/controller/modelc_args.c | 4 +- dse/modelc/controller/modelc_debug.c | 2 +- dse/modelc/controller/step.c | 3 +- dse/modelc/examples/CMakeLists.txt | 10 +- dse/modelc/examples/apis/CMakeLists.txt | 5 +- dse/modelc/examples/apis/model_create.c | 44 ++ dse/modelc/examples/apis/model_interface.c | 47 +- dse/modelc/examples/apis/model_sv_create.c | 13 - .../examples/apis/signalvector_annotation.c | 15 + ...ignalvector.c => signalvector_interface.c} | 12 +- dse/modelc/examples/apis/simmock_configure.c | 2 +- dse/modelc/examples/binary/CMakeLists.txt | 58 +-- dse/modelc/examples/binary/binary_model.c | 116 ----- dse/modelc/examples/binary/model.c | 106 ++++ dse/modelc/examples/binary/model.yaml | 21 +- dse/modelc/examples/binary/signal_group.yaml | 19 - dse/modelc/examples/binary/simulation.yaml | 58 +++ dse/modelc/examples/binary/stack.yaml | 39 -- dse/modelc/examples/dynamic/CMakeLists.txt | 79 --- dse/modelc/examples/dynamic/README.md | 36 -- dse/modelc/examples/dynamic/dynamic_model.c | 86 ---- dse/modelc/examples/dynamic/signal_group.yaml | 15 - dse/modelc/examples/extended/CMakeLists.txt | 45 ++ dse/modelc/examples/extended/model.c | 61 +++ .../examples/{dynamic => extended}/model.yaml | 16 +- dse/modelc/examples/extended/simulation.yaml | 43 ++ dse/modelc/examples/gateway/gateway.c | 1 + dse/modelc/examples/minimal/CMakeLists.txt | 35 ++ dse/modelc/examples/minimal/model.c | 16 + dse/modelc/examples/minimal/model.yaml | 27 + .../stack.yaml => minimal/simulation.yaml} | 23 +- dse/modelc/examples/stacked/CMakeLists.txt | 102 ---- dse/modelc/examples/stacked/README.md | 7 - dse/modelc/examples/stacked/model.yaml | 50 -- dse/modelc/examples/stacked/signal_group.yaml | 15 - dse/modelc/examples/stacked/stack.yaml | 39 -- dse/modelc/examples/stacked/stacked_model.c | 69 --- dse/modelc/mcl.h | 10 +- dse/modelc/model.h | 370 ++++++-------- dse/modelc/model/gateway.c | 71 +-- dse/modelc/model/model.c | 382 +++++++------- dse/modelc/model/signal.c | 197 +++++++- dse/modelc/runtime.h | 150 ++++++ dse/modelc/schema.h | 2 +- dse/modelc/tools/mcl_model/model.c | 167 +++---- dse/modelc/tools/modelc/modelc.c | 2 +- dse/modelc/tools/mstep/mstep.c | 46 +- dse/modelc/tools/simbus/simbus.c | 2 +- tests/cmocka/CMakeLists.txt | 44 +- tests/cmocka/Makefile | 1 + tests/cmocka/model/interface/__test__.c | 17 + .../model/interface/test_model_interface.c | 204 ++++++++ tests/cmocka/model/stub_controller.c | 14 +- tests/cmocka/model/test_ncodec.c | 40 +- tests/cmocka/model/test_signal.c | 50 +- tests/pytest/modelc/test_modelc.py | 17 +- tests/pytest/modelc/test_mstep.py | 19 +- tests/pytest/modelc/test_stacked_modelc.py | 1 + 82 files changed, 2569 insertions(+), 1898 deletions(-) create mode 100644 doc/content/apis/modelc/examples/model_create.c delete mode 100644 doc/content/apis/modelc/examples/model_sv_create.c create mode 100644 doc/content/apis/modelc/examples/signalvector_annotation.c rename doc/content/apis/modelc/examples/{model_signalvector.c => signalvector_interface.c} (84%) delete mode 100644 doc/content/apis/modelc/model/model-signal-vector.png create mode 100644 doc/content/apis/modelc/runtime/index.md create mode 100644 dse/modelc/examples/apis/model_create.c delete mode 100644 dse/modelc/examples/apis/model_sv_create.c create mode 100644 dse/modelc/examples/apis/signalvector_annotation.c rename dse/modelc/examples/apis/{model_signalvector.c => signalvector_interface.c} (84%) delete mode 100644 dse/modelc/examples/binary/binary_model.c create mode 100644 dse/modelc/examples/binary/model.c delete mode 100644 dse/modelc/examples/binary/signal_group.yaml create mode 100644 dse/modelc/examples/binary/simulation.yaml delete mode 100644 dse/modelc/examples/binary/stack.yaml delete mode 100644 dse/modelc/examples/dynamic/CMakeLists.txt delete mode 100644 dse/modelc/examples/dynamic/README.md delete mode 100644 dse/modelc/examples/dynamic/dynamic_model.c delete mode 100644 dse/modelc/examples/dynamic/signal_group.yaml create mode 100644 dse/modelc/examples/extended/CMakeLists.txt create mode 100644 dse/modelc/examples/extended/model.c rename dse/modelc/examples/{dynamic => extended}/model.yaml (52%) create mode 100644 dse/modelc/examples/extended/simulation.yaml create mode 100644 dse/modelc/examples/minimal/CMakeLists.txt create mode 100644 dse/modelc/examples/minimal/model.c create mode 100644 dse/modelc/examples/minimal/model.yaml rename dse/modelc/examples/{dynamic/stack.yaml => minimal/simulation.yaml} (55%) delete mode 100644 dse/modelc/examples/stacked/CMakeLists.txt delete mode 100644 dse/modelc/examples/stacked/README.md delete mode 100644 dse/modelc/examples/stacked/model.yaml delete mode 100644 dse/modelc/examples/stacked/signal_group.yaml delete mode 100644 dse/modelc/examples/stacked/stack.yaml delete mode 100644 dse/modelc/examples/stacked/stacked_model.c create mode 100644 dse/modelc/runtime.h create mode 100644 tests/cmocka/model/interface/__test__.c create mode 100644 tests/cmocka/model/interface/test_model_interface.c diff --git a/Makefile b/Makefile index a5526e1..72f4fb8 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ export DSE_SCHEMA_URL ?= $(DSE_SCHEMA_REPO)/releases/download/v$(DSE_SCHEMA_VERS ############### ## DSE C Library. DSE_CLIB_REPO ?= https://github.com/boschglobal/dse.clib -DSE_CLIB_VERSION ?= 1.0.7 +DSE_CLIB_VERSION ?= 1.0.8 export DSE_CLIB_URL ?= $(DSE_CLIB_REPO)/archive/refs/tags/v$(DSE_CLIB_VERSION).zip diff --git a/doc/Makefile b/doc/Makefile index a4bca91..29e4b56 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -45,6 +45,13 @@ DOC_OUTPUT_model := doc/content/apis/modelc/model/index.md DOC_LINKTITLE_model := Model DOC_TITLE_model := "Model API Reference" +# Module "runtime" +DOC_INPUT_runtime := dse/modelc/runtime.h +DOC_CDIR_runtime := dse/modelc/controller/modelc.c,dse/modelc/controller/modelc_args.c,dse/modelc/controller/modelc_debug.c, +DOC_OUTPUT_runtime := doc/content/apis/modelc/runtime/index.md +DOC_LINKTITLE_runtime := Runtime +DOC_TITLE_runtime := "Runtime API Reference" + # Module "schema" DOC_INPUT_schema := dse/modelc/schema.h DOC_CDIR_schema := dse/modelc/model/schema.c @@ -53,15 +60,15 @@ DOC_LINKTITLE_schema := Schema DOC_TITLE_schema := "Schema API Reference" # Module "simmock" -DOC_INPUT_simmock := dse/modelc/mocks/simmock.h -DOC_CDIR_simmock := dse/modelc/mocks/simmock.c +DOC_INPUT_simmock := dse/mocks/simmock.h +DOC_CDIR_simmock := dse/mocks/simmock.c DOC_OUTPUT_simmock := doc/content/apis/modelc/simmock/index.md DOC_LINKTITLE_simmock := SimMock DOC_TITLE_simmock := "SimMock API Reference" # Targets -DOC_C_MODULES := gateway mcl model schema simmock +DOC_C_MODULES := gateway mcl model runtime schema simmock #DOC_C_MODULES := model .PHONY: examples diff --git a/doc/content/apis/modelc/examples/gateway.c b/doc/content/apis/modelc/examples/gateway.c index 61b6e16..f081151 100644 --- a/doc/content/apis/modelc/examples/gateway.c +++ b/doc/content/apis/modelc/examples/gateway.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include #include diff --git a/doc/content/apis/modelc/examples/model_create.c b/doc/content/apis/modelc/examples/model_create.c new file mode 100644 index 0000000..715e53c --- /dev/null +++ b/doc/content/apis/modelc/examples/model_create.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef struct { + ModelDesc model; + /* Signal Pointers. */ + struct { + double* counter; + } signals; +} ExtendedModelDesc; + +static inline double* _index(ExtendedModelDesc* m, const char* v, const char* s) +{ + ModelSignalIndex idx = m->model.index((ModelDesc*)m, v, s); + if (idx.scalar == NULL) log_fatal("Signal not found (%s:%s)", v, s); + return idx.scalar; +} + +ModelDesc* model_create(ModelDesc* model) +{ + /* Extend the ModelDesc object (using a shallow copy). */ + ExtendedModelDesc* m = calloc(1, sizeof(ExtendedModelDesc)); + memcpy(m, model, sizeof(ModelDesc)); + + /* Index the signals that are used by this model. */ + m->signals.counter = _index(m, "data", "counter"); + + /* Set initial values. */ + *(m->signals.counter) = 42; + + /* Return the extended object. */ + return (ModelDesc*)m; +} + +int model_step(ModelDesc* model, double* model_time, double stop_time) +{ + ExtendedModelDesc* m = (ExtendedModelDesc*)model; + *(m->signals.counter) += 1; + + *model_time = stop_time; + return 0; +} diff --git a/doc/content/apis/modelc/examples/model_interface.c b/doc/content/apis/modelc/examples/model_interface.c index 9c4453e..b3570d8 100644 --- a/doc/content/apis/modelc/examples/model_interface.c +++ b/doc/content/apis/modelc/examples/model_interface.c @@ -1,50 +1,25 @@ +#include +#include #include -#include - #define UNUSED(x) ((void)x) - -/* Signal Vector definition. - Note: Signal order should match order in related SignalGroup (YAML). */ -typedef enum signal_name_index { - SIGNAL_FOO, - SIGNAL_BAR, - __SIGNAL__COUNT__ -} signal_name_index; - -static double* signal_value; - - -int model_step(double* model_time, double stop_time) +ModelDesc* model_create(ModelDesc* m) { - signal_value[SIGNAL_FOO] += 1.2; - signal_value[SIGNAL_BAR] += 4.2; - - *model_time = stop_time; - return 0; + return (ModelDesc*)m; } -int model_setup(ModelInstanceSpec* mi) +int model_step(ModelDesc* m, double* model_time, double stop_time) { - int rc = model_function_register(mi, "example", - 0.005, model_step); - if (rc != 0) return rc; - - /* Register channels (and get storage). */ - static ModelChannelDesc channel_desc = { - .name = "model_channel", - .function_name = "example", - }; - rc = model_configure_channel(mi, &channel_desc); - if (rc != 0) return rc; - signal_value = channel_desc.vector_double; + ModelSignalIndex counter = m->index(m, "data", "counter"); + if (counter.scalar == NULL) return -EINVAL; + *(counter.scalar) += 1; + *model_time = stop_time; return 0; } -int model_exit(ModelInstanceSpec* mi) +void model_destroy(ModelDesc* m) { - UNUSED(mi); - return 0; + UNUSED(m); } diff --git a/doc/content/apis/modelc/examples/model_sv_create.c b/doc/content/apis/modelc/examples/model_sv_create.c deleted file mode 100644 index 49ac8be..0000000 --- a/doc/content/apis/modelc/examples/model_sv_create.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -void print_signal_names(ModelInstanceSpec* mi) -{ - SignalVector* sv_save = model_sv_create(mi); - for (SignalVector* sv = sv_save; sv->name; sv++) { - for (uint32_t i = 0; i < sv->count; i++) { - log_debug(" signal : %s", sv->signal[i]); - } - } - model_sv_destroy(sv_save); -} diff --git a/doc/content/apis/modelc/examples/signalvector_annotation.c b/doc/content/apis/modelc/examples/signalvector_annotation.c new file mode 100644 index 0000000..d2709a6 --- /dev/null +++ b/doc/content/apis/modelc/examples/signalvector_annotation.c @@ -0,0 +1,15 @@ +#include +#include + +ModelDesc* model_create(ModelDesc* m) +{ + ModelSignalIndex idx = m->index(m, "data", "counter"); + + if (idx.scalar) { + /* Set initial value. */ + const char* v = idx.sv->annotation(idx.sv, idx.signal, "initial_value"); + if (v) *(idx.scalar) = atoi(v); + } + + return m; +} diff --git a/doc/content/apis/modelc/examples/model_signalvector.c b/doc/content/apis/modelc/examples/signalvector_interface.c similarity index 84% rename from doc/content/apis/modelc/examples/model_signalvector.c rename to doc/content/apis/modelc/examples/signalvector_interface.c index 5e95506..efcf2a4 100644 --- a/doc/content/apis/modelc/examples/model_signalvector.c +++ b/doc/content/apis/modelc/examples/signalvector_interface.c @@ -1,9 +1,12 @@ +#include #include #include -void print_signal_vectors(ModelInstanceSpec* mi) +#define UNUSED(x) ((void)x) + +int model_step(ModelDesc* m, double* model_time, double stop_time) { - SignalVector* sv = model_sv_create(mi); + SignalVector* sv = m->sv; while (sv && sv->name) { log_debug("Signal Vector : %s", sv->name); @@ -30,4 +33,7 @@ void print_signal_vectors(ModelInstanceSpec* mi) // Next signal vector. sv++; } -} \ No newline at end of file + + *model_time = stop_time; + return 0; +} diff --git a/doc/content/apis/modelc/examples/simmock_configure.c b/doc/content/apis/modelc/examples/simmock_configure.c index 3ce29f5..fc0a31d 100644 --- a/doc/content/apis/modelc/examples/simmock_configure.c +++ b/doc/content/apis/modelc/examples/simmock_configure.c @@ -1,5 +1,5 @@ #include -#include +#include int test_setup(void** state) { @@ -19,7 +19,7 @@ int test_setup(void** state) }; SimMock* mock = simmock_alloc(inst_names, ARRAY_SIZE(inst_names)); simmock_configure(mock, argv, ARRAY_SIZE(argv), ARRAY_SIZE(inst_names)); - simmock_load(mock, true); + simmock_load(mock); simmock_setup(mock, "signal", "network"); /* Return the mock. */ diff --git a/doc/content/apis/modelc/examples/simmock_frame_check.c b/doc/content/apis/modelc/examples/simmock_frame_check.c index 340ec15..5f80e76 100644 --- a/doc/content/apis/modelc/examples/simmock_frame_check.c +++ b/doc/content/apis/modelc/examples/simmock_frame_check.c @@ -1,5 +1,5 @@ #include -#include +#include void test_network__frame_check(void** state) { diff --git a/doc/content/apis/modelc/examples/simmock_signal_check.c b/doc/content/apis/modelc/examples/simmock_signal_check.c index 501ae0c..9a5b2b0 100644 --- a/doc/content/apis/modelc/examples/simmock_signal_check.c +++ b/doc/content/apis/modelc/examples/simmock_signal_check.c @@ -1,5 +1,5 @@ #include -#include +#include #define SIG_task_init_done 1 #define SIG_task_5_active 2 diff --git a/doc/content/apis/modelc/mcl/index.md b/doc/content/apis/modelc/mcl/index.md index b33448f..ddc246c 100644 --- a/doc/content/apis/modelc/mcl/index.md +++ b/doc/content/apis/modelc/mcl/index.md @@ -71,7 +71,7 @@ typedef struct MclAdapterDesc { ```c typedef struct MclInstanceDesc { int * model_instance; - int * channel; + int * mcl_channel_sv; MclStrategyDesc * strategy; int models; } diff --git a/doc/content/apis/modelc/model/index.md b/doc/content/apis/modelc/model/index.md index 418ec43..087ab1d 100644 --- a/doc/content/apis/modelc/model/index.md +++ b/doc/content/apis/modelc/model/index.md @@ -5,67 +5,39 @@ linkTitle: Model ## Model API -The Model API allows model developers and integrators to interface with a -Dynamic Simulation Environment via a connection with a Simulation Bus. +The Model API allows model developers and integrators to implement models which +can be connected to a Simulation Bus. +Models are able to exchange signals with other models via this connection to +a Simulation Bus. +A runtime environment, such as the ModelC Runtime/Importer, will load the +model and also manages the connection with the Simulation Bus. +The Model API provides two simple interfaces which facilitate the development +of models; the Model Interface which is concerned with the model lifecycle; and +the Signal Interface which facilitates signal exchange. -## Signal Vector Interface +### Model Interface -Models exchange signals via the Simulation Bus using a Signal Vector. Signal -Vectors represent a logical grouping of signals (i.e. a collection of signals -belonging to an ECU interface or bus), they are defined by a `SignalGroup` -schema kind, and a Signal Vector can represent either scalar or binary values. - - -### Component Diagram - - - -![](model-signal-vector.png) - +The Model Interface provides the necessary types, methods and objects required +for implementing a model. Such a model can easily participate in a simulation +by being connecting to a Simulation Bus (using the ModelC Importer) and then +exchanging signals with other models in that simulation by using the +provided SignalVector objects (which represent those signals). -### Example +Additionally, model implementers may extend or modify the Model Interface +to support more complex integrations. -{{< readfile file="../examples/model_signalvector.c" code="true" lang="c" >}} +### Signal Vector Interface - - -## Model Interface - - -The Model Interface must be implemented by a Model. It includes the functions -necessary for a Model to be loaded and executed in the Dynamic Simulation -Environment. +Models exchange signals via the Simulation Bus using a Signal Vector. Signal +Vectors represent a logical grouping of signals (e.g. a collection of signals +belonging to an ECU interface or bus). They are defined by a `SignalGroup` +schema kind and may be configured to represent either either scalar +(double, int, bool) or binary values. ### Component Diagram @@ -87,14 +59,14 @@ m1 -left-> SBif m2 -right-> SBif package "Model" { - component "ModelC Lib" as ModelC - interface "ModelInterfaceVTable" as MIvt - component "Model" as Mdl + component "Runtime" as ModelC + interface "ModelVTable" as Mvt + component "Model" as Mdl } SBif <-down- ModelC -Mdl -up- MIvt -MIvt )-up- ModelC +Mdl -up- Mvt +Mvt )-up- ModelC center footer Dynamic Simulation Environment @@ -106,100 +78,54 @@ center footer Dynamic Simulation Environment ![](model-interface.png) -### Example +### Example (Model Interface) {{< readfile file="../examples/model_interface.c" code="true" lang="c" >}} +### Example (Signal Vector Interface) -## Typedefs +{{< readfile file="../examples/signalvector_interface.c" code="true" lang="c" >}} -### ChannelSpec -```c -typedef struct ChannelSpec { - const char * name; - const char * alias; - void * private; -} -``` -### ModelCArguments -```c -typedef struct ModelCArguments { - const char * transport; - char * uri; - const char * host; - uint32_t port; - double timeout; - uint8_t log_level; - double step_size; - double end_time; - uint32_t uid; - const char * name; - const char * file; - const char * path; - int * yaml_doc_list; - int timeout_set_by_cli; - int log_level_set_by_cli; - uint32_t steps; -} -``` - -### ModelChannelDesc - -```c -typedef struct ModelChannelDesc { - const char * name; - const char * function_name; - const char ** signal_names; - uint32_t signal_count; - bool propagator_source_channel; - bool propagator_target_channel; - double * vector_double; - void ** vector_binary; - uint32_t * vector_binary_size; - uint32_t * vector_binary_buffer_size; -} -``` +## Typedefs -### ModelDefinitionSpec +### ModelDesc ```c -typedef struct ModelDefinitionSpec { - const char * name; - const char * path; - const char * file; - char * full_path; - int * doc; - int * channels; +typedef struct ModelDesc { + ModelVTable vtable; + ModelIndex index; + SimulationSpec * sim; + ModelInstanceSpec * mi; + SignalVector * sv; } ``` -### ModelInstanceSpec +### ModelSignalIndex ```c -typedef struct ModelInstanceSpec { - uint32_t uid; - char * name; - ModelDefinitionSpec model_definition; - int * spec; - int * propagators; - int * yaml_doc_list; - void * private; +typedef struct ModelSignalIndex { + SignalVector * sv; + double * scalar; + void ** binary; + uint32_t vector; + uint32_t signal; } ``` -### ModelInterfaceVTable +### ModelVTable ```c -typedef struct ModelInterfaceVTable { - ModelSetupHandler setup; - ModelDoStepHandler step; - ModelExitHandler exit; +typedef struct ModelVTable { + ModelCreate create; + ModelStep step; + ModelDestroy destroy; + ModelIndex index; } ``` @@ -210,7 +136,7 @@ typedef struct SignalVector { const char * name; const char * alias; const char * function_name; - bool is_binary; + _Bool is_binary; uint32_t count; const char ** signal; BinarySignalAppendFunc append; @@ -234,115 +160,294 @@ typedef struct SignalVectorVTable { } ``` -### SimulationSpec +## Functions -```c -typedef struct SimulationSpec { - const char * transport; - char * uri; - uint32_t uid; - double timeout; - double step_size; - double end_time; - ModelInstanceSpec * instance_list; -} -``` +### model_create -## Functions +> Optional method of `ModelVTable` interface. + +Called by the Model Runtime to create a new instance of this model. + +The `model_create()` method may extend or mutilate the provided Model +Descriptor. When extending the Model Descriptor _and_ allocating additional +resources then the `model_destroy()` method should also be implemented. + +Fault conditions can be communicated to the caller by setting variable +`errno` to a non-zero value. Additionally, `log_fatal()` can be used to +immediately halt execution of a model. + +#### Parameters + +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +#### Returns + +NULL +: The Channel was configured. + +(ModelDesc*) +: Pointer to a new, or mutilated, version of the Model Descriptor object. The + original Model Descriptor object will be released by the Model Runtime (i.e. + don't call `free()`). + +errno <> 0 (indirect) +: Indicates an error condition. + +#### Example + + +{{< readfile file="../examples/model_create.c" code="true" lang="c" >}} + + + + + +### model_destroy -### model_configure_channel +> Optional method of `ModelVTable` interface. -Configure a connection from this Model to a Channel on the Simulation Bus. The -Channel can then be represented by a Signal Vector making access to individual -Signals and their configuration (annotations) easy. +Called by the Model Runtime at the end of a simulation, the `model_destroy()` +function may be implemented by a Model Integrator to perform any custom +cleanup operations (e.g. releasing instance related resources, such as open +files or allocated memory). #### Parameters -model_instance (ModelInstanceSpec*) -: The Model Instance object (provided via the `model_setup()` function of the - Model API). +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. -channel_desc (ModelChannelDesc*) -: A channel descriptor object which defines the Channel and Model Function names - which should be configured. + + + +### model_index_ + +> Provided method (by the Runtime). Model implementers may specify + a different index method by mutilating the Model Descriptor in the + `model_create()` method, or even at runtime. + +A model may use this method to index a signal that is contained within the +Signal Vectors of the Model Descriptor. + +#### Parameters + +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +vname (const char*) +: The name (alias) of the Signal Vector. + +sname (const char*) +: The name of the signal within the Signal Vector. + +#### Returns + +ModelSignalIndex +: An index. When valid, either the `scalar` or `binary` fields will be set to + a valid pointer (i.e. not NULL). + + + + +### model_step + +> Mandatory method of `ModelVTable` interface. Alternatively, Model implementers + may specify the `ModelVTable.step` method dynamically by mutilating the + Model Descriptor in the `model_create()` method, or even at runtime. + +Called by the Model Runtime to step the model for a time interval. + +#### Parameters + +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +model_time (double*) +: (in/out) Specifies the model time for this step of the model. + +stop_time (double) +: Specifies the stop time for this step of the model. The model step should not + exceed this time. #### Returns 0 -: The Channel was configured. +: The step completed without error. -+VE -: An error occurred during the registration of the Channel. +<>0 +: An error occurred at some point during the step execution. +model_time (via parameter) +: The final model time reached for this step. This value may be less than + `stop_time` if a step decides to return early. -### model_function_register +### signal_annotation -Register a Model Function. A Model may register one or more Model Functions -with repeated calls to this function. +Get an annotation from a signal definition. #### Parameters -model_instance (ModelInstanceSpec*) -: The Model Instance object (provided via the `model_setup()` function of the - Model API). +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. name (const char*) -: The name of the Model Function. +: The name of the annotation. + +#### Returns + +const char* +: The annotation value. + +#### Example (Annotation Specification) + + +```yaml +kind: SignalGroup +metadata: + name: data +spec: + signals: + - signal: counter + annotations: + initial_value: 10 +``` + +#### Example (Code Usage) + + +{{< readfile file="../examples/signalvector_annotation.c" code="true" lang="c" >}} + -step_size (double) -: The step size of the Model Function. +NULL +: The requested annotation was not found. -do_step_handler (ModelDoStepHandler) -: The "do step" function of the Model Function. + + +### signal_append + +Append data to the end of the specified binary signal. The append method will +resize the buffers of the binary signal as required. + +#### Parameters + +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +data (void*) +: Address/pointer to the data which should be appended to the binary signal. + +len (uint32_t) +: Length of the provided data buffer being appended. #### Returns 0 -: The model function was registered. +: The operation completed without error. -(errno) -: An error occurred during registration of the model function. The return - value is the `errno` which may indicate the reason for the failure. +<>0 +: Indicates an error condition. Inspect `errno` for additional information. +### signal_codec -### model_sv_create +Return a pointer to the Codec object associated with a binary signal. -This is Model User API replacing modelc_debug.c::modelc_get_model_vectors(). +Codec objects are created when a binary signal is specified with a `mime_type` +annotation. #### Parameters -mi (ModelInstanceSpec*) -: The model instance, which holds references to the registered channels. +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. #### Returns -SignalVector (pointer to NULL terminated list) -: A list of SignalVector objects representing the signals assigned to a model. - The list is NULL terminated (sv->name == NULL). Caller to free. +void* +: The Codec object associated with the binary signal. -#### Example +NULL +: The binary signal does not have an associated Codec object. +#### Example (Codec Specification) -{{< readfile file="../examples/model_sv_create.c" code="true" lang="c" >}} +```yaml +kind: SignalGroup +metadata: + name: network + labels: + channel: network_vector + annotations: + vector_type: binary +spec: + signals: + - signal: can_bus + annotations: + mime_type: application/x-automotive-bus; interface=stream; type=frame; bus=can; schema=fbs; bus_id=1; node_id=2; interface_id=3 +``` + +#### Reference +[Network Codec API](https://github.com/boschglobal/dse.standards/tree/main/dse/ncodec) -### model_sv_destroy -The underlying objects of a SignalVector object (e.g. from ModelC object) -are not affected by calling this method. + + +### signal_release + +Release the resources allocated to a binary signal (e.g. free the buffer). #### Parameters sv (SignalVector*) -: The SignalVector object to destroy. Should be the same object as returned - from the call to `model_sv_create()`. +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +#### Returns + +0 +: The operation completed without error. + +<>0 +: Indicates an error condition. Inspect `errno` for additional information. + + + +### signal_reset + +Reset a binary signal (e.g. sets its buffer length to 0). The buffers of the +binary signal are not released (see `signal_release()`). + +#### Parameters + +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +#### Returns + +0 +: The operation completed without error. +<>0 +: Indicates an error condition. Inspect `errno` for additional information. diff --git a/doc/content/apis/modelc/model/model-interface.png b/doc/content/apis/modelc/model/model-interface.png index 97e6201ad82189c55f7275abf41e4d5dc2e6b451..10c0007ffa468f30821046895bf090da42c33c22 100644 GIT binary patch literal 11648 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 diff --git a/doc/content/apis/modelc/model/model-signal-vector.png b/doc/content/apis/modelc/model/model-signal-vector.png deleted file mode 100644 index b6ef0b3a71a8f589cdd56a6aaf59d9304690103f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19464 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 #include #include +#include #include #include /* Private interface from ncodec.c */ -extern void* _create_stream(SignalVector* sv, uint32_t idx); -extern void _free_stream(void* stream); +extern void* model_sv_stream_create(SignalVector* sv, uint32_t idx); +extern void model_sv_stream_destroy(void* stream); /* Private interface from dse/modelc/controller/step.c */ extern int step_model(ModelInstanceSpec* mi, double* model_time); @@ -85,7 +86,7 @@ static void __free_stub_sv(SignalVector* sv) if (sv->binary[i]) free(sv->binary[i]); NCodecInstance* nc = sv->ncodec[i]; if (nc) { - if (nc->stream) _free_stream(nc->stream); + if (nc->stream) model_sv_stream_destroy(nc->stream); ncodec_close((NCODEC*)nc); } } @@ -183,10 +184,8 @@ Parameters mock (SimMock*) : A SimMock object. -expect_exit_function (bool) -: Indicate that model libraries should contain a `model_exit` function. */ -void simmock_load(SimMock* mock, bool expect_exit_func) +void simmock_load(SimMock* mock) { assert_non_null(mock); @@ -197,11 +196,11 @@ void simmock_load(SimMock* mock, bool expect_exit_func) void* handle = dlopen( model->mi->model_definition.full_path, RTLD_NOW | RTLD_LOCAL); + if (handle == NULL) log_notice("ERROR: dlopen call: %s", dlerror()); assert_non_null(handle); - model->model_setup_func = dlsym(handle, MODEL_SETUP_FUNC_STR); - model->model_exit_func = dlsym(handle, MODEL_EXIT_FUNC_STR); - assert_non_null(model->model_setup_func); - if (expect_exit_func) assert_non_null(model->model_exit_func); + model->vtable.create = dlsym(handle, MODEL_CREATE_FUNC_NAME); + model->vtable.step = dlsym(handle, MODEL_STEP_FUNC_NAME); + model->vtable.destroy = dlsym(handle, MODEL_DESTROY_FUNC_NAME); } /* Save a doc_list reference for simmock_free(). */ @@ -209,8 +208,43 @@ void simmock_load(SimMock* mock, bool expect_exit_func) } +/** +simmock_load_model_check +======================== + +Check the condition/state of a loaded model. + +Parameters +---------- +mock (SimMock*) +: A SimMock object. + +expect_create_func (bool) +: Indicate that model libraries should contain a `model_create` function. + +expect_step_func (bool) +: Indicate that model libraries should contain a `model_step` function. + +expect_destroy_func (bool) +: Indicate that model libraries should contain a `model_destroy` function. +*/ +void simmock_load_model_check(ModelMock* model, bool expect_create_func, + bool expect_step_func, bool expect_destroy_func) +{ + assert_non_null(model); + + log_debug("Load model check: %s", model->name); + assert_non_null(model->mi); + + if (expect_create_func) assert_non_null(model->vtable.create); + if (expect_step_func) assert_non_null(model->vtable.step); + if (expect_destroy_func) assert_non_null(model->vtable.destroy); +} + + static SignalVector* __stub_sv(SignalVector* sv) { + if (sv == NULL) return NULL; SignalVector* stub_sv = calloc(1, sizeof(SignalVector)); stub_sv->mi = sv->mi; @@ -232,12 +266,12 @@ static SignalVector* __stub_sv(SignalVector* sv) for (uint32_t i = 0; i < stub_sv->count; i++) { stub_sv->signal[i] = sv->signal[i]; stub_sv->mime_type[i] = sv->mime_type[i]; - void* stream = _create_stream(stub_sv, i); + void* stream = model_sv_stream_create(stub_sv, i); NCODEC* nc = ncodec_open(stub_sv->mime_type[i], stream); if (nc) { stub_sv->ncodec[i] = nc; } else { - _free_stream(stream); + model_sv_stream_destroy(stream); } } @@ -266,13 +300,25 @@ sig_name (const char*) void simmock_setup(SimMock* mock, const char* sig_name, const char* net_name) { assert_non_null(mock); + SignalVector* sv = NULL; for (ModelMock* model = mock->model; model->name; model++) { - log_debug("Call model_setup(): %s", model->name); - int rc = model->model_setup_func(model->mi); + log_debug("Setup the Model: %s", model->name); + log_debug("Call modelc_model_create(): %s", model->name); + int rc = modelc_model_create(&mock->sim, model->mi, &model->vtable); assert_int_equal(rc, 0); - SignalVector* sv = model_sv_create(model->mi); - model->sv_save = sv; + + assert_non_null(model->mi->model_desc); + assert_ptr_equal(&mock->sim, model->mi->model_desc->sim); + assert_ptr_equal(model->mi, model->mi->model_desc->mi); + assert_ptr_equal( + model->vtable.create, model->mi->model_desc->vtable.create); + assert_ptr_equal( + model->vtable.step, model->mi->model_desc->vtable.step); + assert_ptr_equal( + model->vtable.destroy, model->mi->model_desc->vtable.destroy); + assert_non_null(model->mi->model_desc->sv); + model->sv_save = sv = model->mi->model_desc->sv; /* Locate the vectors ... */ while (sv && sv->name) { @@ -286,14 +332,18 @@ void simmock_setup(SimMock* mock, const char* sig_name, const char* net_name) } /* Setup the mocked signal exchange. */ - mock->sv_signal = calloc(1, sizeof(SignalVector)); - mock->sv_signal->count = mock->model->sv_signal->count; - mock->sv_signal->scalar = calloc(mock->sv_signal->count, sizeof(double)); - memcpy(mock->sv_signal->scalar, mock->model->sv_signal->scalar, - (mock->sv_signal->count * sizeof(double))); - - mock->sv_network_rx = __stub_sv(mock->model->sv_network); - mock->sv_network_tx = __stub_sv(mock->model->sv_network); + if (mock->model->sv_signal) { + mock->sv_signal = calloc(1, sizeof(SignalVector)); + mock->sv_signal->count = mock->model->sv_signal->count; + mock->sv_signal->scalar = + calloc(mock->sv_signal->count, sizeof(double)); + memcpy(mock->sv_signal->scalar, mock->model->sv_signal->scalar, + (mock->sv_signal->count * sizeof(double))); + } + if (mock->model->sv_network) { + mock->sv_network_rx = __stub_sv(mock->model->sv_network); + mock->sv_network_tx = __stub_sv(mock->model->sv_network); + } } @@ -323,11 +373,13 @@ int simmock_step(SimMock* mock, bool assert_rc) assert_non_null(mock); /* Copy simmock->binary_tx to simmock->binary_rx */ - for (uint32_t i = 0; i < mock->sv_network_tx->count; i++) { - mock->sv_network_rx->reset(mock->sv_network_rx, i); - mock->sv_network_rx->append(mock->sv_network_rx, i, - mock->sv_network_tx->binary[i], mock->sv_network_tx->length[i]); - mock->sv_network_tx->reset(mock->sv_network_tx, i); + if (mock->sv_network_rx && mock->sv_network_tx) { + for (uint32_t i = 0; i < mock->sv_network_tx->count; i++) { + mock->sv_network_rx->reset(mock->sv_network_rx, i); + mock->sv_network_rx->append(mock->sv_network_rx, i, + mock->sv_network_tx->binary[i], mock->sv_network_tx->length[i]); + mock->sv_network_tx->reset(mock->sv_network_tx, i); + } } int rc = 0; @@ -337,24 +389,31 @@ int simmock_step(SimMock* mock, bool assert_rc) model->sv_signal->scalar[i] = mock->sv_signal->scalar[i]; } /* Copy binary from simmock->binary_rx. */ - for (uint32_t i = 0; i < mock->sv_network_tx->count; i++) { - model->sv_network->reset(model->sv_network, i); - model->sv_network->append(model->sv_network, i, - mock->sv_network_rx->binary[i], mock->sv_network_rx->length[i]); + if (mock->sv_network_rx && mock->sv_network_tx) { + for (uint32_t i = 0; i < mock->sv_network_tx->count; i++) { + model->sv_network->reset(model->sv_network, i); + model->sv_network->append(model->sv_network, i, + mock->sv_network_rx->binary[i], + mock->sv_network_rx->length[i]); + } } rc |= modelc_step(model->mi, mock->step_size); - for (uint32_t i = 0; i < model->sv_network->count; i++) { - mock->sv_network_tx->append(mock->sv_network_tx, i, - model->sv_network->binary[i], model->sv_network->length[i]); + if (mock->sv_network_rx && mock->sv_network_tx) { + for (uint32_t i = 0; i < model->sv_network->count; i++) { + mock->sv_network_tx->append(mock->sv_network_tx, i, + model->sv_network->binary[i], model->sv_network->length[i]); + } } /* Copy scalars to simmock->scalars. */ for (uint32_t i = 0; i < mock->sv_signal->count; i++) { mock->sv_signal->scalar[i] = model->sv_signal->scalar[i]; } /* Copy binary to simmock->binary_tx. */ - for (uint32_t i = 0; i < mock->sv_network_tx->count; i++) { - mock->sv_network_tx->append(mock->sv_network_tx, i, - model->sv_network->binary[i], model->sv_network->length[i]); + if (mock->sv_network_rx && mock->sv_network_tx) { + for (uint32_t i = 0; i < mock->sv_network_tx->count; i++) { + mock->sv_network_tx->append(mock->sv_network_tx, i, + model->sv_network->binary[i], model->sv_network->length[i]); + } } if (assert_rc) assert_int_equal(rc, 0); } @@ -377,15 +436,6 @@ mock (SimMock*) void simmock_exit(SimMock* mock) { assert_non_null(mock); - - for (ModelMock* model = mock->model; model->name; model++) { - log_debug("Call model_exit(): %s", model->name); - if (model->model_exit_func) { - int rc = model->model_exit_func(model->mi); - assert_int_equal(rc, 0); - } - if (model->sv_save) model_sv_destroy(model->sv_save); - } modelc_exit(&mock->sim); } @@ -468,6 +518,53 @@ void simmock_signal_check(SimMock* mock, const char* model_name, } +/** +simmock_binary_check +==================== + +Check the content of a binary signal. + +Parameters +---------- +mock (SimMock*) +: A SimMock object. + +model_name (const char*) +: The name of the model to check. + +checks (BinaryCheck*) +: Array of BinaryCheck objects. + +count (size_t) +: The number elements in the checks array. + +func (BinaryCheckFunc) +: Optional function pointer for performing the binary check. +*/ +void simmock_binary_check(SimMock* mock, const char* model_name, + BinaryCheck* checks, size_t count, BinaryCheckFunc func) +{ + assert_non_null(mock); + ModelMock* check_model = simmock_find_model(mock, model_name); + assert_non_null(check_model); + + SignalVector* sv = check_model->sv_network; + for (size_t i = 0; i < count; i++) { + if (func) { + int rc = func(&checks[i], sv); + assert_int_equal(rc, 0); + } else { + assert_true(checks[i].index < sv->count); + assert_int_equal(sv->length[checks[i].index], checks[i].len); + if (sv->binary[checks[i].index]) { + assert_memory_equal(sv->binary[checks[i].index], + checks[i].buffer, checks[i].len); + } + } + } +} + + /** simmock_frame_check =================== @@ -692,6 +789,47 @@ void simmock_print_scalar_signals(SimMock* mock, int level) } +/** +simmock_print_binary_signals +============================ + +Print the binary signals contained in each network vector of each model. + +Parameters +---------- +mock (SimMock*) +: A SimMock object. + +level (int) +: The log level to print at. +*/ +void simmock_print_binary_signals(SimMock* mock, int level) +{ + assert_non_null(mock); + + log_at(level, "SignalVector (Network) at %f:", mock->model_time); + for (ModelMock* model = mock->model; model->name; model++) { + log_at(level, " Model Instance: %s", model->name); + SignalVector* sv = model->sv_network; + for (uint32_t idx = 0; idx < sv->count; idx++) { + log_at(level, " Network Signal: %s (%d)", sv->signal[idx], + sv->length[idx]); + uint8_t* b = sv->binary[idx]; + for (uint32_t i = 0; i < sv->length[idx]; i += 8) { + char buffer[100] = {}; + for (uint32_t j = i; j < i + 8; j++) { + if (j < sv->length[idx]) { + snprintf(buffer + strlen(buffer), + sizeof(buffer + strlen(buffer)), "%02x ", b[j]); + } + } + log_at(level, "%s", buffer); + } + } + } +} + + /** simmock_print_network_frames ============================ diff --git a/dse/mocks/simmock.h b/dse/mocks/simmock.h index 49b450c..f16a962 100644 --- a/dse/mocks/simmock.h +++ b/dse/mocks/simmock.h @@ -8,6 +8,7 @@ #include #include #include +#include #define UNUSED(x) ((void)x) @@ -115,8 +116,7 @@ typedef struct ModelMock { SignalVector* sv_signal; SignalVector* sv_network; SignalVector* sv_save; - ModelSetupHandler model_setup_func; - ModelExitHandler model_exit_func; + ModelVTable vtable; } ModelMock; typedef struct SimMock { @@ -137,7 +137,9 @@ typedef struct SimMock { void* simmock_alloc(const char* inst_names[], size_t count); void simmock_configure( SimMock* mock, char** argv, size_t argc, size_t expect_model_count); -void simmock_load(SimMock* mock, bool expect_exit_func); +void simmock_load(SimMock* mock); +void simmock_load_model_check(ModelMock* model, bool expect_create_func, + bool expect_step_func, bool expect_destroy_func); void simmock_setup(SimMock* mock, const char* sig_name, const char* net_name); int simmock_step(SimMock* mock, bool assert_rc); void simmock_exit(SimMock* mock); @@ -155,6 +157,12 @@ typedef struct SignalCheck { double value; } SignalCheck; +typedef struct BinaryCheck { + uint32_t index; + uint8_t* buffer; + uint32_t len; +} BinaryCheck; + typedef struct FrameCheck { uint32_t frame_id; uint8_t offset; @@ -163,15 +171,19 @@ typedef struct FrameCheck { } FrameCheck; typedef int (*SignalCheckFunc)(SignalCheck* check, SignalVector* sv); +typedef int (*BinaryCheckFunc)(BinaryCheck* check, SignalVector* sv); void simmock_signal_check(SimMock* mock, const char* model_name, SignalCheck* checks, size_t count, SignalCheckFunc func); +void simmock_binary_check(SimMock* mock, const char* model_name, + BinaryCheck* checks, size_t count, BinaryCheckFunc func); void simmock_frame_check(SimMock* mock, const char* model_name, const char* sig_name, FrameCheck* checks, size_t count); /* Information API. */ void simmock_print_scalar_signals(SimMock* mock, int level); +void simmock_print_binary_signals(SimMock* mock, int level); void simmock_print_network_frames(SimMock* mock, int level); diff --git a/dse/modelc/CMakeLists.txt b/dse/modelc/CMakeLists.txt index f483c55..4f55235 100644 --- a/dse/modelc/CMakeLists.txt +++ b/dse/modelc/CMakeLists.txt @@ -189,6 +189,7 @@ set(DSE_MODELC_PUBLIC_HEADERS gateway.h mcl.h model.h + runtime.h schema.h ) add_subdirectory(adapter) diff --git a/dse/modelc/controller/controller.c b/dse/modelc/controller/controller.c index a6c156a..37313a7 100644 --- a/dse/modelc/controller/controller.c +++ b/dse/modelc/controller/controller.c @@ -310,16 +310,13 @@ void controller_exit(SimulationSpec* sim) ModelInstanceSpec* _instptr = sim->instance_list; while (_instptr && _instptr->name) { - ModelInstancePrivate* mip = _instptr->private; - ControllerModel* cm = mip->controller_model; - if (cm->model_exit_func == NULL) goto exit_next; - - log_notice("Call symbol: %s ...", MODEL_EXIT_FUNC_STR); - errno = 0; - int rc = cm->model_exit_func(_instptr); - if (rc) { - if (errno == 0) errno = rc; - log_error("model_exit_func() failed"); + if (_instptr->model_desc) { + if (_instptr->model_desc->vtable.destroy == NULL) goto exit_next; + + log_notice("Call symbol: %s ...", MODEL_DESTROY_FUNC_NAME); + errno = 0; + _instptr->model_desc->vtable.destroy(_instptr->model_desc); + if (errno) log_error(MODEL_DESTROY_FUNC_NAME "() failed"); } exit_next: /* Next instance? */ diff --git a/dse/modelc/controller/controller.h b/dse/modelc/controller/controller.h index 7ad38c7..435926f 100644 --- a/dse/modelc/controller/controller.h +++ b/dse/modelc/controller/controller.h @@ -30,23 +30,23 @@ typedef struct ModelFunctionChannel { typedef struct ModelFunction { - const char* name; - double step_size; - ModelDoStepHandler do_step_handler; + const char* name; + double step_size; - HashMap - channels; /* Collection of ModelFunctionChannel, Key is channel_name. */ + /* Collection of ModelFunctionChannel, Key is channel_name. */ + HashMap channels; } ModelFunction; typedef struct ControllerModel { /* Controller specific objects (placed in Model instance). */ const char* model_dynlib_filename; - HashMap model_functions; /* Collection of ModelFunction, Key is Model - Function name. */ - ModelSetupHandler model_setup_func; - ModelExitHandler model_exit_func; + /* Collection of ModelFunction, Key is Model Function name. */ + HashMap model_functions; + + /* Model interface vTable. */ + ModelVTable vtable; } ControllerModel; @@ -67,7 +67,7 @@ DLL_PRIVATE int controller_init(Endpoint* endpoint); DLL_PRIVATE int controller_init_channel(ModelInstanceSpec* model_instance, const char* channel_name, const char** signal_name, uint32_t signal_count); -/* These are called indirectly from the Model, via model_function_register() +/* These are called indirectly from the Model, via _model_function_register() and model_configure_channel_*(). */ DLL_PRIVATE int controller_register_model_function( ModelInstanceSpec* model_instance, ModelFunction* model_function); diff --git a/dse/modelc/controller/loader.c b/dse/modelc/controller/loader.c index 01cf763..ac4ca77 100644 --- a/dse/modelc/controller/loader.c +++ b/dse/modelc/controller/loader.c @@ -10,15 +10,15 @@ #include #include #include +#include extern Controller* controller_object_ref(void); -static ModelSetupHandler __model_setup_func = NULL; -static ModelExitHandler __model_exit_func = NULL; -extern int __model_gw_setup__(ModelInstanceSpec* mi); -extern int __model_gw_exit__(ModelInstanceSpec* mi); +extern ModelDesc* __model_gw_create__(ModelDesc* m); +extern int __model_gw_step__(ModelDesc* m, double* model_time, double stop_time); +extern void __model_gw_destroy__(ModelDesc* m); int controller_load_model(ModelInstanceSpec* model_instance) @@ -27,8 +27,6 @@ int controller_load_model(ModelInstanceSpec* model_instance) ModelInstancePrivate* mip = model_instance->private; ControllerModel* controller_model = mip->controller_model; assert(controller_model); - ModelSetupHandler model_setup_func = NULL; - ModelExitHandler model_exit_func = NULL; const char* dynlib_filename = model_instance->model_definition.full_path; errno = 0; @@ -40,32 +38,28 @@ int controller_load_model(ModelInstanceSpec* model_instance) log_notice("ERROR: dlopen call: %s", dlerror()); goto error_dl; } - log_notice("Loading symbol: %s ...", MODEL_SETUP_FUNC_STR); - model_setup_func = dlsym(handle, MODEL_SETUP_FUNC_STR); - if (model_setup_func == NULL) { - log_notice("ERROR: dlsym call: %s", dlerror()); - goto error_dl; - } - log_notice("Loading optional symbol: %s ...", MODEL_EXIT_FUNC_STR); - model_exit_func = dlsym(handle, MODEL_EXIT_FUNC_STR); - if (model_exit_func) { - log_debug("... symbol loaded"); - } + /* Load the model interface.*/ + controller_model->vtable.create = dlsym(handle, MODEL_CREATE_FUNC_NAME); + log_notice("Loading symbol: %s ... %s", MODEL_CREATE_FUNC_NAME, + controller_model->vtable.create ? "ok" : "not found"); + controller_model->vtable.step = dlsym(handle, MODEL_STEP_FUNC_NAME); + log_notice("Loading symbol: %s ... %s", MODEL_STEP_FUNC_NAME, + controller_model->vtable.step ? "ok" : "not found"); + controller_model->vtable.destroy = + dlsym(handle, MODEL_DESTROY_FUNC_NAME); + log_notice("Loading symbol: %s ... %s", MODEL_DESTROY_FUNC_NAME, + controller_model->vtable.destroy ? "ok" : "not found"); + } else { if (dse_yaml_find_node( model_instance->model_definition.doc, "spec/runtime/gateway")) { log_notice("Using gateway symbols: ..."); - model_setup_func = __model_gw_setup__; - model_exit_func = __model_gw_exit__; - } else { - log_notice("Using linked/registered symbols: ..."); - model_setup_func = __model_setup_func; - model_exit_func = __model_exit_func; + controller_model->vtable.create = __model_gw_create__; + controller_model->vtable.step = __model_gw_step__; + controller_model->vtable.destroy = __model_gw_destroy__; } } - controller_model->model_setup_func = model_setup_func; - controller_model->model_exit_func = model_exit_func; return 0; error_dl: @@ -106,18 +100,18 @@ int controller_load_models(SimulationSpec* sim) log_error("controller_load_model() failed!"); break; } - /* Call model_setup(), inversion of control. */ - log_notice("Call symbol: %s ...", MODEL_SETUP_FUNC_STR); - if (cm->model_setup_func == NULL) { - rc = errno = EINVAL; - log_error("model_setup_func() not loaded!"); + /* Create/Setup the model. */ + if (cm->vtable.create == NULL && cm->vtable.step == NULL) { + log_error("Model interface not complete!"); + log_error(" %s (%p)", MODEL_CREATE_FUNC_NAME, cm->vtable.create); + log_error(" %s (%p)", MODEL_STEP_FUNC_NAME, cm->vtable.step); + log_error(" %s (%p)", MODEL_DESTROY_FUNC_NAME, cm->vtable.destroy); break; } - errno = 0; - rc = cm->model_setup_func(_instptr); + rc = modelc_model_create(sim, _instptr, &cm->vtable); if (rc) { if (errno == 0) errno = EINVAL; - log_error("model_setup_func() failed!"); + log_error("modelc_model_create() failed!"); break; } /* Next instance? */ diff --git a/dse/modelc/controller/modelc.c b/dse/modelc/controller/modelc.c index 91928be..543258c 100644 --- a/dse/modelc/controller/modelc.c +++ b/dse/modelc/controller/modelc.c @@ -28,6 +28,9 @@ static double __stop_request = 0; /* Very private, indicate stop request. */ +extern ModelSignalIndex __model_index__(ModelDesc* m, const char* vname, + const char* sname); + static int _destroy_model_function(void* mf, void* additional_data) { @@ -46,6 +49,11 @@ static void _destroy_model_instances(SimulationSpec* sim) ModelInstancePrivate* mip = _instptr->private; free(_instptr->name); free(_instptr->model_definition.full_path); + if (_instptr->model_desc) { + if (_instptr->model_desc->sv) + model_sv_destroy(_instptr->model_desc->sv); + free(_instptr->model_desc); + } /* ControllerModel */ ControllerModel* cm = mip->controller_model; if (cm) { @@ -137,11 +145,6 @@ int modelc_configure_model( args->yaml_doc_list = dse_yaml_load_file(md_file, args->yaml_doc_list); free(md_file); } - - /* Propagators list. */ - model_instance->propagators = - dse_yaml_find_node(model_instance->spec, "propagators"); - /* Model Definition. */ const char* selector[] = { "metadata/name" }; const char* value[] = { model_name }; @@ -285,6 +288,139 @@ int modelc_configure(ModelCArguments* args, SimulationSpec* sim) } +static int _configure_model_channel(YamlNode* ch_node, ModelInstanceSpec* mi) +{ + const char* name; + + /* Locate the channel by alias name. */ + dse_yaml_get_string(ch_node, "alias", &name); + if (name == NULL) { + /* Fallback to name. */ + dse_yaml_get_string(ch_node, "name", &name); + if (name == NULL) { + errno = EINVAL; + log_error("Could not find channel alias or name!"); + return -EINVAL; + } + } + + /* Configure the channel. */ + ModelChannelDesc channel_desc = { + .name = name, + .function_name = MODEL_STEP_FUNC_NAME, + }; + int rc = model_configure_channel(mi, &channel_desc); + if (rc != 0) { + if (errno == 0) errno = rc; + log_error("Channel could not be configured! Check stack alias."); + return -EINVAL; + } + + return 0; +} + + +static int _model_function_register( + ModelInstanceSpec* model_instance, const char* name, double step_size) +{ + int rc; + errno = 0; + + /* Create the Model Function object. */ + ModelFunction* mf = calloc(1, sizeof(ModelFunction)); + if (mf == NULL) { + log_error("ModelFunction malloc failed!"); + goto error_clean_up; + } + mf->name = name; + mf->step_size = step_size; + rc = hashmap_init(&mf->channels); + if (rc) { + log_error("Hashmap init failed for channels!"); + if (errno == 0) errno = rc; + goto error_clean_up; + } + /* Register the object with the Controller. */ + rc = controller_register_model_function(model_instance, mf); + if (rc && (errno != EEXIST)) goto error_clean_up; + return 0; + +error_clean_up: + model_function_destroy(mf); + return errno; +} + +int modelc_model_create( + SimulationSpec* sim, ModelInstanceSpec* mi, ModelVTable* model_vtable) +{ + /* Create the Model Function (to represent model_step). */ + if (model_vtable->step == NULL) { + errno = EINVAL; + log_error("Model has no " MODEL_STEP_FUNC_NAME "() function"); + return -errno; + } + int rc = _model_function_register(mi, MODEL_STEP_FUNC_NAME, sim->step_size); + if (rc != 0) { + if (errno == 0) errno = rc; + log_error("Model function registration failed!"); + return rc; + } + + /* Setup the channels and signal vector. */ + YamlNode* c_node; + if (dse_yaml_find_node(mi->model_definition.doc, "spec/runtime/gateway")) { + log_debug("Select channels based on Model Instance (Gateway)"); + c_node = dse_yaml_find_node(mi->spec, "channels"); + } else { + c_node = dse_yaml_find_node(mi->model_definition.doc, "spec/channels"); + } + if (c_node) { + for (uint32_t i = 0; i < hashlist_length(&c_node->sequence); i++) { + YamlNode* ch_node = hashlist_at(&c_node->sequence, i); + int rc = _configure_model_channel(ch_node, mi); + if (rc) { + if (errno == 0) errno = EINVAL; + log_error("Model has no " MODEL_STEP_FUNC_NAME "() function"); + return -errno; + } + } + } + SignalVector* sv = model_sv_create(mi); + + /* Setup the initial ModelDesc object. */ + ModelDesc* model_desc = calloc(1, sizeof(ModelDesc)); + memcpy(&model_desc->vtable, model_vtable, sizeof(ModelVTable)); + model_desc->index = model_desc->vtable.index = __model_index__; + model_desc->sim = sim; + model_desc->mi = mi; + model_desc->sv = sv; + + /* Call create (if it exists). */ + if (model_desc->vtable.create) { + errno = 0; + ModelDesc* extended_model_desc = model_desc->vtable.create(model_desc); + if (errno) { + log_error("Error condition while calling " MODEL_CREATE_FUNC_NAME); + } + if (extended_model_desc) { + if (extended_model_desc != model_desc) { + /* The model returned an extended (new) ModelDesc object. */ + free(model_desc); + model_desc = extended_model_desc; + } + } + /* Reset some elements of the ModelDesc (don't trust the model). */ + model_desc->sim = sim; + model_desc->mi = mi; + model_desc->sv = sv; + } + + /* Finalise the ModelDesc object. */ + mi->model_desc = model_desc; + return 0; +} + + /** * modelc_get_model_instance * diff --git a/dse/modelc/controller/modelc_args.c b/dse/modelc/controller/modelc_args.c index 99a896f..3d8c1df 100644 --- a/dse/modelc/controller/modelc_args.c +++ b/dse/modelc/controller/modelc_args.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include @@ -69,7 +69,7 @@ static void print_usage(const char* doc_string) } -/** +/* * _args_extract_environment * * Extract arguments from environment variables. diff --git a/dse/modelc/controller/modelc_debug.c b/dse/modelc/controller/modelc_debug.c index be76cda..d52610f 100644 --- a/dse/modelc/controller/modelc_debug.c +++ b/dse/modelc/controller/modelc_debug.c @@ -12,7 +12,7 @@ #include -/** +/* * The ModelC Debug API * ==================== */ diff --git a/dse/modelc/controller/step.c b/dse/modelc/controller/step.c index 5669fcb..a9e30ac 100644 --- a/dse/modelc/controller/step.c +++ b/dse/modelc/controller/step.c @@ -27,8 +27,9 @@ static int _do_step_func(void* _mf, void* _step_data) { ModelFunction* mf = _mf; mf_step_data* step_data = _step_data; + ModelDesc* md = step_data->mi->model_desc; double model_time = step_data->model_time; - int rc = mf->do_step_handler(&model_time, step_data->stop_time); + int rc = md->vtable.step(md, &model_time, step_data->stop_time); if (rc) log_error( "Model Function %s:%s (rc=%d)", step_data->mi->name, mf->name, rc); diff --git a/dse/modelc/examples/CMakeLists.txt b/dse/modelc/examples/CMakeLists.txt index 1101514..60b7564 100644 --- a/dse/modelc/examples/CMakeLists.txt +++ b/dse/modelc/examples/CMakeLists.txt @@ -2,11 +2,15 @@ # # SPDX-License-Identifier: Apache-2.0 -add_subdirectory(dynamic) + +# Example Models. +add_subdirectory(minimal) +add_subdirectory(extended) add_subdirectory(binary) +# TODO add_subdirectory(ncodec) + add_subdirectory(gateway) -add_subdirectory(stacked) -add_subdirectory(benchmark) +#add_subdirectory(benchmark) # Code examples for documentation. if(UNIX) diff --git a/dse/modelc/examples/apis/CMakeLists.txt b/dse/modelc/examples/apis/CMakeLists.txt index e2babc4..ee73a29 100644 --- a/dse/modelc/examples/apis/CMakeLists.txt +++ b/dse/modelc/examples/apis/CMakeLists.txt @@ -45,9 +45,10 @@ set(DSE_CLIB_INCLUDE_DIR "${DSE_CLIB_SOURCE_DIR}/..") # APIs # ---- add_library(apis OBJECT + model_create.c model_interface.c - model_signalvector.c - model_sv_create.c + signalvector_annotation.c + signalvector_interface.c schema_object_search.c simmock_configure.c simmock_frame_check.c diff --git a/dse/modelc/examples/apis/model_create.c b/dse/modelc/examples/apis/model_create.c new file mode 100644 index 0000000..715e53c --- /dev/null +++ b/dse/modelc/examples/apis/model_create.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +typedef struct { + ModelDesc model; + /* Signal Pointers. */ + struct { + double* counter; + } signals; +} ExtendedModelDesc; + +static inline double* _index(ExtendedModelDesc* m, const char* v, const char* s) +{ + ModelSignalIndex idx = m->model.index((ModelDesc*)m, v, s); + if (idx.scalar == NULL) log_fatal("Signal not found (%s:%s)", v, s); + return idx.scalar; +} + +ModelDesc* model_create(ModelDesc* model) +{ + /* Extend the ModelDesc object (using a shallow copy). */ + ExtendedModelDesc* m = calloc(1, sizeof(ExtendedModelDesc)); + memcpy(m, model, sizeof(ModelDesc)); + + /* Index the signals that are used by this model. */ + m->signals.counter = _index(m, "data", "counter"); + + /* Set initial values. */ + *(m->signals.counter) = 42; + + /* Return the extended object. */ + return (ModelDesc*)m; +} + +int model_step(ModelDesc* model, double* model_time, double stop_time) +{ + ExtendedModelDesc* m = (ExtendedModelDesc*)model; + *(m->signals.counter) += 1; + + *model_time = stop_time; + return 0; +} diff --git a/dse/modelc/examples/apis/model_interface.c b/dse/modelc/examples/apis/model_interface.c index 9c4453e..b3570d8 100644 --- a/dse/modelc/examples/apis/model_interface.c +++ b/dse/modelc/examples/apis/model_interface.c @@ -1,50 +1,25 @@ +#include +#include #include -#include - #define UNUSED(x) ((void)x) - -/* Signal Vector definition. - Note: Signal order should match order in related SignalGroup (YAML). */ -typedef enum signal_name_index { - SIGNAL_FOO, - SIGNAL_BAR, - __SIGNAL__COUNT__ -} signal_name_index; - -static double* signal_value; - - -int model_step(double* model_time, double stop_time) +ModelDesc* model_create(ModelDesc* m) { - signal_value[SIGNAL_FOO] += 1.2; - signal_value[SIGNAL_BAR] += 4.2; - - *model_time = stop_time; - return 0; + return (ModelDesc*)m; } -int model_setup(ModelInstanceSpec* mi) +int model_step(ModelDesc* m, double* model_time, double stop_time) { - int rc = model_function_register(mi, "example", - 0.005, model_step); - if (rc != 0) return rc; - - /* Register channels (and get storage). */ - static ModelChannelDesc channel_desc = { - .name = "model_channel", - .function_name = "example", - }; - rc = model_configure_channel(mi, &channel_desc); - if (rc != 0) return rc; - signal_value = channel_desc.vector_double; + ModelSignalIndex counter = m->index(m, "data", "counter"); + if (counter.scalar == NULL) return -EINVAL; + *(counter.scalar) += 1; + *model_time = stop_time; return 0; } -int model_exit(ModelInstanceSpec* mi) +void model_destroy(ModelDesc* m) { - UNUSED(mi); - return 0; + UNUSED(m); } diff --git a/dse/modelc/examples/apis/model_sv_create.c b/dse/modelc/examples/apis/model_sv_create.c deleted file mode 100644 index 49ac8be..0000000 --- a/dse/modelc/examples/apis/model_sv_create.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -void print_signal_names(ModelInstanceSpec* mi) -{ - SignalVector* sv_save = model_sv_create(mi); - for (SignalVector* sv = sv_save; sv->name; sv++) { - for (uint32_t i = 0; i < sv->count; i++) { - log_debug(" signal : %s", sv->signal[i]); - } - } - model_sv_destroy(sv_save); -} diff --git a/dse/modelc/examples/apis/signalvector_annotation.c b/dse/modelc/examples/apis/signalvector_annotation.c new file mode 100644 index 0000000..d2709a6 --- /dev/null +++ b/dse/modelc/examples/apis/signalvector_annotation.c @@ -0,0 +1,15 @@ +#include +#include + +ModelDesc* model_create(ModelDesc* m) +{ + ModelSignalIndex idx = m->index(m, "data", "counter"); + + if (idx.scalar) { + /* Set initial value. */ + const char* v = idx.sv->annotation(idx.sv, idx.signal, "initial_value"); + if (v) *(idx.scalar) = atoi(v); + } + + return m; +} diff --git a/dse/modelc/examples/apis/model_signalvector.c b/dse/modelc/examples/apis/signalvector_interface.c similarity index 84% rename from dse/modelc/examples/apis/model_signalvector.c rename to dse/modelc/examples/apis/signalvector_interface.c index 5e95506..efcf2a4 100644 --- a/dse/modelc/examples/apis/model_signalvector.c +++ b/dse/modelc/examples/apis/signalvector_interface.c @@ -1,9 +1,12 @@ +#include #include #include -void print_signal_vectors(ModelInstanceSpec* mi) +#define UNUSED(x) ((void)x) + +int model_step(ModelDesc* m, double* model_time, double stop_time) { - SignalVector* sv = model_sv_create(mi); + SignalVector* sv = m->sv; while (sv && sv->name) { log_debug("Signal Vector : %s", sv->name); @@ -30,4 +33,7 @@ void print_signal_vectors(ModelInstanceSpec* mi) // Next signal vector. sv++; } -} \ No newline at end of file + + *model_time = stop_time; + return 0; +} diff --git a/dse/modelc/examples/apis/simmock_configure.c b/dse/modelc/examples/apis/simmock_configure.c index 3586390..fc0a31d 100644 --- a/dse/modelc/examples/apis/simmock_configure.c +++ b/dse/modelc/examples/apis/simmock_configure.c @@ -19,7 +19,7 @@ int test_setup(void** state) }; SimMock* mock = simmock_alloc(inst_names, ARRAY_SIZE(inst_names)); simmock_configure(mock, argv, ARRAY_SIZE(argv), ARRAY_SIZE(inst_names)); - simmock_load(mock, true); + simmock_load(mock); simmock_setup(mock, "signal", "network"); /* Return the mock. */ diff --git a/dse/modelc/examples/binary/CMakeLists.txt b/dse/modelc/examples/binary/CMakeLists.txt index 831f2fe..06482ec 100644 --- a/dse/modelc/examples/binary/CMakeLists.txt +++ b/dse/modelc/examples/binary/CMakeLists.txt @@ -1,79 +1,45 @@ -# Copyright 2023 Robert Bosch GmbH +# Copyright 2024 Robert Bosch GmbH # # SPDX-License-Identifier: Apache-2.0 cmake_minimum_required(VERSION 3.21) -project(BinaryModel - DESCRIPTION "ModelC - Example Binary Model." - HOMEPAGE_URL "${PROJECT_URL}" -) -set(PROJECT_VERSION ${VERSION}) - -include(FetchContent) - +project(Binary) set(MODEL_PATH "examples/binary") -set(CMAKE_SHARED_LIBRARY_PREFIX "") - -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_STANDARD_REQUIRED TRUE) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_C_FLAGS_DEBUG "-g -ggdb") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O3") -list(APPEND C_CXX_WARNING_FLAGS - -Wall - -W - -Wwrite-strings - -Wno-missing-field-initializers - -Wno-misleading-indentation -) -add_compile_options(${C_CXX_WARNING_FLAGS}) - -# External Project - DSE C Lib -# ---------------------------- +include(FetchContent) FetchContent_Declare(dse_clib URL $ENV{DSE_CLIB_URL} HTTP_USERNAME $ENV{GHE_USER} HTTP_PASSWORD $ENV{GHE_TOKEN} ) FetchContent_MakeAvailable(dse_clib) -set(DSE_CLIB_SOURCE_DIR ${dse_clib_SOURCE_DIR}/dse) -set(DSE_CLIB_SOURCE_FILES ) -set(DSE_CLIB_INCLUDE_DIR "${DSE_CLIB_SOURCE_DIR}/..") - - - -# Targets -# ======= +set(DSE_CLIB_INCLUDE_DIR ${dse_clib_SOURCE_DIR}) -# Target - Binary Model -# ---------------------- -add_library(binary_model SHARED - binary_model.c +add_library(binary SHARED + model.c ) -target_include_directories(binary_model +target_include_directories(binary PRIVATE ${DSE_CLIB_INCLUDE_DIR} ../../../.. ) -target_link_libraries(binary_model +target_link_libraries(binary PRIVATE $<$:${modelc_link_lib}> ) -install(TARGETS binary_model +install(TARGETS binary LIBRARY DESTINATION ${MODEL_PATH}/lib COMPONENT - binary_model + binary ) install( FILES model.yaml - stack.yaml - signal_group.yaml + simulation.yaml DESTINATION ${MODEL_PATH}/data COMPONENT - binary_model + binary ) diff --git a/dse/modelc/examples/binary/binary_model.c b/dse/modelc/examples/binary/binary_model.c deleted file mode 100644 index 54facb4..0000000 --- a/dse/modelc/examples/binary/binary_model.c +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2023 Robert Bosch GmbH -// -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include -#include -#include - - -#define ARRAY_LENGTH(array) (sizeof((array)) / sizeof((array)[0])) - - -/* Model Function definitions. A single Model Function is defined. */ -#define MODEL_FUNCTION_NAME "binary_example" -#define MODEL_FUNCTION_STEP_SIZE 0.005 -#define MODEL_FUNCTION_CHANNEL "binary_channel" -#define MODEL_FUNCTION_DO_STEP_FUNC do_step -#define MODEL_FUNCTION_DO_STEP_FUNC_STR "do_step" - - -/* Signals are defined in dynamic_model.yaml, order must match here! */ -typedef enum signal_name_index { - SIGNAL_RAW, - __SIGNAL__COUNT__ -} signal_name_index; - - -/* Signal Vector (binary). */ -static void** signal_value; -static uint32_t* signal_value_size; -static uint32_t* signal_value_buffer_size; - - -/* Model Function do_step() definition. Each Model Function has its own - do_step() and they are registered during model_setup(). */ -int MODEL_FUNCTION_DO_STEP_FUNC(double* model_time, double stop_time) -{ - log_simbus("Model function " MODEL_FUNCTION_DO_STEP_FUNC_STR " called"); - - /* Define some test data. */ - static int index = 0; - static const char* test_data[4] = { - "one", - "two", - "three", - "four", - }; - - /* Print the incoming content of the binary signal. */ - if (signal_value_size[SIGNAL_RAW]) { - /* The binary string may have embedded NULL characters, replace - them before printing the buffer. */ - char* buffer = (char*)signal_value[SIGNAL_RAW]; - for (uint32_t i = 0; i < signal_value_size[SIGNAL_RAW] - 1; i++) { - if (buffer[i] == 0) { - buffer[i] = ' '; - } - } - /* Now print the buffer*/ - log_notice("RECV: %s (buffer size=%u)", signal_value[SIGNAL_RAW], - signal_value_buffer_size[SIGNAL_RAW]); - } - - /* Indicate the binary object/signal was consumed (important!). */ - signal_value_size[SIGNAL_RAW] = 0; - - /* Write some test data to the binary signal. */ - if (index < 4) { - dse_buffer_append(&signal_value[SIGNAL_RAW], - &signal_value_size[SIGNAL_RAW], - &signal_value_buffer_size[SIGNAL_RAW], test_data[index], - strlen(test_data[index]) + 1); - index += 1; - } - - /* Advance the model time. */ - *model_time = stop_time; - - return 0; -} - - -/* Model Setup: a handle to this function will be dynamically loaded by the - Controller and it (this function) will be called to initialise the Model - and its Model Functions. */ -int MODEL_SETUP_FUNC(ModelInstanceSpec* model_instance) -{ - log_notice("Model function " MODEL_SETUP_FUNC_STR " called"); - assert(model_instance); - - int rc = model_function_register(model_instance, MODEL_FUNCTION_NAME, - MODEL_FUNCTION_STEP_SIZE, MODEL_FUNCTION_DO_STEP_FUNC); - if (rc != 0) return rc; - - /* Register channels (and get storage). */ - static ModelChannelDesc channel_desc = { - .name = MODEL_FUNCTION_CHANNEL, - .function_name = MODEL_FUNCTION_NAME, - }; - rc = model_configure_channel(model_instance, &channel_desc); - if (rc != 0) return rc; - if (channel_desc.vector_binary == NULL) { - log_fatal("Binary vector not allocated!"); - } - assert(channel_desc.signal_count == __SIGNAL__COUNT__); - assert(channel_desc.vector_binary); - assert(channel_desc.vector_binary_size); - assert(channel_desc.vector_binary_buffer_size); - signal_value = channel_desc.vector_binary; - signal_value_size = channel_desc.vector_binary_size; - signal_value_buffer_size = channel_desc.vector_binary_buffer_size; - - return 0; -} diff --git a/dse/modelc/examples/binary/model.c b/dse/modelc/examples/binary/model.c new file mode 100644 index 0000000..876b65f --- /dev/null +++ b/dse/modelc/examples/binary/model.c @@ -0,0 +1,106 @@ +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include + + +typedef struct { + SignalVector* sv; + uint32_t index; + char* buffer; + uint32_t buffer_size; +} BinarySignalDesc; + +typedef struct { + ModelDesc model; + /* Scalar Signal Pointers. */ + struct { + double* counter; + } scalars; + /* Binary Signal Indexes. */ + struct { + BinarySignalDesc message; + } binary; +} ExtendedModelDesc; + + +static inline double* _index_scalar( + ExtendedModelDesc* m, const char* v, const char* s) +{ + ModelSignalIndex idx = m->model.index((ModelDesc*)m, v, s); + if (idx.scalar == NULL) log_fatal("Signal not found (%s:%s)", v, s); + return idx.scalar; +} + + +static inline BinarySignalDesc _index_binary( + ExtendedModelDesc* m, const char* v, const char* s) +{ + ModelSignalIndex idx = m->model.index((ModelDesc*)m, v, s); + if (idx.binary == NULL) log_fatal("Signal not found (%s:%s)", v, s); + + BinarySignalDesc ret = { + .sv = &(m->model.sv[idx.vector]), + .index = idx.signal, + }; + return ret; +} + + +ModelDesc* model_create(ModelDesc* model) +{ + /* Extend the ModelDesc object (using a shallow copy). */ + ExtendedModelDesc* m = calloc(1, sizeof(ExtendedModelDesc)); + memcpy(m, model, sizeof(ModelDesc)); + + /* Index the signals that are used by this model. */ + m->scalars.counter = _index_scalar(m, "scalar", "counter"); + m->binary.message = _index_binary(m, "binary", "message"); + + /* Set initial values. */ + *(m->scalars.counter) = 42; + m->binary.message.buffer = calloc(10, sizeof(char)); + m->binary.message.buffer_size = 10; + + /* Return the extended object. */ + return (ModelDesc*)m; +} + + +static inline int _format_message(BinarySignalDesc* b, int v) +{ + return snprintf(b->buffer, b->buffer_size, "count is %d", v); +} + +int model_step(ModelDesc* model, double* model_time, double stop_time) +{ + ExtendedModelDesc* m = (ExtendedModelDesc*)model; + + /* Scalar signals. */ + *(m->scalars.counter) += 1; + /* Binary signals. */ + int len = _format_message(&(m->binary.message), (int)*(m->scalars.counter)); + if (len >= (int)(m->binary.message.buffer_size - 1)) { + m->binary.message.buffer = realloc(m->binary.message.buffer, len + 1); + m->binary.message.buffer_size = len + 1; + _format_message(&(m->binary.message), (int)*(m->scalars.counter)); + } + m->binary.message.sv->reset(m->binary.message.sv, m->binary.message.index); + m->binary.message.sv->append(m->binary.message.sv, m->binary.message.index, + m->binary.message.buffer, strlen(m->binary.message.buffer) + 1); + + *model_time = stop_time; + return 0; +} + + +void model_destroy(ModelDesc* model) +{ + ExtendedModelDesc* m = (ExtendedModelDesc*)model; + if (m->binary.message.buffer) free(m->binary.message.buffer); +} diff --git a/dse/modelc/examples/binary/model.yaml b/dse/modelc/examples/binary/model.yaml index 71b9828..a09a572 100644 --- a/dse/modelc/examples/binary/model.yaml +++ b/dse/modelc/examples/binary/model.yaml @@ -1,21 +1,30 @@ -# Copyright 2023 Robert Bosch GmbH +# Copyright 2024 Robert Bosch GmbH # # SPDX-License-Identifier: Apache-2.0 --- kind: Model metadata: - name: BinaryModel + name: Binary spec: runtime: dynlib: - os: linux arch: amd64 - path: lib/binary_model.so + path: lib/libbinary.so - os: linux arch: x86 - path: lib/binary_model.so + path: lib/libbinary.so + - os: windows + arch: x64 + path: bin/binary.dll + - os: windows + arch: x86 + path: bin/binary.dll channels: - - alias: binary_channel + - alias: scalar + selectors: + channel: scalar_channel + - alias: binary selectors: - channel: network + channel: binary_channel diff --git a/dse/modelc/examples/binary/signal_group.yaml b/dse/modelc/examples/binary/signal_group.yaml deleted file mode 100644 index 0be06f1..0000000 --- a/dse/modelc/examples/binary/signal_group.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - ---- -kind: SignalGroup -metadata: - name: network_signals - labels: - channel: network - model: BinaryModel - annotations: - vector_type: binary - vector_name: network_vector -spec: - signals: - - signal: RAW - annotations: - mime_type: 'application/octet-stream' diff --git a/dse/modelc/examples/binary/simulation.yaml b/dse/modelc/examples/binary/simulation.yaml new file mode 100644 index 0000000..361b4ae --- /dev/null +++ b/dse/modelc/examples/binary/simulation.yaml @@ -0,0 +1,58 @@ +# Copyright 2024 Robert Bosch GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +--- +kind: Stack +metadata: + name: binary_stack +spec: + connection: + transport: + redispubsub: + uri: redis://localhost:6379 + timeout: 60 + models: + - name: simbus + model: + name: simbus + channels: + - name: scalar_channel + expectedModelCount: 1 + - name: binary_channel + expectedModelCount: 1 + - name: binary_inst + uid: 42 + model: + name: Binary + channels: + - name: scalar_channel + alias: scalar + - name: binary_channel + alias: binary +--- +kind: Model +metadata: + name: simbus +--- +kind: SignalGroup +metadata: + name: scalar_channel + labels: + channel: scalar_channel +spec: + signals: + - signal: counter +--- +kind: SignalGroup +metadata: + name: binary_channel + labels: + channel: binary_channel + annotations: + vector_type: binary +spec: + signals: + - signal: message + annotations: + mime_type: 'application/octet-stream' diff --git a/dse/modelc/examples/binary/stack.yaml b/dse/modelc/examples/binary/stack.yaml deleted file mode 100644 index a3efc06..0000000 --- a/dse/modelc/examples/binary/stack.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - ---- -kind: Stack -metadata: - name: binary_model_stack -spec: - connection: - transport: - redispubsub: - uri: redis://localhost:6379 - timeout: 60 - models: - - name: simbus - model: - name: simbus - channels: - - name: network - expectedModelCount: 2 - - name: binary_model_instance - uid: 42 - model: - name: BinaryModel - channels: - - name: network - alias: binary_channel - - name: second_binary_model_instance - uid: 24 - model: - name: BinaryModel - channels: - - name: network - alias: binary_channel ---- -kind: Model -metadata: - name: simbus diff --git a/dse/modelc/examples/dynamic/CMakeLists.txt b/dse/modelc/examples/dynamic/CMakeLists.txt deleted file mode 100644 index 424fae3..0000000 --- a/dse/modelc/examples/dynamic/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.21) - -project(DynamicModel - DESCRIPTION "ModelC - Example Dynamic Model." - HOMEPAGE_URL "${PROJECT_URL}" -) -set(PROJECT_VERSION ${VERSION}) - -include(FetchContent) - -set(MODEL_PATH "examples/dynamic") -set(CMAKE_SHARED_LIBRARY_PREFIX "") - -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_STANDARD_REQUIRED TRUE) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_C_FLAGS_DEBUG "-g -ggdb") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O3") -list(APPEND C_CXX_WARNING_FLAGS - -Wall - -W - -Wwrite-strings - -Wno-missing-field-initializers - -Wno-misleading-indentation -) -add_compile_options(${C_CXX_WARNING_FLAGS}) - - -# External Project - DSE C Lib -# ---------------------------- -FetchContent_Declare(dse_clib - URL $ENV{DSE_CLIB_URL} - HTTP_USERNAME $ENV{GHE_USER} - HTTP_PASSWORD $ENV{GHE_TOKEN} -) -FetchContent_MakeAvailable(dse_clib) -set(DSE_CLIB_SOURCE_DIR ${dse_clib_SOURCE_DIR}/dse) -set(DSE_CLIB_SOURCE_FILES ) -set(DSE_CLIB_INCLUDE_DIR "${DSE_CLIB_SOURCE_DIR}/..") - - - -# Targets -# ======= - -# Target - Dynamic Model -# ---------------------- -add_library(dynamic_model SHARED - dynamic_model.c -) -target_include_directories(dynamic_model - PRIVATE - ${DSE_CLIB_INCLUDE_DIR} - ../../../.. -) -target_link_libraries(dynamic_model - PRIVATE - $<$:${modelc_link_lib}> -) -install(TARGETS dynamic_model - LIBRARY DESTINATION - ${MODEL_PATH}/lib - COMPONENT - dynamic_model -) -install( - FILES - model.yaml - stack.yaml - signal_group.yaml - DESTINATION - ${MODEL_PATH}/data - COMPONENT - dynamic_model -) diff --git a/dse/modelc/examples/dynamic/README.md b/dse/modelc/examples/dynamic/README.md deleted file mode 100644 index be350ce..0000000 --- a/dse/modelc/examples/dynamic/README.md +++ /dev/null @@ -1,36 +0,0 @@ - - -### Run the Example - -##### Terminal 1: Redis - -```bash -$ docker run --rm -it --name redis -p 6379:6379 redis & -``` - -##### Terminal 2: Standalone SimBus - -```bash -$ export SIMBUS_EXE=$(pwd)/libmodelcapi/build/_out/bin/simbus -$ export MODEL_SANDBOX_DIR=$(pwd)/examples/dynamic_model/build/_out -$ export YAML_DIR=${MODEL_SANDBOX_DIR}/data/yaml/dynamic_model - -$ cd ${MODEL_SANDBOX_DIR} -$ ${SIMBUS_EXE} --name simbus ${YAML_DIR}/dynamic_model.yaml -``` - -##### Terminal 3: Dynamically Linked Model - -```bash -$ export MODELC_EXE=$(pwd)/libmodelcapi/build/_out/bin/modelc -$ export MODEL_SANDBOX_DIR=$(pwd)/examples/dynamic_model/build/_out -$ export YAML_DIR=${MODEL_SANDBOX_DIR}/data/yaml/dynamic_model - -$ cd ${MODEL_SANDBOX_DIR}; \ - ${MODELC_EXE} --name dynamic_model_instance ${YAML_DIR}/dynamic_model.yaml; \ - cd - -``` diff --git a/dse/modelc/examples/dynamic/dynamic_model.c b/dse/modelc/examples/dynamic/dynamic_model.c deleted file mode 100644 index 70c45f3..0000000 --- a/dse/modelc/examples/dynamic/dynamic_model.c +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2023 Robert Bosch GmbH -// -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include -#include - - -#define ARRAY_LENGTH(array) (sizeof((array)) / sizeof((array)[0])) - - -/* Model Function definitions. */ -#define MODEL_FUNCTION_NAME "example" -#define MODEL_FUNCTION_DO_STEP do_step -#define MODEL_FUNCTION_STEP_SIZE 0.005 -#define MODEL_FUNCTION_CHANNEL "model_channel" - - -/* Signals are defined in dynamic_model.yaml, order must match here! */ -typedef enum signal_name_index { - SIGNAL_FOO, - SIGNAL_BAR, - __SIGNAL__COUNT__ -} signal_name_index; - - -/* Signal Vector definition (storage allocated during model_setup()). */ -static double* signal_value; - - -/* Model Function do_step() definition. Each Model Function has its own - do_step() and they are registered during model_setup(). */ -int MODEL_FUNCTION_DO_STEP(double* model_time, double stop_time) -{ - assert(signal_value); - - signal_value[SIGNAL_FOO] += 1.2; - signal_value[SIGNAL_BAR] += 4.2; - *model_time = stop_time; - - return 0; -} - - -/* Model Setup: a handle to this function will be dynamically loaded by the - Controller and it (this function) will be called to initialise the Model - and its Model Functions. */ -int MODEL_SETUP_FUNC(ModelInstanceSpec* model_instance) -{ - log_notice("Model function " MODEL_SETUP_FUNC_STR " called"); - assert(model_instance); - - int rc = model_function_register(model_instance, MODEL_FUNCTION_NAME, - MODEL_FUNCTION_STEP_SIZE, MODEL_FUNCTION_DO_STEP); - if (rc != 0) return rc; - - /* Register channels (and get storage). */ - static ModelChannelDesc channel_desc = { - .name = MODEL_FUNCTION_CHANNEL, - .function_name = MODEL_FUNCTION_NAME, - }; - rc = model_configure_channel(model_instance, &channel_desc); - if (rc != 0) return rc; - assert(channel_desc.signal_count == __SIGNAL__COUNT__); - assert(channel_desc.vector_double); - signal_value = channel_desc.vector_double; - - return 0; -} - - -/* Model Exit: OPTIONAL! a handle to this function, if present, will be - dynamically loaded by the Controller and called before the Controller exits - the simulation (and sends the ModelExit message to the SimBus). */ -int MODEL_EXIT_FUNC(ModelInstanceSpec* model_instance) -{ - log_notice("Model function " MODEL_EXIT_FUNC_STR " called"); - if (model_instance) { - /* The parameter model_instance may, in some circumstances, not - be set. Therefore check before using. */ - } - - return 0; -} diff --git a/dse/modelc/examples/dynamic/signal_group.yaml b/dse/modelc/examples/dynamic/signal_group.yaml deleted file mode 100644 index 35525c3..0000000 --- a/dse/modelc/examples/dynamic/signal_group.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - ---- -kind: SignalGroup -metadata: - name: test_signals - labels: - channel: test - model: dynamic_model -spec: - signals: - - signal: foo - - signal: bar diff --git a/dse/modelc/examples/extended/CMakeLists.txt b/dse/modelc/examples/extended/CMakeLists.txt new file mode 100644 index 0000000..17cd3e2 --- /dev/null +++ b/dse/modelc/examples/extended/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright 2024 Robert Bosch GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.21) + +project(Extended) +set(MODEL_PATH "examples/extended") + +include(FetchContent) +FetchContent_Declare(dse_clib + URL $ENV{DSE_CLIB_URL} + HTTP_USERNAME $ENV{GHE_USER} + HTTP_PASSWORD $ENV{GHE_TOKEN} +) +FetchContent_MakeAvailable(dse_clib) +set(DSE_CLIB_INCLUDE_DIR ${dse_clib_SOURCE_DIR}) + +add_library(extended SHARED + model.c +) +target_include_directories(extended + PRIVATE + ${DSE_CLIB_INCLUDE_DIR} + ../../../.. +) +target_link_libraries(extended + PRIVATE + $<$:${modelc_link_lib}> +) +install(TARGETS extended + LIBRARY DESTINATION + ${MODEL_PATH}/lib + COMPONENT + extended +) +install( + FILES + model.yaml + simulation.yaml + DESTINATION + ${MODEL_PATH}/data + COMPONENT + extended +) diff --git a/dse/modelc/examples/extended/model.c b/dse/modelc/examples/extended/model.c new file mode 100644 index 0000000..ebe14f0 --- /dev/null +++ b/dse/modelc/examples/extended/model.c @@ -0,0 +1,61 @@ +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include + + +typedef struct { + ModelDesc model; + /* Signal Pointers. */ + struct { + double* counter; + double* odd; + double* even; + } signals; +} ExtendedModelDesc; + + +static inline double* _index(ExtendedModelDesc* m, const char* v, const char* s) +{ + ModelSignalIndex idx = m->model.index((ModelDesc*)m, v, s); + if (idx.scalar == NULL) log_fatal("Signal not found (%s:%s)", v, s); + return idx.scalar; +} + + +ModelDesc* model_create(ModelDesc* model) +{ + /* Extend the ModelDesc object (using a shallow copy). */ + ExtendedModelDesc* m = calloc(1, sizeof(ExtendedModelDesc)); + memcpy(m, model, sizeof(ModelDesc)); + + /* Index the signals that are used by this model. */ + m->signals.counter = _index(m, "data", "counter"); + m->signals.odd = _index(m, "data", "odd"); + m->signals.even = _index(m, "data", "even"); + + /* Set initial values. */ + *(m->signals.counter) = 42; + *(m->signals.odd) = false; + *(m->signals.even) = true; + + /* Return the extended object. */ + return (ModelDesc*)m; +} + + +int model_step(ModelDesc* model, double* model_time, double stop_time) +{ + ExtendedModelDesc* m = (ExtendedModelDesc*)model; + *(m->signals.counter) += 1; + *(m->signals.odd) = (int)(*(m->signals.counter)) % 2 ? true : false; + *(m->signals.even) = (int)(*(m->signals.counter)) % 2 ? false : true; + + *model_time = stop_time; + return 0; +} diff --git a/dse/modelc/examples/dynamic/model.yaml b/dse/modelc/examples/extended/model.yaml similarity index 52% rename from dse/modelc/examples/dynamic/model.yaml rename to dse/modelc/examples/extended/model.yaml index b3125c3..8cd8caf 100644 --- a/dse/modelc/examples/dynamic/model.yaml +++ b/dse/modelc/examples/extended/model.yaml @@ -1,27 +1,27 @@ -# Copyright 2023 Robert Bosch GmbH +# Copyright 2024 Robert Bosch GmbH # # SPDX-License-Identifier: Apache-2.0 --- kind: Model metadata: - name: DynamicModel + name: Extended spec: runtime: dynlib: - os: linux arch: amd64 - path: lib/dynamic_model.so + path: lib/libextended.so - os: linux arch: x86 - path: lib/dynamic_model.so + path: lib/libextended.so - os: windows arch: x64 - path: bin/dynamic_model.dll + path: bin/extended.dll - os: windows arch: x86 - path: bin/dynamic_model.dll + path: bin/extended.dll channels: - - alias: model_channel + - alias: data selectors: - channel: test + side: data diff --git a/dse/modelc/examples/extended/simulation.yaml b/dse/modelc/examples/extended/simulation.yaml new file mode 100644 index 0000000..f96a5a2 --- /dev/null +++ b/dse/modelc/examples/extended/simulation.yaml @@ -0,0 +1,43 @@ +# Copyright 2024 Robert Bosch GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +--- +kind: Stack +metadata: + name: extended_stack +spec: + connection: + transport: + redispubsub: + uri: redis://localhost:6379 + timeout: 60 + models: + - name: simbus + model: + name: simbus + channels: + - name: data_channel + expectedModelCount: 1 + - name: extended_inst + uid: 42 + model: + name: Extended + channels: + - name: data_channel + alias: data +--- +kind: Model +metadata: + name: simbus +--- +kind: SignalGroup +metadata: + name: data + labels: + side: data +spec: + signals: + - signal: counter + - signal: odd + - signal: even diff --git a/dse/modelc/examples/gateway/gateway.c b/dse/modelc/examples/gateway/gateway.c index 61b6e16..f081151 100644 --- a/dse/modelc/examples/gateway/gateway.c +++ b/dse/modelc/examples/gateway/gateway.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include #include diff --git a/dse/modelc/examples/minimal/CMakeLists.txt b/dse/modelc/examples/minimal/CMakeLists.txt new file mode 100644 index 0000000..e07d159 --- /dev/null +++ b/dse/modelc/examples/minimal/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2024 Robert Bosch GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.21) + +project(Minimal) +set(MODEL_PATH "examples/minimal") + +add_library(minimal SHARED + model.c +) +target_include_directories(minimal + PRIVATE + ../../../.. +) +target_link_libraries(minimal + PRIVATE + $<$:${modelc_link_lib}> +) +install(TARGETS minimal + LIBRARY DESTINATION + ${MODEL_PATH}/lib + COMPONENT + minimal +) +install( + FILES + model.yaml + simulation.yaml + DESTINATION + ${MODEL_PATH}/data + COMPONENT + minimal +) diff --git a/dse/modelc/examples/minimal/model.c b/dse/modelc/examples/minimal/model.c new file mode 100644 index 0000000..4ce7914 --- /dev/null +++ b/dse/modelc/examples/minimal/model.c @@ -0,0 +1,16 @@ +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include + +int model_step(ModelDesc* m, double* model_time, double stop_time) +{ + ModelSignalIndex counter = m->index(m, "data", "counter"); + if (counter.scalar == NULL) return -EINVAL; + *(counter.scalar) += 1; + *model_time = stop_time; + return 0; +} diff --git a/dse/modelc/examples/minimal/model.yaml b/dse/modelc/examples/minimal/model.yaml new file mode 100644 index 0000000..1718cfe --- /dev/null +++ b/dse/modelc/examples/minimal/model.yaml @@ -0,0 +1,27 @@ +# Copyright 2024 Robert Bosch GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +--- +kind: Model +metadata: + name: Minimal +spec: + runtime: + dynlib: + - os: linux + arch: amd64 + path: lib/libminimal.so + - os: linux + arch: x86 + path: lib/libminimal.so + - os: windows + arch: x64 + path: bin/minimal.dll + - os: windows + arch: x86 + path: bin/minimal.dll + channels: + - alias: data + selectors: + side: data diff --git a/dse/modelc/examples/dynamic/stack.yaml b/dse/modelc/examples/minimal/simulation.yaml similarity index 55% rename from dse/modelc/examples/dynamic/stack.yaml rename to dse/modelc/examples/minimal/simulation.yaml index 9aa5a28..deb856c 100644 --- a/dse/modelc/examples/dynamic/stack.yaml +++ b/dse/modelc/examples/minimal/simulation.yaml @@ -1,11 +1,11 @@ -# Copyright 2023 Robert Bosch GmbH +# Copyright 2024 Robert Bosch GmbH # # SPDX-License-Identifier: Apache-2.0 --- kind: Stack metadata: - name: dynamic_model_stack + name: minimal_stack spec: connection: transport: @@ -17,16 +17,25 @@ spec: model: name: simbus channels: - - name: test + - name: data_channel expectedModelCount: 1 - - name: dynamic_model_instance + - name: minimal_inst uid: 42 model: - name: DynamicModel + name: Minimal channels: - - name: test - alias: model_channel + - name: data_channel + alias: data --- kind: Model metadata: name: simbus +--- +kind: SignalGroup +metadata: + name: data + labels: + side: data +spec: + signals: + - signal: counter diff --git a/dse/modelc/examples/stacked/CMakeLists.txt b/dse/modelc/examples/stacked/CMakeLists.txt deleted file mode 100644 index 2337df9..0000000 --- a/dse/modelc/examples/stacked/CMakeLists.txt +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.21) - -project(StackedModel - DESCRIPTION "ModelC - Example Stacked Model." - HOMEPAGE_URL "${PROJECT_URL}" -) -set(PROJECT_VERSION ${VERSION}) - -include(FetchContent) - -set(MODEL_PATH "examples/stacked") -set(CMAKE_SHARED_LIBRARY_PREFIX "") - -set(CMAKE_C_STANDARD 99) -set(CMAKE_C_STANDARD_REQUIRED TRUE) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(CMAKE_C_FLAGS_DEBUG "-g -ggdb") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O3") -list(APPEND C_CXX_WARNING_FLAGS - -Wall - -W - -Wwrite-strings - -Wno-missing-field-initializers - -Wno-misleading-indentation -) -add_compile_options(${C_CXX_WARNING_FLAGS}) - - -# External Project - DSE C Lib -# ---------------------------- -FetchContent_Declare(dse_clib - URL $ENV{DSE_CLIB_URL} - HTTP_USERNAME $ENV{GHE_USER} - HTTP_PASSWORD $ENV{GHE_TOKEN} -) -FetchContent_MakeAvailable(dse_clib) -set(DSE_CLIB_SOURCE_DIR ${dse_clib_SOURCE_DIR}/dse) -set(DSE_CLIB_SOURCE_FILES ) -set(DSE_CLIB_INCLUDE_DIR "${DSE_CLIB_SOURCE_DIR}/..") - - - -# Targets -# ======= - -# Target - stacked_one -# ---------------------- -add_library(stacked_one SHARED - stacked_model.c -) -target_include_directories(stacked_one - PRIVATE - ${DSE_CLIB_INCLUDE_DIR} - ../../../.. -) -target_link_libraries(stacked_one - PRIVATE - $<$:${modelc_link_lib}> -) -install(TARGETS stacked_one - LIBRARY DESTINATION - ${MODEL_PATH}/lib - COMPONENT - stacked_one -) - - -# Target - stacked_two -# ---------------------- -add_library(stacked_two SHARED - stacked_model.c -) -target_include_directories(stacked_two - PRIVATE - ${DSE_CLIB_INCLUDE_DIR} - ../../../.. -) -target_link_libraries(stacked_two - PRIVATE - $<$:${modelc_link_lib}> -) -install(TARGETS stacked_two - LIBRARY DESTINATION - ${MODEL_PATH}/lib - COMPONENT - stacked_two -) - - - -install( - FILES - model.yaml - stack.yaml - signal_group.yaml - DESTINATION - ${MODEL_PATH}/data -) diff --git a/dse/modelc/examples/stacked/README.md b/dse/modelc/examples/stacked/README.md deleted file mode 100644 index 78373f1..0000000 --- a/dse/modelc/examples/stacked/README.md +++ /dev/null @@ -1,7 +0,0 @@ - - -> Note: This model is used for testing stacked models in a single ModelC instance. diff --git a/dse/modelc/examples/stacked/model.yaml b/dse/modelc/examples/stacked/model.yaml deleted file mode 100644 index d4597a5..0000000 --- a/dse/modelc/examples/stacked/model.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - ---- -kind: Model -metadata: - name: StackedModelOne -spec: - runtime: - dynlib: - - os: linux - arch: amd64 - path: lib/stacked_one.so - - os: linux - arch: x86 - path: lib/stacked_one.so - - os: windows - arch: x64 - path: bin/stacked_one.dll - - os: windows - arch: x86 - path: bin/stacked_one.dll - channels: - - alias: model_channel - selectors: - channel: test ---- -kind: Model -metadata: - name: StackedModelTwo -spec: - runtime: - dynlib: - - os: linux - arch: amd64 - path: lib/stacked_two.so - - os: linux - arch: x86 - path: lib/stacked_two.so - - os: windows - arch: x64 - path: bin/stacked_two.dll - - os: windows - arch: x86 - path: bin/stacked_two.dll - channels: - - alias: model_channel - selectors: - channel: test diff --git a/dse/modelc/examples/stacked/signal_group.yaml b/dse/modelc/examples/stacked/signal_group.yaml deleted file mode 100644 index 7ae9e49..0000000 --- a/dse/modelc/examples/stacked/signal_group.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - ---- -kind: SignalGroup -metadata: - name: test_signals - labels: - channel: test - model: stacked_model -spec: - signals: - - signal: foo - - signal: bar diff --git a/dse/modelc/examples/stacked/stack.yaml b/dse/modelc/examples/stacked/stack.yaml deleted file mode 100644 index 34b8c85..0000000 --- a/dse/modelc/examples/stacked/stack.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2023 Robert Bosch GmbH -# -# SPDX-License-Identifier: Apache-2.0 - ---- -kind: Stack -metadata: - name: stacked_model -spec: - connection: - transport: - redispubsub: - uri: redis://localhost:6379 - timeout: 60 - models: - - name: simbus - model: - name: simbus - channels: - - name: test - expectedModelCount: 2 - - name: stacked_one - uid: 43 - model: - name: StackedModelOne - channels: - - name: test - alias: model_channel - - name: stacked_two - uid: 44 - model: - name: StackedModelTwo - channels: - - name: test - alias: model_channel ---- -kind: Model -metadata: - name: simbus diff --git a/dse/modelc/examples/stacked/stacked_model.c b/dse/modelc/examples/stacked/stacked_model.c deleted file mode 100644 index 05ea63c..0000000 --- a/dse/modelc/examples/stacked/stacked_model.c +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2023 Robert Bosch GmbH -// -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include -#include - - -/* Model Function definitions. */ -#define MODEL_FUNCTION_NAME "example" -#define MODEL_FUNCTION_DO_STEP do_step -#define MODEL_FUNCTION_STEP_SIZE 0.005 -#define MODEL_FUNCTION_CHANNEL "model_channel" - - -/* Signals are defined in signal_group.yaml, order must match here! */ -typedef enum signal_name_index { - SIGNAL_FOO, - SIGNAL_BAR, - __SIGNAL__COUNT__ -} signal_name_index; - -static double* signal_value; - - -int MODEL_FUNCTION_DO_STEP(double* model_time, double stop_time) -{ - assert(signal_value); - - signal_value[SIGNAL_FOO] += 1.2; - signal_value[SIGNAL_BAR] += 4.2; - *model_time = stop_time; - - return 0; -} - - -int MODEL_SETUP_FUNC(ModelInstanceSpec* model_instance) -{ - log_notice("Model function " MODEL_SETUP_FUNC_STR " called"); - assert(model_instance); - - int rc = model_function_register(model_instance, MODEL_FUNCTION_NAME, - MODEL_FUNCTION_STEP_SIZE, MODEL_FUNCTION_DO_STEP); - if (rc != 0) return rc; - - /* Register channels (and get storage). */ - static ModelChannelDesc channel_desc = { - .name = MODEL_FUNCTION_CHANNEL, - .function_name = MODEL_FUNCTION_NAME, - }; - rc = model_configure_channel(model_instance, &channel_desc); - if (rc != 0) return rc; - assert(channel_desc.signal_count == __SIGNAL__COUNT__); - assert(channel_desc.vector_double); - signal_value = channel_desc.vector_double; - - return 0; -} - - -int MODEL_EXIT_FUNC(ModelInstanceSpec* model_instance) -{ - assert(model_instance); - log_notice("Model function " MODEL_EXIT_FUNC_STR " called"); - return 0; -} diff --git a/dse/modelc/mcl.h b/dse/modelc/mcl.h index 30419bd..3755d46 100644 --- a/dse/modelc/mcl.h +++ b/dse/modelc/mcl.h @@ -5,9 +5,10 @@ #ifndef DSE_MODELC_MCL_H_ #define DSE_MODELC_MCL_H_ -#include #include +#include #include +#include /** @@ -84,7 +85,7 @@ typedef struct MclModelDesc MclModelDesc; /* MCL Strategy methods (generic model provided). */ -typedef int (*MclExecuteMethod)(MclStrategyAction action); +typedef int (*MclExecuteMethod)(ModelDesc* model, MclStrategyAction action); /* MCL Strategy handler functions. */ @@ -154,14 +155,11 @@ typedef struct MclModelDesc { typedef struct MclInstanceDesc { ModelInstanceSpec* model_instance; /* Instance Properties. */ - ModelChannelDesc* channel; + SignalVector* mcl_channel_sv; MclStrategyDesc* strategy; HashList models; /* MclModelDesc */ } MclInstanceDesc; -/* This portion of the API is implemented by an MCL. */ -DLL_PUBLIC int MCL_SETUP_FUNC(void); - /* mcl.c - Model Compatibility Library (MCL) interface.*/ DLL_PUBLIC void mcl_register_strategy(MclStrategyDesc* strategy); diff --git a/dse/modelc/model.h b/dse/modelc/model.h index 8f1a641..37ec038 100644 --- a/dse/modelc/model.h +++ b/dse/modelc/model.h @@ -1,4 +1,4 @@ -// Copyright 2023 Robert Bosch GmbH +// Copyright 2024 Robert Bosch GmbH // // SPDX-License-Identifier: Apache-2.0 @@ -7,111 +7,79 @@ #include #include -#include -#include -#include #ifndef DLL_PUBLIC -#define DLL_PUBLIC __attribute__((visibility("default"))) +#if defined _WIN32 || defined __CYGWIN__ +#ifdef DLL_BUILD +#define DLL_PUBLIC __declspec(dllexport) +#else +#define DLL_PUBLIC __declspec(dllimport) +#endif +#else +#define DLL_PUBLIC __attribute__((visibility("default"))) +#endif #endif #ifndef DLL_PRIVATE +#if defined _WIN32 || defined __CYGWIN__ +#define DLL_PRIVATE +#else #define DLL_PRIVATE __attribute__((visibility("hidden"))) #endif +#endif + + +#define __MODELC_ERROR_OFFSET (2000) +#define MODEL_DEFAULT_STEP_SIZE 0.0005 +#define MODEL_CREATE_FUNC_NAME "model_create" +#define MODEL_STEP_FUNC_NAME "model_step" +#define MODEL_DESTROY_FUNC_NAME "model_destroy" + + +typedef struct SimulationSpec SimulationSpec; +typedef struct ModelInstanceSpec ModelInstanceSpec; +typedef struct SignalVector SignalVector; +typedef struct ModelDesc ModelDesc; +typedef struct ModelSignalIndex ModelSignalIndex; /** Model API ========= -The Model API allows model developers and integrators to interface with a -Dynamic Simulation Environment via a connection with a Simulation Bus. -*/ +The Model API allows model developers and integrators to implement models which +can be connected to a Simulation Bus. +Models are able to exchange signals with other models via this connection to +a Simulation Bus. +A runtime environment, such as the ModelC Runtime/Importer, will load the +model and also manages the connection with the Simulation Bus. -#define __MODELC_ERROR_OFFSET (2000) - -#define MODEL_SETUP_FUNC model_setup -#define MODEL_SETUP_FUNC_STR "model_setup" - -#define MODEL_EXIT_FUNC model_exit -#define MODEL_EXIT_FUNC_STR "model_exit" - - -typedef struct ModelDefinitionSpec { - const char* name; - /* Path to the Model Package (i.e. where model.yaml is found). */ - const char* path; - /* Path to the Model Lib, relative to path (above). */ - const char* file; - /* Combined path and file for the Model Lib. */ - char* full_path; - /* Reference to parsed YAML Documents. */ - YamlNode* doc; - YamlNode* channels; -} ModelDefinitionSpec; - - -typedef struct ModelInstanceSpec { - uint32_t uid; - char* name; - ModelDefinitionSpec model_definition; - /* Reference to parsed YAML Documents. */ - YamlNode* spec; - YamlNode* propagators; - YamlDocList* yaml_doc_list; - /* Private data of the specific Model Instance. */ - void* private; -} ModelInstanceSpec; - - -typedef struct SimulationSpec { - /* Transport. */ - const char* transport; - char* uri; - uint32_t uid; - double timeout; - /* Simulation. */ - double step_size; - double end_time; - /* Model Instances, list, last entry all values set NULL (EOL detect). */ - ModelInstanceSpec* instance_list; -} SimulationSpec; - - -typedef struct ModelChannelDesc { - const char* name; - const char* function_name; - /* Reference to the parsed signal names. */ - const char** signal_names; - uint32_t signal_count; - /* Indicate if this Channel is connected to a Propagator Model. */ - bool propagator_source_channel; - bool propagator_target_channel; - /* Allocated vector table (one only depending on type). */ - double* vector_double; - void** vector_binary; - /* Additional vector tables supporting vector_binary. */ - uint32_t* vector_binary_size; /* Size of binary object. */ - uint32_t* vector_binary_buffer_size; /* Size of allocated buffer. */ -} ModelChannelDesc; - - -typedef struct ChannelSpec { - const char* name; - const char* alias; - /* Private data. */ - void* private; -} ChannelSpec; +The Model API provides two simple interfaces which facilitate the development +of models; the Model Interface which is concerned with the model lifecycle; and +the Signal Interface which facilitates signal exchange. + + +Model Interface +--------------- + +The Model Interface provides the necessary types, methods and objects required +for implementing a model. Such a model can easily participate in a simulation +by being connecting to a Simulation Bus (using the ModelC Importer) and then +exchanging signals with other models in that simulation by using the +provided SignalVector objects (which represent those signals). + +Additionally, model implementers may extend or modify the Model Interface +to support more complex integrations. -/** Signal Vector Interface -======================= +----------------------- Models exchange signals via the Simulation Bus using a Signal Vector. Signal -Vectors represent a logical grouping of signals (i.e. a collection of signals -belonging to an ECU interface or bus), they are defined by a `SignalGroup` -schema kind, and a Signal Vector can represent either scalar or binary values. +Vectors represent a logical grouping of signals (e.g. a collection of signals +belonging to an ECU interface or bus). They are defined by a `SignalGroup` +schema kind and may be configured to represent either either scalar +(double, int, bool) or binary values. Component Diagram @@ -119,23 +87,28 @@ Component Diagram -![](model-signal-vector.png) +![](model-interface.png) + + +Example (Model Interface) +------- + +{{< readfile file="../examples/model_interface.c" code="true" lang="c" >}} -Example +Example (Signal Vector Interface) ------- -{{< readfile file="../examples/model_signalvector.c" code="true" lang="c" >}} +{{< readfile file="../examples/signalvector_interface.c" code="true" lang="c" >}} */ -typedef struct SignalVector SignalVector; + +/* Model Interface. */ + +typedef ModelDesc* (*ModelCreate)(ModelDesc* m); +typedef int (*ModelStep)(ModelDesc* m, double* model_time, double stop_time); +typedef void (*ModelDestroy)(ModelDesc* m); +typedef ModelSignalIndex (*ModelIndex)(ModelDesc* m, const char* vname, + const char* sname); + + +typedef struct ModelVTable { + ModelCreate create; + ModelStep step; + ModelDestroy destroy; + ModelIndex index; +} ModelVTable; + + +typedef struct ModelDesc { + ModelVTable vtable; + ModelIndex index; + SimulationSpec* sim; + ModelInstanceSpec* mi; + SignalVector* sv; +} ModelDesc; + + +typedef struct ModelSignalIndex { + /* References, only set if index is valid. */ + SignalVector* sv; + double* scalar; + void** binary; + /* Indexes to the SignalVector object. */ + uint32_t vector; + uint32_t signal; +} ModelSignalIndex; + + +/* Implemented by Model. */ +DLL_PUBLIC ModelDesc* model_create(ModelDesc* m); +DLL_PUBLIC int model_step(ModelDesc* m, double* model_time, double stop_time); +DLL_PUBLIC void model_destroy(ModelDesc* m); + + +/* Provided by ModelC (via ModelIndex in ModelDesc and also ModelVTable). */ +DLL_PUBLIC ModelSignalIndex model_index_( + ModelDesc* model, const char* vname, const char* sname); + + +/* Signal Interface. */ typedef int (*BinarySignalAppendFunc)( SignalVector* sv, uint32_t index, void* data, uint32_t len); @@ -164,6 +192,7 @@ typedef void* (*BinarySignalCodecFunc)(SignalVector* sv, uint32_t index); typedef const char* (*SignalAnnotationGetFunc)( SignalVector* sv, uint32_t index, const char* name); + typedef struct SignalVectorVTable { BinarySignalAppendFunc append; BinarySignalResetFunc reset; @@ -172,6 +201,7 @@ typedef struct SignalVectorVTable { BinarySignalCodecFunc codec; } SignalVectorVTable; + typedef struct SignalVector { const char* name; const char* alias; @@ -203,136 +233,14 @@ typedef struct SignalVector { } SignalVector; -/** -Model Interface -=============== - -The Model Interface must be implemented by a Model. It includes the functions -necessary for a Model to be loaded and executed in the Dynamic Simulation -Environment. - - -Component Diagram ------------------ - - -![](model-interface.png) - - -Example -------- - -{{< readfile file="../examples/model_interface.c" code="true" lang="c" >}} - -*/ - -typedef int (*ModelSetupHandler)(ModelInstanceSpec* model_instance); -typedef int (*ModelDoStepHandler)(double* model_time, double stop_time); -typedef int (*ModelExitHandler)(ModelInstanceSpec* model_instance); - -typedef struct ModelInterfaceVTable { - ModelSetupHandler setup; - ModelDoStepHandler step; - ModelExitHandler exit; -} ModelInterfaceVTable; - -DLL_PUBLIC int MODEL_SETUP_FUNC(ModelInstanceSpec* model_instance); - - -/* Loader/Runner API Definition */ - -typedef struct ModelCArguments { - const char* transport; - char* uri; - const char* host; - uint32_t port; - double timeout; - uint8_t log_level; - double step_size; - double end_time; - uint32_t uid; - const char* name; - const char* file; - const char* path; - /* Parsed YAML Files. */ - YamlDocList* yaml_doc_list; - /* Allow detection of CLI provided arguments. */ - int timeout_set_by_cli; - int log_level_set_by_cli; - /* MStep "hidden" arguments. */ - uint32_t steps; -} ModelCArguments; - - -/* model.c - Model Interface. */ -DLL_PUBLIC int model_function_register(ModelInstanceSpec* model_instance, - const char* model_function_name, double step_size, - ModelDoStepHandler do_step_handler); -DLL_PUBLIC int model_configure_channel( - ModelInstanceSpec* model_instance, ModelChannelDesc* channel_desc); -DLL_PUBLIC ChannelSpec* model_build_channel_spec( - ModelInstanceSpec* model_instance, const char* channel_name); - - -/* signal.c - Signal Vector Interface. */ -DLL_PUBLIC SignalVector* model_sv_create(ModelInstanceSpec* mi); -DLL_PUBLIC void model_sv_destroy(SignalVector* sv); - -/* ncodec.c - Stream Interface (for NCodec). */ -DLL_PRIVATE void* model_sv_stream_create(SignalVector* sv, uint32_t idx); -DLL_PRIVATE void model_sv_stream_destroy(void* stream); - - -/* modelc.c - Runtime Interface (i.e. ModelC.exe). */ -DLL_PUBLIC int modelc_configure(ModelCArguments* args, SimulationSpec* sim); -DLL_PUBLIC ModelInstanceSpec* modelc_get_model_instance( - SimulationSpec* sim, const char* name); -DLL_PUBLIC int modelc_run(SimulationSpec* sim, bool run_async); -DLL_PUBLIC void modelc_exit(SimulationSpec* sim); -DLL_PUBLIC int modelc_sync(SimulationSpec* sim); -DLL_PUBLIC void modelc_shutdown(void); - - -/* modelc_debug.c - Debug Interface. */ -DLL_PUBLIC int modelc_step(ModelInstanceSpec* model_instance, double step_size); - - -/* modelc_args.c - CLI argument parsing routines. */ -DLL_PUBLIC void modelc_set_default_args(ModelCArguments* args, - const char* model_instance_name, double step_size, double end_time); -DLL_PUBLIC void modelc_parse_arguments( - ModelCArguments* args, int argc, char** argv, const char* doc_string); +/* Provided by ModelC (virtual methods of SignalVectorVTable). */ +DLL_PUBLIC int signal_append(SignalVector* sv, uint32_t index, + void* data, uint32_t len); +DLL_PUBLIC int signal_reset(SignalVector* sv, uint32_t index); +DLL_PUBLIC int signal_release(SignalVector* sv, uint32_t index); +DLL_PUBLIC void* signal_codec(SignalVector* sv, uint32_t index); +DLL_PUBLIC const char* signal_annotation(SignalVector* sv, uint32_t index, + const char* name); #endif // DSE_MODELC_MODEL_H_ diff --git a/dse/modelc/model/gateway.c b/dse/modelc/model/gateway.c index 13aef4e..64a6ec3 100644 --- a/dse/modelc/model/gateway.c +++ b/dse/modelc/model/gateway.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,81 +16,26 @@ /* Gateway Model Functions * These represent the Model Interface of the Gateway. */ - -static HashList __mcd_list; /* Storage for ModelChannelDesc objects. */ -static double __gw_step_size; - - -static void* channel_spec_generator(ModelInstanceSpec* mi, void* data) -{ - UNUSED(mi); - - const char* name = dse_yaml_get_scalar((YamlNode*)data, "name"); - const char* alias = dse_yaml_get_scalar((YamlNode*)data, "alias"); - if (name || alias) { - ChannelSpec* cs = calloc(1, sizeof(ChannelSpec)); - cs->name = name; - cs->alias = alias; - return cs; /* Caller to free. */ - } - return NULL; -} - - -DLL_PRIVATE int __model_gw_step__(double* model_time, double stop_time) +DLL_PRIVATE int __model_gw_step__(ModelDesc* model, double* model_time, double stop_time) { + UNUSED(model); *model_time = stop_time; - return 0; } -DLL_PRIVATE int __model_gw_setup__(ModelInstanceSpec* mi) +DLL_PRIVATE ModelDesc* __model_gw_create__(ModelDesc* model) { - int rc; - - hashlist_init(&__mcd_list, 10); - rc = model_function_register( - mi, mi->name, __gw_step_size, __model_gw_step__); - if (rc) log_fatal("Model registration failed!"); - - uint32_t index = 0; - do { - /* Enumerate over all channels of the Model Instance (not the Model). */ - SchemaObject object = { .doc = mi->spec }; - ChannelSpec* cs = schema_object_enumerator( - mi, &object, "channels", &index, channel_spec_generator); - if (cs == NULL) break; - - /* Register this channel. Priority to 'alias' over 'name' (for channel) - * as alias (if used) would match against a SignalGroup. Selector is - * defined on the Model Instance and will match to a Label on the - * signal group. */ - ModelChannelDesc* mcd = calloc(1, sizeof(ModelChannelDesc)); - mcd->name = cs->alias ? cs->alias : cs->name; - mcd->function_name = mi->name; - rc = model_configure_channel(mi, mcd); - hashlist_append(&__mcd_list, mcd); /* Keep the mcd object. */ - free(cs); - } while (1); - - return 0; + return model; } -DLL_PRIVATE int __model_gw_exit__(ModelInstanceSpec* mi) +DLL_PRIVATE void __model_gw_destroy__(ModelDesc* model) { - UNUSED(mi); - - for (uint32_t i = 0; i < hashlist_length(&__mcd_list); i++) { - void* o = hashlist_at(&__mcd_list, i); - free(o); - } - hashlist_destroy(&__mcd_list); - - return 0; + UNUSED(model); } + /** model_gw_setup ============== @@ -170,7 +116,6 @@ int model_gw_setup(ModelGatewayDesc* gw, const char* name, if (rc) log_fatal("Unable to configure Model C!"); /* Start the GW. */ - __gw_step_size = gw->sim->step_size; modelc_run(gw->sim, true); /* Calls __model_gw_setup__(). */ /* Complete the Gateway descriptor. */ diff --git a/dse/modelc/model/model.c b/dse/modelc/model/model.c index dc1af5b..2b350d2 100644 --- a/dse/modelc/model/model.c +++ b/dse/modelc/model/model.c @@ -65,70 +65,6 @@ void model_function_destroy(ModelFunction* model_function) } -/** -model_function_register -======================= - -Register a Model Function. A Model may register one or more Model Functions -with repeated calls to this function. - -Parameters ----------- -model_instance (ModelInstanceSpec*) -: The Model Instance object (provided via the `model_setup()` function of the - Model API). - -name (const char*) -: The name of the Model Function. - -step_size (double) -: The step size of the Model Function. - -do_step_handler (ModelDoStepHandler) -: The "do step" function of the Model Function. - -Returns -------- -0 -: The model function was registered. - -(errno) -: An error occurred during registration of the model function. The return - value is the `errno` which may indicate the reason for the failure. - -*/ -int model_function_register(ModelInstanceSpec* model_instance, const char* name, - double step_size, ModelDoStepHandler do_step_handler) -{ - int rc; - errno = 0; - - /* Create the Model Function object. */ - ModelFunction* mf = calloc(1, sizeof(ModelFunction)); - if (mf == NULL) { - log_error("ModelFunction malloc failed!"); - goto error_clean_up; - } - mf->name = name; - mf->step_size = step_size; - mf->do_step_handler = do_step_handler; - rc = hashmap_init(&mf->channels); - if (rc) { - log_error("Hashmap init failed for channels!"); - if (errno == 0) errno = rc; - goto error_clean_up; - } - /* Register the object with the Controller. */ - rc = controller_register_model_function(model_instance, mf); - if (rc && (errno != EEXIST)) goto error_clean_up; - return 0; - -error_clean_up: - model_function_destroy(mf); - return errno; -} - - static ModelFunctionChannel* _get_mfc(ModelInstanceSpec* model_instance, const char* model_function_name, const char* channel_name) { @@ -155,68 +91,6 @@ static ModelFunctionChannel* _get_mfc(ModelInstanceSpec* model_instance, } -static void _load_propagator_signal_names( - SimpleSet* set, YamlNode* signals_node, bool target_channel) -{ - if (signals_node == NULL) return; - - uint32_t _sig_count = hashlist_length(&signals_node->sequence); - for (uint32_t i = 0; i < _sig_count; i++) { - YamlNode* sig_node = hashlist_at(&signals_node->sequence, i); - YamlNode* n_node = NULL; - if (target_channel) { - n_node = dse_yaml_find_node(sig_node, "target"); - } else { - n_node = dse_yaml_find_node(sig_node, "source"); - } - /* Fallback the the common "signal" specifier. */ - if (n_node == NULL) { - n_node = dse_yaml_find_node(sig_node, "signal"); - } - set_add(set, n_node->scalar); - } -} - - -static void _find_signals_node_legacy(ModelInstanceSpec* model_instance, - const char* channel_name, YamlNode** channels_node, YamlNode** signals_node) -{ - *channels_node = NULL; - *signals_node = NULL; - const char* selectors[] = { "name" }; - const char* values[] = { channel_name }; - - /* Search in the Model definition. */ - if (model_instance->model_definition.doc) { - YamlNode* c_node = - dse_yaml_find_node_in_seq(model_instance->model_definition.doc, - "spec/channels", selectors, values, 1); - YamlNode* s_node = dse_yaml_find_node(c_node, "signals"); - if (c_node && s_node) { - log_info("Signals for channel[%s] selected from Model Definition.", - channel_name); - *channels_node = c_node; - *signals_node = s_node; - return; - } - } - - /* Search in the Model Instance. */ - if (model_instance->spec) { - YamlNode* c_node = dse_yaml_find_node_in_seq( - model_instance->spec, "channels", selectors, values, 1); - YamlNode* s_node = dse_yaml_find_node(c_node, "signals"); - if (c_node && s_node) { - log_info("Signals for channel[%s] selected from Model Instance.", - channel_name); - *channels_node = c_node; - *signals_node = s_node; - return; - } - } -} - - static HashList __handler_signal_list; static ModelChannelType __handler_signal_vector_type; @@ -319,78 +193,7 @@ void _load_signals(ModelInstanceSpec* model_instance, ChannelSpec* channel_spec, } -void _load_propagator_signals(ModelInstanceSpec* model_instance, - ModelChannelDesc* channel_desc, __signal_list_t* signal_list) -{ - YamlNode* propagators_node = model_instance->propagators; - /* Propagators are loaded dynamically from one or more YAML Docs - which means duplicate signal name might exist. Therefore parse the - signal names into a Set to avoid duplicates. - - NOTE: The order of signals for a propagator does not matter as the - propagator model will dynamically load the related configuration direct - from the YAML Documents. Therefore a Set is viable intermediate storage - container. - */ - SimpleSet signal_name_set; - set_init(&signal_name_set); - /* Parse out the signals from all listed propagators. */ - uint32_t _prop_count = hashlist_length(&propagators_node->sequence); - for (uint32_t i = 0; i < _prop_count; i++) { - YamlNode* prop_node = hashlist_at(&propagators_node->sequence, i); - YamlNode* prop_name_node = dse_yaml_find_node(prop_node, "name"); - // Find the propagator. - const char* selector[] = { "metadata/name" }; - const char* value[] = { prop_name_node->scalar }; - YamlNode* p_doc = dse_yaml_find_doc_in_doclist( - model_instance->yaml_doc_list, "Propagator", selector, value, 1); - assert(p_doc); - // Find the signals node. - YamlNode* signals_node = dse_yaml_find_node(p_doc, "spec/signals"); - _load_propagator_signal_names(&signal_name_set, signals_node, - channel_desc->propagator_target_channel); - } - /* Get the list of signals. */ - uint64_t _sig_count64 = 0; - signal_list->names = - (const char**)set_to_array(&signal_name_set, &_sig_count64); - signal_list->length = _sig_count64; - set_destroy(&signal_name_set); -} - - -void _load_signals_legacy(ModelInstanceSpec* model_instance, - const char* channel_name, __signal_list_t* signal_list) -{ - /* Models are expected to define and reference signals according to the - index of the signal in the Model Definition. - - IMPORTANT: signals must be parsed in the order which they occur in the - Model Definition YAML Doc. - */ - YamlNode* c_node = NULL; - YamlNode* signals_node = NULL; - _find_signals_node_legacy( - model_instance, channel_name, &c_node, &signals_node); - if (c_node == NULL) { - log_fatal("Channel (%s) not found in model definition", channel_name); - } - if (signals_node == NULL) { - log_fatal("Signals node not found in model definition "); - } - assert(c_node); - assert(signals_node); - signal_list->length = hashlist_length(&signals_node->sequence); - signal_list->names = calloc(signal_list->length, sizeof(const char*)); - for (uint32_t i = 0; i < signal_list->length; i++) { - YamlNode* sig_node = hashlist_at(&signals_node->sequence, i); - YamlNode* n_node = dse_yaml_find_node(sig_node, "signal"); - signal_list->names[i] = n_node->scalar; - } -} - - -/** +/* model_configure_channel ======================= @@ -459,25 +262,11 @@ int model_configure_channel( return 0; } - /* Find the signal definitions: - If the Model Instance specifies a Propagator, then the signals will be - defined under Propagator:spec/signals. - Otherwise, the signals will be under Model:spec/channels[name]/signals. - */ + /* Load signals via SignalGroups. */ __signal_list_t signal_list = { NULL, 0 }; ModelChannelType vector_type = MODEL_VECTOR_DOUBLE; assert(model_instance->spec); - if (model_instance->propagators) { - _load_propagator_signals(model_instance, channel_desc, &signal_list); - } else { - /* Load signals via SignalGroups. */ - _load_signals(model_instance, channel_spec, &signal_list, &vector_type); - if (signal_list.length == 0) { - /* Fallback to legacy method. */ - _load_signals_legacy( - model_instance, channel_spec->name, &signal_list); - } - } + _load_signals(model_instance, channel_spec, &signal_list, &vector_type); log_notice(" Unique signals identified: %u", signal_list.length); /* Init the channel and register signals. */ @@ -519,3 +308,168 @@ int model_configure_channel( /* Brutal, eh? */ return 0; } + + +DLL_PRIVATE ModelSignalIndex __model_index__(ModelDesc* m, const char* vname, const char* sname) +{ + ModelSignalIndex index = {}; + if (m == NULL || m->sv == NULL) return index; + + SignalVector* sv = m->sv; + uint32_t v_idx = 0; + while (sv && sv->name) { + if (strcmp(sv->alias, vname) == 0) { + for (uint32_t s_idx = 0; s_idx < sv->count; s_idx++) { + if (strcmp(sv->signal[s_idx], sname) == 0) { + /* Match! */ + index.sv = sv; + index.vector = v_idx; + index.signal = s_idx; + if (sv->is_binary) { + index.binary = &(sv->binary[s_idx]); + } else { + index.scalar = &(sv->scalar[s_idx]); + } + return index; + } + } + } + sv++; + v_idx++; + } + return index; +} + + +/** +model_create +============ + +> Optional method of `ModelVTable` interface. + +Called by the Model Runtime to create a new instance of this model. + +The `model_create()` method may extend or mutilate the provided Model +Descriptor. When extending the Model Descriptor _and_ allocating additional +resources then the `model_destroy()` method should also be implemented. + +Fault conditions can be communicated to the caller by setting variable +`errno` to a non-zero value. Additionally, `log_fatal()` can be used to +immediately halt execution of a model. + +Parameters +---------- +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +Returns +------- +NULL +: The Channel was configured. + +(ModelDesc*) +: Pointer to a new, or mutilated, version of the Model Descriptor object. The + original Model Descriptor object will be released by the Model Runtime (i.e. + don't call `free()`). + +errno <> 0 (indirect) +: Indicates an error condition. + +Example +------- + +{{< readfile file="../examples/model_create.c" code="true" lang="c" >}} + + +*/ +extern ModelDesc* model_create(ModelDesc* m); + + +/** +model_step +========== + +> Mandatory method of `ModelVTable` interface. Alternatively, Model implementers + may specify the `ModelVTable.step` method dynamically by mutilating the + Model Descriptor in the `model_create()` method, or even at runtime. + +Called by the Model Runtime to step the model for a time interval. + +Parameters +---------- +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +model_time (double*) +: (in/out) Specifies the model time for this step of the model. + +stop_time (double) +: Specifies the stop time for this step of the model. The model step should not + exceed this time. + +Returns +------- +0 +: The step completed without error. + +<>0 +: An error occurred at some point during the step execution. + +model_time (via parameter) +: The final model time reached for this step. This value may be less than + `stop_time` if a step decides to return early. +*/ +extern int model_step(ModelDesc* model, double* model_time, double stop_time); + + +/** +model_destroy +============= + +> Optional method of `ModelVTable` interface. + +Called by the Model Runtime at the end of a simulation, the `model_destroy()` +function may be implemented by a Model Integrator to perform any custom +cleanup operations (e.g. releasing instance related resources, such as open +files or allocated memory). + +Parameters +---------- +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +*/ +extern void model_destroy(ModelDesc* model); + + +/** +model_index_ +============ + +> Provided method (by the Runtime). Model implementers may specify + a different index method by mutilating the Model Descriptor in the + `model_create()` method, or even at runtime. + +A model may use this method to index a signal that is contained within the +Signal Vectors of the Model Descriptor. + +Parameters +---------- +model (ModelDesc*) +: The Model Descriptor object representing an instance of this model. + +vname (const char*) +: The name (alias) of the Signal Vector. + +sname (const char*) +: The name of the signal within the Signal Vector. + +Returns +------- +ModelSignalIndex +: An index. When valid, either the `scalar` or `binary` fields will be set to + a valid pointer (i.e. not NULL). + +*/ +extern ModelSignalIndex model_index_(ModelDesc* model, const char* vname, + const char* sname); diff --git a/dse/modelc/model/signal.c b/dse/modelc/model/signal.c index bc0ef88..08c9593 100644 --- a/dse/modelc/model/signal.c +++ b/dse/modelc/model/signal.c @@ -7,8 +7,9 @@ #include #include #include +#include #include -#include +#include #include #include @@ -255,7 +256,7 @@ static int _count_sv(void* _mf, void* _number) } -/** +/* model_sv_create =============== @@ -272,11 +273,6 @@ SignalVector (pointer to NULL terminated list) : A list of SignalVector objects representing the signals assigned to a model. The list is NULL terminated (sv->name == NULL). Caller to free. -Example -------- - -{{< readfile file="../examples/model_sv_create.c" code="true" lang="c" >}} - */ SignalVector* model_sv_create(ModelInstanceSpec* mi) { @@ -321,7 +317,7 @@ SignalVector* model_sv_create(ModelInstanceSpec* mi) } -/** +/* model_sv_destroy ================ @@ -360,3 +356,188 @@ void model_sv_destroy(SignalVector* sv) free(sv_save); } + + + +/** +signal_append +============= + +Append data to the end of the specified binary signal. The append method will +resize the buffers of the binary signal as required. + +Parameters +---------- +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +data (void*) +: Address/pointer to the data which should be appended to the binary signal. + +len (uint32_t) +: Length of the provided data buffer being appended. + +Returns +------- +0 +: The operation completed without error. + +<>0 +: Indicates an error condition. Inspect `errno` for additional information. +*/ +extern int signal_append(SignalVector* sv, uint32_t index, + void* data, uint32_t len); + + +/** +signal_reset +============ + +Reset a binary signal (e.g. sets its buffer length to 0). The buffers of the +binary signal are not released (see `signal_release()`). + +Parameters +---------- +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +Returns +------- +0 +: The operation completed without error. + +<>0 +: Indicates an error condition. Inspect `errno` for additional information. +*/ +extern int signal_reset(SignalVector* sv, uint32_t index); + + +/** +signal_release +============== + +Release the resources allocated to a binary signal (e.g. free the buffer). + +Parameters +---------- +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +Returns +------- +0 +: The operation completed without error. + +<>0 +: Indicates an error condition. Inspect `errno` for additional information. +*/ +extern int signal_release(SignalVector* sv, uint32_t index); + + +/** +signal_codec +============ + +Return a pointer to the Codec object associated with a binary signal. + +Codec objects are created when a binary signal is specified with a `mime_type` +annotation. + +Parameters +---------- +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +Returns +------- +void* +: The Codec object associated with the binary signal. + +NULL +: The binary signal does not have an associated Codec object. + +Example (Codec Specification) +------- + +```yaml +kind: SignalGroup +metadata: + name: network + labels: + channel: network_vector + annotations: + vector_type: binary +spec: + signals: + - signal: can_bus + annotations: + mime_type: application/x-automotive-bus; interface=stream; type=frame; bus=can; schema=fbs; bus_id=1; node_id=2; interface_id=3 +``` + +Reference +--------- + +[Network Codec API](https://github.com/boschglobal/dse.standards/tree/main/dse/ncodec) + +*/ +extern void* signal_codec(SignalVector* sv, uint32_t index); + + +/** +signal_annotation +================= + +Get an annotation from a signal definition. + +Parameters +---------- +sv (SignalVector*) +: The Signal Vector object containing the signal. + +index (uint32_t) +: Index of the signal in the Signal Vector object. + +name (const char*) +: The name of the annotation. + +Returns +------- +const char* +: The annotation value. + +Example (Annotation Specification) +------- + +```yaml +kind: SignalGroup +metadata: + name: data +spec: + signals: + - signal: counter + annotations: + initial_value: 10 +``` + +Example (Code Usage) +------- + +{{< readfile file="../examples/signalvector_annotation.c" code="true" lang="c" >}} + + +NULL +: The requested annotation was not found. +*/ +extern const char* signal_annotation(SignalVector* sv, uint32_t index, const char* name); diff --git a/dse/modelc/runtime.h b/dse/modelc/runtime.h new file mode 100644 index 0000000..df15676 --- /dev/null +++ b/dse/modelc/runtime.h @@ -0,0 +1,150 @@ +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef DSE_MODELC_RUNTIME_H_ +#define DSE_MODELC_RUNTIME_H_ + +#include + + +/** +Runtime API +=========== + +The Runtime API provides methods for implementing a model Runtime/Importer +which can be used to load, configure and execute a model. + +*/ + +typedef struct ChannelSpec { + const char* name; + const char* alias; + /* Private data. */ + void* private; +} ChannelSpec; + + +typedef struct ModelChannelDesc { + const char* name; + const char* function_name; + /* Reference to the parsed signal names. */ + const char** signal_names; + uint32_t signal_count; + /* Indicate if this Channel is connected to a Propagator Model. */ + bool propagator_source_channel; + bool propagator_target_channel; + /* Allocated vector table (one only depending on type). */ + double* vector_double; + void** vector_binary; + /* Additional vector tables supporting vector_binary. */ + uint32_t* vector_binary_size; /* Size of binary object. */ + uint32_t* vector_binary_buffer_size; /* Size of allocated buffer. */ +} ModelChannelDesc; + + +typedef struct ModelDefinitionSpec { + const char* name; + const char* path; + const char* file; + char* full_path; /* path + file */ + + /* Reference to parsed YAML Documents. */ + void* doc; + void* channels; +} ModelDefinitionSpec; + + +typedef struct ModelInstanceSpec { + uint32_t uid; + char* name; + ModelDesc* model_desc; + ModelDefinitionSpec model_definition; + + /* Reference to parsed YAML Documents. */ + void* spec; + void* yaml_doc_list; + /* Private data of the specific Model Instance. */ + void* private; +} ModelInstanceSpec; + + +typedef struct SimulationSpec { + /* Transport. */ + const char* transport; + char* uri; + uint32_t uid; + double timeout; + /* Simulation. */ + double step_size; + double end_time; + /* Model Instances, list, last entry all values set NULL (EOL detect). */ + ModelInstanceSpec* instance_list; +} SimulationSpec; + + +/* Loader/Runner API Definition */ +typedef struct ModelCArguments { + const char* transport; + char* uri; + const char* host; + uint32_t port; + double timeout; + uint8_t log_level; + double step_size; + double end_time; + uint32_t uid; + const char* name; + const char* file; + const char* path; + /* Parsed YAML Files. */ + void* yaml_doc_list; + /* Allow detection of CLI provided arguments. */ + int timeout_set_by_cli; + int log_level_set_by_cli; + /* MStep "hidden" arguments. */ + uint32_t steps; +} ModelCArguments; + + +/* modelc.c - Runtime Interface (i.e. ModelC.exe). */ +DLL_PUBLIC int modelc_configure(ModelCArguments* args, SimulationSpec* sim); +DLL_PUBLIC ModelInstanceSpec* modelc_get_model_instance( + SimulationSpec* sim, const char* name); +DLL_PUBLIC int modelc_run(SimulationSpec* sim, bool run_async); +DLL_PUBLIC void modelc_exit(SimulationSpec* sim); +DLL_PUBLIC int modelc_sync(SimulationSpec* sim); +DLL_PUBLIC void modelc_shutdown(void); +DLL_PUBLIC int modelc_model_create( + SimulationSpec* sim, ModelInstanceSpec* mi, ModelVTable* model_vtable); + + +/* modelc_debug.c - Debug Interface. */ +DLL_PUBLIC int modelc_step(ModelInstanceSpec* model_instance, double step_size); + + +/* modelc_args.c - CLI argument parsing routines. */ +DLL_PUBLIC void modelc_set_default_args(ModelCArguments* args, + const char* model_instance_name, double step_size, double end_time); +DLL_PUBLIC void modelc_parse_arguments( + ModelCArguments* args, int argc, char** argv, const char* doc_string); + + +/* signal.c - Signal Vector Interface. */ +DLL_PUBLIC SignalVector* model_sv_create(ModelInstanceSpec* mi); +DLL_PUBLIC void model_sv_destroy(SignalVector* sv); + + +/* ncodec.c - Stream Interface (for NCodec). */ +DLL_PRIVATE void* model_sv_stream_create(SignalVector* sv, uint32_t idx); +DLL_PRIVATE void model_sv_stream_destroy(void* stream); + + +/* model.c - Model Interface. */ +DLL_PRIVATE ChannelSpec* model_build_channel_spec( + ModelInstanceSpec* model_instance, const char* channel_name); +DLL_PRIVATE int model_configure_channel( + ModelInstanceSpec* model_instance, ModelChannelDesc* channel_desc); + + +#endif // DSE_MODELC_RUNTIME_H_ diff --git a/dse/modelc/schema.h b/dse/modelc/schema.h index 48babe3..5a67936 100644 --- a/dse/modelc/schema.h +++ b/dse/modelc/schema.h @@ -7,7 +7,7 @@ #include #include -#include +#include #ifndef DLL_PUBLIC diff --git a/dse/modelc/tools/mcl_model/model.c b/dse/modelc/tools/mcl_model/model.c index b18fb9d..f5101b5 100644 --- a/dse/modelc/tools/mcl_model/model.c +++ b/dse/modelc/tools/mcl_model/model.c @@ -13,155 +13,124 @@ #include -#define ARRAY_LENGTH(array) (sizeof((array)) / sizeof((array)[0])) +#define MCL_CHANNEL "mcl_channel" -/* Model Function definitions. */ -#define MODEL_FUNCTION_NAME "mcl_model" -#define MODEL_FUNCTION_DO_STEP do_step -#define MODEL_FUNCTION_STEP_SIZE 0.005 -#define MODEL_FUNCTION_CHANNEL "mcl_channel" +typedef struct { + ModelDesc model; + /* MCL Properties. */ + MclInstanceDesc* mcl_instance; +} MclExtendedModelDesc; -/* Copy of MCL Instance for DO_STEP(). */ -static MclInstanceDesc* __mcl_instance; - -static int __mcl_execute(MclStrategyAction action) -{ - assert(__mcl_instance); - assert(__mcl_instance->strategy); - assert(__mcl_instance->strategy->execute_func); - - int rc = __mcl_instance->strategy->execute_func(__mcl_instance, action); - return rc; -} - - -/* Model Function do_step() definition. */ -int MODEL_FUNCTION_DO_STEP(double* model_time, double stop_time) +static int __mcl_execute(ModelDesc* model, MclStrategyAction action) { - log_debug("Model function do_step() called: model_time=%f, stop_time=%f", - *model_time, stop_time); - MclInstanceDesc* mcl_instance = __mcl_instance; - assert(mcl_instance); - assert(mcl_instance->channel); + MclExtendedModelDesc* m = (MclExtendedModelDesc*)model; + MclInstanceDesc* mcl_instance = m->mcl_instance; assert(mcl_instance->strategy); - assert(mcl_instance->strategy->mcl_instance); - - /* Marshall data from Channel to MCL Models. */ - mcl_instance->strategy->execute(MCL_STRATEGY_ACTION_MARSHALL_OUT); - /* Execute the step strategy (i.e. call step_func() on all MCL Models). */ - log_debug("Call MCL Strategy: step_func ..."); - mcl_instance->strategy->model_time = *model_time; - mcl_instance->strategy->stop_time = stop_time; - int rc = mcl_instance->strategy->execute(MCL_STRATEGY_ACTION_STEP); - if (rc != 0) return rc; - /* Marshall data from Channel to MCL Models. */ - mcl_instance->strategy->execute(MCL_STRATEGY_ACTION_MARSHALL_IN); - /* Set the model_time to the *finalised* stop_time of the strategy. */ - *model_time = mcl_instance->strategy->stop_time; + assert(mcl_instance->strategy->execute_func); + int rc = mcl_instance->strategy->execute_func(mcl_instance, action); return rc; } -/* Model Setup: a handle to this function will be dynamically loaded by the - Controller and it (this function) will be called to initialise the Model - and its Model Functions. */ -int MODEL_SETUP_FUNC(ModelInstanceSpec* model_instance) +ModelDesc* model_create(ModelDesc* model) { - log_notice("Model function " MODEL_SETUP_FUNC_STR " called"); - assert(model_instance); - int rc = 0; - - /* Register this Model Function with the SimBus/ModelC. */ - rc = model_function_register(model_instance, MODEL_FUNCTION_NAME, - MODEL_FUNCTION_STEP_SIZE, MODEL_FUNCTION_DO_STEP); - if (rc != 0) return rc; - - /* Register channels (and get storage). */ - static ModelChannelDesc channel_desc = { - .name = MODEL_FUNCTION_CHANNEL, - .function_name = MODEL_FUNCTION_NAME, - }; - rc = model_configure_channel(model_instance, &channel_desc); - if (rc != 0) return rc; - log_debug("%p", channel_desc.vector_double); - assert(channel_desc.vector_double); + /* Extend the ModelDesc object (using a shallow copy). */ + MclExtendedModelDesc* m = calloc(1, sizeof(MclExtendedModelDesc)); + memcpy(m, model, sizeof(ModelDesc)); + ModelInstanceSpec* mi = m->model.mi; - /* Load the MCL dll's. */ + /* Load the MCL dll's. */ log_debug("Load the MCL(s) ..."); errno = 0; - rc = mcl_load(model_instance); + int rc = mcl_load(mi); if (rc) { if (errno == 0) errno = ECANCELED; - log_error("Failed to load the configured MCL(s)!"); - return rc; + log_fatal("Failed to load the configured MCL(s)!"); } /* Create the MCL Instance. */ log_debug("Create the MCL Instance ..."); errno = 0; - rc = mcl_create(model_instance); + rc = mcl_create(mi); if (rc) { if (errno == 0) errno = ECANCELED; - log_error("Failed to create the MCL Instance!"); - return rc; + log_fatal("Failed to create the MCL Instance!"); } /* Save a reference to MCL Instance for the do_step(). */ - assert(model_instance->private); - ModelInstancePrivate* mip = model_instance->private; + assert(mi->private); + ModelInstancePrivate* mip = mi->private; assert(mip->mcl_instance); - __mcl_instance = mip->mcl_instance; /* Save for use by do_step(). */ - MclInstanceDesc* mcl_instance = __mcl_instance; - /* Set the MCL Instance Channel to the Channel created here. */ - mcl_instance->channel = &channel_desc; + MclInstanceDesc* mcl_instance = m->mcl_instance = mip->mcl_instance; + + /* Set the MCL Channel (should be the first/only SV). */ + assert(strcmp(m->model.sv->name, MCL_CHANNEL) == 0); + mcl_instance->mcl_channel_sv = m->model.sv; /* Set the MCL Strategy execute function. */ mcl_instance->strategy->execute = __mcl_execute; /* Execute the load strategy (i.e. call load_func() on all MCL Models). */ log_debug("Call MCL Strategy: load_func ..."); - rc = mcl_instance->strategy->execute(MCL_STRATEGY_ACTION_LOAD); + rc = mcl_instance->strategy->execute(model, MCL_STRATEGY_ACTION_LOAD); if (rc) { if (errno == 0) errno = ECANCELED; - log_error("MCL strategy ACTION_LOAD failed!"); - return rc; + log_fatal("MCL strategy ACTION_LOAD failed!"); } /* Execute the Init strategy (i.e. call load_func() on all MCL Models). */ log_debug("Call MCL Strategy: init_func ..."); - rc = mcl_instance->strategy->execute(MCL_STRATEGY_ACTION_INIT); + rc = mcl_instance->strategy->execute(model, MCL_STRATEGY_ACTION_INIT); if (rc) { if (errno == 0) errno = ECANCELED; - log_error("MCL strategy ACTION_INIT failed!"); - return rc; + log_fatal("MCL strategy ACTION_INIT failed!"); } - return 0; + /* Return the extended object. */ + return (ModelDesc*)m; } -/* Model Exit: called before the Controller exits the simulation (and sends - the SyncExit message to the SimBus). */ -int MODEL_EXIT_FUNC(ModelInstanceSpec* model_instance) +int model_step(ModelDesc* model, double* model_time, double stop_time) { - log_notice("Model function " MODEL_EXIT_FUNC_STR " called"); - assert(model_instance); - assert(model_instance->private); - ModelInstancePrivate* mip = model_instance->private; - assert(mip->mcl_instance); - MclInstanceDesc* mcl_instance = mip->mcl_instance; + MclExtendedModelDesc* m = (MclExtendedModelDesc*)model; + MclInstanceDesc* mcl_instance = m->mcl_instance; + assert(mcl_instance); + //assert(mcl_instance->channel); assert(mcl_instance->strategy); assert(mcl_instance->strategy->mcl_instance); - /* Execute the unload strategy (i.e. call unload_func() on all MCL Models). - */ - log_debug("Call MCL Strategy: unload_func ..."); - int rc = mcl_instance->strategy->execute(MCL_STRATEGY_ACTION_UNLOAD); - mcl_destroy(model_instance); - /* Set the local copy of mcl_instance to NULL. */ - __mcl_instance = NULL; + /* Marshall data from Channel to MCL Models. */ + mcl_instance->strategy->execute(model, MCL_STRATEGY_ACTION_MARSHALL_OUT); + /* Execute the step strategy (i.e. call step_func() on all MCL Models). */ + log_debug("Call MCL Strategy: step_func ..."); + mcl_instance->strategy->model_time = *model_time; + mcl_instance->strategy->stop_time = stop_time; + int rc = mcl_instance->strategy->execute(model, MCL_STRATEGY_ACTION_STEP); + if (rc != 0) return rc; + /* Marshall data from Channel to MCL Models. */ + mcl_instance->strategy->execute(model, MCL_STRATEGY_ACTION_MARSHALL_IN); + /* Set the model_time to the *finalised* stop_time of the strategy. */ + *model_time = mcl_instance->strategy->stop_time; return rc; } + + +void model_destroy(ModelDesc* model) +{ + MclExtendedModelDesc* m = (MclExtendedModelDesc*)model; + ModelInstanceSpec* mi = m->model.mi; + MclInstanceDesc* mcl_instance = m->mcl_instance; + assert(mcl_instance->strategy); + assert(mcl_instance->strategy->mcl_instance); + + log_notice("Model function " MODEL_DESTROY_FUNC_NAME " called"); + + /* Execute the unload strategy. */ + log_debug("Call MCL Strategy: unload_func ..."); + mcl_instance->strategy->execute(model, MCL_STRATEGY_ACTION_UNLOAD); + mcl_destroy(mi); +} diff --git a/dse/modelc/tools/modelc/modelc.c b/dse/modelc/tools/modelc/modelc.c index c042475..66b6048 100644 --- a/dse/modelc/tools/modelc/modelc.c +++ b/dse/modelc/tools/modelc/modelc.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/dse/modelc/tools/mstep/mstep.c b/dse/modelc/tools/mstep/mstep.c index 2509dba..c6c956e 100644 --- a/dse/modelc/tools/mstep/mstep.c +++ b/dse/modelc/tools/mstep/mstep.c @@ -10,11 +10,11 @@ #include #include #include -#include +#include #include -#define STEP_SIZE 0.005 +#define STEP_SIZE MODEL_DEFAULT_STEP_SIZE #define END_TIME 3600 #define STEPS 10 @@ -46,10 +46,11 @@ static void print_signal_vectors(SignalVector* sv); * - sample: 0.0005 * values: * - D_BrakePedal_0_1_f: 0.0 # 0..1 - * - D_ActMode_1_3_f: 3 # 1 = MC Press, 2 = Pedal Force, 3 = Rod Stroke + * - D_ActMode_1_3_f: 3 # 1 = MC Press, 2 = Pedal Force, 3 = Rod + * Stroke * - sample: 0.0010 * values: - * - D_BrakePedal_0_1_f: 0.3 + * - D_BrakePedal_0_1_f: 0.3 */ typedef struct ValueObject { char* signal; @@ -119,20 +120,25 @@ int main(int argc, char** argv) log_error("ERROR: dlopen call failed: %s", dlerror()); log_fatal("Model library not loaded!"); } - ModelSetupHandler model_setup_func = dlsym(handle, MODEL_SETUP_FUNC_STR); - ModelExitHandler model_exit_func = dlsym(handle, MODEL_EXIT_FUNC_STR); - if (model_setup_func == NULL) log_fatal("model_setup_func not found!"); - + ModelVTable vtable; + vtable.create = dlsym(handle, MODEL_CREATE_FUNC_NAME); + vtable.step = dlsym(handle, MODEL_STEP_FUNC_NAME); + vtable.destroy = dlsym(handle, MODEL_DESTROY_FUNC_NAME); + if (vtable.create == NULL && vtable.step == NULL) { + log_fatal("vtable not complete!"); + } - /* Call the setup function of the Model. */ - rc = model_setup_func(mi); - if (rc) log_fatal("Call: model_setup_func failed! (rc=%d)!", rc); - SignalVector* sv = model_sv_create(mi); + /* Call the create function of the Model. */ + rc = modelc_model_create(&sim, mi, &vtable); + if (rc) { + log_fatal("Call: model_setup_func failed! (rc=%d)!", rc); + } + memcpy(&vtable, &mi->model_desc->vtable, sizeof(ModelVTable)); + SignalVector* sv = mi->model_desc->sv; print_signal_vectors(sv); - /* Load any input data. */ - Enumerator samples = { .sv = sv }; + Enumerator samples = { .sv = sv }; SchemaObjectSelector selector = { .kind = "Input", .name = args.name, @@ -192,9 +198,8 @@ int main(int argc, char** argv) /* Call the exit function of the Model. */ - if (model_exit_func) { - rc = model_exit_func(mi); - if (rc) log_fatal("Executing model exit failed! (rc=%d)!", rc); + if (vtable.destroy) { + vtable.destroy(mi->model_desc); } exit(0); @@ -252,15 +257,16 @@ static void* value_object_generator(ModelInstanceSpec* mi, void* data) YamlNode* node = data; - int len = hashmap_number_keys(node->mapping); + int len = hashmap_number_keys(node->mapping); if (len == 0) return NULL; - char** keys = hashmap_keys(&node->mapping); + char** keys = hashmap_keys(&node->mapping); ValueObject* vo = calloc(1, sizeof(ValueObject)); vo->signal = keys[0]; dse_yaml_get_double(node, keys[0], &vo->value); /* Free the keys, except for the first entry ... which is returned. */ - for (int i = 1; i < len; i++) free(keys[i]); + for (int i = 1; i < len; i++) + free(keys[i]); free(keys); return vo; /* Caller to free, also vo->signal. */ diff --git a/dse/modelc/tools/simbus/simbus.c b/dse/modelc/tools/simbus/simbus.c index 99571d7..f1d8b19 100644 --- a/dse/modelc/tools/simbus/simbus.c +++ b/dse/modelc/tools/simbus/simbus.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include diff --git a/tests/cmocka/CMakeLists.txt b/tests/cmocka/CMakeLists.txt index 06fc4ac..694c970 100644 --- a/tests/cmocka/CMakeLists.txt +++ b/tests/cmocka/CMakeLists.txt @@ -93,6 +93,7 @@ set(DSE_NCODEC_INCLUDE_DIR "${DSE_NCODEC_SOURCE_DIR}") # Set the project paths # ===================== set(DSE_MODELC_SOURCE_DIR ../../dse/modelc) +set(DSE_MOCKS_SOURCE_DIR ../../dse/mocks) set(DSE_MODELC_SOURCE_FILES ${DSE_MODELC_SOURCE_DIR}/model/gateway.c ${DSE_MODELC_SOURCE_DIR}/model/model.c @@ -103,9 +104,11 @@ set(DSE_MODELC_SOURCE_FILES ${DSE_MODELC_SOURCE_DIR}/controller/loader.c ${DSE_MODELC_SOURCE_DIR}/controller/model_function.c ${DSE_MODELC_SOURCE_DIR}/controller/modelc.c + ${DSE_MODELC_SOURCE_DIR}/controller/modelc_debug.c ${DSE_MODELC_SOURCE_DIR}/controller/modelc_args.c ${DSE_MODELC_SOURCE_DIR}/controller/step.c + ${DSE_MOCKS_SOURCE_DIR}/simmock.c ) set(DSE_MODELC_INCLUDE_DIR "${DSE_MODELC_SOURCE_DIR}/../..") @@ -138,7 +141,7 @@ target_include_directories(test_model ) target_compile_definitions(test_model PUBLIC -# UNIT_TESTING # Using valgrind instead. + CMOCKA_TESTING PRIVATE PLATFORM_OS="${CDEF_PLATFORM_OS}" PLATFORM_ARCH="${CDEF_PLATFORM_ARCH}" @@ -160,4 +163,41 @@ install( model/signal.yaml DESTINATION resources/model -) \ No newline at end of file +) + + +# Target - Model Interface +# ------------------------ +add_executable(test_model_interface + model/interface/__test__.c + model/interface/test_model_interface.c + model/stub_controller.c + ${DSE_MODELC_SOURCE_FILES} + ${DSE_NCODEC_SOURCE_FILES} + ${DSE_CLIB_SOURCE_FILES} +) +target_include_directories(test_model_interface + PRIVATE + ${DSE_MODELC_INCLUDE_DIR} + ${DSE_NCODEC_INCLUDE_DIR} + ${DSE_CLIB_INCLUDE_DIR} + ${YAML_SOURCE_DIR}/include + ./ +) +target_compile_definitions(test_model_interface + PUBLIC + CMOCKA_TESTING + PRIVATE + PLATFORM_OS="${CDEF_PLATFORM_OS}" + PLATFORM_ARCH="${CDEF_PLATFORM_ARCH}" +) +target_link_libraries(test_model_interface + PRIVATE + dse_ncodec + cmocka + yaml + dl + m + # -Wl,--wrap=strdup # Wrapping strdup does not work with libyaml. +) +install(TARGETS test_model_interface) diff --git a/tests/cmocka/Makefile b/tests/cmocka/Makefile index 2d2815c..2f3bde5 100644 --- a/tests/cmocka/Makefile +++ b/tests/cmocka/Makefile @@ -24,6 +24,7 @@ build: run: cd build/_out; $(GDB_CMD) bin/test_model + cd build/_out; $(GDB_CMD) bin/test_model_interface clean: rm -rf build diff --git a/tests/cmocka/model/interface/__test__.c b/tests/cmocka/model/interface/__test__.c new file mode 100644 index 0000000..6d8403f --- /dev/null +++ b/tests/cmocka/model/interface/__test__.c @@ -0,0 +1,17 @@ +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: BIOS-4.0 + +#include + + +extern int run_model_interface_tests(void); + + +int main() +{ + int rc = 0; + rc |= run_model_interface_tests(); + return rc; +} diff --git a/tests/cmocka/model/interface/test_model_interface.c b/tests/cmocka/model/interface/test_model_interface.c new file mode 100644 index 0000000..1f7cd1c --- /dev/null +++ b/tests/cmocka/model/interface/test_model_interface.c @@ -0,0 +1,204 @@ +// Copyright 2024 Robert Bosch GmbH +// +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: BIOS-4.0 + +#include +#include +#include +#include +#include + + +static char __entry_path__[200]; + + +static int test_setup(void** state) +{ + UNUSED(state); + return 0; +} + + +static int test_teardown(void** state) +{ + SimMock* mock = *state; + + simmock_exit(mock); + simmock_free(mock); + + chdir(__entry_path__); + + return 0; +} + + +#define MINIMAL_INST_NAME "minimal_inst" +#define MINIMAL_SIGNAL_COUNTER 0 + +void test_model__minimal(void** state) +{ + chdir("../../../../dse/modelc/build/_out/examples/minimal"); + + const char* inst_names[] = { + MINIMAL_INST_NAME, + }; + char* argv[] = { + (char*)"test_model_interface", + (char*)"--name=" MINIMAL_INST_NAME, + (char*)"--logger=5", // 1=debug, 5=QUIET (commit with 5!) + (char*)"data/simulation.yaml", + (char*)"data/model.yaml", + }; + SimMock* mock = *state = simmock_alloc(inst_names, ARRAY_SIZE(inst_names)); + simmock_configure(mock, argv, ARRAY_SIZE(argv), ARRAY_SIZE(inst_names)); + ModelMock* model = simmock_find_model(mock, MINIMAL_INST_NAME); + simmock_load(mock); + simmock_load_model_check(model, false, true, false); + simmock_setup(mock, "data_channel", NULL); + + /* Initial value. */ + double counter = 0.0; + simmock_print_scalar_signals(mock, LOG_DEBUG); + /* T0 ... Tn */ + for (uint32_t i = 0; i < 5; i++) { + /* Do the check. */ + SignalCheck checks[] = { + { .index = MINIMAL_SIGNAL_COUNTER, .value = counter }, + }; + simmock_signal_check( + mock, MINIMAL_INST_NAME, checks, ARRAY_SIZE(checks), NULL); + /* Step the model. */ + assert_int_equal(simmock_step(mock, true), 0); + simmock_print_scalar_signals(mock, LOG_DEBUG); + counter += 1.0; + } +} + + +#define EXTENDED_INST_NAME "extended_inst" +#define EXTENDED_SIGNAL_COUNTER 0 +#define EXTENDED_SIGNAL_ODD 1 +#define EXTENDED_SIGNAL_EVEN 2 + +void test_model__extended(void** state) +{ + chdir("../../../../dse/modelc/build/_out/examples/extended"); + + const char* inst_names[] = { + EXTENDED_INST_NAME, + }; + char* argv[] = { + (char*)"test_model_interface", + (char*)"--name=" EXTENDED_INST_NAME, + (char*)"--logger=5", // 1=debug, 5=QUIET (commit with 5!) + (char*)"data/simulation.yaml", + (char*)"data/model.yaml", + }; + SimMock* mock = *state = simmock_alloc(inst_names, ARRAY_SIZE(inst_names)); + simmock_configure(mock, argv, ARRAY_SIZE(argv), ARRAY_SIZE(inst_names)); + ModelMock* model = simmock_find_model(mock, EXTENDED_INST_NAME); + simmock_load(mock); + simmock_load_model_check(model, true, true, false); + simmock_setup(mock, "data_channel", NULL); + + /* Initial value. */ + double counter = 42.0; + double odd = false; + double even = true; + simmock_print_scalar_signals(mock, LOG_DEBUG); + /* T0 ... Tn */ + for (uint32_t i = 0; i < 5; i++) { + /* Do the check. */ + SignalCheck checks[] = { + { .index = EXTENDED_SIGNAL_COUNTER, .value = counter }, + { .index = EXTENDED_SIGNAL_ODD, .value = odd }, + { .index = EXTENDED_SIGNAL_EVEN, .value = even }, + }; + simmock_signal_check( + mock, EXTENDED_INST_NAME, checks, ARRAY_SIZE(checks), NULL); + /* Step the model. */ + assert_int_equal(simmock_step(mock, true), 0); + simmock_print_scalar_signals(mock, LOG_DEBUG); + /* Set check conditions (for next step). */ + counter += 1.0; + odd = (bool)odd ? false : true; + even = (bool)even ? false : true; + } +} + + +#define BINARY_INST_NAME "binary_inst" +#define BINARY_SIGNAL_COUNTER 0 +#define BINARY_SIGNAL_MESSAGE 0 + +void test_model__binary(void** state) +{ + chdir("../../../../dse/modelc/build/_out/examples/binary"); + + const char* inst_names[] = { + BINARY_INST_NAME, + }; + char* argv[] = { + (char*)"test_model_interface", + (char*)"--name=" BINARY_INST_NAME, + (char*)"--logger=5", // 1=debug, 5=QUIET (commit with 5!) + (char*)"data/simulation.yaml", + (char*)"data/model.yaml", + }; + SimMock* mock = *state = simmock_alloc(inst_names, ARRAY_SIZE(inst_names)); + simmock_configure(mock, argv, ARRAY_SIZE(argv), ARRAY_SIZE(inst_names)); + ModelMock* model = simmock_find_model(mock, BINARY_INST_NAME); + simmock_load(mock); + simmock_load_model_check(model, true, true, true); + simmock_setup(mock, "scalar_channel", "binary_channel"); + + /* Initial value. */ + double counter = 42.0; + char buffer[100] = ""; + uint32_t len = 0; + + simmock_print_scalar_signals(mock, LOG_DEBUG); + simmock_print_binary_signals(mock, LOG_DEBUG); + /* T0 ... Tn */ + for (uint32_t i = 0; i < 2; i++) { + /* Do the check. */ + SignalCheck checks[] = { + { .index = BINARY_SIGNAL_COUNTER, .value = counter }, + }; + BinaryCheck b_checks[] = { + { .index = BINARY_SIGNAL_MESSAGE, + .buffer = (uint8_t*)buffer, + .len = len }, + }; + simmock_signal_check( + mock, BINARY_INST_NAME, checks, ARRAY_SIZE(checks), NULL); + simmock_binary_check( + mock, BINARY_INST_NAME, b_checks, ARRAY_SIZE(b_checks), NULL); + /* Step the model. */ + assert_int_equal(simmock_step(mock, true), 0); + simmock_print_scalar_signals(mock, LOG_DEBUG); + simmock_print_binary_signals(mock, LOG_DEBUG); + /* Set check conditions (for next step). */ + counter += 1.0; + snprintf(buffer, sizeof(buffer), "count is %d", (int)counter); + len = strlen(buffer) + 1; + } +} + + +int run_model_interface_tests(void) +{ + void* s = test_setup; + void* t = test_teardown; + + getcwd(__entry_path__, 200); + + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_model__minimal, s, t), + cmocka_unit_test_setup_teardown(test_model__extended, s, t), + cmocka_unit_test_setup_teardown(test_model__binary, s, t), + }; + + return cmocka_run_group_tests_name("MODEL / INTERFACE", tests, NULL, NULL); +} diff --git a/tests/cmocka/model/stub_controller.c b/tests/cmocka/model/stub_controller.c index 2bd8b77..145d552 100644 --- a/tests/cmocka/model/stub_controller.c +++ b/tests/cmocka/model/stub_controller.c @@ -77,17 +77,13 @@ void controller_exit(SimulationSpec* sim) { ModelInstanceSpec* _instptr = sim->instance_list; while (_instptr && _instptr->name) { - ModelInstancePrivate* mip = _instptr->private; - ControllerModel* cm = mip->controller_model; - if (cm->model_exit_func == NULL) goto exit_next; + if (_instptr->model_desc->vtable.destroy == NULL) goto exit_next; - log_notice("Call symbol: %s ...", MODEL_EXIT_FUNC_STR); + log_notice("Call symbol: %s ...", MODEL_DESTROY_FUNC_NAME); errno = 0; - int rc = cm->model_exit_func(_instptr); - if (rc) { - if (errno == 0) errno = rc; - log_error("model_exit_func() failed"); - } + _instptr->model_desc->vtable.destroy(_instptr->model_desc); + if (errno) log_error(MODEL_DESTROY_FUNC_NAME "() failed"); + exit_next: /* Next instance? */ _instptr++; diff --git a/tests/cmocka/model/test_ncodec.c b/tests/cmocka/model/test_ncodec.c index f772fde..8fb4d3c 100644 --- a/tests/cmocka/model/test_ncodec.c +++ b/tests/cmocka/model/test_ncodec.c @@ -2,16 +2,12 @@ // // SPDX-License-Identifier: Apache-2.0 -#include -#include -#include -#include -#include -#include -#include +#include #include #include +#include #include +#include #include @@ -39,8 +35,9 @@ static uint _sv_count(SignalVector* sv) } -static int _sv_nop(double* model_time, double stop_time) +static int _sv_nop(ModelDesc* model, double* model_time, double stop_time) { + UNUSED(model); UNUSED(model_time); UNUSED(stop_time); return 0; @@ -67,15 +64,8 @@ static int test_setup(void** state) assert_int_equal(rc, 0); mock->mi = modelc_get_model_instance(&mock->sim, args.name); assert_non_null(mock->mi); - rc = model_function_register(mock->mi, "NOP", 0.005, _sv_nop); - assert_int_equal(rc, 0); - - /* Binary channel. */ - static ModelChannelDesc binary_channel_desc = { - .name = "binary_vector", - .function_name = "NOP", - }; - rc = model_configure_channel(mock->mi, &binary_channel_desc); + ModelVTable vtable = { .step = _sv_nop }; + rc = modelc_model_create(&mock->sim, mock->mi, &vtable); assert_int_equal(rc, 0); /* Return the mock. */ @@ -104,7 +94,7 @@ void test_ncodec__ncodec_open(void** state) { ModelCMock* mock = *state; - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 1); /* Use the "binary" signal vector. */ @@ -123,8 +113,6 @@ void test_ncodec__ncodec_open(void** state) assert_null(sv->ncodec[1]); assert_non_null(sv->ncodec[2]); assert_ptr_equal(sv->codec(sv, 2), sv->ncodec[2]); - - model_sv_destroy(sv_save); } @@ -135,7 +123,7 @@ void test_ncodec__read_empty(void** state) NCodecMessage msg; /* Use the "binary" signal vector. */ - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 1); SignalVector* sv = sv_save; while (sv && sv->name) { @@ -168,8 +156,6 @@ void test_ncodec__read_empty(void** state) assert_int_equal(len, -ENOMSG); assert_int_equal(msg.len, 0); assert_null(msg.buffer); - - model_sv_destroy(sv_save); } @@ -179,7 +165,7 @@ void test_ncodec__network_stream(void** state) int rc; /* Use the "binary" signal vector. */ - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 1); SignalVector* sv = sv_save; while (sv && sv->name) { @@ -223,8 +209,6 @@ void test_ncodec__network_stream(void** state) assert_int_equal(msg.len, strlen(greeting)); assert_non_null(msg.buffer); assert_memory_equal(msg.buffer, greeting, strlen(greeting)); - - model_sv_destroy(sv_save); } @@ -233,7 +217,7 @@ void test_ncodec__config(void** state) ModelCMock* mock = *state; /* Use the "binary" signal vector. */ - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 1); SignalVector* sv = sv_save; while (sv && sv->name) { @@ -259,8 +243,6 @@ void test_ncodec__config(void** state) assert_int_equal(len, 0x66); assert_int_equal(len, sv->length[2]); assert_int_equal(((uint8_t*)(sv->binary[2]))[54], 8); - - model_sv_destroy(sv_save); } diff --git a/tests/cmocka/model/test_signal.c b/tests/cmocka/model/test_signal.c index 78e7b7a..57d3824 100644 --- a/tests/cmocka/model/test_signal.c +++ b/tests/cmocka/model/test_signal.c @@ -2,16 +2,12 @@ // // SPDX-License-Identifier: Apache-2.0 -#include -#include -#include -#include -#include -#include -#include +#include #include #include +#include #include +#include #define UNUSED(x) ((void)x) @@ -38,8 +34,9 @@ static uint _sv_count(SignalVector* sv) } -static int _sv_nop(double* model_time, double stop_time) +static int _sv_nop(ModelDesc* model, double* model_time, double stop_time) { + UNUSED(model); UNUSED(model_time); UNUSED(stop_time); return 0; @@ -66,23 +63,8 @@ static int test_setup(void** state) assert_int_equal(rc, 0); mock->mi = modelc_get_model_instance(&mock->sim, args.name); assert_non_null(mock->mi); - rc = model_function_register(mock->mi, "NOP", 0.005, _sv_nop); - assert_int_equal(rc, 0); - - /* Scalar channel. */ - static ModelChannelDesc scalar_channel_desc = { - .name = "scalar_vector", - .function_name = "NOP", - }; - rc = model_configure_channel(mock->mi, &scalar_channel_desc); - assert_int_equal(rc, 0); - - /* Binary channel. */ - static ModelChannelDesc binary_channel_desc = { - .name = "binary_vector", - .function_name = "NOP", - }; - rc = model_configure_channel(mock->mi, &binary_channel_desc); + ModelVTable vtable = { .step = _sv_nop }; + rc = modelc_model_create(&mock->sim, mock->mi, &vtable); assert_int_equal(rc, 0); /* Return the mock. */ @@ -111,7 +93,7 @@ void test_signal__scalar(void** state) { ModelCMock* mock = *state; - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 2); /* Use the "scalar" signal vector. */ @@ -125,7 +107,7 @@ void test_signal__scalar(void** state) /* General properties. */ assert_string_equal(sv->name, "scalar"); assert_string_equal(sv->alias, "scalar_vector"); - assert_string_equal(sv->function_name, "NOP"); + assert_string_equal(sv->function_name, "model_step"); assert_int_equal(sv->count, 2); assert_int_equal(sv->is_binary, false); assert_non_null(sv->signal); @@ -151,8 +133,6 @@ void test_signal__scalar(void** state) sv->append(sv, i, (void*)"1234", 4); /* NOP */ assert_double_equal(sv->scalar[i], test_val, DBL_EPSILON); } - - model_sv_destroy(sv_save); } @@ -160,7 +140,7 @@ void test_signal__binary(void** state) { ModelCMock* mock = *state; - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 2); /* Use the "binary" signal vector. */ @@ -174,7 +154,7 @@ void test_signal__binary(void** state) /* General properties. */ assert_string_equal(sv->name, "binary"); assert_string_equal(sv->alias, "binary_vector"); - assert_string_equal(sv->function_name, "NOP"); + assert_string_equal(sv->function_name, "model_step"); assert_int_equal(sv->count, 2); assert_int_equal(sv->is_binary, true); assert_non_null(sv->signal); @@ -230,8 +210,6 @@ void test_signal__binary(void** state) /* Cleanup. */ free(test_val); } - - model_sv_destroy(sv_save); } @@ -239,7 +217,7 @@ void test_signal__annotations(void** state) { ModelCMock* mock = *state; - SignalVector* sv_save = model_sv_create(mock->mi); + SignalVector* sv_save = mock->mi->model_desc->sv; assert_int_equal(_sv_count(sv_save), 2); /* Use the "binary" signal vector. */ @@ -262,8 +240,6 @@ void test_signal__annotations(void** state) assert_string_equal(value, "binary_bar"); value = sv->annotation(sv, 1, "mime_type"); assert_string_equal(value, "application/custom-stream"); - - model_sv_destroy(sv_save); } @@ -278,5 +254,5 @@ int run_signal_tests(void) cmocka_unit_test_setup_teardown(test_signal__annotations, s, t), }; - return cmocka_run_group_tests_name("NCODEC", tests, NULL, NULL); + return cmocka_run_group_tests_name("SIGNAL", tests, NULL, NULL); } diff --git a/tests/pytest/modelc/test_modelc.py b/tests/pytest/modelc/test_modelc.py index c773c76..8e6fe98 100644 --- a/tests/pytest/modelc/test_modelc.py +++ b/tests/pytest/modelc/test_modelc.py @@ -22,8 +22,7 @@ # Sandbox for the Model (common only, specific in test cases). MODEL_YAML = 'data/model.yaml' -SIGNAL_GROUP_YAML = 'data/signal_group.yaml' -STACK_YAML = 'data/stack.yaml' +STACK_YAML = 'data/simulation.yaml' async def run(dir, cmd): @@ -81,21 +80,21 @@ async def main(params, checks): def test_modelc_double(): params = { - 'MODEL_SANDBOX_DIR': os.getenv('MODELC_SANDBOX_DIR')+'/examples/dynamic', + 'MODEL_SANDBOX_DIR': os.getenv('MODELC_SANDBOX_DIR')+'/examples/minimal', 'models': [ { - 'MODEL_INST': 'dynamic_model_instance', - 'MODEL_YAML_FILES': f'{MODEL_YAML} ' + f'{STACK_YAML} ' + f'{SIGNAL_GROUP_YAML}', + 'MODEL_INST': 'minimal_inst', + 'MODEL_YAML_FILES': f'{MODEL_YAML} ' + f'{STACK_YAML} ', }, ] } checks = [ - 'SignalValue: 2851307223 = 4.800000 [name=foo]', - 'SignalValue: 1991736602 = 16.800000 [name=bar]', + 'SignalValue: 2628574755 = 4.000000 [name=counter]', ] asyncio.run(main(params, checks)) +@pytest.mark.skip(reason="needs refactor") @pytest.mark.skipif(os.environ["PACKAGE_ARCH"] != "linux-amd64", reason="test only runs on linux-amd64") def test_modelc_binary(): # Two models write data at same cycle (ModelReady). SimBus should append @@ -106,11 +105,11 @@ def test_modelc_binary(): 'models': [ { 'MODEL_INST': 'binary_model_instance', - 'MODEL_YAML_FILES' : f'{MODEL_YAML} ' + f'{STACK_YAML} ' + f'{SIGNAL_GROUP_YAML}', + 'MODEL_YAML_FILES' : f'{MODEL_YAML} ' + f'{STACK_YAML} ', }, { 'MODEL_INST': 'second_binary_model_instance', - 'MODEL_YAML_FILES' : f'{MODEL_YAML} ' + f'{STACK_YAML} ' + f'{SIGNAL_GROUP_YAML}', + 'MODEL_YAML_FILES' : f'{MODEL_YAML} ' + f'{STACK_YAML} ', }, ] } diff --git a/tests/pytest/modelc/test_mstep.py b/tests/pytest/modelc/test_mstep.py index 4ac1c47..f1774ee 100644 --- a/tests/pytest/modelc/test_mstep.py +++ b/tests/pytest/modelc/test_mstep.py @@ -19,13 +19,12 @@ MODELC_SANDBOX_DIR = os.getenv('MODELC_SANDBOX_DIR') MSTEP_EXE = MODELC_SANDBOX_DIR+'/bin/mstep' -# Sandbox for the Dynamic Model (test basis). -MODEL_SANDBOX_DIR = os.getenv('MODELC_SANDBOX_DIR')+'/examples/dynamic' -DYNAMIC_MODEL_INST = 'dynamic_model_instance' +# Sandbox for the Minimal Model (test basis). +MODEL_SANDBOX_DIR = os.getenv('MODELC_SANDBOX_DIR')+'/examples/minimal' +DYNAMIC_MODEL_INST = 'minimal_inst' DYNAMIC_MODEL_YAML = 'data/model.yaml' -DYNAMIC_MODEL_LIB = 'lib/dynamic_model.so' # Not used, see model.yaml. -SIGNAL_GROUP_YAML = 'data/signal_group.yaml' -STACK_YAML = 'data/stack.yaml' +DYNAMIC_MODEL_LIB = 'lib/libminimal.so' # Not used, see model.yaml. +STACK_YAML = 'data/simulation.yaml' async def run(dir, cmd): @@ -46,7 +45,7 @@ async def main(): result_list = await asyncio.gather( asyncio.wait_for( run( - MODEL_SANDBOX_DIR, f'{MSTEP_EXE} --logger 2 --name {DYNAMIC_MODEL_INST} ' + f'{DYNAMIC_MODEL_YAML} ' + f'{STACK_YAML} ' + f'{SIGNAL_GROUP_YAML} ' + ''), timeout=TIMEOUT), + MODEL_SANDBOX_DIR, f'{MSTEP_EXE} --logger 2 --name {DYNAMIC_MODEL_INST} ' + f'{DYNAMIC_MODEL_YAML} ' + f'{STACK_YAML} ' + ''), timeout=TIMEOUT), ) for result in result_list: print('************************************************************') @@ -64,11 +63,9 @@ async def main(): for result in result_list: assert result['rc'] == 0 - assert 'value: 12' in result['stdout'] - assert 'value: 42' in result['stdout'] + assert 'value: 10' in result['stdout'] assert 'Starting Simulation (for 10 steps) ...' in result['stdout'] - assert 'Model Function: example' in result['stdout'] - assert 'Model function model_exit called' in result['stdout'] + assert 'Model Function: model_step' in result['stdout'] if __name__ == '__main__': diff --git a/tests/pytest/modelc/test_stacked_modelc.py b/tests/pytest/modelc/test_stacked_modelc.py index aad8461..b0e0bae 100644 --- a/tests/pytest/modelc/test_stacked_modelc.py +++ b/tests/pytest/modelc/test_stacked_modelc.py @@ -77,6 +77,7 @@ async def main(params, checks): assert found, check +@pytest.mark.skip(reason="Needs refactor") def test_modelc_stack(): # Two models executed by the same instance of ModelC. params = {