@typecad/cuttlefish 1.0.0-alpha.14 → 1.0.0-alpha.16

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 (315) hide show
  1. package/README.md +82 -79
  2. package/assets/editor-extensions/typecad-debug/README.md +25 -26
  3. package/dist/api/config.d.ts +22 -26
  4. package/dist/api/schema/types.d.ts +20 -3
  5. package/dist/api/shared/async-runtime-static.d.ts +1 -1
  6. package/dist/api/shared/async-runtime-static.js +5 -5
  7. package/dist/api/shared/async-types.d.ts +3 -2
  8. package/dist/api/shared/board-catalog.d.ts +2 -0
  9. package/dist/api/shared/board-catalog.js +6 -0
  10. package/dist/api/shared/board-resolver.d.ts +4 -7
  11. package/dist/api/shared/board-resolver.js +2 -1
  12. package/dist/api/shared/coop-scheduler.d.ts +1 -1
  13. package/dist/api/shared/coop-scheduler.js +1 -1
  14. package/dist/api/shared/cpp-type-ir.d.ts +1 -1
  15. package/dist/api/shared/cpp-type-ir.js +1 -1
  16. package/dist/api/shared/display-profile.d.ts +1 -1
  17. package/dist/api/shared/display-profile.js +3 -5
  18. package/dist/api/shared/framework-manifest-registry.d.ts +1 -1
  19. package/dist/api/shared/framework-manifest-registry.js +0 -1
  20. package/dist/api/shared/framework-manifest.d.ts +7 -6
  21. package/dist/api/shared/framework-manifest.js +6 -11
  22. package/dist/api/shared/hal-op-ir.d.ts +294 -685
  23. package/dist/api/shared/hal-op-ir.js +31 -65
  24. package/dist/api/shared/index.d.ts +0 -4
  25. package/dist/api/shared/index.js +1 -7
  26. package/dist/api/shared/ir-core.d.ts +6 -0
  27. package/dist/api/shared/ir-declarations.d.ts +4 -0
  28. package/dist/api/shared/ir.d.ts +1 -3
  29. package/dist/api/shared/platform-strategy.d.ts +14 -37
  30. package/dist/api/shared/polyfill-helper-registry.js +0 -5
  31. package/dist/api/shared/polyfill-types.js +0 -27
  32. package/dist/api/shared/promise-runtime.js +3 -3
  33. package/dist/api/shared/spdx-licenses.d.ts +12 -10
  34. package/dist/api/shared/spdx-licenses.js +1 -1
  35. package/dist/api/shared/toolchain-types.d.ts +1 -1
  36. package/dist/api/shared/toolchain-types.js +3 -3
  37. package/dist/api/shared/types.d.ts +0 -3
  38. package/dist/api/shared/validate-framework-manifest.js +13 -33
  39. package/dist/board-catalog/dts-reader.d.ts +220 -0
  40. package/dist/board-catalog/dts-reader.js +1052 -0
  41. package/dist/board-catalog/index.d.ts +11 -0
  42. package/dist/board-catalog/index.js +12 -0
  43. package/dist/board-catalog/pinconfig.d.ts +48 -0
  44. package/dist/board-catalog/pinconfig.js +263 -0
  45. package/dist/board-catalog/sdk.d.ts +82 -0
  46. package/dist/board-catalog/sdk.js +180 -0
  47. package/dist/board-catalog/store.d.ts +196 -0
  48. package/dist/board-catalog/store.js +363 -0
  49. package/dist/board-catalog/types.d.ts +233 -0
  50. package/dist/board-catalog/types.js +7 -0
  51. package/dist/board-catalog/walker.d.ts +112 -0
  52. package/dist/board-catalog/walker.js +1101 -0
  53. package/dist/cli-utils.d.ts +2 -2
  54. package/dist/cli-utils.js +5 -5
  55. package/dist/cli.js +219 -242
  56. package/dist/config-loader.d.ts +14 -19
  57. package/dist/config-loader.js +240 -78
  58. package/dist/config-schema.d.ts +3 -5
  59. package/dist/config-schema.js +8 -8
  60. package/dist/contract/board-generator.d.ts +4 -4
  61. package/dist/contract/board-generator.js +16 -5
  62. package/dist/contract/contract-parser.d.ts +27 -0
  63. package/dist/contract/contract-parser.js +76 -0
  64. package/dist/contract/index.d.ts +1 -1
  65. package/dist/contract/index.js +70 -21
  66. package/dist/create/active-board-catalog.d.ts +9 -0
  67. package/dist/create/active-board-catalog.js +94 -0
  68. package/dist/create/board-catalog.generated.d.ts +96 -0
  69. package/dist/create/board-catalog.generated.js +128737 -0
  70. package/dist/create/board-search.d.ts +23 -0
  71. package/dist/create/board-search.js +88 -0
  72. package/dist/create/editor-integration.d.ts +4 -2
  73. package/dist/create/editor-integration.js +41 -2
  74. package/dist/create/framework-catalog.d.ts +57 -9
  75. package/dist/create/framework-catalog.js +76 -57
  76. package/dist/create/index.d.ts +5 -11
  77. package/dist/create/index.js +3 -8
  78. package/dist/create/mcu-target.d.ts +39 -0
  79. package/dist/create/mcu-target.js +80 -0
  80. package/dist/create/pack-targets.d.ts +19 -0
  81. package/dist/create/pack-targets.js +56 -0
  82. package/dist/create/scaffold.d.ts +4 -7
  83. package/dist/create/scaffold.js +19 -109
  84. package/dist/create/templates.d.ts +32 -5
  85. package/dist/create/templates.js +130 -116
  86. package/dist/create/wizard.d.ts +12 -1
  87. package/dist/create/wizard.js +168 -38
  88. package/dist/debug/preprocessor.d.ts +5 -0
  89. package/dist/debug/preprocessor.js +31 -7
  90. package/dist/diagnostics/diagnostics-report.d.ts +1 -1
  91. package/dist/diagnostics/diagnostics-report.js +3 -11
  92. package/dist/diagnostics/json-schema.d.ts +1 -1
  93. package/dist/diagnostics/md-writer.js +2 -2
  94. package/dist/diagnostics/mermaid-builder.d.ts +1 -1
  95. package/dist/diagnostics/mermaid-builder.js +1 -1
  96. package/dist/emit/cpp-emitter.js +4 -1
  97. package/dist/emit/emitters/class-emitter.js +32 -4
  98. package/dist/emit/emitters/emitter-context.d.ts +11 -0
  99. package/dist/emit/emitters/entrypoint-synthesizer.js +1 -1
  100. package/dist/emit/emitters/function-emitter-impl.js +33 -17
  101. package/dist/emit/emitters/output-finalizer.d.ts +7 -0
  102. package/dist/emit/emitters/output-finalizer.js +31 -23
  103. package/dist/emit/emitters/setup.js +125 -63
  104. package/dist/emit/emitters/top-level-prep.js +1 -1
  105. package/dist/emit/emitters/type-decl-emitter.js +13 -8
  106. package/dist/emit/emitters/ui-emitter.js +1 -1
  107. package/dist/emit/expression-renderer.d.ts +3 -3
  108. package/dist/emit/expression-renderer.js +17 -7
  109. package/dist/emit/route-hal-op.js +17 -48
  110. package/dist/emit/snprintf-helpers.d.ts +1 -3
  111. package/dist/emit/snprintf-helpers.js +1 -39
  112. package/dist/emit/statement-renderer.d.ts +0 -4
  113. package/dist/emit/statement-renderer.js +54 -45
  114. package/dist/emit/utils/async-state-machine.d.ts +16 -9
  115. package/dist/emit/utils/async-state-machine.js +56 -54
  116. package/dist/emit/utils/comment-helpers.d.ts +0 -8
  117. package/dist/emit/utils/comment-helpers.js +1 -1
  118. package/dist/emit/utils/cpp-helpers.d.ts +2 -2
  119. package/dist/emit/utils/cpp-helpers.js +2 -2
  120. package/dist/emit/utils/hal-op-cpp-type.js +4 -6
  121. package/dist/emit/utils/index.d.ts +3 -3
  122. package/dist/emit/utils/index.js +3 -3
  123. package/dist/emit/utils/type-inference.d.ts +1 -29
  124. package/dist/emit/utils/type-inference.js +0 -75
  125. package/dist/framework-package.d.ts +3 -0
  126. package/dist/framework-package.js +23 -6
  127. package/dist/framework-registry.d.ts +5 -5
  128. package/dist/frameworks/native/graphics/terminal-preview.d.ts +5 -0
  129. package/dist/frameworks/native/graphics/terminal-preview.js +33 -0
  130. package/dist/frameworks/native/index.d.ts +3 -0
  131. package/dist/frameworks/native/index.js +15 -0
  132. package/dist/frameworks/native/native-compile.d.ts +17 -0
  133. package/dist/frameworks/native/native-compile.js +170 -0
  134. package/dist/frameworks/native/native-config.d.ts +41 -0
  135. package/dist/frameworks/native/native-config.js +7 -0
  136. package/dist/frameworks/native/strategy.d.ts +97 -0
  137. package/dist/frameworks/native/strategy.js +664 -0
  138. package/dist/ir/board-resolver.d.ts +18 -23
  139. package/dist/ir/board-resolver.js +43 -401
  140. package/dist/ir/build-ir-state.d.ts +3 -0
  141. package/dist/ir/build-ir-state.js +42 -0
  142. package/dist/ir/build-ir.d.ts +1 -1
  143. package/dist/ir/build-ir.js +40 -42
  144. package/dist/ir/declaration-builders.js +1 -0
  145. package/dist/ir/expression-to-ir.js +17 -10
  146. package/dist/ir/hal/hal-emitter.d.ts +0 -2
  147. package/dist/ir/hal/hal-emitter.js +92 -41
  148. package/dist/ir/hal/hal-parser.d.ts +5 -5
  149. package/dist/ir/hal/hal-parser.js +128 -36
  150. package/dist/ir/hal/hal-plugins.d.ts +0 -1
  151. package/dist/ir/hal/hal-plugins.js +425 -716
  152. package/dist/ir/heap-analysis.js +2 -41
  153. package/dist/ir/identifier-collector.js +32 -20
  154. package/dist/ir/network-validation.js +7 -11
  155. package/dist/ir/ownership-analysis.js +75 -13
  156. package/dist/ir/peripheral-usage.d.ts +8 -2
  157. package/dist/ir/peripheral-usage.js +78 -149
  158. package/dist/ir/peripheral-validation.js +23 -3
  159. package/dist/ir/pin-capability-validation.d.ts +12 -0
  160. package/dist/ir/pin-capability-validation.js +61 -97
  161. package/dist/ir/pin-mode-validation.js +5 -5
  162. package/dist/ir/program-analysis.d.ts +8 -15
  163. package/dist/ir/program-analysis.js +140 -323
  164. package/dist/ir/pulldown-validation.js +11 -4
  165. package/dist/ir/resource-analysis.js +15 -3
  166. package/dist/ir/statement-to-ir.js +0 -6
  167. package/dist/ir/timing-validation.js +1 -1
  168. package/dist/ir/transformers/array-methods.js +11 -5
  169. package/dist/ir/transformers/call-statement.js +20 -87
  170. package/dist/ir/transformers/callback-context-registry.d.ts +1 -1
  171. package/dist/ir/transformers/callback-context-registry.js +8 -16
  172. package/dist/ir/transformers/control-flow.js +0 -13
  173. package/dist/ir/transformers/expressions.js +10 -9
  174. package/dist/ir/transformers/hal-call-resolver.d.ts +2 -2
  175. package/dist/ir/transformers/hal-call-resolver.js +24 -10
  176. package/dist/ir/transformers/hal-emit-helpers.d.ts +2 -2
  177. package/dist/ir/transformers/hal-emit-helpers.js +2 -2
  178. package/dist/ir/transformers/namespace-methods.js +1 -1
  179. package/dist/ir/transformers/ui-callback-lowering.d.ts +0 -2
  180. package/dist/ir/transformers/ui-callback-lowering.js +0 -24
  181. package/dist/ir/transformers/variables.js +338 -42
  182. package/dist/ir/try-catch-validation.js +4 -3
  183. package/dist/ir/type-resolution.js +15 -4
  184. package/dist/ir/validation-orchestrator.js +0 -9
  185. package/dist/libdef/cpp-to-decl.d.ts +0 -9
  186. package/dist/libdef/cpp-to-decl.js +0 -72
  187. package/dist/libdef/registry.d.ts +0 -1
  188. package/dist/libdef/registry.js +1 -24
  189. package/dist/library/init.d.ts +1 -1
  190. package/dist/library/init.js +137 -137
  191. package/dist/library-packages.d.ts +1 -1
  192. package/dist/library-packages.js +1 -1
  193. package/dist/mapping/peripheral-names.js +9 -4
  194. package/dist/mapping/source-map.d.ts +3 -4
  195. package/dist/mapping/source-map.js +12 -18
  196. package/dist/orchestrator/graph-builder.d.ts +3 -3
  197. package/dist/orchestrator/graph-builder.js +13 -12
  198. package/dist/orchestrator/type-checker.d.ts +3 -3
  199. package/dist/orchestrator/type-checker.js +3 -3
  200. package/dist/platform/async-runtime.js +1 -1
  201. package/dist/platform/coop-scheduler-runtime.js +2 -2
  202. package/dist/platform/generic-debug-codegen.d.ts +36 -0
  203. package/dist/platform/generic-debug-codegen.js +185 -0
  204. package/dist/platform/generic-strategy.d.ts +3 -4
  205. package/dist/platform/generic-strategy.js +5 -80
  206. package/dist/platform/index.js +1 -1
  207. package/dist/platform/registry.d.ts +2 -2
  208. package/dist/platform/registry.js +2 -2
  209. package/dist/safety/asil-decorators.d.ts +32 -0
  210. package/dist/safety/asil-decorators.js +32 -0
  211. package/dist/safety/authoring.d.ts +85 -0
  212. package/dist/safety/authoring.js +61 -0
  213. package/dist/safety/engine.d.ts +3 -0
  214. package/dist/safety/engine.js +83 -0
  215. package/dist/safety/hal/ops.d.ts +48 -0
  216. package/dist/safety/hal/ops.js +46 -0
  217. package/dist/safety/iso26262/analyze.d.ts +13 -0
  218. package/dist/safety/iso26262/analyze.js +29 -0
  219. package/dist/safety/iso26262/asil.d.ts +10 -0
  220. package/dist/safety/iso26262/asil.js +22 -0
  221. package/dist/safety/iso26262/collect.d.ts +14 -0
  222. package/dist/safety/iso26262/collect.js +137 -0
  223. package/dist/safety/iso26262/goto-checker.d.ts +10 -0
  224. package/dist/safety/iso26262/goto-checker.js +72 -0
  225. package/dist/safety/iso26262/heap-checker.d.ts +7 -0
  226. package/dist/safety/iso26262/heap-checker.js +57 -0
  227. package/dist/safety/iso26262/init-checker.d.ts +13 -0
  228. package/dist/safety/iso26262/init-checker.js +127 -0
  229. package/dist/safety/iso26262/loop-checker.d.ts +7 -0
  230. package/dist/safety/iso26262/loop-checker.js +86 -0
  231. package/dist/safety/iso26262/recursion-checker.d.ts +9 -0
  232. package/dist/safety/iso26262/recursion-checker.js +134 -0
  233. package/dist/safety/iso26262/sidecar-writer.d.ts +25 -0
  234. package/dist/safety/iso26262/sidecar-writer.js +13 -0
  235. package/dist/safety/passes/pinMode-intercept.d.ts +3 -0
  236. package/dist/safety/passes/pinMode-intercept.js +60 -0
  237. package/dist/safety/runtime/mode-table.d.ts +5 -0
  238. package/dist/safety/runtime/mode-table.js +55 -0
  239. package/dist/safety/runtime/polyfills.d.ts +6 -0
  240. package/dist/safety/runtime/polyfills.js +12 -0
  241. package/dist/safety/runtime/result-struct.d.ts +11 -0
  242. package/dist/safety/runtime/result-struct.js +98 -0
  243. package/dist/safety/runtime/safe-int.d.ts +33 -0
  244. package/dist/safety/runtime/safe-int.js +170 -0
  245. package/dist/safety/runtime/safe-traits.d.ts +4 -0
  246. package/dist/safety/runtime/safe-traits.js +95 -0
  247. package/dist/safety/runtime/safe-variable.d.ts +39 -0
  248. package/dist/safety/runtime/safe-variable.js +226 -0
  249. package/dist/safety/runtime/vote.d.ts +8 -0
  250. package/dist/safety/runtime/vote.js +92 -0
  251. package/dist/safety/runtime/write-verify.d.ts +8 -0
  252. package/dist/safety/runtime/write-verify.js +71 -0
  253. package/dist/safety/safe-int-types.d.ts +45 -0
  254. package/dist/safety/safe-int-types.js +25 -0
  255. package/dist/safety/safe-variable-types.d.ts +29 -0
  256. package/dist/safety/safe-variable-types.js +19 -0
  257. package/dist/safety/safety-bridge.d.ts +5 -6
  258. package/dist/safety/safety-bridge.js +15 -28
  259. package/dist/safety/sidecar-bridge.d.ts +1 -3
  260. package/dist/safety/sidecar-bridge.js +3 -20
  261. package/dist/safety/specifiers.d.ts +6 -0
  262. package/dist/safety/specifiers.js +14 -0
  263. package/dist/safety-hook.d.ts +8 -7
  264. package/dist/safety-hook.js +12 -13
  265. package/dist/testing.d.ts +4 -5
  266. package/dist/testing.js +5 -5
  267. package/dist/transpile/resolution.d.ts +1 -1
  268. package/dist/transpile/resolution.js +18 -9
  269. package/dist/transpile/test-pins.d.ts +18 -0
  270. package/dist/transpile/test-pins.js +142 -0
  271. package/dist/transpile.d.ts +1 -2
  272. package/dist/transpile.js +36 -30
  273. package/dist/types.d.ts +26 -26
  274. package/dist/ui-hook.d.ts +1 -1
  275. package/dist/utils/cli.d.ts +2 -2
  276. package/dist/utils/cli.js +92 -154
  277. package/dist/utils/fs.d.ts +3 -4
  278. package/dist/utils/fs.js +4 -5
  279. package/dist/utils/strings.d.ts +0 -1
  280. package/dist/utils/strings.js +0 -8
  281. package/dist/utils/ui.d.ts +5 -2
  282. package/dist/utils/ui.js +13 -3
  283. package/package.json +158 -157
  284. package/dist/add-preset.d.ts +0 -4
  285. package/dist/add-preset.js +0 -74
  286. package/dist/api/shared/async-symbol-detector.d.ts +0 -11
  287. package/dist/api/shared/async-symbol-detector.js +0 -140
  288. package/dist/api/shared/native-display-op-resolver.d.ts +0 -10
  289. package/dist/api/shared/native-display-op-resolver.js +0 -64
  290. package/dist/create/board-checklist.d.ts +0 -2
  291. package/dist/create/board-checklist.js +0 -52
  292. package/dist/create/board-codegen.d.ts +0 -9
  293. package/dist/create/board-codegen.js +0 -238
  294. package/dist/create/board-generators.d.ts +0 -12
  295. package/dist/create/board-generators.js +0 -651
  296. package/dist/create/board-spec.d.ts +0 -181
  297. package/dist/create/board-spec.js +0 -214
  298. package/dist/install/framework-catalog.d.ts +0 -53
  299. package/dist/install/framework-catalog.js +0 -107
  300. package/dist/install/handle-install.d.ts +0 -35
  301. package/dist/install/handle-install.js +0 -177
  302. package/dist/install/index.d.ts +0 -4
  303. package/dist/install/index.js +0 -3
  304. package/dist/ir/pin-state-tracking.d.ts +0 -58
  305. package/dist/ir/pin-state-tracking.js +0 -182
  306. package/dist/ir/pwm-timer-sharing.d.ts +0 -4
  307. package/dist/ir/pwm-timer-sharing.js +0 -94
  308. package/dist/ir/timer0-pwm-timing-conflict.d.ts +0 -4
  309. package/dist/ir/timer0-pwm-timing-conflict.js +0 -72
  310. package/dist/libdef/component-decls.d.ts +0 -2
  311. package/dist/libdef/component-decls.js +0 -6
  312. package/dist/libdef/component-discovery.d.ts +0 -43
  313. package/dist/libdef/component-discovery.js +0 -83
  314. package/dist/theme-tokens.d.ts +0 -22
  315. package/dist/theme-tokens.js +0 -172
@@ -0,0 +1,33 @@
1
+ import type { RuntimePolyfillIR } from "../../api/index.js";
2
+ /** SafeInt<T> polyfill: chainable bounds-checked signed-integer arithmetic.
3
+ *
4
+ * Mutating chain — every math op returns SafeInt<T>& so calls compose:
5
+ * x.add(5).mul(2).get()
6
+ *
7
+ * Sticky-fault overflow policy: on overflow or division error, set fault_
8
+ * and stop computing. Subsequent ops are no-ops returning *this. get()
9
+ * returns the last good value. hasFault()/valid() inspect the flag;
10
+ * reset() clears it.
11
+ *
12
+ * Overflow detection uses portable pure-C++14 PRE-CHECKS (bounds tests
13
+ * before the assignment). The reconstruction trick would compute first
14
+ * then check, but the initial computation is signed-overflow UB. Pre-checks
15
+ * avoid the UB, work at every width including int64_t (no wider promotion
16
+ * type needed), and need no __builtin_*_overflow (a GCC/clang extension
17
+ * that would require an AUTOSAR deviation).
18
+ *
19
+ * NO <type_traits> / <limits> includes: AVR's toolchain ships neither
20
+ * header. The type constraint (static_assert) and the per-width bounds come
21
+ * from the shared hand-rolled __tc_safe_traits block (safe-traits.ts), which
22
+ * uses only core-language features (template specialization, static_cast,
23
+ * constexpr) that every supported target — including AVR's avr-gcc — has.
24
+ *
25
+ * AUTOSAR C++14 compliance:
26
+ * - static_assert on T (rejects unsigned, bool, float, non-integer)
27
+ * - noexcept on all methods (A15-0-2)
28
+ * - [[nodiscard]] on get/hasFault/valid (A0-1-1)
29
+ * - constexpr constructor
30
+ * - static_cast throughout (no C-casts M5-0-7, no builtins M5-0-10,
31
+ * no malloc A18-5-10). Zero deviations required.
32
+ */
33
+ export declare function safeIntPolyfill(): RuntimePolyfillIR;
@@ -0,0 +1,170 @@
1
+ import { emitSafeTraits } from "./safe-traits.js";
2
+ /** SafeInt<T> polyfill: chainable bounds-checked signed-integer arithmetic.
3
+ *
4
+ * Mutating chain — every math op returns SafeInt<T>& so calls compose:
5
+ * x.add(5).mul(2).get()
6
+ *
7
+ * Sticky-fault overflow policy: on overflow or division error, set fault_
8
+ * and stop computing. Subsequent ops are no-ops returning *this. get()
9
+ * returns the last good value. hasFault()/valid() inspect the flag;
10
+ * reset() clears it.
11
+ *
12
+ * Overflow detection uses portable pure-C++14 PRE-CHECKS (bounds tests
13
+ * before the assignment). The reconstruction trick would compute first
14
+ * then check, but the initial computation is signed-overflow UB. Pre-checks
15
+ * avoid the UB, work at every width including int64_t (no wider promotion
16
+ * type needed), and need no __builtin_*_overflow (a GCC/clang extension
17
+ * that would require an AUTOSAR deviation).
18
+ *
19
+ * NO <type_traits> / <limits> includes: AVR's toolchain ships neither
20
+ * header. The type constraint (static_assert) and the per-width bounds come
21
+ * from the shared hand-rolled __tc_safe_traits block (safe-traits.ts), which
22
+ * uses only core-language features (template specialization, static_cast,
23
+ * constexpr) that every supported target — including AVR's avr-gcc — has.
24
+ *
25
+ * AUTOSAR C++14 compliance:
26
+ * - static_assert on T (rejects unsigned, bool, float, non-integer)
27
+ * - noexcept on all methods (A15-0-2)
28
+ * - [[nodiscard]] on get/hasFault/valid (A0-1-1)
29
+ * - constexpr constructor
30
+ * - static_cast throughout (no C-casts M5-0-7, no builtins M5-0-10,
31
+ * no malloc A18-5-10). Zero deviations required.
32
+ */
33
+ export function safeIntPolyfill() {
34
+ return {
35
+ kind: "polyfill",
36
+ id: "safety_safe_int",
37
+ domain: "embedded",
38
+ requiredIncludes: [],
39
+ forwardDeclarations: [],
40
+ helperStructs: [],
41
+ helperFunctions: [`
42
+ ${emitSafeTraits()}
43
+
44
+ #ifndef __TC_SAFE_INT_DEFINED
45
+ #define __TC_SAFE_INT_DEFINED
46
+
47
+ // No #include here: the fixed-width integer types come transitively from
48
+ // <Arduino.h> on embedded targets (which pulls <stdint.h>), mirroring the
49
+ // other safety polyfills (mode-table, vote). The shared __tc_safe_traits
50
+ // block (emitted above) is also header-free.
51
+
52
+ template <typename T>
53
+ struct SafeInt {
54
+ static_assert(__tc_safe_traits::is_integral<T>::value
55
+ && __tc_safe_traits::is_signed<T>::value
56
+ && !__tc_safe_traits::is_same<T, bool>::value,
57
+ "SafeInt<T> requires a signed integer T (int8_t/int16_t/int32_t/int64_t). "
58
+ "Unsigned, bool, floating-point, and non-integer types are rejected.");
59
+
60
+ private:
61
+ T value_;
62
+ bool fault_;
63
+
64
+ static constexpr T kMax = __tc_safe_traits::bounds<T>::kMax;
65
+ static constexpr T kMin = __tc_safe_traits::bounds<T>::kMin;
66
+
67
+ public:
68
+ // Default constructor: zero-initialized, no fault. Required because promoted
69
+ // top-level variables default-construct via '= {}' before their real
70
+ // initializer is assigned inside the entrypoint. Mirrors SafeVariable's
71
+ // default ctor.
72
+ constexpr SafeInt() noexcept : value_(0), fault_(false) {}
73
+ constexpr SafeInt(T initial) noexcept : value_(initial), fault_(false) {}
74
+
75
+ SafeInt<T>& add(T delta) noexcept {
76
+ if (fault_) { return *this; }
77
+ // Pre-check: overflow iff (delta>0 && value>Max-delta) || (delta<0 && value<Min-delta).
78
+ // (Max-delta) and (Min-delta) are safe because delta has the opposite sign
79
+ // of the bound being approached, so the subtraction cannot itself overflow.
80
+ if ((delta > 0 && value_ > kMax - delta) || (delta < 0 && value_ < kMin - delta)) {
81
+ fault_ = true;
82
+ return *this;
83
+ }
84
+ value_ = static_cast<T>(value_ + delta);
85
+ return *this;
86
+ }
87
+
88
+ SafeInt<T>& sub(T delta) noexcept {
89
+ if (fault_) { return *this; }
90
+ // Direct pre-check (NOT add(-delta), since -delta is UB when delta==Min):
91
+ // value - delta > Max iff value > Max + delta (when delta < 0)
92
+ // value - delta < Min iff value < Min + delta (when delta > 0)
93
+ // (Max+delta)/(Min+delta) are safe — delta has the opposite sign of the bound.
94
+ if ((delta < 0 && value_ > kMax + delta) || (delta > 0 && value_ < kMin + delta)) {
95
+ fault_ = true;
96
+ return *this;
97
+ }
98
+ value_ = static_cast<T>(value_ - delta);
99
+ return *this;
100
+ }
101
+
102
+ SafeInt<T>& mul(T factor) noexcept {
103
+ if (fault_) { return *this; }
104
+ if (factor == 0 || value_ == 0) { value_ = 0; return *this; }
105
+ // Pre-check via absolute bounds. |value| > Max / |factor| => overflow.
106
+ // (Also catches the value==Min && factor==-1 case since |Min| > Max.)
107
+ // absWithoutUB: -(kMin) is UB, so compute |kMin| as -(kMin+1) + (-1) = kMax... no,
108
+ // |kMin| is kMax+1 which is NOT representable. The check absValue > kMax/absFactor
109
+ // still fires for value==kMin because absValue (computed without UB) exceeds any
110
+ // representable positive value when factor==-1. We compute |x| without UB below.
111
+ const T absValue = (value_ < 0) ? static_cast<T>(-(value_ + 1)) + (-1) : value_;
112
+ const T absFactor = (factor < 0) ? static_cast<T>(-(factor + 1)) + (-1) : factor;
113
+ if (absValue > kMax / absFactor) {
114
+ fault_ = true;
115
+ return *this;
116
+ }
117
+ value_ = static_cast<T>(value_ * factor);
118
+ return *this;
119
+ }
120
+
121
+ // Named divide (not div) to avoid the cuttlefish reserved-name escaper
122
+ // renaming .div( to .div_( because div() is a C stdlib (<cstdlib>) name.
123
+ SafeInt<T>& divide(T d) noexcept {
124
+ if (fault_) { return *this; }
125
+ if (d == 0) { fault_ = true; return *this; }
126
+ // INT_MIN / -1 overflows.
127
+ if (value_ == kMin && d == static_cast<T>(-1)) { fault_ = true; return *this; }
128
+ value_ = static_cast<T>(value_ / d);
129
+ return *this;
130
+ }
131
+
132
+ SafeInt<T>& mod(T d) noexcept {
133
+ if (fault_) { return *this; }
134
+ if (d == 0) { fault_ = true; return *this; }
135
+ if (value_ == kMin && d == static_cast<T>(-1)) { value_ = 0; return *this; }
136
+ value_ = static_cast<T>(value_ % d);
137
+ return *this;
138
+ }
139
+
140
+ SafeInt<T>& negate() noexcept {
141
+ if (fault_) { return *this; }
142
+ if (value_ == kMin) { fault_ = true; return *this; }
143
+ value_ = static_cast<T>(-value_);
144
+ return *this;
145
+ }
146
+
147
+ // Named absValue (not abs) to avoid colliding with Arduino's abs() macro
148
+ // (Arduino.h #defines abs(x)), which would mangle the method declaration on
149
+ // AVR. Same caution for any future method whose name matches an Arduino core
150
+ // macro (min/max/round/...).
151
+ SafeInt<T>& absValue() noexcept {
152
+ if (fault_) { return *this; }
153
+ if (value_ == kMin) { fault_ = true; return *this; }
154
+ if (value_ < 0) { value_ = static_cast<T>(-value_); }
155
+ return *this;
156
+ }
157
+
158
+ [[nodiscard]] constexpr T get() const noexcept { return value_; }
159
+ [[nodiscard]] bool hasFault() const noexcept { return fault_; }
160
+ [[nodiscard]] bool valid() const noexcept { return !fault_; }
161
+
162
+ void reset(T newValue) noexcept { value_ = newValue; fault_ = false; }
163
+ };
164
+
165
+ #endif // __TC_SAFE_INT_DEFINED
166
+ `.trim()],
167
+ shimMacros: [],
168
+ dependencies: [],
169
+ };
170
+ }
@@ -0,0 +1,4 @@
1
+ /** Returns the C++ source for the __tc_safe_traits block. Idempotent via the
2
+ * __TC_SAFE_TRAITS_DEFINED guard, so emitting it from both the SafeInt and
3
+ * SafeVariable polyfills is harmless (the second include is a no-op). */
4
+ export declare function emitSafeTraits(): string;
@@ -0,0 +1,95 @@
1
+ // Hand-rolled C++ type traits for the safety polyfills.
2
+ //
3
+ // AVR's avr-gcc ships neither <type_traits> nor <limits>. The SafeInt and
4
+ // SafeVariable polyfills need is_integral / is_signed / is_same for their
5
+ // static_asserts, but must not include <type_traits>. This helper returns a
6
+ // self-contained C++14 block (no includes) that defines a __tc_safe_traits
7
+ // namespace with exactly the traits the polyfills use.
8
+ //
9
+ // SPECIALIZATION DISCIPLINE (avoids redefinition errors):
10
+ // On AVR, the fixed-width typedefs alias the built-ins: int8_t == signed char,
11
+ // int16_t == short, int32_t == long (int is 16-bit on AVR). Specializing for
12
+ // BOTH a typedef and its underlying built-in is a redefinition error. So:
13
+ // - is_integral / is_signed specialize the BUILT-IN types only (signed char,
14
+ // short, int, long, long long, unsigned variants, char, bool). A lookup
15
+ // via a typedef (is_integral<int32_t>) resolves to the built-in
16
+ // specialization automatically because the typedef names the same type.
17
+ // - bounds specializes the FIXED-WIDTH typedefs only (int8_t/int16_t/
18
+ // int32_t/int64_t). Each typedef maps to exactly one specialization, and
19
+ // the bounds values match the typedef's width (not the host 'int' width).
20
+ /** Returns the C++ source for the __tc_safe_traits block. Idempotent via the
21
+ * __TC_SAFE_TRAITS_DEFINED guard, so emitting it from both the SafeInt and
22
+ * SafeVariable polyfills is harmless (the second include is a no-op). */
23
+ export function emitSafeTraits() {
24
+ return `
25
+ #ifndef __TC_SAFE_TRAITS_DEFINED
26
+ #define __TC_SAFE_TRAITS_DEFINED
27
+
28
+ // No #include here: the integer types come transitively from <Arduino.h> on
29
+ // embedded targets (which pulls <stdint.h>) and from the test harness's own
30
+ // includes on native. This mirrors the other safety polyfills (mode-table,
31
+ // vote) which use uint32_t with no explicit include.
32
+
33
+ namespace __tc_safe_traits {
34
+
35
+ // is_integral<T>: specialized on canonical built-in integer types only.
36
+ // Lookups via fixed-width typedefs (int8_t/int32_t/etc.) resolve to these
37
+ // because each typedef names the same type as its underlying built-in.
38
+ template <typename T> struct is_integral { static constexpr bool value = false; };
39
+ template <> struct is_integral<bool> { static constexpr bool value = true; };
40
+ template <> struct is_integral<char> { static constexpr bool value = true; };
41
+ template <> struct is_integral<signed char> { static constexpr bool value = true; };
42
+ template <> struct is_integral<unsigned char> { static constexpr bool value = true; };
43
+ template <> struct is_integral<short> { static constexpr bool value = true; };
44
+ template <> struct is_integral<unsigned short> { static constexpr bool value = true; };
45
+ template <> struct is_integral<int> { static constexpr bool value = true; };
46
+ template <> struct is_integral<unsigned int> { static constexpr bool value = true; };
47
+ template <> struct is_integral<long> { static constexpr bool value = true; };
48
+ template <> struct is_integral<unsigned long> { static constexpr bool value = true; };
49
+ template <> struct is_integral<long long> { static constexpr bool value = true; };
50
+ template <> struct is_integral<unsigned long long> { static constexpr bool value = true; };
51
+
52
+ // is_signed<T>: specialized on canonical signed built-in integer types only.
53
+ template <typename T> struct is_signed { static constexpr bool value = false; };
54
+ template <> struct is_signed<signed char> { static constexpr bool value = true; };
55
+ template <> struct is_signed<short> { static constexpr bool value = true; };
56
+ template <> struct is_signed<int> { static constexpr bool value = true; };
57
+ template <> struct is_signed<long> { static constexpr bool value = true; };
58
+ template <> struct is_signed<long long> { static constexpr bool value = true; };
59
+
60
+ // is_same<T,U>: standard two-type trait.
61
+ template <typename T, typename U> struct is_same { static constexpr bool value = false; };
62
+ template <typename T> struct is_same<T, T> { static constexpr bool value = true; };
63
+
64
+ // bounds<T>: per-fixed-width min/max via literals + static_cast (no <limits>).
65
+ // Specialized on the FIXED-WIDTH typedefs only. Each typedef has a unique
66
+ // specialization whose bounds match that typedef's width (independent of the
67
+ // host 'int' width — critical because AVR's int is 16-bit while ESP32/native
68
+ // is 32-bit). int64_t is guarded because some freestanding toolchains lack it.
69
+ template <typename T> struct bounds;
70
+ template <> struct bounds<int8_t> {
71
+ static constexpr int8_t kMin = static_cast<int8_t>(static_cast<uint8_t>(0x80u));
72
+ static constexpr int8_t kMax = static_cast<int8_t>(0x7Fu);
73
+ };
74
+ template <> struct bounds<int16_t> {
75
+ static constexpr int16_t kMin = static_cast<int16_t>(static_cast<uint16_t>(0x8000u));
76
+ static constexpr int16_t kMax = static_cast<int16_t>(0x7FFFu);
77
+ };
78
+ template <> struct bounds<int32_t> {
79
+ static constexpr int32_t kMin = static_cast<int32_t>(static_cast<uint32_t>(0x80000000u));
80
+ static constexpr int32_t kMax = static_cast<int32_t>(0x7FFFFFFFu);
81
+ };
82
+ #if defined(__INT64_TYPE__)
83
+ template <> struct bounds<__INT64_TYPE__> {
84
+ // Use unsigned-long-long literals (standard 'ull' suffix) and cast — the
85
+ // 'ill' signed suffix is a GNU extension needing -fext-numeric-literals.
86
+ static constexpr __INT64_TYPE__ kMin = static_cast<__INT64_TYPE__>(static_cast<unsigned long long>(0x8000000000000000ull));
87
+ static constexpr __INT64_TYPE__ kMax = static_cast<__INT64_TYPE__>(static_cast<unsigned long long>(0x7FFFFFFFFFFFFFFFull));
88
+ };
89
+ #endif
90
+
91
+ } // namespace __tc_safe_traits
92
+
93
+ #endif // __TC_SAFE_TRAITS_DEFINED
94
+ `.trim();
95
+ }
@@ -0,0 +1,39 @@
1
+ import type { RuntimePolyfillIR } from "../../api/index.js";
2
+ /** SafeVariable polyfill: 3-replica TMR with per-replica inversion for
3
+ * integral types, and plain 3-copy TMR for float/double.
4
+ *
5
+ * Combines TMR (triple modular redundancy) with inverted-redundancy for
6
+ * integral types: three replicas of the value, each stored alongside its
7
+ * bitwise inverse. On read, each replica is individually validated (XOR
8
+ * check), then the valid replicas are majority-voted. This gives both
9
+ * detection AND correction:
10
+ *
11
+ * - A single-bit SEU in any replica's value or inverse breaks that
12
+ * replica's XOR invariant → the corrupted replica is excluded from
13
+ * the vote, and the good replicas correct it.
14
+ * - If two replicas agree (majority), the value is returned with
15
+ * confidence. The corrupted replica is silently repaired on the next
16
+ * set().
17
+ * - For float/double, replicas are stored as plain copies (no inversion
18
+ * possible), and majority vote still corrects single-replica corruption.
19
+ *
20
+ * Fault signaling: hasFault() returns true iff the last get() found ZERO
21
+ * valid replicas (triple corruption). Callers should check hasFault() after
22
+ * get() on safety-critical paths. set() clears the fault flag.
23
+ *
24
+ * Memory cost: 3× T (same as plain TMR). The inversion is per-replica and
25
+ * does not add copies beyond the three TMR replicas.
26
+ *
27
+ * Arithmetic T only — a static_assert rejects non-arithmetic types (notably
28
+ * std::string) and bool (for which bitwise inversion is ill-defined) at
29
+ * compile time. float and double have explicit specializations.
30
+ *
31
+ * AUTOSAR C++14 compliance:
32
+ * - noexcept on all methods (A15-0-2)
33
+ * - [[nodiscard]] on get/valid/hasFault (A0-1-1)
34
+ * - constexpr constructors/methods
35
+ * - no malloc/new (A18-5-8/A18-5-10)
36
+ * - no C-style casts (M5-0-7)
37
+ * - fixed-width types via template parameter (A3-9-1)
38
+ */
39
+ export declare function safeVariablePolyfill(): RuntimePolyfillIR;
@@ -0,0 +1,226 @@
1
+ import { emitSafeTraits } from "./safe-traits.js";
2
+ /** SafeVariable polyfill: 3-replica TMR with per-replica inversion for
3
+ * integral types, and plain 3-copy TMR for float/double.
4
+ *
5
+ * Combines TMR (triple modular redundancy) with inverted-redundancy for
6
+ * integral types: three replicas of the value, each stored alongside its
7
+ * bitwise inverse. On read, each replica is individually validated (XOR
8
+ * check), then the valid replicas are majority-voted. This gives both
9
+ * detection AND correction:
10
+ *
11
+ * - A single-bit SEU in any replica's value or inverse breaks that
12
+ * replica's XOR invariant → the corrupted replica is excluded from
13
+ * the vote, and the good replicas correct it.
14
+ * - If two replicas agree (majority), the value is returned with
15
+ * confidence. The corrupted replica is silently repaired on the next
16
+ * set().
17
+ * - For float/double, replicas are stored as plain copies (no inversion
18
+ * possible), and majority vote still corrects single-replica corruption.
19
+ *
20
+ * Fault signaling: hasFault() returns true iff the last get() found ZERO
21
+ * valid replicas (triple corruption). Callers should check hasFault() after
22
+ * get() on safety-critical paths. set() clears the fault flag.
23
+ *
24
+ * Memory cost: 3× T (same as plain TMR). The inversion is per-replica and
25
+ * does not add copies beyond the three TMR replicas.
26
+ *
27
+ * Arithmetic T only — a static_assert rejects non-arithmetic types (notably
28
+ * std::string) and bool (for which bitwise inversion is ill-defined) at
29
+ * compile time. float and double have explicit specializations.
30
+ *
31
+ * AUTOSAR C++14 compliance:
32
+ * - noexcept on all methods (A15-0-2)
33
+ * - [[nodiscard]] on get/valid/hasFault (A0-1-1)
34
+ * - constexpr constructors/methods
35
+ * - no malloc/new (A18-5-8/A18-5-10)
36
+ * - no C-style casts (M5-0-7)
37
+ * - fixed-width types via template parameter (A3-9-1)
38
+ */
39
+ export function safeVariablePolyfill() {
40
+ return {
41
+ kind: "polyfill",
42
+ id: "safety_safe_variable",
43
+ domain: "embedded",
44
+ requiredIncludes: [],
45
+ forwardDeclarations: [],
46
+ helperStructs: [],
47
+ helperFunctions: [`
48
+ ${emitSafeTraits()}
49
+
50
+ #ifndef __TC_SAFE_VARIABLE_DEFINED
51
+ #define __TC_SAFE_VARIABLE_DEFINED
52
+
53
+ // ── SafeVariable: integer types (bitwise XOR validation per replica) ──
54
+ // Each replica stores value + ~value. On read, each replica is validated
55
+ // independently. Valid replicas are majority-voted; the corrupted one
56
+ // (if any) is excluded. This provides both detection AND correction.
57
+ template <typename T>
58
+ struct SafeVariable {
59
+ // Arithmetic T only. bool is rejected explicitly because ~bool and ^bool
60
+ // undergo integer promotion and do not behave as a 1-bit inversion.
61
+ // float/double are handled by the explicit specializations below.
62
+ static_assert(__tc_safe_traits::is_integral<T>::value && !__tc_safe_traits::is_same<T, bool>::value,
63
+ "SafeVariable<T> requires an integral T (use float/double specializations for those; "
64
+ "std::string and bool are not supported)");
65
+
66
+ private:
67
+ T replicaA_val;
68
+ T replicaA_inv;
69
+ T replicaB_val;
70
+ T replicaB_inv;
71
+ T replicaC_val;
72
+ T replicaC_inv;
73
+ // mutable: get() is logically const (it does not change the stored value)
74
+ // but caches the "last read saw triple corruption" fault flag so callers
75
+ // can inspect it via hasFault() after get().
76
+ mutable bool fault_;
77
+ template <typename U> friend struct SafeVariable;
78
+
79
+ static bool replicaValid(T val, T inv) noexcept {
80
+ return (val ^ inv) == static_cast<T>(~static_cast<T>(0));
81
+ }
82
+
83
+ public:
84
+ SafeVariable() noexcept
85
+ : replicaA_val(0), replicaA_inv(static_cast<T>(~static_cast<T>(0))),
86
+ replicaB_val(0), replicaB_inv(static_cast<T>(~static_cast<T>(0))),
87
+ replicaC_val(0), replicaC_inv(static_cast<T>(~static_cast<T>(0))),
88
+ fault_(false) {}
89
+
90
+ SafeVariable(T initial) noexcept
91
+ : replicaA_val(initial), replicaA_inv(static_cast<T>(~initial)),
92
+ replicaB_val(initial), replicaB_inv(static_cast<T>(~initial)),
93
+ replicaC_val(initial), replicaC_inv(static_cast<T>(~initial)),
94
+ fault_(false) {}
95
+
96
+ template <typename U>
97
+ SafeVariable(const SafeVariable<U>& other) noexcept
98
+ : replicaA_val(static_cast<T>(other.replicaA_val)), replicaA_inv(static_cast<T>(other.replicaA_inv)),
99
+ replicaB_val(static_cast<T>(other.replicaB_val)), replicaB_inv(static_cast<T>(other.replicaB_inv)),
100
+ replicaC_val(static_cast<T>(other.replicaC_val)), replicaC_inv(static_cast<T>(other.replicaC_inv)),
101
+ fault_(other.fault_) {}
102
+
103
+ // Majority vote: returns the agreed-upon value from valid replicas.
104
+ // If a replica is corrupted (XOR check fails), it is excluded from
105
+ // the vote. If two or more valid replicas agree, return that value.
106
+ // If only one replica is valid, return it as a best-effort fallback.
107
+ // If NO replica is valid (triple corruption), returns replicaC_val as a
108
+ // last resort and sets the fault flag — callers must check hasFault().
109
+ [[nodiscard]] T get() const noexcept {
110
+ const bool aValid = replicaValid(replicaA_val, replicaA_inv);
111
+ const bool bValid = replicaValid(replicaB_val, replicaB_inv);
112
+ const bool cValid = replicaValid(replicaC_val, replicaC_inv);
113
+
114
+ // Two valid replicas agree → majority.
115
+ if (aValid && bValid && (replicaA_val == replicaB_val)) { fault_ = false; return replicaA_val; }
116
+ if (aValid && cValid && (replicaA_val == replicaC_val)) { fault_ = false; return replicaA_val; }
117
+ if (bValid && cValid && (replicaB_val == replicaC_val)) { fault_ = false; return replicaB_val; }
118
+
119
+ // Only one valid replica → return it (no majority but best available).
120
+ if (aValid) { fault_ = false; return replicaA_val; }
121
+ if (bValid) { fault_ = false; return replicaB_val; }
122
+ if (cValid) { fault_ = false; return replicaC_val; }
123
+
124
+ // Zero valid replicas → triple corruption. Flag the fault and return
125
+ // replicaC_val as a degenerate fallback; callers MUST check hasFault().
126
+ fault_ = true;
127
+ return replicaC_val;
128
+ }
129
+
130
+ // Returns true if all three replicas pass their XOR checks AND agree.
131
+ // Does not mutate the fault flag (it reflects the last get(), not valid()).
132
+ [[nodiscard]] bool valid() const noexcept {
133
+ return replicaValid(replicaA_val, replicaA_inv)
134
+ && replicaValid(replicaB_val, replicaB_inv)
135
+ && replicaValid(replicaC_val, replicaC_inv)
136
+ && (replicaA_val == replicaB_val)
137
+ && (replicaB_val == replicaC_val);
138
+ }
139
+
140
+ // Returns true iff the most recent get() found zero valid replicas
141
+ // (triple corruption). Cleared by set() and by a subsequent get() that
142
+ // finds at least one valid replica.
143
+ [[nodiscard]] bool hasFault() const noexcept { return fault_; }
144
+
145
+ void set(T newValue) noexcept {
146
+ const T inv = static_cast<T>(~newValue);
147
+ replicaA_val = newValue; replicaA_inv = inv;
148
+ replicaB_val = newValue; replicaB_inv = inv;
149
+ replicaC_val = newValue; replicaC_inv = inv;
150
+ fault_ = false;
151
+ }
152
+ };
153
+
154
+ // ── SafeVariable: float (3-replica majority vote, no inversion) ──
155
+ // Floats can't use bitwise XOR/inversion. Three identical copies are
156
+ // stored and majority-voted. A single corrupted copy is outvoted and
157
+ // silently repaired on the next set().
158
+ template <>
159
+ struct SafeVariable<float> {
160
+ private:
161
+ float replicaA;
162
+ float replicaB;
163
+ float replicaC;
164
+ mutable bool fault_;
165
+ template <typename U> friend struct SafeVariable;
166
+ public:
167
+ SafeVariable() noexcept : replicaA(0.0f), replicaB(0.0f), replicaC(0.0f), fault_(false) {}
168
+ SafeVariable(float initial) noexcept : replicaA(initial), replicaB(initial), replicaC(initial), fault_(false) {}
169
+ [[nodiscard]] float get() const noexcept {
170
+ if (replicaA == replicaB) { fault_ = false; return replicaA; }
171
+ if (replicaA == replicaC) { fault_ = false; return replicaA; }
172
+ if (replicaB == replicaC) { fault_ = false; return replicaB; }
173
+ // No two replicas agree — triple corruption.
174
+ fault_ = true;
175
+ return replicaC;
176
+ }
177
+ [[nodiscard]] bool valid() const noexcept {
178
+ return (replicaA == replicaB) && (replicaB == replicaC);
179
+ }
180
+ [[nodiscard]] bool hasFault() const noexcept { return fault_; }
181
+ void set(float newValue) noexcept {
182
+ replicaA = newValue;
183
+ replicaB = newValue;
184
+ replicaC = newValue;
185
+ fault_ = false;
186
+ }
187
+ };
188
+
189
+ // ── SafeVariable: double (3-replica majority vote, no inversion) ──
190
+ template <>
191
+ struct SafeVariable<double> {
192
+ private:
193
+ double replicaA;
194
+ double replicaB;
195
+ double replicaC;
196
+ mutable bool fault_;
197
+ template <typename U> friend struct SafeVariable;
198
+ public:
199
+ SafeVariable() noexcept : replicaA(0.0), replicaB(0.0), replicaC(0.0), fault_(false) {}
200
+ SafeVariable(double initial) noexcept : replicaA(initial), replicaB(initial), replicaC(initial), fault_(false) {}
201
+ [[nodiscard]] double get() const noexcept {
202
+ if (replicaA == replicaB) { fault_ = false; return replicaA; }
203
+ if (replicaA == replicaC) { fault_ = false; return replicaA; }
204
+ if (replicaB == replicaC) { fault_ = false; return replicaB; }
205
+ // No two replicas agree — triple corruption.
206
+ fault_ = true;
207
+ return replicaC;
208
+ }
209
+ [[nodiscard]] bool valid() const noexcept {
210
+ return (replicaA == replicaB) && (replicaB == replicaC);
211
+ }
212
+ [[nodiscard]] bool hasFault() const noexcept { return fault_; }
213
+ void set(double newValue) noexcept {
214
+ replicaA = newValue;
215
+ replicaB = newValue;
216
+ replicaC = newValue;
217
+ fault_ = false;
218
+ }
219
+ };
220
+
221
+ #endif // __TC_SAFE_VARIABLE_DEFINED
222
+ `.trim()],
223
+ shimMacros: [],
224
+ dependencies: [],
225
+ };
226
+ }
@@ -0,0 +1,8 @@
1
+ import type { RuntimePolyfillIR } from "../../api/index.js";
2
+ /** The 2-of-3 voter. Tree-shaken out unless __tc_safety_read_safe appears
3
+ * in the program (registered in POLYFILL_HELPER_MAP).
4
+ *
5
+ * MCU-agnosticism: the voter reads via the strategy-injected __tc_gpio_read
6
+ * shim (defined per-target by each framework strategy's shimLines()). The
7
+ * safety package references zero target-specific symbols. */
8
+ export declare function voterPolyfill(): RuntimePolyfillIR;
@@ -0,0 +1,92 @@
1
+ /** The 2-of-3 voter. Tree-shaken out unless __tc_safety_read_safe appears
2
+ * in the program (registered in POLYFILL_HELPER_MAP).
3
+ *
4
+ * MCU-agnosticism: the voter reads via the strategy-injected __tc_gpio_read
5
+ * shim (defined per-target by each framework strategy's shimLines()). The
6
+ * safety package references zero target-specific symbols. */
7
+ export function voterPolyfill() {
8
+ return {
9
+ kind: "polyfill",
10
+ id: "safety_read_safe",
11
+ domain: "embedded",
12
+ requiredIncludes: [],
13
+ forwardDeclarations: [],
14
+ helperStructs: [],
15
+ helperFunctions: [`
16
+ // Forward declarations — the strategy's shimLines() defines these AFTER the
17
+ // polyfill block (polyfills emit before shims in emitPreamble). Without the
18
+ // forward decls, the voter's __tc_gpio_read / __tc_delay_us calls below would
19
+ // be unresolved.
20
+ int __tc_gpio_read(uint32_t pin);
21
+ void __tc_delay_us(uint32_t us);
22
+
23
+ namespace __tc_safety {
24
+
25
+ // Settle delay between temporally-separated reads. ~2 us is enough to defeat
26
+ // single-event transient (SET) glitches on a typical GPIO line while staying
27
+ // well under a debounce timescale. Tunable in one place.
28
+ constexpr uint32_t TC_SAFETY_SETTLE_US = 2U;
29
+
30
+ // Perform 3 temporally-separated reads via the strategy-injected shim, take
31
+ // the majority. On disagreement, VoteDisagreement. On pin-mode mismatch,
32
+ // PinModeMismatch. On untracked pin, PinModeUnknown. value is left 0 when
33
+ // ok==false — callers must check 'ok' before consuming 'value'.
34
+ inline SafeReadResult read_safe(uint32_t pin) {
35
+ SafeReadResult result;
36
+ result.value = 0x00000000U;
37
+ result.category = SafetyFaultCategory::Ok;
38
+ result.code = SafetyFaultCode::Ok;
39
+ result.status = SafetyStatus::Ok;
40
+
41
+ // 1. Confirm pin mode (Input, InputPullup, or InputPulldown are valid for
42
+ // reading). Output is rejected (PinModeMismatch). InputPulldown is
43
+ // accepted because it is a legitimate input mode on ESP32 (and AVR via
44
+ // external pulldown); rejecting it caused false faults.
45
+ const TrackedMode mode = get_pin_mode(pin);
46
+ if (mode == TrackedMode::Unknown) {
47
+ result.category = SafetyFaultCategory::Configuration;
48
+ result.code = SafetyFaultCode::PinModeUnknown;
49
+ result.status = SafetyStatus::Fault;
50
+ return result;
51
+ }
52
+ if ((mode != TrackedMode::Input) && (mode != TrackedMode::InputPullup) && (mode != TrackedMode::InputPulldown)) {
53
+ result.category = SafetyFaultCategory::Configuration;
54
+ result.code = SafetyFaultCode::PinModeMismatch;
55
+ result.status = SafetyStatus::Fault;
56
+ return result;
57
+ }
58
+
59
+ // 2. 2-of-3 vote via the strategy-injected __tc_gpio_read shim.
60
+ // __tc_delay_us provides temporal separation between reads so a single
61
+ // input glitch is unlikely to corrupt two samples; the strategy injects a
62
+ // real microsecond delay (Arduino/ESP32: delayMicroseconds; AVR:
63
+ // _native_delay_us; native: stub).
64
+ const uint32_t r0 = __tc_gpio_read(pin);
65
+ __tc_delay_us(TC_SAFETY_SETTLE_US);
66
+ const uint32_t r1 = __tc_gpio_read(pin);
67
+ __tc_delay_us(TC_SAFETY_SETTLE_US);
68
+ const uint32_t r2 = __tc_gpio_read(pin);
69
+
70
+ if ((r0 == r1) && (r1 == r2)) {
71
+ result.status = SafetyStatus::Ok;
72
+ result.value = r0 ? 0xFFFFFFFFU : 0x00000000U;
73
+ } else {
74
+ result.category = SafetyFaultCategory::Signal;
75
+ result.code = SafetyFaultCode::VoteDisagreement;
76
+ result.status = SafetyStatus::Fault;
77
+ }
78
+ return result;
79
+ }
80
+
81
+ // Namespace-scoped forwarding entry point — kept inside the namespace so
82
+ // the emitter's forward-declaration pass does not generate a global prototype
83
+ // that references SafeReadResult before the struct is defined.
84
+ inline SafeReadResult __tc_safety_read_safe(uint32_t pin) {
85
+ return read_safe(pin);
86
+ }
87
+
88
+ } // namespace __tc_safety`.trim()],
89
+ shimMacros: [],
90
+ dependencies: ["safety_mode_table"],
91
+ };
92
+ }