Skip to content
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
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ jobs:
git clone https://github.com/arduino/ArduinoCore-API.git $MODULE_PATH/../ArduinoCore-API
cp -rfp $MODULE_PATH/../ArduinoCore-API/api $MODULE_PATH/cores/arduino/
- name: Setup Rust toolchain
run: |
wget https://sh.rustup.rs
mv index.html rustup_install.sh
bash rustup_install.sh -y
/root/.cargo/bin/rustup default stable
/root/.cargo/bin/rustup target add thumbv6m-none-eabi thumbv7em-none-eabihf thumbv7em-none-eabi thumbv7m-none-eabi
echo "/root/.cargo/bin" >> $GITHUB_PATH
- name: Build fade
run: |
west build -p -b arduino_nano_33_ble/nrf52840/sense $MODULE_PATH/samples/fade
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rust/Cargo.lock
70 changes: 70 additions & 0 deletions CMakeLists.txt
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()
4 changes: 4 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ config ARDUINO_API

if ARDUINO_API

config USE_ARDUINO_API_RUST_IMPLEMENTATION
Copy link
Contributor

Choose a reason for hiding this comment

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

I am missing where this symbol is effectively used? AFAICS CMakeLists.txt will try to invoke cargo build regardless of this being set or not.

bool "Use Rust implementation API core"
select RUST

config QEMU_ICOUNT
bool "QEMU icount mode"
default n
Expand Down
1 change: 1 addition & 0 deletions cores/arduino/CMakeLists.txt
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
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
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
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)
}

#[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
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