Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

rust: Add a Rust compatible API implementation. #141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
soburi wants to merge 2 commits into zephyrproject-rtos:next
base: next
Choose a base branch
Loading
from soburi:rust_impl
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ jobs:
run: |
git clone https://github.com/arduino/ArduinoCore-API.git $MODULE_PATH/../ArduinoCore-API
cp -rfp $MODULE_PATH/../ArduinoCore-API/api $MODULE_PATH/cores/arduino/
apt install rustup
Copy link
Member

@DhruvaG2000 DhruvaG2000 Nov 5, 2025

Choose a reason for hiding this comment

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

The recommended way to install Rust is via the rustup.rs installer script, Ubuntu's rustup package from apt is often outdated and may not work correctly

Copy link
Member

@DhruvaG2000 DhruvaG2000 Nov 5, 2025

Choose a reason for hiding this comment

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

Also,
All initialization is lumped into one "Initialize" step mixing unrelated concerns (cloning API, copying files, Rust setup)...
Better structure:

 - name: Clone ArduinoCore-API
[...]
 - name: Install Rust toolchain
[...]

rustup default stable
rustup target add thumbv6m-none-eabi
rustup target add thumbv7em-none-eabihf
rustup target add thumbv7em-none-eabi
rustup target add thumbv7m-none-eabi
Copy link
Member

@DhruvaG2000 DhruvaG2000 Nov 5, 2025

Choose a reason for hiding this comment

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

Installing targets one-by-one is slower. Rustup supports installing multiple targets in one command

Copy link
Member

@DhruvaG2000 DhruvaG2000 Nov 5, 2025

Choose a reason for hiding this comment

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

Suggested change
rustup target add thumbv7m-none-eabi
rustup target add thumbv6m-none-eabi thumbv7em-none-eabihf thumbv7em-none-eabi thumbv7m-none-eabi

- name: Build fade
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rust/Cargo.lock
70 changes: 70 additions & 0 deletions CMakeLists.txt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,74 @@ if (CONFIG_ARDUINO_API)
add_subdirectory(cores)
add_subdirectory(libraries)
zephyr_include_directories(${variant_dir})

# quote from https://github.com/zephyrproject-rtos/zephyr-lang-rust/blob/main/CMakeLists.txt
function (rust_target_arch RUST_TARGET)
# Map Zephyr targets to LLVM targets.
if(CONFIG_CPU_CORTEX_M)
if(CONFIG_CPU_CORTEX_M0 OR CONFIG_CPU_CORTEX_M0PLUS OR CONFIG_CPU_CORTEX_M1)
set(${RUST_TARGET} "thumbv6m-none-eabi" PARENT_SCOPE)
elseif(CONFIG_CPU_CORTEX_M3)
set(${RUST_TARGET} "thumbv7m-none-eabi" PARENT_SCOPE)
elseif(CONFIG_CPU_CORTEX_M4 OR CONFIG_CPU_CORTEX_M7)
if(CONFIG_FP_HARDABI OR FORCE_FP_HARDABI)
set(${RUST_TARGET} "thumbv7em-none-eabihf" PARENT_SCOPE)
else()
set(${RUST_TARGET} "thumbv7em-none-eabi" PARENT_SCOPE)
endif()
elseif(CONFIG_CPU_CORTEX_M23)
set(${RUST_TARGET} "thumbv8m.base-none-eabi" PARENT_SCOPE)
elseif(CONFIG_CPU_CORTEX_M33 OR CONFIG_CPU_CORTEX_M55)
# Not a typo, Zephyr, uses ARMV7_M_ARMV8_M_FP to select the FP even on v8m.
if(CONFIG_FP_HARDABI OR FORCE_FP_HARDABI)
set(${RUST_TARGET} "thumbv8m.main-none-eabihf" PARENT_SCOPE)
else()
set(${RUST_TARGET} "thumbv8m.main-none-eabi" PARENT_SCOPE)
endif()

# Todo: The M55 is thumbv8.1m.main-none-eabi, which can be added when Rust
# gain support for this target.
else()
message(FATAL_ERROR "Unknown Cortex-M target.")
endif()
elseif(CONFIG_RISCV)
if(CONFIG_RISCV_ISA_RV64I)
# TODO: Should fail if the extensions don't match.
set(${RUST_TARGET} "riscv64imac-unknown-none-elf" PARENT_SCOPE)
elseif(CONFIG_RISCV_ISA_RV32I)
# TODO: We have multiple choices, try to pick the best.
set(${RUST_TARGET} "riscv32i-unknown-none-elf" PARENT_SCOPE)
else()
message(FATAL_ERROR "Rust: Unsupported riscv ISA")
endif()
elseif(CONFIG_ARCH_POSIX AND CONFIG_64BIT AND (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "x86_64"))
set(${RUST_TARGET} "x86_64-unknown-none" PARENT_SCOPE)
elseif(CONFIG_ARCH_POSIX AND CONFIG_64BIT AND (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "aarch64"))
set(${RUST_TARGET} "aarch64-unknown-none" PARENT_SCOPE)
else()
message(FATAL_ERROR "Rust: Add support for other target")
endif()
endfunction()

rust_target_arch(RUST_TARGET_TRIPLE)

set(RUST_CRATE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/rust)
set(RUST_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/rust)
set(RUST_LIB ${RUST_OUT_DIR}/target/${RUST_TARGET_TRIPLE}/release/libarduinocore_api_rust.a)

add_custom_command(
OUTPUT ${RUST_LIB}
COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${RUST_OUT_DIR}/target
cargo build --manifest-path ${RUST_CRATE_DIR}/Cargo.toml
--target ${RUST_TARGET_TRIPLE} --release
WORKING_DIRECTORY ${RUST_CRATE_DIR}
COMMENT "Building Rust staticlib for ${RUST_TARGET}"
VERBATIM
)

add_custom_target(arduinocore_api_rust_build ALL DEPENDS ${RUST_LIB})
add_library(arduinocore_api_rust STATIC IMPORTED GLOBAL)
set_target_properties(arduinocore_api_rust PROPERTIES IMPORTED_LOCATION ${RUST_LIB})
zephyr_link_libraries(arduinocore_api_rust)

endif()
5 changes: 5 additions & 0 deletions Kconfig
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ config ARDUINO_API

if ARDUINO_API

config USE_ARDUINO_API_RUST_IMPLEMENTATION
bool "Use Rust implementation API core"
default y
Comment on lines +20 to +22
Copy link
Contributor

@pillo79 pillo79 Nov 5, 2025

Choose a reason for hiding this comment

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

Sorry to be nitpicky, but I asked this before and I'm still confused. 🙂

Is Rust expected to be installed by anyone trying to use the core at this stage?
If not, I would expect this to be manually set somehow (via the west command line, using snippets, etc) and not being default y-ed.

select RUST

config QEMU_ICOUNT
bool "QEMU icount mode"
default n
Expand Down
1 change: 1 addition & 0 deletions cores/arduino/CMakeLists.txt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ if(NOT DEFINED ARDUINO_BUILD_PATH)
zephyr_sources(zephyrPrint.cpp)
zephyr_sources(zephyrSerial.cpp)
zephyr_sources(zephyrCommon.cpp)
zephyr_sources(apiCommon.cpp)

if(DEFINED CONFIG_ARDUINO_ENTRY)
zephyr_sources(main.cpp)
Expand Down
26 changes: 26 additions & 0 deletions cores/arduino/apiCommon.cpp
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <Arduino.h>
#include "zephyrInternal.h"

extern "C" {
int32_t map_i32(int32_t x, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max);
uint16_t makeWord_w(uint16_t w);
uint16_t makeWord_hl(byte h, byte l);
}

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return map_i32(x, in_min, in_max, out_min, out_max);
}

uint16_t makeWord(uint16_t w) {
return makeWord_w(w);
}
uint16_t makeWord(byte h, byte l) {
return makeWord_hl(h, l);
}
8 changes: 8 additions & 0 deletions rust/Cargo.toml
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "arduinocore_api_rust"
version = "0.1.0"
edition = "2024"
license = "Apache-2.0"

[lib]
crate-type = ["staticlib"]
22 changes: 22 additions & 0 deletions rust/src/common.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2025 TOKITA Hiroshi
// SPDX-License-Identifier: Apache-2.0

#[unsafe(no_mangle)]
pub extern "C" fn map_i32(
x: i32, in_min: i32, in_max: i32, out_min: i32, out_max: i32
) -> i32 {
let num = x.wrapping_sub(in_min).wrapping_mul(out_max.wrapping_sub(out_min));
let den = in_max.wrapping_sub(in_min);
// Note: To keep compatibility, the panic when den=0 is left as is.
num / den.wrapping_add(out_min)
Copy link
Member

@DhruvaG2000 DhruvaG2000 Nov 5, 2025

Choose a reason for hiding this comment

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

Due to operator precedence, this evaluates as:

 num / (den + out_min) // Division happens AFTER adding out_min to den! 

Original C++ code:

 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;

Can we just follow similar arithmetic syntax in rust too, the code using wrapping_* is making the logic really confusing to understand, and with rust already being a new addition I feel like we should make an effort to keep things simple where possible.

}

#[unsafe(no_mangle)]
pub extern "C" fn makeWord_w(w: u16) -> u16 {
w
}

#[unsafe(no_mangle)]
pub extern "C" fn makeWord_hl(h: u8, l: u8) -> u16 {
((h as u16) << 8) | (l as u16)
}
14 changes: 14 additions & 0 deletions rust/src/lib.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2025 TOKITA Hiroshi
// SPDX-License-Identifier: Apache-2.0

#![no_std]

mod common;
pub use common::*;

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}
Loading

AltStyle によって変換されたページ (->オリジナル) /