can-api-generator 2.5.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.5.0 → can_api_generator-2.6.0}/PKG-INFO +38 -5
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/README.md +37 -4
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/__about__.py +1 -1
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/code_generator.py +3 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/main.py +34 -10
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/header_template.jinja +8 -3
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/source_template.jinja +7 -1
- {can_api_generator-2.5.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.5.0/Advantics_Bootloader.kcd +0 -384
- can_api_generator-2.5.0/manual_api_test.c +0 -93
- can_api_generator-2.5.0/manual_api_test.h +0 -60
- can_api_generator-2.5.0/manual_api_test.o +0 -0
- can_api_generator-2.5.0/test_1_rx_over_can +0 -0
- can_api_generator-2.5.0/test_api.c +0 -78
- can_api_generator-2.5.0/test_api.h +0 -68
- can_api_generator-2.5.0/test_kcd_api_test_mux_with_same_signal_names_labeled_mux_variants.c +0 -686
- can_api_generator-2.5.0/test_mux_with_same_signal_names_labeled_mux_variants.c +0 -237
- can_api_generator-2.5.0/test_mux_with_same_signal_names_labeled_mux_variants.h +0 -265
- can_api_generator-2.5.0/test_test_1_rx_over_can.c +0 -65
- can_api_generator-2.5.0/test_test_basic_multiplex_rx_over_can.c +0 -67
- can_api_generator-2.5.0/test_test_mux_with_partially_labled_index_rx_over_can.c +0 -67
- can_api_generator-2.5.0/test_test_mux_with_same_signal_names_labeled_mux_variants_rx_over_can.c +0 -67
- can_api_generator-2.5.0/tests/test_config_file.py +0 -68
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/.gitignore +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/LICENSE.txt +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/manual_cag_test.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/pyproject.toml +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/__init__.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/cbdb_generator.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/msg_processor.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/callback_macros.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/canframe.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/declaration_macros.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/dyndec_header.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/dyndec_source.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/encoding_macros.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/rx_macros.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/types.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/utils.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/__init__.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/cantool_test_utils.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/compat_shim.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/dyndec_test_harness.c +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/multiple_busses_test.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_1.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_basic_multiplex.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_big_endian.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_can_db_model_dep.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_cbdb_generator.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_cli.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_cross_interface_compat.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_cross_interface_compat.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_dyndec_round_trip.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_float_wrong_length.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_message_parser.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_missing_consumer.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_missing_producer.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_mux_group_count_out_of_order.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_mux_with_labeled_index.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_mux_with_partially_labled_index.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_mux_with_same_signal_names.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_mux_with_same_signal_names_labeled_mux_variants.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_mux_with_scale_and_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_non_encodable_0.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_overlapping_signals.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_periodic_tx_over_can.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_procedures.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_prog_source_template.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_rx_over_can.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_direction.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/double_plain.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/double_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/double_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/float_plain.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/float_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/float_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_fractional_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_plain.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_matching_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_plain.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/sint_nonmatching_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/test_decoding_numerical_value.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/test_encoding_numerical_value.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/test_signal_encoding_wrong_float_size.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_plain.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_matching_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_fractional_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_plain.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_scaled.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_encoding/uint_nonmatching_scaled_offset.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_signal_info.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_time_callback_arg.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_too_large_message.kcd +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_tx_function.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_tx_over_can.jinja +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_utils.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_vcan_round_trip.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_yaml_cbdb.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_yaml_input.py +0 -0
- {can_api_generator-2.5.0 → can_api_generator-2.6.0}/tests/test_yaml_kcd_equivalence.py +0 -0
- {can_api_generator-2.5.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
|
|
@@ -244,6 +244,31 @@ slot (`now % period == offset`); the missed slot is skipped, not caught up.
|
|
|
244
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
|
|
245
245
|
`--tx-signal-store`.
|
|
246
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
|
+
|
|
247
272
|
### Encode All Signals
|
|
248
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
|
|
249
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
|
|
@@ -666,6 +691,8 @@ Options:
|
|
|
666
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
|
|
667
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
|
|
668
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`.
|
|
669
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
|
|
670
697
|
generated and decoded signals reach the application only through the RX callback. See [Global RX](#global-rx). Only meaningful together with `-r`.
|
|
671
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
|
|
@@ -682,6 +709,8 @@ Options:
|
|
|
682
709
|
to an existing project's frame struct naming.
|
|
683
710
|
* `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
|
|
684
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.
|
|
685
714
|
* `-v`, `--verbose` — dump the processed message dicts that get fed into the Jinja templates. Useful when debugging template or generator changes.
|
|
686
715
|
* `--help` — show the CLI help and exit.
|
|
687
716
|
|
|
@@ -722,11 +751,15 @@ Options:
|
|
|
722
751
|
### Config file
|
|
723
752
|
|
|
724
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
|
|
725
|
-
one file can serve `api`, `cbdb` and `dyndec`; a command reads only its own section. Keys are the long option names without the leading `--`
|
|
726
|
-
underscores both work), and values are the option values (`true`/`false` for flags)
|
|
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.
|
|
727
757
|
|
|
728
758
|
```yaml
|
|
729
759
|
api:
|
|
760
|
+
db-file: db.kcd
|
|
761
|
+
library-name: my_api
|
|
762
|
+
node-name: DUT
|
|
730
763
|
periodic-tx: true
|
|
731
764
|
tx-signal-store: true
|
|
732
765
|
time-as-tx-callback-arg: true
|
|
@@ -736,5 +769,5 @@ dyndec:
|
|
|
736
769
|
```
|
|
737
770
|
|
|
738
771
|
Anything given on the command line overrides the file. Every flag has a `--no-` form for this, e.g.
|
|
739
|
-
`can-api-gen api --config can.yaml --no-tx-signal-store
|
|
740
|
-
|
|
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.
|
|
@@ -218,6 +218,31 @@ slot (`now % period == offset`); the missed slot is skipped, not caught up.
|
|
|
218
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
|
|
219
219
|
`--tx-signal-store`.
|
|
220
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
|
+
|
|
221
246
|
### Encode All Signals
|
|
222
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
|
|
223
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
|
|
@@ -640,6 +665,8 @@ Options:
|
|
|
640
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
|
|
641
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
|
|
642
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`.
|
|
643
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
|
|
644
671
|
generated and decoded signals reach the application only through the RX callback. See [Global RX](#global-rx). Only meaningful together with `-r`.
|
|
645
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
|
|
@@ -656,6 +683,8 @@ Options:
|
|
|
656
683
|
to an existing project's frame struct naming.
|
|
657
684
|
* `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
|
|
658
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.
|
|
659
688
|
* `-v`, `--verbose` — dump the processed message dicts that get fed into the Jinja templates. Useful when debugging template or generator changes.
|
|
660
689
|
* `--help` — show the CLI help and exit.
|
|
661
690
|
|
|
@@ -696,11 +725,15 @@ Options:
|
|
|
696
725
|
### Config file
|
|
697
726
|
|
|
698
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
|
|
699
|
-
one file can serve `api`, `cbdb` and `dyndec`; a command reads only its own section. Keys are the long option names without the leading `--`
|
|
700
|
-
underscores both work), and values are the option values (`true`/`false` for flags)
|
|
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.
|
|
701
731
|
|
|
702
732
|
```yaml
|
|
703
733
|
api:
|
|
734
|
+
db-file: db.kcd
|
|
735
|
+
library-name: my_api
|
|
736
|
+
node-name: DUT
|
|
704
737
|
periodic-tx: true
|
|
705
738
|
tx-signal-store: true
|
|
706
739
|
time-as-tx-callback-arg: true
|
|
@@ -710,5 +743,5 @@ dyndec:
|
|
|
710
743
|
```
|
|
711
744
|
|
|
712
745
|
Anything given on the command line overrides the file. Every flag has a `--no-` form for this, e.g.
|
|
713
|
-
`can-api-gen api --config can.yaml --no-tx-signal-store
|
|
714
|
-
|
|
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
|
|
@@ -19,9 +20,10 @@ def _load_config(ctx, param, value):
|
|
|
19
20
|
"""Turn the command's section of a YAML config file into click defaults.
|
|
20
21
|
|
|
21
22
|
The file maps command names to option tables, e.g. {"api": {"periodic-tx":
|
|
22
|
-
true}}. Keys are long option names
|
|
23
|
-
become ctx.default_map, so
|
|
24
|
-
takes precedence over the file.
|
|
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.
|
|
25
27
|
"""
|
|
26
28
|
if value is None:
|
|
27
29
|
return
|
|
@@ -39,14 +41,17 @@ def _load_config(ctx, param, value):
|
|
|
39
41
|
if not isinstance(section, dict):
|
|
40
42
|
raise click.BadParameter(
|
|
41
43
|
f"section '{ctx.info_name}' must map option names to values", ctx, param)
|
|
42
|
-
known = {p.name for p in ctx.command.params
|
|
43
|
-
if isinstance(p, click.Option) and p.name != "config"}
|
|
44
|
+
known = {p.name: p for p in ctx.command.params if p.name != "config"}
|
|
44
45
|
defaults = {}
|
|
45
46
|
for key, option_value in section.items():
|
|
46
47
|
name = str(key).replace("-", "_")
|
|
47
48
|
if name not in known:
|
|
48
49
|
raise click.BadParameter(
|
|
49
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)
|
|
50
55
|
defaults[name] = option_value
|
|
51
56
|
ctx.default_map = {**(ctx.default_map or {}), **defaults}
|
|
52
57
|
|
|
@@ -54,9 +59,9 @@ def _load_config(ctx, param, value):
|
|
|
54
59
|
config_option = click.option(
|
|
55
60
|
"--config", type=click.Path(exists=True, dir_okay=False),
|
|
56
61
|
is_eager=True, expose_value=False, callback=_load_config,
|
|
57
|
-
help="YAML file providing defaults for this command's options
|
|
58
|
-
"section named after the command (api, cbdb,
|
|
59
|
-
"on the command line
|
|
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.")
|
|
60
65
|
|
|
61
66
|
|
|
62
67
|
@click.group()
|
|
@@ -171,6 +176,14 @@ def main():
|
|
|
171
176
|
"due message to it in a single pass and returns the number "
|
|
172
177
|
"accepted. A 0 return leaves last_tx and send_now untouched, "
|
|
173
178
|
"so the message is retried. Only meaningful with -p.")
|
|
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.")
|
|
174
187
|
@click.option("--prefix-signal-struct-names/--no-prefix-signal-struct-names", default=False,
|
|
175
188
|
help="Prefix every per-message signal struct type name with the "
|
|
176
189
|
"CamelCase API prefix (the same prefix used for "
|
|
@@ -182,6 +195,10 @@ def main():
|
|
|
182
195
|
"their include-guard tokens) with the CamelCase API prefix, so "
|
|
183
196
|
"context structs from two coexisting APIs do not share one "
|
|
184
197
|
"definition.")
|
|
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.")
|
|
185
202
|
@click.option("-v", "--verbose/--no-verbose", default=False,
|
|
186
203
|
help="Print the Data that is passed to the template that "
|
|
187
204
|
"generates the code")
|
|
@@ -191,12 +208,18 @@ def api(db_file, library_name, node_name, force, encode_all_signals_func,
|
|
|
191
208
|
rx_callback_context, tx_callback_context, msg_as_rx_callback_arg,
|
|
192
209
|
rx_signal_store, with_rx_valid, msg_as_tx_callback_arg,
|
|
193
210
|
tx_signal_store, time_as_rx_callback_arg, time_as_tx_callback_arg,
|
|
194
|
-
tx_function, prefix_signal_struct_names,
|
|
195
|
-
prefix_context_struct_names, verbose):
|
|
211
|
+
tx_function, tx_timing, prefix_signal_struct_names,
|
|
212
|
+
prefix_context_struct_names, seed, verbose):
|
|
196
213
|
"""
|
|
197
214
|
Generate the static C API for NODE_NAME from DB_FILE (.kcd or .yaml)
|
|
198
215
|
"""
|
|
216
|
+
if seed is not None:
|
|
217
|
+
random.seed(seed)
|
|
199
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")
|
|
200
223
|
try:
|
|
201
224
|
basepath = Path(library_name)
|
|
202
225
|
source_path = basepath.parent / f"{basepath.stem}.c"
|
|
@@ -263,6 +286,7 @@ def api(db_file, library_name, node_name, force, encode_all_signals_func,
|
|
|
263
286
|
tx_function=tx_function,
|
|
264
287
|
time_as_rx_callback_arg=time_as_rx_callback_arg,
|
|
265
288
|
time_as_tx_callback_arg=time_as_tx_callback_arg,
|
|
289
|
+
tx_timing=tx_timing,
|
|
266
290
|
)
|
|
267
291
|
if not user_supplied_canframe:
|
|
268
292
|
with (header_path.parent / 'canframe.h').open('w+') as canframe_header_file:
|
|
@@ -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' %}
|
{can_api_generator-2.5.0 → can_api_generator-2.6.0}/src/can_api_generator/templates/tx_macros.jinja
RENAMED
|
@@ -2,13 +2,18 @@
|
|
|
2
2
|
{% from "encoding_macros.jinja" import rotate_multiplex_func_call %}
|
|
3
3
|
{% from "callback_macros.jinja" import callback_param_types, callback_args %}
|
|
4
4
|
|
|
5
|
-
{% macro define_tx_context_struct(tx_callback, flag_type, time_type, send_now, tx_callback_context=false, msg_as_tx_callback_arg=false, ctx_name='MsgTxContext', time_as_tx_callback_arg=false) -%}
|
|
5
|
+
{% macro define_tx_context_struct(tx_callback, flag_type, time_type, send_now, tx_callback_context=false, msg_as_tx_callback_arg=false, ctx_name='MsgTxContext', time_as_tx_callback_arg=false, tx_timing='absolute') -%}
|
|
6
6
|
#ifndef {{ ctx_name | upper }}
|
|
7
7
|
#define {{ ctx_name | upper }}
|
|
8
8
|
struct {{ ctx_name }} {
|
|
9
9
|
uint32_t arb_id;
|
|
10
10
|
{{ flag_type }} enable;
|
|
11
|
+
{%- if tx_timing == 'delta' %}
|
|
12
|
+
{{ flag_type }} pending;
|
|
13
|
+
uint32_t remaining;
|
|
14
|
+
{%- else %}
|
|
11
15
|
{{ time_type }} last_tx;
|
|
16
|
+
{%- endif %}
|
|
12
17
|
uint32_t period;
|
|
13
18
|
uint32_t offset;
|
|
14
19
|
uint32_t offset_seed;
|
|
@@ -25,10 +30,13 @@ struct {{ ctx_name }} {
|
|
|
25
30
|
#endif
|
|
26
31
|
{%- endmacro %}
|
|
27
32
|
|
|
28
|
-
{% macro declare_period_update_function(api_name, context_type) -%}
|
|
33
|
+
{% macro declare_period_update_function(api_name, context_type, tx_timing='absolute') -%}
|
|
29
34
|
static inline void {{ api_name }}_update_tx_period({{ context_type }} *txctx, uint32_t period) {
|
|
30
35
|
txctx->period = period;
|
|
31
36
|
txctx->offset = txctx->offset_seed % period;
|
|
37
|
+
{%- if tx_timing == 'delta' %}
|
|
38
|
+
txctx->remaining = txctx->offset + 1;
|
|
39
|
+
{%- endif %}
|
|
32
40
|
}
|
|
33
41
|
{%- endmacro %}
|
|
34
42
|
|
|
@@ -92,8 +100,8 @@ void {{ api_name }}_{{ message.name }}_commit(struct {{ api_struct_prefix }}TxSi
|
|
|
92
100
|
}
|
|
93
101
|
{%- endmacro %}
|
|
94
102
|
|
|
95
|
-
{% macro declare_periodic_tx_function(api_name, api_struct_prefix, can_frame_type, return_type, time_type, flag_type, tx_function=false) -%}
|
|
96
|
-
{{ return_type }} {{ api_name }}_periodic_tx(struct {{ api_struct_prefix }}TxSignals *tx_signals, {% if not tx_function %}{{ can_frame_type }} *output_frame, {% endif %}{{ time_type }}
|
|
103
|
+
{% macro declare_periodic_tx_function(api_name, api_struct_prefix, can_frame_type, return_type, time_type, flag_type, tx_function=false, time_arg='now') -%}
|
|
104
|
+
{{ return_type }} {{ api_name }}_periodic_tx(struct {{ api_struct_prefix }}TxSignals *tx_signals, {% if not tx_function %}{{ can_frame_type }} *output_frame, {% endif %}{{ time_type }} {{ time_arg }})
|
|
97
105
|
{%- endmacro %}
|
|
98
106
|
|
|
99
107
|
{% macro tx_callback_call(message, msg_arg, tx_callback_context, msg_as_tx_callback_arg, time_as_tx_callback_arg) -%}
|
|
@@ -190,14 +198,122 @@ void {{ api_name }}_{{ message.name }}_commit(struct {{ api_struct_prefix }}TxSi
|
|
|
190
198
|
}
|
|
191
199
|
{%- endmacro %}
|
|
192
200
|
|
|
193
|
-
{
|
|
194
|
-
|
|
201
|
+
{#
|
|
202
|
+
# --tx-timing delta: dt is the number of ticks since the previous call. Each
|
|
203
|
+
# message counts down; when its countdown runs out the message is marked
|
|
204
|
+
# pending (if enabled; a disabled message's slot is skipped, its countdown
|
|
205
|
+
# keeps running) and rescheduled to its next slot on the original grid, so a
|
|
206
|
+
# stall over several periods sends once and keeps the phase.
|
|
207
|
+
# Without a frame sink one pending frame is returned per call, in message
|
|
208
|
+
# order; the rest are drained by calling again with dt = 0. With a sink
|
|
209
|
+
# (--tx-function) every pending message is handed over in one pass, and a
|
|
210
|
+
# frame the sink rejects stays pending for the next call.
|
|
211
|
+
#}
|
|
212
|
+
{% macro define_periodic_tx_delta_function(messages, api_name, api_struct_prefix, can_frame_type, return_type, flag_type, tx_callback, send_now, double_buffered=False, tx_callback_context=false, msg_as_tx_callback_arg=false, tx_signal_store=false, tx_function=false) -%}
|
|
213
|
+
{%- set tx_messages = messages | selectattr('direction', 'in', ['tx', 'rt']) | list %}
|
|
214
|
+
{%- set frame_arg = '&frame' if tx_function else 'output_frame' -%}
|
|
215
|
+
{{ declare_periodic_tx_function(api_name, api_struct_prefix, can_frame_type, return_type, 'uint32_t', flag_type, tx_function, 'dt') }} {
|
|
216
|
+
{%- if tx_function %}
|
|
217
|
+
{{ can_frame_type }} frame;
|
|
218
|
+
{{ return_type }} queued = 0;
|
|
219
|
+
{%- endif %}
|
|
220
|
+
{%- for message in tx_messages %}
|
|
221
|
+
{%- set ctx = 'tx_signals->' ~ message.name ~ '_context' %}
|
|
222
|
+
if (dt >= {{ ctx }}.remaining) {
|
|
223
|
+
{{ ctx }}.pending = {{ ctx }}.enable;
|
|
224
|
+
{{ ctx }}.remaining = {{ ctx }}.period - (dt - {{ ctx }}.remaining) % {{ ctx }}.period;
|
|
225
|
+
} else {
|
|
226
|
+
{{ ctx }}.remaining -= dt;
|
|
227
|
+
}
|
|
228
|
+
{%- endfor %}
|
|
229
|
+
{%- for message in tx_messages %}
|
|
230
|
+
{%- set ctx = 'tx_signals->' ~ message.name ~ '_context' %}
|
|
231
|
+
|
|
232
|
+
if ({% if send_now %}{{ ctx }}.send_now || {% endif %}({{ ctx }}.pending && {{ ctx }}.enable)) {
|
|
233
|
+
{%- if not tx_signal_store %}
|
|
234
|
+
{%- if msg_as_tx_callback_arg %}
|
|
235
|
+
struct {{ message.struct_name }} {{ message.name }}_tx_storage;
|
|
236
|
+
{%- endif %}
|
|
237
|
+
void *{{ message.name }}_tx_data = 0;
|
|
238
|
+
{%- endif %}
|
|
239
|
+
{%- if not tx_function %}
|
|
240
|
+
{%- if send_now %}
|
|
241
|
+
{{ ctx }}.send_now = 0;
|
|
242
|
+
{%- endif %}
|
|
243
|
+
{{ ctx }}.pending = 0;
|
|
244
|
+
{%- endif %}
|
|
245
|
+
{%- if tx_signal_store %}
|
|
246
|
+
{%- set msg_arg = ('tx_signals->' ~ message.name ~ '_signals_committed') if double_buffered else ('&tx_signals->' ~ message.name ~ '_signals') %}
|
|
247
|
+
{%- if tx_callback %}
|
|
248
|
+
if ({{ ctx }}.tx_callback) {
|
|
249
|
+
(void){{ tx_callback_call(message, msg_arg, tx_callback_context, msg_as_tx_callback_arg, false) }};
|
|
250
|
+
}
|
|
251
|
+
{%- endif %}
|
|
252
|
+
{{ message_encoding_function_call(message, msg_arg, frame_arg) }};
|
|
253
|
+
{%- if tx_function %}
|
|
254
|
+
if ((*tx_signals->tx_function)(tx_signals->tx_function_context, &frame)) {
|
|
255
|
+
{%- if send_now %}
|
|
256
|
+
{{ ctx }}.send_now = 0;
|
|
257
|
+
{%- endif %}
|
|
258
|
+
{{ ctx }}.pending = 0;
|
|
259
|
+
{%- endif %}
|
|
260
|
+
{%- for signal in message.all_signals %}
|
|
261
|
+
{%- if signal.multiplex %}
|
|
262
|
+
{%- if double_buffered %}
|
|
263
|
+
{% if tx_function %} {% endif %}{{ rotate_multiplex_func_call(message, signal, '&tx_signals->' ~ message.name ~ '_signals_committed->' ~ signal.name) }};
|
|
264
|
+
{%- else %}
|
|
265
|
+
{% if tx_function %} {% endif %}{{ rotate_multiplex_func_call(message, signal, '&tx_signals->' ~ message.name ~ '_signals.' ~ signal.name) }};
|
|
266
|
+
{%- endif %}
|
|
267
|
+
{%- endif %}
|
|
268
|
+
{%- endfor %}
|
|
269
|
+
{%- if tx_function %}
|
|
270
|
+
queued++;
|
|
271
|
+
}
|
|
272
|
+
{%- else %}
|
|
273
|
+
return 1;
|
|
274
|
+
{%- endif %}
|
|
275
|
+
{%- else %}
|
|
276
|
+
if ({{ ctx }}.tx_callback) {
|
|
277
|
+
{{ message.name }}_tx_data = {{ tx_callback_call(message, '&' ~ message.name ~ '_tx_storage', tx_callback_context, msg_as_tx_callback_arg, false) }};
|
|
278
|
+
}
|
|
279
|
+
if ({{ message.name }}_tx_data) {
|
|
280
|
+
{%- if tx_function %}
|
|
281
|
+
{{ message_encoding_function_call(message, '(struct ' ~ message.struct_name ~ ' *)' ~ message.name ~ '_tx_data', frame_arg) }};
|
|
282
|
+
if ((*tx_signals->tx_function)(tx_signals->tx_function_context, &frame)) {
|
|
283
|
+
{%- if send_now %}
|
|
284
|
+
{{ ctx }}.send_now = 0;
|
|
285
|
+
{%- endif %}
|
|
286
|
+
{{ ctx }}.pending = 0;
|
|
287
|
+
queued++;
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
// nothing to send for this slot; a send_now request stays set
|
|
291
|
+
{{ ctx }}.pending = 0;
|
|
292
|
+
}
|
|
293
|
+
{%- else %}
|
|
294
|
+
{{ message_encoding_function_call(message, '(struct ' ~ message.struct_name ~ ' *)' ~ message.name ~ '_tx_data', frame_arg) }};
|
|
295
|
+
return 1;
|
|
296
|
+
}
|
|
297
|
+
{%- endif %}
|
|
298
|
+
{%- endif %}
|
|
299
|
+
}
|
|
300
|
+
{%- endfor %}
|
|
301
|
+
{%- if tx_function %}
|
|
302
|
+
return queued;
|
|
303
|
+
{%- else %}
|
|
304
|
+
return 0;
|
|
305
|
+
{%- endif %}
|
|
306
|
+
}
|
|
307
|
+
{%- endmacro %}
|
|
308
|
+
|
|
309
|
+
{% macro declare_periodic_tx_init_function(api_name, api_struct_prefix, time_type, can_frame_type='CanFrame', tx_function=false, tx_timing='absolute') -%}
|
|
310
|
+
void {{ api_name }}_periodic_tx_init(struct {{ api_struct_prefix }}TxSignals *tx_signals{% if tx_timing != 'delta' %}, {{ time_type }} now{% endif %}
|
|
195
311
|
{%- if tx_function %}, uint16_t (*tx_function)(void *, const {{ can_frame_type }} *), void *tx_function_context{% endif %})
|
|
196
312
|
{%- endmacro %}
|
|
197
313
|
|
|
198
|
-
{% macro define_periodic_tx_init_function(api_name, api_struct_prefix, time_type, messages, default_period, double_buffered=False, tx_signal_store=False, can_frame_type='CanFrame', tx_function=false) -%}
|
|
314
|
+
{% macro define_periodic_tx_init_function(api_name, api_struct_prefix, time_type, messages, default_period, double_buffered=False, tx_signal_store=False, can_frame_type='CanFrame', tx_function=false, tx_timing='absolute') -%}
|
|
199
315
|
{% set tx_messages = messages | selectattr('direction', 'in', '["tx", "rt"]') -%}
|
|
200
|
-
{{ declare_periodic_tx_init_function(api_name, api_struct_prefix, time_type, can_frame_type, tx_function) }} {
|
|
316
|
+
{{ declare_periodic_tx_init_function(api_name, api_struct_prefix, time_type, can_frame_type, tx_function, tx_timing) }} {
|
|
201
317
|
memset(tx_signals, 0, sizeof(*tx_signals));
|
|
202
318
|
{%- if tx_function %}
|
|
203
319
|
tx_signals->tx_function = tx_function;
|
|
@@ -205,7 +321,9 @@ void {{ api_name }}_periodic_tx_init(struct {{ api_struct_prefix }}TxSignals *tx
|
|
|
205
321
|
{%- endif %}
|
|
206
322
|
{%- for msg in tx_messages %}
|
|
207
323
|
tx_signals->{{ msg.name }}_context.arb_id = {{ msg.arb_id }};
|
|
324
|
+
{%- if tx_timing != 'delta' %}
|
|
208
325
|
tx_signals->{{ msg.name }}_context.last_tx = now;
|
|
326
|
+
{%- endif %}
|
|
209
327
|
tx_signals->{{ msg.name }}_context.offset_seed = {{ msg.offset_seed }}ull;
|
|
210
328
|
{%- if double_buffered and tx_signal_store %}
|
|
211
329
|
tx_signals->{{ msg.name }}_signals = &tx_signals->{{ msg.name }}_signals_storage[0];
|