├── boards ├── hifive1_revb.conf ├── esp32c3_devkitm.conf ├── hifive1_revb.overlay └── esp32c3_devkitm.overlay ├── .gitignore ├── src ├── led_service │ ├── CMakeLists.txt │ └── led_service_pwm.c ├── messages.h └── consumer.c ├── prj.conf ├── prj_nrf52833dk_nrf52833.conf ├── rust ├── src │ ├── zephyr │ │ ├── CMakeLists.txt │ │ ├── rs_log.h │ │ ├── bridge.c │ │ └── mod.rs │ ├── producer_bridge.c │ └── lib.rs ├── Cargo.toml ├── build.rs ├── CMakeLists.txt └── Cargo.lock ├── esp32c3_devkitm.overlay ├── CMakeLists.txt ├── sample.yaml ├── hifive1_revb.resc └── .clang-format /boards/hifive1_revb.conf: -------------------------------------------------------------------------------- 1 | CONFIG_GPIO=y 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.idea/** 2 | **/build/** 3 | **/target/** 4 | -------------------------------------------------------------------------------- /boards/esp32c3_devkitm.conf: -------------------------------------------------------------------------------- 1 | CONFIG_PWM=y 2 | CONFIG_LED=y 3 | CONFIG_PWM_LED_ESP32=y 4 | -------------------------------------------------------------------------------- /src/led_service/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | target_sources(app PRIVATE 4 | "${PROJECT_SOURCE_DIR}/src/led_service/led_service.c") 5 | -------------------------------------------------------------------------------- /boards/hifive1_revb.overlay: -------------------------------------------------------------------------------- 1 | / { 2 | leds { 3 | compatible = "gpio-leds"; 4 | led0: led_0 { 5 | gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; 6 | label = "Green LED"; 7 | }; 8 | }; 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_LOG=y 2 | CONFIG_LOG_MODE_MINIMAL=y 3 | CONFIG_HEAP_MEM_POOL_SIZE=2048 4 | CONFIG_ZBUS=y 5 | CONFIG_ZBUS_CHANNEL_NAME=y 6 | CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE=5 7 | CONFIG_THREAD_NAME=y 8 | -------------------------------------------------------------------------------- /prj_nrf52833dk_nrf52833.conf: -------------------------------------------------------------------------------- 1 | CONFIG_LOG=y 2 | CONFIG_LOG_MODE_MINIMAL=y 3 | CONFIG_HEAP_MEM_POOL_SIZE=1024 4 | CONFIG_ZBUS=y 5 | CONFIG_ZBUS_CHANNEL_NAME=y 6 | CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE=5 7 | CONFIG_FPU=y 8 | CONFIG_THREAD_NAME=y 9 | -------------------------------------------------------------------------------- /rust/src/zephyr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | target_include_directories(app PRIVATE 3 | "${PROJECT_SOURCE_DIR}/rust/src/zephyr/") 4 | 5 | target_sources(app PRIVATE 6 | "${PROJECT_SOURCE_DIR}/rust/src/zephyr/bridge.c") 7 | -------------------------------------------------------------------------------- /esp32c3_devkitm.overlay: -------------------------------------------------------------------------------- 1 | / { 2 | aliases { 3 | led0 = &myled0; 4 | }; 5 | 6 | leds { 7 | compatible = "gpio-leds"; 8 | myled0: led_0 { 9 | gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; 10 | }; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | 5 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 6 | project(hello_world) 7 | 8 | target_sources(app PRIVATE src/consumer.c) 9 | 10 | add_subdirectory(rust) 11 | #add_subdirectory("${PROJECT_SOURCE_DIR}/src/led_service") 12 | -------------------------------------------------------------------------------- /rust/src/zephyr/rs_log.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by rodrigopex on 29/12/22. 3 | // 4 | 5 | #ifndef ZBUS_RS_RS_LOG_H 6 | #define ZBUS_RS_RS_LOG_H 7 | 8 | enum rs_log_level { 9 | RS_ERR, 10 | RS_WRN, 11 | RS_INF, 12 | RS_DBG 13 | }; 14 | 15 | struct rs_log_msg { 16 | const enum rs_log_level level; 17 | const char *msg; 18 | const uint8_t size; 19 | }; 20 | #endif // ZBUS_RS_RS_LOG_H 21 | -------------------------------------------------------------------------------- /sample.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: Hello World sample, the simplest Zephyr 3 | application 4 | name: hello world 5 | common: 6 | tags: introduction 7 | integration_platforms: 8 | - native_posix 9 | harness: console 10 | harness_config: 11 | type: one_line 12 | regex: 13 | - "Hello World! (.*)" 14 | tests: 15 | sample.basic.helloworld: 16 | tags: introduction 17 | -------------------------------------------------------------------------------- /src/messages.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #ifndef _MESSAGES_H_ 6 | #define _MESSAGES_H_ 7 | #include 8 | 9 | struct version_msg { 10 | uint8_t major; 11 | uint8_t minor; 12 | uint16_t build; 13 | }; 14 | 15 | struct acc_msg { 16 | int x; 17 | int y; 18 | int z; 19 | }; 20 | 21 | struct ack_msg { 22 | uint32_t sequence; 23 | }; 24 | 25 | #endif /* _MESSAGES_H_ */ 26 | -------------------------------------------------------------------------------- /hifive1_revb.resc: -------------------------------------------------------------------------------- 1 | :name: SiFive-FE310 2 | :description: This script runs Zephyr RTOS shell sample on SiFive-FE310 platform. 3 | 4 | $name?="SiFive-FE310" 5 | 6 | using sysbus 7 | mach create $name 8 | machine LoadPlatformDescription @platforms/cpus/sifive-fe310.repl 9 | 10 | $bin=@build/zephyr/zephyr.elf 11 | 12 | showAnalyzer uart0 13 | sysbus LoadELF $bin 14 | 15 | sysbus Tag <0x10008000 4> "PRCI_HFROSCCFG" 0xFFFFFFFF 16 | sysbus Tag <0x10008008 4> "PRCI_PLLCFG" 0xFFFFFFFF 17 | 18 | :cpu PerformanceInMips 320 19 | 20 | machine StartGdbServer 3333 21 | start 22 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Rodrigo Peixoto 2 | # SPDX-License-Identifier: Apache-2.0 3 | [package] 4 | name = "rust" 5 | version = "0.1.0" 6 | authors = ["Rodrigo Peixoto "] 7 | edition = "2021" 8 | 9 | [lib] 10 | crate-type = ["staticlib"] 11 | 12 | [build-dependencies] 13 | bindgen = "0.63.0" 14 | 15 | [dependencies] 16 | panic-halt = "0.2.0" 17 | paste = "1.0.10" 18 | 19 | [profile.release] 20 | codegen-units = 1 21 | lto = true 22 | panic = "abort" 23 | 24 | [profile.dev] 25 | codegen-units = 1 26 | lto = false 27 | debug = true 28 | panic = "abort" 29 | -------------------------------------------------------------------------------- /boards/esp32c3_devkitm.overlay: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: Apache-2.0 3 | * 4 | * Copyright (c) 2021 Andrei-Edward Popa 5 | * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | / { 12 | aliases { 13 | pwm-0 = &ledc0; 14 | pwm-led0 = &pwm_led_blue; 15 | }; 16 | 17 | pwmleds { 18 | compatible = "pwm-leds"; 19 | pwm_led_blue: pwm_led_gpio0_8 { 20 | label = "PWM LED0"; 21 | pwms = <&ledc0 0 1000 PWM_POLARITY_NORMAL>; 22 | }; 23 | }; 24 | }; 25 | 26 | &pinctrl { 27 | ledc0_default: ledc0_default { 28 | group1 { 29 | pinmux = ; 30 | output-enable; 31 | }; 32 | }; 33 | }; 34 | 35 | &ledc0 { 36 | pinctrl-0 = <&ledc0_default>; 37 | pinctrl-names = "default"; 38 | status = "okay"; 39 | #address-cells = <1>; 40 | #size-cells = <0>; 41 | channel0@0 { 42 | reg = <0x0>; 43 | timer = <0>; 44 | }; 45 | }; 46 | -------------------------------------------------------------------------------- /src/consumer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include "messages.h" 6 | 7 | #include 8 | #include 9 | LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); 10 | 11 | ZBUS_SUBSCRIBER_DEFINE(consumer_sub, 4); 12 | 13 | ZBUS_CHAN_DEFINE(ack_chan, /* Name */ 14 | struct ack_msg, /* Message type */ 15 | 16 | NULL, /* Validator */ 17 | NULL, /* User data */ 18 | ZBUS_OBSERVERS(c_listener, rust_listener, rust_sub), /* observers */ 19 | ZBUS_MSG_INIT(.sequence = 0) /* Initial value */ 20 | ); 21 | 22 | static void consumer_subscriber_thread(void) 23 | { 24 | LOG_INF("C subscriber thread started!"); 25 | 26 | const struct zbus_channel *chan; 27 | struct ack_msg ack = {.sequence = 0}; 28 | while (!zbus_sub_wait(&consumer_sub, &chan, K_FOREVER)) { 29 | struct acc_msg acc; 30 | 31 | zbus_chan_read(chan, &acc, K_MSEC(500)); 32 | LOG_INF("C subscriber --> Consuming data: Acc x=%d, y=%d, z=%d", acc.x, acc.y, acc.z); 33 | 34 | ++ack.sequence; 35 | zbus_chan_pub(&ack_chan, &ack, K_MSEC(250)); 36 | } 37 | } 38 | 39 | K_THREAD_DEFINE(consumer_thread_id, 512, consumer_subscriber_thread, NULL, NULL, NULL, 3, 0, 0); 40 | -------------------------------------------------------------------------------- /rust/src/producer_bridge.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | #include 8 | #define LOG_LEVEL LOG_LEVEL_DBG 9 | LOG_MODULE_REGISTER(rust_bridge); 10 | 11 | #include "messages.h" 12 | 13 | ZBUS_CHAN_DEFINE(version_chan, /* Name */ 14 | struct version_msg, /* Message type */ 15 | 16 | NULL, /* Validator */ 17 | NULL, /* User data */ 18 | ZBUS_OBSERVERS_EMPTY, /* observers */ 19 | ZBUS_MSG_INIT(.major = 0, .minor = 1, 20 | .build = 2) /* Initial value major 0, minor 1, build 2 */ 21 | ); 22 | 23 | static struct version_msg acc_fw_version = {1, 3, 2089}; 24 | 25 | ZBUS_CHAN_DEFINE(acc_data_chan, /* Name */ 26 | struct acc_msg, /* Message type */ 27 | 28 | NULL, /* Validator */ 29 | &acc_fw_version, /* User data */ 30 | ZBUS_OBSERVERS(consumer_sub), /* observers */ 31 | ZBUS_MSG_INIT(.x = 0, .y = 0, .z = 0) /* Initial value */ 32 | ); 33 | 34 | /* External declaration for the Rust callback. */ 35 | void rust_function(const struct zbus_channel *chan); 36 | 37 | /* External declaration for the Rust thread. */ 38 | void rust_thread(void); 39 | 40 | void c_listener_callback(const struct zbus_channel *chan) 41 | { 42 | const struct ack_msg *msg = zbus_chan_const_msg(chan); 43 | LOG_DBG("C listener sequence: %u", msg->sequence); 44 | } 45 | 46 | 47 | ZBUS_SUBSCRIBER_DEFINE(rust_sub, 4); 48 | 49 | ZBUS_LISTENER_DEFINE(c_listener, c_listener_callback); 50 | ZBUS_LISTENER_DEFINE(rust_listener, rust_function); 51 | 52 | K_THREAD_DEFINE(rust_thread_id, 1024, rust_thread, NULL, NULL, NULL, 3, 0, 0); 53 | -------------------------------------------------------------------------------- /rust/src/zephyr/bridge.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include "rs_log.h" 9 | #define LOG_LEVEL LOG_LEVEL_DBG 10 | LOG_MODULE_REGISTER(zephyr_rs); 11 | 12 | const void *zbus_chan_msg_const_wrapper(const struct zbus_channel *chan) 13 | { 14 | return zbus_chan_const_msg(chan); 15 | } 16 | void *zbus_chan_msg_wrapper(const struct zbus_channel *chan) 17 | { 18 | return zbus_chan_msg(chan); 19 | } 20 | 21 | void *zbus_chan_user_data_wrapper(const struct zbus_channel *chan) 22 | { 23 | return zbus_chan_user_data(chan); 24 | } 25 | 26 | k_timeout_t zephyr_rs_timeout_from_ms(uint32_t ms) 27 | { 28 | return Z_TIMEOUT_MS(ms); 29 | } 30 | 31 | int32_t zephyr_rs_delay_ms(uint32_t ms) 32 | { 33 | return k_sleep(Z_TIMEOUT_MS(ms)); 34 | } 35 | 36 | void log_listener_callback(const struct zbus_channel *chan) 37 | { 38 | char msg[256] = {0}; 39 | const struct rs_log_msg *l = zbus_chan_const_msg(chan); 40 | memcpy(msg,l->msg, l->size); 41 | switch (l->level) { 42 | case RS_ERR: 43 | LOG_ERR("%s", msg); 44 | break; 45 | case RS_WRN: 46 | LOG_WRN("%s", msg); 47 | break; 48 | case RS_INF: 49 | LOG_INF("%s", msg); 50 | break; 51 | case RS_DBG: 52 | LOG_DBG("%s", msg); 53 | break; 54 | } 55 | } 56 | 57 | ZBUS_LISTENER_DEFINE(log_listener, log_listener_callback); 58 | 59 | ZBUS_CHAN_DEFINE(log_chan, /* Name */ 60 | struct rs_log_msg, /* Message type */ 61 | 62 | NULL, /* Validator */ 63 | NULL, /* User data */ 64 | ZBUS_OBSERVERS(log_listener), /* observers */ 65 | ZBUS_MSG_INIT(0) /* Initial value major 0, minor 1, build 2 */ 66 | ); 67 | -------------------------------------------------------------------------------- /rust/build.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | extern crate bindgen; 6 | 7 | use std::env; 8 | use std::path::PathBuf; 9 | 10 | fn main() { 11 | // Tell cargo to invalidate the built crate whenever the wrapper changes 12 | println!("cargo:rerun-if-changed=../src/messages.h"); 13 | 14 | // The bindgen::Builder is the main entry point 15 | // to bindgen, and lets you build up options for 16 | // the resulting bindings. 17 | let bindings = bindgen::Builder::default() 18 | // The input header we would like to generate 19 | // bindings for. 20 | .header("../src/messages.h") 21 | // .clang_arg("--gcc-install-dir=~/.local/zephyr-sdk-0.15.2/arm-zephyr-eabi/lib/gcc/arm-zephyr-eabi/12.1.0") 22 | // .clang_arg("--target=thumbv7-eabif") 23 | // .clang_arg("-mfloat-abi=hard") 24 | .clang_arg("--target=riscv32") 25 | .clang_arg("-march=rv32imc") 26 | // .clang_arg("-march=rv32imac") 27 | .derive_default(true) 28 | .size_t_is_usize(true) 29 | .rustfmt_bindings(true) 30 | .wrap_unsafe_ops(true) 31 | .c_naming(true) 32 | .layout_tests(false) 33 | .use_core() 34 | // Tell cargo to invalidate the built crate whenever any of the 35 | // included header files changed. 36 | .parse_callbacks(Box::new(bindgen::CargoCallbacks)) 37 | // Finish the builder and generate the bindings. 38 | .generate() 39 | // Unwrap the Result and panic on failure. 40 | .expect("Unable to generate bindings"); 41 | 42 | // Write the bindings to the $OUT_DIR/bindings.rs file. 43 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 44 | bindings 45 | .write_to_file(out_path.join("bindings.rs")) 46 | .expect("Couldn't write bindings!"); 47 | } 48 | -------------------------------------------------------------------------------- /src/led_service/led_service_pwm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Intel Corporation 3 | * Copyright (c) 2020 Nordic Semiconductor ASA 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | /** 9 | * @file Sample app to demonstrate PWM. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0)); 18 | 19 | #define MIN_PERIOD PWM_SEC(1U) / 128U 20 | #define MAX_PERIOD PWM_SEC(1U) 21 | 22 | void main(void) 23 | { 24 | uint32_t max_period; 25 | uint32_t period; 26 | uint8_t dir = 0U; 27 | int ret; 28 | 29 | printk("PWM-based blinky\n"); 30 | 31 | if (!device_is_ready(pwm_led0.dev)) { 32 | printk("Error: PWM device %s is not ready\n", 33 | pwm_led0.dev->name); 34 | return; 35 | } 36 | 37 | /* 38 | * In case the default MAX_PERIOD value cannot be set for 39 | * some PWM hardware, decrease its value until it can. 40 | * 41 | * Keep its value at least MIN_PERIOD * 4 to make sure 42 | * the sample changes frequency at least once. 43 | */ 44 | printk("Calibrating for channel %d...\n", pwm_led0.channel); 45 | max_period = MAX_PERIOD; 46 | while (pwm_set_dt(&pwm_led0, max_period, max_period / 2U)) { 47 | max_period /= 2U; 48 | if (max_period < (4U * MIN_PERIOD)) { 49 | printk("Error: PWM device " 50 | "does not support a period at least %lu\n", 51 | 4U * MIN_PERIOD); 52 | return; 53 | } 54 | } 55 | 56 | printk("Done calibrating; maximum/minimum periods %u/%lu usec\n", 57 | max_period, MIN_PERIOD); 58 | 59 | // period = max_period; 60 | period = MIN_PERIOD; 61 | 62 | while (1) { 63 | ret = pwm_set_dt(&pwm_led0, period, period / 2U); 64 | if (ret) { 65 | printk("Error %d: failed to set pulse width\n", ret); 66 | return; 67 | } 68 | 69 | period = dir ? (period * 2U) : (period / 2U); 70 | if (period > max_period) { 71 | period = max_period / 2U; 72 | dir = 0U; 73 | } else if (period < MIN_PERIOD) { 74 | period = MIN_PERIOD * 2U; 75 | dir = 1U; 76 | } 77 | printk("Blink!\n"); 78 | k_sleep(K_SECONDS(1U)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /rust/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | target_sources(app PRIVATE 4 | "${PROJECT_SOURCE_DIR}/rust/src/producer_bridge.c" 5 | # If needed, add your C source files here 6 | ) 7 | 8 | target_include_directories(app PRIVATE "${PROJECT_SOURCE_DIR}/src") 9 | 10 | # Build and bring in the rust package as an "external project". 11 | include(ExternalProject) 12 | 13 | set(RUST_SRC_DIR "${PROJECT_SOURCE_DIR}/rust") 14 | 15 | #set(RUST_TARGET "riscv32imac-unknown-none-elf") 16 | set(RUST_TARGET "riscv32imc-unknown-none-elf") 17 | #set(RUST_TARGET "thumbv7em-none-eabihf") 18 | 19 | set(RUST_TARGET_DIR "${PROJECT_SOURCE_DIR}/build") 20 | 21 | option(RUST_MODE_RELEASE "This enables release as the Rust code portion mode" ON) 22 | if(RUST_MODE_RELEASE) 23 | set(RUST_LIB_DESTINATION "${RUST_TARGET_DIR}/${RUST_TARGET}/release/librust.a") 24 | set(RUST_RELEASE_FLAG "--release") 25 | else() 26 | set(RUST_LIB_DESTINATION "${RUST_TARGET_DIR}/${RUST_TARGET}/debug/librust.a") 27 | set(RUST_RELEASE_FLAG "--debug") 28 | endif() 29 | 30 | ExternalProject_Add( 31 | rust 32 | PREFIX "" 33 | SOURCE_DIR ${RUST_SRC_DIR} 34 | BINARY_DIR ${RUST_SRC_DIR} 35 | CONFIGURE_COMMAND "" 36 | # For the build to always be run, so that changes in the Rust 37 | # code are detected. 38 | BUILD_ALWAYS TRUE 39 | BUILD_COMMAND 40 | "cargo" 41 | "+nightly" 42 | "build" 43 | "--target" ${RUST_TARGET} 44 | "--target-dir" ${RUST_TARGET_DIR} 45 | ${RUST_RELEASE_FLAG} 46 | INSTALL_COMMAND "" 47 | BUILD_BYPRODUCTS 48 | ${RUST_LIB_DESTINATION} 49 | ) 50 | 51 | # By calling west build -t clean_rust, the target folder will be deleted 52 | add_custom_target(clean_rust 53 | WORKING_DIRECTORY ${RUST_SRC_DIR} 54 | COMMAND 55 | "cargo" 56 | "+nightly" 57 | "clean" 58 | VERBATIM 59 | ) 60 | 61 | add_library(rust_lib STATIC IMPORTED GLOBAL) 62 | 63 | add_dependencies( 64 | rust_lib 65 | rust 66 | ) 67 | 68 | set_target_properties(rust_lib PROPERTIES IMPORTED_LOCATION 69 | ${RUST_LIB_DESTINATION}) 70 | 71 | # Add our application, along with -lgcc 72 | target_link_libraries(app PUBLIC rust_lib gcc) 73 | 74 | add_subdirectory("${PROJECT_SOURCE_DIR}/rust/src/zephyr") 75 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # 3 | # Note: The list of ForEachMacros can be obtained using: 4 | # 5 | # git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \ 6 | # | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$, - '\1'," \ 7 | # | sort | uniq 8 | # 9 | # References: 10 | # - https://clang.llvm.org/docs/ClangFormatStyleOptions.html 11 | 12 | --- 13 | BasedOnStyle: LLVM 14 | AlignConsecutiveMacros: AcrossComments 15 | AllowShortBlocksOnASingleLine: false 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortEnumsOnASingleLine: false 18 | AllowShortFunctionsOnASingleLine: None 19 | AllowShortIfStatementsOnASingleLine: false 20 | AllowShortLoopsOnASingleLine: false 21 | AttributeMacros: 22 | - __aligned 23 | - __deprecated 24 | - __packed 25 | - __printf_like 26 | - __syscall 27 | - __subsystem 28 | BitFieldColonSpacing: After 29 | BreakBeforeBraces: Linux 30 | ColumnLimit: 100 31 | ConstructorInitializerIndentWidth: 8 32 | ContinuationIndentWidth: 8 33 | ForEachMacros: 34 | - 'FOR_EACH' 35 | - 'FOR_EACH_FIXED_ARG' 36 | - 'FOR_EACH_IDX' 37 | - 'FOR_EACH_IDX_FIXED_ARG' 38 | - 'FOR_EACH_NONEMPTY_TERM' 39 | - 'RB_FOR_EACH' 40 | - 'RB_FOR_EACH_CONTAINER' 41 | - 'SYS_DLIST_FOR_EACH_CONTAINER' 42 | - 'SYS_DLIST_FOR_EACH_CONTAINER_SAFE' 43 | - 'SYS_DLIST_FOR_EACH_NODE' 44 | - 'SYS_DLIST_FOR_EACH_NODE_SAFE' 45 | - 'SYS_SFLIST_FOR_EACH_CONTAINER' 46 | - 'SYS_SFLIST_FOR_EACH_CONTAINER_SAFE' 47 | - 'SYS_SFLIST_FOR_EACH_NODE' 48 | - 'SYS_SFLIST_FOR_EACH_NODE_SAFE' 49 | - 'SYS_SLIST_FOR_EACH_CONTAINER' 50 | - 'SYS_SLIST_FOR_EACH_CONTAINER_SAFE' 51 | - 'SYS_SLIST_FOR_EACH_NODE' 52 | - 'SYS_SLIST_FOR_EACH_NODE_SAFE' 53 | - '_WAIT_Q_FOR_EACH' 54 | - 'Z_FOR_EACH' 55 | - 'Z_FOR_EACH_ENGINE' 56 | - 'Z_FOR_EACH_EXEC' 57 | - 'Z_FOR_EACH_FIXED_ARG' 58 | - 'Z_FOR_EACH_FIXED_ARG_EXEC' 59 | - 'Z_FOR_EACH_IDX' 60 | - 'Z_FOR_EACH_IDX_EXEC' 61 | - 'Z_FOR_EACH_IDX_FIXED_ARG' 62 | - 'Z_FOR_EACH_IDX_FIXED_ARG_EXEC' 63 | - 'Z_GENLIST_FOR_EACH_CONTAINER' 64 | - 'Z_GENLIST_FOR_EACH_CONTAINER_SAFE' 65 | - 'Z_GENLIST_FOR_EACH_NODE' 66 | - 'Z_GENLIST_FOR_EACH_NODE_SAFE' 67 | # Disabled for now, see bug https://github.com/zephyrproject-rtos/zephyr/issues/48520 68 | #IncludeBlocks: Regroup 69 | IncludeCategories: 70 | - Regex: '^".*\.h"$' 71 | Priority: 0 72 | - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$' 73 | Priority: 1 74 | - Regex: '^\$' 75 | Priority: 2 76 | - Regex: '.*' 77 | Priority: 3 78 | IndentCaseLabels: false 79 | IndentWidth: 8 80 | # SpaceBeforeParens: ControlStatementsExceptControlMacros # clang-format >= 13.0 81 | SortIncludes: false 82 | UseTab: Always 83 | WhitespaceSensitiveMacros: 84 | - STRINGIFY 85 | - Z_STRINGIFY 86 | -------------------------------------------------------------------------------- /rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #![no_std] 6 | #![feature(alloc_error_handler)] 7 | #![feature(c_variadic)] 8 | #![allow(non_upper_case_globals)] 9 | #![allow(non_camel_case_types)] 10 | #![allow(non_snake_case)] 11 | 12 | extern crate alloc; 13 | 14 | use alloc::format; 15 | use core::time::Duration; 16 | use zephyr::*; 17 | 18 | //./target/riscv32imac-unknown-none-elf/release/build/rust-hello-d57ce81a5a6371c7/out/bindings.rs 19 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 20 | mod zephyr; 21 | 22 | zbus_static_channel_declare! { 23 | name: version_chan, 24 | msg_type: struct_version_msg 25 | } 26 | zbus_static_channel_declare! { 27 | name: acc_data_chan, 28 | msg_type: struct_acc_msg 29 | } 30 | zbus_static_channel_declare! { 31 | name: ack_chan, 32 | msg_type: struct_ack_msg 33 | } 34 | zbus_static_subscriber_declare! { 35 | name: rust_sub 36 | } 37 | 38 | #[no_mangle] 39 | pub extern "C" fn rust_function(_chan: *const struct_zbus_channel) { 40 | printk!( 41 | "Rust listener sequence: %u\n\0", 42 | ack_chan.get_const_msg().sequence 43 | ); 44 | } 45 | 46 | #[no_mangle] 47 | pub extern "C" fn rust_thread() { 48 | z_log_inf!("Rust thread started!"); 49 | 50 | let mut acc = struct_acc_msg { x: 1, y: 2, z: 3 }; 51 | 52 | match version_chan.read(Duration::from_secs(1)) { 53 | Ok(struct_version_msg { 54 | major, 55 | minor, 56 | build, 57 | }) => { 58 | let v = format!("Product firmware v{major}.{minor}.{build}\0"); 59 | debug_assert_eq!(v, "Product firmware v0.1.2"); 60 | z_log_inf!("{}", v); 61 | } 62 | Err(e) => z_log_err!("Could not read the channel. Error code {e}"), 63 | } 64 | let _ = acc_data_chan.claim(Duration::from_millis(1000), |claimed_channel| { 65 | let struct_version_msg { 66 | major, 67 | minor, 68 | build, 69 | } = claimed_channel.get_user_data(); 70 | let v = format!("Accelerometer firmware v{major}.{minor}.{build}"); 71 | debug_assert_eq!(v, "Accelerometer firmware v1.3.2089"); 72 | z_log_inf!("{}", v); 73 | Ok(()) 74 | }); 75 | 76 | loop { 77 | match acc_data_chan.publish(&acc, Duration::from_secs(1)) { 78 | Ok(_) => z_log_inf!("Rust producer: Message sent!"), 79 | Err(e) => z_log_err!("Could not publish the message. Error code {e}"), 80 | } 81 | acc.x += 1; 82 | acc.y += 2; 83 | acc.z += 3; 84 | 85 | match rust_sub.wait(Duration::MAX) { 86 | Ok(changed_channel_ptr) => { 87 | debug_assert_eq!( 88 | ack_chan, changed_channel_ptr, 89 | "This subscriber must not receive a channel other then ack_channel" 90 | ); 91 | match ack_chan.read(Duration::from_secs(1)) { 92 | Ok(struct_ack_msg { sequence }) => { 93 | z_log_wrn!("Rust subscriber sequence: {sequence}") 94 | } 95 | Err(e) => z_log_err!("Could not publish the message. Error code {e}"), 96 | }; 97 | } 98 | Err(e) => z_log_err!("No notification arrived. Reason code {e}"), 99 | } 100 | sleep(Duration::from_secs(3)); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "bindgen" 7 | version = "0.63.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" 10 | dependencies = [ 11 | "bitflags", 12 | "cexpr", 13 | "clang-sys", 14 | "lazy_static", 15 | "lazycell", 16 | "log", 17 | "peeking_take_while", 18 | "proc-macro2", 19 | "quote", 20 | "regex", 21 | "rustc-hash", 22 | "shlex", 23 | "syn", 24 | "which", 25 | ] 26 | 27 | [[package]] 28 | name = "bitflags" 29 | version = "1.3.2" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 32 | 33 | [[package]] 34 | name = "cexpr" 35 | version = "0.6.0" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 38 | dependencies = [ 39 | "nom", 40 | ] 41 | 42 | [[package]] 43 | name = "cfg-if" 44 | version = "1.0.0" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 47 | 48 | [[package]] 49 | name = "clang-sys" 50 | version = "1.4.0" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" 53 | dependencies = [ 54 | "glob", 55 | "libc", 56 | "libloading", 57 | ] 58 | 59 | [[package]] 60 | name = "either" 61 | version = "1.8.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" 64 | 65 | [[package]] 66 | name = "glob" 67 | version = "0.3.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 70 | 71 | [[package]] 72 | name = "lazy_static" 73 | version = "1.4.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 76 | 77 | [[package]] 78 | name = "lazycell" 79 | version = "1.3.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 82 | 83 | [[package]] 84 | name = "libc" 85 | version = "0.2.138" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" 88 | 89 | [[package]] 90 | name = "libloading" 91 | version = "0.7.4" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 94 | dependencies = [ 95 | "cfg-if", 96 | "winapi", 97 | ] 98 | 99 | [[package]] 100 | name = "log" 101 | version = "0.4.17" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 104 | dependencies = [ 105 | "cfg-if", 106 | ] 107 | 108 | [[package]] 109 | name = "memchr" 110 | version = "2.5.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 113 | 114 | [[package]] 115 | name = "minimal-lexical" 116 | version = "0.2.1" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 119 | 120 | [[package]] 121 | name = "nom" 122 | version = "7.1.1" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 125 | dependencies = [ 126 | "memchr", 127 | "minimal-lexical", 128 | ] 129 | 130 | [[package]] 131 | name = "once_cell" 132 | version = "1.16.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 135 | 136 | [[package]] 137 | name = "panic-halt" 138 | version = "0.2.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" 141 | 142 | [[package]] 143 | name = "paste" 144 | version = "1.0.10" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "cf1c2c742266c2f1041c914ba65355a83ae8747b05f208319784083583494b4b" 147 | 148 | [[package]] 149 | name = "peeking_take_while" 150 | version = "0.1.2" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 153 | 154 | [[package]] 155 | name = "proc-macro2" 156 | version = "1.0.47" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" 159 | dependencies = [ 160 | "unicode-ident", 161 | ] 162 | 163 | [[package]] 164 | name = "quote" 165 | version = "1.0.21" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" 168 | dependencies = [ 169 | "proc-macro2", 170 | ] 171 | 172 | [[package]] 173 | name = "regex" 174 | version = "1.7.0" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" 177 | dependencies = [ 178 | "regex-syntax", 179 | ] 180 | 181 | [[package]] 182 | name = "regex-syntax" 183 | version = "0.6.28" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 186 | 187 | [[package]] 188 | name = "rust" 189 | version = "0.1.0" 190 | dependencies = [ 191 | "bindgen", 192 | "panic-halt", 193 | "paste", 194 | ] 195 | 196 | [[package]] 197 | name = "rustc-hash" 198 | version = "1.1.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 201 | 202 | [[package]] 203 | name = "shlex" 204 | version = "1.1.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" 207 | 208 | [[package]] 209 | name = "syn" 210 | version = "1.0.105" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" 213 | dependencies = [ 214 | "proc-macro2", 215 | "quote", 216 | "unicode-ident", 217 | ] 218 | 219 | [[package]] 220 | name = "unicode-ident" 221 | version = "1.0.5" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 224 | 225 | [[package]] 226 | name = "which" 227 | version = "4.3.0" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" 230 | dependencies = [ 231 | "either", 232 | "libc", 233 | "once_cell", 234 | ] 235 | 236 | [[package]] 237 | name = "winapi" 238 | version = "0.3.9" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 241 | dependencies = [ 242 | "winapi-i686-pc-windows-gnu", 243 | "winapi-x86_64-pc-windows-gnu", 244 | ] 245 | 246 | [[package]] 247 | name = "winapi-i686-pc-windows-gnu" 248 | version = "0.4.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 251 | 252 | [[package]] 253 | name = "winapi-x86_64-pc-windows-gnu" 254 | version = "0.4.0" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 257 | -------------------------------------------------------------------------------- /rust/src/zephyr/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Rodrigo Peixoto 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | #![allow(dead_code)] 6 | extern crate alloc; 7 | 8 | use alloc::format; 9 | use core::alloc::{GlobalAlloc, Layout}; 10 | use core::ffi::{c_char, c_void}; 11 | use core::fmt::Debug; 12 | use core::marker::PhantomData; 13 | use core::panic::PanicInfo; 14 | use core::time::Duration; 15 | 16 | pub mod ffi { 17 | use super::*; 18 | 19 | extern "C" { 20 | pub fn k_free(ptr: *mut u8); 21 | 22 | pub fn k_malloc(size: usize) -> *mut u8; 23 | 24 | pub fn printk(fmt: *const c_char, ...); 25 | 26 | pub fn zephyr_rs_delay_ms(ms: u32); 27 | 28 | pub fn zephyr_rs_log(level: u8, text: *const c_char); 29 | 30 | pub fn zephyr_rs_timeout_from_ms(ms: u32) -> struct_k_timeout_t; 31 | 32 | pub fn zbus_chan_pub( 33 | chan: *const struct_zbus_channel, 34 | msg: *const c_void, 35 | timeout: struct_k_timeout_t, 36 | ) -> i32; 37 | 38 | pub fn zbus_chan_read( 39 | chan: *const struct_zbus_channel, 40 | msg: *mut c_void, 41 | timeout: struct_k_timeout_t, 42 | ) -> i32; 43 | 44 | pub fn zbus_chan_notify( 45 | chan: *const struct_zbus_channel, 46 | timeout: struct_k_timeout_t, 47 | ) -> i32; 48 | 49 | pub fn zbus_chan_claim( 50 | chan: *const struct_zbus_channel, 51 | timeout: struct_k_timeout_t, 52 | ) -> i32; 53 | 54 | pub fn zbus_chan_finish(chan: *const struct_zbus_channel) -> i32; 55 | 56 | pub fn zbus_chan_msg_const_wrapper(chan: *const struct_zbus_channel) -> *const c_void; 57 | 58 | pub fn zbus_chan_msg_wrapper(chan: *const struct_zbus_channel) -> *mut c_void; 59 | 60 | pub fn zbus_chan_user_data_wrapper(chan: *const struct_zbus_channel) -> *mut c_void; 61 | 62 | pub fn zbus_sub_wait( 63 | obs: *const struct_zbus_observer, 64 | chan: *mut struct_zbus_channel, 65 | timeout: struct_k_timeout_t, 66 | ) -> i32; 67 | } 68 | } 69 | 70 | pub const enum_rs_log_level_RS_ERR: enum_rs_log_level = 0; 71 | pub const enum_rs_log_level_RS_WRN: enum_rs_log_level = 1; 72 | pub const enum_rs_log_level_RS_INF: enum_rs_log_level = 2; 73 | pub const enum_rs_log_level_RS_DBG: enum_rs_log_level = 3; 74 | 75 | pub type enum_rs_log_level = ::core::ffi::c_uint; 76 | 77 | #[repr(C)] 78 | #[derive(Debug, Copy, Clone)] 79 | pub struct struct_rs_log_msg { 80 | pub level: enum_rs_log_level, 81 | pub msg: *const ::core::ffi::c_char, 82 | pub size: u8, 83 | } 84 | 85 | impl Default for struct_rs_log_msg { 86 | fn default() -> Self { 87 | let mut s = ::core::mem::MaybeUninit::::uninit(); 88 | unsafe { 89 | ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); 90 | s.assume_init() 91 | } 92 | } 93 | } 94 | 95 | #[repr(C)] 96 | #[derive(Debug, Copy, Clone)] 97 | pub struct struct_zbus_observer { 98 | _private: [u8; 0], 99 | } 100 | 101 | #[repr(C)] 102 | #[derive(Debug, Copy, Clone)] 103 | pub struct struct_zbus_channel { 104 | _private: [u8; 0], 105 | } 106 | 107 | impl struct_zbus_channel { 108 | pub fn init() -> *const struct_zbus_channel { 109 | core::ptr::null() 110 | } 111 | 112 | pub fn init_mut() -> *mut struct_zbus_channel { 113 | core::ptr::null_mut() 114 | } 115 | } 116 | 117 | pub type k_ticks = u32; 118 | 119 | #[repr(C)] 120 | #[derive(Debug, Copy, Clone)] 121 | pub struct struct_k_timeout_t { 122 | pub ticks: k_ticks, 123 | } 124 | 125 | pub mod zbus { 126 | use super::*; 127 | use core::marker::PhantomData; 128 | 129 | #[repr(C)] 130 | #[derive(Debug, Copy, Clone)] 131 | pub struct Channel { 132 | pub(crate) c_reference: &'static struct_zbus_channel, 133 | pub(crate) phantom: PhantomData, 134 | } 135 | 136 | pub trait CStructWrapper { 137 | type Output; 138 | fn get_c_reference(&self) -> Self::Output; 139 | } 140 | 141 | impl CStructWrapper for Channel { 142 | type Output = *const struct_zbus_channel; 143 | fn get_c_reference(&self) -> Self::Output { 144 | self.c_reference 145 | } 146 | } 147 | 148 | impl PartialEq<*const struct_zbus_channel> for Channel 149 | where 150 | MessageType: Debug + Default, 151 | { 152 | fn eq(&self, other: &*const struct_zbus_channel) -> bool { 153 | self.c_reference as *const struct_zbus_channel == *other 154 | } 155 | } 156 | 157 | unsafe impl Sync for Channel {} 158 | 159 | impl Channel 160 | where 161 | MessageType: Default + Debug, 162 | { 163 | pub fn new(chan_ref: &'static struct_zbus_channel) -> Self { 164 | Self { 165 | c_reference: chan_ref, 166 | phantom: PhantomData, 167 | } 168 | } 169 | 170 | pub fn publish(&self, msg: &MessageType, timeout: Duration) -> Result<(), i32> { 171 | match unsafe { 172 | ffi::zbus_chan_pub( 173 | self.c_reference, 174 | msg as *const _ as *const c_void, 175 | ffi::zephyr_rs_timeout_from_ms(timeout.as_millis() as u32), 176 | ) 177 | } { 178 | 0 => Ok(()), 179 | e => Err(e), 180 | } 181 | } 182 | 183 | pub fn notify(&self, timeout: Duration) -> Result<(), i32> { 184 | match unsafe { 185 | ffi::zbus_chan_notify( 186 | self.c_reference, 187 | ffi::zephyr_rs_timeout_from_ms(timeout.as_millis() as u32), 188 | ) 189 | } { 190 | 0 => Ok(()), 191 | e => Err(e), 192 | } 193 | } 194 | 195 | pub fn read(&self, timeout: Duration) -> Result { 196 | let mut msg = MessageType::default(); 197 | 198 | match unsafe { 199 | ffi::zbus_chan_read( 200 | self.c_reference, 201 | &mut msg as *mut _ as *mut c_void, 202 | ffi::zephyr_rs_timeout_from_ms(timeout.as_millis() as u32), 203 | ) 204 | } { 205 | 0 => Ok(msg), 206 | e => Err(e), 207 | } 208 | } 209 | 210 | pub fn claim(&self, timeout: Duration, function: F) -> Result<(), i32> 211 | where 212 | F: FnOnce(ClaimedChannel) -> Result<(), i32>, 213 | { 214 | match unsafe { 215 | ffi::zbus_chan_claim( 216 | self.c_reference, 217 | ffi::zephyr_rs_timeout_from_ms(timeout.as_millis() as u32), 218 | ) 219 | } { 220 | 0 => function(ClaimedChannel::new(self)), 221 | e => Err(e), 222 | } 223 | } 224 | 225 | pub fn get_const_msg(&self) -> &MessageType { 226 | unsafe { 227 | core::mem::transmute::<*const c_void, &MessageType>( 228 | ffi::zbus_chan_msg_const_wrapper(self.c_reference), 229 | ) 230 | } 231 | } 232 | } 233 | 234 | pub struct ClaimedChannel<'a, MessageType> { 235 | channel: &'a Channel, 236 | } 237 | 238 | impl<'a, MessageType> Drop for ClaimedChannel<'a, MessageType> { 239 | fn drop(&mut self) { 240 | unsafe { ffi::zbus_chan_finish(self.channel.get_c_reference()) }; 241 | } 242 | } 243 | 244 | impl<'a, MessageType> ClaimedChannel<'a, MessageType> { 245 | fn new(chan: &'a Channel) -> Self { 246 | ClaimedChannel { channel: chan } 247 | } 248 | 249 | pub fn finish(self) { 250 | /*! The finish is performed automatically by the Drop trait */ 251 | } 252 | 253 | pub fn get_msg(&self) -> &mut MessageType { 254 | unsafe { 255 | core::mem::transmute::<*mut c_void, &mut MessageType>(ffi::zbus_chan_msg_wrapper( 256 | self.channel.get_c_reference(), 257 | )) 258 | } 259 | } 260 | 261 | pub fn get_user_data(&self) -> &mut UserDataType { 262 | unsafe { 263 | core::mem::transmute::<*mut c_void, &mut UserDataType>( 264 | ffi::zbus_chan_user_data_wrapper(self.channel.get_c_reference()), 265 | ) 266 | } 267 | } 268 | } 269 | 270 | #[repr(C)] 271 | #[derive(Debug, Copy, Clone)] 272 | pub struct Subscriber { 273 | pub c_reference: &'static struct_zbus_observer, 274 | } 275 | 276 | impl CStructWrapper for Subscriber { 277 | type Output = &'static struct_zbus_observer; 278 | 279 | fn get_c_reference(&self) -> Self::Output { 280 | self.c_reference 281 | } 282 | } 283 | 284 | unsafe impl Sync for Subscriber {} 285 | 286 | impl Subscriber { 287 | pub fn new(sub_ref: &'static struct_zbus_observer) -> Self { 288 | Self { 289 | c_reference: sub_ref, 290 | } 291 | } 292 | 293 | pub fn wait(&self, timeout: Duration) -> Result<*const struct_zbus_channel, i32> { 294 | let mut chan = struct_zbus_channel::init_mut(); 295 | match unsafe { 296 | ffi::zbus_sub_wait( 297 | self.c_reference, 298 | &mut chan as *mut _ as *mut struct_zbus_channel, 299 | ffi::zephyr_rs_timeout_from_ms(timeout.as_millis() as u32), 300 | ) 301 | } { 302 | 0 => Ok(chan as *const struct_zbus_channel), 303 | e => Err(e), 304 | } 305 | } 306 | } 307 | } 308 | 309 | struct ZephyrAllocator; 310 | 311 | unsafe impl GlobalAlloc for ZephyrAllocator { 312 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 313 | ffi::k_malloc(layout.size()) 314 | } 315 | 316 | unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { 317 | ffi::k_free(ptr) 318 | } 319 | } 320 | 321 | #[global_allocator] 322 | static GLOBAL: ZephyrAllocator = ZephyrAllocator; 323 | 324 | #[panic_handler] 325 | fn panic(info: &PanicInfo) -> ! { 326 | unsafe { 327 | ffi::printk( 328 | "[RUST PANIC] %s\n\0".as_ptr() as *const c_char, 329 | format!("{}\0", info).as_ptr() as *const c_char, 330 | ); 331 | } 332 | loop {} 333 | } 334 | 335 | #[alloc_error_handler] 336 | fn err_handler(layout: core::alloc::Layout) -> ! { 337 | unsafe { 338 | ffi::printk( 339 | "[RUST ALLOC ERROR] Layout %d\n\0".as_ptr() as *const c_char, 340 | layout.size() as i32, 341 | ); 342 | } 343 | loop {} 344 | } 345 | 346 | pub fn sleep(timeout: Duration) { 347 | unsafe { 348 | ffi::zephyr_rs_delay_ms(timeout.as_millis() as u32); 349 | } 350 | } 351 | 352 | pub enum LogLevel { 353 | Err = 0, 354 | Wrn = 1, 355 | Inf = 2, 356 | Dbg = 3, 357 | } 358 | 359 | extern "C" { 360 | #[link_name = "log_chan"] 361 | static c_log_chan: struct_zbus_channel; 362 | } 363 | 364 | static LOG_CHAN: zbus::Channel:: = zbus::Channel { 365 | c_reference: unsafe { &c_log_chan }, 366 | phantom: PhantomData, 367 | }; 368 | 369 | pub fn log(level: LogLevel, text: &str) { 370 | let x = struct_rs_log_msg { 371 | level: level as enum_rs_log_level, 372 | msg: text.as_ptr() as *const c_char, 373 | size: text.len() as u8, 374 | }; 375 | LOG_CHAN.publish(&x, Duration::from_millis(200)).expect("It must publish!"); 376 | } 377 | 378 | #[macro_export] 379 | macro_rules! z_log_err { 380 | ($($args:tt)*) => {{ 381 | crate::zephyr::log(crate::zephyr::LogLevel::Err, format!($($args)*).as_str()); 382 | }} 383 | } 384 | 385 | #[macro_export] 386 | macro_rules! z_log_wrn { 387 | ($($args:tt)*) => {{ 388 | crate::zephyr::log(crate::zephyr::LogLevel::Wrn, format!($($args)*).as_str()); 389 | }} 390 | } 391 | #[macro_export] 392 | macro_rules! z_log_inf { 393 | ($($args:tt)*) => {{ 394 | crate::zephyr::log(crate::zephyr::LogLevel::Inf, format!($($args)*).as_str()); 395 | }} 396 | } 397 | #[macro_export] 398 | macro_rules! z_log_dbg { 399 | ($($args:tt)*) => {{ 400 | crate::zephyr::log(crate::zephyr::LogLevel::Dbg, format!($($args)*).as_str()); 401 | }} 402 | } 403 | 404 | #[macro_export] 405 | macro_rules! zbus_static_channel_declare { 406 | {name:$chan:ident, msg_type:$msg:ident} => { 407 | paste::paste! { 408 | extern "C" { 409 | #[link_name=stringify!($chan)] 410 | static [] : struct_zbus_channel; 411 | } 412 | static $chan : zbus::Channel::<$msg> = zbus::Channel{ 413 | c_reference: unsafe { & [] }, 414 | phantom: ::core::marker::PhantomData, 415 | }; 416 | } 417 | }; 418 | } 419 | 420 | #[macro_export] 421 | macro_rules! zbus_static_subscriber_declare { 422 | {name:$sub:ident} => { 423 | paste::paste! { 424 | extern "C" { 425 | #[link_name=stringify!($sub)] 426 | static [] : struct_zbus_observer; 427 | } 428 | static $sub : zbus::Subscriber = zbus::Subscriber{ 429 | c_reference: unsafe { & [] }, 430 | }; 431 | } 432 | }; 433 | } 434 | 435 | #[macro_export] 436 | macro_rules! printk { 437 | ($fmt:literal) => { 438 | if let Ok(c_string) = alloc::ffi::CString::new(format!("{}", format_args!($fmt))) { 439 | unsafe { 440 | zephyr::ffi::printk(c_string.into_raw()); 441 | } 442 | } 443 | }; 444 | ($fmt:literal,$($arg:expr),+) => { 445 | if let Ok(c_string) = alloc::ffi::CString::new($fmt) { 446 | unsafe { 447 | zephyr::ffi::printk(c_string.as_ptr(),$($arg),+); 448 | } 449 | } 450 | }; 451 | } 452 | --------------------------------------------------------------------------------