|
30 | 30 | * |
31 | 31 | */ |
32 | 32 |
|
33 | | -#ifndef LADDER_INSTRUCTIONS_H |
34 | | -#define LADDER_INSTRUCTIONS_H |
| 33 | +#ifndef FN_COMMONS_H |
| 34 | +#define FN_COMMONS_H |
35 | 35 |
|
36 | 36 | #include <stdbool.h> |
37 | 37 | #include <stdint.h> |
38 | 38 | #include <string.h> |
39 | 39 |
|
40 | 40 | #include "ladder.h" |
41 | 41 |
|
42 | | -extern uint32_t basetime_factor[]; |
43 | | - |
44 | | -static inline int32_t to_integer(int32_t val, ladder_data_type_t type) { |
45 | | - (void)type; // Unused; suppress warning (original behavior preserved) |
46 | | - if (val == 0) { |
47 | | - return (int32_t)(uint32_t)val; // Explicit cast as in original |
48 | | - } else if (val == 1) { |
49 | | - return (int32_t)val; |
50 | | - } |
51 | | - return 0; |
52 | | -} |
53 | 42 |
|
54 | 43 | #define exnet(lctx) (*(*lctx).exec_network) |
55 | 44 |
|
56 | | -static inline int32_t safe_get_register_index(ladder_ctx_t *lctx, ladder_register_t type, int32_t raw_idx, ladder_ins_err_t *err) { |
57 | | - if (raw_idx < 0) { |
58 | | - *err = LADDER_INS_ERR_OUTOFRANGE; |
59 | | - return -1; |
60 | | - } |
61 | | - uint32_t idx = (uint32_t) raw_idx; |
62 | | - uint32_t qty = 0; |
63 | | - switch (type) { |
64 | | - case LADDER_REGISTER_M: |
65 | | - qty = lctx->ladder.quantity.m; |
66 | | - break; |
67 | | - case LADDER_REGISTER_Cd: |
68 | | - case LADDER_REGISTER_Cr: |
69 | | - case LADDER_REGISTER_C: |
70 | | - qty = lctx->ladder.quantity.c; |
71 | | - break; |
72 | | - case LADDER_REGISTER_Td: |
73 | | - case LADDER_REGISTER_Tr: |
74 | | - case LADDER_REGISTER_T: |
75 | | - qty = lctx->ladder.quantity.t; |
76 | | - break; |
77 | | - case LADDER_REGISTER_D: |
78 | | - qty = lctx->ladder.quantity.d; |
79 | | - break; |
80 | | - case LADDER_REGISTER_R: |
81 | | - qty = lctx->ladder.quantity.r; |
82 | | - break; |
83 | | - default: |
84 | | - *err = LADDER_INS_ERR_TYPEMISMATCH; |
85 | | - return -1; |
86 | | - } |
87 | | - if (idx >= qty) { |
88 | | - *err = LADDER_INS_ERR_OUTOFRANGE; |
89 | | - return -1; |
90 | | - } |
91 | | - *err = LADDER_INS_ERR_OK; |
92 | | - return (int32_t) idx; |
93 | | -} |
94 | | - |
95 | | -static inline bool safe_check_module_port(ladder_ctx_t *lctx, ladder_register_t type, uint32_t mod, uint8_t port, uint32_t *qty_out, ladder_ins_err_t *err) { |
96 | | - uint32_t fn_qty = 0; |
97 | | - switch (type) { |
98 | | - case LADDER_REGISTER_Q: |
99 | | - case LADDER_REGISTER_QW: |
100 | | - fn_qty = lctx->hw.io.fn_write_qty; |
101 | | - break; |
102 | | - case LADDER_REGISTER_I: |
103 | | - case LADDER_REGISTER_IW: |
104 | | - fn_qty = lctx->hw.io.fn_read_qty; |
105 | | - break; |
106 | | - default: |
107 | | - *err = LADDER_INS_ERR_TYPEMISMATCH; |
108 | | - return false; |
109 | | - } |
110 | | - if (mod >= fn_qty) { |
111 | | - *err = LADDER_INS_ERR_OUTOFRANGE; |
112 | | - return false; |
113 | | - } |
114 | | - switch (type) { |
115 | | - case LADDER_REGISTER_Q: |
116 | | - *qty_out = lctx->output[mod].q_qty; |
117 | | - break; |
118 | | - case LADDER_REGISTER_QW: |
119 | | - *qty_out = lctx->output[mod].qw_qty; |
120 | | - break; |
121 | | - case LADDER_REGISTER_I: |
122 | | - *qty_out = lctx->input[mod].i_qty; |
123 | | - break; |
124 | | - case LADDER_REGISTER_IW: |
125 | | - *qty_out = lctx->input[mod].iw_qty; |
126 | | - break; |
127 | | - default: |
128 | | - break; // Unreachable |
129 | | - } |
130 | | - if (port >= *qty_out) { |
131 | | - *err = LADDER_INS_ERR_OUTOFRANGE; |
132 | | - return false; |
133 | | - } |
134 | | - *err = LADDER_INS_ERR_OK; |
135 | | - return true; |
136 | | -} |
137 | | - |
138 | | -static inline int32_t ladder_get_data_value(ladder_ctx_t *lctx, uint32_t r, uint32_t c, uint32_t i) { |
139 | | - if (lctx == NULL || lctx->exec_network == NULL) { |
140 | | - return 0; // Safe default on invalid context |
141 | | - } |
142 | | - ladder_network_t *net = lctx->exec_network; |
143 | | - if (r >= net->rows || c >= net->cols || i >= net->cells[r][c].data_qty) { |
144 | | - return 0; // Safe default on OOB |
145 | | - } |
146 | | - ladder_register_t type = net->cells[r][c].data[i].type; |
147 | | - ladder_value_t *val = &net->cells[r][c].data[i]; |
148 | | - ladder_ins_err_t err = LADDER_INS_ERR_OK; |
149 | | - |
150 | | - switch (type) { |
151 | | - case LADDER_REGISTER_NONE: |
152 | | - return (int32_t) (uint32_t) val->value.i32; |
153 | | - case LADDER_REGISTER_M: |
154 | | - case LADDER_REGISTER_Cd: |
155 | | - case LADDER_REGISTER_Cr: |
156 | | - case LADDER_REGISTER_Td: |
157 | | - case LADDER_REGISTER_Tr: |
158 | | - case LADDER_REGISTER_C: |
159 | | - case LADDER_REGISTER_T: |
160 | | - case LADDER_REGISTER_D: |
161 | | - case LADDER_REGISTER_R: { |
162 | | - int32_t idx = safe_get_register_index(lctx, type, val->value.i32, &err); |
163 | | - if (err != LADDER_INS_ERR_OK) { |
164 | | - lctx->ladder.last.err = err; |
165 | | - return 0; // Safe default on error |
166 | | - } |
167 | | - switch (type) { |
168 | | - case LADDER_REGISTER_M: return (int32_t) lctx->memory.M[idx]; |
169 | | - case LADDER_REGISTER_Cd: return (int32_t) lctx->memory.Cd[idx]; |
170 | | - case LADDER_REGISTER_Cr: return (int32_t) lctx->memory.Cr[idx]; |
171 | | - case LADDER_REGISTER_Td: return (int32_t) lctx->memory.Td[idx]; |
172 | | - case LADDER_REGISTER_Tr: return (int32_t) lctx->memory.Tr[idx]; |
173 | | - case LADDER_REGISTER_C: return (int32_t) lctx->registers.C[idx]; |
174 | | - case LADDER_REGISTER_T: { |
175 | | - uint64_t acc = lctx->timers[idx].acc; |
176 | | - if (acc > (uint64_t) INT32_MAX) { |
177 | | - lctx->ladder.last.err = LADDER_INS_ERR_OVERFLOW; |
178 | | - return 0; |
179 | | - } |
180 | | - return (int32_t) acc; |
181 | | - } |
182 | | - case LADDER_REGISTER_D: return lctx->registers.D[idx]; |
183 | | - case LADDER_REGISTER_R: return (int32_t) lctx->registers.R[idx]; |
184 | | - default: return 0; |
185 | | - } |
186 | | - } |
187 | | - case LADDER_REGISTER_Q: |
188 | | - case LADDER_REGISTER_I: |
189 | | - case LADDER_REGISTER_IW: |
190 | | - case LADDER_REGISTER_QW: { |
191 | | - uint32_t mod = val->value.mp.module; |
192 | | - uint8_t port = val->value.mp.port; |
193 | | - uint32_t qty = 0; |
194 | | - if (!safe_check_module_port(lctx, type, mod, port, &qty, &err)) { |
195 | | - lctx->ladder.last.err = err; |
196 | | - return 0; |
197 | | - } |
198 | | - switch (type) { |
199 | | - case LADDER_REGISTER_Q: return (int32_t) lctx->output[mod].Q[port]; |
200 | | - case LADDER_REGISTER_I: return (int32_t) lctx->input[mod].I[port]; |
201 | | - case LADDER_REGISTER_IW: return lctx->input[mod].IW[port]; |
202 | | - case LADDER_REGISTER_QW: return lctx->output[mod].QW[port]; |
203 | | - default: return 0; |
204 | | - } |
205 | | - } |
206 | | - case LADDER_REGISTER_S: |
207 | | - return 0; // Strings not numeric; default 0 |
208 | | - case LADDER_REGISTER_INV: |
209 | | - default: |
210 | | - return 0; |
211 | | - } |
212 | | -} |
213 | | - |
214 | | -static inline int32_t ladder_get_previous_value(ladder_ctx_t *lctx, uint32_t r, uint32_t c, uint32_t i) { |
215 | | - if (lctx == NULL || lctx->exec_network == NULL) { |
216 | | - return 0; // Safe default on invalid context |
217 | | - } |
218 | | - ladder_network_t *net = lctx->exec_network; |
219 | | - if (r >= net->rows || c >= net->cols || i >= net->cells[r][c].data_qty) { |
220 | | - return 0; // Safe default on OOB |
221 | | - } |
222 | | - ladder_register_t type = net->cells[r][c].data[i].type; |
223 | | - ladder_value_t *val = &net->cells[r][c].data[i]; |
224 | | - |
225 | | - switch (type) { |
226 | | - case LADDER_REGISTER_M: |
227 | | - return (int32_t) lctx->prev_scan_vals.Mh[val->value.i32]; |
228 | | - case LADDER_REGISTER_Q: { |
229 | | - uint32_t mod = val->value.mp.module; |
230 | | - uint8_t port = val->value.mp.port; |
231 | | - if (mod >= lctx->hw.io.fn_write_qty) { |
232 | | - return 0; |
233 | | - } |
234 | | - // Null check for Qh to prevent dereference of unallocated array |
235 | | - if (lctx->output[mod].Qh == NULL) { |
236 | | - return 0; // Safe default if history not allocated |
237 | | - } |
238 | | - // Bounds check for port to prevent OOB access |
239 | | - if (port >= lctx->output[mod].q_qty) { |
240 | | - return 0; // Safe default on invalid port |
241 | | - } |
242 | | - return (int32_t) lctx->output[mod].Qh[port]; |
243 | | - } |
244 | | - case LADDER_REGISTER_I: { |
245 | | - uint32_t mod = val->value.mp.module; |
246 | | - uint8_t port = val->value.mp.port; |
247 | | - if (mod >= lctx->hw.io.fn_read_qty) { |
248 | | - return 0; |
249 | | - } |
250 | | - // Null check for Ih to prevent dereference of unallocated array |
251 | | - if (lctx->input[mod].Ih == NULL) { |
252 | | - return 0; // Safe default if history not allocated |
253 | | - } |
254 | | - // Bounds check for port to prevent OOB access |
255 | | - if (port >= lctx->input[mod].i_qty) { |
256 | | - return 0; // Safe default on invalid port |
257 | | - } |
258 | | - return (int32_t) lctx->input[mod].Ih[port]; |
259 | | - } |
260 | | - case LADDER_REGISTER_Cd: |
261 | | - return (int32_t) lctx->prev_scan_vals.Cdh[val->value.i32]; |
262 | | - case LADDER_REGISTER_Cr: |
263 | | - return (int32_t) lctx->prev_scan_vals.Crh[val->value.i32]; |
264 | | - case LADDER_REGISTER_Td: |
265 | | - return (int32_t) lctx->prev_scan_vals.Tdh[val->value.i32]; |
266 | | - case LADDER_REGISTER_Tr: |
267 | | - return (int32_t) lctx->prev_scan_vals.Trh[val->value.i32]; |
268 | | - // For other types like IW/QW/C/T/D/R/S, previous values may not be stored (e.g., no prev for accumulators or data regs). |
269 | | - // Default to current value or 0; adjust based on requirements (e.g., add prev for D if needed). |
270 | | - case LADDER_REGISTER_IW: { |
271 | | - uint32_t mod = val->value.mp.module; |
272 | | - uint8_t port = val->value.mp.port; |
273 | | - if (mod >= lctx->hw.io.fn_read_qty) |
274 | | - return 0; |
275 | | - return lctx->input[mod].IW[port]; // No prev for words; use current |
276 | | - } |
277 | | - case LADDER_REGISTER_QW: { |
278 | | - uint32_t mod = val->value.mp.module; |
279 | | - uint8_t port = val->value.mp.port; |
280 | | - if (mod >= lctx->hw.io.fn_write_qty) |
281 | | - return 0; |
282 | | - return lctx->output[mod].QW[port]; // No prev for words; use current |
283 | | - } |
284 | | - case LADDER_REGISTER_C: |
285 | | - return (int32_t) lctx->registers.C[val->value.i32]; // No prev; use current |
286 | | - case LADDER_REGISTER_T: |
287 | | - return (int32_t) lctx->timers[val->value.i32].acc; // No prev acc; use current |
288 | | - case LADDER_REGISTER_D: |
289 | | - return lctx->registers.D[val->value.i32]; // No prev; use current |
290 | | - case LADDER_REGISTER_R: |
291 | | - return (int32_t) lctx->registers.R[val->value.i32]; // No prev; use current |
292 | | - case LADDER_REGISTER_S: |
293 | | - return 0; // Strings not applicable for previous |
294 | | - case LADDER_REGISTER_NONE: |
295 | | - case LADDER_REGISTER_INV: |
296 | | - default: |
297 | | - return 0; |
298 | | - } |
299 | | -} |
300 | | - |
301 | | -static inline int32_t ladder_get_data_int32(ladder_ctx_t *lctx, uint32_t r, uint32_t c, uint32_t i) { |
302 | | - if (lctx == NULL || lctx->exec_network == NULL) { |
303 | | - return 0; // Safe default on invalid context |
304 | | - } |
305 | | - ladder_network_t *net = lctx->exec_network; |
306 | | - if (r >= net->rows || c >= net->cols || i >= net->cells[r][c].data_qty) { |
307 | | - return 0; // Safe default on OOB |
308 | | - } |
309 | | - ladder_register_t type = net->cells[r][c].data[i].type; |
310 | | - ladder_value_t *val = &net->cells[r][c].data[i]; |
311 | | - |
312 | | - switch (type) { |
313 | | - case LADDER_REGISTER_NONE: |
314 | | - return val->value.i32; |
315 | | - case LADDER_REGISTER_M: |
316 | | - case LADDER_REGISTER_Q: |
317 | | - case LADDER_REGISTER_I: |
318 | | - case LADDER_REGISTER_Cd: |
319 | | - case LADDER_REGISTER_Cr: |
320 | | - case LADDER_REGISTER_Td: |
321 | | - case LADDER_REGISTER_Tr: |
322 | | - // Bool types: Treat false=0, true=1 |
323 | | - return (int32_t) ladder_get_data_value(lctx, r, c, i); |
324 | | - case LADDER_REGISTER_IW: { |
325 | | - uint32_t mod = val->value.mp.module; |
326 | | - uint8_t port = val->value.mp.port; |
327 | | - if (mod >= lctx->hw.io.fn_read_qty) |
328 | | - return 0; |
329 | | - return lctx->input[mod].IW[port]; |
330 | | - } |
331 | | - case LADDER_REGISTER_QW: { |
332 | | - uint32_t mod = val->value.mp.module; |
333 | | - uint8_t port = val->value.mp.port; |
334 | | - if (mod >= lctx->hw.io.fn_write_qty) |
335 | | - return 0; |
336 | | - return lctx->output[mod].QW[port]; |
337 | | - } |
338 | | - case LADDER_REGISTER_C: |
339 | | - return (int32_t) lctx->registers.C[val->value.i32]; |
340 | | - case LADDER_REGISTER_T: |
341 | | - return (int32_t) lctx->timers[val->value.i32].acc; // Truncate u64 to i32 if needed |
342 | | - case LADDER_REGISTER_D: |
343 | | - return lctx->registers.D[val->value.i32]; |
344 | | - case LADDER_REGISTER_R: |
345 | | - return (int32_t) lctx->registers.R[val->value.i32]; |
346 | | - case LADDER_REGISTER_S: |
347 | | - return 0; // Strings not numeric |
348 | | - case LADDER_REGISTER_INV: |
349 | | - default: |
350 | | - return 0; |
351 | | - } |
352 | | -} |
353 | | - |
354 | 45 | /** |
355 | 46 | * @def ladder_cell_data_exec |
356 | 47 | * @brief |
@@ -810,4 +501,4 @@ ladder_ins_err_t fn_FOREIGN(ladder_ctx_t *ladder_ctx, uint32_t column, uint32_t |
810 | 501 | */ |
811 | 502 | ladder_ins_err_t fn_TMOVE(ladder_ctx_t *ladder_ctx, uint32_t column, uint32_t row); |
812 | 503 |
|
813 | | -#endif /* LADDER_INSTRUCTIONS_H */ |
| 504 | +#endif /* FN_COMMONS_H */ |
0 commit comments