@typecad/framework-arduino 0.1.0-alpha.1

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +192 -0
  3. package/dist/arduino/i2c-arduino.d.ts +47 -0
  4. package/dist/arduino/i2c-arduino.js +6 -0
  5. package/dist/arduino/index.d.ts +6 -0
  6. package/dist/arduino/index.js +8 -0
  7. package/dist/arduino/spi-arduino.d.ts +42 -0
  8. package/dist/arduino/spi-arduino.js +6 -0
  9. package/dist/arduino/stubs-uno.d.ts +9 -0
  10. package/dist/arduino/stubs-uno.js +65 -0
  11. package/dist/arduino/uart-arduino.d.ts +41 -0
  12. package/dist/arduino/uart-arduino.js +6 -0
  13. package/dist/arduino-class-map.d.ts +5 -0
  14. package/dist/arduino-class-map.js +21 -0
  15. package/dist/arduino-compile.d.ts +24 -0
  16. package/dist/arduino-compile.js +316 -0
  17. package/dist/arduino-libs.d.ts +6 -0
  18. package/dist/arduino-libs.js +11 -0
  19. package/dist/cli-metadata.d.ts +12 -0
  20. package/dist/cli-metadata.js +196 -0
  21. package/dist/cpp-parser.d.ts +47 -0
  22. package/dist/cpp-parser.js +292 -0
  23. package/dist/debug-codegen.d.ts +20 -0
  24. package/dist/debug-codegen.js +115 -0
  25. package/dist/displays/ili9341-spi.d.ts +6 -0
  26. package/dist/displays/ili9341-spi.js +28 -0
  27. package/dist/displays/ssd1309-i2c.d.ts +2 -0
  28. package/dist/displays/ssd1309-i2c.js +16 -0
  29. package/dist/displays/st7796-spi.d.ts +2 -0
  30. package/dist/displays/st7796-spi.js +20 -0
  31. package/dist/graphics/ili9341.d.ts +24 -0
  32. package/dist/graphics/ili9341.js +59 -0
  33. package/dist/index.d.ts +13 -0
  34. package/dist/index.js +27 -0
  35. package/dist/lib-declaration.d.ts +35 -0
  36. package/dist/lib-declaration.js +399 -0
  37. package/dist/lib-discovery.d.ts +38 -0
  38. package/dist/lib-discovery.js +189 -0
  39. package/dist/profile.d.ts +8 -0
  40. package/dist/profile.js +584 -0
  41. package/dist/strategy.d.ts +174 -0
  42. package/dist/strategy.js +2032 -0
  43. package/package.json +73 -0
  44. package/src/arduino/i2c-arduino.ts +72 -0
  45. package/src/arduino/index.ts +18 -0
  46. package/src/arduino/spi-arduino.ts +63 -0
  47. package/src/arduino/stubs-uno.ts +80 -0
  48. package/src/arduino/uart-arduino.ts +59 -0
  49. package/src/arduino-class-map.ts +32 -0
  50. package/src/arduino-compile.ts +359 -0
  51. package/src/arduino-libs.ts +33 -0
  52. package/src/cli-metadata.ts +250 -0
  53. package/src/cpp-parser.ts +361 -0
  54. package/src/debug-codegen.ts +155 -0
  55. package/src/displays/ili9341-spi.ts +33 -0
  56. package/src/displays/ssd1309-i2c.ts +19 -0
  57. package/src/displays/st7796-spi.ts +23 -0
  58. package/src/graphics/ili9341.ts +80 -0
  59. package/src/index.ts +37 -0
  60. package/src/lib-declaration.ts +493 -0
  61. package/src/lib-discovery.ts +267 -0
  62. package/src/profile.ts +676 -0
  63. package/src/strategy.ts +2126 -0
@@ -0,0 +1,292 @@
1
+ // ---------------------------------------------------------------------------
2
+ // @typecad/framework-arduino — C++ Header Parser
3
+ //
4
+ // Parses C++ header files from Arduino libraries into an IR that can be
5
+ // used for TypeScript type declaration generation.
6
+ // ---------------------------------------------------------------------------
7
+ // ---------------------------------------------------------------------------
8
+ // Arduino-to-TypeCAD type mappings
9
+ // ---------------------------------------------------------------------------
10
+ /**
11
+ * Maps Arduino peripheral C++ types to TypeCAD equivalents.
12
+ * Uses the instance names (I2C0, SPI0, UART0) as types for simplicity.
13
+ */
14
+ const ARDUINO_TYPE_MAPPINGS = {
15
+ // I2C - TypeCAD uses I2C0 instance
16
+ "TwoWire": "I2C0",
17
+ "TwoWire*": "I2C0",
18
+ "TwoWire&": "I2C0",
19
+ // SPI - TypeCAD uses SPI0 instance
20
+ "SPIClass": "SPI0",
21
+ "SPIClass*": "SPI0",
22
+ "SPIClass&": "SPI0",
23
+ // Serial - TypeCAD uses UART0 instance
24
+ "HardwareSerial": "UART0",
25
+ "HardwareSerial*": "UART0",
26
+ "HardwareSerial&": "UART0",
27
+ "Stream": "UART0",
28
+ "Stream*": "UART0",
29
+ "Stream&": "UART0",
30
+ // Common Arduino types
31
+ "Print": "UART0",
32
+ "Print*": "UART0",
33
+ "Print&": "UART0",
34
+ };
35
+ // ---------------------------------------------------------------------------
36
+ // Type mapping
37
+ // ---------------------------------------------------------------------------
38
+ /**
39
+ * Maps C++ types to TypeScript types.
40
+ */
41
+ export function mapCppTypeToTs(cppType) {
42
+ const trimmed = cppType.trim();
43
+ // Remove const qualifier
44
+ const withoutConst = trimmed.replace(/^const\s+/, "");
45
+ // Check Arduino type mappings first
46
+ if (ARDUINO_TYPE_MAPPINGS[withoutConst]) {
47
+ return ARDUINO_TYPE_MAPPINGS[withoutConst];
48
+ }
49
+ // Basic type mappings
50
+ const typeMap = {
51
+ "int": "number",
52
+ "unsigned int": "number",
53
+ "uint8_t": "number",
54
+ "uint16_t": "number",
55
+ "uint32_t": "number",
56
+ "int8_t": "number",
57
+ "int16_t": "number",
58
+ "int32_t": "number",
59
+ "float": "number",
60
+ "double": "number",
61
+ "bool": "boolean",
62
+ "void": "void",
63
+ "char": "string",
64
+ "char*": "string",
65
+ "const char*": "string",
66
+ "std::string": "string",
67
+ "String": "string",
68
+ "byte": "number",
69
+ "word": "number",
70
+ "size_t": "number",
71
+ };
72
+ // Check direct mapping
73
+ if (typeMap[withoutConst]) {
74
+ return typeMap[withoutConst];
75
+ }
76
+ // Handle pointers - check if base type is an Arduino type
77
+ if (withoutConst.endsWith("*")) {
78
+ const baseType = withoutConst.slice(0, -1).trim();
79
+ if (ARDUINO_TYPE_MAPPINGS[baseType]) {
80
+ return ARDUINO_TYPE_MAPPINGS[baseType];
81
+ }
82
+ return "number";
83
+ }
84
+ // Handle references - check if base type is an Arduino type
85
+ if (withoutConst.endsWith("&")) {
86
+ const baseType = withoutConst.slice(0, -1).trim();
87
+ if (ARDUINO_TYPE_MAPPINGS[baseType]) {
88
+ return ARDUINO_TYPE_MAPPINGS[baseType];
89
+ }
90
+ return mapCppTypeToTs(baseType);
91
+ }
92
+ // Default to any for unknown types
93
+ return "any";
94
+ }
95
+ // ---------------------------------------------------------------------------
96
+ // Parameter parsing
97
+ // ---------------------------------------------------------------------------
98
+ /**
99
+ * Extracts the parameter list from a function signature.
100
+ */
101
+ export function parseParameters(paramString) {
102
+ if (!paramString.trim()) {
103
+ return [];
104
+ }
105
+ const params = [];
106
+ const parts = paramString.split(",");
107
+ for (const part of parts) {
108
+ const trimmed = part.trim();
109
+ if (!trimmed)
110
+ continue;
111
+ // Handle default values (remove them for the declaration)
112
+ const withoutDefault = trimmed.split("=")[0].trim();
113
+ // Split into tokens to find type and name
114
+ const tokens = withoutDefault.split(/\s+/);
115
+ if (tokens.length >= 2) {
116
+ // Last token is the name, rest is the type
117
+ let name = tokens[tokens.length - 1];
118
+ let type = tokens.slice(0, -1).join(" ");
119
+ // Strip & and * prefixes from parameter names (C++ reference/pointer syntax)
120
+ // These can appear as &name or *name when the type doesn't include them
121
+ if (name.startsWith("&") || name.startsWith("*")) {
122
+ // Move the & or * to the type
123
+ type = type + name[0];
124
+ name = name.slice(1);
125
+ }
126
+ params.push({ type: mapCppTypeToTs(type), name });
127
+ }
128
+ else if (tokens.length === 1) {
129
+ // Just a type (unnamed parameter)
130
+ params.push({ type: mapCppTypeToTs(tokens[0]), name: "" });
131
+ }
132
+ }
133
+ return params;
134
+ }
135
+ // ---------------------------------------------------------------------------
136
+ // Class parsing helpers
137
+ // ---------------------------------------------------------------------------
138
+ /**
139
+ * Extract content inside a namespace block.
140
+ */
141
+ function extractNamespaceContent(content, namespaceName) {
142
+ // Find namespace block: namespace Name { ... }
143
+ const namespaceRegex = new RegExp(`namespace\\s+${namespaceName}\\s*\\{`, 'g');
144
+ const match = namespaceRegex.exec(content);
145
+ if (!match)
146
+ return "";
147
+ const startIndex = match.index + match[0].length;
148
+ let braceCount = 1;
149
+ let endIndex = startIndex;
150
+ while (endIndex < content.length && braceCount > 0) {
151
+ if (content[endIndex] === '{')
152
+ braceCount++;
153
+ else if (content[endIndex] === '}')
154
+ braceCount--;
155
+ endIndex++;
156
+ }
157
+ return content.slice(startIndex, endIndex - 1);
158
+ }
159
+ /**
160
+ * Parse classes from content, optionally within a namespace.
161
+ */
162
+ function parseClassesFromContent(content, namespace) {
163
+ const classes = [];
164
+ // Parse class definitions - handle nested braces properly
165
+ const classStartRegex = /\bclass\s+(\w+)\s*\{?/g;
166
+ let classStartMatch;
167
+ while ((classStartMatch = classStartRegex.exec(content)) !== null) {
168
+ const className = classStartMatch[1];
169
+ const fullName = namespace ? `${namespace}::${className}` : className;
170
+ const cppClass = {
171
+ name: className,
172
+ fullName,
173
+ namespace,
174
+ methods: [],
175
+ constructors: [],
176
+ };
177
+ // For header files, try to find method declarations
178
+ // Match: type name(params);
179
+ const methodRegex = /(\w+(?:\s*[*&])?)\s+(\w+)\s*\(([^)]*)\)\s*(?:const\s*)?;/g;
180
+ let methodMatch;
181
+ while ((methodMatch = methodRegex.exec(content)) !== null) {
182
+ const returnType = methodMatch[1].trim();
183
+ const name = methodMatch[2].trim();
184
+ const params = methodMatch[3];
185
+ // Skip keywords
186
+ if (["public", "private", "protected", "virtual", "static", "class", "struct"].includes(returnType)) {
187
+ continue;
188
+ }
189
+ // Check if this is a constructor (name matches class name)
190
+ if (name === className) {
191
+ cppClass.constructors.push({
192
+ parameters: parseParameters(params),
193
+ });
194
+ }
195
+ else {
196
+ cppClass.methods.push({
197
+ returnType: mapCppTypeToTs(returnType),
198
+ name,
199
+ parameters: parseParameters(params),
200
+ isPublic: true,
201
+ });
202
+ }
203
+ }
204
+ classes.push(cppClass);
205
+ }
206
+ return classes;
207
+ }
208
+ // ---------------------------------------------------------------------------
209
+ // Main parser
210
+ // ---------------------------------------------------------------------------
211
+ /**
212
+ * Parses a C++ class definition from header content.
213
+ */
214
+ export function parseCppClass(content) {
215
+ const result = {
216
+ classes: [],
217
+ constants: [],
218
+ };
219
+ // Parse top-level constants: const int NAME = value;
220
+ const constRegex = /const\s+(\w+)\s+(\w+)\s*=\s*([^;]+);/g;
221
+ let constMatch;
222
+ while ((constMatch = constRegex.exec(content)) !== null) {
223
+ result.constants.push({
224
+ type: mapCppTypeToTs(constMatch[1]),
225
+ name: constMatch[2],
226
+ value: constMatch[3].trim(),
227
+ });
228
+ }
229
+ // Parse methods with scope resolution (ClassName::methodName) - for .cpp implementation files
230
+ const scopeResolutionRegex = /(?:^|\n)\s*(?:(\w+(?:\s*[*&])?)\s+)?(\w+)::(\w+)\s*\(([^)]*)\)\s*(?:const\s*)?(?:\{|;)/g;
231
+ let scopeMatch;
232
+ const classesFromImpl = new Map();
233
+ while ((scopeMatch = scopeResolutionRegex.exec(content)) !== null) {
234
+ const returnType = scopeMatch[1]?.trim();
235
+ const className = scopeMatch[2];
236
+ const methodName = scopeMatch[3];
237
+ const params = scopeMatch[4];
238
+ // Skip if this looks like a namespace (e.g., std::something)
239
+ if (!returnType && className.toLowerCase() === className) {
240
+ continue;
241
+ }
242
+ if (!classesFromImpl.has(className)) {
243
+ classesFromImpl.set(className, {
244
+ name: className,
245
+ fullName: className,
246
+ methods: [],
247
+ constructors: [],
248
+ });
249
+ }
250
+ const cppClass = classesFromImpl.get(className);
251
+ // Check if this is a constructor (method name matches class name)
252
+ if (methodName === className) {
253
+ cppClass.constructors.push({
254
+ parameters: parseParameters(params),
255
+ });
256
+ }
257
+ else if (returnType) {
258
+ cppClass.methods.push({
259
+ returnType: mapCppTypeToTs(returnType),
260
+ name: methodName,
261
+ parameters: parseParameters(params),
262
+ isPublic: true,
263
+ });
264
+ }
265
+ }
266
+ // Add inferred classes to result
267
+ for (const cppClass of classesFromImpl.values()) {
268
+ result.classes.push(cppClass);
269
+ }
270
+ // Parse namespaces first
271
+ const namespaceRegex = /namespace\s+(\w+)\s*\{/g;
272
+ let nsMatch;
273
+ const namespaces = [];
274
+ while ((nsMatch = namespaceRegex.exec(content)) !== null) {
275
+ namespaces.push(nsMatch[1]);
276
+ }
277
+ // Parse classes within each namespace
278
+ for (const ns of namespaces) {
279
+ const nsContent = extractNamespaceContent(content, ns);
280
+ const nsClasses = parseClassesFromContent(nsContent, ns);
281
+ result.classes.push(...nsClasses);
282
+ }
283
+ // Parse classes outside of namespaces (skip if already found in a namespace)
284
+ const namespaceClassNames = new Set(result.classes.map(c => c.name));
285
+ const topLevelClasses = parseClassesFromContent(content);
286
+ for (const cls of topLevelClasses) {
287
+ if (!namespaceClassNames.has(cls.name)) {
288
+ result.classes.push(cls);
289
+ }
290
+ }
291
+ return result;
292
+ }
@@ -0,0 +1,20 @@
1
+ export interface CapturedVariable {
2
+ name: string;
3
+ isFunction?: boolean;
4
+ }
5
+ export interface LogMessagePart {
6
+ type: 'text' | 'variable';
7
+ value: string;
8
+ }
9
+ /**
10
+ * Generate Serial.begin() initialization code for Arduino debug mode.
11
+ */
12
+ export declare function generateSerialInitCode(): string[];
13
+ /**
14
+ * Generate the Serial debug code for a breakpoint.
15
+ */
16
+ export declare function generateBreakpointCode(fileName: string, lineNum: number, originalLine: string, variables: CapturedVariable[], normalizedCondition: string | undefined): string[];
17
+ /**
18
+ * Generate code for a logpoint (logs message without stopping execution).
19
+ */
20
+ export declare function generateLogpointCode(fileName: string, lineNum: number, parts: LogMessagePart[], variables: CapturedVariable[]): string[];
@@ -0,0 +1,115 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Arduino debug code generator — Serial-based debug output
3
+ //
4
+ // Generates Arduino Serial.print/println code for debug breakpoints,
5
+ // logpoints, and initialization. Used by the CLI debug preprocessor.
6
+ // ---------------------------------------------------------------------------
7
+ /**
8
+ * Generate Serial.begin() initialization code for Arduino debug mode.
9
+ */
10
+ export function generateSerialInitCode() {
11
+ return [
12
+ `// === DEBUG: Initialize Serial ===`,
13
+ `Serial.begin(9600);`,
14
+ `while (!Serial) {`,
15
+ ` delay(10);`,
16
+ `}`,
17
+ `Serial.println("🔧 TypeCAD Debug Mode Active");`,
18
+ `Serial.println("");`,
19
+ `// === END DEBUG INIT ===`,
20
+ ``,
21
+ ];
22
+ }
23
+ /**
24
+ * Generate the Serial debug code for a breakpoint.
25
+ */
26
+ export function generateBreakpointCode(fileName, lineNum, originalLine, variables, normalizedCondition) {
27
+ const lines = [];
28
+ // Comment marker
29
+ lines.push(` // === BREAKPOINT: ${fileName}:${lineNum} ===`);
30
+ // If conditional, wrap everything in an if statement
31
+ if (normalizedCondition) {
32
+ lines.push(` if (${normalizedCondition}) {`);
33
+ }
34
+ // Visual separator
35
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");`);
36
+ // Breakpoint header (with condition indicator if present)
37
+ const headerText = normalizedCondition
38
+ ? `⏸️ BREAKPOINT: ${fileName}:${lineNum} (condition: ${escapeString(normalizedCondition)})`
39
+ : `⏸️ BREAKPOINT: ${fileName}:${lineNum}`;
40
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println("${headerText}");`);
41
+ // Original source line (escaped)
42
+ const escapedLine = escapeString(originalLine);
43
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println(" ${escapedLine}");`);
44
+ // Blank line
45
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println("");`);
46
+ // Variables section
47
+ if (variables.length > 0) {
48
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println(" Variables:");`);
49
+ for (const v of variables) {
50
+ if (v.isFunction) {
51
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println(" • ${v.name} = [function]");`);
52
+ }
53
+ else {
54
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.print(" • ${v.name} = "); Serial.println(${v.name});`);
55
+ }
56
+ }
57
+ }
58
+ else {
59
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println(" (no variables in scope)");`);
60
+ }
61
+ // Blank line
62
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println("");`);
63
+ // Continue prompt
64
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println(" [Press ENTER to continue...]");`);
65
+ // Visual separator (end)
66
+ lines.push(` ${normalizedCondition ? ' ' : ''}Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");`);
67
+ // Blocking wait for serial input
68
+ lines.push(` ${normalizedCondition ? ' ' : ''}while(Serial.available() == 0) { delay(10); }`);
69
+ lines.push(` ${normalizedCondition ? ' ' : ''}while(Serial.available() > 0) { Serial.read(); delay(10); }`);
70
+ // Close conditional if statement
71
+ if (normalizedCondition) {
72
+ lines.push(` }`);
73
+ }
74
+ // End marker
75
+ lines.push(` // === END BREAKPOINT ===`);
76
+ return lines;
77
+ }
78
+ /**
79
+ * Generate code for a logpoint (logs message without stopping execution).
80
+ */
81
+ export function generateLogpointCode(fileName, lineNum, parts, variables) {
82
+ const lines = [];
83
+ // Comment marker
84
+ lines.push(` // === LOGPOINT: ${fileName}:${lineNum} ===`);
85
+ // Build the Serial output
86
+ lines.push(` Serial.print("[LOG ${fileName}:${lineNum}] ");`);
87
+ for (const part of parts) {
88
+ if (part.type === 'text') {
89
+ lines.push(` Serial.print("${escapeString(part.value)}");`);
90
+ }
91
+ else if (part.type === 'variable') {
92
+ // Check if the variable exists in scope
93
+ const varExists = variables.some(v => v.name === part.value && !v.isFunction);
94
+ if (varExists) {
95
+ lines.push(` Serial.print(${part.value});`);
96
+ }
97
+ else {
98
+ lines.push(` Serial.print("{${part.value}}"); // variable not in scope`);
99
+ }
100
+ }
101
+ }
102
+ lines.push(` Serial.println("");`);
103
+ lines.push(` // === END LOGPOINT ===`);
104
+ return lines;
105
+ }
106
+ /**
107
+ * Escape a string for use in Serial.println("...").
108
+ */
109
+ function escapeString(s) {
110
+ return s
111
+ .replace(/\\/g, '\\\\')
112
+ .replace(/"/g, '\\"')
113
+ .replace(/\n/g, '\\n')
114
+ .replace(/\r/g, '\\r');
115
+ }
@@ -0,0 +1,6 @@
1
+ import type { DisplayProfile } from "@typecad/cuttlefish/api/shared";
2
+ export declare const ILI9341_SPI: DisplayProfile;
3
+ /** Registry of all built-in profiles. Keyed by profile name. */
4
+ export declare const BUILT_IN_PROFILES: Record<string, DisplayProfile>;
5
+ /** Get the registry as a Map (for resolveDisplayProfile). */
6
+ export declare function getProfileRegistry(): Map<string, DisplayProfile>;
@@ -0,0 +1,28 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Built-in display profiles for @typecad/framework-arduino.
3
+ //
4
+ // Each profile describes a common display's capabilities. Projects reference
5
+ // them by name in cuttlefish.config.ts:
6
+ // display: { profile: 'ili9341-spi', cs: 5, dc: 21, rst: 22 }
7
+ // ---------------------------------------------------------------------------
8
+ import { SSD1309_I2C } from "./ssd1309-i2c.js";
9
+ import { ST7796_SPI } from "./st7796-spi.js";
10
+ export const ILI9341_SPI = {
11
+ driver: "ili9341",
12
+ width: 320,
13
+ height: 240,
14
+ colorFormat: "rgb565",
15
+ rotation: 1,
16
+ backlight: 17,
17
+ spiPins: { mosi: 23, sck: 18, miso: 19 },
18
+ };
19
+ /** Registry of all built-in profiles. Keyed by profile name. */
20
+ export const BUILT_IN_PROFILES = {
21
+ "ili9341-spi": ILI9341_SPI,
22
+ "st7796-spi": ST7796_SPI,
23
+ "ssd1309-i2c": SSD1309_I2C,
24
+ };
25
+ /** Get the registry as a Map (for resolveDisplayProfile). */
26
+ export function getProfileRegistry() {
27
+ return new Map(Object.entries(BUILT_IN_PROFILES));
28
+ }
@@ -0,0 +1,2 @@
1
+ import type { DisplayProfile } from "@typecad/cuttlefish/api/shared";
2
+ export declare const SSD1309_I2C: DisplayProfile;
@@ -0,0 +1,16 @@
1
+ // ---------------------------------------------------------------------------
2
+ // SSD1309 OLED display profile — 128×64 1-bit monochrome OLED over I2C.
3
+ //
4
+ // The Adafruit_SSD1306 library drives SSD1309-class panels via the same API.
5
+ // displayClass: "oled" uses the same deferred, backing-store mono capability
6
+ // path as e-ink panels (UI_NATIVE_MONO + UI_REQUIRES_BACKING_STORE), while
7
+ // keeping the profile semantically accurate for page-buffered OLED hardware.
8
+ // ---------------------------------------------------------------------------
9
+ export const SSD1309_I2C = {
10
+ driver: "ssd1309",
11
+ width: 128,
12
+ height: 64,
13
+ colorFormat: "mono",
14
+ displayClass: "oled",
15
+ rotation: 0,
16
+ };
@@ -0,0 +1,2 @@
1
+ import type { DisplayProfile } from "@typecad/cuttlefish/api/shared";
2
+ export declare const ST7796_SPI: DisplayProfile;
@@ -0,0 +1,20 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Built-in profile for the ST7796S 320×480 SPI TFT.
3
+ //
4
+ // Targets the Adafruit_ST7735_and_ST7789_Library fork that exposes the
5
+ // Adafruit_ST7796S class. RGB565 (the library hardcodes 565 in its init
6
+ // sequence; see display-adapters/st7796.ts for the 666 constraint).
7
+ //
8
+ // Reference usage in cuttlefish.config.ts:
9
+ // display: { profile: 'st7796-spi', cs: 5, dc: 17, rst: 16 }
10
+ // ---------------------------------------------------------------------------
11
+ export const ST7796_SPI = {
12
+ driver: "st7796",
13
+ width: 480,
14
+ height: 320,
15
+ nativeWidth: 320,
16
+ nativeHeight: 480,
17
+ colorFormat: "rgb565",
18
+ rotation: 1, // landscape → effective 480×320
19
+ spiPins: { mosi: 23, sck: 18, miso: 19 },
20
+ };
@@ -0,0 +1,24 @@
1
+ import type { DisplayHALOp } from "@typecad/cuttlefish/api/shared";
2
+ /** Display-side object variable name (instantiated by display.init). */
3
+ export declare const DISPLAY_VAR = "__tc_display";
4
+ /** The library's required headers — emitted as forced includes. */
5
+ export declare const ILI9341_INCLUDES: string[];
6
+ export interface ILI9341Context {
7
+ bus: string;
8
+ cs: number;
9
+ dc: number;
10
+ rst: number;
11
+ width: number;
12
+ height: number;
13
+ rotation?: number;
14
+ backlight?: number;
15
+ spiFrequency?: number;
16
+ }
17
+ /**
18
+ * Resolve a display HAL op to a method call on the Adafruit_ILI9341 object.
19
+ * Returns undefined for ops this driver does not handle.
20
+ */
21
+ export declare function resolveILI9341Op(op: DisplayHALOp, ctx: ILI9341Context): {
22
+ code?: string;
23
+ expression?: string;
24
+ } | undefined;
@@ -0,0 +1,59 @@
1
+ // ---------------------------------------------------------------------------
2
+ // ILI9341 — display driver resolver built on the Adafruit_ILI9341 library.
3
+ //
4
+ // Maps each DisplayHALOp to a method call on a library-instantiated
5
+ // Adafruit_ILI9341 object. The library owns SPI, command sequences, fonts,
6
+ // and glyph rendering — we own the tree, layout, and reactive driver.
7
+ //
8
+ // The framework instantiates one library object per mount; ui.mount's
9
+ // display.init emits the constructor + begin() + setRotation(), and
10
+ // subsequent ops reference the same object by name (__tc_display).
11
+ // ---------------------------------------------------------------------------
12
+ /** Display-side object variable name (instantiated by display.init). */
13
+ export const DISPLAY_VAR = "__tc_display";
14
+ /** The library's required headers — emitted as forced includes. */
15
+ export const ILI9341_INCLUDES = ["<Adafruit_GFX.h>", "<Adafruit_ILI9341.h>"];
16
+ /** Render a color value as a C++ hex literal (e.g. 0x07e0) for readable RGB565. */
17
+ function hexColor(c) {
18
+ return `0x${c.toString(16)}`;
19
+ }
20
+ /**
21
+ * Resolve a display HAL op to a method call on the Adafruit_ILI9341 object.
22
+ * Returns undefined for ops this driver does not handle.
23
+ */
24
+ export function resolveILI9341Op(op, ctx) {
25
+ switch (op.operation) {
26
+ case "display.init":
27
+ return {
28
+ code: [
29
+ ctx.backlight ? `pinMode(${ctx.backlight}, OUTPUT); digitalWrite(${ctx.backlight}, HIGH);` : ``,
30
+ `display_init();`,
31
+ ].filter(Boolean).join("\n"),
32
+ };
33
+ case "display.fill_rect":
34
+ // Adafruit_GFX fillRect(x, y, w, h, color) — color is uint16 RGB565.
35
+ return {
36
+ code: `${DISPLAY_VAR}.fillRect(${op.x}, ${op.y}, ${op.w}, ${op.h}, ${hexColor(op.color)});`,
37
+ };
38
+ case "display.draw_rect":
39
+ return {
40
+ code: `${DISPLAY_VAR}.drawRect(${op.x}, ${op.y}, ${op.w}, ${op.h}, ${hexColor(op.color)});`,
41
+ };
42
+ case "display.draw_text":
43
+ // Set cursor + color + size, then print. print() is the Print mixin
44
+ // (not in the auto-gen d.ts but present on the real C++ object).
45
+ return {
46
+ code: [
47
+ `${DISPLAY_VAR}.setCursor(${op.x}, ${op.y});`,
48
+ `${DISPLAY_VAR}.setTextColor(${hexColor(op.color)});`,
49
+ `${DISPLAY_VAR}.setTextSize(2);`,
50
+ `${DISPLAY_VAR}.print(${JSON.stringify(op.text)});`,
51
+ ].join("\n"),
52
+ };
53
+ case "display.flush":
54
+ // ILI9341 is immediate — draws go straight to the panel. No flush.
55
+ return { code: `/* flush: ${op.rects.length} rect(s) — immediate draw */` };
56
+ default:
57
+ return undefined;
58
+ }
59
+ }
@@ -0,0 +1,13 @@
1
+ export { ArduinoStrategy } from './strategy.js';
2
+ export { ArduinoStrategy as FrameworkStrategy } from './strategy.js';
3
+ export { flattenGeneratedModulesIntoSketch, compileArduinoSketch, uploadArduinoSketch, monitorArduinoSketch, } from './arduino-compile.js';
4
+ import { flattenGeneratedModulesIntoSketch } from './arduino-compile.js';
5
+ export declare const Toolchain: {
6
+ prepare: typeof flattenGeneratedModulesIntoSketch;
7
+ compile: (options: any) => import("@typecad/cuttlefish/api").CompileResult;
8
+ upload: (options: any) => import("@typecad/cuttlefish/api").UploadResult;
9
+ monitor: (options: any) => void;
10
+ };
11
+ export { isArduinoLibraryImport as isFrameworkLibraryImport, getArduinoLibraryHeaderName as getFrameworkLibraryHeaderName } from './arduino-libs.js';
12
+ export { tryGenerateArduinoLibDecl as tryGenerateLibDecl } from './arduino-libs.js';
13
+ export { buildArduinoClassNameMap as buildClassNameMap } from './arduino-class-map.js';
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ // ---------------------------------------------------------------------------
2
+ // @typecad/framework-arduino — Arduino framework strategy
3
+ //
4
+ // Provides the ArduinoStrategy implementation for Arduino framework code
5
+ // generation. This is the main entry point for the framework-arduino package.
6
+ // ---------------------------------------------------------------------------
7
+ // Export the main strategy class
8
+ export { ArduinoStrategy } from './strategy.js';
9
+ // Export as FrameworkStrategy for consistency with framework package naming
10
+ export { ArduinoStrategy as FrameworkStrategy } from './strategy.js';
11
+ // Arduino compile/upload/monitor
12
+ export { flattenGeneratedModulesIntoSketch, compileArduinoSketch, uploadArduinoSketch, monitorArduinoSketch, } from './arduino-compile.js';
13
+ // Toolchain object for the framework registry
14
+ import { flattenGeneratedModulesIntoSketch, compileArduinoSketch, uploadArduinoSketch, monitorArduinoSketch } from './arduino-compile.js';
15
+ export const Toolchain = {
16
+ prepare: flattenGeneratedModulesIntoSketch,
17
+ compile: (options) => compileArduinoSketch(options.sourcePath, options.buildTarget, {
18
+ extraFlags: options.extraFlags,
19
+ defines: options.defines,
20
+ }),
21
+ upload: (options) => uploadArduinoSketch(options.outputDir, options.buildTarget, options.port),
22
+ monitor: (options) => monitorArduinoSketch(options.port, options.baud),
23
+ };
24
+ // Library discovery — consumed by the transpiler's dynamic module loader
25
+ export { isArduinoLibraryImport as isFrameworkLibraryImport, getArduinoLibraryHeaderName as getFrameworkLibraryHeaderName } from './arduino-libs.js';
26
+ export { tryGenerateArduinoLibDecl as tryGenerateLibDecl } from './arduino-libs.js';
27
+ export { buildArduinoClassNameMap as buildClassNameMap } from './arduino-class-map.js';