can-api-generator 2.4.0__tar.gz → 2.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/PKG-INFO +57 -1
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/README.md +55 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/pyproject.toml +1 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/__about__.py +1 -1
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/code_generator.py +3 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/main.py +96 -24
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/header_template.jinja +8 -3
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/source_template.jinja +7 -1
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/tx_macros.jinja +126 -8
- can_api_generator-2.6.0/tests/test_config_file.py +132 -0
- can_api_generator-2.6.0/tests/test_seed.py +32 -0
- can_api_generator-2.6.0/tests/test_tx_timing_delta.py +308 -0
- can_api_generator-2.6.0/uv.lock +905 -0
- can_api_generator-2.4.0/Advantics_Bootloader.kcd +0 -384
- can_api_generator-2.4.0/manual_api_test.c +0 -93
- can_api_generator-2.4.0/manual_api_test.h +0 -60
- can_api_generator-2.4.0/manual_api_test.o +0 -0
- can_api_generator-2.4.0/test_1_rx_over_can +0 -0
- can_api_generator-2.4.0/test_api.c +0 -78
- can_api_generator-2.4.0/test_api.h +0 -68
- can_api_generator-2.4.0/test_kcd_api_test_mux_with_same_signal_names_labeled_mux_variants.c +0 -686
- can_api_generator-2.4.0/test_mux_with_same_signal_names_labeled_mux_variants.c +0 -237
- can_api_generator-2.4.0/test_mux_with_same_signal_names_labeled_mux_variants.h +0 -265
- can_api_generator-2.4.0/test_test_1_rx_over_can.c +0 -65
- can_api_generator-2.4.0/test_test_basic_multiplex_rx_over_can.c +0 -67
- can_api_generator-2.4.0/test_test_mux_with_partially_labled_index_rx_over_can.c +0 -67
- can_api_generator-2.4.0/test_test_mux_with_same_signal_names_labeled_mux_variants_rx_over_can.c +0 -67
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/.gitignore +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/LICENSE.txt +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/manual_cag_test.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/__init__.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/cbdb_generator.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/msg_processor.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/callback_macros.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/canframe.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/declaration_macros.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/dyndec_header.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/dyndec_source.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/encoding_macros.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/rx_macros.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/types.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/src/can_api_generator/utils.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/__init__.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/cantool_test_utils.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/compat_shim.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/dyndec_test_harness.c +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/multiple_busses_test.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_1.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_basic_multiplex.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_big_endian.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_can_db_model_dep.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_cbdb_generator.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_cli.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_cross_interface_compat.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_cross_interface_compat.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_dyndec_round_trip.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_float_wrong_length.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_message_parser.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_missing_consumer.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_missing_producer.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_mux_group_count_out_of_order.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_mux_with_labeled_index.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_mux_with_partially_labled_index.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_mux_with_same_signal_names.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_mux_with_same_signal_names_labeled_mux_variants.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_mux_with_scale_and_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_non_encodable_0.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_overlapping_signals.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_periodic_tx_over_can.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_procedures.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_prog_source_template.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_rx_over_can.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_direction.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/double_plain.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/double_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/double_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/float_plain.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/float_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/float_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_fractional_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_plain.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_plain.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/test_decoding_numerical_value.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/test_encoding_numerical_value.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/test_signal_encoding_wrong_float_size.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_plain.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_plain.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_scaled.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_scaled_offset.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_signal_info.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_time_callback_arg.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_too_large_message.kcd +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_tx_function.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_tx_over_can.jinja +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_utils.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_vcan_round_trip.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_yaml_cbdb.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_yaml_input.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/tests/test_yaml_kcd_equivalence.py +0 -0
- {can_api_generator-2.4.0 → can_api_generator-2.6.0}/todo.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: can-api-generator
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: Program to generate a 'signal' style CAN API in C
|
|
5
5
|
Project-URL: Documentation, https://sr.ht/~laplace/can-api-generator#readme
|
|
6
6
|
Project-URL: Issues, https://sr.ht/~laplace/can-api-generator/issues
|
|
@@ -20,6 +20,7 @@ Requires-Dist: can-db-model>=0.1
|
|
|
20
20
|
Requires-Dist: cantools
|
|
21
21
|
Requires-Dist: click
|
|
22
22
|
Requires-Dist: jinja2
|
|
23
|
+
Requires-Dist: pyyaml
|
|
23
24
|
Requires-Dist: rich
|
|
24
25
|
Description-Content-Type: text/markdown
|
|
25
26
|
|
|
@@ -56,6 +57,7 @@ Description-Content-Type: text/markdown
|
|
|
56
57
|
- [`api`](#api)
|
|
57
58
|
- [`cbdb`](#cbdb)
|
|
58
59
|
- [`dyndec`](#dyndec)
|
|
60
|
+
- [Config file](#config-file)
|
|
59
61
|
|
|
60
62
|
## Installation
|
|
61
63
|
|
|
@@ -242,6 +244,31 @@ slot (`now % period == offset`); the missed slot is skipped, not caught up.
|
|
|
242
244
|
The `tx_callback` rules are unchanged: in callback-only mode a `NULL` return queues nothing, and `send_now` stays set as well. Works with and without
|
|
243
245
|
`--tx-signal-store`.
|
|
244
246
|
|
|
247
|
+
#### Delta timing (`--tx-timing delta`)
|
|
248
|
+
By default `<api>_periodic_tx` takes an absolute time and fires a message only when `now % period == offset`, so it has to be called on every tick. With
|
|
249
|
+
`--tx-timing delta` it instead takes the number of ticks elapsed since the previous call, and each message counts down on its own:
|
|
250
|
+
```c
|
|
251
|
+
void <api>_periodic_tx_init(struct <Prefix>TxSignals *tx_signals);
|
|
252
|
+
uint16_t <api>_periodic_tx(struct <Prefix>TxSignals *tx_signals, CanFrame *output_frame, uint32_t dt);
|
|
253
|
+
|
|
254
|
+
uint32_t dt = now - prev;
|
|
255
|
+
prev = now;
|
|
256
|
+
while (<api>_periodic_tx(&tx_signals, &frame, dt)) {
|
|
257
|
+
send(&frame);
|
|
258
|
+
dt = 0; // drain the other messages that fell due
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
Every message whose countdown runs out during `dt` is marked pending; one pending frame is returned per call, in message order, and the rest are drained by calling
|
|
262
|
+
again with `dt = 0`. With `--tx-function` there is no draining: one call hands every pending message to the sink, and a frame the sink rejects stays pending and is
|
|
263
|
+
retried on the next call (unlike absolute timing, where the slot is missed).
|
|
264
|
+
If `dt` spans several periods (a stall), the message is sent once and rescheduled to the next slot on its original grid, so its phase does not change. A message
|
|
265
|
+
whose countdown runs out while `enable` is 0 is skipped, but its countdown keeps running. In callback-only mode a `NULL` callback return sends nothing for that slot.
|
|
266
|
+
`send_now` behaves as with absolute timing; if it coincides with a due slot, a single frame is sent.
|
|
267
|
+
|
|
268
|
+
In `MsgTxContext`, `last_tx` is replaced by `remaining` (ticks until the next slot) and `pending`. `<api>_periodic_tx_init` takes no time argument, and
|
|
269
|
+
`<api>_update_tx_period(ctx, period)` re-phases the message to `offset + 1` ticks from the next call.
|
|
270
|
+
`--time-as-tx-callback-arg` cannot be combined with delta timing, as there is no absolute time to pass.
|
|
271
|
+
|
|
245
272
|
### Encode All Signals
|
|
246
273
|
Some messages use multiplexes combining many signals in to a single message. This may be particularly true for configuration messages that have many related parameters and use
|
|
247
274
|
multiplexes to fit all parameters in to a single message using many mux groups. If the entire config should be read out and the read back happens periodically, the supervisory controller
|
|
@@ -610,6 +637,7 @@ to a mux group. The message list is followed immediately by that message's signa
|
|
|
610
637
|
## Command-line reference
|
|
611
638
|
|
|
612
639
|
All generation is done through subcommands of `can-api-gen`. Run `can-api-gen COMMAND --help` for the authoritative option list.
|
|
640
|
+
Every command also accepts `--config FILE`; see [Config file](#config-file).
|
|
613
641
|
|
|
614
642
|
### `api`
|
|
615
643
|
|
|
@@ -663,6 +691,8 @@ Options:
|
|
|
663
691
|
`<api>_periodic_tx(tx_signals, now)` then queues every due message through it in one pass and returns the number accepted. A 0 return leaves `last_tx` and
|
|
664
692
|
`send_now` untouched so the message is retried. See [Queueing frames through a bound TX function](#queueing-frames-through-a-bound-tx-function). Only meaningful
|
|
665
693
|
together with `-p`.
|
|
694
|
+
* `--tx-timing [absolute|delta]` — `absolute` (default) passes the current time to `<api>_periodic_tx`; `delta` passes the ticks since the previous call. See
|
|
695
|
+
[Delta timing](#delta-timing---tx-timing-delta). Only meaningful together with `-p`; cannot be combined with `--time-as-tx-callback-arg`.
|
|
666
696
|
* `--rx-signal-store` — generate the permanent per-message RX signal store (the pre-2.0 default). Without it, global RX is callback-only: no store is
|
|
667
697
|
generated and decoded signals reach the application only through the RX callback. See [Global RX](#global-rx). Only meaningful together with `-r`.
|
|
668
698
|
* `--with-rx-valid` — in callback-only mode, add a `valid` field to `MsgRxContext` and set it on each matched frame, for struct-layout compatibility with
|
|
@@ -679,6 +709,8 @@ Options:
|
|
|
679
709
|
to an existing project's frame struct naming.
|
|
680
710
|
* `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
|
|
681
711
|
* `-pm`, `--payload-member-name TEXT` — override the name of the `CanFrame` payload member (default `payload`).
|
|
712
|
+
* `--seed INT` — seed the random number generator that picks each periodic message's `offset_seed`, so repeated runs produce identical output.
|
|
713
|
+
Unseeded by default, so every run picks new values.
|
|
682
714
|
* `-v`, `--verbose` — dump the processed message dicts that get fed into the Jinja templates. Useful when debugging template or generator changes.
|
|
683
715
|
* `--help` — show the CLI help and exit.
|
|
684
716
|
|
|
@@ -715,3 +747,27 @@ Options:
|
|
|
715
747
|
* `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
|
|
716
748
|
* `-pm`, `--payload-member-name TEXT` — override the name of the `CanFrame` payload member (default `payload`).
|
|
717
749
|
* `--help` — show the CLI help and exit.
|
|
750
|
+
|
|
751
|
+
### Config file
|
|
752
|
+
|
|
753
|
+
Instead of repeating a long flag list, put the options in a YAML file and pass it with `--config FILE` to any command. The file has one section per command, so
|
|
754
|
+
one file can serve `api`, `cbdb` and `dyndec`; a command reads only its own section. Keys are the long option names without the leading `--` or the
|
|
755
|
+
positional argument names (dashes or underscores both work), and values are the option values (`true`/`false` for flags). A relative `db-file` is resolved
|
|
756
|
+
against the config file's directory; output files are still written to the working directory.
|
|
757
|
+
|
|
758
|
+
```yaml
|
|
759
|
+
api:
|
|
760
|
+
db-file: db.kcd
|
|
761
|
+
library-name: my_api
|
|
762
|
+
node-name: DUT
|
|
763
|
+
periodic-tx: true
|
|
764
|
+
tx-signal-store: true
|
|
765
|
+
time-as-tx-callback-arg: true
|
|
766
|
+
id-member-name: can_id
|
|
767
|
+
dyndec:
|
|
768
|
+
id-member-name: can_id
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
Anything given on the command line overrides the file. Every flag has a `--no-` form for this, e.g.
|
|
772
|
+
`can-api-gen api --config can.yaml --no-tx-signal-store`. Positional arguments given on the command line fill from the left and take precedence over the
|
|
773
|
+
file, so `can-api-gen api --config can.yaml other.kcd other_api DUT` ignores all three from the file. An unknown key or an invalid value is an error.
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
- [`api`](#api)
|
|
32
32
|
- [`cbdb`](#cbdb)
|
|
33
33
|
- [`dyndec`](#dyndec)
|
|
34
|
+
- [Config file](#config-file)
|
|
34
35
|
|
|
35
36
|
## Installation
|
|
36
37
|
|
|
@@ -217,6 +218,31 @@ slot (`now % period == offset`); the missed slot is skipped, not caught up.
|
|
|
217
218
|
The `tx_callback` rules are unchanged: in callback-only mode a `NULL` return queues nothing, and `send_now` stays set as well. Works with and without
|
|
218
219
|
`--tx-signal-store`.
|
|
219
220
|
|
|
221
|
+
#### Delta timing (`--tx-timing delta`)
|
|
222
|
+
By default `<api>_periodic_tx` takes an absolute time and fires a message only when `now % period == offset`, so it has to be called on every tick. With
|
|
223
|
+
`--tx-timing delta` it instead takes the number of ticks elapsed since the previous call, and each message counts down on its own:
|
|
224
|
+
```c
|
|
225
|
+
void <api>_periodic_tx_init(struct <Prefix>TxSignals *tx_signals);
|
|
226
|
+
uint16_t <api>_periodic_tx(struct <Prefix>TxSignals *tx_signals, CanFrame *output_frame, uint32_t dt);
|
|
227
|
+
|
|
228
|
+
uint32_t dt = now - prev;
|
|
229
|
+
prev = now;
|
|
230
|
+
while (<api>_periodic_tx(&tx_signals, &frame, dt)) {
|
|
231
|
+
send(&frame);
|
|
232
|
+
dt = 0; // drain the other messages that fell due
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
Every message whose countdown runs out during `dt` is marked pending; one pending frame is returned per call, in message order, and the rest are drained by calling
|
|
236
|
+
again with `dt = 0`. With `--tx-function` there is no draining: one call hands every pending message to the sink, and a frame the sink rejects stays pending and is
|
|
237
|
+
retried on the next call (unlike absolute timing, where the slot is missed).
|
|
238
|
+
If `dt` spans several periods (a stall), the message is sent once and rescheduled to the next slot on its original grid, so its phase does not change. A message
|
|
239
|
+
whose countdown runs out while `enable` is 0 is skipped, but its countdown keeps running. In callback-only mode a `NULL` callback return sends nothing for that slot.
|
|
240
|
+
`send_now` behaves as with absolute timing; if it coincides with a due slot, a single frame is sent.
|
|
241
|
+
|
|
242
|
+
In `MsgTxContext`, `last_tx` is replaced by `remaining` (ticks until the next slot) and `pending`. `<api>_periodic_tx_init` takes no time argument, and
|
|
243
|
+
`<api>_update_tx_period(ctx, period)` re-phases the message to `offset + 1` ticks from the next call.
|
|
244
|
+
`--time-as-tx-callback-arg` cannot be combined with delta timing, as there is no absolute time to pass.
|
|
245
|
+
|
|
220
246
|
### Encode All Signals
|
|
221
247
|
Some messages use multiplexes combining many signals in to a single message. This may be particularly true for configuration messages that have many related parameters and use
|
|
222
248
|
multiplexes to fit all parameters in to a single message using many mux groups. If the entire config should be read out and the read back happens periodically, the supervisory controller
|
|
@@ -585,6 +611,7 @@ to a mux group. The message list is followed immediately by that message's signa
|
|
|
585
611
|
## Command-line reference
|
|
586
612
|
|
|
587
613
|
All generation is done through subcommands of `can-api-gen`. Run `can-api-gen COMMAND --help` for the authoritative option list.
|
|
614
|
+
Every command also accepts `--config FILE`; see [Config file](#config-file).
|
|
588
615
|
|
|
589
616
|
### `api`
|
|
590
617
|
|
|
@@ -638,6 +665,8 @@ Options:
|
|
|
638
665
|
`<api>_periodic_tx(tx_signals, now)` then queues every due message through it in one pass and returns the number accepted. A 0 return leaves `last_tx` and
|
|
639
666
|
`send_now` untouched so the message is retried. See [Queueing frames through a bound TX function](#queueing-frames-through-a-bound-tx-function). Only meaningful
|
|
640
667
|
together with `-p`.
|
|
668
|
+
* `--tx-timing [absolute|delta]` — `absolute` (default) passes the current time to `<api>_periodic_tx`; `delta` passes the ticks since the previous call. See
|
|
669
|
+
[Delta timing](#delta-timing---tx-timing-delta). Only meaningful together with `-p`; cannot be combined with `--time-as-tx-callback-arg`.
|
|
641
670
|
* `--rx-signal-store` — generate the permanent per-message RX signal store (the pre-2.0 default). Without it, global RX is callback-only: no store is
|
|
642
671
|
generated and decoded signals reach the application only through the RX callback. See [Global RX](#global-rx). Only meaningful together with `-r`.
|
|
643
672
|
* `--with-rx-valid` — in callback-only mode, add a `valid` field to `MsgRxContext` and set it on each matched frame, for struct-layout compatibility with
|
|
@@ -654,6 +683,8 @@ Options:
|
|
|
654
683
|
to an existing project's frame struct naming.
|
|
655
684
|
* `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
|
|
656
685
|
* `-pm`, `--payload-member-name TEXT` — override the name of the `CanFrame` payload member (default `payload`).
|
|
686
|
+
* `--seed INT` — seed the random number generator that picks each periodic message's `offset_seed`, so repeated runs produce identical output.
|
|
687
|
+
Unseeded by default, so every run picks new values.
|
|
657
688
|
* `-v`, `--verbose` — dump the processed message dicts that get fed into the Jinja templates. Useful when debugging template or generator changes.
|
|
658
689
|
* `--help` — show the CLI help and exit.
|
|
659
690
|
|
|
@@ -690,3 +721,27 @@ Options:
|
|
|
690
721
|
* `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
|
|
691
722
|
* `-pm`, `--payload-member-name TEXT` — override the name of the `CanFrame` payload member (default `payload`).
|
|
692
723
|
* `--help` — show the CLI help and exit.
|
|
724
|
+
|
|
725
|
+
### Config file
|
|
726
|
+
|
|
727
|
+
Instead of repeating a long flag list, put the options in a YAML file and pass it with `--config FILE` to any command. The file has one section per command, so
|
|
728
|
+
one file can serve `api`, `cbdb` and `dyndec`; a command reads only its own section. Keys are the long option names without the leading `--` or the
|
|
729
|
+
positional argument names (dashes or underscores both work), and values are the option values (`true`/`false` for flags). A relative `db-file` is resolved
|
|
730
|
+
against the config file's directory; output files are still written to the working directory.
|
|
731
|
+
|
|
732
|
+
```yaml
|
|
733
|
+
api:
|
|
734
|
+
db-file: db.kcd
|
|
735
|
+
library-name: my_api
|
|
736
|
+
node-name: DUT
|
|
737
|
+
periodic-tx: true
|
|
738
|
+
tx-signal-store: true
|
|
739
|
+
time-as-tx-callback-arg: true
|
|
740
|
+
id-member-name: can_id
|
|
741
|
+
dyndec:
|
|
742
|
+
id-member-name: can_id
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
Anything given on the command line overrides the file. Every flag has a `--no-` form for this, e.g.
|
|
746
|
+
`can-api-gen api --config can.yaml --no-tx-signal-store`. Positional arguments given on the command line fill from the left and take precedence over the
|
|
747
|
+
file, so `can-api-gen api --config can.yaml other.kcd other_api DUT` ignores all three from the file. An unknown key or an invalid value is an error.
|
|
@@ -52,6 +52,7 @@ def generate_api_implementation(msgs: list[dict],
|
|
|
52
52
|
tx_function: bool = False,
|
|
53
53
|
time_as_rx_callback_arg: bool = False,
|
|
54
54
|
time_as_tx_callback_arg: bool = False,
|
|
55
|
+
tx_timing: str = "absolute",
|
|
55
56
|
):
|
|
56
57
|
header_template = jinja_env.get_template("header_template.jinja")
|
|
57
58
|
source_template = jinja_env.get_template("source_template.jinja")
|
|
@@ -94,6 +95,7 @@ def generate_api_implementation(msgs: list[dict],
|
|
|
94
95
|
tx_function=tx_function,
|
|
95
96
|
time_as_rx_callback_arg=time_as_rx_callback_arg,
|
|
96
97
|
time_as_tx_callback_arg=time_as_tx_callback_arg,
|
|
98
|
+
tx_timing=tx_timing,
|
|
97
99
|
)
|
|
98
100
|
source_code = source_template.render(
|
|
99
101
|
messages=msgs,
|
|
@@ -123,6 +125,7 @@ def generate_api_implementation(msgs: list[dict],
|
|
|
123
125
|
tx_function=tx_function,
|
|
124
126
|
time_as_rx_callback_arg=time_as_rx_callback_arg,
|
|
125
127
|
time_as_tx_callback_arg=time_as_tx_callback_arg,
|
|
128
|
+
tx_timing=tx_timing,
|
|
126
129
|
)
|
|
127
130
|
canframe_header_code = canframe_template.render(
|
|
128
131
|
arb_id_member_name=arb_id_member_name,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from can_api_generator.types import SignalDirection
|
|
2
2
|
from importlib.metadata import files
|
|
3
3
|
import hashlib
|
|
4
|
+
import random
|
|
4
5
|
import json
|
|
5
6
|
import click
|
|
6
7
|
import rich
|
|
@@ -12,6 +13,55 @@ from can_api_generator.cbdb_generator import generate_cbdb, build_sidecar, CbdbG
|
|
|
12
13
|
from can_api_generator.utils import converrt_to_c_identifier
|
|
13
14
|
from jinja2 import Environment, FileSystemLoader
|
|
14
15
|
from pathlib import Path
|
|
16
|
+
import yaml
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_config(ctx, param, value):
|
|
20
|
+
"""Turn the command's section of a YAML config file into click defaults.
|
|
21
|
+
|
|
22
|
+
The file maps command names to option tables, e.g. {"api": {"periodic-tx":
|
|
23
|
+
true}}. Keys are long option names or positional argument names (dashes
|
|
24
|
+
or underscores). The values become ctx.default_map, so everything given on
|
|
25
|
+
the command line still takes precedence over the file. Relative file
|
|
26
|
+
arguments are resolved against the config file's directory.
|
|
27
|
+
"""
|
|
28
|
+
if value is None:
|
|
29
|
+
return
|
|
30
|
+
try:
|
|
31
|
+
with open(value) as config_file:
|
|
32
|
+
data = yaml.safe_load(config_file)
|
|
33
|
+
except (OSError, yaml.YAMLError) as e:
|
|
34
|
+
raise click.BadParameter(f"cannot read config file: {e}", ctx, param)
|
|
35
|
+
if data is None:
|
|
36
|
+
data = {}
|
|
37
|
+
if not isinstance(data, dict):
|
|
38
|
+
raise click.BadParameter(
|
|
39
|
+
"the config file must map command names to option tables", ctx, param)
|
|
40
|
+
section = data.get(ctx.info_name) or {}
|
|
41
|
+
if not isinstance(section, dict):
|
|
42
|
+
raise click.BadParameter(
|
|
43
|
+
f"section '{ctx.info_name}' must map option names to values", ctx, param)
|
|
44
|
+
known = {p.name: p for p in ctx.command.params if p.name != "config"}
|
|
45
|
+
defaults = {}
|
|
46
|
+
for key, option_value in section.items():
|
|
47
|
+
name = str(key).replace("-", "_")
|
|
48
|
+
if name not in known:
|
|
49
|
+
raise click.BadParameter(
|
|
50
|
+
f"unknown option '{key}' in section '{ctx.info_name}'", ctx, param)
|
|
51
|
+
if (isinstance(known[name], click.Argument)
|
|
52
|
+
and isinstance(known[name].type, click.Path)
|
|
53
|
+
and isinstance(option_value, str)):
|
|
54
|
+
option_value = str(Path(value).parent / option_value)
|
|
55
|
+
defaults[name] = option_value
|
|
56
|
+
ctx.default_map = {**(ctx.default_map or {}), **defaults}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
config_option = click.option(
|
|
60
|
+
"--config", type=click.Path(exists=True, dir_okay=False),
|
|
61
|
+
is_eager=True, expose_value=False, callback=_load_config,
|
|
62
|
+
help="YAML file providing defaults for this command's options and "
|
|
63
|
+
"arguments, under a section named after the command (api, cbdb, "
|
|
64
|
+
"dyndec). Anything given on the command line overrides the file.")
|
|
15
65
|
|
|
16
66
|
|
|
17
67
|
@click.group()
|
|
@@ -23,13 +73,14 @@ def main():
|
|
|
23
73
|
|
|
24
74
|
|
|
25
75
|
@main.command()
|
|
76
|
+
@config_option
|
|
26
77
|
@click.argument("DB_File", type=click.Path(exists=True, dir_okay=False),
|
|
27
78
|
required=True, nargs=1)
|
|
28
79
|
@click.argument("Library_Name", type=str, required=True)
|
|
29
80
|
@click.argument("Node_Name", type=str, required=True)
|
|
30
|
-
@click.option("-f", "--force",
|
|
81
|
+
@click.option("-f", "--force/--no-force", required=False, default=False,
|
|
31
82
|
help="Overwrite existing output files")
|
|
32
|
-
@click.option("-a", "--encode-all-signals-func",
|
|
83
|
+
@click.option("-a", "--encode-all-signals-func/--no-encode-all-signals-func", default=False,
|
|
33
84
|
help="Generate a function for each message that encodes every signal into frames at least once,"
|
|
34
85
|
" this is helpful when some signals are inside of a mux, but all signals need to be sent "
|
|
35
86
|
" regardless of how many frames need to be encoded to send the state of each signal at least"
|
|
@@ -50,74 +101,74 @@ def main():
|
|
|
50
101
|
@click.option("-pm", "--payload-member-name", type=str, default="payload",
|
|
51
102
|
help="The name of the CanFrame struct member that holds the "
|
|
52
103
|
"payload as uint64")
|
|
53
|
-
@click.option("-r", "--global-rx",
|
|
104
|
+
@click.option("-r", "--global-rx/--no-global-rx", default=False,
|
|
54
105
|
help="Generate a function and api-wide struct that updates an"
|
|
55
106
|
" api message struct upon reception of a matching frame")
|
|
56
|
-
@click.option("-p", "--periodic-tx",
|
|
107
|
+
@click.option("-p", "--periodic-tx/--no-periodic-tx", default=False,
|
|
57
108
|
help="Generate code that will define a TX struct as well as a function "
|
|
58
109
|
"that periodically sends the messages according to their "
|
|
59
110
|
"periodicity")
|
|
60
|
-
@click.option("--ti-compatible",
|
|
111
|
+
@click.option("--ti-compatible/--no-ti-compatible", default=False,
|
|
61
112
|
help="Generate C code that can be compiled using the TI C2000 compiler"
|
|
62
113
|
" The TI compiler does not handle variable declarations inside of case"
|
|
63
114
|
" blocks so the variable declaration is moved to the top of a switch")
|
|
64
|
-
@click.option("--send-now",
|
|
115
|
+
@click.option("--send-now/--no-send-now", default=False,
|
|
65
116
|
help="Add mechanism in to the periodic tx function that allows to immediately "
|
|
66
117
|
"send a message even if it is not enabled or has just been sent."
|
|
67
118
|
" This is useful for updating critical signals as early as possible after a change")
|
|
68
|
-
@click.option("--double-buffered",
|
|
119
|
+
@click.option("--double-buffered/--no-double-buffered", default=False,
|
|
69
120
|
help="Generate double-buffered signal storage so that an ISR can safely decode"
|
|
70
121
|
" RX frames without exposing a partially-decoded struct to readers, and so"
|
|
71
122
|
" that user code can stage TX signal updates without racing the periodic TX"
|
|
72
123
|
" encoder. Swaps are performed via per-message pointer swaps; an explicit"
|
|
73
124
|
" <api>_<msg>_commit call is required to publish staged TX values.")
|
|
74
|
-
@click.option("--rx-callback-context",
|
|
125
|
+
@click.option("--rx-callback-context/--no-rx-callback-context", default=False,
|
|
75
126
|
help="Add a void *rx_callback_context field to MsgRxContext and "
|
|
76
127
|
"pass it as the sole argument to the RX callback, widening "
|
|
77
128
|
"its signature to void (*rx_callback)(void *).")
|
|
78
|
-
@click.option("--tx-callback-context",
|
|
129
|
+
@click.option("--tx-callback-context/--no-tx-callback-context", default=False,
|
|
79
130
|
help="Add a void *tx_callback_context field to MsgTxContext and "
|
|
80
131
|
"pass it as the sole argument to the TX callback, widening "
|
|
81
132
|
"its signature to void (*tx_callback)(void *).")
|
|
82
|
-
@click.option("--msg-as-rx-callback-arg",
|
|
133
|
+
@click.option("--msg-as-rx-callback-arg/--no-msg-as-rx-callback-arg", default=False,
|
|
83
134
|
help="Pass a void * to the message's just-decoded signal struct "
|
|
84
135
|
"as the first argument to the RX callback. Composes with "
|
|
85
136
|
"--rx-callback-context, which appends the context pointer as "
|
|
86
137
|
"a second argument. Only meaningful together with -r.")
|
|
87
|
-
@click.option("--rx-signal-store",
|
|
138
|
+
@click.option("--rx-signal-store/--no-rx-signal-store", default=False,
|
|
88
139
|
help="Generate a permanent per-message RX signal store in the "
|
|
89
140
|
"global RX struct (the default before v2.0). Without it, "
|
|
90
141
|
"global RX is callback-only: decoded signals reach the "
|
|
91
142
|
"application solely through the per-message RX callback and "
|
|
92
143
|
"are never stored. Only meaningful together with -r.")
|
|
93
|
-
@click.option("--with-rx-valid",
|
|
144
|
+
@click.option("--with-rx-valid/--no-with-rx-valid", default=False,
|
|
94
145
|
help="In callback-only mode (no --rx-signal-store), add a valid "
|
|
95
146
|
"field to MsgRxContext and set it on each matched frame, for "
|
|
96
147
|
"struct-layout compatibility with store-based APIs. No effect "
|
|
97
148
|
"when --rx-signal-store is set.")
|
|
98
|
-
@click.option("--msg-as-tx-callback-arg",
|
|
149
|
+
@click.option("--msg-as-tx-callback-arg/--no-msg-as-tx-callback-arg", default=False,
|
|
99
150
|
help="Pass a void * to the message's store struct (the one about "
|
|
100
151
|
"to be encoded) as the first argument to the TX callback. "
|
|
101
152
|
"Composes with --tx-callback-context, which appends the "
|
|
102
153
|
"context pointer as a second argument. Only meaningful "
|
|
103
154
|
"together with -p.")
|
|
104
|
-
@click.option("--tx-signal-store",
|
|
155
|
+
@click.option("--tx-signal-store/--no-tx-signal-store", default=False,
|
|
105
156
|
help="Generate a permanent per-message TX signal store in the "
|
|
106
157
|
"periodic-TX struct (the default before v2.0). Without it, "
|
|
107
158
|
"periodic TX is callback-only: each scheduled message's "
|
|
108
159
|
"callback returns the struct to encode, and a NULL return or "
|
|
109
160
|
"missing callback sends nothing. Only meaningful with -p.")
|
|
110
|
-
@click.option("--time-as-rx-callback-arg",
|
|
161
|
+
@click.option("--time-as-rx-callback-arg/--no-time-as-rx-callback-arg", default=False,
|
|
111
162
|
help="Pass the current time (the now argument of "
|
|
112
163
|
"<api>_process_received_frame) to the RX callback as a "
|
|
113
164
|
"uint64_t, after the message pointer and before the context "
|
|
114
165
|
"pointer. Only meaningful together with -r.")
|
|
115
|
-
@click.option("--time-as-tx-callback-arg",
|
|
166
|
+
@click.option("--time-as-tx-callback-arg/--no-time-as-tx-callback-arg", default=False,
|
|
116
167
|
help="Pass the current time (the now argument of "
|
|
117
168
|
"<api>_periodic_tx) to the TX callback as a uint64_t, after "
|
|
118
169
|
"the message pointer and before the context pointer. Only "
|
|
119
170
|
"meaningful together with -p.")
|
|
120
|
-
@click.option("--tx-function",
|
|
171
|
+
@click.option("--tx-function/--no-tx-function", default=False,
|
|
121
172
|
help="Bind a frame sink to the periodic-TX API instead of "
|
|
122
173
|
"returning one frame per call. <api>_periodic_tx_init takes "
|
|
123
174
|
"a uint16_t (*tx_function)(void *, const <frame> *) and its "
|
|
@@ -125,18 +176,30 @@ def main():
|
|
|
125
176
|
"due message to it in a single pass and returns the number "
|
|
126
177
|
"accepted. A 0 return leaves last_tx and send_now untouched, "
|
|
127
178
|
"so the message is retried. Only meaningful with -p.")
|
|
128
|
-
@click.option("--
|
|
179
|
+
@click.option("--tx-timing", type=click.Choice(["absolute", "delta"]),
|
|
180
|
+
default="absolute", show_default=True,
|
|
181
|
+
help="Timing argument of the periodic tx function. 'absolute' takes "
|
|
182
|
+
"the current time and sends a message when it hits its "
|
|
183
|
+
"period/offset slot. 'delta' takes the ticks elapsed since the "
|
|
184
|
+
"previous call and counts each message down; without "
|
|
185
|
+
"--tx-function the messages that are due are sent one per call "
|
|
186
|
+
"and drained by further calls with dt=0. Only meaningful with -p.")
|
|
187
|
+
@click.option("--prefix-signal-struct-names/--no-prefix-signal-struct-names", default=False,
|
|
129
188
|
help="Prefix every per-message signal struct type name with the "
|
|
130
189
|
"CamelCase API prefix (the same prefix used for "
|
|
131
190
|
"<Prefix>RxSignals / <Prefix>TxSignals), so two similar APIs "
|
|
132
191
|
"(e.g. two versions of a database) can coexist in one "
|
|
133
192
|
"translation unit with distinct struct names.")
|
|
134
|
-
@click.option("--prefix-context-struct-names",
|
|
193
|
+
@click.option("--prefix-context-struct-names/--no-prefix-context-struct-names", default=False,
|
|
135
194
|
help="Prefix the MsgRxContext / MsgTxContext struct type names (and "
|
|
136
195
|
"their include-guard tokens) with the CamelCase API prefix, so "
|
|
137
196
|
"context structs from two coexisting APIs do not share one "
|
|
138
197
|
"definition.")
|
|
139
|
-
@click.option("
|
|
198
|
+
@click.option("--seed", type=int, default=None,
|
|
199
|
+
help="Seed for the random number generator that picks each "
|
|
200
|
+
"message's offset_seed, so repeated runs produce identical "
|
|
201
|
+
"output. Unseeded by default.")
|
|
202
|
+
@click.option("-v", "--verbose/--no-verbose", default=False,
|
|
140
203
|
help="Print the Data that is passed to the template that "
|
|
141
204
|
"generates the code")
|
|
142
205
|
def api(db_file, library_name, node_name, force, encode_all_signals_func,
|
|
@@ -145,12 +208,18 @@ def api(db_file, library_name, node_name, force, encode_all_signals_func,
|
|
|
145
208
|
rx_callback_context, tx_callback_context, msg_as_rx_callback_arg,
|
|
146
209
|
rx_signal_store, with_rx_valid, msg_as_tx_callback_arg,
|
|
147
210
|
tx_signal_store, time_as_rx_callback_arg, time_as_tx_callback_arg,
|
|
148
|
-
tx_function, prefix_signal_struct_names,
|
|
149
|
-
prefix_context_struct_names, verbose):
|
|
211
|
+
tx_function, tx_timing, prefix_signal_struct_names,
|
|
212
|
+
prefix_context_struct_names, seed, verbose):
|
|
150
213
|
"""
|
|
151
214
|
Generate the static C API for NODE_NAME from DB_FILE (.kcd or .yaml)
|
|
152
215
|
"""
|
|
216
|
+
if seed is not None:
|
|
217
|
+
random.seed(seed)
|
|
153
218
|
db_path = Path(db_file)
|
|
219
|
+
if tx_timing == "delta" and time_as_tx_callback_arg:
|
|
220
|
+
raise click.UsageError(
|
|
221
|
+
"--time-as-tx-callback-arg needs the absolute time and cannot be "
|
|
222
|
+
"combined with --tx-timing delta")
|
|
154
223
|
try:
|
|
155
224
|
basepath = Path(library_name)
|
|
156
225
|
source_path = basepath.parent / f"{basepath.stem}.c"
|
|
@@ -217,6 +286,7 @@ def api(db_file, library_name, node_name, force, encode_all_signals_func,
|
|
|
217
286
|
tx_function=tx_function,
|
|
218
287
|
time_as_rx_callback_arg=time_as_rx_callback_arg,
|
|
219
288
|
time_as_tx_callback_arg=time_as_tx_callback_arg,
|
|
289
|
+
tx_timing=tx_timing,
|
|
220
290
|
)
|
|
221
291
|
if not user_supplied_canframe:
|
|
222
292
|
with (header_path.parent / 'canframe.h').open('w+') as canframe_header_file:
|
|
@@ -228,10 +298,11 @@ def api(db_file, library_name, node_name, force, encode_all_signals_func,
|
|
|
228
298
|
|
|
229
299
|
|
|
230
300
|
@main.command()
|
|
301
|
+
@config_option
|
|
231
302
|
@click.argument("DB_File", type=click.Path(exists=True, dir_okay=False),
|
|
232
303
|
required=True, nargs=1)
|
|
233
304
|
@click.argument("Output_Base", type=str, required=True)
|
|
234
|
-
@click.option("-f", "--force",
|
|
305
|
+
@click.option("-f", "--force/--no-force", required=False, default=False,
|
|
235
306
|
help="Overwrite existing output files")
|
|
236
307
|
def cbdb(db_file, output_base, force):
|
|
237
308
|
"""
|
|
@@ -267,8 +338,9 @@ def cbdb(db_file, output_base, force):
|
|
|
267
338
|
|
|
268
339
|
|
|
269
340
|
@main.command()
|
|
341
|
+
@config_option
|
|
270
342
|
@click.argument("Library_Name", type=str, required=True)
|
|
271
|
-
@click.option("-f", "--force",
|
|
343
|
+
@click.option("-f", "--force/--no-force", required=False, default=False,
|
|
272
344
|
help="Overwrite existing output files")
|
|
273
345
|
@click.option("-im", "--id-member-name", type=str, default="arbitration_id",
|
|
274
346
|
help="The name of the CanFrame struct member that holds the "
|
|
@@ -47,17 +47,22 @@
|
|
|
47
47
|
{%- endif %}
|
|
48
48
|
{% endif %}
|
|
49
49
|
{%- if periodic_tx %}
|
|
50
|
-
{{ define_tx_context_struct(true, 'uint16_t', 'uint64_t', send_now, tx_callback_context=tx_callback_context, msg_as_tx_callback_arg=msg_as_tx_callback_arg, ctx_name=tx_context_struct_name, time_as_tx_callback_arg=time_as_tx_callback_arg) }}
|
|
50
|
+
{{ define_tx_context_struct(true, 'uint16_t', 'uint64_t', send_now, tx_callback_context=tx_callback_context, msg_as_tx_callback_arg=msg_as_tx_callback_arg, ctx_name=tx_context_struct_name, time_as_tx_callback_arg=time_as_tx_callback_arg, tx_timing=tx_timing) }}
|
|
51
51
|
|
|
52
52
|
{{ generate_global_tx_struct(messages, api_name_struct_prefix, double_buffered, tx_signal_store=tx_signal_store, ctx_name=tx_context_struct_name, can_frame_type=can_frame_type, tx_function=tx_function) }}
|
|
53
53
|
|
|
54
|
-
{{ declare_periodic_tx_init_function(api_name, api_name_struct_prefix, 'uint64_t', can_frame_type, tx_function) }};
|
|
54
|
+
{{ declare_periodic_tx_init_function(api_name, api_name_struct_prefix, 'uint64_t', can_frame_type, tx_function, tx_timing) }};
|
|
55
55
|
|
|
56
56
|
{{ declare_get_msg_tx_context_by_id(messages, api_name, api_name_struct_prefix, 'struct ' ~ tx_context_struct_name) }};
|
|
57
57
|
|
|
58
|
-
{{ declare_period_update_function(api_name, 'struct ' ~ tx_context_struct_name) }}
|
|
58
|
+
{{ declare_period_update_function(api_name, 'struct ' ~ tx_context_struct_name, tx_timing) }}
|
|
59
|
+
{%- if tx_timing == 'delta' %}
|
|
60
|
+
|
|
61
|
+
{{ declare_periodic_tx_function(api_name, api_name_struct_prefix, can_frame_type, 'uint16_t', 'uint32_t', 'uint16_t', tx_function, 'dt') }};
|
|
62
|
+
{%- else %}
|
|
59
63
|
|
|
60
64
|
{{ declare_periodic_tx_function(api_name, api_name_struct_prefix, can_frame_type, 'uint16_t', 'uint64_t', 'uint16_t', tx_function) }};
|
|
65
|
+
{%- endif %}
|
|
61
66
|
{%- if double_buffered and tx_signal_store %}
|
|
62
67
|
{%- for message in messages %}
|
|
63
68
|
{%- if message.direction == 'tx' or message.direction == 'rt' %}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
{% from "rx_macros.jinja" import generate_global_rx_frame_process_function -%}
|
|
8
8
|
{% from "rx_macros.jinja" import define_global_rx_init_function -%}
|
|
9
9
|
{% from "tx_macros.jinja" import define_periodic_tx_function -%}
|
|
10
|
+
{% from "tx_macros.jinja" import define_periodic_tx_delta_function -%}
|
|
10
11
|
{% from "tx_macros.jinja" import define_periodic_tx_init_function -%}
|
|
11
12
|
{% from "tx_macros.jinja" import define_get_msg_tx_context_by_id -%}
|
|
12
13
|
{% from "tx_macros.jinja" import define_commit_function -%}
|
|
@@ -21,12 +22,17 @@
|
|
|
21
22
|
{%- endif %}
|
|
22
23
|
{%- endif %}
|
|
23
24
|
{%- if periodic_tx %}
|
|
25
|
+
{%- if tx_timing == 'delta' %}
|
|
26
|
+
|
|
27
|
+
{{ define_periodic_tx_delta_function(messages, api_name, api_name_struct_prefix, can_frame_type, 'uint16_t', 'uint16_t', true, send_now, double_buffered, tx_callback_context=tx_callback_context, msg_as_tx_callback_arg=msg_as_tx_callback_arg, tx_signal_store=tx_signal_store, tx_function=tx_function) }}
|
|
28
|
+
{%- else %}
|
|
24
29
|
|
|
25
30
|
{{ define_periodic_tx_function(messages, api_name, api_name_struct_prefix, can_frame_type, 'uint16_t', 'uint64_t', 'uint16_t', true, send_now, double_buffered, tx_callback_context=tx_callback_context, msg_as_tx_callback_arg=msg_as_tx_callback_arg, tx_signal_store=tx_signal_store, ctx_name=tx_context_struct_name, tx_function=tx_function, time_as_tx_callback_arg=time_as_tx_callback_arg) }}
|
|
31
|
+
{%- endif %}
|
|
26
32
|
|
|
27
33
|
{{ define_get_msg_tx_context_by_id(messages, api_name, api_name_struct_prefix, 'struct ' ~ tx_context_struct_name) }}
|
|
28
34
|
|
|
29
|
-
{{ define_periodic_tx_init_function(api_name, api_name_struct_prefix, 'uint64_t', messages, '1000', double_buffered, tx_signal_store=tx_signal_store, can_frame_type=can_frame_type, tx_function=tx_function) }}
|
|
35
|
+
{{ define_periodic_tx_init_function(api_name, api_name_struct_prefix, 'uint64_t', messages, '1000', double_buffered, tx_signal_store=tx_signal_store, can_frame_type=can_frame_type, tx_function=tx_function, tx_timing=tx_timing) }}
|
|
30
36
|
{%- if double_buffered and tx_signal_store %}
|
|
31
37
|
{%- for message in messages %}
|
|
32
38
|
{%- if message.direction == 'tx' or message.direction == 'rt' %}
|