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,509 @@
|
|
|
1
|
+
# codegen/code_templates.py
|
|
2
|
+
"""
|
|
3
|
+
Code generation template definitions (multi-layer state machine / ISR support)
|
|
4
|
+
|
|
5
|
+
Version: 2.2.5 (2026-09-20 / gcc compile fix)
|
|
6
|
+
- Fix: SUPER_LOOP_TEMPLATES['run_block'] now wraps each layer's
|
|
7
|
+
event processing in its own `{ ... }` scope. Previously all layers
|
|
8
|
+
emitted `EVENT_<Layer>_t evt = ...` at the same function scope,
|
|
9
|
+
causing "conflicting types for 'evt'" errors under gcc when the
|
|
10
|
+
per-layer EVENT types differ.
|
|
11
|
+
The scoped block keeps the variable name `evt` unchanged, so the
|
|
12
|
+
generated code remains readable and the diff is minimal.
|
|
13
|
+
|
|
14
|
+
Version: 2.2.4 (2026-09-20 / MISRA 12.1 + 10.4 fixes)
|
|
15
|
+
Version: 2.2.3 (2026-09-20 / MISRA 17.3 fix)
|
|
16
|
+
Version: 2.2.2 (2026-09-19)
|
|
17
|
+
Version: 2.2.1
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CodeTemplates:
|
|
22
|
+
"""Code generation template dictionary"""
|
|
23
|
+
|
|
24
|
+
# ===== Basic string definitions =====
|
|
25
|
+
STRINGS = {
|
|
26
|
+
# --- Fixed section line (VALID C block comment) ---
|
|
27
|
+
'section_line_start': '/*==============================================================',
|
|
28
|
+
'section_line_end': ' *==============================================================*/',
|
|
29
|
+
|
|
30
|
+
'indent_1': ' ',
|
|
31
|
+
'indent_2': ' ',
|
|
32
|
+
'indent_3': ' ',
|
|
33
|
+
'newline': '\n',
|
|
34
|
+
'blank_line': '',
|
|
35
|
+
'typedef': 'typedef',
|
|
36
|
+
'struct': 'struct',
|
|
37
|
+
'enum': 'enum',
|
|
38
|
+
'include': '#include',
|
|
39
|
+
'define': '#define',
|
|
40
|
+
'ifndef': '#ifndef',
|
|
41
|
+
'endif': '#endif',
|
|
42
|
+
'return': 'return',
|
|
43
|
+
'void': 'void',
|
|
44
|
+
'static': 'static',
|
|
45
|
+
'const': 'const',
|
|
46
|
+
'switch': 'switch',
|
|
47
|
+
'case': 'case',
|
|
48
|
+
'break': 'break',
|
|
49
|
+
'default': 'default',
|
|
50
|
+
'if': 'if',
|
|
51
|
+
'else': 'else',
|
|
52
|
+
'todo': 'TODO: implement the code here',
|
|
53
|
+
'unused_arg': 'suppress unused argument warning',
|
|
54
|
+
'auto_generated': 'Code auto-generated by StaTable',
|
|
55
|
+
'no_edit': 'Manual editing is not recommended',
|
|
56
|
+
'edit_in_statable': 'To modify, use StaTable',
|
|
57
|
+
'log_debug': 'LOG_DEBUG',
|
|
58
|
+
'log_info': 'LOG_INFO',
|
|
59
|
+
'log_warning': 'LOG_WARNING',
|
|
60
|
+
'log_error': 'LOG_ERROR',
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
SECTION_HEADERS = {
|
|
64
|
+
'include': 'Include files',
|
|
65
|
+
'type_defs': 'Type definitions',
|
|
66
|
+
'custom_types': 'User-defined types',
|
|
67
|
+
'system_structs': 'System structs',
|
|
68
|
+
'transition_context': 'Transition context',
|
|
69
|
+
'pending_event': 'Pending event control',
|
|
70
|
+
'layer_types': 'Layer-specific type definitions',
|
|
71
|
+
'function_decls': 'Function declarations',
|
|
72
|
+
'role_functions': 'Role function declarations',
|
|
73
|
+
'role_impl': 'Role function implementations',
|
|
74
|
+
'transition_table': 'State transition table',
|
|
75
|
+
'transition_cells': 'Per-cell transition functions',
|
|
76
|
+
'transition_func': 'State transition functions',
|
|
77
|
+
'get_next_event': 'Event retrieval function',
|
|
78
|
+
'init_func': 'Initialization function',
|
|
79
|
+
'var_macros': 'Variable access macros',
|
|
80
|
+
'super_include': 'Super include',
|
|
81
|
+
'mutex_impl': 'Mutex implementation',
|
|
82
|
+
'semaphore_impl': 'Semaphore implementation',
|
|
83
|
+
'queue_impl': 'Queue implementation',
|
|
84
|
+
'critical_section_impl': 'Critical section implementation',
|
|
85
|
+
'cell_actions': 'Cell actions (transition-independent)',
|
|
86
|
+
'cell_transitions': 'Cell transitions (ordered)',
|
|
87
|
+
'state_entry_exit': 'State entry / exit calls',
|
|
88
|
+
'common_function_decls': 'Common function declarations',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
STRUCT_COMMENTS = {
|
|
92
|
+
'system_data': {'title': 'Global variable struct', 'description': 'Manages variables shared across the system'},
|
|
93
|
+
'event_flags': {'title': 'Event flag struct', 'description': 'Manages flags indicating event occurrences'},
|
|
94
|
+
'system_context': {'title': 'System context struct', 'description': 'Integrates global variables and event flags'},
|
|
95
|
+
'transition_cell': {'title': 'Transition cell struct', 'description': 'Represents one cell of the state transition table'},
|
|
96
|
+
'transition_context': {'title': 'Transition context struct', 'description': 'Holds source state and event'},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
ENUM_COMMENTS = {
|
|
100
|
+
'state': {'title': 'State definitions', 'description': 'Enum representing states of the state machine'},
|
|
101
|
+
'event': {'title': 'Event definitions', 'description': 'Enum of events that trigger state transitions'},
|
|
102
|
+
'flag': {'title': 'Event flag definitions', 'description': 'Enum representing event flag identifiers'},
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
TYPE_NAMES = {
|
|
106
|
+
'state': 'STATE_t',
|
|
107
|
+
'event': 'EVENT_t',
|
|
108
|
+
'flag': 'FLAG_t',
|
|
109
|
+
'system_data': 'SystemData_t',
|
|
110
|
+
'event_flags': 'EventFlags_t',
|
|
111
|
+
'system_context': 'SystemContext_t',
|
|
112
|
+
'transition_cell': 'TransitionCell_t',
|
|
113
|
+
'transition_table': 'transition_matrix',
|
|
114
|
+
'layer_state_prefix': 'STATE_',
|
|
115
|
+
'layer_event_prefix': 'EVENT_',
|
|
116
|
+
'layer_transition_context_prefix': 'TransitionContext_',
|
|
117
|
+
'layer_process_prefix': 'StateMachine_Process_',
|
|
118
|
+
'layer_get_next_event_prefix': 'StateMachine_GetNextEvent_',
|
|
119
|
+
'layer_role_func_prefix': 'RoleFunc_',
|
|
120
|
+
'layer_transition_func_prefix': 'transition_',
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
FUNCTION_NAMES = {
|
|
124
|
+
'state_machine_process': 'StateMachine_Process',
|
|
125
|
+
'system_context_init': 'SystemContext_Init',
|
|
126
|
+
'role_func_prefix': 'RoleFunc',
|
|
127
|
+
'action_prefix': 'Action',
|
|
128
|
+
'condition_prefix': 'Condition',
|
|
129
|
+
'get_next_event_prefix': 'StateMachine_GetNextEvent',
|
|
130
|
+
'layer_process_prefix': 'StateMachine_Process_',
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
MACRO_NAMES = {
|
|
134
|
+
'data_prefix': 'DATA_',
|
|
135
|
+
'flag_prefix': 'FLAG_',
|
|
136
|
+
'max_suffix': '_MAX',
|
|
137
|
+
'fire_event': 'FIRE_EVENT',
|
|
138
|
+
'max_consecutive_pending_events': 'MAX_CONSECUTIVE_PENDING_EVENTS',
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
FORMATS = {
|
|
142
|
+
'section_header': '{start}\n * {title}\n{end}',
|
|
143
|
+
'file_header': '''/**
|
|
144
|
+
* @file {filename}
|
|
145
|
+
* @brief {description}
|
|
146
|
+
*
|
|
147
|
+
* @note {auto_generated}
|
|
148
|
+
* - {no_edit}
|
|
149
|
+
* - {edit_in_statable}
|
|
150
|
+
*
|
|
151
|
+
* @date {date}
|
|
152
|
+
*/''',
|
|
153
|
+
'include_guard_start': '#ifndef {guard_macro}\n#define {guard_macro}\n',
|
|
154
|
+
'include_guard_end': '#endif /* {guard_macro} */',
|
|
155
|
+
'struct_start': 'typedef struct {',
|
|
156
|
+
'struct_end': '} {type_name};',
|
|
157
|
+
'enum_start': 'typedef enum {',
|
|
158
|
+
'enum_end': '} {type_name};',
|
|
159
|
+
'enum_value': '{name} = {value},',
|
|
160
|
+
'enum_value_with_comment': '{name} = {value}, /* {comment} */',
|
|
161
|
+
'enum_max': '{name} /* {comment} */',
|
|
162
|
+
'data_macro': '#define DATA_{var_name}(ctx) ((ctx)->data.{var_name})',
|
|
163
|
+
'flag_macro': '#define FLAG_{flag_name}(ctx) ((ctx)->flags.{flag_name})',
|
|
164
|
+
'group_separator': '/* === {group_name} === */',
|
|
165
|
+
'member_normal': '{indent}{type} {name};',
|
|
166
|
+
'member_array': '{indent}{type} {name}[{size}];',
|
|
167
|
+
'member_bitfield': '{indent}{type} {name} : {width};',
|
|
168
|
+
'inline_comment': '{indent}/* {comment} */',
|
|
169
|
+
'title_comment': '{indent}/* Title: {title} */',
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
LAYER_TEMPLATES = {
|
|
173
|
+
'types_header_comment': '''/**
|
|
174
|
+
* @file statable_types_{layer}.h
|
|
175
|
+
* @brief Type definitions for {layer} layer
|
|
176
|
+
*/''',
|
|
177
|
+
'state_enum_comment': '/* State definitions for {layer} layer */',
|
|
178
|
+
'event_enum_comment': '/* Event definitions for {layer} layer */',
|
|
179
|
+
'transition_context_comment': '/* Transition context for {layer} layer */',
|
|
180
|
+
'transition_context_struct': '''typedef struct {{
|
|
181
|
+
STATE_{layer}_t from_state;
|
|
182
|
+
EVENT_{layer}_t event;
|
|
183
|
+
}} TransitionContext_{layer}_t;''',
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
COMMON_TYPES_TEMPLATES = {
|
|
187
|
+
'system_context': '''typedef struct {{
|
|
188
|
+
SystemData_t data;
|
|
189
|
+
EventFlags_t flags;
|
|
190
|
+
uint16_t pending_event;
|
|
191
|
+
bool pending_event_valid;
|
|
192
|
+
}} SystemContext_t;''',
|
|
193
|
+
'fire_event_macro': '''#define FIRE_EVENT(ctx, evt) do {{ \\
|
|
194
|
+
(ctx)->pending_event = (uint16_t)(evt); \\
|
|
195
|
+
(ctx)->pending_event_valid = true; \\
|
|
196
|
+
}} while(0)''',
|
|
197
|
+
'max_consecutive_pending_events': '''#ifndef MAX_CONSECUTIVE_PENDING_EVENTS
|
|
198
|
+
#define MAX_CONSECUTIVE_PENDING_EVENTS 16
|
|
199
|
+
#endif''',
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
ISR_TEMPLATES = {
|
|
203
|
+
'context_section': ' /* ===== Context reference (auto-generated) ===== */',
|
|
204
|
+
'enter_log_section': ' /* ===== Enter log ===== */',
|
|
205
|
+
'action_section': ' /* ===== Actions (auto-generated) ===== */',
|
|
206
|
+
'user_section': ' /* ===== User code area ===== */',
|
|
207
|
+
'exit_log_section': ' /* ===== Exit log ===== */',
|
|
208
|
+
'context_decl': ' SystemContext_t *ctx = &g_ctx;',
|
|
209
|
+
'context_void': ' (void)ctx;',
|
|
210
|
+
'enter_log': ' LOG_DEBUG("Enter ISR: {name}");',
|
|
211
|
+
'exit_log': ' LOG_DEBUG("Exit ISR: {name}");',
|
|
212
|
+
'user_marker_start': ' /* [[STABLE_USER_CODE_START:{marker}]] */',
|
|
213
|
+
'user_hint': ' /* Write user code here */',
|
|
214
|
+
'user_marker_end': ' /* [[STABLE_USER_CODE_END:{marker}]] */',
|
|
215
|
+
'used_rf_header': ' * @note Used role functions:',
|
|
216
|
+
'used_rf_line': ' * - {ref}',
|
|
217
|
+
'no_action_hint': ' /* (no action defined) */',
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
DEBUG_MESSAGES = {
|
|
221
|
+
'function_entry': 'Enter {func_name}: state={state}, event={event}',
|
|
222
|
+
'function_exit': 'Exit {func_name}: next_state={next_state}',
|
|
223
|
+
'condition_check': 'Check condition: {condition_name}',
|
|
224
|
+
'condition_not_met': 'Condition not met',
|
|
225
|
+
'action_execute': 'Execute action: {action_name}',
|
|
226
|
+
'transition': 'Transition: {from_state} -> {to_state} (event: {event})',
|
|
227
|
+
'no_transition': 'No transition: state={state}, event={event}',
|
|
228
|
+
'null_pointer': 'NULL pointer: {var_name}',
|
|
229
|
+
'out_of_range': 'Out of range: {var_name}={value}, max={max}',
|
|
230
|
+
'pending_event_too_long': 'Pending event chain too long ({count})',
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
OSAL = {
|
|
234
|
+
'os_types': {
|
|
235
|
+
'non_rtos': {'name': 'NonRTOS', 'description': 'No RTOS (bare metal)', 'header': 'osal.h', 'source': 'osal.c'},
|
|
236
|
+
'freertos': {'name': 'FreeRTOS', 'description': 'FreeRTOS', 'header': 'osal_freertos.h', 'source': 'osal_freertos.c'},
|
|
237
|
+
'threadx': {'name': 'ThreadX', 'description': 'Azure RTOS ThreadX', 'header': 'osal_threadx.h', 'source': 'osal_threadx.c'},
|
|
238
|
+
},
|
|
239
|
+
'header': {
|
|
240
|
+
'file_comment': '''/**
|
|
241
|
+
* @file {filename}
|
|
242
|
+
* @brief OSAL (OS Abstraction Layer) - {os_name}
|
|
243
|
+
*/''',
|
|
244
|
+
'include_guard_start': '#ifndef {guard_name}\n#define {guard_name}\n',
|
|
245
|
+
'include_guard_end': '#endif /* {guard_name} */',
|
|
246
|
+
'type_defs_comment': '/* OSAL type definitions */',
|
|
247
|
+
'status_enum': '''typedef enum {
|
|
248
|
+
OSAL_OK = 0,
|
|
249
|
+
OSAL_ERROR,
|
|
250
|
+
OSAL_TIMEOUT,
|
|
251
|
+
OSAL_BUSY,
|
|
252
|
+
} OSAL_Status_t;''',
|
|
253
|
+
'mutex_type_nonrtos': '''typedef struct {
|
|
254
|
+
volatile bool locked;
|
|
255
|
+
} OSAL_Mutex_t;''',
|
|
256
|
+
'semaphore_type_nonrtos': '''typedef struct {
|
|
257
|
+
volatile uint32_t count;
|
|
258
|
+
volatile uint32_t max_count;
|
|
259
|
+
} OSAL_Semaphore_t;''',
|
|
260
|
+
'queue_type_nonrtos': '''typedef struct {
|
|
261
|
+
void *buffer;
|
|
262
|
+
uint32_t size;
|
|
263
|
+
uint32_t item_size;
|
|
264
|
+
volatile uint32_t head;
|
|
265
|
+
volatile uint32_t tail;
|
|
266
|
+
volatile uint32_t count;
|
|
267
|
+
} OSAL_Queue_t;''',
|
|
268
|
+
'mutex_decls': '''OSAL_Status_t OSAL_Mutex_Create(OSAL_Mutex_t *mutex);
|
|
269
|
+
OSAL_Status_t OSAL_Mutex_Lock(OSAL_Mutex_t *mutex, uint32_t timeout_ms);
|
|
270
|
+
OSAL_Status_t OSAL_Mutex_Unlock(OSAL_Mutex_t *mutex);''',
|
|
271
|
+
'semaphore_decls': '''OSAL_Status_t OSAL_Semaphore_Create(OSAL_Semaphore_t *sem, uint32_t max_count, uint32_t initial_count);
|
|
272
|
+
OSAL_Status_t OSAL_Semaphore_Take(OSAL_Semaphore_t *sem, uint32_t timeout_ms);
|
|
273
|
+
OSAL_Status_t OSAL_Semaphore_Give(OSAL_Semaphore_t *sem);''',
|
|
274
|
+
'queue_decls': '''OSAL_Status_t OSAL_Queue_Create(OSAL_Queue_t *queue, void *buffer, uint32_t size, uint32_t item_size);
|
|
275
|
+
OSAL_Status_t OSAL_Queue_Send(OSAL_Queue_t *queue, const void *item, uint32_t timeout_ms);
|
|
276
|
+
OSAL_Status_t OSAL_Queue_Receive(OSAL_Queue_t *queue, void *item, uint32_t timeout_ms);''',
|
|
277
|
+
'critical_decls': '''void OSAL_Critical_Enter(void);
|
|
278
|
+
void OSAL_Critical_Exit(void);''',
|
|
279
|
+
'freertos_includes': '#include "FreeRTOS.h"\n#include "semphr.h"\n#include "queue.h"',
|
|
280
|
+
'threadx_includes': '#include "tx_api.h"',
|
|
281
|
+
},
|
|
282
|
+
'source': {
|
|
283
|
+
'file_comment': '''/**
|
|
284
|
+
* @file {filename}
|
|
285
|
+
* @brief OSAL (OS Abstraction Layer) - {os_name} implementation
|
|
286
|
+
*/''',
|
|
287
|
+
'mutex_section_comment': '/* Mutex implementation */',
|
|
288
|
+
'semaphore_section_comment': '/* Semaphore implementation */',
|
|
289
|
+
'queue_section_comment': '/* Queue implementation */',
|
|
290
|
+
'critical_section_comment': '/* Critical section implementation */',
|
|
291
|
+
'mutex_create_nonrtos': '''OSAL_Status_t OSAL_Mutex_Create(OSAL_Mutex_t *mutex)
|
|
292
|
+
{
|
|
293
|
+
if (mutex == NULL) {
|
|
294
|
+
return OSAL_ERROR;
|
|
295
|
+
}
|
|
296
|
+
mutex->locked = false;
|
|
297
|
+
return OSAL_OK;
|
|
298
|
+
}''',
|
|
299
|
+
'mutex_lock_nonrtos': '''OSAL_Status_t OSAL_Mutex_Lock(OSAL_Mutex_t *mutex, uint32_t timeout_ms)
|
|
300
|
+
{
|
|
301
|
+
(void)timeout_ms;
|
|
302
|
+
if (mutex == NULL) {
|
|
303
|
+
return OSAL_ERROR;
|
|
304
|
+
}
|
|
305
|
+
if (mutex->locked) {
|
|
306
|
+
return OSAL_BUSY;
|
|
307
|
+
}
|
|
308
|
+
mutex->locked = true;
|
|
309
|
+
return OSAL_OK;
|
|
310
|
+
}''',
|
|
311
|
+
'mutex_unlock_nonrtos': '''OSAL_Status_t OSAL_Mutex_Unlock(OSAL_Mutex_t *mutex)
|
|
312
|
+
{
|
|
313
|
+
if (mutex == NULL) {
|
|
314
|
+
return OSAL_ERROR;
|
|
315
|
+
}
|
|
316
|
+
mutex->locked = false;
|
|
317
|
+
return OSAL_OK;
|
|
318
|
+
}''',
|
|
319
|
+
'semaphore_create_nonrtos': '''OSAL_Status_t OSAL_Semaphore_Create(OSAL_Semaphore_t *sem, uint32_t max_count, uint32_t initial_count)
|
|
320
|
+
{
|
|
321
|
+
if (sem == NULL) {
|
|
322
|
+
return OSAL_ERROR;
|
|
323
|
+
}
|
|
324
|
+
sem->max_count = max_count;
|
|
325
|
+
sem->count = initial_count;
|
|
326
|
+
return OSAL_OK;
|
|
327
|
+
}''',
|
|
328
|
+
'semaphore_take_nonrtos': '''OSAL_Status_t OSAL_Semaphore_Take(OSAL_Semaphore_t *sem, uint32_t timeout_ms)
|
|
329
|
+
{
|
|
330
|
+
(void)timeout_ms;
|
|
331
|
+
if (sem == NULL) {
|
|
332
|
+
return OSAL_ERROR;
|
|
333
|
+
}
|
|
334
|
+
if (sem->count == 0U) {
|
|
335
|
+
return OSAL_BUSY;
|
|
336
|
+
}
|
|
337
|
+
sem->count--;
|
|
338
|
+
return OSAL_OK;
|
|
339
|
+
}''',
|
|
340
|
+
'semaphore_give_nonrtos': '''OSAL_Status_t OSAL_Semaphore_Give(OSAL_Semaphore_t *sem)
|
|
341
|
+
{
|
|
342
|
+
if (sem == NULL) {
|
|
343
|
+
return OSAL_ERROR;
|
|
344
|
+
}
|
|
345
|
+
if (sem->count >= sem->max_count) {
|
|
346
|
+
return OSAL_BUSY;
|
|
347
|
+
}
|
|
348
|
+
sem->count++;
|
|
349
|
+
return OSAL_OK;
|
|
350
|
+
}''',
|
|
351
|
+
'queue_create_nonrtos': '''OSAL_Status_t OSAL_Queue_Create(OSAL_Queue_t *queue, void *buffer, uint32_t size, uint32_t item_size)
|
|
352
|
+
{
|
|
353
|
+
if ((queue == NULL) || (buffer == NULL)) {
|
|
354
|
+
return OSAL_ERROR;
|
|
355
|
+
}
|
|
356
|
+
queue->buffer = buffer;
|
|
357
|
+
queue->size = size;
|
|
358
|
+
queue->item_size = item_size;
|
|
359
|
+
queue->head = 0U;
|
|
360
|
+
queue->tail = 0U;
|
|
361
|
+
queue->count = 0U;
|
|
362
|
+
return OSAL_OK;
|
|
363
|
+
}''',
|
|
364
|
+
'queue_send_nonrtos': '''OSAL_Status_t OSAL_Queue_Send(OSAL_Queue_t *queue, const void *item, uint32_t timeout_ms)
|
|
365
|
+
{
|
|
366
|
+
(void)timeout_ms;
|
|
367
|
+
if ((queue == NULL) || (item == NULL)) {
|
|
368
|
+
return OSAL_ERROR;
|
|
369
|
+
}
|
|
370
|
+
if (queue->count >= queue->size) {
|
|
371
|
+
return OSAL_BUSY;
|
|
372
|
+
}
|
|
373
|
+
uint8_t *dest = (uint8_t *)queue->buffer + (queue->tail * queue->item_size);
|
|
374
|
+
const uint8_t *src = (const uint8_t *)item;
|
|
375
|
+
for (uint32_t i = 0U; i < queue->item_size; i++) {
|
|
376
|
+
dest[i] = src[i];
|
|
377
|
+
}
|
|
378
|
+
queue->tail = (queue->tail + 1U) % queue->size;
|
|
379
|
+
queue->count++;
|
|
380
|
+
return OSAL_OK;
|
|
381
|
+
}''',
|
|
382
|
+
'queue_receive_nonrtos': '''OSAL_Status_t OSAL_Queue_Receive(OSAL_Queue_t *queue, void *item, uint32_t timeout_ms)
|
|
383
|
+
{
|
|
384
|
+
(void)timeout_ms;
|
|
385
|
+
if ((queue == NULL) || (item == NULL)) {
|
|
386
|
+
return OSAL_ERROR;
|
|
387
|
+
}
|
|
388
|
+
if (queue->count == 0U) {
|
|
389
|
+
return OSAL_BUSY;
|
|
390
|
+
}
|
|
391
|
+
uint8_t *src = (uint8_t *)queue->buffer + (queue->head * queue->item_size);
|
|
392
|
+
uint8_t *dest = (uint8_t *)item;
|
|
393
|
+
for (uint32_t i = 0U; i < queue->item_size; i++) {
|
|
394
|
+
dest[i] = src[i];
|
|
395
|
+
}
|
|
396
|
+
queue->head = (queue->head + 1U) % queue->size;
|
|
397
|
+
queue->count--;
|
|
398
|
+
return OSAL_OK;
|
|
399
|
+
}''',
|
|
400
|
+
'critical_enter_nonrtos': '''/* ===== Critical section: enter =====
|
|
401
|
+
*
|
|
402
|
+
* [!] STUB - must be implemented for your target.
|
|
403
|
+
*
|
|
404
|
+
* Called by the generated framework to prevent interrupts /
|
|
405
|
+
* preemption until OSAL_Critical_Exit() is called. Must be
|
|
406
|
+
* nestable on platforms where the caller may re-enter.
|
|
407
|
+
*
|
|
408
|
+
* Implementation examples:
|
|
409
|
+
* ARM Cortex-M : __asm__ volatile ("cpsid i" ::: "memory");
|
|
410
|
+
* ARM Cortex-A : __asm__ volatile ("msr DAIFSet, #2" ::: "memory");
|
|
411
|
+
* RISC-V : __asm__ volatile ("csrsi mstatus, 8" ::: "memory");
|
|
412
|
+
* FreeRTOS : taskENTER_CRITICAL();
|
|
413
|
+
*
|
|
414
|
+
* See docs/OSAL_PORTING_GUIDE_ja.md for the OSAL contract. */
|
|
415
|
+
void OSAL_Critical_Enter(void)
|
|
416
|
+
{
|
|
417
|
+
/* TODO: implement for your target. */
|
|
418
|
+
}''',
|
|
419
|
+
'critical_exit_nonrtos': '''/* ===== Critical section: exit =====
|
|
420
|
+
*
|
|
421
|
+
* [!] STUB - must be implemented for your target.
|
|
422
|
+
*
|
|
423
|
+
* Re-enables interrupts / preemption after a matching
|
|
424
|
+
* OSAL_Critical_Enter(). Must respect nesting depth if the
|
|
425
|
+
* platform requires it.
|
|
426
|
+
*
|
|
427
|
+
* Implementation examples:
|
|
428
|
+
* ARM Cortex-M : __asm__ volatile ("cpsie i" ::: "memory");
|
|
429
|
+
* ARM Cortex-A : __asm__ volatile ("msr DAIFClr, #2" ::: "memory");
|
|
430
|
+
* RISC-V : __asm__ volatile ("csrci mstatus, 8" ::: "memory");
|
|
431
|
+
* FreeRTOS : taskEXIT_CRITICAL();
|
|
432
|
+
*
|
|
433
|
+
* See docs/OSAL_PORTING_GUIDE_ja.md for the OSAL contract. */
|
|
434
|
+
void OSAL_Critical_Exit(void)
|
|
435
|
+
{
|
|
436
|
+
/* TODO: implement for your target. */
|
|
437
|
+
}''',
|
|
438
|
+
},
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
SUPER_INCLUDE_TEMPLATES = {
|
|
442
|
+
'file_comment': '''/**
|
|
443
|
+
* @file {filename}
|
|
444
|
+
* @brief StaTable generated code super include
|
|
445
|
+
*/''',
|
|
446
|
+
'guard_start': '#ifndef STATABLE_ALL_H\n#define STATABLE_ALL_H\n',
|
|
447
|
+
'common_section': '/* ---- Common headers ---- */',
|
|
448
|
+
'layer_section': '/* ---- Per-layer headers ---- */',
|
|
449
|
+
'project_section': '/* ---- Project headers ---- */',
|
|
450
|
+
'external_section': '/* ---- External includes (user-specified) ---- */',
|
|
451
|
+
'user_section': '/* ---- User-added includes ---- */',
|
|
452
|
+
'user_marker_start': '/* [[STABLE_USER_INCLUDES_START]] */',
|
|
453
|
+
'user_marker_end': '/* [[STABLE_USER_INCLUDES_END]] */',
|
|
454
|
+
'guard_end': '#endif /* STATABLE_ALL_H */',
|
|
455
|
+
'extern_var_section': '/* ---- Super loop variables (extern) ---- */',
|
|
456
|
+
'extern_context': 'extern SystemContext_t g_ctx;',
|
|
457
|
+
'extern_state': 'extern STATE_{layer}_t g_{layer}_state;',
|
|
458
|
+
'extern_state_nolayer': 'extern STATE_t g_state;',
|
|
459
|
+
'extern_func_section': '/* ---- Super loop functions ---- */',
|
|
460
|
+
'extern_init': 'void {project_name}_Init(void);',
|
|
461
|
+
'extern_run': 'void {project_name}_Run(void);',
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
# [v2.2.5 / gcc compile fix]
|
|
465
|
+
# Each layer's event processing is now wrapped in its own `{ ... }`
|
|
466
|
+
# scope, so `evt` (of type EVENT_<Layer>_t) does not conflict across
|
|
467
|
+
# layers. The variable name is kept as `evt` for readability.
|
|
468
|
+
SUPER_LOOP_TEMPLATES = {
|
|
469
|
+
'file_comment': '''/**
|
|
470
|
+
* @file {project_name}_run.c
|
|
471
|
+
* @brief State machine super loop
|
|
472
|
+
*/''',
|
|
473
|
+
'include': '#include "statable_all.h"',
|
|
474
|
+
'context_var': 'SystemContext_t g_ctx;',
|
|
475
|
+
'state_var': 'STATE_{layer}_t g_{layer}_state;',
|
|
476
|
+
'state_var_nolayer': 'STATE_t g_state;',
|
|
477
|
+
'init_func_comment': '''/**
|
|
478
|
+
* @brief State machine initialization
|
|
479
|
+
*/''',
|
|
480
|
+
'init_func_signature': 'void {project_name}_Init(void)',
|
|
481
|
+
'init_func_open': '{',
|
|
482
|
+
'init_context': (
|
|
483
|
+
' SystemContext_Init(&g_ctx);\n'
|
|
484
|
+
' SystemContext_InitQueues(&g_ctx);'
|
|
485
|
+
),
|
|
486
|
+
'init_state': ' g_{layer}_state = STATE_{layer}_{initial};',
|
|
487
|
+
'init_state_nolayer': ' g_state = STATE_{initial};',
|
|
488
|
+
'init_func_close': '}',
|
|
489
|
+
'run_func_comment': '''/**
|
|
490
|
+
* @brief State machine main loop
|
|
491
|
+
*/''',
|
|
492
|
+
'run_func_signature': 'void {project_name}_Run(void)',
|
|
493
|
+
'run_func_open': '{',
|
|
494
|
+
'run_while': ' while (1) {',
|
|
495
|
+
'run_block': ''' {{
|
|
496
|
+
EVENT_{layer}_t evt = StateMachine_GetNextEvent_{layer}(&g_ctx);
|
|
497
|
+
if (evt != EVENT_{layer}_NONE) {{
|
|
498
|
+
g_{layer}_state = StateMachine_Process_{layer}(g_{layer}_state, evt, &g_ctx);
|
|
499
|
+
}}
|
|
500
|
+
}}''',
|
|
501
|
+
'run_block_nolayer': ''' {
|
|
502
|
+
EVENT_t evt = StateMachine_GetNextEvent(&g_ctx);
|
|
503
|
+
if (evt != EVENT_NONE) {
|
|
504
|
+
g_state = StateMachine_Process(g_state, evt, &g_ctx);
|
|
505
|
+
}
|
|
506
|
+
}''',
|
|
507
|
+
'run_while_close': ' }',
|
|
508
|
+
'run_func_close': '}',
|
|
509
|
+
}
|
codegen/config.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# codegen/config.py
|
|
2
|
+
"""
|
|
3
|
+
Code generation settings management module
|
|
4
|
+
Centralizes generation options
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from typing import Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class CodeGenerationConfig:
|
|
13
|
+
"""Code generation settings"""
|
|
14
|
+
|
|
15
|
+
# ===== Generation style =====
|
|
16
|
+
generation_style: str = "table_driven" # table_driven / switch_case
|
|
17
|
+
|
|
18
|
+
# Transition table style
|
|
19
|
+
table_type: str = "array" # array / switch / dictionary
|
|
20
|
+
|
|
21
|
+
# OS type
|
|
22
|
+
os_type: str = "non_rtos" # non_rtos / freertos / threadx
|
|
23
|
+
|
|
24
|
+
# ===== Naming convention =====
|
|
25
|
+
naming_prefix: str = ""
|
|
26
|
+
state_prefix: str = "STATE"
|
|
27
|
+
event_prefix: str = "EVENT"
|
|
28
|
+
flag_prefix: str = "FLAG"
|
|
29
|
+
|
|
30
|
+
# ===== Debug log =====
|
|
31
|
+
enable_debug_logs: bool = True
|
|
32
|
+
enable_info_logs: bool = True
|
|
33
|
+
enable_error_logs: bool = True
|
|
34
|
+
|
|
35
|
+
# ===== Comment generation =====
|
|
36
|
+
enable_comments: bool = True
|
|
37
|
+
enable_doxygen: bool = True
|
|
38
|
+
|
|
39
|
+
# ===== Marker =====
|
|
40
|
+
enable_user_markers: bool = True
|
|
41
|
+
|
|
42
|
+
# ===== Output settings =====
|
|
43
|
+
output_directory: str = ""
|
|
44
|
+
save_with_merge: bool = True
|
|
45
|
+
|
|
46
|
+
# ===== Project settings =====
|
|
47
|
+
project_name: str = "MyProject"
|
|
48
|
+
|
|
49
|
+
# ===== Folder structure =====
|
|
50
|
+
folder_structure: str = "by_type" # flat / by_layer / by_type
|
|
51
|
+
include_dir_name: str = "include"
|
|
52
|
+
source_dir_name: str = "src"
|
|
53
|
+
common_dir_name: str = "common"
|
|
54
|
+
project_dir_name: str = "project"
|
|
55
|
+
|
|
56
|
+
# ===== Super include =====
|
|
57
|
+
generate_super_include: bool = True
|
|
58
|
+
super_include_file: str = "statable_all.h"
|
|
59
|
+
super_include_dir: str = "common"
|
|
60
|
+
|
|
61
|
+
# ===== External include =====
|
|
62
|
+
external_includes: List[str] = field(default_factory=list)
|
|
63
|
+
external_includes_in_super: bool = True
|
|
64
|
+
external_includes_in_role: bool = True
|
|
65
|
+
external_includes_in_transitions: bool = False
|
|
66
|
+
external_includes_in_common: bool = False
|
|
67
|
+
|
|
68
|
+
# ===== Reserved event limit =====
|
|
69
|
+
max_consecutive_pending_events: int = 16
|
|
70
|
+
|
|
71
|
+
def to_dict(self) -> Dict:
|
|
72
|
+
"""Convert to dictionary"""
|
|
73
|
+
return {
|
|
74
|
+
'generation_style': self.generation_style,
|
|
75
|
+
'table_type': self.table_type,
|
|
76
|
+
'os_type': self.os_type,
|
|
77
|
+
'naming_prefix': self.naming_prefix,
|
|
78
|
+
'state_prefix': self.state_prefix,
|
|
79
|
+
'event_prefix': self.event_prefix,
|
|
80
|
+
'flag_prefix': self.flag_prefix,
|
|
81
|
+
'enable_debug_logs': self.enable_debug_logs,
|
|
82
|
+
'enable_info_logs': self.enable_info_logs,
|
|
83
|
+
'enable_error_logs': self.enable_error_logs,
|
|
84
|
+
'enable_comments': self.enable_comments,
|
|
85
|
+
'enable_doxygen': self.enable_doxygen,
|
|
86
|
+
'enable_user_markers': self.enable_user_markers,
|
|
87
|
+
'output_directory': self.output_directory,
|
|
88
|
+
'save_with_merge': self.save_with_merge,
|
|
89
|
+
'project_name': self.project_name,
|
|
90
|
+
'folder_structure': self.folder_structure,
|
|
91
|
+
'include_dir_name': self.include_dir_name,
|
|
92
|
+
'source_dir_name': self.source_dir_name,
|
|
93
|
+
'common_dir_name': self.common_dir_name,
|
|
94
|
+
'project_dir_name': self.project_dir_name,
|
|
95
|
+
'generate_super_include': self.generate_super_include,
|
|
96
|
+
'super_include_file': self.super_include_file,
|
|
97
|
+
'super_include_dir': self.super_include_dir,
|
|
98
|
+
'external_includes': self.external_includes,
|
|
99
|
+
'external_includes_in_super': self.external_includes_in_super,
|
|
100
|
+
'external_includes_in_role': self.external_includes_in_role,
|
|
101
|
+
'external_includes_in_transitions': self.external_includes_in_transitions,
|
|
102
|
+
'external_includes_in_common': self.external_includes_in_common,
|
|
103
|
+
'max_consecutive_pending_events': self.max_consecutive_pending_events,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def from_dict(cls, data: Dict) -> 'CodeGenerationConfig':
|
|
108
|
+
"""Restore from dictionary"""
|
|
109
|
+
# Ignore unknown keys
|
|
110
|
+
valid_keys = {f.name for f in cls.__dataclass_fields__.values()}
|
|
111
|
+
filtered = {k: v for k, v in data.items() if k in valid_keys}
|
|
112
|
+
return cls(**filtered)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ConfigManager:
|
|
116
|
+
"""Settings management class"""
|
|
117
|
+
|
|
118
|
+
def __init__(self):
|
|
119
|
+
self._config = CodeGenerationConfig()
|
|
120
|
+
|
|
121
|
+
def get_config(self) -> CodeGenerationConfig:
|
|
122
|
+
"""Get current settings"""
|
|
123
|
+
return self._config
|
|
124
|
+
|
|
125
|
+
def set_config(self, config: CodeGenerationConfig):
|
|
126
|
+
"""Update settings"""
|
|
127
|
+
self._config = config
|
|
128
|
+
|
|
129
|
+
def update(self, **kwargs):
|
|
130
|
+
"""Partially update settings"""
|
|
131
|
+
for key, value in kwargs.items():
|
|
132
|
+
if hasattr(self._config, key):
|
|
133
|
+
setattr(self._config, key, value)
|
|
134
|
+
|
|
135
|
+
def reset(self):
|
|
136
|
+
"""Reset settings"""
|
|
137
|
+
self._config = CodeGenerationConfig()
|
|
138
|
+
|
|
139
|
+
def get_available_styles(self) -> Dict[str, str]:
|
|
140
|
+
"""Available generation styles"""
|
|
141
|
+
return {
|
|
142
|
+
'table_driven': 'Table-driven style',
|
|
143
|
+
'switch_case': 'switch-case style',
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
def get_available_table_types(self) -> Dict[str, str]:
|
|
147
|
+
"""Available table styles"""
|
|
148
|
+
return {
|
|
149
|
+
'array': 'Array style',
|
|
150
|
+
'switch': 'switch-case style',
|
|
151
|
+
'dictionary': 'Dictionary style (deprecated)',
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
def get_available_os_types(self) -> Dict[str, str]:
|
|
155
|
+
"""Available OS types"""
|
|
156
|
+
return {
|
|
157
|
+
'non_rtos': 'NonRTOS (bare metal)',
|
|
158
|
+
'freertos': 'FreeRTOS',
|
|
159
|
+
'threadx': 'ThreadX',
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
def get_available_folder_structures(self) -> Dict[str, str]:
|
|
163
|
+
return {
|
|
164
|
+
'flat': 'Flat',
|
|
165
|
+
'by_layer': 'Per layer',
|
|
166
|
+
'by_type': 'include/src separation',
|
|
167
|
+
}
|