can-api-generator 0.0.10__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 (73) hide show
  1. can_api_generator-0.0.10/.gitignore +2 -0
  2. can_api_generator-0.0.10/LICENSE.txt +166 -0
  3. can_api_generator-0.0.10/PKG-INFO +348 -0
  4. can_api_generator-0.0.10/README.md +324 -0
  5. can_api_generator-0.0.10/manual_cag_test.py +135 -0
  6. can_api_generator-0.0.10/pyproject.toml +70 -0
  7. can_api_generator-0.0.10/src/can_api_generator/__about__.py +4 -0
  8. can_api_generator-0.0.10/src/can_api_generator/__init__.py +3 -0
  9. can_api_generator-0.0.10/src/can_api_generator/code_generator.py +112 -0
  10. can_api_generator-0.0.10/src/can_api_generator/main.py +123 -0
  11. can_api_generator-0.0.10/src/can_api_generator/msg_processor.py +371 -0
  12. can_api_generator-0.0.10/src/can_api_generator/templates/canframe.jinja +12 -0
  13. can_api_generator-0.0.10/src/can_api_generator/templates/declaration_macros.jinja +23 -0
  14. can_api_generator-0.0.10/src/can_api_generator/templates/encoding_macros.jinja +304 -0
  15. can_api_generator-0.0.10/src/can_api_generator/templates/header_template.jinja +87 -0
  16. can_api_generator-0.0.10/src/can_api_generator/templates/rx_macros.jinja +92 -0
  17. can_api_generator-0.0.10/src/can_api_generator/templates/source_template.jinja +60 -0
  18. can_api_generator-0.0.10/src/can_api_generator/templates/tx_macros.jinja +149 -0
  19. can_api_generator-0.0.10/src/can_api_generator/types.py +39 -0
  20. can_api_generator-0.0.10/src/can_api_generator/utils.py +64 -0
  21. can_api_generator-0.0.10/tests/__init__.py +3 -0
  22. can_api_generator-0.0.10/tests/cantool_test_utils.jinja +67 -0
  23. can_api_generator-0.0.10/tests/multiple_busses_test.kcd +42 -0
  24. can_api_generator-0.0.10/tests/test_1.kcd +37 -0
  25. can_api_generator-0.0.10/tests/test_basic_multiplex.kcd +33 -0
  26. can_api_generator-0.0.10/tests/test_big_endian.kcd +22 -0
  27. can_api_generator-0.0.10/tests/test_float_wrong_length.kcd +17 -0
  28. can_api_generator-0.0.10/tests/test_message_parser.py +278 -0
  29. can_api_generator-0.0.10/tests/test_missing_consumer.kcd +24 -0
  30. can_api_generator-0.0.10/tests/test_missing_producer.kcd +20 -0
  31. can_api_generator-0.0.10/tests/test_mux_group_count_out_of_order.kcd +33 -0
  32. can_api_generator-0.0.10/tests/test_mux_with_labeled_index.kcd +37 -0
  33. can_api_generator-0.0.10/tests/test_mux_with_partially_labled_index.kcd +36 -0
  34. can_api_generator-0.0.10/tests/test_mux_with_same_signal_names.kcd +33 -0
  35. can_api_generator-0.0.10/tests/test_mux_with_same_signal_names_labeled_mux_variants.kcd +37 -0
  36. can_api_generator-0.0.10/tests/test_mux_with_scale_and_offset.kcd +34 -0
  37. can_api_generator-0.0.10/tests/test_non_encodable_0.kcd +22 -0
  38. can_api_generator-0.0.10/tests/test_overlapping_signals.kcd +33 -0
  39. can_api_generator-0.0.10/tests/test_periodic_tx_over_can.jinja +114 -0
  40. can_api_generator-0.0.10/tests/test_procedures.jinja +360 -0
  41. can_api_generator-0.0.10/tests/test_prog_source_template.jinja +100 -0
  42. can_api_generator-0.0.10/tests/test_rx_over_can.jinja +89 -0
  43. can_api_generator-0.0.10/tests/test_signal_direction.kcd +32 -0
  44. can_api_generator-0.0.10/tests/test_signal_encoding/double_plain.kcd +16 -0
  45. can_api_generator-0.0.10/tests/test_signal_encoding/double_scaled.kcd +16 -0
  46. can_api_generator-0.0.10/tests/test_signal_encoding/double_scaled_offset.kcd +16 -0
  47. can_api_generator-0.0.10/tests/test_signal_encoding/float_plain.kcd +15 -0
  48. can_api_generator-0.0.10/tests/test_signal_encoding/float_scaled.kcd +15 -0
  49. can_api_generator-0.0.10/tests/test_signal_encoding/float_scaled_offset.kcd +15 -0
  50. can_api_generator-0.0.10/tests/test_signal_encoding/sint_matching_fractional_scaled.kcd +15 -0
  51. can_api_generator-0.0.10/tests/test_signal_encoding/sint_matching_fractional_scaled_offset.kcd +15 -0
  52. can_api_generator-0.0.10/tests/test_signal_encoding/sint_matching_plain.kcd +15 -0
  53. can_api_generator-0.0.10/tests/test_signal_encoding/sint_matching_scaled.kcd +15 -0
  54. can_api_generator-0.0.10/tests/test_signal_encoding/sint_matching_scaled_offset.kcd +15 -0
  55. can_api_generator-0.0.10/tests/test_signal_encoding/sint_nonmatching_fractional_scaled.kcd +15 -0
  56. can_api_generator-0.0.10/tests/test_signal_encoding/sint_nonmatching_plain.kcd +15 -0
  57. can_api_generator-0.0.10/tests/test_signal_encoding/sint_nonmatching_scaled.kcd +15 -0
  58. can_api_generator-0.0.10/tests/test_signal_encoding/sint_nonmatching_scaled_offset.kcd +15 -0
  59. can_api_generator-0.0.10/tests/test_signal_encoding/test_decoding_numerical_value.jinja +2 -0
  60. can_api_generator-0.0.10/tests/test_signal_encoding/test_encoding_numerical_value.jinja +2 -0
  61. can_api_generator-0.0.10/tests/test_signal_encoding/test_signal_encoding_wrong_float_size.kcd +25 -0
  62. can_api_generator-0.0.10/tests/test_signal_encoding/uint_matching_fractional_scaled.kcd +15 -0
  63. can_api_generator-0.0.10/tests/test_signal_encoding/uint_matching_plain.kcd +15 -0
  64. can_api_generator-0.0.10/tests/test_signal_encoding/uint_matching_scaled.kcd +15 -0
  65. can_api_generator-0.0.10/tests/test_signal_encoding/uint_matching_scaled_offset.kcd +15 -0
  66. can_api_generator-0.0.10/tests/test_signal_encoding/uint_nonmatching_fractional_scaled.kcd +15 -0
  67. can_api_generator-0.0.10/tests/test_signal_encoding/uint_nonmatching_plain.kcd +15 -0
  68. can_api_generator-0.0.10/tests/test_signal_encoding/uint_nonmatching_scaled.kcd +15 -0
  69. can_api_generator-0.0.10/tests/test_signal_encoding/uint_nonmatching_scaled_offset.kcd +15 -0
  70. can_api_generator-0.0.10/tests/test_too_large_message.kcd +17 -0
  71. can_api_generator-0.0.10/tests/test_tx_over_can.jinja +85 -0
  72. can_api_generator-0.0.10/tests/test_vcan_round_trip.py +437 -0
  73. can_api_generator-0.0.10/todo.md +61 -0
@@ -0,0 +1,2 @@
1
+ __pycache__/
2
+ dist/
@@ -0,0 +1,166 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
166
+
@@ -0,0 +1,348 @@
1
+ Metadata-Version: 2.4
2
+ Name: can-api-generator
3
+ Version: 0.0.10
4
+ Summary: Program to generate a 'signal' style CAN API in C
5
+ Project-URL: Documentation, https://sr.ht/~laplace/can-api-generator#readme
6
+ Project-URL: Issues, https://sr.ht/~laplace/can-api-generator/issues
7
+ Project-URL: Source, https://sr.ht/~laplace/can-api-generator
8
+ Author-email: Alexande Krishna-Becker <nabla.becker@mailbox.org>
9
+ License-Expression: LGPL-3.0-only
10
+ License-File: LICENSE.txt
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
18
+ Requires-Python: >=3.8
19
+ Requires-Dist: cantools
20
+ Requires-Dist: click
21
+ Requires-Dist: jinja2
22
+ Requires-Dist: rich
23
+ Description-Content-Type: text/markdown
24
+
25
+ # can-api-generator
26
+
27
+ [![PyPI - Version](https://img.shields.io/pypi/v/can-api-generator.svg)](https://pypi.org/project/can-api-generator)
28
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/can-api-generator.svg)](https://pypi.org/project/can-api-generator)
29
+
30
+ -----
31
+
32
+ ## Table of Contents
33
+
34
+ - [Installation](#installation)
35
+ - [License](#license)
36
+ - [Overview](#overview)
37
+ - [Features of the library](#features-of-the-library)
38
+ - [Additional features](#additional-features)
39
+ - [Global RX](#global-rx)
40
+ - [Periodic TX](#periodic-tx)
41
+ - [Encode All Signals](#encode-all-signals)
42
+ - [TI C2000 compatibility](#ti-c2000-compatibility)
43
+ - [Double-buffered signal access](#double-buffered-signal-access)
44
+ - [Example Use](#example-use)
45
+ - [Command-line reference](#command-line-reference)
46
+
47
+ ## Installation
48
+
49
+ ```console
50
+ pip install can-api-generator
51
+ ```
52
+
53
+ ## License
54
+
55
+ `can-api-generator` is distributed under the terms of the [GPL-3.0-only](https://spdx.org/licenses/GPL-3.0-only.html) license.
56
+
57
+ ## Overview
58
+ The `can-api-generator` is a program to generate a C implementation for a 'signal' style CAN API from a KCD file describing the signals and their arrangement
59
+ in to messages sent over the can bus.
60
+ A signal represents a value that is shared among all nodes of the bus. Due to the fact that CAN is based on packets, which are referred
61
+ to as frames, multiple signals may to be grouped into a common message which is then transmitted as a can frame. Different messages are distinguished via the arbitration id
62
+ that is part of the can frame.
63
+ Thus the arbitration ID acts as a content address (think address of memory shared over the can bus), and not a source or destination address.
64
+
65
+ A Frames are sent out by the node that modifies a value that is contained in the Frame.
66
+ A KCD file may encompass multiple nodes that have messages sent between them. To minimize the code generated, a Node needs to be specified so that only the messages that
67
+ are transmitted or received by this node. Flags allow generating the additional code if needed.
68
+
69
+ The API is only concerned with frames that are defined by the KCD file from which the API was generated. Other frames may be transmitted over the bus and are
70
+ outside the scope of this API. The code simply decodes what it can identify and only produces frames that are defined as 'tx' from the nodes
71
+
72
+ ### Practical uses
73
+ In practice frames are often sent periodically, even if no change has occured, to provide redundancy and fault tolerance to the system.
74
+ Even though any node in the network may send any frame, in practice only a single node on a bus will update certain signals, thus avoiding the problems that
75
+ arise when multiple nodes modify the same signal.
76
+
77
+ Can frames generated by this library are compatible to the DBC and KCD definitions and can thus be decoded by industry standard tools like busmaster/canoe/PeakCan etc.
78
+
79
+ # Features of the library
80
+ ---
81
+ * One struct per message: The struct contains the signals that are explicitly defined in the can frame (including multiplexes). This allows a single message struct
82
+ to fully define a frame (the ID and length are declared as defines). (see the example for explicit code)
83
+ * Decodeing/Encoding functions: For each Message a decode and encode functions is generated that allow to translate the struct into a 'CanFrame' and decode a 'CanFrame' struct in to the
84
+ message struct that contains the values encoded as native data types. The encoding function also sets the length and the arbitration id of the can frame.
85
+
86
+ ## Additional features
87
+ ---
88
+
89
+ This generator may generate additional code that was found useful in many common cases:
90
+ * a **global rx** function (enabled with `-r`/`--global-rx`): takes a received can frame, matches it against the message definitions in the API, and decodes it into
91
+ a 'global' api struct containing the signals for every message this node consumes.
92
+ * a **periodic tx** function (enabled with `-p`/`--periodic-tx`): schedules messages to be sent automatically. Auxiliary information is stored, similar to the
93
+ 'global rx', in a TxContext struct. It allows for changing the period of the transmission on the fly and also allows a tx callback to be called upon
94
+ transmission of any particular message. Transmission may also be disabled per message.
95
+ * an **encode-every-signal** helper per message (enabled with `-a`/`--encode-all-signals-func`): fills a caller-provided buffer with the minimum number of frames
96
+ needed to cover every signal in a multiplexed message at least once. See [Encode All Signals](#encode-all-signals).
97
+ * an **immediate-send override** for the periodic tx path (enabled with `--send-now`): adds a per-message `send_now` flag that fires the next `periodic_tx` call
98
+ regardless of schedule or enable state. Useful for publishing critical signal changes without waiting out the rest of the period.
99
+ * **TI C2000 compatible** codegen (enabled with `--ti-compatible`): hoists local variable declarations to the top of encode/decode functions so the generated C
100
+ compiles under the TI C2000 compiler's strict C90 rules. See [TI C2000 compatibility](#ti-c2000-compatibility).
101
+ * **double-buffered signal access** (enabled with `--double-buffered`): emits two storage slots and front/back pointers per message so that an ISR-side decode
102
+ never exposes a partially-written struct to readers, and a periodic tx encoder never reads a struct that user code is mid-update. See
103
+ [Double-buffered signal access](#double-buffered-signal-access).
104
+
105
+ ### Global RX
106
+ Global RX generates the code needed to take any received can frame and decode it in to the API if the message matches a definition in the API. This allows the application to
107
+ call a single function once per received frame and have access to all signals shared via the CAN bus system by simply reading the signals in the RX struct.
108
+
109
+ The global rx funciton needs to be called with the 'current time'. which for MCUs is most often represented by a count of the milliseconds passed since power up.
110
+
111
+ The global RX struct also contains one `MsgRxContext` struct per message. This allows to configure parameters and read back metadata about the message.
112
+ The `MsgRxContext` has the following form:
113
+ ```c
114
+ struct MsgRxContext {
115
+ uint16_t ignore;
116
+ uint16_t valid;
117
+ uint64_t last_rx;
118
+ void (*rx_callback)(void);
119
+ };
120
+ ```
121
+ * When the `ignore` value is set to 1, the received message is not decoded even if it's arbitration id and length matched with the message definition.
122
+ * The `valid` field is set to 1 every time the corresponging message is received. This value may be written to 0 by the application and allows the application
123
+ to simply check if the information in the message has been written to. This is useful when a critical section is to be entered that requires other programs
124
+ to have set configuration parameters that need to be valid before the critical section is entered.
125
+ * `last_rx` field stores the value of the 'clock' the last time this message was received. this may be used for diagnostics and statistics
126
+
127
+ ### Periodic TX
128
+ The periodic TX is the counterpart to the 'global RX'. It takes care to schedule the transmission of periodic frames at the proper time. Periodic frames are pretty
129
+ common on CAN bus systems and provide robust communication of critical data without the need for explicit synchronization mechanisms. Many controllers, often found in
130
+ automotive applications send the same message periodically. This allows for 'quasi-analog' values to be transmitted via the CAN bus. When enabling the `-p`/`--periodic-tx` flag
131
+ the can api generator generates a `<api>_periodic_tx` function that properly schedules periodic messages, an `<api>_periodic_tx_init` function that seeds the per-message
132
+ contexts from the `cycle_time` values in the KCD, and an `<api>_get_msg_tx_context_by_id` helper for looking up a message context by arbitration id. To configure the
133
+ periodic transmission the `TxSignals` struct, that is generated along with the periodic tx function, provisions one `MsgTxContext` struct for each message. The
134
+ `MsgTxContext` is defined as following:
135
+ ```c
136
+ struct MsgTxContext {
137
+ uint32_t arb_id;
138
+ uint16_t enable;
139
+ uint64_t last_tx;
140
+ uint32_t period;
141
+ uint32_t offset;
142
+ uint32_t offset_seed;
143
+ void (*tx_callback)(void);
144
+ uint16_t send_now; // only present when compiled with --send-now
145
+ };
146
+ ```
147
+ * `arb_id` is the arbitration id of the message the context controls. It is seeded by `<api>_periodic_tx_init` so the application can look up a context by id via
148
+ `<api>_get_msg_tx_context_by_id`.
149
+ * `enable` needs to be set to 1 for the message to be sent periodically. This allows the application to reduce bus load by silencing messages depending on the situation.
150
+ Init sets this to 1 for messages that declare a `cycle_time` in the KCD and 0 for the rest.
151
+ * `last_tx` is updated by the periodic tx function every time a frame fires. Combined with `period`, it gates retransmission so a frame cannot fire more often than once
152
+ per period.
153
+ * `period` configures the time between two messages (in MCU clock units). Most MCUs use a 1ms tick so this value often ends up being the number of milliseconds between
154
+ two periodic transmissions. The application may change this at runtime via `<api>_update_tx_period(ctx, new_period)`, which also recomputes `offset` so the phase stays
155
+ consistent.
156
+ * `offset` is a value that adds an offset to the transmission time. Multiple messages will often have the same period (say 100ms). Without the offset the CAN bus becomes
157
+ quite 'bursty' as every 100ms many messages are encoded at once and require transmission. This may lead to dropped messages and bus load problems even at low average
158
+ load. This offset spreads out the transmission of messages through the entire transmission period, reducing pileup of messages.
159
+ * `offset_seed` is a per-message constant seeded at generation time so that different messages with the same period end up at different phases inside that period without
160
+ the application having to pick offsets by hand.
161
+ * `tx_callback` is a function that is called after the tx frame has been encoded. It allows sending one message after the other (as used for data transfers). Using this
162
+ technique it is possible to effectively set data transfer rates. This works well in combination with the enable flag.
163
+ * `send_now` is only emitted when the generator is invoked with `--send-now`. Setting this flag to 1 makes the next `<api>_periodic_tx` call emit the corresponding frame
164
+ immediately, regardless of the periodic schedule or the `enable` bit. The function auto-clears the flag after firing, so each set fires exactly once. Useful when a
165
+ critical signal has just changed and you want it on the bus on the very next tick instead of waiting out the remainder of the period.
166
+
167
+ ### Encode All Signals
168
+ 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
169
+ 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
170
+ must wait a long time until the multiplex is cycled throug all it's mux groups. To reduce the time it takes to read back this kind of message, the `encode all messages` function is used.
171
+ This function generates a group of CanFrames and stores them in to a buffer provided by the caller. This buffer can then be flushed by the application. The size of the buffer required for
172
+ a given message is declared as a preprocessor define in the library header file. To receive all frames generated by the function the caller needs to provide a buffer of at least that size.
173
+
174
+ the 'encode all signals' function is generated when the tool is passed the `-a` option.
175
+
176
+ ### TI C2000 compatibility
177
+ Some target compilers — notably the TI C2000 toolchain — refuse C99-style "declaration after statement" code, which requires all local variables to be declared at
178
+ the top of a block before any statements. The default code generator emits variable declarations inline inside `switch`/`case` bodies for multiplexed messages, which
179
+ the TI compiler rejects. Passing `--ti-compatible` changes the codegen so every per-signal temporary is hoisted to the top of the enclosing encode/decode function, all
180
+ mux variant assignments become pure stores instead of declarations, and the loop counter in the `encode_every_signal` helper is predeclared before its initializer.
181
+ The resulting source compiles cleanly under both `-std=c99` and `-std=c90 -Wdeclaration-after-statement -Werror=declaration-after-statement`, matching what the TI
182
+ C2000 compiler will accept.
183
+
184
+ ### Double-buffered signal access
185
+ When an RX frame is decoded from an ISR while the main loop reads signals (or the converse for TX, where the user updates the struct while `periodic_tx` encodes
186
+ it), a reader can observe a half-written struct and act on inconsistent data. Passing `--double-buffered` changes the generated global RX and periodic TX
187
+ structs so every message carries two storage slots and two pointers, and the dispatcher / commit helper publishes new values via an atomic pointer swap
188
+ instead of an in-place update:
189
+
190
+ ```c
191
+ struct DUTRxSignals {
192
+ struct MsgRxContext message_1_context;
193
+ struct Message1 message_1_signals_storage[2];
194
+ struct Message1 * volatile message_1_signals; /* reader view */
195
+ struct Message1 * message_1_signals_back; /* dispatcher decodes here */
196
+ /* ... */
197
+ };
198
+
199
+ struct DUTTxSignals {
200
+ struct MsgTxContext message_1_context;
201
+ struct Message1 message_1_signals_storage[2];
202
+ struct Message1 * message_1_signals; /* staging — user writes here */
203
+ struct Message1 * volatile message_1_signals_committed; /* periodic_tx reads this */
204
+ /* ... */
205
+ };
206
+ ```
207
+
208
+ Semantics:
209
+
210
+ * Access to the signal sub-struct becomes pointer-style instead of dot-style. Read the latest decoded RX value as
211
+ `rx_signals.message_1_signals->field`, and write a pending TX value as `tx_signals.message_1_signals->field`.
212
+ * `<api>_global_rx_init(&rx_signals)` wires up the front/back pointers and zeroes both storage slots. Call it once before `<api>_process_received_frame`.
213
+ * `<api>_periodic_tx_init(&tx_signals, now)` wires up the staging/committed pointers in addition to the usual context init. Call it once before
214
+ `<api>_periodic_tx`.
215
+ * For each TX message the generator emits a per-message commit helper, `<api>_<message_name>_commit(&tx_signals)`. It swaps the staging and committed
216
+ pointers — after the call, the values the user just wrote into staging are live on the `committed` side, and the new staging slot contains the previous
217
+ `committed` snapshot. The swap is cheap (two pointer writes) and allocation-free.
218
+ * The RX dispatcher decodes into `message_<n>_signals_back` and, on success, swaps `message_<n>_signals` ↔ `message_<n>_signals_back` inside a short inner
219
+ block. A decode that aborts mid-way never publishes a partial struct — the front pointer keeps pointing at the previously-good decode.
220
+ * Because commits are pointer-swap rather than memcpy, the new staging slot holds the previous committed snapshot. Code that updates a subset of fields per
221
+ commit therefore still publishes coherent messages, but code that relies on staging being zero after commit must zero it explicitly.
222
+
223
+ Ordering guarantee: the front/committed pointers are declared `volatile` so the compiler will not reorder the pointer publish across reads in the same
224
+ translation unit. This is sufficient for a single-core MCU where the dispatcher runs in an ISR and readers run in the main loop, which is the target use
225
+ case. On weakly-ordered multicore hosts, user code is responsible for inserting the appropriate memory barrier between the decode writes and the pointer
226
+ publish, and between reading the pointer and dereferencing it — the generator does not emit any barriers itself.
227
+
228
+ ## Example Use
229
+
230
+ As an example the following KCD definition of all messages on a CAN bus is converted:
231
+ ```xml
232
+ <?xml version="1.0" ?>
233
+ <NetworkDefinition xmlns="http://kayak.2codeornot2code.org/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="KCD_Definition.xsd">
234
+ <Document name="can-api-generator-test-1" version="1" author="Alexander Krishna-Becker" company="radiation.systems" date="2025-11-01"/>
235
+ <Node id="0" name="DUT"/>
236
+ <Node id="1" name="other"/>
237
+ <Bus name="ControlBus" baudrate="500000">
238
+ <Message id="0x0" length="1" name="Message 1" interval="100" format="extended">
239
+ <Notes>Test Note 1</Notes>
240
+ <Producer> <NodeRef id="0"/> </Producer>
241
+ <Signal name="Signal 1" offset="0" length="1">
242
+ <Notes>Signal 1 of Message 1 of the DUT</Notes>
243
+ <Consumer> <NodeRef id="1"/> </Consumer>
244
+ <Value type="unsigned"/>
245
+ </Signal>
246
+ <Signal name="Signal 2" offset="1" length="7">
247
+ <Notes>Signal 1 of Message 1 of the DUT</Notes>
248
+ <Consumer> <NodeRef id="1"/> </Consumer>
249
+ <Value type="signed"/>
250
+ </Signal>
251
+ </Message>
252
+
253
+ <Message id="0x1" length="2" name="Message 2" interval="100" format="extended">
254
+ <Notes>Test Note 1</Notes>
255
+ <Producer> <NodeRef id="0"/> </Producer>
256
+ <Signal name="Signal 3" offset="0" length="16">
257
+ <Notes>Signal 1 of Message 1 of the DUT</Notes>
258
+ <Consumer> <NodeRef id="1"/> </Consumer>
259
+ <Value type="unsigned"/>
260
+ </Signal>
261
+ </Message>
262
+ </Bus>
263
+ </NetworkDefinition>
264
+ ```
265
+ The result of the conversion are the decode/encode functions along with the structs to hold the application accessible signals.
266
+
267
+ To convert the KCD file into C code the following command is used:
268
+
269
+ ```bash
270
+ can-api-gen example.kcd my_api DUT
271
+ ```
272
+ The first argument is the path to the kcd file. The second argument is the name of the API. This name determins the name of the C and H file headers as well as parts of the name of the struct and functions.
273
+ This is done so that multiple APIs may be used within the same project without interfering with each other. The last entry is the name of the Device for which the can api is to be generated.
274
+ This is needed as multiple devices may be described on a single can Bus. The KCD file then needs to describe what signal is sent by a device, as well as which signal a device is listening for.
275
+ The interface generator uses this info to only generate messages that are relevant to the particular device. The following is the resulting header:
276
+
277
+ ```c
278
+ #ifndef CAN_API_MY_API
279
+ #define CAN_API_MY_API
280
+ #include "canframe.h"
281
+
282
+ // If all signals in a message need to be encoded then it will need
283
+ // a buffer of at least the size defined here to hold the frames to set each signal
284
+ // contained in the message at least once
285
+ #define MESSAGE_1_MIN_FRAMES_FOR_ALL_SIGNALS 1
286
+ #define MESSAGE_2_MIN_FRAMES_FOR_ALL_SIGNALS 1
287
+
288
+
289
+
290
+ struct Message1 {
291
+ uint16_t signal_1;
292
+ int16_t signal_2;
293
+ };
294
+ struct Message2 {
295
+ uint16_t signal_3;
296
+ };
297
+
298
+ void my_api_message_1_decode(struct Message1 *msg, CanFrame *input_frame);
299
+ void my_api_message_1_encode(struct Message1 *msg, CanFrame *output_frame);
300
+ uint16_t my_api_message_1_encode_every_signal(struct Message1* msg, CanFrame *output_frame_buf, uint32_t buf_size);
301
+ void my_api_message_2_decode(struct Message2 *msg, CanFrame *input_frame);
302
+ void my_api_message_2_encode(struct Message2 *msg, CanFrame *output_frame);
303
+ uint16_t my_api_message_2_encode_every_signal(struct Message2* msg, CanFrame *output_frame_buf, uint32_t buf_size);
304
+ #endif
305
+ ```
306
+
307
+ As can be seen it provides `encode` and `decode` functions for each message that interacts with the DUT. It also emits an `encode_every_signal` helper per message
308
+ (because the example was generated with `-a`), the minimum buffer-size defines the caller needs for that helper, and the message structs themselves. The companion
309
+ `canframe.h` file is written next to the library header; it declares the small `CanFrame` struct the API uses as an I/O boundary with the application's can driver.
310
+
311
+ To enable the additional features, pass the corresponding flags at generation time:
312
+
313
+ ```bash
314
+ # Generate a full-featured API with global rx, periodic tx, encode-every-signal,
315
+ # send-now support, and TI C2000 compatible codegen.
316
+ can-api-gen example.kcd my_api DUT -r -p -a --send-now --ti-compatible
317
+ ```
318
+
319
+ ## Command-line reference
320
+
321
+ Positional arguments:
322
+ * `KCD_FILE` — path to the KCD (XML) description of the bus.
323
+ * `LIBRARY_NAME` — stem of the generated library. The output files are `<LIBRARY_NAME>.c`, `<LIBRARY_NAME>.h`, and a sibling `canframe.h`. The stem is also used as
324
+ the prefix for every generated function so multiple APIs can coexist in the same project.
325
+ * `NODE_NAME` — name of the node the API is being generated for. Only messages that this node produces or consumes are emitted, so the binary size stays small for
326
+ embedded targets.
327
+
328
+ Options:
329
+ * `-f`, `--force` — overwrite existing output files. Without this, the generator refuses to clobber an existing `.c`/`.h`.
330
+ * `-a`, `--encode-all-signals-func` — for each message, emit an `<api>_<msg>_encode_every_signal` helper that fills a caller-provided buffer with enough
331
+ frames to cover every signal at least once (primarily useful for multiplexed config messages).
332
+ * `-r`, `--global-rx` — emit the api-wide `RxSignals` struct plus a `<api>_process_received_frame` dispatcher that takes a raw `CanFrame`, figures out which
333
+ message it corresponds to, and decodes it into the right per-message struct. See the [Global RX](#global-rx) section for details.
334
+ * `-p`, `--periodic-tx` — emit the api-wide `TxSignals` struct, the `<api>_periodic_tx` function, and `<api>_periodic_tx_init` / `<api>_update_tx_period` /
335
+ `<api>_get_msg_tx_context_by_id` helpers. See the [Periodic TX](#periodic-tx) section.
336
+ * `--send-now` — add a `send_now` field to each `MsgTxContext` and a gate in the periodic tx function that fires a frame immediately when the flag is set,
337
+ bypassing both `enable` and the periodic schedule. Only meaningful together with `-p`.
338
+ * `--ti-compatible` — hoist all per-signal temporaries to the top of every encode/decode function so the generated C compiles under strict C90
339
+ ("declarations before statements"), which is what the TI C2000 compiler requires. See [TI C2000 compatibility](#ti-c2000-compatibility).
340
+ * `--double-buffered` — emit two signal-struct storage slots plus front/back pointers per message, an `<api>_global_rx_init` helper that wires the RX
341
+ pointers, and a per-message `<api>_<msg>_commit` helper that swaps the TX staging and committed pointers. The RX dispatcher publishes new decodes via
342
+ pointer swap, and `<api>_periodic_tx` encodes from the committed slot. See [Double-buffered signal access](#double-buffered-signal-access).
343
+ * `-im`, `--id-member-name TEXT` — override the name of the `CanFrame` member that carries the arbitration id (default `arbitration_id`). Used to adapt the API
344
+ to an existing project's frame struct naming.
345
+ * `-lm`, `--length-member-name TEXT` — override the name of the `CanFrame` length member (default `length`).
346
+ * `-pm`, `--payload-member-name TEXT` — override the name of the `CanFrame` payload member (default `payload`).
347
+ * `-v`, `--verbose` — dump the processed message dicts that get fed into the Jinja templates. Useful when debugging template or generator changes.
348
+ * `--help` — show the CLI help and exit.