can-api-generator 2.3.0__tar.gz → 2.4.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.
Files changed (106) hide show
  1. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/PKG-INFO +17 -1
  2. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/README.md +16 -0
  3. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/__about__.py +1 -1
  4. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/rx_macros.jinja +1 -1
  5. can_api_generator-2.4.0/tests/test_time_callback_arg.py +107 -0
  6. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/.gitignore +0 -0
  7. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/Advantics_Bootloader.kcd +0 -0
  8. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/LICENSE.txt +0 -0
  9. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/manual_api_test.c +0 -0
  10. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/manual_api_test.h +0 -0
  11. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/manual_api_test.o +0 -0
  12. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/manual_cag_test.py +0 -0
  13. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/pyproject.toml +0 -0
  14. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/__init__.py +0 -0
  15. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/cbdb_generator.py +0 -0
  16. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/code_generator.py +0 -0
  17. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/main.py +0 -0
  18. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/msg_processor.py +0 -0
  19. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/callback_macros.jinja +0 -0
  20. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/canframe.jinja +0 -0
  21. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/declaration_macros.jinja +0 -0
  22. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/dyndec_header.jinja +0 -0
  23. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/dyndec_source.jinja +0 -0
  24. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/encoding_macros.jinja +0 -0
  25. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/header_template.jinja +0 -0
  26. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/source_template.jinja +0 -0
  27. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/templates/tx_macros.jinja +0 -0
  28. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/types.py +0 -0
  29. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/src/can_api_generator/utils.py +0 -0
  30. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_1_rx_over_can +0 -0
  31. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_api.c +0 -0
  32. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_api.h +0 -0
  33. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_kcd_api_test_mux_with_same_signal_names_labeled_mux_variants.c +0 -0
  34. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_mux_with_same_signal_names_labeled_mux_variants.c +0 -0
  35. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_mux_with_same_signal_names_labeled_mux_variants.h +0 -0
  36. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_test_1_rx_over_can.c +0 -0
  37. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_test_basic_multiplex_rx_over_can.c +0 -0
  38. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_test_mux_with_partially_labled_index_rx_over_can.c +0 -0
  39. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/test_test_mux_with_same_signal_names_labeled_mux_variants_rx_over_can.c +0 -0
  40. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/__init__.py +0 -0
  41. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/cantool_test_utils.jinja +0 -0
  42. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/compat_shim.jinja +0 -0
  43. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/dyndec_test_harness.c +0 -0
  44. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/multiple_busses_test.kcd +0 -0
  45. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_1.kcd +0 -0
  46. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_basic_multiplex.kcd +0 -0
  47. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_big_endian.kcd +0 -0
  48. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_can_db_model_dep.py +0 -0
  49. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_cbdb_generator.py +0 -0
  50. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_cli.py +0 -0
  51. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_cross_interface_compat.jinja +0 -0
  52. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_cross_interface_compat.py +0 -0
  53. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_dyndec_round_trip.py +0 -0
  54. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_float_wrong_length.kcd +0 -0
  55. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_message_parser.py +0 -0
  56. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_missing_consumer.kcd +0 -0
  57. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_missing_producer.kcd +0 -0
  58. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_mux_group_count_out_of_order.kcd +0 -0
  59. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_mux_with_labeled_index.kcd +0 -0
  60. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_mux_with_partially_labled_index.kcd +0 -0
  61. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_mux_with_same_signal_names.kcd +0 -0
  62. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_mux_with_same_signal_names_labeled_mux_variants.kcd +0 -0
  63. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_mux_with_scale_and_offset.kcd +0 -0
  64. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_non_encodable_0.kcd +0 -0
  65. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_overlapping_signals.kcd +0 -0
  66. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_periodic_tx_over_can.jinja +0 -0
  67. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_procedures.jinja +0 -0
  68. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_prog_source_template.jinja +0 -0
  69. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_rx_over_can.jinja +0 -0
  70. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_direction.kcd +0 -0
  71. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/double_plain.kcd +0 -0
  72. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/double_scaled.kcd +0 -0
  73. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/double_scaled_offset.kcd +0 -0
  74. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/float_plain.kcd +0 -0
  75. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/float_scaled.kcd +0 -0
  76. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/float_scaled_offset.kcd +0 -0
  77. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_matching_fractional_scaled.kcd +0 -0
  78. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_matching_fractional_scaled_offset.kcd +0 -0
  79. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_matching_plain.kcd +0 -0
  80. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_matching_scaled.kcd +0 -0
  81. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_matching_scaled_offset.kcd +0 -0
  82. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_nonmatching_fractional_scaled.kcd +0 -0
  83. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_nonmatching_plain.kcd +0 -0
  84. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_nonmatching_scaled.kcd +0 -0
  85. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/sint_nonmatching_scaled_offset.kcd +0 -0
  86. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/test_decoding_numerical_value.jinja +0 -0
  87. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/test_encoding_numerical_value.jinja +0 -0
  88. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/test_signal_encoding_wrong_float_size.kcd +0 -0
  89. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_matching_fractional_scaled.kcd +0 -0
  90. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_matching_plain.kcd +0 -0
  91. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_matching_scaled.kcd +0 -0
  92. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_matching_scaled_offset.kcd +0 -0
  93. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_nonmatching_fractional_scaled.kcd +0 -0
  94. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_nonmatching_plain.kcd +0 -0
  95. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_nonmatching_scaled.kcd +0 -0
  96. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_encoding/uint_nonmatching_scaled_offset.kcd +0 -0
  97. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_signal_info.kcd +0 -0
  98. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_too_large_message.kcd +0 -0
  99. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_tx_function.py +0 -0
  100. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_tx_over_can.jinja +0 -0
  101. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_utils.py +0 -0
  102. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_vcan_round_trip.py +0 -0
  103. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_yaml_cbdb.py +0 -0
  104. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_yaml_input.py +0 -0
  105. {can_api_generator-2.3.0 → can_api_generator-2.4.0}/tests/test_yaml_kcd_equivalence.py +0 -0
  106. {can_api_generator-2.3.0 → can_api_generator-2.4.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.0
3
+ Version: 2.4.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
@@ -45,6 +45,7 @@ Description-Content-Type: text/markdown
45
45
  - [Double-buffered signal access](#double-buffered-signal-access)
46
46
  - [RX/TX callback context](#rxtx-callback-context)
47
47
  - [Message signals as RX callback argument](#message-signals-as-rx-callback-argument)
48
+ - [Current time as callback argument](#current-time-as-callback-argument)
48
49
  - [Using your own frame type](#using-your-own-frame-type)
49
50
  - [Example Use](#example-use)
50
51
  - [Dynamic decoding](#dynamic-decoding)
@@ -353,6 +354,17 @@ Passing `--msg-as-rx-callback-arg` instead hands the callback a `void *` pointin
353
354
 
354
355
  `struct MsgRxContext` remains a single shared type, which is why the signal struct is passed as `void *` rather than a typed pointer.
355
356
 
357
+ ### Current time as callback argument
358
+
359
+ The `now` handed to `<api>_process_received_frame` and `<api>_periodic_tx` can be forwarded to the callbacks, so a callback that timestamps, filters or rate-limits
360
+ does not have to read the clock again (and sees exactly the time the API used for `last_rx` / `last_tx`). The two paths have separate flags:
361
+
362
+ * `--time-as-rx-callback-arg` adds a `uint64_t now` parameter to the RX callback.
363
+ * `--time-as-tx-callback-arg` adds a `uint64_t now` parameter to the TX callback.
364
+
365
+ Arguments are always in the order message pointer, time, context pointer, each present only when its flag is set. With every RX flag the callback is
366
+ `void (*rx_callback)(void *msg, uint64_t now, void *ctx)`; with only `--time-as-tx-callback-arg` it is `void *(*tx_callback)(uint64_t now)`.
367
+
356
368
  ### Using your own frame type
357
369
 
358
370
  By default every generated function takes a `CanFrame *`, and the generator writes a sibling `canframe.h` that defines `CanFrame`. If the application already has a
@@ -643,6 +655,10 @@ Options:
643
655
  `--tx-signal-store` the pointer is the message's store struct, which the callback edits in place before encode; in callback-only mode `<api>_periodic_tx` stack-allocates
644
656
  the struct, and the callback fills it and returns it (or `NULL` to skip), so no application-provided storage is needed. See [Periodic TX](#periodic-tx). Only meaningful
645
657
  together with `-p`.
658
+ * `--time-as-rx-callback-arg` — pass the `now` of `<api>_process_received_frame` to the RX callback as a `uint64_t`, after the message pointer and before the
659
+ context pointer. See [Current time as callback argument](#current-time-as-callback-argument). Only meaningful together with `-r`.
660
+ * `--time-as-tx-callback-arg` — pass the `now` of `<api>_periodic_tx` to the TX callback as a `uint64_t`, after the message pointer and before the context
661
+ pointer. See [Current time as callback argument](#current-time-as-callback-argument). Only meaningful together with `-p`.
646
662
  * `--tx-function` — bind a `uint16_t (*tx_function)(void *, const <frame> *)` and its context to the periodic-TX API through `<api>_periodic_tx_init`;
647
663
  `<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
648
664
  `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
@@ -20,6 +20,7 @@
20
20
  - [Double-buffered signal access](#double-buffered-signal-access)
21
21
  - [RX/TX callback context](#rxtx-callback-context)
22
22
  - [Message signals as RX callback argument](#message-signals-as-rx-callback-argument)
23
+ - [Current time as callback argument](#current-time-as-callback-argument)
23
24
  - [Using your own frame type](#using-your-own-frame-type)
24
25
  - [Example Use](#example-use)
25
26
  - [Dynamic decoding](#dynamic-decoding)
@@ -328,6 +329,17 @@ Passing `--msg-as-rx-callback-arg` instead hands the callback a `void *` pointin
328
329
 
329
330
  `struct MsgRxContext` remains a single shared type, which is why the signal struct is passed as `void *` rather than a typed pointer.
330
331
 
332
+ ### Current time as callback argument
333
+
334
+ The `now` handed to `<api>_process_received_frame` and `<api>_periodic_tx` can be forwarded to the callbacks, so a callback that timestamps, filters or rate-limits
335
+ does not have to read the clock again (and sees exactly the time the API used for `last_rx` / `last_tx`). The two paths have separate flags:
336
+
337
+ * `--time-as-rx-callback-arg` adds a `uint64_t now` parameter to the RX callback.
338
+ * `--time-as-tx-callback-arg` adds a `uint64_t now` parameter to the TX callback.
339
+
340
+ Arguments are always in the order message pointer, time, context pointer, each present only when its flag is set. With every RX flag the callback is
341
+ `void (*rx_callback)(void *msg, uint64_t now, void *ctx)`; with only `--time-as-tx-callback-arg` it is `void *(*tx_callback)(uint64_t now)`.
342
+
331
343
  ### Using your own frame type
332
344
 
333
345
  By default every generated function takes a `CanFrame *`, and the generator writes a sibling `canframe.h` that defines `CanFrame`. If the application already has a
@@ -618,6 +630,10 @@ Options:
618
630
  `--tx-signal-store` the pointer is the message's store struct, which the callback edits in place before encode; in callback-only mode `<api>_periodic_tx` stack-allocates
619
631
  the struct, and the callback fills it and returns it (or `NULL` to skip), so no application-provided storage is needed. See [Periodic TX](#periodic-tx). Only meaningful
620
632
  together with `-p`.
633
+ * `--time-as-rx-callback-arg` — pass the `now` of `<api>_process_received_frame` to the RX callback as a `uint64_t`, after the message pointer and before the
634
+ context pointer. See [Current time as callback argument](#current-time-as-callback-argument). Only meaningful together with `-r`.
635
+ * `--time-as-tx-callback-arg` — pass the `now` of `<api>_periodic_tx` to the TX callback as a `uint64_t`, after the message pointer and before the context
636
+ pointer. See [Current time as callback argument](#current-time-as-callback-argument). Only meaningful together with `-p`.
621
637
  * `--tx-function` — bind a `uint16_t (*tx_function)(void *, const <frame> *)` and its context to the periodic-TX API through `<api>_periodic_tx_init`;
622
638
  `<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
623
639
  `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
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present Alexande Becker <nabla.becker@mailbox.org>
2
2
  #
3
3
  # SPDX-License-Identifier: LGPL-3.0-only
4
- __version__ = "2.3.0"
4
+ __version__ = "2.4.0"
@@ -68,7 +68,7 @@ struct {{ api_struct_prefix }}RxSignals {{ var_name }};
68
68
  {% endmacro %}
69
69
 
70
70
  {% macro generate_global_rx_frame_process_function(messages, api_name, api_struct_prefix, can_frame_type, return_type, time_type, rx_callback, double_buffered=False, rx_callback_context=false, msg_as_rx_callback_arg=false, rx_signal_store=false, with_rx_valid=false, ctx_name='MsgRxContext', time_as_rx_callback_arg=false) -%}
71
- {%- set time_arg = 'now' if time_as_rx_callback_arg else '' %}
71
+ {%- set time_arg = 'now' if time_as_rx_callback_arg else '' -%}
72
72
  {{ declare_global_rx_frame_process_function(api_name, api_struct_prefix, can_frame_type, return_type, time_type) }} {
73
73
  {%- for message in messages %}
74
74
  {%- if message.direction == 'rx' or message.direction == 'rt' %}
@@ -0,0 +1,107 @@
1
+ """Runtime checks for --time-as-rx-callback-arg / --time-as-tx-callback-arg.
2
+
3
+ Generates the test_1.kcd API with the flag, links it against a C harness and
4
+ asserts that the callback receives the now passed to the API entry point, in
5
+ the documented argument order (message, now, context).
6
+ """
7
+ import subprocess
8
+ from pathlib import Path
9
+
10
+ import pytest
11
+ from click.testing import CliRunner
12
+
13
+ from src.can_api_generator.main import main
14
+
15
+ RX_HARNESS = r"""
16
+ #include <assert.h>
17
+ #include <stdio.h>
18
+ #include "tc.h"
19
+
20
+ static uint64_t seen_now;
21
+ static int ctx_token;
22
+
23
+ static void rx_cb(void *msg, uint64_t now, void *ctx) {
24
+ assert(msg != 0);
25
+ assert(ctx == &ctx_token);
26
+ seen_now = now;
27
+ }
28
+
29
+ int main(void) {
30
+ struct TcRxSignals rx = {0};
31
+ CanFrame frame = {.length = 4, .arbitration_id = 0x1, .payload = 0};
32
+ rx.message_2_context.rx_callback = rx_cb;
33
+ rx.message_2_context.rx_callback_context = &ctx_token;
34
+ assert(tc_process_received_frame(&rx, &frame, 12345) == 1);
35
+ assert(seen_now == 12345);
36
+ puts("ok");
37
+ return 0;
38
+ }
39
+ """
40
+
41
+ TX_HARNESS = r"""
42
+ #include <assert.h>
43
+ #include <stdio.h>
44
+ #include "tc.h"
45
+
46
+ static struct Message2 m2;
47
+ static uint64_t seen_now;
48
+ static int ctx_token;
49
+
50
+ static void *tx_cb(void *msg, uint64_t now, void *ctx) {
51
+ assert(msg != 0);
52
+ assert(ctx == &ctx_token);
53
+ seen_now = now;
54
+ return &m2;
55
+ }
56
+
57
+ int main(void) {
58
+ struct TcTxSignals tx;
59
+ CanFrame frame;
60
+ tc_periodic_tx_init(&tx, 0);
61
+ tx.message_2_context.tx_callback = tx_cb;
62
+ tx.message_2_context.tx_callback_context = &ctx_token;
63
+ tx.message_2_context.send_now = 1;
64
+ assert(tc_periodic_tx(&tx, &frame, 777) == 1);
65
+ assert(seen_now == 777);
66
+ puts("ok");
67
+ return 0;
68
+ }
69
+ """
70
+
71
+
72
+ @pytest.mark.parametrize("path", ["rx", "tx"])
73
+ def test_callback_receives_now(tmp_path, monkeypatch, path):
74
+ kcd = str(Path("tests/test_1.kcd").resolve())
75
+ monkeypatch.chdir(tmp_path)
76
+ if path == "rx":
77
+ flags = ["-r", "--time-as-rx-callback-arg", "--rx-callback-context"]
78
+ harness = RX_HARNESS
79
+ node = "other"
80
+ else:
81
+ flags = ["-p", "--time-as-tx-callback-arg", "--tx-callback-context",
82
+ "--msg-as-tx-callback-arg", "--send-now"]
83
+ harness = TX_HARNESS
84
+ node = "DUT"
85
+ result = CliRunner().invoke(main, ["api", kcd, "tc", node, *flags])
86
+ assert result.exit_code == 0, result.output
87
+ (tmp_path / "harness.c").write_text(harness)
88
+ build = subprocess.run(
89
+ ["gcc", "-Wall", "-Werror", "-o", "harness", "harness.c", "tc.c"],
90
+ capture_output=True, text=True)
91
+ assert build.returncode == 0, build.stderr
92
+ run = subprocess.run(["./harness"], capture_output=True, text=True)
93
+ assert run.returncode == 0, run.stdout + run.stderr
94
+ assert run.stdout.strip() == "ok"
95
+
96
+
97
+ @pytest.mark.parametrize("flag,cb", [
98
+ ("-r", "void (*rx_callback)(void *);"),
99
+ ("-p", "void *(*tx_callback)(void);"),
100
+ ])
101
+ def test_time_arg_absent_by_default(tmp_path, monkeypatch, flag, cb):
102
+ kcd = str(Path("tests/test_1.kcd").resolve())
103
+ monkeypatch.chdir(tmp_path)
104
+ node = "other" if flag == "-r" else "DUT"
105
+ result = CliRunner().invoke(main, ["api", kcd, "tc", node, flag])
106
+ assert result.exit_code == 0, result.output
107
+ assert cb in (tmp_path / "tc.h").read_text()