Skip to content

Conversation

JoaoGSP
Copy link
Member

@JoaoGSP JoaoGSP commented Aug 23, 2025

Summary by CodeRabbit

  • New Features
    • Added an option to auto-generate C glue code from a located-variables header, producing a module that wires inputs, outputs and memory buffers and advances time.
    • Added a CLI flag to invoke glue-generation with clear success/error feedback and progress messages.
    • Generated output uses a template for declarations, bindings and platform-specific buffering to simplify PLC-to-C integration.
  • Chore
    • Improved CLI argument presentation for better usability.

Copy link

coderabbitai bot commented Aug 23, 2025

Walkthrough

Adds a GlueGenerator module using Jinja2 to render glueVars.c from LOCATED_VARIABLES.h entries, a Jinja2 template for the generated C glue, and a CLI integration in xml2st.py to generate and write glueVars.c from a LOCATED_VARIABLES.h file.

Changes

Cohort / File(s) Summary
Glue generation module
GlueGenerator.py
New GlueGenerator class that loads templates from a neighboring templates dir, parses __LOCATED_VAR(...) lines, computes per-variable glue snippets (pointer/index derivation by kind/subtype), and renders templates/glueVars.c.j2, returning the generated C source.
C template for glue
templates/glueVars.c.j2
New Jinja2 template that emits a generated glueVars.c containing global state, platform-conditional buffer pointer definitions, setBufferPointers(...), glueVars() loop that inserts per-variable glue code, updateTime(), and LOCATED_VARIABLES declarations.
CLI integration
xml2st.py
Adds generate_gluevars(located_vars_file) which reads LOCATED_VARIABLES.h, invokes GlueGenerator.generate_glue_variables, writes glueVars.c next to the input, and a new CLI option --generate-gluevars wired into the main flow with basic validation and messaging.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant CLI as xml2st.py (CLI)
  participant FS as Filesystem
  participant GG as GlueGenerator
  participant T as Jinja2 Template

  U->>CLI: run --generate-gluevars LOCATED_VARIABLES.h
  CLI->>FS: read LOCATED_VARIABLES.h
  FS-->>CLI: located_vars_lines
  CLI->>GG: generate_glue_variables(lines)
  GG->>GG: parse lines, compute glue_code (warn/skip non-matches)
  GG->>T: render templates/glueVars.c.j2 with vars
  T-->>GG: rendered glueVars.c
  GG-->>CLI: return glue source
  CLI->>FS: write glueVars.c (same dir)
  FS-->>CLI: write OK
  CLI-->>U: success / error message
Loading
sequenceDiagram
  autonumber
  participant App as Host App
  participant GV as glueVars.c (generated)

  App->>GV: setBufferPointers(...)   %% bind external buffers
  App->>GV: glueVars()               %% execute generated wiring
  App->>GV: updateTime()             %% advance __CURRENT_TIME
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I nudge the wires with whiskered care,
From LOCATED lines to C we share;
Templates hum, the glue takes flight,
Buffers bound and time set right.
Thump-thump—commit hops in with glee.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Generate-glue-vars

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (12)
xml2st.py (4)

9-9: Import path may break when installed as a package; consider relative import

If xml2st.py and GlueGenerator.py live in the same package, absolute import without a package prefix can break when installed or executed from a different CWD. Prefer a relative import.

Apply this diff if xml2st.py is inside a package:

-from GlueGenerator import GlueGenerator
+from .GlueGenerator import GlueGenerator

101-128: Return the output path and write with explicit encoding and Unix newlines

The helper currently prints but doesn’t return the generated file path. Returning it improves composability/tests. Also, read/write with explicit UTF-8 and normalize line endings for deterministic builds.

Apply this diff:

-def generate_gluevars(located_vars_file):
+def generate_gluevars(located_vars_file) -> str:
@@
-    with open(located_vars_file, "r") as f:
+    with open(located_vars_file, "r", encoding="utf-8") as f:
         located_vars = f.readlines()
@@
-    with open(glue_vars_file, "w") as f:
-        f.write(glueVars)
+    with open(glue_vars_file, "w", encoding="utf-8", newline="\n") as f:
+        f.write(glueVars)
@@
-    print(f"Glue variables saved to {glue_vars_file}")
+    print(f"Glue variables saved to {glue_vars_file}")
+    return glue_vars_file

122-124: Consider guarding against partial writes

If the process is interrupted while writing, glueVars.c may be left truncated. Writing to a temp file and atomic rename reduces risk.

I can provide a temp-write + atomic replace snippet if you want to harden this path.


191-199: Propagate the generated path and fail fast on None

If generate_gluevars() returns None due to earlier validation, the CLI still prints “Generating glue variables...” then exits. Capture and validate the return for clearer UX.

Apply this diff after adopting the return value:

-            print("Generating glue variables...")
-            generate_gluevars(args.generate_gluevars)
+            print("Generating glue variables...")
+            out = generate_gluevars(args.generate_gluevars)
+            if not out:
+                raise RuntimeError("No glue file produced")
+            print(f"Done: {out}")
GlueGenerator.py (5)

13-15: Template loader path: OK; consider trimming blocks for cleaner output

The loader root is correct. You can reduce extraneous whitespace in generated C by enabling trim_blocks and lstrip_blocks on the Environment.

Apply this diff (paired with the env creation below):

-        self.__loader = FileSystemLoader(os.path.join(paths.AbsDir(__file__), "templates"))
+        self.__loader = FileSystemLoader(os.path.join(paths.AbsDir(__file__), "templates"))

And later:

-        env = Environment(loader=self.__loader)
+        env = Environment(loader=self.__loader, trim_blocks=True, lstrip_blocks=True)

21-29: Preserve original traceback using exception chaining

Re-raising without chaining drops the original stack, making debugging harder. Chain the exception to keep context. Also tighten the parsing to guard against unexpected prefixes.

Apply this diff:

-        try:
-            parts = varName.split("_")
-            pos1 = int(parts[2][2:])  # number after QX0 or QW0
-            pos2 = int(parts[3]) if len(parts) > 3 else 0
-        except Exception as e:
-            raise Exception(f"Error parsing variable name '{varName}': {e}")
+        try:
+            parts = varName.split("_")
+            # Expect names like __QX0_0 or __QW10
+            if len(parts) < 3 or not varName.startswith("__") or len(parts[2]) < 3:
+                raise ValueError(f"Unexpected located var shape: '{varName}'")
+            pos1 = int(parts[2][2:])  # number after QX0 or QW0
+            pos2 = int(parts[3]) if len(parts) > 3 else 0
+        except Exception as e:
+            raise Exception(f"Error parsing variable name '{varName}': {e}") from e

30-65: Collapse nested if/elif into a data-driven map

A lookup table reduces branching and future maintenance errors, and aligns with the Ruff hint (SIM116).

Apply this diff:

-        kind = varName[2]  # I, Q, M
-        sub  = varName[3]  # X, B, W, D, L
-
-        if kind == 'I':
-            if sub == 'X':
-                return f"bool_input_ptr[{pos1}][{pos2}] = (IEC_BOOL *){varName};"
-            elif sub == 'B':
-                return f"byte_input_ptr[{pos1}] = (IEC_BYTE *){varName};"
-            elif sub == 'W':
-                return f"int_input_ptr[{pos1}] = (IEC_UINT *){varName};"
-            elif sub == 'D':
-                return f"dint_input_ptr[{pos1}] = (IEC_UDINT *){varName};"
-            elif sub == 'L':
-                return f"lint_input_ptr[{pos1}] = (IEC_ULINT *){varName};"
-
-        elif kind == 'Q':
-            if sub == 'X':
-                return f"bool_output_ptr[{pos1}][{pos2}] = (IEC_BOOL *){varName};"
-            elif sub == 'B':
-                return f"byte_output_ptr[{pos1}] = (IEC_BYTE *){varName};"
-            elif sub == 'W':
-                return f"int_output_ptr[{pos1}] = (IEC_UINT *){varName};"
-            elif sub == 'D':
-                return f"dint_output_ptr[{pos1}] = (IEC_UDINT *){varName};"
-            elif sub == 'L':
-                return f"lint_output_ptr[{pos1}] = (IEC_ULINT *){varName};"
-
-        elif kind == 'M':
-            if sub == 'W':
-                return f"int_memory_ptr[{pos1}] = (IEC_UINT *){varName};"
-            elif sub == 'D':
-                return f"dint_memory_ptr[{pos1}] = (IEC_UDINT *){varName};"
-            elif sub == 'L':
-                return f"lint_memory_ptr[{pos1}] = (IEC_ULINT *){varName};"
-
-        raise Exception(f"Unhandled variable type: {varName}")
+        kind = varName[2]  # I, Q, M
+        sub  = varName[3]  # X, B, W, D, L
+
+        table = {
+            'I': {
+                'X': "bool_input_ptr[{p1}][{p2}] = (IEC_BOOL *){vn};",
+                'B': "byte_input_ptr[{p1}] = (IEC_BYTE *){vn};",
+                'W': "int_input_ptr[{p1}] = (IEC_UINT *){vn};",
+                'D': "dint_input_ptr[{p1}] = (IEC_UDINT *){vn};",
+                'L': "lint_input_ptr[{p1}] = (IEC_ULINT *){vn};",
+            },
+            'Q': {
+                'X': "bool_output_ptr[{p1}][{p2}] = (IEC_BOOL *){vn};",
+                'B': "byte_output_ptr[{p1}] = (IEC_BYTE *){vn};",
+                'W': "int_output_ptr[{p1}] = (IEC_UINT *){vn};",
+                'D': "dint_output_ptr[{p1}] = (IEC_UDINT *){vn};",
+                'L': "lint_output_ptr[{p1}] = (IEC_ULINT *){vn};",
+            },
+            'M': {
+                'W': "int_memory_ptr[{p1}] = (IEC_UINT *){vn};",
+                'D': "dint_memory_ptr[{p1}] = (IEC_UDINT *){vn};",
+                'L': "lint_memory_ptr[{p1}] = (IEC_ULINT *){vn};",
+            },
+        }
+        try:
+            fmt = table[kind][sub]
+            return fmt.format(p1=pos1, p2=pos2, vn=varName)
+        except KeyError:
+            raise Exception(f"Unhandled variable type: {varName}")

72-77: Pre-compile the regex for speed and clarity; allow leading whitespace

Minor perf/readability win; avoids recompiling per line and tolerates indentation in headers.

Apply this diff:

-        m = re.match(r"__LOCATED_VAR\(([^,]+),([^,]+),.*\)", line.strip())
+        # Precompiled at module scope:
+        # LOCATED_RE = re.compile(r"\s*__LOCATED_VAR\(([^,]+),([^,]+),.*\)")
+        m = LOCATED_RE.match(line)

And at the top-level:

+LOCATED_RE = re.compile(r"\s*__LOCATED_VAR\(([^,]+),([^,]+),.*\)")

79-92: Environment construction: enable block trimming and consider stable ordering

Good use of Jinja2. If deterministic output is desired, sort parsed by name to avoid diff churn across runs with different header orders.

Apply this diff:

-        parsed = []
-        for line in located_vars_lines:
-            entry = self.__parse_line(line)
-            if entry is not None:
-                parsed.append(entry)
+        parsed = []
+        for line in located_vars_lines:
+            entry = self.__parse_line(line)
+            if entry is not None:
+                parsed.append(entry)
+        # Keep output stable
+        parsed.sort(key=lambda e: e["name"])
@@
-        env = Environment(loader=self.__loader)
+        env = Environment(loader=self.__loader, trim_blocks=True, lstrip_blocks=True)
templates/glueVars.c.j2 (3)

15-16: Make BUFFER_SIZE configurable or documented

A hardcoded 1024 may not match target hardware layouts. Consider parameterizing via a Jinja variable with a sensible default or document the assumption in the header.

Example:

-#define BUFFER_SIZE		1024
+#ifndef BUFFER_SIZE
+#define BUFFER_SIZE 1024
+#endif

21-44: Pointer declarations are correct but non-idiomatic for non-boolean channels

The IEC_BYTE *(*byte_input_ptr) style is equivalent to IEC_BYTE **byte_input_ptr but less readable. Consider using the double-pointer form for non-boolean channels for consistency.

Apply this diff:

-static IEC_BYTE *(*byte_input_ptr) = NULL;
-static IEC_BYTE *(*byte_output_ptr) = NULL;
+static IEC_BYTE **byte_input_ptr = NULL;
+static IEC_BYTE **byte_output_ptr = NULL;
@@
-static IEC_UINT *(*int_input_ptr) = NULL;
-static IEC_UINT *(*int_output_ptr) = NULL;
+static IEC_UINT **int_input_ptr = NULL;
+static IEC_UINT **int_output_ptr = NULL;
@@
-static IEC_UDINT *(*dint_input_ptr) = NULL;
-static IEC_UDINT *(*dint_output_ptr) = NULL;
+static IEC_UDINT **dint_input_ptr = NULL;
+static IEC_UDINT **dint_output_ptr = NULL;
@@
-static IEC_ULINT *(*lint_input_ptr) = NULL;
-static IEC_ULINT *(*lint_output_ptr) = NULL;
+static IEC_ULINT **lint_input_ptr = NULL;
+static IEC_ULINT **lint_output_ptr = NULL;
@@
-static IEC_UINT *(*int_memory_ptr) = NULL;
-static IEC_UDINT *(*dint_memory_ptr) = NULL;
-static IEC_ULINT *(*lint_memory_ptr) = NULL;
+static IEC_UINT **int_memory_ptr = NULL;
+static IEC_UDINT **dint_memory_ptr = NULL;
+static IEC_ULINT **lint_memory_ptr = NULL;

This keeps assignments in setBufferPointers valid due to parameter decay rules.


52-73: API surface looks coherent; consider basic null checks in debug builds

If any buffer pointer is NULL, subsequent glue code may dereference them. Optional runtime guards (even under a DEBUG macro) can help catch integration issues early.

Example:

 void setBufferPointers(IEC_BOOL *input_bool[BUFFER_SIZE][8], IEC_BOOL *output_bool[BUFFER_SIZE][8],
@@
 {
+#ifdef DEBUG
+    if (!input_bool || !output_bool || !input_byte || !output_byte ||
+        !input_int || !output_int || !input_dint || !output_dint ||
+        !input_lint || !output_lint || !int_memory || !dint_memory || !lint_memory) {
+        // Intentional crash in debug to surface wiring mistakes early
+        __builtin_trap();
+    }
+#endif
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dbeaf2f and 5ccca70.

📒 Files selected for processing (3)
  • GlueGenerator.py (1 hunks)
  • templates/glueVars.c.j2 (1 hunks)
  • xml2st.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
xml2st.py (1)
GlueGenerator.py (2)
  • GlueGenerator (11-91)
  • generate_glue_variables (79-91)
GlueGenerator.py (1)
util/paths.py (1)
  • AbsDir (36-37)
🪛 Ruff (0.12.2)
GlueGenerator.py

28-28: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


34-43: Use a dictionary instead of consecutive if statements

(SIM116)


46-55: Use a dictionary instead of consecutive if statements

(SIM116)


58-63: Use a dictionary instead of consecutive if statements

(SIM116)

🔇 Additional comments (5)
xml2st.py (2)

133-138: Argparse metavar usage is correct; nice UX improvement

Using a single-string metavar improves --help output without changing behavior. All good here.


146-151: Good: isolates glue generation as its own CLI entry

Clear help text and argument name. Consider adding a brief example in README in a follow-up.

templates/glueVars.c.j2 (3)

45-51: Double-include pattern looks good; verify include path

Relying on a quoted relative include assumes glueVars.c and LOCATED_VARIABLES.h sit side by side, which xml2st.generate_gluevars() satisfies. LGTM.


75-80: Emitting glue code: ensure trailing semicolons are present in all variants

Current generator returns statements with ;. If future glue snippets ever omit ;, the template may generate invalid C. Safe as-is; just a note for future edits.

Would you like me to add a simple CI check that compiles the rendered glue with a stub to catch such regressions?


82-92: Time update logic is correct; add comments on time units

common_ticktime__ appears to be in nanoseconds; the normalization is correct. Adding a brief comment helps future maintainers.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
templates/glueVars.c.j2 (3)

24-61: Risk of missing memory buffers on tiny AVR targets; add safe 1-length arrays to keep glue uniform.

On the AVR subset (Line 27), MAX_MEMORY_* are 0 and no memory arrays are declared. If any located %M* variables appear, generated glue will reference missing symbols and fail to link. Add zero-safe dims so arrays always exist.

Proposed patch:

 #ifdef ARDUINO

     //OpenPLC Buffers
+    // Avoid zero-length arrays on tiny AVRs when MAX_MEMORY_* == 0
+    #define DIM_OR_ONE(n) ((n) > 0 ? (n) : 1)
     #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
@@
-        #define MAX_MEMORY_WORD            0
-        #define MAX_MEMORY_DWORD           0
-        #define MAX_MEMORY_LWORD           0
+        #define MAX_MEMORY_WORD            0
+        #define MAX_MEMORY_DWORD           0
+        #define MAX_MEMORY_LWORD           0
@@
-        IEC_UINT *int_output[MAX_ANALOG_OUTPUT];
+        IEC_UINT *int_output[MAX_ANALOG_OUTPUT];
+        // Provide memory arrays even if size is 0 to keep glue code uniform
+        IEC_UINT  *int_memory[DIM_OR_ONE(MAX_MEMORY_WORD)];
+        IEC_UDINT *dint_memory[DIM_OR_ONE(MAX_MEMORY_DWORD)];
+        IEC_ULINT *lint_memory[DIM_OR_ONE(MAX_MEMORY_LWORD)];

62-93: Unify symbol names across platforms to simplify glue generation.

Arduino path exposes bool_input/int_input/... while non-Arduino exposes *_ptr. Alias the non-Arduino pointers to Arduino-style names so a single glue emission works for both.

Proposed patch:

 #else

     #define BUFFER_SIZE		1024
@@
     static IEC_ULINT *(*lint_memory_ptr) = NULL;

+    // Alias non-Arduino pointer variables to Arduino-style names
+    #define bool_input   bool_input_ptr
+    #define bool_output  bool_output_ptr
+    #define byte_input   byte_input_ptr
+    #define byte_output  byte_output_ptr
+    #define int_input    int_input_ptr
+    #define int_output   int_output_ptr
+    #define dint_input   dint_input_ptr
+    #define dint_output  dint_output_ptr
+    #define lint_input   lint_input_ptr
+    #define lint_output  lint_output_ptr
+    #define int_memory   int_memory_ptr
+    #define dint_memory  dint_memory_ptr
+    #define lint_memory  lint_memory_ptr

94-116: Document call order and consider basic pointer guards in setBufferPointers.

glueVars() assumes these are set; a brief comment and light sanity checks prevent hard-to-debug NULL derefs.

Proposed patch:

-    void setBufferPointers(IEC_BOOL *input_bool[BUFFER_SIZE][8], IEC_BOOL *output_bool[BUFFER_SIZE][8],
+    // Must be called once at startup before glueVars() is ever invoked.
+    void setBufferPointers(IEC_BOOL *input_bool[BUFFER_SIZE][8], IEC_BOOL *output_bool[BUFFER_SIZE][8],
                             IEC_BYTE *input_byte[BUFFER_SIZE], IEC_BYTE *output_byte[BUFFER_SIZE],
@@
-    {
+    {
+        // minimal guards in debug builds
+        #ifdef DEBUG
+        if (!input_bool || !output_bool || !input_int || !output_int) { return; }
+        #endif
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5ccca70 and 7c23543.

📒 Files selected for processing (1)
  • templates/glueVars.c.j2 (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-windows-arm
🔇 Additional comments (3)
templates/glueVars.c.j2 (3)

11-18: Two-pass __LOCATED_VAR include pattern looks correct.

Macro varargs and the two-pass trick to define storage then pointers is sound.


125-135: Time accumulator logic is correct.

Carry handling and 64-bit math look good.


118-124: Confirm generated glueVars.c references only supported symbols

The initial grep check failed because glueVars.c wasn’t present—this template must first be rendered by the GlueGenerator. Please generate the C output and then verify that no byte-input/output or memory array symbols appear unguarded:

• Render the Jinja2 template (e.g. via your build or a standalone script) to produce glueVars.c.
• Run:

rg -nP '(\bbyte_input(_ptr)?\b|\bbyte_output(_ptr)?\b|\bint_memory(_ptr)?\b|\bdint_memory(_ptr)?\b|\blint_memory(_ptr)?\b)' path/to/generated/glueVars.c -n

• Confirm the output is empty (i.e., no unsupported symbols). If any matches remain, ensure they’re wrapped by the alias macros (non-Arduino) or use the DIM_OR_ONE fix (Arduino AVR) so that both AVR tiny and standard AVR targets compile cleanly.
• If you encounter any unresolved references afterward, update the generator or template accordingly.

@thiagoralves thiagoralves self-requested a review August 27, 2025 22:00
@thiagoralves thiagoralves merged commit b88005b into development Aug 27, 2025
7 checks passed
@thiagoralves thiagoralves deleted the Generate-glue-vars branch August 27, 2025 22:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants