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,282 @@
|
|
|
1
|
+
# codegen/osal_generator.py
|
|
2
|
+
"""
|
|
3
|
+
OSAL (OS abstraction layer) code generation module (template-split version)
|
|
4
|
+
|
|
5
|
+
Version: 2.5 (2026-09-22 / ARM toolchain portability fix)
|
|
6
|
+
- The generated osal.c now includes <stddef.h> so that NULL is
|
|
7
|
+
defined. Required by ARM GNU Toolchain 14.x (strict C99).
|
|
8
|
+
|
|
9
|
+
Version: 2.2 (2026-09-20 / MISRA 17.3 fix)
|
|
10
|
+
- The generated osal.c now includes its own header "osal.h" first.
|
|
11
|
+
MISRA C:2012 Rule 17.3 requires that a function be declared before
|
|
12
|
+
its definition; including osal.h in osal.c satisfies this without
|
|
13
|
+
changing the function signatures.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import sys
|
|
17
|
+
import os
|
|
18
|
+
import logging
|
|
19
|
+
from typing import Dict, Callable, List, Any
|
|
20
|
+
|
|
21
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from .code_templates import CodeTemplates
|
|
25
|
+
from .naming_convention import CNamingConvention
|
|
26
|
+
except ImportError:
|
|
27
|
+
from code_templates import CodeTemplates
|
|
28
|
+
from naming_convention import CNamingConvention
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class OSALGenerator:
|
|
34
|
+
"""OSAL code generation class (template-split version)"""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.templates = CodeTemplates()
|
|
38
|
+
self.strings = self.templates.STRINGS
|
|
39
|
+
self.formats = self.templates.FORMATS
|
|
40
|
+
self.osal_templates = self.templates.OSAL
|
|
41
|
+
self.naming = CNamingConvention()
|
|
42
|
+
|
|
43
|
+
# Header generation step
|
|
44
|
+
self.header_steps = [
|
|
45
|
+
{'action': 'file_comment'},
|
|
46
|
+
{'action': 'include_guard_start'},
|
|
47
|
+
{'action': 'includes'},
|
|
48
|
+
{'action': 'type_defs'},
|
|
49
|
+
{'action': 'mutex_decls'},
|
|
50
|
+
{'action': 'semaphore_decls'},
|
|
51
|
+
{'action': 'queue_decls'},
|
|
52
|
+
{'action': 'critical_decls'},
|
|
53
|
+
{'action': 'include_guard_end'},
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
# Source generation step
|
|
57
|
+
self.source_steps = [
|
|
58
|
+
{'action': 'file_comment'},
|
|
59
|
+
{'action': 'includes'},
|
|
60
|
+
{'action': 'mutex_impl'},
|
|
61
|
+
{'action': 'semaphore_impl'},
|
|
62
|
+
{'action': 'queue_impl'},
|
|
63
|
+
{'action': 'critical_impl'},
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
# Step execution dictionary
|
|
67
|
+
self.step_executors: Dict[str, Callable] = {
|
|
68
|
+
'file_comment': self._execute_file_comment,
|
|
69
|
+
'include_guard_start': self._execute_include_guard_start,
|
|
70
|
+
'includes': self._execute_includes,
|
|
71
|
+
'type_defs': self._execute_type_defs,
|
|
72
|
+
'mutex_decls': self._execute_mutex_decls,
|
|
73
|
+
'semaphore_decls': self._execute_semaphore_decls,
|
|
74
|
+
'queue_decls': self._execute_queue_decls,
|
|
75
|
+
'critical_decls': self._execute_critical_decls,
|
|
76
|
+
'include_guard_end': self._execute_include_guard_end,
|
|
77
|
+
'mutex_impl': self._execute_mutex_impl,
|
|
78
|
+
'semaphore_impl': self._execute_semaphore_impl,
|
|
79
|
+
'queue_impl': self._execute_queue_impl,
|
|
80
|
+
'critical_impl': self._execute_critical_impl,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
def _log_debug(self, message, level='debug'):
|
|
84
|
+
log_func = getattr(logger, level, logger.debug)
|
|
85
|
+
log_func(message)
|
|
86
|
+
|
|
87
|
+
# ===== Step execution function =====
|
|
88
|
+
def _execute_file_comment(self, step, context):
|
|
89
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
90
|
+
os_info = self.osal_templates['os_types'].get(os_type, {})
|
|
91
|
+
filename = context.get('filename', 'osal.h')
|
|
92
|
+
os_name = os_info.get('name', 'NonRTOS')
|
|
93
|
+
|
|
94
|
+
template = self.osal_templates['header']['file_comment']
|
|
95
|
+
return [template.format(filename=filename, os_name=os_name)]
|
|
96
|
+
|
|
97
|
+
def _execute_include_guard_start(self, step, context):
|
|
98
|
+
guard_name = context.get('guard_name', 'OSAL_H')
|
|
99
|
+
return [self.osal_templates['header']['include_guard_start'].format(guard_name=guard_name)]
|
|
100
|
+
|
|
101
|
+
def _execute_includes(self, step, context):
|
|
102
|
+
"""Emit include section.
|
|
103
|
+
|
|
104
|
+
[v2.2 / MISRA 17.3]
|
|
105
|
+
- Header (osal.h): only <stdint.h> / <stdbool.h> are needed.
|
|
106
|
+
- Source (osal.c): must include its own header "osal.h" FIRST,
|
|
107
|
+
so all OSAL function prototypes are visible before the
|
|
108
|
+
definitions (MISRA C:2012 Rule 17.3).
|
|
109
|
+
|
|
110
|
+
[v2.5 / ARM portability]
|
|
111
|
+
- Source additionally includes <stddef.h> to make NULL
|
|
112
|
+
available. Required by ARM GNU Toolchain 14.x, which
|
|
113
|
+
enforces C99 strictly. MinGW gcc accepts the code without
|
|
114
|
+
it, but the ARM build fails.
|
|
115
|
+
"""
|
|
116
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
117
|
+
is_header = 'guard_name' in context
|
|
118
|
+
|
|
119
|
+
lines: List[str] = []
|
|
120
|
+
|
|
121
|
+
if is_header:
|
|
122
|
+
lines.extend(["#include <stdint.h>", "#include <stdbool.h>", ""])
|
|
123
|
+
else:
|
|
124
|
+
# Source: include own header first (MISRA 17.3)
|
|
125
|
+
os_info = self.osal_templates['os_types'].get(os_type, {})
|
|
126
|
+
header_name = os_info.get('header', 'osal.h')
|
|
127
|
+
lines.append(f'#include "{header_name}"')
|
|
128
|
+
# [v2.5] <stddef.h> provides NULL. Required by ARM
|
|
129
|
+
# GNU Toolchain 14.x (strict C99).
|
|
130
|
+
lines.append("#include <stddef.h>")
|
|
131
|
+
lines.append("")
|
|
132
|
+
|
|
133
|
+
if os_type == 'freertos':
|
|
134
|
+
lines.append(self.osal_templates['header']['freertos_includes'])
|
|
135
|
+
lines.append("")
|
|
136
|
+
elif os_type == 'threadx':
|
|
137
|
+
lines.append(self.osal_templates['header']['threadx_includes'])
|
|
138
|
+
lines.append("")
|
|
139
|
+
|
|
140
|
+
return lines
|
|
141
|
+
|
|
142
|
+
def _execute_type_defs(self, step, context):
|
|
143
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
144
|
+
lines = []
|
|
145
|
+
|
|
146
|
+
lines.append(self.osal_templates['header']['type_defs_comment'])
|
|
147
|
+
lines.append(self.osal_templates['header']['status_enum'])
|
|
148
|
+
lines.append("")
|
|
149
|
+
|
|
150
|
+
if os_type == 'non_rtos':
|
|
151
|
+
lines.append(self.osal_templates['header']['mutex_type_nonrtos'])
|
|
152
|
+
lines.append("")
|
|
153
|
+
lines.append(self.osal_templates['header']['semaphore_type_nonrtos'])
|
|
154
|
+
lines.append("")
|
|
155
|
+
lines.append(self.osal_templates['header']['queue_type_nonrtos'])
|
|
156
|
+
lines.append("")
|
|
157
|
+
|
|
158
|
+
return lines
|
|
159
|
+
|
|
160
|
+
def _execute_mutex_decls(self, step, context):
|
|
161
|
+
return [self.osal_templates['header']['mutex_decls'], ""]
|
|
162
|
+
|
|
163
|
+
def _execute_semaphore_decls(self, step, context):
|
|
164
|
+
return [self.osal_templates['header']['semaphore_decls'], ""]
|
|
165
|
+
|
|
166
|
+
def _execute_queue_decls(self, step, context):
|
|
167
|
+
return [self.osal_templates['header']['queue_decls'], ""]
|
|
168
|
+
|
|
169
|
+
def _execute_critical_decls(self, step, context):
|
|
170
|
+
return [self.osal_templates['header']['critical_decls'], ""]
|
|
171
|
+
|
|
172
|
+
def _execute_include_guard_end(self, step, context):
|
|
173
|
+
guard_name = context.get('guard_name', 'OSAL_H')
|
|
174
|
+
return [self.osal_templates['header']['include_guard_end'].format(guard_name=guard_name)]
|
|
175
|
+
|
|
176
|
+
def _execute_mutex_impl(self, step, context):
|
|
177
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
178
|
+
lines = []
|
|
179
|
+
|
|
180
|
+
if os_type == 'non_rtos':
|
|
181
|
+
lines.append(self.osal_templates['source']['mutex_section_comment'])
|
|
182
|
+
lines.append(self.osal_templates['source']['mutex_create_nonrtos'])
|
|
183
|
+
lines.append("")
|
|
184
|
+
lines.append(self.osal_templates['source']['mutex_lock_nonrtos'])
|
|
185
|
+
lines.append("")
|
|
186
|
+
lines.append(self.osal_templates['source']['mutex_unlock_nonrtos'])
|
|
187
|
+
lines.append("")
|
|
188
|
+
|
|
189
|
+
return lines
|
|
190
|
+
|
|
191
|
+
def _execute_semaphore_impl(self, step, context):
|
|
192
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
193
|
+
lines = []
|
|
194
|
+
|
|
195
|
+
if os_type == 'non_rtos':
|
|
196
|
+
lines.append(self.osal_templates['source']['semaphore_section_comment'])
|
|
197
|
+
lines.append(self.osal_templates['source']['semaphore_create_nonrtos'])
|
|
198
|
+
lines.append("")
|
|
199
|
+
lines.append(self.osal_templates['source']['semaphore_take_nonrtos'])
|
|
200
|
+
lines.append("")
|
|
201
|
+
lines.append(self.osal_templates['source']['semaphore_give_nonrtos'])
|
|
202
|
+
lines.append("")
|
|
203
|
+
|
|
204
|
+
return lines
|
|
205
|
+
|
|
206
|
+
def _execute_queue_impl(self, step, context):
|
|
207
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
208
|
+
lines = []
|
|
209
|
+
|
|
210
|
+
if os_type == 'non_rtos':
|
|
211
|
+
lines.append(self.osal_templates['source']['queue_section_comment'])
|
|
212
|
+
lines.append(self.osal_templates['source']['queue_create_nonrtos'])
|
|
213
|
+
lines.append("")
|
|
214
|
+
lines.append(self.osal_templates['source']['queue_send_nonrtos'])
|
|
215
|
+
lines.append("")
|
|
216
|
+
lines.append(self.osal_templates['source']['queue_receive_nonrtos'])
|
|
217
|
+
lines.append("")
|
|
218
|
+
|
|
219
|
+
return lines
|
|
220
|
+
|
|
221
|
+
def _execute_critical_impl(self, step, context):
|
|
222
|
+
os_type = context.get('os_type', 'non_rtos')
|
|
223
|
+
lines = []
|
|
224
|
+
|
|
225
|
+
if os_type == 'non_rtos':
|
|
226
|
+
lines.append(self.osal_templates['source']['critical_section_comment'])
|
|
227
|
+
lines.append(self.osal_templates['source']['critical_enter_nonrtos'])
|
|
228
|
+
lines.append("")
|
|
229
|
+
lines.append(self.osal_templates['source']['critical_exit_nonrtos'])
|
|
230
|
+
lines.append("")
|
|
231
|
+
|
|
232
|
+
return lines
|
|
233
|
+
|
|
234
|
+
# ===== Public methods =====
|
|
235
|
+
def generate_header(self, os_type='non_rtos') -> str:
|
|
236
|
+
"""OSAL header generation"""
|
|
237
|
+
self._log_debug(f"Generating OSAL header for: {os_type}")
|
|
238
|
+
|
|
239
|
+
os_info = self.osal_templates['os_types'].get(os_type, {})
|
|
240
|
+
context = {
|
|
241
|
+
'filename': os_info.get('header', 'osal.h'),
|
|
242
|
+
'os_type': os_type,
|
|
243
|
+
'guard_name': 'OSAL_H',
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
lines = []
|
|
247
|
+
for step in self.header_steps:
|
|
248
|
+
executor = self.step_executors.get(step['action'])
|
|
249
|
+
if executor:
|
|
250
|
+
lines.extend(executor(step, context))
|
|
251
|
+
|
|
252
|
+
return '\n'.join(lines)
|
|
253
|
+
|
|
254
|
+
def generate_source(self, os_type='non_rtos') -> str:
|
|
255
|
+
"""OSAL source generation"""
|
|
256
|
+
self._log_debug(f"Generating OSAL source for: {os_type}")
|
|
257
|
+
|
|
258
|
+
os_info = self.osal_templates['os_types'].get(os_type, {})
|
|
259
|
+
context = {
|
|
260
|
+
'filename': os_info.get('source', 'osal.c'),
|
|
261
|
+
'os_type': os_type,
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
lines = []
|
|
265
|
+
for step in self.source_steps:
|
|
266
|
+
executor = self.step_executors.get(step['action'])
|
|
267
|
+
if executor:
|
|
268
|
+
lines.extend(executor(step, context))
|
|
269
|
+
|
|
270
|
+
return '\n'.join(lines)
|
|
271
|
+
|
|
272
|
+
def generate_all(self, os_type='non_rtos') -> Dict[str, str]:
|
|
273
|
+
"""Generate all OSAL code"""
|
|
274
|
+
os_info = self.osal_templates['os_types'].get(os_type, {})
|
|
275
|
+
return {
|
|
276
|
+
os_info.get('header', 'osal.h'): self.generate_header(os_type),
|
|
277
|
+
os_info.get('source', 'osal.c'): self.generate_source(os_type),
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
def get_available_os_types(self) -> Dict[str, str]:
|
|
281
|
+
"""Get available OS types"""
|
|
282
|
+
return {key: value['description'] for key, value in self.osal_templates['os_types'].items()}
|