statable 3.1.0__py3-none-any.whl
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.
- codegen/__init__.py +38 -0
- codegen/c_code_generator.py +1752 -0
- codegen/code_merger.py +371 -0
- codegen/code_templates.py +509 -0
- codegen/config.py +167 -0
- codegen/enum_generator.py +377 -0
- codegen/event_queue_generator.py +303 -0
- codegen/interrupt_generator.py +345 -0
- codegen/naming_convention.py +171 -0
- codegen/osal_generator.py +282 -0
- codegen/role_function_generator.py +1244 -0
- codegen/sample_data.py +269 -0
- codegen/state_actions_generator.py +395 -0
- codegen/struct_generator.py +721 -0
- codegen/timer_generator.py +299 -0
- codegen/transition_generator.py +907 -0
- codegen/type_mapper.py +69 -0
- codegen/validate/__init__.py +38 -0
- codegen/validate/change_actions.py +90 -0
- codegen/validate/change_applier.py +416 -0
- codegen/validate/clipboard_manager.py +47 -0
- codegen/validate/data/__init__.py +30 -0
- codegen/validate/data/action_definitions.py +200 -0
- codegen/validate/data/keywords.py +46 -0
- codegen/validate/data/prompt_templates.py +176 -0
- codegen/validate/data/validation_rules.py +205 -0
- codegen/validate/items/__init__.py +30 -0
- codegen/validate/items/base_validator.py +25 -0
- codegen/validate/items/cell_validator.py +275 -0
- codegen/validate/items/custom_type_validator.py +75 -0
- codegen/validate/items/event_validator.py +78 -0
- codegen/validate/items/flag_validator.py +74 -0
- codegen/validate/items/interrupt_validator.py +75 -0
- codegen/validate/items/queue_validator.py +73 -0
- codegen/validate/items/role_function_validator.py +175 -0
- codegen/validate/items/state_validator.py +88 -0
- codegen/validate/items/timer_validator.py +120 -0
- codegen/validate/items/transition_validator.py +113 -0
- codegen/validate/items/variable_validator.py +132 -0
- codegen/validate/logger.py +52 -0
- codegen/validate/models.py +177 -0
- codegen/validate/prompt_generator.py +724 -0
- codegen/validate/response_parser.py +154 -0
- codegen/validate/response_validator.py +275 -0
- codegen/validate/validation_dialog.py +322 -0
- codegen/validate/validator.py +94 -0
- codegen/variable_generator.py +419 -0
- statable/__init__.py +71 -0
- statable/__main__.py +49 -0
- statable/cli.py +251 -0
- statable/global_defs.py +256 -0
- statable/mermaid_gen.py +144 -0
- statable/model.py +426 -0
- statable/parser.py +64 -0
- statable/sample_data.py +435 -0
- statable/shared/__init__.py +24 -0
- statable/shared/condition_library.py +63 -0
- statable/shared/literal_library.py +66 -0
- statable/shared/role_function_library.py +150 -0
- statable/state_machine.py +121 -0
- statable/xml_io.py +1164 -0
- statable-3.1.0.dist-info/METADATA +151 -0
- statable-3.1.0.dist-info/RECORD +117 -0
- statable-3.1.0.dist-info/WHEEL +5 -0
- statable-3.1.0.dist-info/entry_points.txt +2 -0
- statable-3.1.0.dist-info/top_level.txt +3 -0
- statable_gui/__init__.py +23 -0
- statable_gui/action_edit_dialog.py +214 -0
- statable_gui/code_generation_dialog.py +486 -0
- statable_gui/code_generation_settings_dialog.py +522 -0
- statable_gui/common_widgets.py +537 -0
- statable_gui/condition_builder_dialog.py +500 -0
- statable_gui/condition_edit_dialog.py +123 -0
- statable_gui/condition_template_dialog.py +58 -0
- statable_gui/config.py +21 -0
- statable_gui/dialogs.py +439 -0
- statable_gui/event_definition_dialog.py +605 -0
- statable_gui/event_delivery_settings_dialog.py +191 -0
- statable_gui/event_queue_dialog.py +245 -0
- statable_gui/global_defs.py +167 -0
- statable_gui/global_defs_dialog.py +796 -0
- statable_gui/i18n/__init__.py +118 -0
- statable_gui/interrupt_handler_edit_dialog.py +810 -0
- statable_gui/layer_settings_dialog.py +180 -0
- statable_gui/libcntrl/__init__.py +23 -0
- statable_gui/libcntrl/condition_library.py +13 -0
- statable_gui/libcntrl/literal_library.py +13 -0
- statable_gui/libcntrl/literal_management_dialog.py +185 -0
- statable_gui/libcntrl/role_function_edit_dialog.py +145 -0
- statable_gui/libcntrl/role_function_library.py +13 -0
- statable_gui/literal_definition_dialog.py +62 -0
- statable_gui/logger.py +83 -0
- statable_gui/main_window.py +1380 -0
- statable_gui/matrix_table.py +413 -0
- statable_gui/preference_keys.py +18 -0
- statable_gui/preferences.py +74 -0
- statable_gui/role_function_dialog.py +244 -0
- statable_gui/sample_data.py +11 -0
- statable_gui/state_actions_dialog.py +398 -0
- statable_gui/symbol_picker.py +170 -0
- statable_gui/traceball.py +37 -0
- statable_gui/transition_editor_direct/__init__.py +15 -0
- statable_gui/transition_editor_direct/actions_tab.py +856 -0
- statable_gui/transition_editor_direct/code_widget.py +344 -0
- statable_gui/transition_editor_direct/coverage_analyzer.py +163 -0
- statable_gui/transition_editor_direct/dialog.py +335 -0
- statable_gui/transition_editor_direct/draft.py +270 -0
- statable_gui/transition_editor_direct/edit_dialogs.py +160 -0
- statable_gui/transition_editor_direct/overview_tab.py +173 -0
- statable_gui/transition_editor_direct/palette_widget.py +233 -0
- statable_gui/transition_editor_direct/relations_edit_dialog.py +156 -0
- statable_gui/transition_editor_direct/relations_tab.py +230 -0
- statable_gui/transition_editor_direct/system_global_dialog.py +52 -0
- statable_gui/transition_editor_direct/transition_actions_dialog.py +109 -0
- statable_gui/transition_editor_direct/transitions_tab.py +620 -0
- statable_gui/validation_dialog.py +285 -0
- statable_gui/widgets.py +1315 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# codegen/timer_generator.py
|
|
2
|
+
"""
|
|
3
|
+
Timer variable generation module (fully data-driven version)
|
|
4
|
+
|
|
5
|
+
Version: 2.2 (2026-09-20 / MISRA 10.4 fix)
|
|
6
|
+
- Fix (MISRA C:2012 Rule 10.4): the derived-timer update expression
|
|
7
|
+
ctx->data.<derived> = (uint8_t)(ctx->data.<base> / 10);
|
|
8
|
+
mixed an unsigned `uint32_t` (base) with a signed integer literal
|
|
9
|
+
`10` (multiplier). Both operands of `/` must have the same
|
|
10
|
+
essential type category. The multiplier is now emitted as an
|
|
11
|
+
unsigned literal `10U`, satisfying 10.4.
|
|
12
|
+
|
|
13
|
+
[v1.5 fix]
|
|
14
|
+
- generate_struct: TimerVariables_t removed
|
|
15
|
+
Timer variables are already expanded into SystemData_t via
|
|
16
|
+
add_timer_variables(), so the unused typedef is no longer emitted.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import sys
|
|
20
|
+
import os
|
|
21
|
+
import logging
|
|
22
|
+
from typing import Dict, Callable, List, Any
|
|
23
|
+
|
|
24
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
25
|
+
|
|
26
|
+
from statable.global_defs import TimerBaseDef, TimerDerivedDef, GlobalDefinitions
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
from .type_mapper import CTypeMapper
|
|
30
|
+
from .naming_convention import CNamingConvention
|
|
31
|
+
from .code_templates import CodeTemplates
|
|
32
|
+
except ImportError:
|
|
33
|
+
from type_mapper import CTypeMapper
|
|
34
|
+
from naming_convention import CNamingConvention
|
|
35
|
+
from code_templates import CodeTemplates
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TimerGenerator:
|
|
41
|
+
"""Timer variable generation class (fully data-driven)"""
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
self.mapper = CTypeMapper()
|
|
45
|
+
self.naming = CNamingConvention()
|
|
46
|
+
self.templates = CodeTemplates()
|
|
47
|
+
self.strings = self.templates.STRINGS
|
|
48
|
+
self.formats = self.templates.FORMATS
|
|
49
|
+
|
|
50
|
+
self.timer_struct_steps = [
|
|
51
|
+
{'action': 'comment'},
|
|
52
|
+
{'action': 'struct_start'},
|
|
53
|
+
{'action': 'members'},
|
|
54
|
+
{'action': 'struct_end'},
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
self.init_steps = [
|
|
58
|
+
{'action': 'comment'},
|
|
59
|
+
{'action': 'signature'},
|
|
60
|
+
{'action': 'open'},
|
|
61
|
+
{'action': 'null_check'},
|
|
62
|
+
{'action': 'entry_log'},
|
|
63
|
+
{'action': 'init_base_timers'},
|
|
64
|
+
{'action': 'init_derived_timers'},
|
|
65
|
+
{'action': 'exit_log'},
|
|
66
|
+
{'action': 'close'},
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
self.update_steps = [
|
|
70
|
+
{'action': 'comment'},
|
|
71
|
+
{'action': 'signature'},
|
|
72
|
+
{'action': 'open'},
|
|
73
|
+
{'action': 'null_check'},
|
|
74
|
+
{'action': 'update_derived_timers'},
|
|
75
|
+
{'action': 'close'},
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
self.struct_executors: Dict[str, Callable] = {
|
|
79
|
+
'comment': self._execute_struct_comment,
|
|
80
|
+
'struct_start': self._execute_struct_start,
|
|
81
|
+
'members': self._execute_members,
|
|
82
|
+
'struct_end': self._execute_struct_end,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
self.init_executors: Dict[str, Callable] = {
|
|
86
|
+
'comment': self._execute_init_comment,
|
|
87
|
+
'signature': self._execute_init_signature,
|
|
88
|
+
'open': self._execute_open,
|
|
89
|
+
'null_check': self._execute_null_check,
|
|
90
|
+
'entry_log': self._execute_entry_log,
|
|
91
|
+
'init_base_timers': self._execute_init_base_timers,
|
|
92
|
+
'init_derived_timers': self._execute_init_derived_timers,
|
|
93
|
+
'exit_log': self._execute_exit_log,
|
|
94
|
+
'close': self._execute_close,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
self.update_executors: Dict[str, Callable] = {
|
|
98
|
+
'comment': self._execute_update_comment,
|
|
99
|
+
'signature': self._execute_update_signature,
|
|
100
|
+
'open': self._execute_open,
|
|
101
|
+
'null_check': self._execute_null_check,
|
|
102
|
+
'update_derived_timers': self._execute_update_derived_timers,
|
|
103
|
+
'close': self._execute_close,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
def _log_debug(self, message, level='debug'):
|
|
107
|
+
log_func = getattr(logger, level, logger.debug)
|
|
108
|
+
log_func(message)
|
|
109
|
+
|
|
110
|
+
def _get_all_timers(self, global_defs):
|
|
111
|
+
timers = []
|
|
112
|
+
timer_base = getattr(global_defs, 'timer_base', None)
|
|
113
|
+
if timer_base:
|
|
114
|
+
timers.append(timer_base)
|
|
115
|
+
timers.extend(getattr(global_defs, 'extra_timers', []))
|
|
116
|
+
return timers
|
|
117
|
+
|
|
118
|
+
def _get_all_derived_timers(self, global_defs):
|
|
119
|
+
derived_timers = []
|
|
120
|
+
for timer in self._get_all_timers(global_defs):
|
|
121
|
+
derived_timers.extend(getattr(timer, 'derived', []))
|
|
122
|
+
return derived_timers
|
|
123
|
+
|
|
124
|
+
def _execute_struct_comment(self, step, context):
|
|
125
|
+
return ["/* Timer variable struct */", "/* Manages timer variables used across the system */"]
|
|
126
|
+
|
|
127
|
+
def _execute_struct_start(self, step, context):
|
|
128
|
+
return ["typedef struct {"]
|
|
129
|
+
|
|
130
|
+
def _execute_members(self, step, context):
|
|
131
|
+
global_defs = context.get('global_defs')
|
|
132
|
+
indent = self.strings['indent_1']
|
|
133
|
+
lines = []
|
|
134
|
+
|
|
135
|
+
for timer in self._get_all_timers(global_defs):
|
|
136
|
+
var_name = self.naming.sanitize_identifier(getattr(timer, 'variable_name', 'unknown'))
|
|
137
|
+
data_type = self.mapper.map_type(getattr(timer, 'data_type', 'uint32_t'))
|
|
138
|
+
unit = getattr(timer, 'unit', '')
|
|
139
|
+
comment = f"/* {unit} */" if unit else ""
|
|
140
|
+
lines.append(f"{indent}{data_type} {var_name}; {comment}".rstrip())
|
|
141
|
+
|
|
142
|
+
for derived in self._get_all_derived_timers(global_defs):
|
|
143
|
+
var_name = self.naming.sanitize_identifier(getattr(derived, 'variable_name', 'unknown'))
|
|
144
|
+
data_type = self.mapper.map_type(getattr(derived, 'data_type', 'uint8_t'))
|
|
145
|
+
period_name = getattr(derived, 'period_name', '')
|
|
146
|
+
comment = f"/* {period_name} */" if period_name else ""
|
|
147
|
+
lines.append(f"{indent}{data_type} {var_name}; {comment}".rstrip())
|
|
148
|
+
|
|
149
|
+
return lines
|
|
150
|
+
|
|
151
|
+
def _execute_struct_end(self, step, context):
|
|
152
|
+
return ["} TimerVariables_t;"]
|
|
153
|
+
|
|
154
|
+
def _execute_init_comment(self, step, context):
|
|
155
|
+
return [
|
|
156
|
+
"/**",
|
|
157
|
+
" * @brief Timer variable initialization",
|
|
158
|
+
" * @param ctx System context pointer",
|
|
159
|
+
" */",
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
def _execute_init_signature(self, step, context):
|
|
163
|
+
return ["void Timer_Init(SystemContext_t *ctx)"]
|
|
164
|
+
|
|
165
|
+
def _execute_open(self, step, context):
|
|
166
|
+
return ["{"]
|
|
167
|
+
|
|
168
|
+
def _execute_close(self, step, context):
|
|
169
|
+
return ["}"]
|
|
170
|
+
|
|
171
|
+
def _execute_null_check(self, step, context):
|
|
172
|
+
indent = self.strings['indent_1']
|
|
173
|
+
return [
|
|
174
|
+
f"{indent}if (ctx == NULL) {{",
|
|
175
|
+
f"{indent}{indent}return;",
|
|
176
|
+
f"{indent}}}",
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
def _execute_entry_log(self, step, context):
|
|
180
|
+
indent = self.strings['indent_1']
|
|
181
|
+
return [f"{indent}{self.strings['log_debug']}(\"Enter Timer_Init\");", ""]
|
|
182
|
+
|
|
183
|
+
def _execute_init_base_timers(self, step, context):
|
|
184
|
+
global_defs = context.get('global_defs')
|
|
185
|
+
indent = self.strings['indent_1']
|
|
186
|
+
lines = []
|
|
187
|
+
|
|
188
|
+
for timer in self._get_all_timers(global_defs):
|
|
189
|
+
var_name = self.naming.sanitize_identifier(getattr(timer, 'variable_name', 'unknown'))
|
|
190
|
+
lines.append(f"{indent}ctx->data.{var_name} = 0;")
|
|
191
|
+
|
|
192
|
+
return lines
|
|
193
|
+
|
|
194
|
+
def _execute_init_derived_timers(self, step, context):
|
|
195
|
+
global_defs = context.get('global_defs')
|
|
196
|
+
indent = self.strings['indent_1']
|
|
197
|
+
lines = []
|
|
198
|
+
|
|
199
|
+
for derived in self._get_all_derived_timers(global_defs):
|
|
200
|
+
var_name = self.naming.sanitize_identifier(getattr(derived, 'variable_name', 'unknown'))
|
|
201
|
+
lines.append(f"{indent}ctx->data.{var_name} = 0;")
|
|
202
|
+
|
|
203
|
+
return lines
|
|
204
|
+
|
|
205
|
+
def _execute_exit_log(self, step, context):
|
|
206
|
+
indent = self.strings['indent_1']
|
|
207
|
+
return ["", f"{indent}{self.strings['log_debug']}(\"Exit Timer_Init\");"]
|
|
208
|
+
|
|
209
|
+
def _execute_update_comment(self, step, context):
|
|
210
|
+
return [
|
|
211
|
+
"/**",
|
|
212
|
+
" * @brief Timer update processing",
|
|
213
|
+
" * @param ctx System context pointer",
|
|
214
|
+
" */",
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
def _execute_update_signature(self, step, context):
|
|
218
|
+
return ["void Timer_Update(SystemContext_t *ctx)"]
|
|
219
|
+
|
|
220
|
+
def _execute_update_derived_timers(self, step, context):
|
|
221
|
+
"""Generate derived-timer update expressions.
|
|
222
|
+
|
|
223
|
+
[v2.2 / MISRA 10.4 fix]
|
|
224
|
+
The multiplier is emitted as an unsigned literal (`10U`)
|
|
225
|
+
because the base timer variable is `uint32_t` and the `/`
|
|
226
|
+
operator requires both operands to have the same essential
|
|
227
|
+
type category.
|
|
228
|
+
|
|
229
|
+
Before: ctx->data.<d> = (uint8_t)(ctx->data.<b> / 10);
|
|
230
|
+
After: ctx->data.<d> = (uint8_t)(ctx->data.<b> / 10U);
|
|
231
|
+
"""
|
|
232
|
+
global_defs = context.get('global_defs')
|
|
233
|
+
indent = self.strings['indent_1']
|
|
234
|
+
lines = []
|
|
235
|
+
|
|
236
|
+
for timer in self._get_all_timers(global_defs):
|
|
237
|
+
base_var = self.naming.sanitize_identifier(
|
|
238
|
+
getattr(timer, 'variable_name', 'unknown'))
|
|
239
|
+
|
|
240
|
+
for derived in getattr(timer, 'derived', []):
|
|
241
|
+
derived_var = self.naming.sanitize_identifier(
|
|
242
|
+
getattr(derived, 'variable_name', 'unknown'))
|
|
243
|
+
multiplier = getattr(derived, 'multiplier', 1)
|
|
244
|
+
data_type = self.mapper.map_type(
|
|
245
|
+
getattr(derived, 'data_type', 'uint8_t'))
|
|
246
|
+
|
|
247
|
+
if multiplier > 0:
|
|
248
|
+
# [MISRA 10.4] unsigned literal
|
|
249
|
+
lines.append(
|
|
250
|
+
f"{indent}ctx->data.{derived_var} = "
|
|
251
|
+
f"({data_type})(ctx->data.{base_var} / "
|
|
252
|
+
f"{multiplier}U);"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
return lines
|
|
256
|
+
|
|
257
|
+
def generate_struct(self, global_defs: GlobalDefinitions) -> str:
|
|
258
|
+
"""
|
|
259
|
+
Generate timer variable struct.
|
|
260
|
+
|
|
261
|
+
[v1.5 change]
|
|
262
|
+
Timer variables are already expanded into SystemData_t;
|
|
263
|
+
TimerVariables_t is no longer used (v1.5 sec 9.6 #83).
|
|
264
|
+
The function is retained for backward compatibility but
|
|
265
|
+
now returns an empty string.
|
|
266
|
+
"""
|
|
267
|
+
self._log_debug(
|
|
268
|
+
"generate_struct: TimerVariables_t is unused, returning empty"
|
|
269
|
+
)
|
|
270
|
+
return ""
|
|
271
|
+
|
|
272
|
+
def generate_init_function(self, global_defs: GlobalDefinitions) -> str:
|
|
273
|
+
self._log_debug("Generating timer init function")
|
|
274
|
+
context = {'global_defs': global_defs}
|
|
275
|
+
lines = []
|
|
276
|
+
for step in self.init_steps:
|
|
277
|
+
executor = self.init_executors.get(step['action'])
|
|
278
|
+
if executor:
|
|
279
|
+
lines.extend(executor(step, context))
|
|
280
|
+
return '\n'.join(lines)
|
|
281
|
+
|
|
282
|
+
def generate_update_function(self, global_defs: GlobalDefinitions) -> str:
|
|
283
|
+
self._log_debug("Generating timer update function")
|
|
284
|
+
context = {'global_defs': global_defs}
|
|
285
|
+
lines = []
|
|
286
|
+
for step in self.update_steps:
|
|
287
|
+
executor = self.update_executors.get(step['action'])
|
|
288
|
+
if executor:
|
|
289
|
+
lines.extend(executor(step, context))
|
|
290
|
+
return '\n'.join(lines)
|
|
291
|
+
|
|
292
|
+
def generate_all(self, global_defs: GlobalDefinitions) -> str:
|
|
293
|
+
lines = []
|
|
294
|
+
lines.append(self.generate_struct(global_defs))
|
|
295
|
+
lines.append("")
|
|
296
|
+
lines.append(self.generate_init_function(global_defs))
|
|
297
|
+
lines.append("")
|
|
298
|
+
lines.append(self.generate_update_function(global_defs))
|
|
299
|
+
return '\n'.join(lines)
|