├── .cargo └── config.toml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── Cargo.toml ├── LICENSE ├── README.md ├── community-ports.md ├── freertos-cargo-build ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md └── src │ └── lib.rs ├── freertos-rust-examples ├── Cargo.toml ├── README.md ├── build.rs └── examples │ ├── linux │ ├── FreeRTOSConfig.h │ ├── hooks.c │ └── main.rs │ ├── nrf9160 │ ├── FreeRTOSConfig.h │ ├── main.rs │ └── memory.x │ ├── stm32-cortex-m3 │ ├── FreeRTOSConfig.h │ ├── README.md │ ├── layout.ld │ ├── main.rs │ └── memory.x │ ├── stm32-cortex-m4-blackpill │ ├── FreeRTOSConfig.h │ ├── README.md │ ├── main.rs │ └── memory.x │ └── win │ ├── FreeRTOSConfig.h │ ├── Run-time-stats-utils.c │ ├── hooks.c │ └── main.rs ├── freertos-rust ├── .gitignore ├── .vscode │ └── settings.json ├── Cargo.toml ├── README.md ├── build.rs └── src │ ├── allocator.rs │ ├── base.rs │ ├── critical.rs │ ├── delays.rs │ ├── event_group.rs │ ├── freertos │ ├── ports │ │ └── arm │ │ │ └── hooks.c │ └── shim.c │ ├── hooks.rs │ ├── isr.rs │ ├── lib.rs │ ├── mutex.rs │ ├── patterns │ ├── compute_task.rs │ ├── mod.rs │ ├── processor.rs │ └── pub_sub.rs │ ├── portmacro.h │ ├── prelude │ ├── mod.rs │ └── no_std.rs │ ├── queue.rs │ ├── semaphore.rs │ ├── shim.rs │ ├── task.rs │ ├── timers.rs │ ├── units.rs │ └── utils.rs └── publish-all.sh /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] 2 | rustflags = [ 3 | # LLD (shipped with the Rust toolchain) is used as the default linker 4 | "-C", "link-arg=-Tlink.x", 5 | 6 | # if you run into problems with LLD switch to the GNU linker by commenting out 7 | # this line 8 | # "-C", "linker=arm-none-eabi-ld", 9 | 10 | # if you need to link to pre-compiled C libraries provided by a C toolchain 11 | # use GCC as the linker by commenting out both lines above and then 12 | # uncommenting the three lines below 13 | # "-C", "linker=arm-none-eabi-gcc", 14 | # "-C", "link-arg=-Wl,-Tlink.x", 15 | # "-C", "link-arg=-nostartfiles", 16 | ] 17 | 18 | [build] 19 | # Pick a target or use --target 20 | # target = "x86_64-pc-windows-gnu" # Windows GNU Toolchain 21 | # target = "x86_64-pc-windows-msvc" # Windows MSVC Toolchain (no debugging) 22 | # target = "thumbv7m-none-eabi" # Cortex-M3 23 | # target = "thumbv7em-none-eabihf" # Cortex-M4 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | freertos-rust: 14 | name: Build freertos-rust 15 | runs-on: ubuntu-latest 16 | env: 17 | RUSTFLAGS: -D warnings # Warnings disabled only in CI 18 | steps: 19 | - name: Clone 20 | uses: actions/checkout@v3 21 | - name: Cache 22 | uses: actions/cache@v3 23 | with: 24 | path: | 25 | ~/.cargo/registry 26 | ~/.cargo/git 27 | ~/.rustup 28 | target 29 | key: ${{ runner.os }}-${{ runner.arch }} 30 | - name: Install Rust 31 | uses: dtolnay/rust-toolchain@nightly 32 | with: 33 | components: rustfmt, clippy 34 | #- name: Format 35 | # run: cargo fmt -- --check 36 | - name: Build 37 | run: cargo build --verbose 38 | #- name: Test 39 | # run: cargo test 40 | #- name: Clippy 41 | # run: cargo clippy -- -Dwarnings 42 | freertos-rust-stable: 43 | name: Build freertos-rust using stable 44 | runs-on: ubuntu-latest 45 | env: 46 | RUSTFLAGS: -D warnings # Warnings disabled only in CI 47 | steps: 48 | - name: Clone 49 | uses: actions/checkout@v3 50 | - name: Cache 51 | uses: actions/cache@v3 52 | with: 53 | path: | 54 | ~/.cargo/registry 55 | ~/.cargo/git 56 | ~/.rustup 57 | target 58 | key: ${{ runner.os }}-${{ runner.arch }}-stable 59 | - name: Install Rust 60 | uses: dtolnay/rust-toolchain@stable 61 | - name: Build 62 | run: cargo build --verbose --no-default-features --features=sync,time,hooks,interrupt --package freertos-rust # Don't build the whole workspace because the examples use nightly features which will fail the build 63 | freertos-rust-examples: 64 | name: Build examples 65 | runs-on: ubuntu-latest 66 | strategy: 67 | matrix: 68 | include: 69 | #- example: win 70 | # target: x86_64-pc-windows-gnu 71 | #- example: linux 72 | # target: x86_64-unknown-linux-gnu 73 | #- example: stm32-cortex-m3 74 | # target: thumbv7m-none-eabi 75 | - example: stm32-cortex-m4-blackpill 76 | target: thumbv7em-none-eabihf 77 | #- example: nrf9160 78 | # target: thumbv8m.main-none-eabihf 79 | #env: 80 | # RUSTFLAGS: -D warnings # Warnings disabled only in CI 81 | steps: 82 | - name: Clone 83 | uses: actions/checkout@v3 84 | with: 85 | submodules: recursive 86 | - name: Cache 87 | uses: actions/cache@v3 88 | with: 89 | path: | 90 | ~/.cargo/registry 91 | ~/.cargo/git 92 | ~/.rustup 93 | target 94 | key: ${{ runner.os }}-${{ runner.arch }} 95 | - name: Install Rust 96 | uses: dtolnay/rust-toolchain@nightly 97 | with: 98 | targets: ${{ matrix.target }} 99 | - name: Install cross deps 100 | run: | 101 | case ${{ matrix.target }} in 102 | "x86_64-pc-windows-gnu") 103 | sudo apt-get install -y gcc-mingw-w64 104 | ;; 105 | "thumbv7m-none-eabi" | "thumbv7em-none-eabihf" | "thumbv8m.main-none-eabihf") 106 | sudo apt-get install -y gcc-arm-none-eabi 107 | ;; 108 | esac 109 | - name: Build example 110 | run: cargo build --verbose --example ${{ matrix.example }} --target ${{ matrix.target }} 111 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.idea 3 | /.vscode 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "freertos-rust-examples/FreeRTOS-Kernel"] 2 | path = freertos-rust-examples/FreeRTOS-Kernel 3 | url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git 4 | [submodule "freertos-rust-examples/freertos-addons"] 5 | path = freertos-rust-examples/freertos-addons 6 | url = https://github.com/michaelbecker/freertos-addons.git 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "freertos-rust", 5 | "freertos-cargo-build", 6 | "freertos-rust-examples" 7 | ] 8 | 9 | [profile.release] 10 | codegen-units = 1 # better optimizations 11 | debug = true # symbols are nice and they don't increase the size on Flash 12 | lto = true # better optimizations 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lobaro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FreeRTOS-rust 2 | 3 | This project is based on code from [freertos.rs](https://github.com/hashmismatch/freertos.rs) and some additions to 4 | simplify the usage of [FreeRTOS](https://github.com/FreeRTOS/FreeRTOS-Kernel) in embedded applications written 5 | in Rust. 6 | 7 | In contrast to freertos.rs this crate differs in these points: 8 | 9 | - The application `main()` entry point is written in Rust. 10 | - The FreeRTOS scheduler can be started from Rust. 11 | - The FreeRTOS heap `MemMang/heap/heap_x.c`is used as global memory allocator for Rust 12 | - No need for a Clang skeleton project 13 | 14 | ## How it works 15 | 16 | The `freertos-cargo-build` build-dependency compiles the FreeRTOS code from its original "C" sources files into an 17 | archive to be linked against your Rust app. Internally it uses the [cc crate](https://docs.rs/crate/cc) and some meta 18 | info provided by your apps `build.rs`: 19 | 20 | 1. A path to the [FreeRTOS](https://github.com/FreeRTOS/FreeRTOS-Kernel) `Sources` 21 | 1. A path to the app specific `FreeRTOSConfig.h` 22 | 1. A relative path to the `FreeRTOS port` to be used, e.g. for ARM Cortex-M3 cores. 23 | 1. Optional: Additional C code to be compiled 24 | 25 | The `freertos-rust` dependency provides an interface to access all FreeRTOS functionality from your (embedded) 26 | Rust app. 27 | 28 | ## Usage 29 | 30 | 1. Checkout FreeRTOS: https://github.com/FreeRTOS/FreeRTOS-Kernel 31 | 32 | 1. Add dependencies to your Rust apps `Cargo.toml` 33 | 34 | ``` 35 | [dependencies] 36 | freertos-rust = "*" 37 | 38 | [build-dependencies] 39 | freertos-cargo-build = "*" 40 | ``` 41 | 42 | 1. Add this snippet to your apps `build.rs`: 43 | ``` 44 | fn main() { 45 | let mut b = freertos_cargo_build::Builder::new(); 46 | 47 | // Path to FreeRTOS kernel or set ENV "FREERTOS_SRC" instead 48 | b.freertos("path/to/FreeRTOS-Kernel"); 49 | b.freertos_config("src"); // Location of `FreeRTOSConfig.h` 50 | b.freertos_port("GCC/ARM_CM3"); // Port dir relativ to 'FreeRTOS-Kernel/portable' 51 | b.heap("heap_4.c"); // Set the heap_?.c allocator to use from 52 | // 'FreeRTOS-Kernel/portable/MemMang' (Default: heap_4.c) 53 | 54 | // b.get_cc().file("More.c"); // Optional additional C-Code to be compiled 55 | 56 | b.compile().unwrap_or_else(|e| { panic!("{}", e.to_string()) }); 57 | } 58 | ``` 59 | 60 | ### Used C compiler 61 | `freertos-cargo-build` depends on the [cc crate](https://docs.rs/crate/cc). So the C compiler 62 | used can be set by using the `CC` enviroment variable or otherwise defined by internal 63 | defaults. For the ARM architecture this is the `arm-none-eabi-gcc` which can be found [here](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads). 64 | 65 | ## Examples 66 | To get started there are examples in [freertos-rust-examples](freertos-rust-examples) for: 67 | 68 | * Cortex M33 (nRF9160) 69 | * Cortex M3 (STM32L151CBU6A) 70 | * Cortex M4 (STM32F411CEU6) 71 | * Windows 72 | * ...more to come... 73 | 74 | ## Project Crates 75 | * To build a project using this create see [freertos-cargo-build](freertos-cargo-build) 76 | * The runtime dependency for you FreeRTOS Rust application will be [freertos-rust](freertos-rust) 77 | 78 | 79 | # License 80 | This repository is using the MIT License. Some parts might state different licenses that need to be respected when used. 81 | 82 | * The [Linux port](https://github.com/michaelbecker/freertos-addons) is licensed under GPLv2 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /community-ports.md: -------------------------------------------------------------------------------- 1 | This is a list of ports added by the community 2 | 3 | * Board: STM32F3DISCOVERY 4 | CPU: STM32F303VC 5 | URL: https://github.com/sheref-sidarous/stm32f3discovery_freertos_rust 6 | -------------------------------------------------------------------------------- /freertos-cargo-build/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /freertos-cargo-build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "freertos-cargo-build" 3 | description = """ 4 | Utility lib for building & using FreeRTOS in rust projects inside the build.rs. 5 | """ 6 | version = "0.1.1" 7 | authors = ["Tobias Kaupat "] 8 | edition = "2018" 9 | license = "MIT" 10 | readme = "README.md" 11 | repository = "https://github.com/lobaro/FreeRTOS-rust" 12 | 13 | [lib] 14 | 15 | [dependencies] 16 | cc = "1.0.52" 17 | walkdir = "2.3.1" 18 | -------------------------------------------------------------------------------- /freertos-cargo-build/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /freertos-cargo-build/README.md: -------------------------------------------------------------------------------- 1 | # freertos-cargo-build 2 | Helper crate for building FreeRTOS applications with Cargo and Rust using a `build.rs`. 3 | 4 | To build an embedded application with FreeRTOS please refer 5 | to [freertos-rust home](https://github.com/lobaro/FreeRTOS-rust). 6 | 7 | 8 | ## Usage 9 | 10 | The crate is published on [crates.io](https://crates.io/crates/freertos-cargo-build) 11 | 12 | [build-dependencies] 13 | freertos-cargo-build = "*" 14 | 15 | Create a `build.rs` file to build FreeRTOS and other C code. See [freertos-rust home](https://github.com/lobaro/FreeRTOS-rust) for an initial example. 16 | -------------------------------------------------------------------------------- /freertos-cargo-build/src/lib.rs: -------------------------------------------------------------------------------- 1 | use cc::Build; 2 | use std::ffi::OsStr; 3 | use std::fmt::Display; 4 | use std::path::{Path, PathBuf}; 5 | use std::{env, fmt}; 6 | use walkdir::WalkDir; 7 | 8 | /// The FREERTOS_SRC env variable must point to the FreeRTOS kernel code. 9 | /// The Kernel can be found at Github: https://github.com/FreeRTOS/FreeRTOS-Kernel 10 | /// 11 | /// When not set, you can use the Builder to specify the path 12 | const ENV_KEY_FREERTOS_SRC: &str = "FREERTOS_SRC"; 13 | 14 | /// The FREERTOS_CONFIG variable must point to the directory 15 | /// where the FreeRTOSConfig.h file is located for the current project. 16 | /// 17 | /// When not set, you can use the Builder to specify the path 18 | const ENV_KEY_FREERTOS_CONFIG: &str = "DEP_FREERTOS_CONFIG"; 19 | 20 | /// FreeRTOS shim.c file to enable usage of FreeRTOS with freertos-rust crate 21 | /// This variable is set by freertos-rust build.rs 22 | const ENV_KEY_FREERTOS_SHIM: &str = "DEP_FREERTOS_SHIM"; 23 | 24 | #[derive(Clone, Debug)] 25 | pub struct Builder { 26 | freertos_dir: PathBuf, 27 | freertos_config_dir: PathBuf, 28 | freertos_shim: PathBuf, 29 | freertos_port: Option, 30 | freertos_port_base: Option, 31 | // name of the heap_?.c file 32 | heap_c: PathBuf, 33 | cc: Build, 34 | } 35 | 36 | pub struct Error { 37 | /// More explanation of error that occurred. 38 | message: String, 39 | } 40 | 41 | impl Error { 42 | fn new(message: &str) -> Error { 43 | Error { 44 | message: message.to_owned(), 45 | } 46 | } 47 | } 48 | 49 | impl Display for Error { 50 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 51 | write!(f, "{}", self.message) 52 | } 53 | } 54 | 55 | impl Default for Builder { 56 | fn default() -> Self { 57 | let freertos_path = env::var(ENV_KEY_FREERTOS_SRC).unwrap_or_default(); 58 | let freertos_config_path = env::var(ENV_KEY_FREERTOS_CONFIG).unwrap_or_default(); 59 | let freertos_shim = env::var(ENV_KEY_FREERTOS_SHIM).unwrap_or_default(); 60 | 61 | Self { 62 | freertos_dir: PathBuf::from(freertos_path), 63 | freertos_config_dir: PathBuf::from(freertos_config_path), 64 | freertos_shim: PathBuf::from(freertos_shim), 65 | freertos_port: None, 66 | freertos_port_base: None, 67 | cc: cc::Build::new(), 68 | heap_c: PathBuf::from("heap_4.c"), 69 | } 70 | } 71 | } 72 | 73 | impl Builder { 74 | /// Construct a new instance of a blank set of configuration. 75 | /// 76 | /// This builder is finished with the [`compile`] function. 77 | /// 78 | /// [`compile`]: struct.Build.html#method.compile 79 | pub fn new() -> Builder { 80 | Self::default() 81 | } 82 | 83 | /// Set the path to freeRTOS source 84 | /// Default is loaded from ENV variable "FREERTOS_SRC" 85 | pub fn freertos>(&mut self, path: P) { 86 | self.freertos_dir = path.as_ref().to_path_buf(); 87 | } 88 | /// Set the path to freeRTOSConfig.h 89 | /// Default is loaded from ENV variable, see: ENV_KEY_FREERTOS_CONFIG 90 | pub fn freertos_config>(&mut self, path: P) { 91 | self.freertos_config_dir = path.as_ref().to_path_buf(); 92 | } 93 | 94 | /// Set the path to shim.c (required for freertos-rust) 95 | /// Default is loaded from ENV variable, see: ENV_KEY_FREERTOS_SHIM 96 | pub fn freertos_shim>(&mut self, path: P) { 97 | self.freertos_shim = path.as_ref().to_path_buf(); 98 | } 99 | 100 | /// Returns a list of all files in the shim folder 101 | fn freertos_shim_files(&self) -> Vec { 102 | let files: Vec<_> = WalkDir::new(self.freertos_shim.as_path()) 103 | .follow_links(false) 104 | .max_depth(1) 105 | .into_iter() 106 | .filter_map(|e| e.ok()) 107 | .filter_map(|entry| { 108 | let f_name = entry.path().to_str().unwrap(); 109 | 110 | if f_name.ends_with(".c") { 111 | return Some(entry.path().to_owned()); 112 | } 113 | None 114 | }) 115 | .collect(); 116 | files 117 | } 118 | 119 | /// Returns a list of all FreeRTOS source files 120 | fn freertos_files(&self) -> Vec { 121 | let files: Vec<_> = WalkDir::new(self.freertos_dir.as_path()) 122 | .follow_links(false) 123 | .max_depth(1) 124 | .into_iter() 125 | .filter_map(|e| e.ok()) 126 | .filter_map(|entry| { 127 | let f_name = entry.path().to_str().unwrap(); 128 | 129 | if f_name.ends_with(".c") { 130 | return Some(entry.path().to_owned()); 131 | } 132 | None 133 | }) 134 | .collect(); 135 | files 136 | } 137 | fn freertos_port_files(&self) -> Vec { 138 | let files: Vec<_> = WalkDir::new(self.get_freertos_port_dir()) 139 | .follow_links(false) 140 | .into_iter() 141 | .filter_map(|e| e.ok()) 142 | .filter_map(|entry| { 143 | match entry 144 | .path() 145 | .extension() 146 | .map(|s| s.to_string_lossy()) 147 | .as_ref() 148 | .map(|s| s.as_ref()) 149 | { 150 | Some("c" | "s" | "S") => Some(entry.path().to_owned()), 151 | _ => None, 152 | } 153 | }) 154 | .collect(); 155 | files 156 | } 157 | 158 | /// Set the heap_?.c file to use from the "/portable/MemMang/" folder. 159 | /// heap_1.c ... heap_5.c (Default: heap_4.c) 160 | /// see also: https://www.freertos.org/a00111.html 161 | pub fn heap>(&mut self, file_name: P) { 162 | self.heap_c = file_name.as_ref().to_path_buf(); 163 | } 164 | 165 | /// Access to the underlining cc::Build instance to further customize the build. 166 | pub fn get_cc(&mut self) -> &mut Build { 167 | &mut self.cc 168 | } 169 | 170 | fn freertos_include_dir(&self) -> PathBuf { 171 | self.freertos_dir.join("include") 172 | } 173 | 174 | /// set the freertos port dir relativ to the FreeRTOS/Source/portable directory 175 | /// e.g. "GCC/ARM_CM33_NTZ/non_secure" 176 | /// 177 | /// If not set it will be detected based on the current build target (not many targets supported yet). 178 | pub fn freertos_port>(&mut self, port_dir: P) { 179 | self.freertos_port = Some(port_dir.as_ref().to_path_buf()); 180 | } 181 | 182 | fn get_freertos_port_dir(&self) -> PathBuf { 183 | let base = self.get_freertos_port_base(); 184 | if self.freertos_port.is_some() { 185 | return base.join(self.freertos_port.as_ref().unwrap()); 186 | } 187 | 188 | let target = env::var("TARGET").unwrap_or_default(); 189 | let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default(); // msvc, gnu, ... 190 | //let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default(); // unix, windows 191 | let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); // x86_64 192 | let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); // none, windows, linux, macos 193 | let port = match ( 194 | target.as_str(), 195 | target_arch.as_str(), 196 | target_os.as_str(), 197 | target_env.as_str(), 198 | ) { 199 | (_, "x86_64", "windows", _) => "MSVC-MingW", 200 | (_, "x86_64", "linux", "gnu") => "GCC/Linux", 201 | ("thumbv7m-none-eabi", _, _, _) => "GCC/ARM_CM3", 202 | ("thumbv7em-none-eabi", _, _, _) => "GCC/ARM_CM3", // M4 cores without FPU use M3 203 | ("thumbv7em-none-eabihf", _, _, _) => "GCC/ARM_CM4F", 204 | // TODO We should support feature "trustzone" 205 | ("thumbv8m.main-none-eabi", _, _, _) => "GCC/ARM_CM33_NTZ/non_secure", 206 | ("thumbv8m.main-none-eabihf", _, _, _) => "GCC/ARM_CM33_NTZ/non_secure", 207 | _ => { 208 | panic!( 209 | "Unknown target: '{}', from TARGET environment variable.", 210 | target 211 | ); 212 | } 213 | }; 214 | base.join(port) 215 | } 216 | 217 | pub fn freertos_port_base>(&mut self, base_dir: P) { 218 | self.freertos_port_base = Some(base_dir.as_ref().to_path_buf()); 219 | } 220 | 221 | fn get_freertos_port_base(&self) -> PathBuf { 222 | if let Some(base) = &self.freertos_port_base { 223 | base.clone() 224 | } else { 225 | PathBuf::from(&self.freertos_dir).join("portable") 226 | } 227 | } 228 | 229 | fn heap_c_file(&self) -> PathBuf { 230 | self.freertos_dir 231 | .join("portable/MemMang") 232 | .join(&self.heap_c) 233 | } 234 | fn shim_c_file(&self) -> PathBuf { 235 | self.freertos_shim.join("shim.c") 236 | } 237 | 238 | /// Check that all required files and paths exist 239 | fn verify_paths(&self) -> Result<(), Error> { 240 | if !self.freertos_dir.is_dir() { 241 | return Err(Error::new(&format!( 242 | "Directory freertos_dir does not exist: {}", 243 | self.freertos_dir.to_str().unwrap() 244 | ))); 245 | } 246 | let port_dir = self.get_freertos_port_dir(); 247 | if !port_dir.is_dir() { 248 | return Err(Error::new(&format!( 249 | "Directory freertos_port_dir does not exist: {}", 250 | port_dir.to_str().unwrap() 251 | ))); 252 | } 253 | 254 | let include_dir = self.freertos_include_dir(); 255 | if !include_dir.is_dir() { 256 | return Err(Error::new(&format!( 257 | "Directory freertos_include_dir does not exist: {}", 258 | include_dir.to_str().unwrap() 259 | ))); 260 | } 261 | 262 | // The heap implementation 263 | let heap_c = self.heap_c_file(); 264 | if !heap_c.is_file() { 265 | return Err(Error::new(&format!( 266 | "File heap_?.c does not exist: {}", 267 | heap_c.to_str().unwrap() 268 | ))); 269 | } 270 | 271 | // Allows to find the FreeRTOSConfig.h 272 | if !self.freertos_config_dir.is_dir() { 273 | return Err(Error::new(&format!( 274 | "Directory freertos_config_dir does not exist: {}", 275 | self.freertos_config_dir.to_str().unwrap() 276 | ))); 277 | } 278 | // Make sure FreeRTOSConfig.h exists in freertos_config_dir 279 | if !self.freertos_config_dir.join("FreeRTOSConfig.h").is_file() { 280 | return Err(Error::new(&format!( 281 | "File FreeRTOSConfig.h does not exist in the freertos_config_dir directory: {}", 282 | self.freertos_config_dir.to_str().unwrap() 283 | ))); 284 | } 285 | 286 | // Add the freertos shim.c to support freertos-rust 287 | let shim_c = self.shim_c_file(); 288 | if !shim_c.is_file() { 289 | return Err(Error::new(&format!( 290 | "File freertos_shim '{}' does not exist, missing freertos-rust dependency?", 291 | shim_c.to_str().unwrap() 292 | ))); 293 | } 294 | 295 | Ok(()) 296 | } 297 | 298 | pub fn compile(&self) -> Result<(), Error> { 299 | let mut b = self.cc.clone(); 300 | 301 | self.verify_paths()?; 302 | 303 | add_include_with_rerun(&mut b, self.freertos_include_dir()); // FreeRTOS header files 304 | add_include_with_rerun(&mut b, self.get_freertos_port_dir()); // FreeRTOS port header files (e.g. portmacro.h) 305 | add_include_with_rerun(&mut b, &self.freertos_config_dir); // User's FreeRTOSConfig.h 306 | 307 | add_build_files_with_rerun(&mut b, self.freertos_files()); // Non-port C files 308 | add_build_files_with_rerun(&mut b, self.freertos_port_files()); // Port C files 309 | add_build_files_with_rerun(&mut b, self.freertos_shim_files()); // Shim C file 310 | add_build_file_with_rerun(&mut b, self.heap_c_file()); // Heap C file 311 | 312 | println!("cargo:rerun-if-env-changed={ENV_KEY_FREERTOS_SRC}"); 313 | println!("cargo:rerun-if-env-changed={ENV_KEY_FREERTOS_CONFIG}"); 314 | println!("cargo:rerun-if-env-changed={ENV_KEY_FREERTOS_SHIM}"); 315 | 316 | b.try_compile("freertos") 317 | .map_err(|e| Error::new(&format!("{}", e)))?; 318 | 319 | Ok(()) 320 | } 321 | 322 | /// Add a single file to the build. This also tags the file with cargo:rerun-if-changed so that cargo will re-run 323 | /// the build script if the file changes. If you don't want this additional behavior, use get_cc().file() to 324 | /// directly add a file to the build instead. 325 | pub fn add_build_file>(&mut self, file: P) { 326 | add_build_file_with_rerun(self.get_cc(), file); 327 | } 328 | 329 | /// Add multiple files to the build. This also tags the files with cargo:rerun-if-changed so that cargo will re-run 330 | /// the build script if the files change. If you don't want this additional behavior, use get_cc().files() to 331 | /// directly add files to the build instead. 332 | pub fn add_build_files

(&mut self, files: P) 333 | where 334 | P: IntoIterator, 335 | P::Item: AsRef, 336 | { 337 | add_build_files_with_rerun(self.get_cc(), files); 338 | } 339 | } 340 | 341 | fn add_build_file_with_rerun>(build: &mut Build, file: P) { 342 | build.file(&file); 343 | println!("cargo:rerun-if-changed={}", file.as_ref().display()); 344 | } 345 | 346 | fn add_build_files_with_rerun

(build: &mut Build, files: P) 347 | where 348 | P: IntoIterator, 349 | P::Item: AsRef, 350 | { 351 | for file in files.into_iter() { 352 | add_build_file_with_rerun(build, file); 353 | } 354 | } 355 | 356 | fn add_include_with_rerun>(build: &mut Build, dir: P) { 357 | build.include(&dir); 358 | 359 | WalkDir::new(&dir) 360 | .follow_links(false) 361 | .max_depth(1) 362 | .into_iter() 363 | .filter_map(|e| e.ok()) 364 | .for_each(|entry| { 365 | let f_name = entry.path(); 366 | if f_name.extension() == Some(OsStr::new("h")) { 367 | println!("cargo:rerun-if-changed={}", f_name.display()); 368 | } 369 | }); 370 | } 371 | 372 | #[test] 373 | fn test_paths() { 374 | env::set_var("FREERTOS_SRC", "some/path"); 375 | env::set_var("TARGET", "thumbv8m.main-none-eabihf"); 376 | let b = Builder::new(); 377 | assert_eq!(b.freertos_dir.to_str().unwrap(), "some/path"); 378 | } 379 | /* 380 | #[test] 381 | fn test_compile() { 382 | env::set_var("FREERTOS_SRC", "C:\\dev\\projects\\FreeRTOS\\FreeRTOS\\Source"); 383 | env::set_var("TARGET", "thumbv8m.main-none-eabihf"); 384 | env::set_var("OUT_DIR", "out"); 385 | env::set_var("OPT_LEVEL", "0"); 386 | env::set_var("HOST", "x86_64-pc-windows-gnu"); 387 | let mut b = Builder::new(); 388 | 389 | let res = b.compile(); 390 | 391 | if res.is_err() { 392 | panic!(res.err().unwrap().message) 393 | } 394 | assert!(res.is_ok()) 395 | }*/ 396 | -------------------------------------------------------------------------------- /freertos-rust-examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "freertos-rust-examples" 3 | version = "0.1.1" 4 | authors = ["Tobias Kaupat "] 5 | edition = "2018" 6 | description = """ 7 | Create to use FreeRTOS in rust projects. It contains binaries for demos on some architecutres. 8 | """ 9 | keywords = ["FreeRTOS", "embedded", "demo", "examples"] 10 | repository = "https://github.com/lobaro/FreeRTOS-rust" 11 | 12 | [dependencies] 13 | freertos-rust = {path = "../freertos-rust"} 14 | 15 | [target.'cfg(target_arch = "arm")'.dependencies] 16 | cortex-m = "0.6.0" 17 | cortex-m-rt = {version = "0.6.12"} 18 | nrf9160-pac = "0.2.1" 19 | 20 | # Example: stm32-cortex-m3 21 | [target.thumbv7m-none-eabi.dependencies] 22 | panic-halt = "0.2.0" 23 | stm32l1xx-hal = {version = "0.1.0", features = ["stm32l151"], default-features = false} 24 | 25 | # Example: stm32-cortex-m4-blackpill 26 | [target.thumbv7em-none-eabihf.dependencies] 27 | panic-halt = "0.2.0" 28 | embedded-hal = "0.2.3" 29 | stm32f4xx-hal = {version = "0.8.3", features = ["rt", "stm32f411"]} 30 | 31 | # Example: nrf9160 32 | [target."thumbv8m.main-none-eabihf".dependencies] 33 | nrf9160-pac = "0.2.1" 34 | 35 | # Example: win 36 | [target.x86_64-pc-windows-gnu.dependencies] 37 | 38 | # Example: linux 39 | [target.x86_64-unknown-linux-gnu.dependencies] 40 | 41 | [build-dependencies] 42 | freertos-cargo-build = {path = "../freertos-cargo-build"} -------------------------------------------------------------------------------- /freertos-rust-examples/README.md: -------------------------------------------------------------------------------- 1 | # FreeRTOS Rust Examples 2 | 3 | ## Setup 4 | 5 | We need to use nightly toolchain to support all examples. 6 | Even if some might run with the stable toolchain as well. 7 | 8 | **GNU Toolchain** is required for debugging some examples (e.g. windows): 9 | 10 | rustup default nightly 11 | rustup toolchain install nightly-gnu 12 | rustup default nightly-gnu 13 | 14 | _If you have issues that the build does not ends, try th MSVC Toolchain!_ 15 | 16 | **MSVC Toolchain** is not working for debugging: 17 | 18 | rustup toolchain install stable-msvc 19 | rustup default nightly-msvc 20 | 21 | Add you target, e.g. for Cortex-M3 (ARMv7-M architecture): 22 | 23 | rustup target add thumbv7m-none-eabi 24 | 25 | Install required/useful tooling 26 | 27 | cargo install cargo-binutils 28 | rustup component add llvm-tools-preview 29 | 30 | ### Checkout 31 | 32 | The FreeRTOS Kernel source is a submodule of this repo, referencing the official FreeRTOS-Kernel distribution. 33 | Currently tagged at [v10.5.0](https://github.com/FreeRTOS/FreeRTOS-Kernel/releases/tag/V10.5.0). 34 | To checkout the submodule with the kernel sources: 35 | 36 | git submodule update --init --recursive 37 | 38 | ### Build 39 | 40 | cargo build --example win 41 | 42 | 43 | To see all errors use: 44 | 45 | cargo build -vv 46 | 47 | ### Run Windows Demo 48 | 49 | You need to build with nightly GNU to allow debugging. 50 | The target must be `x86_64-pc-windows-msvc` for the FreeRTOS `MSVC-MingW` port. 51 | 52 | Prepare the build with: 53 | 54 | rustup default nightly-x86_64-pc-windows-gnu 55 | rustup target add x86_64-pc-windows-msvc 56 | 57 | Run the build 58 | 59 | cargo run --package freertos-rust-examples --example win --target x86_64-pc-windows-msvc 60 | 61 | ### Run Linux Demo 62 | 63 | Prepare the build with: 64 | 65 | rustup default nightly 66 | rustup toolchain install nightly 67 | rustup target add x86_64-unknown-linux-gnu 68 | rustup component add llvm-tools-preview 69 | cargo install cargo-binutils 70 | 71 | sudo apt install gcc g++ make 72 | 73 | Run the build 74 | 75 | cargo build --package freertos-rust-examples --example linux --target x86_64-unknown-linux-gnu 76 | 77 | Run the example 78 | 79 | cargo run --package freertos-rust-examples --example linux --target x86_64-unknown-linux-gnu 80 | 81 | ### Run STM32 Cortex-M3 Demo 82 | 83 | we need the nightly build for some features like allocator_api: 84 | 85 | rustup default nightly-x86_64-pc-windows-gnu // TODO: Build does not finish with GNU Toolchain 86 | rustup default nightly-x86_64-pc-windows-msvc 87 | rustup target add thumbv7m-none-eabi 88 | 89 | Build the binary: 90 | 91 | cargo build --package freertos-rust-examples --example stm32-cortex-m3 --target thumbv7m-none-eabi 92 | 93 | Create hex file to be flashed: 94 | 95 | cargo objcopy --example stm32-cortex-m3 --target thumbv7m-none-eabi -- -O ihex stm32-cortex-m3.hex 96 | 97 | ### Run STM32 Cortex-M4 Demo 98 | 99 | As the previous example, we need nightly toolchain and the target is thumbv7em-none-eabihf: 100 | rustup target add thumbv7em-none-eabihf 101 | 102 | Build the binary: 103 | 104 | cargo build --package freertos-rust-examples --example stm32-cortex-m4-blackpill --target thumbv7em-none-eabihf 105 | 106 | Create hex file to be flashed: 107 | 108 | cargo objcopy --example stm32-cortex-m4-blackpill --target thumbv7em-none-eabihf -- -O ihex stm32-cortex-m4-blackpill.hex 109 | 110 | ### Run nRF9160 Demo 111 | 112 | Setup: 113 | 114 | rustup default nightly-x86_64-pc-windows-msvc 115 | rustup target add thumbv8m.main-none-eabihf 116 | 117 | Build: 118 | 119 | cargo build --package freertos-rust-examples --example nrf9160 --target thumbv8m.main-none-eabihf 120 | 121 | Create hex file to be flashed: 122 | 123 | cargo objcopy --example nrf9160 --target thumbv8m.main-none-eabihf -- -O ihex nrf9160.hex 124 | 125 | **CLion Embedded GDB Server Settings** (for debugging): 126 | 127 | * Go to: _File | Settings | Build, Execution, Deployment | Custom Build Targets_: 128 | * Click Add 129 | * Name: `nrf9160-example` 130 | * Toolchain: `arm-none-eabi` 131 | 132 | Create the Toolchain under: `File | Settings | Build, Execution, Deployment | Toolchains` 133 | 134 | * Name: `arm-none-eabi` 135 | * Debugger: `/path/to/arm-none-eabi-gdb.exe` 136 | 137 | Build: 138 | 139 | * Name: `build-nrf9160-example` 140 | * Programm: `cargo` 141 | * Arguments: `build --package freertos-rust-examples --example nrf9160 --target thumbv8m.main-none-eabihf` 142 | * Working directory: `$ProjectFileDir$` 143 | 144 | Clean: 145 | 146 | * Name: `clean` 147 | * Programm: `cargo` 148 | * Arguments: `clean` 149 | * Working directory: `$ProjectFileDir$` 150 | 151 | Setup a Run Configuration: 152 | 153 | * Executable: `target\thumbv8m.main-none-eabihf\debug\examples\nrf9160` (only selectable after first build!) 154 | * Download executable: `Always` 155 | * 'target remote' args: `tcp:localhost:2331` 156 | * GDB Server: `path/to/JLinkGDBServerCL.exe` 157 | * GDB Server args: `-select USB -device nRF9160 -endian little -if SWD -speed 10000 -LocalhostOnly -noir` 158 | 159 | 160 | ## CLion Settings 161 | 162 | To get proper auto completion for macros (e.g. in HAL crates for GPIOs) you have to set 163 | *Settings | Languages & Frameworks | Rust | Expand declarative macros* to `Expand with experimental engine`. 164 | -------------------------------------------------------------------------------- /freertos-rust-examples/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::copy; 3 | use std::path::PathBuf; 4 | 5 | fn main() { 6 | // Allows to show relevant environment variables for debugging purpose 7 | print_env(); 8 | 9 | let target = env::var("TARGET").unwrap_or_default(); 10 | let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default(); 11 | let target_family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default(); 12 | let out_dir = env::var("OUT_DIR").unwrap(); 13 | 14 | let mut b = freertos_cargo_build::Builder::new(); 15 | 16 | b.freertos("FreeRTOS-Kernel/"); 17 | 18 | // Windows example specific stuff. 19 | if target_family == "windows" { 20 | b.freertos_config("examples/win"); 21 | // TODO: in future all FreeRTOS API should be implemented by the freertos-rust crate 22 | // until then, we need to compile some C code manually 23 | b.add_build_file("examples/win/hooks.c"); 24 | b.add_build_file("examples/win/Run-time-stats-utils.c"); 25 | 26 | if target_env == "msvc" { 27 | println!("cargo:rustc-link-lib=static=winmm"); 28 | } 29 | } 30 | 31 | if target == "x86_64-unknown-linux-gnu" { 32 | b.freertos_config("examples/linux"); 33 | b.freertos_port_base("freertos-addons/Linux/portable"); 34 | 35 | b.add_build_file("examples/linux/hooks.c"); 36 | // b.add_build_file("examples/linux/Run-time-stats-utils.c"); // Unimplemented yet.. 37 | } 38 | 39 | if target == "thumbv7m-none-eabi" { 40 | b.freertos_config("examples/stm32-cortex-m3"); 41 | copy( 42 | "examples/stm32-cortex-m3/memory.x", 43 | PathBuf::from(out_dir.as_str()).join("memory.x"), 44 | ) 45 | .unwrap(); 46 | } 47 | if target == "thumbv7em-none-eabihf" { 48 | b.freertos_config("examples/stm32-cortex-m4-blackpill"); 49 | copy( 50 | "examples/stm32-cortex-m4-blackpill/memory.x", 51 | PathBuf::from(out_dir.as_str()).join("memory.x"), 52 | ) 53 | .unwrap(); 54 | } 55 | if target == "thumbv8m.main-none-eabihf" { 56 | b.freertos_config("examples/nrf9160"); 57 | copy( 58 | "examples/nrf9160/memory.x", 59 | PathBuf::from(out_dir.as_str()).join("memory.x"), 60 | ) 61 | .unwrap(); 62 | } 63 | 64 | b.compile().unwrap_or_else(|e| panic!("{}", e)); 65 | } 66 | 67 | /// Print relevant environment variables. 68 | /// To avoid cluttering the output on each build, this is not displayed in the terminal. 69 | /// See the output in the corresponding target output file e.g. target/debug/build//output 70 | fn print_env() { 71 | let env_keys = ["TARGET", "OUT_DIR", "HOST"]; 72 | env::vars().for_each(|(key, val)| { 73 | if key.starts_with("CARGO") { 74 | println!("{}={}", key, val); 75 | } else if env_keys.contains(&key.as_str()) { 76 | println!("{}={}", key, val); 77 | } else { 78 | // println!("{}={}", key, val); 79 | } 80 | }); 81 | } 82 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/linux/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd. 3 | All rights reserved 4 | VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 5 | This file is part of the FreeRTOS distribution. 6 | FreeRTOS is free software; you can redistribute it and/or modify it under 7 | the terms of the GNU General Public License (version 2) as published by the 8 | Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. 9 | *************************************************************************** 10 | >>! NOTE: The modification to the GPL is included to allow you to !<< 11 | >>! distribute a combined work that includes FreeRTOS without being !<< 12 | >>! obliged to provide the source code for proprietary components !<< 13 | >>! outside of the FreeRTOS kernel. !<< 14 | *************************************************************************** 15 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 16 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | FOR A PARTICULAR PURPOSE. Full license text is available on the following 18 | link: http://www.freertos.org/a00114.html 19 | *************************************************************************** 20 | * * 21 | * FreeRTOS provides completely free yet professionally developed, * 22 | * robust, strictly quality controlled, supported, and cross * 23 | * platform software that is more than just the market leader, it * 24 | * is the industry's de facto standard. * 25 | * * 26 | * Help yourself get started quickly while simultaneously helping * 27 | * to support the FreeRTOS project by purchasing a FreeRTOS * 28 | * tutorial book, reference manual, or both: * 29 | * http://www.FreeRTOS.org/Documentation * 30 | * * 31 | *************************************************************************** 32 | http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 33 | the FAQ page "My application does not run, what could be wrong?". Have you 34 | defined configASSERT()? 35 | http://www.FreeRTOS.org/support - In return for receiving this top quality 36 | embedded software for free we request you assist our global community by 37 | participating in the support forum. 38 | http://www.FreeRTOS.org/training - Investing in training allows your team to 39 | be as productive as possible as early as possible. Now you can receive 40 | FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 41 | Ltd, and the world's leading authority on the world's leading RTOS. 42 | http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 43 | including FreeRTOS+Trace - an indispensable productivity tool, a DOS 44 | compatible FAT file system, and our tiny thread aware UDP/IP stack. 45 | http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 46 | Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 47 | http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 48 | Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 49 | licenses offer ticketed support, indemnification and commercial middleware. 50 | http://www.SafeRTOS.com - High Integrity Systems also provide a safety 51 | engineered and independently SIL3 certified version for use in safety and 52 | mission critical applications that require provable dependability. 53 | 1 tab == 4 spaces! 54 | */ 55 | 56 | 57 | #ifndef FREERTOS_CONFIG_H 58 | #define FREERTOS_CONFIG_H 59 | 60 | #ifdef __cplusplus 61 | extern "C" { 62 | #endif 63 | 64 | /*----------------------------------------------------------- 65 | * Application specific definitions. 66 | * 67 | * These definitions should be adjusted for your particular hardware and 68 | * application requirements. 69 | * 70 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 71 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 72 | *----------------------------------------------------------*/ 73 | 74 | #define configUSE_PREEMPTION 1 75 | #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 76 | #define configUSE_IDLE_HOOK 0 77 | #define configUSE_TICK_HOOK 0 78 | #define configTICK_RATE_HZ ( 1000 ) 79 | #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 50 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */ 80 | #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 23 * 1024 ) ) 81 | #define configMAX_TASK_NAME_LEN ( 12 ) 82 | #define configUSE_TRACE_FACILITY 1 83 | #define configUSE_16_BIT_TICKS 0 84 | #define configIDLE_SHOULD_YIELD 1 85 | #define configUSE_MUTEXES 1 86 | #define configCHECK_FOR_STACK_OVERFLOW 0 87 | #define configUSE_RECURSIVE_MUTEXES 1 88 | #define configQUEUE_REGISTRY_SIZE 20 89 | #define configUSE_MALLOC_FAILED_HOOK 1 90 | #define configUSE_APPLICATION_TASK_TAG 1 91 | #define configUSE_COUNTING_SEMAPHORES 1 92 | #define configUSE_QUEUE_SETS 1 93 | #define configUSE_TASK_NOTIFICATIONS 1 94 | 95 | /* Software timer related configuration options. */ 96 | #define configUSE_TIMERS 1 97 | #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) 98 | #define configTIMER_QUEUE_LENGTH 20 99 | #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) 100 | 101 | #define configMAX_PRIORITIES ( 7 ) 102 | 103 | /* Run time stats gathering configuration options. */ 104 | unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ 105 | #define configGENERATE_RUN_TIME_STATS 1 106 | /* Make use of times(man 2) to gather run-time statistics on the tasks. */ 107 | extern void vPortFindTicksPerSecond( void ); 108 | #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vPortFindTicksPerSecond() 109 | extern unsigned long ulPortGetTimerValue( void ); 110 | #define portGET_RUN_TIME_COUNTER_VALUE() ulPortGetTimerValue() 111 | 112 | /* Co-routine related configuration options. */ 113 | #define configUSE_CO_ROUTINES 1 114 | #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) 115 | 116 | /* This demo makes use of one or more example stats formatting functions. These 117 | format the raw data provided by the uxTaskGetSystemState() function in to human 118 | readable ASCII form. See the notes in the implementation of vTaskList() within 119 | FreeRTOS/Source/tasks.c for limitations. */ 120 | #define configUSE_STATS_FORMATTING_FUNCTIONS 1 121 | 122 | /* Set the following definitions to 1 to include the API function, or zero 123 | to exclude the API function. In most cases the linker will remove unused 124 | functions anyway. */ 125 | #define INCLUDE_vTaskPrioritySet 1 126 | #define INCLUDE_uxTaskPriorityGet 1 127 | #define INCLUDE_vTaskDelete 1 128 | #define INCLUDE_vTaskCleanUpResources 0 129 | #define INCLUDE_vTaskSuspend 1 130 | #define INCLUDE_vTaskDelayUntil 1 131 | #define INCLUDE_vTaskDelay 1 132 | #define INCLUDE_uxTaskGetStackHighWaterMark 1 133 | #define INCLUDE_xTaskGetSchedulerState 1 134 | #define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 135 | #define INCLUDE_xTaskGetIdleTaskHandle 1 136 | #define INCLUDE_pcTaskGetTaskName 1 137 | #define INCLUDE_eTaskGetState 1 138 | #define INCLUDE_xSemaphoreGetMutexHolder 1 139 | #define INCLUDE_xTimerPendFunctionCall 1 140 | 141 | /* It is a good idea to define configASSERT() while developing. configASSERT() 142 | uses the same semantics as the standard C assert() macro. */ 143 | extern void vAssertCalled( const char * const pcFileName, unsigned long ulLine ); 144 | #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) 145 | 146 | /* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ 147 | #define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() 148 | #define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() 149 | /*#include "trcKernelPort.h" */ 150 | 151 | #ifdef __cplusplus 152 | } 153 | #endif 154 | 155 | 156 | #endif /* FREERTOS_CONFIG_H */ -------------------------------------------------------------------------------- /freertos-rust-examples/examples/linux/hooks.c: -------------------------------------------------------------------------------- 1 | /* Standard includes. */ 2 | #include 3 | #include 4 | 5 | /* FreeRTOS kernel includes. */ 6 | #include "FreeRTOS.h" 7 | #include "task.h" 8 | 9 | /* 10 | * Prototypes for the standard FreeRTOS application hook (callback) functions 11 | * implemented within this file. See http://www.freertos.org/a00016.html . 12 | */ 13 | void vApplicationMallocFailedHook(void); 14 | void vApplicationIdleHook(void); 15 | void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName); 16 | void vApplicationTickHook(void); 17 | void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize); 18 | void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize); 19 | 20 | /*-----------------------------------------------------------*/ 21 | 22 | /* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can 23 | use a callback function to optionally provide the memory required by the idle 24 | and timer tasks. This is the stack that will be used by the timer task. It is 25 | declared here, as a global, so it can be checked by a test that is implemented 26 | in a different file. */ 27 | StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; 28 | 29 | void vApplicationMallocFailedHook(void) { 30 | /* vApplicationMallocFailedHook() will only be called if 31 | configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook 32 | function that will get called if a call to pvPortMalloc() fails. 33 | pvPortMalloc() is called internally by the kernel whenever a task, queue, 34 | timer or semaphore is created. It is also called by various parts of the 35 | demo application. If heap_1.c, heap_2.c or heap_4.c is being used, then the 36 | size of the heap available to pvPortMalloc() is defined by 37 | configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() 38 | API function can be used to query the size of free heap space that remains 39 | (although it does not provide information on how the remaining heap might be 40 | fragmented). See http://www.freertos.org/a00111.html for more 41 | information. */ 42 | configASSERT(1); 43 | } 44 | /*-----------------------------------------------------------*/ 45 | 46 | void vApplicationIdleHook(void) { 47 | /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set 48 | to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle 49 | task. It is essential that code added to this hook function never attempts 50 | to block in any way (for example, call xQueueReceive() with a block time 51 | specified, or call vTaskDelay()). If application tasks make use of the 52 | vTaskDelete() API function to delete themselves then it is also important 53 | that vApplicationIdleHook() is permitted to return to its calling function, 54 | because it is the responsibility of the idle task to clean up memory 55 | allocated by the kernel to any task that has since deleted itself. */ 56 | } 57 | /*-----------------------------------------------------------*/ 58 | 59 | void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { 60 | (void) pcTaskName; 61 | (void) pxTask; 62 | 63 | /* Run time stack overflow checking is performed if 64 | configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook 65 | function is called if a stack overflow is detected. This function is 66 | provided as an example only as stack overflow checking does not function 67 | when running the FreeRTOS Windows port. */ 68 | configASSERT(1); 69 | } 70 | /*-----------------------------------------------------------*/ 71 | 72 | void vApplicationTickHook(void) { 73 | /* This function will be called by each tick interrupt if 74 | configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be 75 | added here, but the tick hook is called from an interrupt context, so 76 | code must not attempt to block, and only the interrupt safe FreeRTOS API 77 | functions can be used (those that end in FromISR()). */ 78 | } 79 | /*-----------------------------------------------------------*/ 80 | 81 | void vApplicationDaemonTaskStartupHook(void) { 82 | /* This function will be called once only, when the daemon task starts to 83 | execute (sometimes called the timer task). This is useful if the 84 | application includes initialisation code that would benefit from executing 85 | after the scheduler has been started. */ 86 | } 87 | /*-----------------------------------------------------------*/ 88 | 89 | /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an 90 | implementation of vApplicationGetIdleTaskMemory() to provide the memory that is 91 | used by the Idle task. */ 92 | void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { 93 | /* If the buffers to be provided to the Idle task are declared inside this 94 | function then they must be declared static - otherwise they will be allocated on 95 | the stack and so not exists after this function exits. */ 96 | static StaticTask_t xIdleTaskTCB; 97 | static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; 98 | 99 | /* Pass out a pointer to the StaticTask_t structure in which the Idle task's 100 | state will be stored. */ 101 | *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; 102 | 103 | /* Pass out the array that will be used as the Idle task's stack. */ 104 | *ppxIdleTaskStackBuffer = uxIdleTaskStack; 105 | 106 | /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. 107 | Note that, as the array is necessarily of type StackType_t, 108 | configMINIMAL_STACK_SIZE is specified in words, not bytes. */ 109 | *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; 110 | } 111 | /*-----------------------------------------------------------*/ 112 | /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the 113 | application must provide an implementation of vApplicationGetTimerTaskMemory() 114 | to provide the memory that is used by the Timer service task. */ 115 | void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { 116 | /* If the buffers to be provided to the Timer task are declared inside this 117 | function then they must be declared static - otherwise they will be allocated on 118 | the stack and so not exists after this function exits. */ 119 | static StaticTask_t xTimerTaskTCB; 120 | 121 | /* Pass out a pointer to the StaticTask_t structure in which the Timer 122 | task's state will be stored. */ 123 | *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; 124 | 125 | /* Pass out the array that will be used as the Timer task's stack. */ 126 | *ppxTimerTaskStackBuffer = uxTimerTaskStack; 127 | 128 | /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. 129 | Note that, as the array is necessarily of type StackType_t, 130 | configMINIMAL_STACK_SIZE is specified in words, not bytes. */ 131 | *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; 132 | } 133 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/linux/main.rs: -------------------------------------------------------------------------------- 1 | use freertos_rust::*; 2 | 3 | #[global_allocator] 4 | static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; 5 | 6 | 7 | fn main() { 8 | let x = Box::new(15); 9 | println!("Boxed int '{}' (allocator test)", x); 10 | 11 | unsafe { 12 | FREERTOS_HOOKS.set_on_assert(|| { println!("Assert hook called") }); 13 | } 14 | 15 | //println!("Calling assert ..."); 16 | //FreeRtosUtils::invoke_assert(); 17 | 18 | println!("Starting FreeRTOS app ..."); 19 | Task::new().name("hello").stack_size(128).priority(TaskPriority(2)).start(|_this_task| { 20 | let mut i = 0; 21 | loop { 22 | println!("Hello from Task! {}", i); 23 | CurrentTask::delay(Duration::ms(1000)); 24 | i = i + 1; 25 | } 26 | }).unwrap(); 27 | println!("Task registered"); 28 | //let free = freertos_rs_xPortGetFreeHeapSize(); 29 | // println!("Free Memory: {}!", free); 30 | println!("Starting scheduler"); 31 | FreeRtosUtils::start_scheduler(); 32 | #[allow(unreachable_code)] 33 | loop { 34 | println!("Loop forever!"); 35 | } 36 | } 37 | 38 | #[test] 39 | fn many_boxes() { 40 | init_allocator(); 41 | println!("many_boxes... "); 42 | for i in 0..10 { // .. HEAP_SIZE 43 | let x = Box::new(i); 44 | assert_eq!(*x, i); 45 | } 46 | println!("[ok]"); 47 | } 48 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/nrf9160/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * FreeRTOS Kernel V10.2.0 4 | * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * http://www.FreeRTOS.org 24 | * http://aws.amazon.com/freertos 25 | * 26 | * 1 tab == 4 spaces! 27 | * 28 | * The FreeRTOS Cortex M33 port can be configured to run on the Secure Side only 29 | * i.e. the processor boots as secure and never jumps to the non-secure side. 30 | * The Trust Zone support in the port must be disabled in order to run FreeRTOS 31 | * on the secure side. The following are the valid configuration seetings: 32 | * 33 | * 1. Run FreeRTOS on the Secure Side: 34 | * configRUN_FREERTOS_SECURE_ONLY = 1 and configENABLE_TRUSTZONE = 0 35 | * 36 | * 2. Run FreeRTOS on the Non-Secure Side with Secure Side function call support: 37 | * configRUN_FREERTOS_SECURE_ONLY = 0 and configENABLE_TRUSTZONE = 1 38 | * 39 | * 3. Run FreeRTOS on the Non-Secure Side only i.e. no Secure Side function call support: 40 | * configRUN_FREERTOS_SECURE_ONLY = 0 and configENABLE_TRUSTZONE = 0 41 | */ 42 | 43 | /****************************************************************************** 44 | See http://www.freertos.org/a00110.html for an explanation of the 45 | definitions contained in this file. 46 | ******************************************************************************/ 47 | 48 | #ifndef FREERTOS_CONFIG_H 49 | #define FREERTOS_CONFIG_H 50 | 51 | /*----------------------------------------------------------- 52 | * Application specific definitions. 53 | * 54 | * These definitions should be adjusted for your particular hardware and 55 | * application requirements. 56 | * 57 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 58 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 59 | * http://www.freertos.org/a00110.html 60 | *----------------------------------------------------------*/ 61 | 62 | // FreeRTOS Exception handler mapping to rust cortex-m-rt crate linker file naming 63 | #define SVC_Handler SVCall 64 | #define SysTick_Handler SysTick 65 | #define PendSV_Handler PendSV 66 | 67 | //extern uint32_t SystemCoreClock; 68 | 69 | #define configRUN_FREERTOS_SECURE_ONLY 1 70 | #define configENABLE_TRUSTZONE 0 71 | 72 | #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 73 | 74 | /* Cortex M33 port configuration. */ 75 | #define configENABLE_MPU 0 76 | #define configENABLE_FPU 1 77 | 78 | #define configSUPPORT_DYNAMIC_ALLOCATION 1 79 | 80 | /* Constants related to the behaviour or the scheduler. */ 81 | #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 82 | #define configUSE_PREEMPTION 1 83 | #define configUSE_TIME_SLICING 1 84 | #define configMAX_PRIORITIES ( 5 ) 85 | #define configIDLE_SHOULD_YIELD 1 86 | #define configUSE_16_BIT_TICKS 0 /* Only for 8 and 16-bit hardware. */ 87 | 88 | /* Constants that describe the hardware and memory usage. */ 89 | #define configCPU_CLOCK_HZ (64000000UL) // 64M // from HAL: SystemCoreClock 90 | #define configMINIMAL_STACK_SIZE ( ( uint16_t ) 128 ) 91 | #define configMINIMAL_SECURE_STACK_SIZE ( 1024 ) 92 | #define configMAX_TASK_NAME_LEN ( 12 ) 93 | #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 50 * 1024 ) ) 94 | 95 | /* Constants that build features in or out. */ 96 | #define configUSE_MUTEXES 1 97 | #define configUSE_TICKLESS_IDLE 0 98 | #define configUSE_APPLICATION_TASK_TAG 0 99 | #define configUSE_NEWLIB_REENTRANT 0 100 | #define configUSE_CO_ROUTINES 0 101 | #define configUSE_COUNTING_SEMAPHORES 1 102 | #define configUSE_RECURSIVE_MUTEXES 1 103 | #define configUSE_QUEUE_SETS 0 104 | #define configUSE_TASK_NOTIFICATIONS 1 105 | #define configUSE_TRACE_FACILITY 1 106 | 107 | /* Constants that define which hook (callback) functions should be used. */ 108 | #define configUSE_IDLE_HOOK 0 109 | #define configUSE_TICK_HOOK 0 110 | #define configUSE_MALLOC_FAILED_HOOK 0 111 | 112 | /* Constants provided for debugging and optimisation assistance. */ 113 | #define configCHECK_FOR_STACK_OVERFLOW 2 114 | 115 | extern void vAssertCalled(const char *file, int linenum); 116 | 117 | #define configASSERT(x) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) 118 | #define configQUEUE_REGISTRY_SIZE 0 119 | 120 | /* Software timer definitions. */ 121 | #define configUSE_TIMERS 1 122 | #define configTIMER_TASK_PRIORITY ( 3 ) 123 | #define configTIMER_QUEUE_LENGTH 5 124 | #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE ) 125 | 126 | /* Have FreeRTOS provide an errno variable in task handle. 127 | * We need errno for bsd_lib */ 128 | #define configUSE_POSIX_ERRNO 1 129 | 130 | /* Set the following definitions to 1 to include the API function, or zero 131 | * to exclude the API function. NOTE: Setting an INCLUDE_ parameter to 0 is 132 | * only necessary if the linker does not automatically remove functions that are 133 | * not referenced anyway. */ 134 | #define INCLUDE_vTaskPrioritySet 1 135 | #define INCLUDE_uxTaskPriorityGet 1 136 | #define INCLUDE_vTaskDelete 1 137 | #define INCLUDE_vTaskCleanUpResources 0 138 | #define INCLUDE_vTaskSuspend 1 139 | #define INCLUDE_vTaskDelayUntil 1 140 | #define INCLUDE_vTaskDelay 1 141 | #define INCLUDE_uxTaskGetStackHighWaterMark 0 142 | #define INCLUDE_xTaskGetIdleTaskHandle 0 143 | #define INCLUDE_eTaskGetState 1 144 | #define INCLUDE_xTaskResumeFromISR 0 145 | #define INCLUDE_xTaskGetCurrentTaskHandle 1 146 | #define INCLUDE_xTaskGetSchedulerState 0 147 | #define INCLUDE_xSemaphoreGetMutexHolder 0 148 | #define INCLUDE_xTimerPendFunctionCall 1 149 | 150 | /* This demo makes use of one or more example stats formatting functions. These 151 | * format the raw data provided by the uxTaskGetSystemState() function in to 152 | * human readable ASCII form. See the notes in the implementation of vTaskList() 153 | * within FreeRTOS/Source/tasks.c for limitations. */ 154 | #define configUSE_STATS_FORMATTING_FUNCTIONS 1 155 | 156 | /* Dimensions a buffer that can be used by the FreeRTOS+CLI command interpreter. 157 | * See the FreeRTOS+CLI documentation for more information: 158 | * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_CLI/ */ 159 | #define configCOMMAND_INT_MAX_OUTPUT_SIZE 2048 160 | 161 | /* Interrupt priority configuration follows...................... */ 162 | 163 | /* Use the system definition, if there is one. */ 164 | #ifdef __NVIC_PRIO_BITS 165 | #define configPRIO_BITS __NVIC_PRIO_BITS 166 | #else 167 | #define configPRIO_BITS 3 /* 8 priority levels. */ 168 | #endif 169 | 170 | /* The lowest interrupt priority that can be used in a call to a "set priority" 171 | * function. */ 172 | #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x07 173 | 174 | /* The highest interrupt priority that can be used by any interrupt service 175 | * routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT 176 | * CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A 177 | * HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values). */ 178 | #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2 179 | 180 | /* Interrupt priorities used by the kernel port layer itself. These are generic 181 | * to all Cortex-M ports, and do not rely on any particular library functions. */ 182 | #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) ) 183 | 184 | /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! 185 | * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ 186 | #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) ) 187 | 188 | /* The #ifdef guards against the file being included from IAR assembly files. */ 189 | #ifndef __IASMARM__ 190 | 191 | /* Constants related to the generation of run time stats. */ 192 | #define configGENERATE_RUN_TIME_STATS 0 193 | #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 194 | #define portGET_RUN_TIME_COUNTER_VALUE() 0 195 | #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) 196 | 197 | #endif /* __IASMARM__ */ 198 | 199 | /* Enable static allocation. */ 200 | //#define configSUPPORT_STATIC_ALLOCATION 1 201 | 202 | #endif /* FREERTOS_CONFIG_H */ 203 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/nrf9160/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | // For allocator 4 | #![feature(lang_items)] 5 | #![feature(alloc_error_handler)] 6 | 7 | 8 | use cortex_m_rt::{entry, exception, ExceptionFrame}; 9 | use nrf9160_pac as nrf9160; 10 | use cortex_m::asm; 11 | 12 | use core::panic::PanicInfo; 13 | use freertos_rust::*; 14 | use core::alloc::Layout; 15 | 16 | #[global_allocator] 17 | static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; 18 | 19 | // define what happens in an Out Of Memory (OOM) condition 20 | #[alloc_error_handler] 21 | fn alloc_error(_layout: Layout) -> ! { 22 | asm::bkpt(); 23 | loop {} 24 | } 25 | 26 | #[panic_handler] 27 | fn panic(_info: &PanicInfo) -> ! { 28 | loop {} 29 | } 30 | 31 | 32 | #[exception] 33 | unsafe fn DefaultHandler(irqn: i16) { 34 | do_blink(); 35 | // custom default handler 36 | // irqn is negative for Cortex-M exceptions 37 | // irqn is positive for device specific (line IRQ) 38 | //board_set_led(true); 39 | //panic!("Exception: {}", irqn); 40 | } 41 | 42 | 43 | #[exception] 44 | fn HardFault(_ef: &ExceptionFrame) -> ! { 45 | do_blink(); 46 | loop {} 47 | } 48 | 49 | fn do_blink() { 50 | let periphs = nrf9160::Peripherals::take().unwrap(); 51 | let p0 = periphs.P0_S; 52 | 53 | p0.dir.write(|w| w.pin31().bit(true)); 54 | 55 | loop { 56 | let mut baz = 0; 57 | p0.outset.write(|w| w.pin31().bit(true)); 58 | for i in 1..20000 { 59 | baz = i * 10; 60 | } 61 | p0.outclr.write(|w| w.pin31().bit(true)); 62 | 63 | for i in 1..20000 { 64 | baz = i * 10; 65 | } 66 | } 67 | } 68 | 69 | #[entry] 70 | fn main() -> ! { 71 | //asm::nop(); // To not have main optimize to abort in release mode, remove when you add code 72 | 73 | let h = Task::new().name("hello").stack_size(512).priority(TaskPriority(1)).start(|_this_task| { 74 | // Blink forever 75 | do_blink(); 76 | loop { 77 | 78 | } 79 | }).unwrap(); 80 | 81 | FreeRtosUtils::start_scheduler(); 82 | } 83 | 84 | fn test_function(arg: i32) -> i32 { 85 | let mut temp: f64 = arg as f64; 86 | temp = temp * 3.1415; 87 | temp as i32 88 | } 89 | 90 | // -xc /Users/lobaro/cpath/src/github.com/lobaro/c-build/gdb/gdb_nrf9160.txt 91 | // monitor reset 92 | // Workaround for https://github.com/rust-embedded/cortex-m-rt/issues/139 93 | // on stable: GDB set backtrace limit 32 94 | // or rustup default nightly or beta (>1.43.6) 95 | 96 | // FreeRTOS handler 97 | 98 | #[no_mangle] 99 | fn vApplicationMallocFailedHook() {} 100 | 101 | #[no_mangle] 102 | fn vApplicationIdleHook() {} 103 | 104 | #[no_mangle] 105 | fn vApplicationStackOverflowHook(pxTask: FreeRtosTaskHandle, pcTaskName: FreeRtosCharPtr) {} 106 | 107 | #[no_mangle] 108 | fn vApplicationTickHook() {} -------------------------------------------------------------------------------- /freertos-rust-examples/examples/nrf9160/memory.x: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0xc000 /* 48 KByte MCU boot code */ 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 /* 64 KByte of 256 KByte */ 5 | } 6 | 7 | 8 | /* This is where the call stack will be allocated. */ 9 | /* The stack is of the full descending type. */ 10 | /* You may want to use this variable to locate the call stack and static 11 | variables in different memory regions. Below is shown the default value */ 12 | /* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ 13 | 14 | /* You can use this symbol to customize the location of the .text section */ 15 | /* If omitted the .text section will be placed right after the .vector_table 16 | section */ 17 | /* This is required only on microcontrollers that store some configuration right 18 | after the vector table */ 19 | /* _stext = ORIGIN(FLASH) + 0x400; */ 20 | 21 | /* Example of putting non-initialized variables into custom RAM locations. */ 22 | /* This assumes you have defined a region RAM2 above, and in the Rust 23 | sources added the attribute `#[link_section = ".ram2bss"]` to the data 24 | you want to place there. */ 25 | /* Note that the section will not be zero-initialized by the runtime! */ 26 | /* SECTIONS { 27 | .ram2bss (NOLOAD) : ALIGN(4) { 28 | *(.ram2bss); 29 | . = ALIGN(4); 30 | } > RAM2 31 | } INSERT AFTER .bss; 32 | */ 33 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m3/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. 3 | All rights reserved 4 | 5 | VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 6 | 7 | This file is part of the FreeRTOS distribution. 8 | 9 | FreeRTOS is free software; you can redistribute it and/or modify it under 10 | the terms of the GNU General Public License (version 2) as published by the 11 | Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. 12 | 13 | *************************************************************************** 14 | >>! NOTE: The modification to the GPL is included to allow you to !<< 15 | >>! distribute a combined work that includes FreeRTOS without being !<< 16 | >>! obliged to provide the source code for proprietary components !<< 17 | >>! outside of the FreeRTOS kernel. !<< 18 | *************************************************************************** 19 | 20 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 21 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 22 | FOR A PARTICULAR PURPOSE. Full license text is available on the following 23 | link: http://www.freertos.org/a00114.html 24 | 25 | *************************************************************************** 26 | * * 27 | * FreeRTOS provides completely free yet professionally developed, * 28 | * robust, strictly quality controlled, supported, and cross * 29 | * platform software that is more than just the market leader, it * 30 | * is the industry's de facto standard. * 31 | * * 32 | * Help yourself get started quickly while simultaneously helping * 33 | * to support the FreeRTOS project by purchasing a FreeRTOS * 34 | * tutorial book, reference manual, or both: * 35 | * http://www.FreeRTOS.org/Documentation * 36 | * * 37 | *************************************************************************** 38 | 39 | http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 40 | the FAQ page "My application does not run, what could be wrong?". Have you 41 | defined configASSERT()? 42 | 43 | http://www.FreeRTOS.org/support - In return for receiving this top quality 44 | embedded software for free we request you assist our global community by 45 | participating in the support forum. 46 | 47 | http://www.FreeRTOS.org/training - Investing in training allows your team to 48 | be as productive as possible as early as possible. Now you can receive 49 | FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 50 | Ltd, and the world's leading authority on the world's leading RTOS. 51 | 52 | http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 53 | including FreeRTOS+Trace - an indispensable productivity tool, a DOS 54 | compatible FAT file system, and our tiny thread aware UDP/IP stack. 55 | 56 | http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 57 | Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 58 | 59 | http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 60 | Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 61 | licenses offer ticketed support, indemnification and commercial middleware. 62 | 63 | http://www.SafeRTOS.com - High Integrity Systems also provide a safety 64 | engineered and independently SIL3 certified version for use in safety and 65 | mission critical applications that require provable dependability. 66 | 67 | 1 tab == 4 spaces! 68 | */ 69 | 70 | #ifndef FREERTOS_CONFIG_H 71 | #define FREERTOS_CONFIG_H 72 | #include 73 | 74 | extern void vAssertCalled( const char * const pcFileName, unsigned long ulLine ); 75 | #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) 76 | 77 | #define vPortSVCHandler SVCall 78 | #define xPortPendSVHandler PendSV 79 | #define xPortSysTickHandler SysTick 80 | 81 | /*----------------------------------------------------------- 82 | * Application specific definitions. 83 | * 84 | * These definitions should be adjusted for your particular hardware and 85 | * application requirements. 86 | * 87 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 88 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 89 | * 90 | * See http://www.freertos.org/a00110.html. 91 | *----------------------------------------------------------*/ 92 | 93 | #define configUSE_PREEMPTION 1 94 | #define configUSE_IDLE_HOOK 0 95 | #define configUSE_TICK_HOOK 0 96 | #define configCPU_CLOCK_HZ ( 4200000UL ) //also systick runs at this frequency 97 | #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) //1000=1ms per tick, 100=10ms per tick 98 | #define configMAX_PRIORITIES ( 5 ) 99 | #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 80 ) 100 | #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 10 * 1024 ) ) // was 15 101 | #define configMAX_TASK_NAME_LEN ( 16 ) 102 | #define configUSE_TRACE_FACILITY 1 103 | #define configUSE_16_BIT_TICKS 0 104 | #define configIDLE_SHOULD_YIELD 1 105 | #define configUSE_MUTEXES 1 106 | #define configQUEUE_REGISTRY_SIZE 5 107 | #define configCHECK_FOR_STACK_OVERFLOW 2 108 | #define configUSE_RECURSIVE_MUTEXES 0 109 | #define configUSE_MALLOC_FAILED_HOOK 0 //TR 110 | #define configUSE_APPLICATION_TASK_TAG 0 111 | #define configUSE_TICKLESS_IDLE 0 //max tickless period with 16MHz sysclock = ~1sek 112 | #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 3 //min as ticks before geting in tickless sleep 113 | 114 | //http://www.freertos.org/Configuring-a-real-time-RTOS-application-to-use-software-timers.html 115 | #define configUSE_TIMERS 1 116 | #define configTIMER_TASK_PRIORITY 1 117 | #define configTIMER_QUEUE_LENGTH 10 118 | #define configTIMER_TASK_STACK_DEPTH 200 119 | 120 | //Lobaro specifig configs 121 | #define configUSE_LOBARO_TICKLESS_IDLE 1 //use optimized lobaro tickless idle implementation (clock scaling + stop mode for longer sleep periods) 122 | //configUSE_TICKLESS_IDLE must also be 1! 123 | 124 | extern void set_PA0_dbgOut(bool onOff); 125 | //Called immediately before entering tickless idle 126 | #define traceLOW_POWER_IDLE_BEGIN() //set_PA0_dbgOut(false) 127 | 128 | //Called when returning to the Idle task after a tickless idle. 129 | #define traceLOW_POWER_IDLE_END() //set_PA0_dbgOut(true) 130 | 131 | //optional processing for sleep tickless mode (short tickless periods) 132 | #define configPRE_STOP_PROCESSING( x ) 133 | #define configPOST_STOP_PROCESSING( x ) 134 | 135 | //optional processing for stop (deep sleep) tickless mode (long tickless periods > 5 sec) 136 | //note: clock is potentially slowed down if enough ticks could be suppressed! 137 | //so perform sysclock check before invoke timing relevant function as uart tx! 138 | #define configPRE_SLEEP_PROCESSING( x ) 139 | #define configPOST_SLEEP_PROCESSING( x ) 140 | 141 | 142 | /* Co-routine definitions. */ 143 | #define configUSE_CO_ROUTINES 0 144 | #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) 145 | 146 | /* Set the following definitions to 1 to include the API function, or zero 147 | to exclude the API function. */ 148 | 149 | #define INCLUDE_vTaskPrioritySet 1 150 | #define INCLUDE_uxTaskPriorityGet 1 151 | #define INCLUDE_vTaskDelete 1 152 | #define INCLUDE_vTaskCleanUpResources 0 153 | #define INCLUDE_vTaskSuspend 1 154 | #define INCLUDE_vTaskDelayUntil 1 155 | #define INCLUDE_vTaskDelay 1 156 | #define INCLUDE_uxTaskGetStackHighWaterMark 1 157 | #define INCLUDE_eTaskGetState 1 158 | 159 | /* Use the system definition, if there is one */ 160 | //#ifdef __NVIC_PRIO_BITS 161 | // #define configPRIO_BITS __NVIC_PRIO_BITS 162 | //#else 163 | // #define configPRIO_BITS 4 /* 15 priority levels */ 164 | //#endif 165 | #define configPRIO_BITS 4 /* 15 priority levels (STM32L15x*/ 166 | 167 | #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 168 | #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 169 | 170 | /* The lowest priority. */ 171 | #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 172 | /* Priority 5, or 95 as only the top four bits are implemented. */ 173 | /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! 174 | See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ 175 | #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 176 | 177 | /* Run time stats related macros. */ 178 | //#define configGENERATE_RUN_TIME_STATS 0 179 | #define configUSE_STATS_FORMATTING_FUNCTIONS (1) 180 | //#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() //vConfigureTimerForRunTimeStats() 181 | //#define portALT_GET_RUN_TIME_COUNTER_VALUE( ulCountValue ) 182 | // { 183 | // TIM_Cmd( TIM6, DISABLE ); 184 | // ulCountValue = ( ( ulTIM6_OverflowCount << 16UL ) | ( unsigned long ) TIM6->CNT ); 185 | // TIM_Cmd( TIM6, ENABLE ); 186 | // } 187 | 188 | #endif /* FREERTOS_CONFIG_H */ 189 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m3/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | The example is written for stm32l15x (STM32 Cortex-M3) -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m3/layout.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 5 | } -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m3/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | // For allocator 4 | #![feature(lang_items)] 5 | #![feature(alloc_error_handler)] 6 | 7 | extern crate panic_halt; // you can put a breakpoint on `rust_begin_unwind` to catch panics 8 | 9 | use cortex_m::asm; 10 | use cortex_m_rt::exception; 11 | use cortex_m_rt::{entry, ExceptionFrame}; 12 | use freertos_rust::*; 13 | use core::alloc::Layout; 14 | use stm32l1xx_hal as hal; 15 | use stm32l1xx_hal::hal::digital::v2::*; 16 | use stm32l1xx_hal::gpio::*; 17 | use stm32l1xx_hal::gpio::gpioa::PA1; 18 | 19 | 20 | #[global_allocator] 21 | static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; 22 | 23 | fn delay() { 24 | let mut _i = 0; 25 | for _ in 0..2_00 { 26 | _i += 1; 27 | } 28 | } 29 | 30 | fn delay_n(n: i32) { 31 | for _ in 0..n { 32 | delay(); 33 | } 34 | } 35 | 36 | static mut LED: Option>> = None; 37 | 38 | fn set_led(on: bool) { 39 | unsafe { 40 | let mut led = LED.take().unwrap(); 41 | if on { 42 | led.set_low(); 43 | } else { 44 | led.set_high(); 45 | } 46 | } 47 | } 48 | 49 | // Setup IO for the LED and blink, does not return. 50 | fn do_blink_forever() -> ! { 51 | loop { 52 | delay(); 53 | set_led(true); 54 | delay(); 55 | set_led(false); 56 | } 57 | } 58 | 59 | #[entry] 60 | fn main() -> ! { 61 | let dp = hal::stm32::Peripherals::take().unwrap(); 62 | 63 | // Set up the LED, it's connected to pin PA1. 64 | let gpioa: stm32l1xx_hal::gpio::gpioa::Parts = dp.GPIOA.split(); 65 | unsafe { LED = Some(gpioa.pa1.into_push_pull_output()); } 66 | 67 | // Initial blink 68 | set_led(true); 69 | delay_n(10); 70 | set_led(false); 71 | delay_n(10); 72 | 73 | // Just blink (does NOT work!) 74 | do_blink_forever(); 75 | 76 | // TODO: What comes now does not work yet! 77 | // Initialize Tasks and start FreeRTOS 78 | Task::new().name("hello").stack_size(128).priority(TaskPriority(1)).start(|_this_task| { 79 | // Just blink 80 | freertos_rust::CurrentTask::delay(Duration::ms(1000)); 81 | set_led(true); 82 | freertos_rust::CurrentTask::delay(Duration::ms(1000)); 83 | set_led(false); 84 | }).unwrap(); 85 | 86 | 87 | // TODO: Starting the scheduler fails, we need debugging to find the issue 88 | // Seems like we don't even get an assert 89 | FreeRtosUtils::start_scheduler(); 90 | } 91 | 92 | #[exception] 93 | fn DefaultHandler(_irqn: i16) { 94 | // custom default handler 95 | // irqn is negative for Cortex-M exceptions 96 | // irqn is positive for device specific (line IRQ) 97 | // set_led(true);(true); 98 | // panic!("Exception: {}", irqn); 99 | } 100 | 101 | 102 | #[exception] 103 | fn HardFault(_ef: &ExceptionFrame) -> ! { 104 | // Blink 3 times long when exception occures 105 | delay_n(10); 106 | for _ in 0..3 { 107 | set_led(true); 108 | delay_n(10); 109 | set_led(false); 110 | delay_n(5); 111 | } 112 | loop {} 113 | } 114 | 115 | // define what happens in an Out Of Memory (OOM) condition 116 | #[alloc_error_handler] 117 | fn alloc_error(_layout: Layout) -> ! { 118 | set_led(true); 119 | asm::bkpt(); 120 | loop {} 121 | } -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m3/memory.x: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 5 | } -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m4-blackpill/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. 3 | All rights reserved 4 | 5 | VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. 6 | 7 | This file is part of the FreeRTOS distribution. 8 | 9 | FreeRTOS is free software; you can redistribute it and/or modify it under 10 | the terms of the GNU General Public License (version 2) as published by the 11 | Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. 12 | 13 | *************************************************************************** 14 | >>! NOTE: The modification to the GPL is included to allow you to !<< 15 | >>! distribute a combined work that includes FreeRTOS without being !<< 16 | >>! obliged to provide the source code for proprietary components !<< 17 | >>! outside of the FreeRTOS kernel. !<< 18 | *************************************************************************** 19 | 20 | FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY 21 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 22 | FOR A PARTICULAR PURPOSE. Full license text is available on the following 23 | link: http://www.freertos.org/a00114.html 24 | 25 | *************************************************************************** 26 | * * 27 | * FreeRTOS provides completely free yet professionally developed, * 28 | * robust, strictly quality controlled, supported, and cross * 29 | * platform software that is more than just the market leader, it * 30 | * is the industry's de facto standard. * 31 | * * 32 | * Help yourself get started quickly while simultaneously helping * 33 | * to support the FreeRTOS project by purchasing a FreeRTOS * 34 | * tutorial book, reference manual, or both: * 35 | * http://www.FreeRTOS.org/Documentation * 36 | * * 37 | *************************************************************************** 38 | 39 | http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading 40 | the FAQ page "My application does not run, what could be wrong?". Have you 41 | defined configASSERT()? 42 | 43 | http://www.FreeRTOS.org/support - In return for receiving this top quality 44 | embedded software for free we request you assist our global community by 45 | participating in the support forum. 46 | 47 | http://www.FreeRTOS.org/training - Investing in training allows your team to 48 | be as productive as possible as early as possible. Now you can receive 49 | FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers 50 | Ltd, and the world's leading authority on the world's leading RTOS. 51 | 52 | http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, 53 | including FreeRTOS+Trace - an indispensable productivity tool, a DOS 54 | compatible FAT file system, and our tiny thread aware UDP/IP stack. 55 | 56 | http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. 57 | Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. 58 | 59 | http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High 60 | Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS 61 | licenses offer ticketed support, indemnification and commercial middleware. 62 | 63 | http://www.SafeRTOS.com - High Integrity Systems also provide a safety 64 | engineered and independently SIL3 certified version for use in safety and 65 | mission critical applications that require provable dependability. 66 | 67 | 1 tab == 4 spaces! 68 | */ 69 | 70 | #ifndef FREERTOS_CONFIG_H 71 | #define FREERTOS_CONFIG_H 72 | #include 73 | 74 | extern void vAssertCalled( unsigned long ulLine, const char * const pcFileName ); 75 | #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __LINE__, __FILE__ ) 76 | 77 | #define vPortSVCHandler SVCall 78 | #define xPortPendSVHandler PendSV 79 | #define xPortSysTickHandler SysTick 80 | 81 | /*----------------------------------------------------------- 82 | * Application specific definitions. 83 | * 84 | * These definitions should be adjusted for your particular hardware and 85 | * application requirements. 86 | * 87 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 88 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 89 | * 90 | * See http://www.freertos.org/a00110.html. 91 | *----------------------------------------------------------*/ 92 | 93 | #define configUSE_PREEMPTION 1 94 | #define configUSE_IDLE_HOOK 0 95 | #define configUSE_TICK_HOOK 0 96 | #define configCPU_CLOCK_HZ ( 4200000UL ) //also systick runs at this frequency 97 | #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) //1000=1ms per tick, 100=10ms per tick 98 | #define configMAX_PRIORITIES ( 5 ) 99 | #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 80 ) 100 | #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 15 * 1024 ) ) // was 15 101 | #define configMAX_TASK_NAME_LEN ( 16 ) 102 | #define configUSE_TRACE_FACILITY 1 103 | #define configUSE_16_BIT_TICKS 0 104 | #define configIDLE_SHOULD_YIELD 1 105 | #define configUSE_MUTEXES 1 106 | #define configQUEUE_REGISTRY_SIZE 5 107 | #define configCHECK_FOR_STACK_OVERFLOW 2 108 | #define configUSE_RECURSIVE_MUTEXES 0 109 | #define configUSE_MALLOC_FAILED_HOOK 0 //TR 110 | #define configUSE_APPLICATION_TASK_TAG 0 111 | #define configUSE_TICKLESS_IDLE 0 //max tickless period with 16MHz sysclock = ~1sek 112 | #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 3 //min as ticks before geting in tickless sleep 113 | 114 | //http://www.freertos.org/Configuring-a-real-time-RTOS-application-to-use-software-timers.html 115 | #define configUSE_TIMERS 1 116 | #define configTIMER_TASK_PRIORITY 1 117 | #define configTIMER_QUEUE_LENGTH 10 118 | #define configTIMER_TASK_STACK_DEPTH 200 119 | 120 | //Lobaro specifig configs 121 | #define configUSE_LOBARO_TICKLESS_IDLE 1 //use optimized lobaro tickless idle implementation (clock scaling + stop mode for longer sleep periods) 122 | //configUSE_TICKLESS_IDLE must also be 1! 123 | 124 | extern void set_PA0_dbgOut(bool onOff); 125 | //Called immediately before entering tickless idle 126 | #define traceLOW_POWER_IDLE_BEGIN() //set_PA0_dbgOut(false) 127 | 128 | //Called when returning to the Idle task after a tickless idle. 129 | #define traceLOW_POWER_IDLE_END() //set_PA0_dbgOut(true) 130 | 131 | //optional processing for sleep tickless mode (short tickless periods) 132 | #define configPRE_STOP_PROCESSING( x ) 133 | #define configPOST_STOP_PROCESSING( x ) 134 | 135 | //optional processing for stop (deep sleep) tickless mode (long tickless periods > 5 sec) 136 | //note: clock is potentially slowed down if enough ticks could be suppressed! 137 | //so perform sysclock check before invoke timing relevant function as uart tx! 138 | #define configPRE_SLEEP_PROCESSING( x ) 139 | #define configPOST_SLEEP_PROCESSING( x ) 140 | 141 | 142 | /* Co-routine definitions. */ 143 | #define configUSE_CO_ROUTINES 0 144 | #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) 145 | 146 | /* Set the following definitions to 1 to include the API function, or zero 147 | to exclude the API function. */ 148 | 149 | #define INCLUDE_vTaskPrioritySet 1 150 | #define INCLUDE_uxTaskPriorityGet 1 151 | #define INCLUDE_vTaskDelete 1 152 | #define INCLUDE_vTaskCleanUpResources 0 153 | #define INCLUDE_vTaskSuspend 1 154 | #define INCLUDE_vTaskDelayUntil 1 155 | #define INCLUDE_vTaskDelay 1 156 | #define INCLUDE_uxTaskGetStackHighWaterMark 1 157 | #define INCLUDE_eTaskGetState 1 158 | 159 | /* Use the system definition, if there is one */ 160 | //#ifdef __NVIC_PRIO_BITS 161 | // #define configPRIO_BITS __NVIC_PRIO_BITS 162 | //#else 163 | // #define configPRIO_BITS 4 /* 15 priority levels */ 164 | //#endif 165 | #define configPRIO_BITS 4 /* 15 priority levels (STM32L15x*/ 166 | 167 | #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 168 | #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 169 | 170 | /* The lowest priority. */ 171 | #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 172 | /* Priority 5, or 95 as only the top four bits are implemented. */ 173 | /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! 174 | See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ 175 | #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 176 | 177 | /* Run time stats related macros. */ 178 | //#define configGENERATE_RUN_TIME_STATS 0 179 | #define configUSE_STATS_FORMATTING_FUNCTIONS (1) 180 | //#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() //vConfigureTimerForRunTimeStats() 181 | //#define portALT_GET_RUN_TIME_COUNTER_VALUE( ulCountValue ) 182 | // { 183 | // TIM_Cmd( TIM6, DISABLE ); 184 | // ulCountValue = ( ( ulTIM6_OverflowCount << 16UL ) | ( unsigned long ) TIM6->CNT ); 185 | // TIM_Cmd( TIM6, ENABLE ); 186 | // } 187 | 188 | #endif /* FREERTOS_CONFIG_H */ 189 | 190 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m4-blackpill/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | The example is written for stm32f411ceu6 (STM32 Cortex-M4) 4 | 5 | https://stm32-base.org/boards/STM32F411CEU6-WeAct-Black-Pill-V2.0.html -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m4-blackpill/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | // For allocator 4 | #![feature(lang_items)] 5 | #![feature(alloc_error_handler)] 6 | 7 | use cortex_m::asm; 8 | use cortex_m_rt::exception; 9 | use cortex_m_rt::{entry, ExceptionFrame}; 10 | use embedded_hal::digital::v2::OutputPin; 11 | use freertos_rust::*; 12 | use core::alloc::Layout; 13 | use stm32f4xx_hal::gpio::*; 14 | 15 | use cortex_m; 16 | use stm32f4xx_hal as hal; 17 | 18 | use crate::hal::{ 19 | stm32::{Peripherals}, 20 | }; 21 | 22 | extern crate panic_halt; // panic handler 23 | 24 | #[global_allocator] 25 | static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; 26 | 27 | fn delay() { 28 | let mut _i = 0; 29 | for _ in 0..2_00 { 30 | _i += 1; 31 | } 32 | } 33 | 34 | fn delay_n(n: i32) { 35 | for _ in 0..n { 36 | delay(); 37 | } 38 | } 39 | 40 | pub struct MyDevice { 41 | d1: D1, 42 | } 43 | 44 | impl MyDevice 45 | { 46 | pub fn from_pins(d1: D1) -> MyDevice { 47 | MyDevice { 48 | d1 49 | } 50 | } 51 | pub fn set_led(&mut self,on:bool){ 52 | if on { 53 | self.d1.set_high(); 54 | } else { 55 | self.d1.set_low(); 56 | } 57 | } 58 | } 59 | 60 | #[entry] 61 | fn main() -> ! { 62 | let dp = Peripherals::take().unwrap(); 63 | let gpioc = dp.GPIOC.split(); 64 | let mut device = MyDevice::from_pins(gpioc.pc13.into_push_pull_output()); 65 | device.set_led(false); 66 | Task::new().name("hello").stack_size(128).priority(TaskPriority(2)).start(move |_| { 67 | loop{ 68 | freertos_rust::CurrentTask::delay(Duration::ms(1000)); 69 | device.set_led(true); 70 | freertos_rust::CurrentTask::delay(Duration::ms(1000)); 71 | device.set_led(false); 72 | } 73 | }).unwrap(); 74 | FreeRtosUtils::start_scheduler(); 75 | } 76 | 77 | #[exception] 78 | fn DefaultHandler(_irqn: i16) { 79 | // custom default handler 80 | // irqn is negative for Cortex-M exceptions 81 | // irqn is positive for device specific (line IRQ) 82 | // set_led(true);(true); 83 | // panic!("Exception: {}", irqn); 84 | } 85 | 86 | #[exception] 87 | fn HardFault(_ef: &ExceptionFrame) -> ! { 88 | // Blink 3 times long when exception occures 89 | delay_n(10); 90 | for _ in 0..3 { 91 | // set_led(true); 92 | // delay_n(1000); 93 | // set_led(false); 94 | // delay_n(555); 95 | } 96 | loop {} 97 | } 98 | 99 | // define what happens in an Out Of Memory (OOM) condition 100 | #[alloc_error_handler] 101 | fn alloc_error(_layout: Layout) -> ! { 102 | //set_led(true); 103 | asm::bkpt(); 104 | loop {} 105 | } 106 | 107 | #[no_mangle] 108 | fn vApplicationStackOverflowHook(pxTask: FreeRtosTaskHandle, pcTaskName: FreeRtosCharPtr) { 109 | asm::bkpt(); 110 | } 111 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/stm32-cortex-m4-blackpill/memory.x: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K 4 | RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K 5 | } -------------------------------------------------------------------------------- /freertos-rust-examples/examples/win/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | 29 | #ifndef FREERTOS_CONFIG_H 30 | #define FREERTOS_CONFIG_H 31 | 32 | /*----------------------------------------------------------- 33 | * Application specific definitions. 34 | * 35 | * These definitions should be adjusted for your particular hardware and 36 | * application requirements. 37 | * 38 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 39 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See 40 | * http://www.freertos.org/a00110.html 41 | *----------------------------------------------------------*/ 42 | 43 | #define configUSE_PREEMPTION 1 44 | #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 45 | #define configUSE_IDLE_HOOK 0 46 | #define configUSE_TICK_HOOK 0 47 | #define configUSE_DAEMON_TASK_STARTUP_HOOK 1 48 | #define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ 49 | #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 70 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */ 50 | #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 10 * 1024 ) ) 51 | #define configMAX_TASK_NAME_LEN ( 12 ) 52 | #define configUSE_TRACE_FACILITY 1 53 | #define configUSE_16_BIT_TICKS 0 54 | #define configIDLE_SHOULD_YIELD 1 55 | #define configUSE_MUTEXES 1 56 | #define configCHECK_FOR_STACK_OVERFLOW 0 57 | #define configUSE_RECURSIVE_MUTEXES 1 58 | #define configQUEUE_REGISTRY_SIZE 20 59 | #define configUSE_MALLOC_FAILED_HOOK 1 60 | #define configUSE_APPLICATION_TASK_TAG 1 61 | #define configUSE_COUNTING_SEMAPHORES 1 62 | #define configUSE_ALTERNATIVE_API 0 63 | #define configUSE_QUEUE_SETS 1 64 | #define configUSE_TASK_NOTIFICATIONS 1 65 | #define configSUPPORT_STATIC_ALLOCATION 1 66 | #define configINITIAL_TICK_COUNT ( ( TickType_t ) 0 ) /* For test. */ 67 | #define configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN 1 /* As there are a lot of tasks running. */ 68 | 69 | /* Software timer related configuration options. */ 70 | #define configUSE_TIMERS 1 71 | #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) 72 | #define configTIMER_QUEUE_LENGTH 20 73 | #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) 74 | 75 | #define configMAX_PRIORITIES ( 7 ) 76 | 77 | /* Run time stats gathering configuration options. */ 78 | unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ 79 | void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */ 80 | #define configGENERATE_RUN_TIME_STATS 0 81 | #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() 82 | #define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() 83 | 84 | /* Co-routine related configuration options. */ 85 | #define configUSE_CO_ROUTINES 1 86 | #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) 87 | 88 | /* This demo makes use of one or more example stats formatting functions. These 89 | format the raw data provided by the uxTaskGetSystemState() function in to human 90 | readable ASCII form. See the notes in the implementation of vTaskList() within 91 | FreeRTOS/Source/tasks.c for limitations. */ 92 | #define configUSE_STATS_FORMATTING_FUNCTIONS 1 93 | 94 | /* Set the following definitions to 1 to include the API function, or zero 95 | to exclude the API function. In most cases the linker will remove unused 96 | functions anyway. */ 97 | #define INCLUDE_vTaskPrioritySet 1 98 | #define INCLUDE_uxTaskPriorityGet 1 99 | #define INCLUDE_vTaskDelete 1 100 | #define INCLUDE_vTaskCleanUpResources 0 101 | #define INCLUDE_vTaskSuspend 1 102 | #define INCLUDE_vTaskDelayUntil 1 103 | #define INCLUDE_vTaskDelay 1 104 | #define INCLUDE_uxTaskGetStackHighWaterMark 1 105 | #define INCLUDE_xTaskGetSchedulerState 1 106 | #define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 107 | #define INCLUDE_xTaskGetIdleTaskHandle 1 108 | #define INCLUDE_xTaskGetHandle 1 109 | #define INCLUDE_eTaskGetState 1 110 | #define INCLUDE_xSemaphoreGetMutexHolder 1 111 | #define INCLUDE_xTimerPendFunctionCall 1 112 | #define INCLUDE_xTaskAbortDelay 1 113 | 114 | /* It is a good idea to define configASSERT() while developing. configASSERT() 115 | uses the same semantics as the standard C assert() macro. */ 116 | extern void vAssertCalled( const char * const pcFileName, unsigned long ulLine ); 117 | #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) 118 | 119 | #define configINCLUDE_MESSAGE_BUFFER_AMP_DEMO 0 120 | #if ( configINCLUDE_MESSAGE_BUFFER_AMP_DEMO == 1 ) 121 | extern void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer ); 122 | #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer ) 123 | #endif /* configINCLUDE_MESSAGE_BUFFER_AMP_DEMO */ 124 | 125 | /* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ 126 | #if configUSE_TRACE_FACILITY == 1 127 | //#include "trcRecorder.h" 128 | #endif 129 | 130 | #endif /* FREERTOS_CONFIG_H */ 131 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/win/Run-time-stats-utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | /* 29 | * Utility functions required to gather run time statistics. See: 30 | * http://www.freertos.org/rtos-run-time-stats.html 31 | * 32 | * Note that this is a simulated port, where simulated time is a lot slower than 33 | * real time, therefore the run time counter values have no real meaningful 34 | * units. 35 | * 36 | * Also note that it is assumed this demo is going to be used for short periods 37 | * of time only, and therefore timer overflows are not handled. 38 | */ 39 | 40 | /* FreeRTOS includes. */ 41 | #include 42 | 43 | /* Variables used in the creation of the run time stats time base. Run time 44 | stats record how much time each task spends in the Running state. */ 45 | static long long llInitialRunTimeCounterValue = 0LL, llTicksPerHundedthMillisecond = 0LL; 46 | 47 | /*-----------------------------------------------------------*/ 48 | 49 | void vConfigureTimerForRunTimeStats( void ) 50 | { 51 | LARGE_INTEGER liPerformanceCounterFrequency, liInitialRunTimeValue; 52 | 53 | /* Initialise the variables used to create the run time stats time base. 54 | Run time stats record how much time each task spends in the Running 55 | state. */ 56 | 57 | if( QueryPerformanceFrequency( &liPerformanceCounterFrequency ) == 0 ) 58 | { 59 | llTicksPerHundedthMillisecond = 1; 60 | } 61 | else 62 | { 63 | /* How many times does the performance counter increment in 1/100th 64 | millisecond. */ 65 | llTicksPerHundedthMillisecond = liPerformanceCounterFrequency.QuadPart / 100000LL; 66 | 67 | /* What is the performance counter value now, this will be subtracted 68 | from readings taken at run time. */ 69 | QueryPerformanceCounter( &liInitialRunTimeValue ); 70 | llInitialRunTimeCounterValue = liInitialRunTimeValue.QuadPart; 71 | } 72 | } 73 | /*-----------------------------------------------------------*/ 74 | 75 | unsigned long ulGetRunTimeCounterValue( void ) 76 | { 77 | LARGE_INTEGER liCurrentCount; 78 | unsigned long ulReturn; 79 | 80 | /* What is the performance counter value now? */ 81 | QueryPerformanceCounter( &liCurrentCount ); 82 | 83 | /* Subtract the performance counter value reading taken when the 84 | application started to get a count from that reference point, then 85 | scale to (simulated) 1/100ths of a millisecond. */ 86 | if( llTicksPerHundedthMillisecond == 0 ) 87 | { 88 | /* The trace macros are probably calling this function before the 89 | scheduler has been started. */ 90 | ulReturn = 0; 91 | } 92 | else 93 | { 94 | ulReturn = ( unsigned long ) ( ( liCurrentCount.QuadPart - llInitialRunTimeCounterValue ) / llTicksPerHundedthMillisecond ); 95 | } 96 | 97 | return ulReturn; 98 | } 99 | /*-----------------------------------------------------------*/ 100 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/win/hooks.c: -------------------------------------------------------------------------------- 1 | /* Standard includes. */ 2 | #include 3 | #include 4 | #include 5 | 6 | /* FreeRTOS kernel includes. */ 7 | #include "FreeRTOS.h" 8 | #include "task.h" 9 | 10 | /* 11 | * Prototypes for the standard FreeRTOS application hook (callback) functions 12 | * implemented within this file. See http://www.freertos.org/a00016.html . 13 | */ 14 | void vApplicationMallocFailedHook(void); 15 | void vApplicationIdleHook(void); 16 | void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName); 17 | void vApplicationTickHook(void); 18 | void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize); 19 | void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize); 20 | 21 | /*-----------------------------------------------------------*/ 22 | 23 | /* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can 24 | use a callback function to optionally provide the memory required by the idle 25 | and timer tasks. This is the stack that will be used by the timer task. It is 26 | declared here, as a global, so it can be checked by a test that is implemented 27 | in a different file. */ 28 | StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; 29 | 30 | void vApplicationMallocFailedHook(void) { 31 | /* vApplicationMallocFailedHook() will only be called if 32 | configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook 33 | function that will get called if a call to pvPortMalloc() fails. 34 | pvPortMalloc() is called internally by the kernel whenever a task, queue, 35 | timer or semaphore is created. It is also called by various parts of the 36 | demo application. If heap_1.c, heap_2.c or heap_4.c is being used, then the 37 | size of the heap available to pvPortMalloc() is defined by 38 | configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() 39 | API function can be used to query the size of free heap space that remains 40 | (although it does not provide information on how the remaining heap might be 41 | fragmented). See http://www.freertos.org/a00111.html for more 42 | information. */ 43 | configASSERT(1); 44 | } 45 | /*-----------------------------------------------------------*/ 46 | 47 | void vApplicationIdleHook(void) { 48 | /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set 49 | to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle 50 | task. It is essential that code added to this hook function never attempts 51 | to block in any way (for example, call xQueueReceive() with a block time 52 | specified, or call vTaskDelay()). If application tasks make use of the 53 | vTaskDelete() API function to delete themselves then it is also important 54 | that vApplicationIdleHook() is permitted to return to its calling function, 55 | because it is the responsibility of the idle task to clean up memory 56 | allocated by the kernel to any task that has since deleted itself. */ 57 | } 58 | /*-----------------------------------------------------------*/ 59 | 60 | void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { 61 | (void) pcTaskName; 62 | (void) pxTask; 63 | 64 | /* Run time stack overflow checking is performed if 65 | configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook 66 | function is called if a stack overflow is detected. This function is 67 | provided as an example only as stack overflow checking does not function 68 | when running the FreeRTOS Windows port. */ 69 | configASSERT(1); 70 | } 71 | /*-----------------------------------------------------------*/ 72 | 73 | void vApplicationTickHook(void) { 74 | /* This function will be called by each tick interrupt if 75 | configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be 76 | added here, but the tick hook is called from an interrupt context, so 77 | code must not attempt to block, and only the interrupt safe FreeRTOS API 78 | functions can be used (those that end in FromISR()). */ 79 | } 80 | /*-----------------------------------------------------------*/ 81 | 82 | void vApplicationDaemonTaskStartupHook(void) { 83 | /* This function will be called once only, when the daemon task starts to 84 | execute (sometimes called the timer task). This is useful if the 85 | application includes initialisation code that would benefit from executing 86 | after the scheduler has been started. */ 87 | } 88 | /*-----------------------------------------------------------*/ 89 | 90 | /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an 91 | implementation of vApplicationGetIdleTaskMemory() to provide the memory that is 92 | used by the Idle task. */ 93 | void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize) { 94 | /* If the buffers to be provided to the Idle task are declared inside this 95 | function then they must be declared static - otherwise they will be allocated on 96 | the stack and so not exists after this function exits. */ 97 | static StaticTask_t xIdleTaskTCB; 98 | static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; 99 | 100 | /* Pass out a pointer to the StaticTask_t structure in which the Idle task's 101 | state will be stored. */ 102 | *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; 103 | 104 | /* Pass out the array that will be used as the Idle task's stack. */ 105 | *ppxIdleTaskStackBuffer = uxIdleTaskStack; 106 | 107 | /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. 108 | Note that, as the array is necessarily of type StackType_t, 109 | configMINIMAL_STACK_SIZE is specified in words, not bytes. */ 110 | *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; 111 | } 112 | /*-----------------------------------------------------------*/ 113 | /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the 114 | application must provide an implementation of vApplicationGetTimerTaskMemory() 115 | to provide the memory that is used by the Timer service task. */ 116 | void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { 117 | /* If the buffers to be provided to the Timer task are declared inside this 118 | function then they must be declared static - otherwise they will be allocated on 119 | the stack and so not exists after this function exits. */ 120 | static StaticTask_t xTimerTaskTCB; 121 | 122 | /* Pass out a pointer to the StaticTask_t structure in which the Timer 123 | task's state will be stored. */ 124 | *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; 125 | 126 | /* Pass out the array that will be used as the Timer task's stack. */ 127 | *ppxTimerTaskStackBuffer = uxTimerTaskStack; 128 | 129 | /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. 130 | Note that, as the array is necessarily of type StackType_t, 131 | configMINIMAL_STACK_SIZE is specified in words, not bytes. */ 132 | *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; 133 | } 134 | -------------------------------------------------------------------------------- /freertos-rust-examples/examples/win/main.rs: -------------------------------------------------------------------------------- 1 | use freertos_rust::*; 2 | 3 | #[global_allocator] 4 | static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; 5 | 6 | 7 | fn main() { 8 | let x = Box::new(15); 9 | println!("Boxed int '{}' (allocator test)", x); 10 | 11 | unsafe { 12 | FREERTOS_HOOKS.set_on_assert(|| { println!("Assert hook called") }); 13 | } 14 | 15 | //println!("Calling assert ..."); 16 | //FreeRtosUtils::invoke_assert(); 17 | 18 | println!("Starting FreeRTOS app ..."); 19 | Task::new().name("hello").stack_size(128).priority(TaskPriority(2)).start(|_this_task| { 20 | let mut i = 0; 21 | loop { 22 | println!("Hello from Task! {}", i); 23 | CurrentTask::delay(Duration::ms(1000)); 24 | i = i + 1; 25 | } 26 | }).unwrap(); 27 | println!("Task registered"); 28 | //let free = freertos_rs_xPortGetFreeHeapSize(); 29 | // println!("Free Memory: {}!", free); 30 | println!("Starting scheduler"); 31 | FreeRtosUtils::start_scheduler(); 32 | loop { 33 | println!("Loop forever!"); 34 | } 35 | } 36 | 37 | #[test] 38 | fn many_boxes() { 39 | init_allocator(); 40 | println!("many_boxes... "); 41 | for i in 0..10 { // .. HEAP_SIZE 42 | let x = Box::new(i); 43 | assert_eq!(*x, i); 44 | } 45 | println!("[ok]"); 46 | } 47 | -------------------------------------------------------------------------------- /freertos-rust/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /freertos-rust/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /freertos-rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "freertos-rust" 3 | version = "0.1.2" 4 | authors = ["Tobias Kaupat "] 5 | edition = "2018" 6 | description = """ 7 | Create to use FreeRTOS in rust projects. 8 | The freertos-cargo-build crate can be used to build and link FreeRTOS from source inside build.rs. 9 | """ 10 | keywords = ["FreeRTOS", "embedded", "demo", "library"] 11 | license = "MIT" 12 | readme = "README.md" 13 | repository = "https://github.com/lobaro/FreeRTOS-rust" 14 | links = "freertos" 15 | 16 | [lib] 17 | name = "freertos_rust" 18 | path = "src/lib.rs" 19 | 20 | [features] 21 | default = ["allocator", "sync", "time", "hooks", "interrupt", "delete_task"] 22 | allocator = [] 23 | sync = ["interrupt"] 24 | time = ["interrupt"] 25 | hooks = [] 26 | interrupt = [] 27 | cpu_clock = [] 28 | delete_task = [] 29 | -------------------------------------------------------------------------------- /freertos-rust/README.md: -------------------------------------------------------------------------------- 1 | # FreeRTOS Rust 2 | 3 | Wrapper library to use FreeRTOS API in Rust. 4 | 5 | To build an embedded application with FreeRTOS please refer 6 | to [freertos-rust home](https://github.com/lobaro/FreeRTOS-rust). 7 | 8 | ## Usage 9 | 10 | The crate is published on [crates.io](https://crates.io/crates/freertos-rust) 11 | 12 | [dependencies] 13 | freertos-rust = "*" 14 | -------------------------------------------------------------------------------- /freertos-rust/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | 4 | // See: https://doc.rust-lang.org/cargo/reference/build-scripts.html 5 | fn main() { 6 | println!("cargo:rerun-if-changed=build.rs"); 7 | let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); 8 | println!( 9 | "cargo:SHIM={}", 10 | PathBuf::from(manifest_dir) 11 | .join("src/freertos") 12 | .to_str() 13 | .unwrap() 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /freertos-rust/src/allocator.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::shim::*; 3 | use core::alloc::{GlobalAlloc, Layout}; 4 | 5 | /** 6 | Use with: 7 | 8 | #[global_allocator] 9 | static GLOBAL: FreeRtosAllocator = FreeRtosAllocator; 10 | */ 11 | 12 | pub struct FreeRtosAllocator; 13 | 14 | unsafe impl GlobalAlloc for FreeRtosAllocator { 15 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 16 | let res = freertos_rs_pvPortMalloc(layout.size() as u32); 17 | return res as *mut u8; 18 | } 19 | 20 | unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { 21 | freertos_rs_vPortFree(ptr as FreeRtosVoidPtr) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /freertos-rust/src/base.rs: -------------------------------------------------------------------------------- 1 | use core::ffi::c_void; 2 | 3 | /// Basic error type for the library. 4 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 5 | pub enum FreeRtosError { 6 | OutOfMemory, 7 | QueueSendTimeout, 8 | QueueReceiveTimeout, 9 | MutexTimeout, 10 | Timeout, 11 | QueueFull, 12 | StringConversionError, 13 | TaskNotFound, 14 | InvalidQueueSize, 15 | ProcessorHasShutDown, 16 | } 17 | 18 | pub type FreeRtosVoidPtr = *const c_void; 19 | pub type FreeRtosMutVoidPtr = *mut c_void; 20 | pub type FreeRtosCharPtr = *const u8; 21 | pub type FreeRtosChar = u8; 22 | 23 | pub type FreeRtosBaseType = i32; 24 | pub type FreeRtosUBaseType = u32; 25 | pub type FreeRtosTickType = u32; 26 | pub type FreeRtosEventBitsType = u32; 27 | pub type FreeRtosBaseTypeMutPtr = *mut FreeRtosBaseType; 28 | 29 | pub type FreeRtosTaskHandle = *const c_void; 30 | pub type FreeRtosQueueHandle = *const c_void; 31 | pub type FreeRtosSemaphoreHandle = *const c_void; 32 | pub type FreeRtosEventGroupHandle = *const c_void; 33 | pub type FreeRtosTaskFunction = *const c_void; 34 | pub type FreeRtosTimerHandle = *const c_void; 35 | pub type FreeRtosTimerCallback = *const c_void; 36 | #[allow(dead_code)] 37 | pub type FreeRtosStackType = *const c_void; 38 | 39 | pub type FreeRtosUnsignedLong = u32; 40 | pub type FreeRtosUnsignedShort = u16; 41 | 42 | #[derive(Copy, Clone, Debug)] 43 | #[repr(C)] 44 | pub struct FreeRtosTaskStatusFfi { 45 | pub handle: FreeRtosTaskHandle, 46 | pub task_name: FreeRtosCharPtr, 47 | pub task_number: FreeRtosUBaseType, 48 | pub task_state: FreeRtosTaskState, 49 | pub current_priority: FreeRtosUBaseType, 50 | pub base_priority: FreeRtosUBaseType, 51 | pub run_time_counter: FreeRtosUnsignedLong, 52 | pub stack_base: FreeRtosCharPtr, 53 | pub stack_high_water_mark: FreeRtosUnsignedShort, 54 | } 55 | 56 | #[derive(Copy, Clone, Debug)] 57 | #[repr(u8)] 58 | pub enum FreeRtosTaskState { 59 | /// A task is querying the state of itself, so must be running. 60 | Running = 0, 61 | /// The task being queried is in a read or pending ready list. 62 | Ready = 1, 63 | /// The task being queried is in the Blocked state. 64 | Blocked = 2, 65 | /// The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. 66 | Suspended = 3, 67 | /// The task being queried has been deleted, but its TCB has not yet been freed. 68 | Deleted = 4, 69 | } 70 | -------------------------------------------------------------------------------- /freertos-rust/src/critical.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::prelude::v1::*; 3 | use crate::shim::*; 4 | 5 | pub struct CriticalRegion; 6 | impl CriticalRegion { 7 | pub fn enter() -> Self { 8 | unsafe { 9 | freertos_rs_enter_critical(); 10 | } 11 | 12 | CriticalRegion 13 | } 14 | } 15 | 16 | impl Drop for CriticalRegion { 17 | fn drop(&mut self) { 18 | unsafe { 19 | freertos_rs_exit_critical(); 20 | } 21 | } 22 | } 23 | 24 | unsafe impl Send for ExclusiveData {} 25 | unsafe impl Sync for ExclusiveData {} 26 | 27 | /// Data protected with a critical region. Lightweight version of a mutex, 28 | /// intended for simple data structures. 29 | pub struct ExclusiveData { 30 | data: UnsafeCell, 31 | } 32 | 33 | impl ExclusiveData { 34 | pub fn new(data: T) -> Self { 35 | ExclusiveData { 36 | data: UnsafeCell::new(data), 37 | } 38 | } 39 | 40 | pub fn lock(&self) -> Result, FreeRtosError> { 41 | Ok(ExclusiveDataGuard { 42 | __data: &self.data, 43 | __lock: CriticalRegion::enter(), 44 | }) 45 | } 46 | 47 | pub fn lock_from_isr( 48 | &self, 49 | _context: &mut crate::isr::InterruptContext, 50 | ) -> Result, FreeRtosError> { 51 | Ok(ExclusiveDataGuardIsr { __data: &self.data }) 52 | } 53 | } 54 | 55 | /// Holds the mutex until we are dropped 56 | pub struct ExclusiveDataGuard<'a, T: ?Sized + 'a> { 57 | __data: &'a UnsafeCell, 58 | __lock: CriticalRegion, 59 | } 60 | 61 | impl<'mutex, T: ?Sized> Deref for ExclusiveDataGuard<'mutex, T> { 62 | type Target = T; 63 | 64 | fn deref<'a>(&'a self) -> &'a T { 65 | unsafe { &*self.__data.get() } 66 | } 67 | } 68 | 69 | impl<'mutex, T: ?Sized> DerefMut for ExclusiveDataGuard<'mutex, T> { 70 | fn deref_mut<'a>(&'a mut self) -> &'a mut T { 71 | unsafe { &mut *self.__data.get() } 72 | } 73 | } 74 | 75 | pub struct ExclusiveDataGuardIsr<'a, T: ?Sized + 'a> { 76 | __data: &'a UnsafeCell, 77 | } 78 | 79 | impl<'mutex, T: ?Sized> Deref for ExclusiveDataGuardIsr<'mutex, T> { 80 | type Target = T; 81 | 82 | fn deref<'a>(&'a self) -> &'a T { 83 | unsafe { &*self.__data.get() } 84 | } 85 | } 86 | 87 | impl<'mutex, T: ?Sized> DerefMut for ExclusiveDataGuardIsr<'mutex, T> { 88 | fn deref_mut<'a>(&'a mut self) -> &'a mut T { 89 | unsafe { &mut *self.__data.get() } 90 | } 91 | } 92 | 93 | unsafe impl Send for SuspendScheduler {} 94 | unsafe impl Sync for SuspendScheduler {} 95 | 96 | /// Data protected with a critical region, implemented by suspending the 97 | /// FreeRTOS scheduler. 98 | pub struct SuspendScheduler { 99 | data: UnsafeCell, 100 | } 101 | 102 | impl SuspendScheduler { 103 | pub const fn new(data: T) -> Self { 104 | SuspendScheduler { 105 | data: UnsafeCell::new(data), 106 | } 107 | } 108 | 109 | pub fn lock(&self) -> SuspendSchedulerGuard { 110 | unsafe { 111 | freertos_rs_vTaskSuspendAll(); 112 | } 113 | SuspendSchedulerGuard { data: &self.data } 114 | } 115 | 116 | pub fn get_mut(&mut self) -> &mut T { 117 | self.data.get_mut() 118 | } 119 | 120 | pub fn into_inner(self) -> T { 121 | self.data.into_inner() 122 | } 123 | } 124 | 125 | pub struct SuspendSchedulerGuard<'a, T: ?Sized + 'a> { 126 | data: &'a UnsafeCell, 127 | } 128 | 129 | impl<'mutex, T: ?Sized> Deref for SuspendSchedulerGuard<'mutex, T> { 130 | type Target = T; 131 | 132 | fn deref<'a>(&'a self) -> &'a T { 133 | unsafe { &*self.data.get() } 134 | } 135 | } 136 | 137 | impl<'mutex, T: ?Sized> DerefMut for SuspendSchedulerGuard<'mutex, T> { 138 | fn deref_mut<'a>(&'a mut self) -> &'a mut T { 139 | unsafe { &mut *self.data.get() } 140 | } 141 | } 142 | 143 | impl<'mutex, T: ?Sized> Drop for SuspendSchedulerGuard<'mutex, T> { 144 | fn drop(&mut self) { 145 | unsafe { 146 | freertos_rs_xTaskResumeAll(); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /freertos-rust/src/delays.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::shim::*; 3 | use crate::task::*; 4 | use crate::units::*; 5 | 6 | /// Delay the current task by the given duration, minus the 7 | /// time that was spent processing the last wakeup loop. 8 | pub struct TaskDelay { 9 | last_wake_time: FreeRtosTickType, 10 | } 11 | 12 | impl TaskDelay { 13 | /// Create a new helper, marking the current time as the start of the 14 | /// next measurement. 15 | pub fn new() -> TaskDelay { 16 | TaskDelay { 17 | last_wake_time: FreeRtosUtils::get_tick_count(), 18 | } 19 | } 20 | 21 | /// Delay the execution of the current task by the given duration, 22 | /// minus the time spent in this task since the last delay. 23 | pub fn delay_until(&mut self, delay: D) { 24 | unsafe { 25 | freertos_rs_vTaskDelayUntil( 26 | &mut self.last_wake_time as *mut FreeRtosTickType, 27 | delay.to_ticks(), 28 | ); 29 | } 30 | } 31 | } 32 | 33 | /// Periodic delay timer. 34 | /// 35 | /// Use inside a polling loop, for example: the loop polls this instance every second. 36 | /// The method `should_run` will return true once 30 seconds or more has elapsed 37 | /// and it will then reset the timer for that period. 38 | pub struct TaskDelayPeriodic { 39 | last_wake_time: FreeRtosTickType, 40 | period_ticks: FreeRtosTickType, 41 | } 42 | 43 | impl TaskDelayPeriodic { 44 | /// Create a new timer with the set period. 45 | pub fn new(period: D) -> TaskDelayPeriodic { 46 | let l = FreeRtosUtils::get_tick_count(); 47 | 48 | TaskDelayPeriodic { 49 | last_wake_time: l, 50 | period_ticks: period.to_ticks(), 51 | } 52 | } 53 | 54 | /// Has the set period passed? If it has, resets the internal timer. 55 | pub fn should_run(&mut self) -> bool { 56 | let c = FreeRtosUtils::get_tick_count(); 57 | if (c - self.last_wake_time) < (self.period_ticks) { 58 | false 59 | } else { 60 | self.last_wake_time = c; 61 | true 62 | } 63 | } 64 | 65 | /// Set a new delay period 66 | pub fn set_period(&mut self, period: D) { 67 | self.period_ticks = period.to_ticks(); 68 | } 69 | 70 | /// Reset the internal timer to zero. 71 | pub fn reset(&mut self) { 72 | self.last_wake_time = FreeRtosUtils::get_tick_count(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /freertos-rust/src/event_group.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::shim::*; 3 | use crate::units::*; 4 | 5 | /// An event group 6 | pub struct EventGroup { 7 | event_group: FreeRtosEventGroupHandle, 8 | } 9 | 10 | unsafe impl Send for EventGroup {} 11 | unsafe impl Sync for EventGroup {} 12 | 13 | impl EventGroup { 14 | /// Create a new event group 15 | pub fn new() -> Result { 16 | unsafe { 17 | let s = freertos_rs_event_group_create(); 18 | if s == 0 as *const _ { 19 | return Err(FreeRtosError::OutOfMemory); 20 | } 21 | Ok(EventGroup { event_group: s }) 22 | } 23 | } 24 | 25 | /// # Safety 26 | /// 27 | /// `handle` must be a valid FreeRTOS event group handle. 28 | #[inline] 29 | pub unsafe fn from_raw_handle(handle: FreeRtosEventGroupHandle) -> Self { 30 | Self { event_group: handle } 31 | } 32 | #[inline] 33 | pub fn raw_handle(&self) -> FreeRtosEventGroupHandle { 34 | self.event_group 35 | } 36 | 37 | pub fn set_bits(&self, bits_to_set: FreeRtosEventBitsType) -> FreeRtosEventBitsType { 38 | unsafe { freertos_rs_event_group_set_bits(self.event_group, bits_to_set) } 39 | } 40 | 41 | pub fn get_bits(&self) -> FreeRtosEventBitsType { 42 | unsafe { freertos_rs_event_group_get_bits(self.event_group) } 43 | } 44 | 45 | pub fn clear_bits(&self, bits_to_clear: FreeRtosEventBitsType) -> FreeRtosEventBitsType { 46 | unsafe { freertos_rs_event_group_clear_bits(self.event_group, bits_to_clear) } 47 | } 48 | 49 | pub fn wait_bits(&self, bits_to_wait_for: FreeRtosEventBitsType, clear_on_exit: FreeRtosBaseType, wait_for_all_bits: FreeRtosBaseType, duration: D) -> FreeRtosEventBitsType { 50 | unsafe { freertos_rs_event_group_wait_bits(self.event_group, bits_to_wait_for, clear_on_exit, wait_for_all_bits, duration.to_ticks()) } 51 | } 52 | 53 | pub fn sync(&self, bits_to_set: FreeRtosEventBitsType, bits_to_wait_for: FreeRtosEventBitsType, duration: D) -> FreeRtosEventBitsType { 54 | unsafe { freertos_rs_event_group_sync(self.event_group, bits_to_set, bits_to_wait_for, duration.to_ticks()) } 55 | } 56 | } 57 | 58 | impl Drop for EventGroup { 59 | fn drop(&mut self) { 60 | unsafe { 61 | freertos_rs_event_group_delete(self.event_group); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /freertos-rust/src/freertos/ports/arm/hooks.c: -------------------------------------------------------------------------------- 1 | /* FreeRTOS kernel includes. */ 2 | #include "FreeRTOS.h" 3 | #include "task.h" 4 | 5 | /* This project provides two demo applications. A simple blinky style demo 6 | application, and a more comprehensive test and demo application. The 7 | mainCREATE_SIMPLE_BLINKY_DEMO_ONLY setting is used to select between the two. 8 | 9 | If mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is 1 then the blinky demo will be built. 10 | The blinky demo is implemented and described in main_blinky.c. 11 | 12 | If mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is not 1 then the comprehensive test and 13 | demo application will be built. The comprehensive test and demo application is 14 | implemented and described in main_full.c. */ 15 | #define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 1 16 | 17 | /* This demo uses heap_5.c, and these constants define the sizes of the regions 18 | that make up the total heap. heap_5 is only used for test and example purposes 19 | as this demo could easily create one large heap region instead of multiple 20 | smaller heap regions - in which case heap_4.c would be the more appropriate 21 | choice. See http://www.freertos.org/a00111.html for an explanation. */ 22 | #define mainREGION_1_SIZE 8201 23 | #define mainREGION_2_SIZE 29905 24 | #define mainREGION_3_SIZE 7607 25 | 26 | /*-----------------------------------------------------------*/ 27 | 28 | 29 | /* 30 | * Prototypes for the standard FreeRTOS application hook (callback) functions 31 | * implemented within this file. See http://www.freertos.org/a00016.html . 32 | */ 33 | void vApplicationMallocFailedHook( void ); 34 | void vApplicationIdleHook( void ); 35 | void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); 36 | void vApplicationTickHook( void ); 37 | void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); 38 | void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ); 39 | 40 | /*-----------------------------------------------------------*/ 41 | 42 | /* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can 43 | use a callback function to optionally provide the memory required by the idle 44 | and timer tasks. This is the stack that will be used by the timer task. It is 45 | declared here, as a global, so it can be checked by a test that is implemented 46 | in a different file. */ 47 | StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; 48 | 49 | void vApplicationMallocFailedHook( void ) 50 | { 51 | /* vApplicationMallocFailedHook() will only be called if 52 | configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook 53 | function that will get called if a call to pvPortMalloc() fails. 54 | pvPortMalloc() is called internally by the kernel whenever a task, queue, 55 | timer or semaphore is created. It is also called by various parts of the 56 | demo application. If heap_1.c, heap_2.c or heap_4.c is being used, then the 57 | size of the heap available to pvPortMalloc() is defined by 58 | configTOTAL_HEAP_SIZE in FreeRTOSConfig.h, and the xPortGetFreeHeapSize() 59 | API function can be used to query the size of free heap space that remains 60 | (although it does not provide information on how the remaining heap might be 61 | fragmented). See http://www.freertos.org/a00111.html for more 62 | information. */ 63 | configASSERT(1); 64 | } 65 | /*-----------------------------------------------------------*/ 66 | 67 | void vApplicationIdleHook( void ) 68 | { 69 | /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set 70 | to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle 71 | task. It is essential that code added to this hook function never attempts 72 | to block in any way (for example, call xQueueReceive() with a block time 73 | specified, or call vTaskDelay()). If application tasks make use of the 74 | vTaskDelete() API function to delete themselves then it is also important 75 | that vApplicationIdleHook() is permitted to return to its calling function, 76 | because it is the responsibility of the idle task to clean up memory 77 | allocated by the kernel to any task that has since deleted itself. */ 78 | } 79 | /*-----------------------------------------------------------*/ 80 | 81 | void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) 82 | { 83 | ( void ) pcTaskName; 84 | ( void ) pxTask; 85 | 86 | /* Run time stack overflow checking is performed if 87 | configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook 88 | function is called if a stack overflow is detected. This function is 89 | provided as an example only as stack overflow checking does not function 90 | when running the FreeRTOS Windows port. */ 91 | configASSERT(1); 92 | } 93 | /*-----------------------------------------------------------*/ 94 | 95 | void vApplicationTickHook( void ) 96 | { 97 | /* This function will be called by each tick interrupt if 98 | configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be 99 | added here, but the tick hook is called from an interrupt context, so 100 | code must not attempt to block, and only the interrupt safe FreeRTOS API 101 | functions can be used (those that end in FromISR()). */ 102 | } 103 | /*-----------------------------------------------------------*/ 104 | 105 | void vApplicationDaemonTaskStartupHook( void ) 106 | { 107 | /* This function will be called once only, when the daemon task starts to 108 | execute (sometimes called the timer task). This is useful if the 109 | application includes initialisation code that would benefit from executing 110 | after the scheduler has been started. */ 111 | } 112 | /*-----------------------------------------------------------*/ 113 | 114 | /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an 115 | implementation of vApplicationGetIdleTaskMemory() to provide the memory that is 116 | used by the Idle task. */ 117 | void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) 118 | { 119 | /* If the buffers to be provided to the Idle task are declared inside this 120 | function then they must be declared static - otherwise they will be allocated on 121 | the stack and so not exists after this function exits. */ 122 | static StaticTask_t xIdleTaskTCB; 123 | static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; 124 | 125 | /* Pass out a pointer to the StaticTask_t structure in which the Idle task's 126 | state will be stored. */ 127 | *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; 128 | 129 | /* Pass out the array that will be used as the Idle task's stack. */ 130 | *ppxIdleTaskStackBuffer = uxIdleTaskStack; 131 | 132 | /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. 133 | Note that, as the array is necessarily of type StackType_t, 134 | configMINIMAL_STACK_SIZE is specified in words, not bytes. */ 135 | *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; 136 | } 137 | /*-----------------------------------------------------------*/ 138 | /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the 139 | application must provide an implementation of vApplicationGetTimerTaskMemory() 140 | to provide the memory that is used by the Timer service task. */ 141 | void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) 142 | { 143 | /* If the buffers to be provided to the Timer task are declared inside this 144 | function then they must be declared static - otherwise they will be allocated on 145 | the stack and so not exists after this function exits. */ 146 | static StaticTask_t xTimerTaskTCB; 147 | 148 | /* Pass out a pointer to the StaticTask_t structure in which the Timer 149 | task's state will be stored. */ 150 | *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; 151 | 152 | /* Pass out the array that will be used as the Timer task's stack. */ 153 | *ppxTimerTaskStackBuffer = uxTimerTaskStack; 154 | 155 | /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. 156 | Note that, as the array is necessarily of type StackType_t, 157 | configMINIMAL_STACK_SIZE is specified in words, not bytes. */ 158 | *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; 159 | } 160 | -------------------------------------------------------------------------------- /freertos-rust/src/freertos/shim.c: -------------------------------------------------------------------------------- 1 | /* 2 | FreeRTOS.rs shim library 3 | Include headers relevant for your platform. 4 | STM32 example: 5 | #include "stm32f4xx_hal.h" 6 | */ 7 | 8 | #include "FreeRTOS.h" 9 | #include "task.h" 10 | #include "timers.h" 11 | #include "queue.h" 12 | #include "semphr.h" 13 | #include "event_groups.h" 14 | 15 | // Just for testing 16 | void freertos_rs_invoke_configASSERT() { 17 | configASSERT(0); 18 | } 19 | 20 | void freertos_rs_vTaskStartScheduler() { 21 | vTaskStartScheduler(); 22 | } 23 | 24 | BaseType_t freertos_rt_xTaskGetSchedulerState(void) { 25 | return xTaskGetSchedulerState(); 26 | } 27 | 28 | void *freertos_rs_pvPortMalloc(size_t xWantedSize) { 29 | return pvPortMalloc(xWantedSize); 30 | } 31 | 32 | void freertos_rs_vPortFree(void *pv) { 33 | vPortFree(pv); 34 | } 35 | 36 | uint8_t freertos_rs_sizeof(uint8_t _type) { 37 | switch (_type) { 38 | case 0: 39 | return sizeof(void*); 40 | break; 41 | case 1: 42 | return sizeof(char*); 43 | break; 44 | case 2: 45 | return sizeof(char); 46 | break; 47 | 48 | case 10: 49 | return sizeof(BaseType_t); 50 | break; 51 | case 11: 52 | return sizeof(UBaseType_t); 53 | break; 54 | case 12: 55 | return sizeof(TickType_t); 56 | break; 57 | 58 | case 20: 59 | return sizeof(TaskHandle_t); 60 | break; 61 | case 21: 62 | return sizeof(QueueHandle_t); 63 | break; 64 | case 22: 65 | return sizeof(SemaphoreHandle_t); 66 | break; 67 | case 23: 68 | return sizeof(TaskFunction_t); 69 | break; 70 | case 24: 71 | return sizeof(TimerHandle_t); 72 | break; 73 | case 25: 74 | return sizeof(TimerCallbackFunction_t); 75 | break; 76 | 77 | case 30: 78 | return sizeof(TaskStatus_t); 79 | break; 80 | case 31: 81 | return sizeof(eTaskState); 82 | break; 83 | case 32: 84 | return sizeof(unsigned long); 85 | break; 86 | case 33: 87 | return sizeof(unsigned short); 88 | break; 89 | 90 | 91 | break; 92 | default: 93 | return 0; 94 | } 95 | } 96 | 97 | #if (INCLUDE_vTaskDelayUntil == 1) 98 | void freertos_rs_vTaskDelayUntil(TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement) { 99 | vTaskDelayUntil(pxPreviousWakeTime, xTimeIncrement); 100 | } 101 | #endif 102 | 103 | #if (INCLUDE_vTaskDelay == 1) 104 | void freertos_rs_vTaskDelay(TickType_t xTicksToDelay) { 105 | vTaskDelay(xTicksToDelay); 106 | } 107 | #endif 108 | 109 | TickType_t freertos_rs_xTaskGetTickCount() { 110 | return xTaskGetTickCount(); 111 | } 112 | 113 | #if (configUSE_TRACE_FACILITY == 1) 114 | UBaseType_t freertos_rs_get_system_state(TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime) { 115 | return uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, pulTotalRunTime); 116 | } 117 | #endif 118 | 119 | #ifdef configCPU_CLOCK_HZ 120 | unsigned long freertos_rs_get_configCPU_CLOCK_HZ() { 121 | return configCPU_CLOCK_HZ; 122 | } 123 | #endif 124 | 125 | TickType_t freertos_rs_get_portTICK_PERIOD_MS() { 126 | return portTICK_PERIOD_MS; 127 | } 128 | 129 | UBaseType_t freertos_rs_get_number_of_tasks() { 130 | return uxTaskGetNumberOfTasks(); 131 | } 132 | 133 | #if (configUSE_RECURSIVE_MUTEXES == 1) 134 | SemaphoreHandle_t freertos_rs_create_recursive_mutex() { 135 | return xSemaphoreCreateRecursiveMutex(); 136 | } 137 | 138 | UBaseType_t freertos_rs_take_recursive_semaphore(SemaphoreHandle_t semaphore, UBaseType_t max) { 139 | if (xSemaphoreTakeRecursive(semaphore, max) == pdTRUE) { 140 | return 0; 141 | } 142 | 143 | return 1; 144 | } 145 | UBaseType_t freertos_rs_give_recursive_semaphore(SemaphoreHandle_t semaphore) { 146 | if (xSemaphoreGiveRecursive(semaphore) == pdTRUE) { 147 | return 0; 148 | } else { 149 | return 1; 150 | } 151 | } 152 | #endif 153 | 154 | SemaphoreHandle_t freertos_rs_create_mutex() { 155 | return xSemaphoreCreateMutex(); 156 | } 157 | 158 | SemaphoreHandle_t freertos_rs_create_binary_semaphore() { 159 | return xSemaphoreCreateBinary(); 160 | } 161 | 162 | SemaphoreHandle_t freertos_rs_create_counting_semaphore(UBaseType_t max, UBaseType_t initial) { 163 | return xSemaphoreCreateCounting(max, initial); 164 | } 165 | 166 | void freertos_rs_delete_semaphore(SemaphoreHandle_t semaphore) { 167 | vSemaphoreDelete(semaphore); 168 | } 169 | 170 | UBaseType_t freertos_rs_take_semaphore(SemaphoreHandle_t semaphore, UBaseType_t max) { 171 | if (xSemaphoreTake(semaphore, max) == pdTRUE) { 172 | return 0; 173 | } 174 | 175 | return 1; 176 | } 177 | 178 | UBaseType_t freertos_rs_give_semaphore(SemaphoreHandle_t semaphore) { 179 | if (xSemaphoreGive(semaphore) == pdTRUE) { 180 | return 0; 181 | } 182 | 183 | return 1; 184 | } 185 | 186 | UBaseType_t freertos_rs_take_semaphore_isr(SemaphoreHandle_t semaphore, BaseType_t* xHigherPriorityTaskWoken) { 187 | if (xSemaphoreTakeFromISR(semaphore, xHigherPriorityTaskWoken) == pdTRUE) { 188 | return 0; 189 | } 190 | 191 | return 1; 192 | } 193 | 194 | UBaseType_t freertos_rs_give_semaphore_isr(SemaphoreHandle_t semaphore, BaseType_t* xHigherPriorityTaskWoken) { 195 | if (xSemaphoreGiveFromISR(semaphore, xHigherPriorityTaskWoken) == pdTRUE) { 196 | return 0; 197 | } 198 | 199 | return 1; 200 | } 201 | 202 | 203 | UBaseType_t freertos_rs_spawn_task(TaskFunction_t entry_point, void* pvParameters, const char * const name, uint8_t name_len, uint16_t stack_size, UBaseType_t priority, TaskHandle_t* task_handle) { 204 | char c_name[configMAX_TASK_NAME_LEN] = {0}; 205 | for (int i = 0; i < name_len; i++) { 206 | c_name[i] = name[i]; 207 | 208 | if (i == configMAX_TASK_NAME_LEN - 1) { 209 | break; 210 | } 211 | } 212 | 213 | BaseType_t ret = xTaskCreate(entry_point, c_name, stack_size, pvParameters, priority, task_handle); 214 | 215 | if (ret != pdPASS) { 216 | return 1; 217 | } 218 | 219 | configASSERT(task_handle); 220 | 221 | return 0; 222 | } 223 | 224 | #if (INCLUDE_vTaskDelete == 1) 225 | void freertos_rs_delete_task(TaskHandle_t task) { 226 | vTaskDelete(task); 227 | } 228 | #endif 229 | 230 | void freertos_rs_suspend_task(TaskHandle_t task) { 231 | vTaskSuspend(task); 232 | } 233 | 234 | UBaseType_t freertos_rs_get_stack_high_water_mark(TaskHandle_t task) { 235 | #if (INCLUDE_uxTaskGetStackHighWaterMark == 1) 236 | return uxTaskGetStackHighWaterMark(task); 237 | #else 238 | (void)task; 239 | return 0; 240 | #endif 241 | } 242 | 243 | 244 | QueueHandle_t freertos_rs_queue_create(UBaseType_t queue_length, UBaseType_t item_size) { 245 | return xQueueCreate(queue_length, item_size); 246 | } 247 | 248 | void freertos_rs_queue_delete(QueueHandle_t queue) { 249 | vQueueDelete(queue); 250 | } 251 | 252 | UBaseType_t freertos_rs_queue_send(QueueHandle_t queue, void* item, TickType_t max_wait) { 253 | if (xQueueSend(queue, item, max_wait ) != pdTRUE) 254 | { 255 | return 1; 256 | } 257 | 258 | return 0; 259 | } 260 | 261 | UBaseType_t freertos_rs_queue_send_isr(QueueHandle_t queue, void* item, BaseType_t* xHigherPriorityTaskWoken) { 262 | if (xQueueSendFromISR(queue, item, xHigherPriorityTaskWoken) == pdTRUE) { 263 | return 0; 264 | } 265 | return 1; 266 | } 267 | 268 | UBaseType_t freertos_rs_queue_receive(QueueHandle_t queue, void* item, TickType_t max_wait) { 269 | if ( xQueueReceive( queue, item, max_wait ) != pdTRUE ) 270 | { 271 | return 1; 272 | } 273 | 274 | return 0; 275 | } 276 | 277 | UBaseType_t freertos_rs_queue_messages_waiting(QueueHandle_t queue) { 278 | return uxQueueMessagesWaiting( queue ); 279 | } 280 | 281 | void freertos_rs_isr_yield(BaseType_t xHigherPriorityTaskWoken) { 282 | portYIELD_FROM_ISR(xHigherPriorityTaskWoken); 283 | } 284 | 285 | TickType_t freertos_rs_max_wait() { 286 | return portMAX_DELAY; 287 | } 288 | 289 | 290 | char* freertos_rs_task_get_name(TaskHandle_t task) { 291 | return pcTaskGetName(task); 292 | } 293 | 294 | uint32_t freertos_rs_task_notify_take(uint8_t clear_count, TickType_t wait) { 295 | return ulTaskNotifyTake(clear_count == 1 ? pdTRUE : pdFALSE, wait); 296 | } 297 | 298 | BaseType_t freertos_rs_task_notify_wait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait) { 299 | if (xTaskNotifyWait(ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait) == pdTRUE) { 300 | return 0; 301 | } 302 | 303 | return 1; 304 | } 305 | 306 | eNotifyAction freertos_rs_task_notify_action(uint8_t action) { 307 | switch (action) { 308 | case 1: 309 | return eSetBits; 310 | case 2: 311 | return eIncrement; 312 | case 3: 313 | return eSetValueWithOverwrite; 314 | case 4: 315 | return eSetValueWithoutOverwrite; 316 | default: 317 | return eNoAction; 318 | } 319 | } 320 | 321 | BaseType_t freertos_rs_task_notify(void* task, uint32_t value, uint8_t action) { 322 | eNotifyAction eAction = freertos_rs_task_notify_action(action); 323 | 324 | BaseType_t v = xTaskNotify(task, value, eAction); 325 | if (v != pdPASS) { 326 | return 1; 327 | } 328 | return 0; 329 | } 330 | 331 | BaseType_t freertos_rs_task_notify_isr(void* task, uint32_t value, uint8_t action, BaseType_t* xHigherPriorityTaskWoken) { 332 | eNotifyAction eAction = freertos_rs_task_notify_action(action); 333 | 334 | BaseType_t v = xTaskNotifyFromISR(task, value, eAction, xHigherPriorityTaskWoken); 335 | if (v != pdPASS) { 336 | return 1; 337 | } 338 | return 0; 339 | } 340 | 341 | #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) 342 | TaskHandle_t freertos_rs_get_current_task() { 343 | return xTaskGetCurrentTaskHandle(); 344 | } 345 | #endif 346 | 347 | void freertos_rs_vTaskSuspendAll() { 348 | vTaskSuspendAll(); 349 | } 350 | 351 | BaseType_t freertos_rs_xTaskResumeAll() { 352 | return xTaskResumeAll(); 353 | } 354 | 355 | #if (configUSE_TRACE_FACILITY == 1) 356 | BaseType_t freertos_rs_uxTaskGetTaskNumber(TaskHandle_t task) { 357 | return uxTaskGetTaskNumber(task); 358 | } 359 | 360 | void freertos_rs_vTaskSetTaskNumber(TaskHandle_t task, const UBaseType_t value) { 361 | return vTaskSetTaskNumber(task, value); 362 | } 363 | #endif // configUSE_TRACE_FACILITY 364 | 365 | #if (configUSE_TIMERS == 1) 366 | 367 | TimerHandle_t freertos_rs_timer_create(const char * const name, uint8_t name_len, const TickType_t period, 368 | uint8_t auto_reload, void * const timer_id, TimerCallbackFunction_t callback) 369 | { 370 | char c_name[configMAX_TASK_NAME_LEN] = {0}; 371 | for (int i = 0; i < name_len; i++) { 372 | c_name[i] = name[i]; 373 | 374 | if (i == configMAX_TASK_NAME_LEN - 1) { 375 | break; 376 | } 377 | } 378 | 379 | UBaseType_t timer_auto_reload = pdFALSE; 380 | if (auto_reload == 1) { 381 | timer_auto_reload = pdTRUE; 382 | } 383 | 384 | TimerHandle_t handle = xTimerCreate(c_name, period, timer_auto_reload, timer_id, callback); 385 | return handle; 386 | } 387 | 388 | BaseType_t freertos_rs_timer_start(TimerHandle_t timer, TickType_t block_time) { 389 | if (xTimerStart(timer, block_time) != pdPASS) { 390 | return 1; 391 | } 392 | return 0; 393 | } 394 | 395 | BaseType_t freertos_rs_timer_start_from_isr(TimerHandle_t timer, BaseType_t* xHigherPriorityTaskWoken) { 396 | if (xTimerStartFromISR(timer, xHigherPriorityTaskWoken) != pdPASS) { 397 | return 1; 398 | } 399 | return 0; 400 | } 401 | 402 | BaseType_t freertos_rs_timer_stop(TimerHandle_t timer, TickType_t block_time) { 403 | if (xTimerStop(timer, block_time) != pdPASS) { 404 | return 1; 405 | } 406 | return 0; 407 | } 408 | 409 | BaseType_t freertos_rs_timer_delete(TimerHandle_t timer, TickType_t block_time) { 410 | if (xTimerDelete(timer, block_time) != pdPASS) { 411 | return 1; 412 | } 413 | return 0; 414 | } 415 | 416 | BaseType_t freertos_rs_timer_change_period(TimerHandle_t timer, TickType_t block_time, TickType_t new_period) { 417 | if (xTimerChangePeriod(timer, new_period, block_time) != pdPASS) { 418 | return 1; 419 | } 420 | return 0; 421 | } 422 | 423 | void* freertos_rs_timer_get_id(TimerHandle_t timer) { 424 | return pvTimerGetTimerID(timer); 425 | } 426 | 427 | #endif 428 | 429 | void freertos_rs_enter_critical() { 430 | taskENTER_CRITICAL(); 431 | } 432 | 433 | void freertos_rs_exit_critical() { 434 | taskEXIT_CRITICAL(); 435 | } 436 | 437 | EventGroupHandle_t freertos_rs_event_group_create() { 438 | return xEventGroupCreate(); 439 | } 440 | 441 | void freertos_rs_event_group_delete(EventGroupHandle_t event_group) { 442 | vEventGroupDelete(event_group); 443 | } 444 | 445 | EventBits_t freertos_rs_event_group_set_bits(EventGroupHandle_t event_group, const EventBits_t bits_to_set) { 446 | return xEventGroupSetBits(event_group, bits_to_set); 447 | } 448 | 449 | EventBits_t freertos_rs_event_group_get_bits(EventGroupHandle_t event_group) { 450 | return xEventGroupGetBits(event_group); 451 | } 452 | 453 | EventBits_t freertos_rs_event_group_clear_bits(EventGroupHandle_t event_group, const EventBits_t bits_to_clear) { 454 | return xEventGroupClearBits(event_group, bits_to_clear); 455 | } 456 | 457 | EventBits_t freertos_rs_event_group_wait_bits(const EventGroupHandle_t event_group, const EventBits_t bits_to_wait_for, const BaseType_t clear_on_exit, const BaseType_t wait_for_all_bits, TickType_t ticks_to_wait) { 458 | return xEventGroupWaitBits(event_group, bits_to_wait_for, clear_on_exit, wait_for_all_bits, ticks_to_wait); 459 | } 460 | 461 | EventBits_t freertos_rs_event_group_sync(EventGroupHandle_t event_group, const EventBits_t bits_to_set, const EventBits_t bits_to_wait_for, TickType_t ticks_to_wait) { 462 | return xEventGroupSync(event_group, bits_to_set, bits_to_wait_for, ticks_to_wait); 463 | } 464 | -------------------------------------------------------------------------------- /freertos-rust/src/hooks.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::prelude::v1::String; 3 | use crate::utils::*; 4 | 5 | use core::cell::OnceCell; 6 | 7 | type Callback = fn(); 8 | 9 | pub struct FreeRtosHooks { 10 | on_assert: OnceCell, 11 | } 12 | 13 | impl FreeRtosHooks { 14 | pub fn set_on_assert(&mut self, c: Callback) -> Result<(), Callback> { 15 | self.on_assert.set(c) 16 | } 17 | 18 | fn do_on_assert(&self) { 19 | if let Some (cb) = self.on_assert.get() { 20 | cb() 21 | } 22 | } 23 | } 24 | 25 | // SAFETY: must only be set before the scheduler starts and accessed after the 26 | // kernel has asserted, both being single threaded situations. 27 | unsafe impl Sync for FreeRtosHooks {} 28 | 29 | pub static FREERTOS_HOOKS: FreeRtosHooks = FreeRtosHooks { on_assert: OnceCell::new() }; 30 | 31 | #[allow(unused_doc_comments)] 32 | #[no_mangle] 33 | pub extern "C" fn vAssertCalled(file_name_ptr: FreeRtosCharPtr, line: FreeRtosUBaseType) { 34 | let file_name: String; 35 | unsafe { 36 | file_name = str_from_c_string(file_name_ptr).unwrap(); 37 | } 38 | 39 | FREERTOS_HOOKS.do_on_assert(); 40 | 41 | // we can't print without std yet. 42 | // TODO: make the macro work for debug UART? Or use Panic here? 43 | // println!("ASSERT: {} {}", line, file_name); 44 | panic!("FreeRTOS ASSERT: {}:{}", file_name, line); 45 | //loop {} 46 | } 47 | -------------------------------------------------------------------------------- /freertos-rust/src/isr.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::shim::*; 3 | 4 | /// Keep track of whether we need to yield the execution to a different 5 | /// task at the end of the interrupt. 6 | /// 7 | /// Should be dropped as the last thing inside a interrupt. 8 | pub struct InterruptContext { 9 | x_higher_priority_task_woken: FreeRtosBaseType, 10 | } 11 | 12 | impl InterruptContext { 13 | /// Instantiate a new context. 14 | pub fn new() -> InterruptContext { 15 | InterruptContext { 16 | x_higher_priority_task_woken: 0, 17 | } 18 | } 19 | 20 | pub fn get_task_field_mut(&mut self) -> FreeRtosBaseTypeMutPtr { 21 | &mut self.x_higher_priority_task_woken as *mut _ 22 | } 23 | pub fn higher_priority_task_woken(&self) -> FreeRtosBaseType { 24 | self.x_higher_priority_task_woken 25 | } 26 | } 27 | 28 | impl Drop for InterruptContext { 29 | fn drop(&mut self) { 30 | unsafe { 31 | freertos_rs_isr_yield(self.x_higher_priority_task_woken); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /freertos-rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # FreeRTOS for Rust 2 | //! 3 | //! Rust interface for the FreeRTOS embedded operating system. 4 | //! It is assumed that dynamic memory allocation is provided on the target system. 5 | //! For Rust versions 1.68 and later, the stable channel can be used. 6 | //! Prior to version 1.68, the nightly channel is required along with 7 | //! enabling the `alloc_error_handler` feature. 8 | //! 9 | //! This library interfaces with FreeRTOS using a C shim library which provides function 10 | //! wrappers for FreeRTOS macros. The compiled Rust application should be linked to the 11 | //! base C/C++ firmware binary. 12 | //! 13 | //! Examples are provided inside [freertos-rust-examples](https://github.com/lobaro/FreeRTOS-rust/tree/master/freertos-rust-examples) 14 | //! 15 | //! For more examples, check the enclosed GCC ARM/Rust/QEMU based unit tests. The project 16 | //! ``qemu_runner`` cross-compiles this library, compiles the main firmware using GCC ARM and links 17 | //! in the appropriate entry points for unit tests. [GNU ARM Eclipse QEMU](http://gnuarmeclipse.github.io/qemu/) 18 | //! is used to run the test binaries. 19 | //! 20 | //! Be sure to check the [FreeRTOS documentation](http://www.freertos.org/RTOS.html). 21 | //! 22 | //! # Samples 23 | //! 24 | //! Spawning a new task 25 | //! 26 | //! ```rust 27 | //! # use freertos_rs::*; 28 | //! Task::new().name("hello").stack_size(128).start(|| { 29 | //! loop { 30 | //! println!("Hello world!"); 31 | //! CurrentTask::delay(Duration::infinite()); 32 | //! } 33 | //! }).unwrap(); 34 | //! 35 | //! FreeRtosUtils::start_scheduler(); 36 | //! ``` 37 | //! 38 | //! Queue 39 | //! 40 | //! ```rust 41 | //! # use freertos_rs::*; 42 | //! let q = Queue::new(10).unwrap(); 43 | //! q.send(10, Duration::ms(5)).unwrap(); 44 | //! q.receive(Duration::infinite()).unwrap(); 45 | //! ``` 46 | //! 47 | //! Mutex 48 | //! 49 | //! ```rust 50 | //! # use freertos_rs::*; 51 | //! let m = Mutex::new(0).unwrap(); 52 | //! { 53 | //! let mut v = m.lock(Duration::infinite()).unwrap(); 54 | //! *v += 1; 55 | //! } 56 | //! ``` 57 | 58 | #![no_std] 59 | #![allow(non_upper_case_globals)] 60 | #![allow(non_camel_case_types)] 61 | #![allow(non_snake_case)] 62 | 63 | #[cfg_attr(any(feature = "time", feature = "sync"), macro_use)] 64 | extern crate alloc; 65 | 66 | #[cfg(feature = "hooks")] 67 | mod hooks; 68 | mod prelude; 69 | mod shim; 70 | 71 | #[cfg(feature = "allocator")] 72 | mod allocator; 73 | mod base; 74 | #[cfg(feature = "sync")] 75 | mod critical; 76 | #[cfg(feature = "time")] 77 | mod delays; 78 | #[cfg(feature = "interrupt")] 79 | mod isr; 80 | #[cfg(feature = "sync")] 81 | mod mutex; 82 | #[cfg(feature = "sync")] 83 | mod queue; 84 | #[cfg(feature = "sync")] 85 | mod semaphore; 86 | #[cfg(feature = "sync")] 87 | mod event_group; 88 | #[cfg(any(feature = "time", feature = "sync"))] 89 | mod task; 90 | #[cfg(feature = "time")] 91 | mod timers; 92 | #[cfg(any(feature = "time", feature = "sync"))] 93 | mod units; 94 | mod utils; 95 | 96 | #[cfg(feature = "sync")] 97 | pub mod patterns; 98 | 99 | // Internal stuff that is only public for first Proof of Concept 100 | pub use crate::base::*; 101 | pub use crate::shim::*; 102 | // ---------- 103 | 104 | #[cfg(feature = "allocator")] 105 | pub use crate::allocator::*; 106 | pub use crate::base::FreeRtosError; 107 | #[cfg(feature = "sync")] 108 | pub use crate::critical::*; 109 | #[cfg(feature = "time")] 110 | pub use crate::delays::*; 111 | #[cfg(feature = "hooks")] 112 | pub use crate::hooks::*; 113 | #[cfg(feature = "interrupt")] 114 | pub use crate::isr::*; 115 | #[cfg(feature = "sync")] 116 | pub use crate::mutex::*; 117 | #[cfg(feature = "sync")] 118 | pub use crate::queue::*; 119 | #[cfg(feature = "sync")] 120 | pub use crate::semaphore::*; 121 | #[cfg(feature = "sync")] 122 | pub use crate::event_group::*; 123 | #[cfg(any(feature = "time", feature = "sync"))] 124 | pub use crate::task::*; 125 | #[cfg(feature = "time")] 126 | pub use crate::timers::*; 127 | #[cfg(any(feature = "time", feature = "sync"))] 128 | pub use crate::units::*; 129 | 130 | #[cfg(feature = "cpu_clock")] 131 | pub use crate::utils::cpu_clock_hz; 132 | pub use crate::utils::shim_sanity_check; 133 | -------------------------------------------------------------------------------- /freertos-rust/src/mutex.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::prelude::v1::*; 3 | use crate::shim::*; 4 | use crate::units::*; 5 | 6 | pub type Mutex = MutexImpl; 7 | pub type RecursiveMutex = MutexImpl; 8 | 9 | unsafe impl Send for MutexImpl {} 10 | 11 | unsafe impl Sync for MutexImpl {} 12 | 13 | /// Mutual exclusion access to a contained value. Can be recursive - 14 | /// the current owner of a lock can re-lock it. 15 | pub struct MutexImpl { 16 | mutex: M, 17 | data: UnsafeCell, 18 | } 19 | 20 | impl fmt::Debug for MutexImpl 21 | where 22 | M: MutexInnerImpl + fmt::Debug, 23 | { 24 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 25 | write!(f, "Mutex address: {:?}", self.mutex) 26 | } 27 | } 28 | 29 | impl MutexImpl 30 | where 31 | M: MutexInnerImpl, 32 | { 33 | /// Create a new mutex with the given inner value 34 | pub fn new(value: T) -> Result { 35 | Ok(Self::from_parts(M::create()?, value)) 36 | } 37 | 38 | /// Try to obtain a lock and mutable access to our inner value 39 | pub fn lock(&self, max_wait: D) -> Result, FreeRtosError> { 40 | self.mutex.take(max_wait)?; 41 | 42 | Ok(MutexGuard { 43 | __mutex: &self.mutex, 44 | __data: &self.data, 45 | }) 46 | } 47 | 48 | /// Consume the mutex and return its inner value 49 | pub fn into_inner(self) -> T { 50 | self.into_parts().1 51 | } 52 | 53 | /// Get mutable reference to inner value. 54 | /// 55 | /// This method does not lock the mutex because mutable reference guarantees exclusive access. 56 | pub fn get_mut(&mut self) -> &mut T { 57 | self.data.get_mut() 58 | } 59 | 60 | /// Create owning mutex from non-owning mutex and inner value. 61 | /// 62 | /// It is safe to pass an already locked `mutex` although it is not recommended. 63 | pub fn from_parts(mutex: M, value: T) -> Self { 64 | Self { 65 | mutex, 66 | data: UnsafeCell::new(value), 67 | } 68 | } 69 | 70 | /// Split owning mutex into non-owning mutex and inner value. 71 | pub fn into_parts(self) -> (M, T) { 72 | (self.mutex, self.data.into_inner()) 73 | } 74 | 75 | /// Get mutable reference to inner non-owning mutex. 76 | pub fn inner_mutex_mut(&mut self) -> &mut M { 77 | &mut self.mutex 78 | } 79 | } 80 | 81 | /// Holds the mutex until we are dropped 82 | pub struct MutexGuard<'a, T: ?Sized + 'a, M: 'a> 83 | where 84 | M: MutexInnerImpl, 85 | { 86 | __mutex: &'a M, 87 | __data: &'a UnsafeCell, 88 | } 89 | 90 | impl<'mutex, T: ?Sized, M> Deref for MutexGuard<'mutex, T, M> 91 | where 92 | M: MutexInnerImpl, 93 | { 94 | type Target = T; 95 | 96 | fn deref<'a>(&'a self) -> &'a T { 97 | unsafe { &*self.__data.get() } 98 | } 99 | } 100 | 101 | impl<'mutex, T: ?Sized, M> DerefMut for MutexGuard<'mutex, T, M> 102 | where 103 | M: MutexInnerImpl, 104 | { 105 | fn deref_mut<'a>(&'a mut self) -> &'a mut T { 106 | unsafe { &mut *self.__data.get() } 107 | } 108 | } 109 | 110 | impl<'a, T: ?Sized, M> Drop for MutexGuard<'a, T, M> 111 | where 112 | M: MutexInnerImpl, 113 | { 114 | fn drop(&mut self) { 115 | self.__mutex.give(); 116 | } 117 | } 118 | 119 | pub trait MutexInnerImpl 120 | where 121 | Self: Sized, 122 | { 123 | fn create() -> Result; 124 | fn take(&self, max_wait: D) -> Result<(), FreeRtosError>; 125 | fn give(&self); 126 | 127 | /// # Safety 128 | /// 129 | /// `handle` must be a valid FreeRTOS mutex handle. 130 | /// 131 | /// The type of `handle` (normal or recursive mutex) must match the type 132 | /// of instance being created ([`MutexNormal`] or [`MutexRecursive`] respectively). 133 | unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self; 134 | fn raw_handle(&self) -> FreeRtosSemaphoreHandle; 135 | } 136 | 137 | pub struct MutexNormal(FreeRtosSemaphoreHandle); 138 | 139 | impl MutexInnerImpl for MutexNormal { 140 | fn create() -> Result { 141 | let m = unsafe { freertos_rs_create_mutex() }; 142 | if m == 0 as *const _ { 143 | return Err(FreeRtosError::OutOfMemory); 144 | } 145 | Ok(MutexNormal(m)) 146 | } 147 | 148 | fn take(&self, max_wait: D) -> Result<(), FreeRtosError> { 149 | let res = unsafe { freertos_rs_take_semaphore(self.0, max_wait.to_ticks()) }; 150 | 151 | if res != 0 { 152 | return Err(FreeRtosError::MutexTimeout); 153 | } 154 | 155 | Ok(()) 156 | } 157 | 158 | fn give(&self) { 159 | unsafe { 160 | freertos_rs_give_semaphore(self.0); 161 | } 162 | } 163 | 164 | #[inline] 165 | unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self { 166 | Self(handle) 167 | } 168 | 169 | #[inline] 170 | fn raw_handle(&self) -> FreeRtosSemaphoreHandle { 171 | self.0 172 | } 173 | } 174 | 175 | impl Drop for MutexNormal { 176 | fn drop(&mut self) { 177 | unsafe { freertos_rs_delete_semaphore(self.0) } 178 | } 179 | } 180 | 181 | impl fmt::Debug for MutexNormal { 182 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 183 | write!(f, "{:?}", self.0) 184 | } 185 | } 186 | 187 | pub struct MutexRecursive(FreeRtosSemaphoreHandle); 188 | 189 | impl MutexInnerImpl for MutexRecursive { 190 | fn create() -> Result { 191 | let m = unsafe { freertos_rs_create_recursive_mutex() }; 192 | if m == 0 as *const _ { 193 | return Err(FreeRtosError::OutOfMemory); 194 | } 195 | Ok(MutexRecursive(m)) 196 | } 197 | 198 | fn take(&self, max_wait: D) -> Result<(), FreeRtosError> { 199 | let res = unsafe { freertos_rs_take_recursive_semaphore(self.0, max_wait.to_ticks()) }; 200 | 201 | if res != 0 { 202 | return Err(FreeRtosError::MutexTimeout); 203 | } 204 | 205 | Ok(()) 206 | } 207 | 208 | fn give(&self) { 209 | unsafe { 210 | freertos_rs_give_recursive_semaphore(self.0); 211 | } 212 | } 213 | 214 | #[inline] 215 | unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self { 216 | Self(handle) 217 | } 218 | 219 | #[inline] 220 | fn raw_handle(&self) -> FreeRtosSemaphoreHandle { 221 | self.0 222 | } 223 | } 224 | 225 | impl Drop for MutexRecursive { 226 | fn drop(&mut self) { 227 | unsafe { freertos_rs_delete_semaphore(self.0) } 228 | } 229 | } 230 | 231 | impl fmt::Debug for MutexRecursive { 232 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 233 | write!(f, "{:?}", self.0) 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /freertos-rust/src/patterns/compute_task.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::mutex::*; 3 | use crate::prelude::v1::*; 4 | use crate::queue::*; 5 | use crate::task::*; 6 | use crate::units::*; 7 | 8 | pub trait ComputeTaskBuilder { 9 | fn compute(&self, func: F) -> Result, FreeRtosError> 10 | where 11 | F: FnOnce() -> R, 12 | F: Send + 'static, 13 | R: Sync + Send + 'static; 14 | } 15 | 16 | impl ComputeTaskBuilder for TaskBuilder { 17 | #[cfg(target_os = "none")] 18 | /// Spawn a task that can post a return value to the outside. 19 | fn compute(&self, func: F) -> Result, FreeRtosError> 20 | where 21 | F: FnOnce() -> R, 22 | F: Send + 'static, 23 | R: Sync + Send + 'static, 24 | { 25 | let (task, result, status) = { 26 | let result = Arc::new(Mutex::new(None)?); 27 | let status = Arc::new(Queue::new(1)?); 28 | 29 | let task_result = result.clone(); 30 | let task_status = status.clone(); 31 | let task = self.start(move |_this_task| { 32 | { 33 | let mut lock = task_result.lock(Duration::infinite()).unwrap(); 34 | let r = func(); 35 | *lock = Some(r); 36 | } 37 | // release our reference to the mutex, so it can be deconstructed 38 | drop(task_result); 39 | task_status 40 | .send(ComputeTaskStatus::Finished, Duration::infinite()) 41 | .unwrap(); 42 | })?; 43 | 44 | (task, result, status) 45 | }; 46 | 47 | Ok(ComputeTask { 48 | task: task, 49 | result: result, 50 | status: status, 51 | finished: false, 52 | }) 53 | } 54 | 55 | #[cfg(not(target_os = "none"))] 56 | fn compute(&self, func: F) -> Result, FreeRtosError> 57 | where 58 | F: FnOnce() -> R, 59 | F: Send + 'static, 60 | R: Sync + Send + 'static, 61 | { 62 | let r = func(); 63 | 64 | Ok(ComputeTask { 65 | task: Task::new().start(|_this_task| {}).unwrap(), 66 | result: Arc::new(Mutex::new(Some(r)).unwrap()), 67 | status: Arc::new(Queue::new(1).unwrap()), 68 | finished: false, 69 | }) 70 | } 71 | } 72 | 73 | /// A task that can terminate and return its return value. Implemented using an 74 | /// atomically shared mutex. 75 | /// 76 | /// Sample usage: 77 | /// 78 | /// ```rust 79 | /// # use freertos_rs::*; 80 | /// use freertos_rs::patterns::compute_task::*; 81 | /// let task = Task::new().compute(|| { 82 | /// CurrentTask::delay(Duration::ms(100)); 83 | /// 42 84 | /// }).unwrap(); 85 | /// 86 | /// let result = task.into_result(Duration::ms(1000)).unwrap(); 87 | /// # println!("{}", result); 88 | /// ``` 89 | 90 | pub struct ComputeTask { 91 | task: Task, 92 | result: Arc>>, 93 | status: Arc>, 94 | finished: bool, 95 | } 96 | 97 | #[allow(dead_code)] 98 | #[derive(Debug, Copy, Clone)] 99 | enum ComputeTaskStatus { 100 | Finished, 101 | } 102 | 103 | use core::fmt::Debug; 104 | 105 | impl ComputeTask { 106 | /// Get the handle of the task that computes the result. 107 | pub fn get_task(&self) -> &Task { 108 | &self.task 109 | } 110 | 111 | /// Wait until the task computes its result. Otherwise, returns a timeout. 112 | pub fn wait_for_result(&mut self, max_wait: D) -> Result<(), FreeRtosError> { 113 | if self.finished == true { 114 | Ok(()) 115 | } else { 116 | match self.status.receive(max_wait) { 117 | Ok(ComputeTaskStatus::Finished) => { 118 | self.finished = true; 119 | Ok(()) 120 | } 121 | Err(e) => Err(e), 122 | } 123 | } 124 | } 125 | 126 | /// Consume the task and unwrap the computed return value. 127 | pub fn into_result(mut self, max_wait: D) -> Result { 128 | self.wait_for_result(max_wait)?; 129 | 130 | if self.finished != true { 131 | panic!("ComputeTask should be finished!"); 132 | } 133 | 134 | let m = Arc::try_unwrap(self.result) 135 | .expect("ComputeTask: Arc should have only one reference left!"); 136 | let option_r = m.into_inner(); 137 | let r = option_r.expect("ComputeTask: Result should be a Some(R)!"); 138 | 139 | Ok(r) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /freertos-rust/src/patterns/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compute_task; 2 | pub mod processor; 3 | pub mod pub_sub; 4 | -------------------------------------------------------------------------------- /freertos-rust/src/patterns/processor.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::mutex::*; 3 | use crate::prelude::v1::*; 4 | use crate::queue::*; 5 | use crate::units::*; 6 | 7 | pub type SharedClientWithReplyQueue = Arc>; 8 | pub type Client = ProcessorClient; 9 | pub type ClientWithReplies = ProcessorClient>; 10 | 11 | pub trait ReplyableMessage { 12 | fn reply_to_client_id(&self) -> Option; 13 | } 14 | 15 | #[derive(Copy, Clone)] 16 | pub struct InputMessage 17 | where 18 | I: Copy + Send, 19 | { 20 | val: I, 21 | reply_to_client_id: Option, 22 | } 23 | 24 | impl InputMessage 25 | where 26 | I: Copy + Send, 27 | { 28 | pub fn request(val: I) -> Self { 29 | InputMessage { 30 | val: val, 31 | reply_to_client_id: None, 32 | } 33 | } 34 | 35 | pub fn request_with_reply(val: I, client_id: usize) -> Self { 36 | InputMessage { 37 | val: val, 38 | reply_to_client_id: Some(client_id), 39 | } 40 | } 41 | 42 | pub fn get_val(&self) -> I { 43 | self.val 44 | } 45 | } 46 | 47 | impl ReplyableMessage for InputMessage 48 | where 49 | I: Copy + Send, 50 | { 51 | fn reply_to_client_id(&self) -> Option { 52 | self.reply_to_client_id 53 | } 54 | } 55 | 56 | pub struct Processor 57 | where 58 | I: ReplyableMessage + Copy + Send, 59 | O: Copy + Send, 60 | { 61 | queue: Arc>, 62 | inner: Arc>>, 63 | } 64 | 65 | impl Processor 66 | where 67 | I: ReplyableMessage + Copy + Send, 68 | O: Copy + Send, 69 | { 70 | pub fn new(queue_size: usize) -> Result { 71 | let p = ProcessorInner { 72 | clients: Vec::new(), 73 | next_client_id: 1, 74 | }; 75 | let p = Arc::new(Mutex::new(p)?); 76 | let p = Processor { 77 | queue: Arc::new(Queue::new(queue_size)?), 78 | inner: p, 79 | }; 80 | Ok(p) 81 | } 82 | 83 | pub fn new_client(&self) -> Result, FreeRtosError> { 84 | let c = ProcessorClient { 85 | processor_queue: Arc::downgrade(&self.queue), 86 | client_reply: (), 87 | }; 88 | 89 | Ok(c) 90 | } 91 | 92 | pub fn new_client_with_reply( 93 | &self, 94 | client_receive_queue_size: usize, 95 | max_wait: D, 96 | ) -> Result>, FreeRtosError> { 97 | if client_receive_queue_size == 0 { 98 | return Err(FreeRtosError::InvalidQueueSize); 99 | } 100 | 101 | let client_reply = { 102 | let mut processor = self.inner.lock(max_wait)?; 103 | 104 | let c = ClientWithReplyQueue { 105 | id: processor.next_client_id, 106 | processor_inner: self.inner.clone(), 107 | receive_queue: Queue::new(client_receive_queue_size)?, 108 | }; 109 | 110 | let c = Arc::new(c); 111 | processor.clients.push((c.id, Arc::downgrade(&c))); 112 | 113 | processor.next_client_id += 1; 114 | 115 | c 116 | }; 117 | 118 | let c = ProcessorClient { 119 | processor_queue: Arc::downgrade(&self.queue), 120 | client_reply: client_reply, 121 | }; 122 | 123 | Ok(c) 124 | } 125 | 126 | pub fn get_receive_queue(&self) -> &Queue { 127 | &*self.queue 128 | } 129 | 130 | pub fn reply( 131 | &self, 132 | received_message: I, 133 | reply: O, 134 | max_wait: D, 135 | ) -> Result { 136 | if let Some(client_id) = received_message.reply_to_client_id() { 137 | let inner = self.inner.lock(max_wait)?; 138 | if let Some(client) = inner 139 | .clients 140 | .iter() 141 | .flat_map(|ref x| x.1.upgrade().into_iter()) 142 | .find(|x| x.id == client_id) 143 | { 144 | client 145 | .receive_queue 146 | .send(reply, max_wait) 147 | .map_err(|err| err.error())?; 148 | return Ok(true); 149 | } 150 | } 151 | 152 | Ok(false) 153 | } 154 | } 155 | 156 | impl Processor, O> 157 | where 158 | I: Copy + Send, 159 | O: Copy + Send, 160 | { 161 | pub fn reply_val( 162 | &self, 163 | received_message: InputMessage, 164 | reply: O, 165 | max_wait: D, 166 | ) -> Result { 167 | self.reply(received_message, reply, max_wait) 168 | } 169 | } 170 | 171 | struct ProcessorInner 172 | where 173 | O: Copy + Send, 174 | { 175 | clients: Vec<(usize, Weak>)>, 176 | next_client_id: usize, 177 | } 178 | 179 | impl ProcessorInner 180 | where 181 | O: Copy + Send, 182 | { 183 | fn remove_client_reply(&mut self, client: &ClientWithReplyQueue) { 184 | self.clients.retain(|ref x| x.0 != client.id) 185 | } 186 | } 187 | 188 | pub struct ProcessorClient 189 | where 190 | I: ReplyableMessage + Copy + Send, 191 | { 192 | processor_queue: Weak>, 193 | client_reply: C, 194 | } 195 | 196 | impl ProcessorClient 197 | where 198 | I: ReplyableMessage + Copy + Send, 199 | { 200 | pub fn send(&self, message: I, max_wait: D) -> Result<(), FreeRtosError> { 201 | let processor_queue = self 202 | .processor_queue 203 | .upgrade() 204 | .ok_or(FreeRtosError::ProcessorHasShutDown)?; 205 | processor_queue 206 | .send(message, max_wait) 207 | .map_err(|err| err.error())?; 208 | Ok(()) 209 | } 210 | 211 | pub fn send_from_isr( 212 | &self, 213 | context: &mut crate::isr::InterruptContext, 214 | message: I, 215 | ) -> Result<(), FreeRtosError> { 216 | let processor_queue = self 217 | .processor_queue 218 | .upgrade() 219 | .ok_or(FreeRtosError::ProcessorHasShutDown)?; 220 | processor_queue 221 | .send_from_isr(context, message) 222 | .map_err(|err| err.error()) 223 | } 224 | } 225 | 226 | impl ProcessorClient, ()> 227 | where 228 | I: Copy + Send, 229 | { 230 | pub fn send_val(&self, val: I, max_wait: D) -> Result<(), FreeRtosError> { 231 | self.send(InputMessage::request(val), max_wait) 232 | } 233 | 234 | pub fn send_val_from_isr( 235 | &self, 236 | context: &mut crate::isr::InterruptContext, 237 | val: I, 238 | ) -> Result<(), FreeRtosError> { 239 | self.send_from_isr(context, InputMessage::request(val)) 240 | } 241 | } 242 | 243 | impl ProcessorClient> 244 | where 245 | I: ReplyableMessage + Copy + Send, 246 | O: Copy + Send, 247 | { 248 | pub fn call(&self, message: I, max_wait: D) -> Result { 249 | self.send(message, max_wait)?; 250 | self.client_reply.receive_queue.receive(max_wait) 251 | } 252 | 253 | pub fn get_receive_queue(&self) -> &Queue { 254 | &self.client_reply.receive_queue 255 | } 256 | } 257 | 258 | impl ProcessorClient, SharedClientWithReplyQueue> 259 | where 260 | I: Copy + Send, 261 | O: Copy + Send, 262 | { 263 | pub fn send_val(&self, val: I, max_wait: D) -> Result<(), FreeRtosError> { 264 | self.send(InputMessage::request(val), max_wait) 265 | } 266 | 267 | pub fn call_val(&self, val: I, max_wait: D) -> Result { 268 | let reply = self.call( 269 | InputMessage::request_with_reply(val, self.client_reply.id), 270 | max_wait, 271 | )?; 272 | Ok(reply) 273 | } 274 | } 275 | 276 | impl Clone for ProcessorClient 277 | where 278 | I: ReplyableMessage + Copy + Send, 279 | C: Clone, 280 | { 281 | fn clone(&self) -> Self { 282 | ProcessorClient { 283 | processor_queue: self.processor_queue.clone(), 284 | client_reply: self.client_reply.clone(), 285 | } 286 | } 287 | } 288 | 289 | pub struct ClientWithReplyQueue 290 | where 291 | O: Copy + Send, 292 | { 293 | id: usize, 294 | processor_inner: Arc>>, 295 | receive_queue: Queue, 296 | } 297 | 298 | impl Drop for ClientWithReplyQueue 299 | where 300 | O: Copy + Send, 301 | { 302 | fn drop(&mut self) { 303 | if let Ok(mut p) = self.processor_inner.lock(Duration::ms(1000)) { 304 | p.remove_client_reply(&self); 305 | } 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /freertos-rust/src/patterns/pub_sub.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::mutex::*; 3 | use crate::prelude::v1::*; 4 | use crate::queue::*; 5 | use crate::units::*; 6 | 7 | /// A pub-sub queue. An item sent to the publisher is sent to every subscriber. 8 | pub struct QueuePublisher { 9 | inner: Arc>>, 10 | } 11 | 12 | /// A subscribtion to the publisher. 13 | pub struct QueueSubscriber { 14 | inner: Arc>, 15 | } 16 | 17 | impl QueuePublisher { 18 | /// Create a new publisher 19 | pub fn new() -> Result, FreeRtosError> { 20 | let inner = PublisherInner { 21 | subscribers: Vec::new(), 22 | queue_next_id: 1, 23 | }; 24 | 25 | Ok(QueuePublisher { 26 | inner: Arc::new(Mutex::new(inner)?), 27 | }) 28 | } 29 | 30 | /// Send an item to every subscriber. Returns the number of 31 | /// subscribers that have received the item. 32 | pub fn send(&self, item: T, max_wait: D) -> usize { 33 | let mut sent_to = 0; 34 | 35 | if let Ok(m) = self.inner.lock(max_wait) { 36 | for subscriber in &m.subscribers { 37 | if let Ok(_) = subscriber.queue.send(item, max_wait) { 38 | sent_to += 1; 39 | } 40 | } 41 | } 42 | 43 | sent_to 44 | } 45 | 46 | /// Subscribe to this publisher. Can accept a fixed amount of items. 47 | pub fn subscribe( 48 | &self, 49 | max_size: usize, 50 | create_max_wait: D, 51 | ) -> Result, FreeRtosError> { 52 | let mut inner = self.inner.lock(create_max_wait)?; 53 | 54 | let queue = Queue::new(max_size)?; 55 | 56 | let id = inner.queue_next_id; 57 | inner.queue_next_id += 1; 58 | 59 | let subscriber = SubscriberInner { 60 | id: id, 61 | queue: queue, 62 | publisher: self.inner.clone(), 63 | }; 64 | let subscriber = Arc::new(subscriber); 65 | 66 | inner.subscribers.push(subscriber.clone()); 67 | 68 | Ok(QueueSubscriber { inner: subscriber }) 69 | } 70 | } 71 | 72 | impl Clone for QueuePublisher { 73 | fn clone(&self) -> Self { 74 | QueuePublisher { 75 | inner: self.inner.clone(), 76 | } 77 | } 78 | } 79 | 80 | impl Drop for QueueSubscriber { 81 | fn drop(&mut self) { 82 | if let Ok(mut l) = self.inner.publisher.lock(Duration::infinite()) { 83 | l.unsubscribe(&self.inner); 84 | } 85 | } 86 | } 87 | 88 | impl QueueSubscriber { 89 | /// Wait for an item to be posted from the publisher. 90 | pub fn receive(&self, max_wait: D) -> Result { 91 | self.inner.queue.receive(max_wait) 92 | } 93 | } 94 | 95 | struct PublisherInner { 96 | subscribers: Vec>>, 97 | queue_next_id: usize, 98 | } 99 | 100 | impl PublisherInner { 101 | fn unsubscribe(&mut self, subscriber: &SubscriberInner) { 102 | self.subscribers.retain(|ref x| x.id != subscriber.id); 103 | } 104 | } 105 | 106 | struct SubscriberInner { 107 | id: usize, 108 | queue: Queue, 109 | publisher: Arc>>, 110 | } 111 | -------------------------------------------------------------------------------- /freertos-rust/src/portmacro.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeRTOS Kernel V10.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | * 22 | * http://www.FreeRTOS.org 23 | * http://aws.amazon.com/freertos 24 | * 25 | * 1 tab == 4 spaces! 26 | */ 27 | 28 | #ifndef PORTMACRO_H 29 | #define PORTMACRO_H 30 | 31 | // Do not include windows deps 32 | //#include 33 | //#include 34 | 35 | /****************************************************************************** 36 | Defines 37 | ******************************************************************************/ 38 | /* Type definitions. */ 39 | #define portCHAR char 40 | #define portFLOAT float 41 | #define portDOUBLE double 42 | #define portLONG long 43 | #define portSHORT short 44 | #define portSTACK_TYPE size_t 45 | #define portBASE_TYPE long 46 | #define portPOINTER_SIZE_TYPE size_t 47 | 48 | typedef portSTACK_TYPE StackType_t; 49 | typedef long BaseType_t; 50 | typedef unsigned long UBaseType_t; 51 | 52 | 53 | #if( configUSE_16_BIT_TICKS == 1 ) 54 | typedef uint16_t TickType_t; 55 | #define portMAX_DELAY ( TickType_t ) 0xffff 56 | #else 57 | typedef uint32_t TickType_t; 58 | #define portMAX_DELAY ( TickType_t ) 0xffffffffUL 59 | 60 | /* 32/64-bit tick type on a 32/64-bit architecture, so reads of the tick 61 | count do not need to be guarded with a critical section. */ 62 | #define portTICK_TYPE_IS_ATOMIC 1 63 | #endif 64 | 65 | /* Hardware specifics. */ 66 | #define portSTACK_GROWTH ( -1 ) 67 | #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) 68 | #define portINLINE __inline 69 | 70 | #if defined( __x86_64__) || defined( _M_X64 ) 71 | #define portBYTE_ALIGNMENT 8 72 | #else 73 | #define portBYTE_ALIGNMENT 4 74 | #endif 75 | 76 | #define portYIELD() vPortGenerateSimulatedInterrupt( portINTERRUPT_YIELD ) 77 | 78 | 79 | extern volatile BaseType_t xInsideInterrupt; 80 | #define portSOFTWARE_BARRIER() while( xInsideInterrupt != pdFALSE ) 81 | 82 | 83 | /* Simulated interrupts return pdFALSE if no context switch should be performed, 84 | or a non-zero number if a context switch should be performed. */ 85 | #define portYIELD_FROM_ISR( x ) ( void ) x 86 | #define portEND_SWITCHING_ISR( x ) portYIELD_FROM_ISR( ( x ) ) 87 | 88 | void vPortCloseRunningThread( void *pvTaskToDelete, volatile BaseType_t *pxPendYield ); 89 | void vPortDeleteThread( void *pvThreadToDelete ); 90 | #define portCLEAN_UP_TCB( pxTCB ) vPortDeleteThread( pxTCB ) 91 | #define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) vPortCloseRunningThread( ( pvTaskToDelete ), ( pxPendYield ) ) 92 | #define portDISABLE_INTERRUPTS() vPortEnterCritical() 93 | #define portENABLE_INTERRUPTS() vPortExitCritical() 94 | 95 | /* Critical section handling. */ 96 | void vPortEnterCritical( void ); 97 | void vPortExitCritical( void ); 98 | 99 | #define portENTER_CRITICAL() vPortEnterCritical() 100 | #define portEXIT_CRITICAL() vPortExitCritical() 101 | 102 | #ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION 103 | #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 104 | #endif 105 | 106 | #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 107 | 108 | /* Check the configuration. */ 109 | #if( configMAX_PRIORITIES > 32 ) 110 | #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice. 111 | #endif 112 | 113 | /* Store/clear the ready priorities in a bit map. */ 114 | #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) 115 | #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) 116 | 117 | 118 | /*-----------------------------------------------------------*/ 119 | 120 | #ifdef __GNUC__ 121 | #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) \ 122 | __asm volatile( "bsr %1, %0\n\t" \ 123 | :"=r"(uxTopPriority) : "rm"(uxReadyPriorities) : "cc" ) 124 | #else 125 | /* BitScanReverse returns the bit position of the most significant '1' 126 | in the word. */ 127 | #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) _BitScanReverse( ( DWORD * ) &( uxTopPriority ), ( uxReadyPriorities ) ) 128 | #endif /* __GNUC__ */ 129 | 130 | #endif /* taskRECORD_READY_PRIORITY */ 131 | 132 | #ifndef __GNUC__ 133 | __pragma( warning( disable:4211 ) ) /* Nonstandard extension used, as extern is only nonstandard to MSVC. */ 134 | #endif 135 | 136 | 137 | /* Task function macros as described on the FreeRTOS.org WEB site. */ 138 | #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) 139 | #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) 140 | 141 | #define portINTERRUPT_YIELD ( 0UL ) 142 | #define portINTERRUPT_TICK ( 1UL ) 143 | 144 | /* 145 | * Raise a simulated interrupt represented by the bit mask in ulInterruptMask. 146 | * Each bit can be used to represent an individual interrupt - with the first 147 | * two bits being used for the Yield and Tick interrupts respectively. 148 | */ 149 | void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber ); 150 | 151 | /* 152 | * Install an interrupt handler to be called by the simulated interrupt handler 153 | * thread. The interrupt number must be above any used by the kernel itself 154 | * (at the time of writing the kernel was using interrupt numbers 0, 1, and 2 155 | * as defined above). The number must also be lower than 32. 156 | * 157 | * Interrupt handler functions must return a non-zero value if executing the 158 | * handler resulted in a task switch being required. 159 | */ 160 | void vPortSetInterruptHandler( uint32_t ulInterruptNumber, uint32_t (*pvHandler)( void ) ); 161 | 162 | #endif 163 | 164 | -------------------------------------------------------------------------------- /freertos-rust/src/prelude/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "no_std.rs"] 2 | pub mod v1; 3 | -------------------------------------------------------------------------------- /freertos-rust/src/prelude/no_std.rs: -------------------------------------------------------------------------------- 1 | pub use core::cell::UnsafeCell; 2 | pub use core::cmp::*; 3 | pub use core::fmt; 4 | pub use core::marker::PhantomData; 5 | pub use core::mem; 6 | pub use core::ops::{Deref, DerefMut}; 7 | 8 | pub use alloc::boxed::Box; 9 | pub use alloc::string::*; 10 | pub use alloc::sync::{Arc, Weak}; 11 | pub use alloc::vec::Vec; 12 | -------------------------------------------------------------------------------- /freertos-rust/src/queue.rs: -------------------------------------------------------------------------------- 1 | use mem::ManuallyDrop; 2 | use mem::MaybeUninit; 3 | 4 | use crate::base::*; 5 | use crate::isr::*; 6 | use crate::prelude::v1::*; 7 | use crate::shim::*; 8 | use crate::units::*; 9 | 10 | unsafe impl Send for Queue {} 11 | unsafe impl Sync for Queue {} 12 | 13 | #[derive(Debug)] 14 | pub struct SendError { 15 | err: FreeRtosError, 16 | item: T, 17 | } 18 | 19 | impl SendError { 20 | pub fn error(&self) -> FreeRtosError { 21 | self.err 22 | } 23 | 24 | pub fn into_item(self) -> T { 25 | self.item 26 | } 27 | } 28 | 29 | /// A queue with a finite size. 30 | #[derive(Debug)] 31 | pub struct Queue { 32 | queue: FreeRtosQueueHandle, 33 | item_type: PhantomData, 34 | } 35 | 36 | impl Queue { 37 | pub fn new(max_size: usize) -> Result, FreeRtosError> { 38 | let item_size = mem::size_of::(); 39 | 40 | let handle = unsafe { freertos_rs_queue_create(max_size as u32, item_size as u32) }; 41 | 42 | if handle == 0 as *const _ { 43 | return Err(FreeRtosError::OutOfMemory); 44 | } 45 | 46 | Ok(Queue { 47 | queue: handle, 48 | item_type: PhantomData, 49 | }) 50 | } 51 | 52 | /// # Safety 53 | /// 54 | /// `handle` must be a valid FreeRTOS regular queue handle (not semaphore or mutex). 55 | /// 56 | /// The item size of the queue must match the size of `T`. 57 | #[inline] 58 | pub unsafe fn from_raw_handle(handle: FreeRtosQueueHandle) -> Self { 59 | Self { 60 | queue: handle, 61 | item_type: PhantomData, 62 | } 63 | } 64 | #[inline] 65 | pub fn raw_handle(&self) -> FreeRtosQueueHandle { 66 | self.queue 67 | } 68 | 69 | /// Send an item to the end of the queue. Wait for the queue to have empty space for it. 70 | pub fn send(&self, item: T, max_wait: D) -> Result<(), SendError> { 71 | let item = ManuallyDrop::new(item); 72 | let ptr = &item as *const _ as FreeRtosVoidPtr; 73 | 74 | unsafe { 75 | if freertos_rs_queue_send(self.queue, ptr, max_wait.to_ticks()) != 0 { 76 | Err(SendError { 77 | err: FreeRtosError::QueueSendTimeout, 78 | item: ManuallyDrop::into_inner(item), 79 | }) 80 | } else { 81 | Ok(()) 82 | } 83 | } 84 | } 85 | 86 | /// Send an item to the end of the queue, from an interrupt. 87 | pub fn send_from_isr( 88 | &self, 89 | context: &mut InterruptContext, 90 | item: T, 91 | ) -> Result<(), SendError> { 92 | let item = ManuallyDrop::new(item); 93 | let ptr = &item as *const _ as FreeRtosVoidPtr; 94 | 95 | unsafe { 96 | if freertos_rs_queue_send_isr(self.queue, ptr, context.get_task_field_mut()) != 0 { 97 | Err(SendError { 98 | err: FreeRtosError::QueueFull, 99 | item: ManuallyDrop::into_inner(item), 100 | }) 101 | } else { 102 | Ok(()) 103 | } 104 | } 105 | } 106 | 107 | /// Wait for an item to be available on the queue. 108 | pub fn receive(&self, max_wait: D) -> Result { 109 | unsafe { 110 | // Use `MaybeUninit` to avoid calling drop on 111 | // uninitialized struct in case of timeout 112 | let mut buff = MaybeUninit::uninit(); 113 | let r = freertos_rs_queue_receive( 114 | self.queue, 115 | &mut buff as *mut _ as FreeRtosMutVoidPtr, 116 | max_wait.to_ticks(), 117 | ); 118 | if r == 0 { 119 | return Ok(buff.assume_init()); 120 | } else { 121 | return Err(FreeRtosError::QueueReceiveTimeout); 122 | } 123 | } 124 | } 125 | 126 | /// Get the number of messages in the queue. 127 | pub fn len(&self) -> u32 { 128 | unsafe { freertos_rs_queue_messages_waiting(self.queue) } 129 | } 130 | } 131 | 132 | impl Drop for Queue { 133 | fn drop(&mut self) { 134 | unsafe { 135 | freertos_rs_queue_delete(self.queue); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /freertos-rust/src/semaphore.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::isr::*; 3 | use crate::shim::*; 4 | use crate::units::*; 5 | 6 | /// A counting or binary semaphore 7 | pub struct Semaphore { 8 | semaphore: FreeRtosSemaphoreHandle, 9 | } 10 | 11 | unsafe impl Send for Semaphore {} 12 | unsafe impl Sync for Semaphore {} 13 | 14 | impl Semaphore { 15 | /// Create a new binary semaphore 16 | pub fn new_binary() -> Result { 17 | unsafe { 18 | let s = freertos_rs_create_binary_semaphore(); 19 | if s == 0 as *const _ { 20 | return Err(FreeRtosError::OutOfMemory); 21 | } 22 | Ok(Semaphore { semaphore: s }) 23 | } 24 | } 25 | 26 | /// Create a new counting semaphore 27 | pub fn new_counting(max: u32, initial: u32) -> Result { 28 | unsafe { 29 | let s = freertos_rs_create_counting_semaphore(max, initial); 30 | if s == 0 as *const _ { 31 | return Err(FreeRtosError::OutOfMemory); 32 | } 33 | Ok(Semaphore { semaphore: s }) 34 | } 35 | } 36 | 37 | /// # Safety 38 | /// 39 | /// `handle` must be a valid FreeRTOS semaphore handle. 40 | /// 41 | /// Only binary or counting semaphore is expected here. 42 | /// To create mutex from raw handle use [`crate::mutex::MutexInnerImpl::from_raw_handle`]. 43 | #[inline] 44 | pub unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self { 45 | Self { semaphore: handle } 46 | } 47 | #[inline] 48 | pub fn raw_handle(&self) -> FreeRtosSemaphoreHandle { 49 | self.semaphore 50 | } 51 | 52 | /// Lock this semaphore in a RAII fashion 53 | pub fn lock(&self, max_wait: D) -> Result { 54 | self.take(max_wait).map(|()| SemaphoreGuard { owner: self }) 55 | } 56 | 57 | /// Returns `true` on success, `false` when semaphore count already reached its limit 58 | pub fn give(&self) -> bool { 59 | unsafe { freertos_rs_give_semaphore(self.semaphore) == 0 } 60 | } 61 | 62 | pub fn take(&self, max_wait: D) -> Result<(), FreeRtosError> { 63 | unsafe { 64 | let res = freertos_rs_take_semaphore(self.semaphore, max_wait.to_ticks()); 65 | 66 | if res != 0 { 67 | return Err(FreeRtosError::Timeout); 68 | } 69 | 70 | Ok(()) 71 | } 72 | } 73 | 74 | /// Returns `true` on success, `false` when semaphore count already reached its limit 75 | pub fn give_from_isr(&self, context: &mut InterruptContext) -> bool { 76 | unsafe { freertos_rs_give_semaphore_isr(self.semaphore, context.get_task_field_mut()) == 0 } 77 | } 78 | 79 | /// Returns `true` on success, `false` if the semaphore was not successfully taken because it was not available 80 | pub fn take_from_isr(&self, context: &mut InterruptContext) -> bool { 81 | unsafe { freertos_rs_take_semaphore_isr(self.semaphore, context.get_task_field_mut()) == 0 } 82 | } 83 | } 84 | 85 | impl Drop for Semaphore { 86 | fn drop(&mut self) { 87 | unsafe { 88 | freertos_rs_delete_semaphore(self.semaphore); 89 | } 90 | } 91 | } 92 | 93 | /// Holds the lock to the semaphore until we are dropped 94 | pub struct SemaphoreGuard<'a> { 95 | owner: &'a Semaphore, 96 | } 97 | 98 | impl<'a> Drop for SemaphoreGuard<'a> { 99 | fn drop(&mut self) { 100 | self.owner.give(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /freertos-rust/src/shim.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use crate::base::*; 4 | 5 | extern "C" { 6 | pub fn freertos_rs_invoke_configASSERT(); 7 | pub fn freertos_rs_vTaskStartScheduler() -> !; 8 | pub fn freertos_rt_xTaskGetSchedulerState() -> FreeRtosBaseType; 9 | pub fn freertos_rs_pvPortMalloc(xWantedSize: FreeRtosUBaseType) -> FreeRtosVoidPtr; 10 | pub fn freertos_rs_vPortFree(pv: FreeRtosVoidPtr); 11 | 12 | pub fn freertos_rs_sizeof(_type: u8) -> u8; 13 | 14 | pub fn freertos_rs_vTaskDelayUntil( 15 | pxPreviousWakeTime: *mut FreeRtosTickType, 16 | xTimeIncrement: FreeRtosTickType, 17 | ); 18 | pub fn freertos_rs_vTaskDelay(xTicksToDelay: FreeRtosTickType); 19 | #[cfg(feature = "cpu_clock")] 20 | pub fn freertos_rs_get_configCPU_CLOCK_HZ() -> FreeRtosUnsignedLong; 21 | pub fn freertos_rs_get_portTICK_PERIOD_MS() -> FreeRtosTickType; 22 | 23 | pub fn freertos_rs_get_number_of_tasks() -> FreeRtosUBaseType; 24 | 25 | pub fn freertos_rs_xTaskGetTickCount() -> FreeRtosTickType; 26 | 27 | pub fn freertos_rs_create_recursive_mutex() -> FreeRtosSemaphoreHandle; 28 | pub fn freertos_rs_create_mutex() -> FreeRtosSemaphoreHandle; 29 | 30 | pub fn freertos_rs_take_recursive_semaphore( 31 | semaphore: FreeRtosSemaphoreHandle, 32 | max: FreeRtosTickType, 33 | ) -> FreeRtosBaseType; 34 | pub fn freertos_rs_take_semaphore( 35 | semaphore: FreeRtosSemaphoreHandle, 36 | max: FreeRtosTickType, 37 | ) -> FreeRtosBaseType; 38 | pub fn freertos_rs_give_semaphore(semaphore: FreeRtosSemaphoreHandle) -> FreeRtosBaseType; 39 | pub fn freertos_rs_give_recursive_semaphore( 40 | semaphore: FreeRtosSemaphoreHandle, 41 | ) -> FreeRtosBaseType; 42 | 43 | pub fn freertos_rs_take_semaphore_isr( 44 | semaphore: FreeRtosSemaphoreHandle, 45 | xHigherPriorityTaskWoken: FreeRtosBaseTypeMutPtr, 46 | ) -> FreeRtosBaseType; 47 | pub fn freertos_rs_give_semaphore_isr( 48 | semaphore: FreeRtosSemaphoreHandle, 49 | xHigherPriorityTaskWoken: FreeRtosBaseTypeMutPtr, 50 | ) -> FreeRtosBaseType; 51 | 52 | pub fn freertos_rs_delete_semaphore(semaphore: FreeRtosSemaphoreHandle); 53 | 54 | pub fn freertos_rs_create_binary_semaphore() -> FreeRtosSemaphoreHandle; 55 | pub fn freertos_rs_create_counting_semaphore( 56 | max: FreeRtosUBaseType, 57 | initial: FreeRtosUBaseType, 58 | ) -> FreeRtosSemaphoreHandle; 59 | 60 | pub fn freertos_rs_queue_create( 61 | length: FreeRtosUBaseType, 62 | item_size: FreeRtosUBaseType, 63 | ) -> FreeRtosQueueHandle; 64 | pub fn freertos_rs_queue_delete(queue: FreeRtosQueueHandle); 65 | pub fn freertos_rs_queue_send( 66 | queue: FreeRtosQueueHandle, 67 | item: FreeRtosVoidPtr, 68 | max_wait: FreeRtosTickType, 69 | ) -> FreeRtosUBaseType; 70 | pub fn freertos_rs_queue_receive( 71 | queue: FreeRtosQueueHandle, 72 | item: FreeRtosMutVoidPtr, 73 | max_wait: FreeRtosTickType, 74 | ) -> FreeRtosUBaseType; 75 | pub fn freertos_rs_queue_messages_waiting( 76 | queue: FreeRtosQueueHandle, 77 | ) -> FreeRtosUBaseType; 78 | 79 | pub fn freertos_rs_queue_send_isr( 80 | queue: FreeRtosQueueHandle, 81 | item: FreeRtosVoidPtr, 82 | xHigherPriorityTaskWoken: FreeRtosBaseTypeMutPtr, 83 | ) -> FreeRtosUBaseType; 84 | pub fn freertos_rs_isr_yield(xHigherPriorityTaskWoken: FreeRtosBaseType); 85 | 86 | pub fn freertos_rs_task_notify_take(clear_count: u8, wait: FreeRtosTickType) -> u32; 87 | pub fn freertos_rs_task_notify_wait( 88 | ulBitsToClearOnEntry: u32, 89 | ulBitsToClearOnExit: u32, 90 | pulNotificationValue: *mut u32, 91 | xTicksToWait: FreeRtosTickType, 92 | ) -> FreeRtosBaseType; 93 | 94 | pub fn freertos_rs_task_notify( 95 | task: FreeRtosTaskHandle, 96 | value: u32, 97 | action: u8, 98 | ) -> FreeRtosBaseType; 99 | pub fn freertos_rs_task_notify_isr( 100 | task: FreeRtosTaskHandle, 101 | value: u32, 102 | action: u8, 103 | xHigherPriorityTaskWoken: FreeRtosBaseTypeMutPtr, 104 | ) -> FreeRtosBaseType; 105 | 106 | pub fn freertos_rs_spawn_task( 107 | f: extern "C" fn(FreeRtosMutVoidPtr) -> FreeRtosMutVoidPtr, 108 | value: FreeRtosMutVoidPtr, 109 | name: FreeRtosCharPtr, 110 | name_len: u8, 111 | stack_size: u16, 112 | priority: FreeRtosUBaseType, 113 | task_handle: *mut FreeRtosTaskHandle, 114 | ) -> FreeRtosUBaseType; 115 | pub fn freertos_rs_delete_task(task: FreeRtosTaskHandle); 116 | pub fn freertos_rs_suspend_task(task: FreeRtosTaskHandle); 117 | pub fn freertos_rs_vTaskSuspendAll(); 118 | pub fn freertos_rs_xTaskResumeAll() -> FreeRtosBaseType; 119 | 120 | pub fn freertos_rs_uxTaskGetTaskNumber(task_handle: FreeRtosTaskHandle) -> FreeRtosBaseType; 121 | pub fn freertos_rs_vTaskSetTaskNumber( 122 | task_handle: FreeRtosTaskHandle, 123 | value: FreeRtosUBaseType, 124 | ); 125 | 126 | pub fn freertos_rs_task_get_name(task: FreeRtosTaskHandle) -> FreeRtosCharPtr; 127 | pub fn freertos_rs_get_stack_high_water_mark(task: FreeRtosTaskHandle) -> FreeRtosBaseType; 128 | 129 | pub fn freertos_rs_get_current_task() -> FreeRtosTaskHandle; 130 | pub fn freertos_rs_get_system_state( 131 | tasks: *mut FreeRtosTaskStatusFfi, 132 | tasks_len: FreeRtosUBaseType, 133 | total_run_time: *mut u32, 134 | ) -> FreeRtosUBaseType; 135 | 136 | pub fn freertos_rs_max_wait() -> FreeRtosTickType; 137 | 138 | pub fn freertos_rs_timer_create( 139 | name: FreeRtosCharPtr, 140 | name_len: u8, 141 | period: FreeRtosTickType, 142 | auto_reload: u8, 143 | timer_id: FreeRtosVoidPtr, 144 | callback: extern "C" fn(FreeRtosTimerHandle) -> (), 145 | ) -> FreeRtosTimerHandle; 146 | pub fn freertos_rs_timer_start( 147 | timer: FreeRtosTimerHandle, 148 | block_time: FreeRtosTickType, 149 | ) -> FreeRtosBaseType; 150 | pub fn freertos_rs_timer_start_from_isr( 151 | timer: FreeRtosTimerHandle, 152 | xHigherPriorityTaskWoken: FreeRtosBaseTypeMutPtr, 153 | ) -> FreeRtosBaseType; 154 | pub fn freertos_rs_timer_stop( 155 | timer: FreeRtosTimerHandle, 156 | block_time: FreeRtosTickType, 157 | ) -> FreeRtosBaseType; 158 | pub fn freertos_rs_timer_delete( 159 | timer: FreeRtosTimerHandle, 160 | block_time: FreeRtosTickType, 161 | ) -> FreeRtosBaseType; 162 | pub fn freertos_rs_timer_change_period( 163 | timer: FreeRtosTimerHandle, 164 | block_time: FreeRtosTickType, 165 | new_period: FreeRtosTickType, 166 | ) -> FreeRtosBaseType; 167 | pub fn freertos_rs_timer_get_id(timer: FreeRtosTimerHandle) -> FreeRtosVoidPtr; 168 | 169 | pub fn freertos_rs_enter_critical(); 170 | pub fn freertos_rs_exit_critical(); 171 | 172 | pub fn freertos_rs_event_group_create() -> FreeRtosEventGroupHandle; 173 | pub fn freertos_rs_event_group_delete(event_group: FreeRtosEventGroupHandle); 174 | pub fn freertos_rs_event_group_set_bits(event_group: FreeRtosEventGroupHandle, bits_to_set: FreeRtosEventBitsType) -> FreeRtosEventBitsType; 175 | pub fn freertos_rs_event_group_get_bits(event_group: FreeRtosEventGroupHandle) -> FreeRtosEventBitsType; 176 | pub fn freertos_rs_event_group_clear_bits(event_group: FreeRtosEventGroupHandle, bits_to_clear: FreeRtosEventBitsType) -> FreeRtosEventBitsType; 177 | pub fn freertos_rs_event_group_wait_bits(event_group: FreeRtosEventGroupHandle, bits_to_wait_for: FreeRtosEventBitsType, clear_on_exit: FreeRtosBaseType, wait_for_all_bits: FreeRtosBaseType, ticks_to_wait: FreeRtosTickType) -> FreeRtosEventBitsType; 178 | pub fn freertos_rs_event_group_sync(event_group: FreeRtosEventGroupHandle, bits_to_set: FreeRtosEventBitsType, bits_to_wait_for: FreeRtosEventBitsType, ticks_to_wait: FreeRtosTickType) -> FreeRtosEventBitsType; 179 | } 180 | -------------------------------------------------------------------------------- /freertos-rust/src/timers.rs: -------------------------------------------------------------------------------- 1 | use crate::InterruptContext; 2 | use crate::base::*; 3 | use crate::prelude::v1::*; 4 | use crate::shim::*; 5 | use crate::units::*; 6 | 7 | unsafe impl Send for Timer {} 8 | unsafe impl Sync for Timer {} 9 | 10 | /// A FreeRTOS software timer. 11 | /// 12 | /// Note that all operations on a timer are processed by a FreeRTOS internal task 13 | /// that receives messages in a queue. Every operation has an associated waiting time 14 | /// for that queue to get unblocked. 15 | pub struct Timer { 16 | handle: FreeRtosTimerHandle, 17 | } 18 | 19 | /// Helper builder for a new software timer. 20 | pub struct TimerBuilder { 21 | name: String, 22 | period: D, 23 | auto_reload: bool, 24 | } 25 | 26 | impl TimerBuilder { 27 | /// Set the name of the timer. 28 | pub fn set_name(&mut self, name: &str) -> &mut Self { 29 | self.name = name.into(); 30 | self 31 | } 32 | 33 | /// Set the period of the timer. 34 | pub fn set_period(&mut self, period: D) -> &mut Self { 35 | self.period = period; 36 | self 37 | } 38 | 39 | /// Should the timer be automatically reloaded? 40 | pub fn set_auto_reload(&mut self, auto_reload: bool) -> &mut Self { 41 | self.auto_reload = auto_reload; 42 | self 43 | } 44 | 45 | /// Try to create the new timer. 46 | /// 47 | /// Note that the newly created timer must be started. 48 | pub fn create(&self, callback: F) -> Result 49 | where 50 | F: Fn(&Timer) -> (), 51 | F: Send + 'static, 52 | { 53 | Timer::spawn( 54 | self.name.as_str(), 55 | self.period.to_ticks(), 56 | self.auto_reload, 57 | callback, 58 | ) 59 | } 60 | } 61 | 62 | impl Timer { 63 | /// Create a new timer builder. 64 | pub fn new(period: D) -> TimerBuilder { 65 | TimerBuilder { 66 | name: "timer".into(), 67 | period: period, 68 | auto_reload: true, 69 | } 70 | } 71 | 72 | /// Create a timer from a raw handle. 73 | /// 74 | /// # Safety 75 | /// 76 | /// `handle` must be a valid FreeRTOS timer handle. 77 | #[inline] 78 | pub unsafe fn from_raw_handle(handle: FreeRtosTimerHandle) -> Self { 79 | Self { handle } 80 | } 81 | #[inline] 82 | pub fn raw_handle(&self) -> FreeRtosTimerHandle { 83 | self.handle 84 | } 85 | 86 | unsafe fn spawn_inner<'a>( 87 | name: &str, 88 | period_ticks: FreeRtosTickType, 89 | auto_reload: bool, 90 | callback: Box, 91 | ) -> Result { 92 | let f = Box::new(callback); 93 | let param_ptr = &*f as *const _ as *mut _; 94 | 95 | let (success, timer_handle) = { 96 | let name = name.as_bytes(); 97 | let name_len = name.len(); 98 | 99 | let ret = freertos_rs_timer_create( 100 | name.as_ptr(), 101 | name_len as u8, 102 | period_ticks, 103 | if auto_reload { 1 } else { 0 }, 104 | param_ptr, 105 | timer_callback, 106 | ); 107 | 108 | ((ret as usize) != 0, ret) 109 | }; 110 | 111 | if success { 112 | mem::forget(f); 113 | } else { 114 | return Err(FreeRtosError::OutOfMemory); 115 | } 116 | 117 | extern "C" fn timer_callback(handle: FreeRtosTimerHandle) -> () { 118 | unsafe { 119 | { 120 | let timer = Timer { handle }; 121 | if let Ok(callback_ptr) = timer.get_id() { 122 | let b = Box::from_raw(callback_ptr as *mut Box); 123 | b(&timer); 124 | let _ = Box::into_raw(b); 125 | } 126 | mem::forget(timer); 127 | } 128 | } 129 | } 130 | 131 | Ok(Timer { 132 | handle: timer_handle as *const _, 133 | }) 134 | } 135 | 136 | fn spawn( 137 | name: &str, 138 | period_tick: FreeRtosTickType, 139 | auto_reload: bool, 140 | callback: F, 141 | ) -> Result 142 | where 143 | F: Fn(&Timer) -> (), 144 | F: Send + 'static, 145 | { 146 | unsafe { Timer::spawn_inner(name, period_tick, auto_reload, Box::new(callback)) } 147 | } 148 | 149 | /// Start the timer. 150 | pub fn start(&self, block_time: D) -> Result<(), FreeRtosError> { 151 | unsafe { 152 | if freertos_rs_timer_start(self.handle, block_time.to_ticks()) == 0 { 153 | Ok(()) 154 | } else { 155 | Err(FreeRtosError::Timeout) 156 | } 157 | } 158 | } 159 | 160 | /// Start the timer from an interrupt. 161 | pub fn start_from_isr(&self, context: &mut InterruptContext) -> Result<(), FreeRtosError> { 162 | unsafe { 163 | if freertos_rs_timer_start_from_isr(self.handle, context.get_task_field_mut()) == 0 { 164 | Ok(()) 165 | } else { 166 | Err(FreeRtosError::QueueSendTimeout) 167 | } 168 | } 169 | } 170 | 171 | /// Stop the timer. 172 | pub fn stop(&self, block_time: D) -> Result<(), FreeRtosError> { 173 | unsafe { 174 | if freertos_rs_timer_stop(self.handle, block_time.to_ticks()) == 0 { 175 | Ok(()) 176 | } else { 177 | Err(FreeRtosError::Timeout) 178 | } 179 | } 180 | } 181 | 182 | /// Change the period of the timer. 183 | pub fn change_period( 184 | &self, 185 | block_time: D, 186 | new_period: D, 187 | ) -> Result<(), FreeRtosError> { 188 | unsafe { 189 | if freertos_rs_timer_change_period( 190 | self.handle, 191 | block_time.to_ticks(), 192 | new_period.to_ticks(), 193 | ) == 0 194 | { 195 | Ok(()) 196 | } else { 197 | Err(FreeRtosError::Timeout) 198 | } 199 | } 200 | } 201 | 202 | /// Detach this timer from Rust's memory management. The timer will still be active and 203 | /// will consume the memory. 204 | /// 205 | /// Can be used for timers that will never be changed and don't need to stay in scope. 206 | /// 207 | /// This method is safe because resource leak is safe in Rust. 208 | pub fn detach(self) { 209 | mem::forget(self); 210 | } 211 | 212 | fn get_id(&self) -> Result { 213 | unsafe { Ok(freertos_rs_timer_get_id(self.handle)) } 214 | } 215 | } 216 | 217 | impl Drop for Timer { 218 | #[allow(unused_must_use)] 219 | fn drop(&mut self) { 220 | unsafe { 221 | if let Ok(callback_ptr) = self.get_id() { 222 | // free the memory 223 | Box::from_raw(callback_ptr as *mut Box); 224 | } 225 | 226 | // todo: configurable timeout? 227 | freertos_rs_timer_delete(self.handle, Duration::ms(1000).to_ticks()); 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /freertos-rust/src/units.rs: -------------------------------------------------------------------------------- 1 | use crate::base::FreeRtosTickType; 2 | use crate::prelude::v1::*; 3 | use crate::shim::*; 4 | 5 | pub trait FreeRtosTimeUnits { 6 | fn get_tick_period_ms() -> u32; 7 | fn get_max_wait() -> u32; 8 | } 9 | 10 | #[derive(Copy, Clone, Default)] 11 | pub struct FreeRtosTimeUnitsShimmed; 12 | impl FreeRtosTimeUnits for FreeRtosTimeUnitsShimmed { 13 | #[inline] 14 | fn get_tick_period_ms() -> u32 { 15 | unsafe { freertos_rs_get_portTICK_PERIOD_MS() } 16 | } 17 | #[inline] 18 | fn get_max_wait() -> u32 { 19 | unsafe { freertos_rs_max_wait() } 20 | } 21 | } 22 | 23 | pub trait DurationTicks: Copy + Clone { 24 | /// Convert to ticks, the internal time measurement unit of FreeRTOS 25 | fn to_ticks(&self) -> FreeRtosTickType; 26 | } 27 | 28 | pub type Duration = DurationImpl; 29 | 30 | /// Time unit used by FreeRTOS, passed to the scheduler as ticks. 31 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 32 | pub struct DurationImpl { 33 | ticks: u32, 34 | _time_units: PhantomData, 35 | } 36 | 37 | impl DurationImpl 38 | where 39 | T: FreeRtosTimeUnits + Copy, 40 | { 41 | /// Milliseconds constructor 42 | pub fn ms(milliseconds: u32) -> Self { 43 | Self::ticks(milliseconds / T::get_tick_period_ms()) 44 | } 45 | 46 | pub fn ticks(ticks: u32) -> Self { 47 | DurationImpl { 48 | ticks: ticks, 49 | _time_units: PhantomData, 50 | } 51 | } 52 | 53 | /// An infinite duration 54 | pub fn infinite() -> Self { 55 | Self::ticks(T::get_max_wait()) 56 | } 57 | 58 | /// A duration of zero, for non-blocking calls 59 | pub fn zero() -> Self { 60 | Self::ticks(0) 61 | } 62 | 63 | /// Smallest unit of measurement, one tick 64 | pub fn eps() -> Self { 65 | Self::ticks(1) 66 | } 67 | 68 | pub fn to_ms(&self) -> u32 { 69 | self.ticks * T::get_tick_period_ms() 70 | } 71 | } 72 | 73 | impl DurationTicks for DurationImpl 74 | where 75 | T: FreeRtosTimeUnits + Copy, 76 | { 77 | fn to_ticks(&self) -> FreeRtosTickType { 78 | self.ticks 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /freertos-rust/src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::base::*; 2 | use crate::prelude::v1::*; 3 | use crate::shim::*; 4 | 5 | #[derive(Debug, Copy, Clone)] 6 | pub struct TypeSizeError { 7 | pub id: usize, 8 | pub c_size: usize, 9 | pub rust_size: usize, 10 | } 11 | 12 | #[cfg(feature = "cpu_clock")] 13 | pub fn cpu_clock_hz() -> u32 { 14 | unsafe { freertos_rs_get_configCPU_CLOCK_HZ() } 15 | } 16 | 17 | /// Perform checks whether the C FreeRTOS shim and Rust agree on the sizes of used types. 18 | pub fn shim_sanity_check() -> Result<(), TypeSizeError> { 19 | let checks = [ 20 | (0, mem::size_of::()), 21 | (1, mem::size_of::()), 22 | (2, mem::size_of::()), 23 | (10, mem::size_of::()), 24 | (11, mem::size_of::()), 25 | (12, mem::size_of::()), 26 | (20, mem::size_of::()), 27 | (21, mem::size_of::()), 28 | (22, mem::size_of::()), 29 | (23, mem::size_of::()), 30 | (24, mem::size_of::()), 31 | (25, mem::size_of::()), 32 | (30, mem::size_of::()), 33 | (31, mem::size_of::()), 34 | (32, mem::size_of::()), 35 | (33, mem::size_of::()), 36 | ]; 37 | 38 | for check in &checks { 39 | let c_size = unsafe { freertos_rs_sizeof(check.0) }; 40 | 41 | if c_size != check.1 as u8 { 42 | return Err(TypeSizeError { 43 | id: check.0 as usize, 44 | c_size: c_size as usize, 45 | rust_size: check.1, 46 | }); 47 | } 48 | } 49 | 50 | Ok(()) 51 | } 52 | 53 | /// # Safety 54 | /// 55 | /// `str` must be a pointer to the beginning of nul-terminated sequence of bytes. 56 | #[cfg(any(feature = "time", feature = "hooks", feature = "sync"))] 57 | pub unsafe fn str_from_c_string(str: *const u8) -> Result { 58 | let mut buf = Vec::new(); 59 | 60 | let mut p = str; 61 | loop { 62 | if *p == 0 { 63 | break; 64 | } 65 | buf.push(*p); 66 | p = p.offset(1); 67 | } 68 | 69 | match String::from_utf8(buf) { 70 | Ok(s) => Ok(s), 71 | Err(_) => Err(FreeRtosError::StringConversionError), 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /publish-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cargo publish --manifest-path freertos-cargo-build/Cargo.toml 4 | 5 | cargo publish --manifest-path freertos-rust/Cargo.toml --------------------------------------------------------------------------------