Skip to content

Altminimum#25

Closed
soburi wants to merge 61 commits intonextfrom
altminimum
Closed

Altminimum#25
soburi wants to merge 61 commits intonextfrom
altminimum

Conversation

@soburi
Copy link
Copy Markdown
Owner

@soburi soburi commented Feb 24, 2026

Copilot AI review requested due to automatic review settings February 24, 2026 22:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an alternate (“alt”) Arduino Core API implementation path that is enabled via CONFIG_USE_ARDUINO_API_RUST_IMPLEMENTATION, including a Rust staticlib and a protobuf/IDL-driven C++ header generation toolchain.

Changes:

  • Add alt_core_api/ build integration (Rust staticlib + IDL-driven C++ interface header generation).
  • Introduce protoc-gen-arduinoif generator (models, renderers, templates) with unit tests and documentation.
  • Adjust samples/config/build plumbing (e.g., enable alt implementation in Arduino samples, gate Wire on CONFIG_I2C).

Reviewed changes

Copilot reviewed 44 out of 47 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
samples/hello_arduino/prj.conf Enables alt Rust implementation and disables I2C for the sample.
samples/blinky_arduino/prj.conf Enables alt Rust implementation for the sample.
libraries/Wire/CMakeLists.txt Only builds Wire.cpp when CONFIG_I2C is enabled.
documentation/idl_codegen.md Adds an IDL/codegen manual for protoc-gen-arduinoif.
cores/arduino/zephyrPrint.h Removes the prior Zephyr Print inline header implementation.
cores/arduino/zephyrCommon.cpp Fixes integer type in tone() count clamp.
cores/arduino/apiCommon.cpp Removes C++ wrappers for map() / makeWord() used by the alt path previously.
cores/arduino/CMakeLists.txt Removes Rust-path include/source wiring (now moved under alt_core_api/).
alt_core_api/tools/protoc_gen_arduinoif/tests/test_service_model.py Adds service model builder/renderer tests.
alt_core_api/tools/protoc_gen_arduinoif/tests/test_request_context.py Adds RequestContext tests.
alt_core_api/tools/protoc_gen_arduinoif/tests/test_renderer_templates.py Adds template rendering tests.
alt_core_api/tools/protoc_gen_arduinoif/tests/test_options_reader.py Adds tests for reading proto extensions into the model.
alt_core_api/tools/protoc_gen_arduinoif/templates/service_impl_header.hpp.j2 Adds Jinja template for *_service_impl.hpp.
alt_core_api/tools/protoc_gen_arduinoif/templates/service_header.hpp.j2 Adds Jinja template for *_service.hpp.
alt_core_api/tools/protoc_gen_arduinoif/templates/ifc_header.hpp.j2 Adds Jinja template for *_interface.hpp.
alt_core_api/tools/protoc_gen_arduinoif/templates/api_header.hpp.j2 Adds Jinja template for *_api.hpp.
alt_core_api/tools/protoc_gen_arduinoif/service_renderer.py Implements header rendering over multiple “surfaces” with stable iteration order.
alt_core_api/tools/protoc_gen_arduinoif/service_model_builder.py Builds ServiceModel from descriptors + options + lineage.
alt_core_api/tools/protoc_gen_arduinoif/service_model.py Adds IR types (ServiceModel, MethodSpec, PlannedMethod).
alt_core_api/tools/protoc_gen_arduinoif/request_context.py Adds request indexing (messages, services) + requested-file filtering.
alt_core_api/tools/protoc_gen_arduinoif/options_runtime.py Generates/loads arduino_opts_pb2 at runtime for extension access.
alt_core_api/tools/protoc_gen_arduinoif/enum_renderer.py Adds enum-only proto renderer to *_types.h.
alt_core_api/tools/protoc_gen_arduinoif/core.py Implements protoc plugin entrypoint logic.
alt_core_api/tools/protoc_gen_arduinoif/init.py Adds package marker.
alt_core_api/tools/protoc-gen-arduinoif Adds the executable protoc plugin script.
alt_core_api/rust/src/lib.rs Adds no_std Rust library entry with a panic handler.
alt_core_api/rust/src/common.rs Adds Rust C ABI exports (map_i32, makeWord_*).
alt_core_api/rust/Cargo.toml Defines the Rust staticlib crate.
alt_core_api/idl/proto/stream.proto Adds Stream service IDL.
alt_core_api/idl/proto/print.proto Adds Print service IDL.
alt_core_api/idl/proto/hardware_serial.proto Adds HardwareSerial service IDL and options.
alt_core_api/idl/proto/google/protobuf/wrappers.proto Adds minimal wrappers proto used by IDL.
alt_core_api/idl/proto/google/protobuf/empty.proto Adds minimal Empty proto used by IDL.
alt_core_api/idl/proto/common.proto Adds shared enums proto (types header generation).
alt_core_api/idl/proto/arduino_opts.proto Adds custom option extensions for codegen.
alt_core_api/idl/CMakeLists.txt Integrates nanopb + custom interface header generation into the build.
alt_core_api/api/zephyrPrint.cpp Adjusts Print helpers (removes default write(buffer,size) impl from .cpp).
alt_core_api/api/Stream.h Adds alt Stream wrapper type (currently has a syntax issue).
alt_core_api/api/Print.h Adds alt Print wrapper type + inline helpers.
alt_core_api/api/HardwareSerial.h Adds alt HardwareSerial wrapper type.
alt_core_api/api/Common.h Adds a stub compat header.
alt_core_api/api/CMakeLists.txt Adds Zephyr sources for alt API.
alt_core_api/api/ArduinoAPI.h Adds alt Arduino API header (currently disables most declarations).
alt_core_api/CMakeLists.txt Adds alt_core_api build (Rust + IDL + API).
README.md Links new IDL codegen documentation.
Kconfig Selects NANOPB when the alt Rust implementation is enabled.
CMakeLists.txt Switches Rust-enabled builds to use alt_core_api/ subdirectory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread alt_core_api/api/Print.h
Comment on lines +190 to +192
inline size_t Print::println(const String &s) {
return print(s) + println();
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

println(const String&) is inline and calls print(s), but Print::print(const String&) has no active definition in this header (the only implementation is commented out above). This will compile but fail to link if println(String) is used. Restore/provide the print(const String&) (and similarly print(const Printable&)) implementation, or remove/disable the dependent println(...) overloads.

Copilot uses AI. Check for mistakes.
Comment thread alt_core_api/api/Print.h
inline size_t Print::println(double d, int perception) {
return print(d, perception) + println();
}

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

println(const Printable&) is inline and calls print(printable), but Print::print(const Printable&) has no active definition in this header (the only implementation is commented out above). This will lead to undefined references when println(Printable) is used. Provide/restore the missing print(const Printable&) implementation or remove/disable the dependent println(...) overload.

Suggested change
inline size_t Print::print(const Printable &printable) {
return printable.printTo(*this);
}

Copilot uses AI. Check for mistakes.
option (arduino.generate_api_class) = true;
option (arduino.generate_service_class) = true;
option (arduino.generate_service_impl_class) = true;
option (arduino.api_class_name) = "arduino::HardwareSerial";
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

api_class_name is set to a fully-qualified C++ name (arduino::HardwareSerial) while the generator also wraps output in namespace arduino { ... }. That combination will produce an invalid class declaration like namespace arduino { class arduino::HardwareSerial ... } in the generated headers. Either change the option to an unqualified name (e.g., HardwareSerial) or update the generator to detect qualified names and avoid emitting the surrounding namespace / strip the prefix.

Suggested change
option (arduino.api_class_name) = "arduino::HardwareSerial";
option (arduino.api_class_name) = "HardwareSerial";

Copilot uses AI. Check for mistakes.
missing_api = [
spec.decl
for spec in lineage_method_specs
if spec.emit_service and spec.call_name not in api_callable
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The service-impl delegate validation checks spec.call_name not in api_callable. Because api_callable is name-only, this can miss missing overloads (one overload present in API makes all overloads look present), and codegen can still emit an impl method that fails to compile. Make this validation compare overload-unique identifiers (e.g., spec.decl or a computed signature) rather than just call_name.

Suggested change
if spec.emit_service and spec.call_name not in api_callable
if spec.emit_service and spec.decl not in api_callable

Copilot uses AI. Check for mistakes.
Comment thread documentation/idl_codegen.md Outdated
Comment on lines +83 to +87
Defined as `google.protobuf.ServiceOptions` extensions:

1. `generate_ifc_class`
2. `generate_api_class`
3. `generate_service_class`
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

This section lists a generate_ifc_class service option, but arduino_opts.proto doesn’t define such an extension (and the generator currently always emits the Ifc header/class). Either update the documentation to match the implemented options, or add the missing option + implementation so the documented configuration is actually supported.

Copilot uses AI. Check for mistakes.
Comment thread documentation/idl_codegen.md Outdated
Comment on lines +128 to +132
The generator intentionally fails when configuration is inconsistent:

1. `generate_api_class = true` requires `generate_ifc_class = true`
2. `generate_service_impl_class = true` requires `generate_service_class = true`
3. `generate_api_class = true` rejects methods with `emit_api = true` and `source_virtual = false`
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The validation rules and example here refer to generate_ifc_class / (arduino.generate_ifc_class), but those extensions are not present in arduino_opts.proto and the generator doesn’t implement that toggle (Ifc is always emitted). Update this section (and the example proto snippet) to reflect the actual supported options, otherwise readers will try options that have no effect / fail to compile.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +48
#if 0
void yield(void);

void init(void);
void initVariant(void);
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

Almost the entire Arduino API surface is currently disabled by #if 0 (starting here), including core declarations like pinMode, digitalWrite, interrupt APIs, and the map/makeWord helpers. With the Rust implementation enabled, sketches including <Arduino.h> will not see these declarations and will fail to compile (e.g., the blinky sample calls pinMode/digitalWrite). Replace #if 0 with the intended feature guard or remove it so these APIs are declared.

Copilot uses AI. Check for mistakes.
Comment on lines +159 to +164
spec.call_name
for spec in lineage_specs
if spec.emit_api and spec.source_virtual
}
service_callable = {
spec.call_name for spec in lineage_specs if spec.emit_service
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

api_callable is tracked as a set of spec.call_name, but overloads share the same call_name (e.g., write, begin). Downstream checks/gating then treat all overloads as callable if any overload is present, which can generate service_impl methods that call API overloads that were never emitted. Track callability using an overload-unique key (e.g., spec.decl or a dedicated signature field) instead of just call_name.

Suggested change
spec.call_name
for spec in lineage_specs
if spec.emit_api and spec.source_virtual
}
service_callable = {
spec.call_name for spec in lineage_specs if spec.emit_service
spec.decl
for spec in lineage_specs
if spec.emit_api and spec.source_virtual
}
service_callable = {
spec.decl for spec in lineage_specs if spec.emit_service

Copilot uses AI. Check for mistakes.
in_api=spec.emit_api and spec.source_virtual,
in_service=in_service,
in_service_impl=in_service
and spec.call_name in service_impl_callable,
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

in_service_impl is enabled based on spec.call_name in service_impl_callable, which is not overload-safe (multiple overloads share the same call_name). This can cause the generator to emit service_impl overrides for overloads that are not actually callable on the delegate API class. Use an overload-unique key (e.g., full signature/decl) for service_impl_callable membership checks.

Suggested change
and spec.call_name in service_impl_callable,
and spec.decl in service_impl_callable,

Copilot uses AI. Check for mistakes.
@soburi soburi closed this Apr 29, 2026
@soburi soburi deleted the altminimum branch April 29, 2026 12:33
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