utzig commented on a change in pull request #97: URL: https://github.com/apache/mynewt-documentation/pull/97#discussion_r434937287
########## File path: docs/tutorials/other/rust.rst ########## @@ -0,0 +1,275 @@ +.. + # + # Copyright 2020 Casper Meijn <cas...@meijn.net> + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + # + +Rust Blinky application +=========================================== + +This tutorial shows you how to convert the Blinky application to Rust. This includes +integrating Cargo into newt builder. + +.. contents:: + :local: + :depth: 2 + +Prerequisites +~~~~~~~~~~~~~ + +Ensure that you meet the following prerequisites before continuing with +this tutorial: + +- You have basic knowledge about `Rust <https://doc.rust-lang.org/stable/book/>`__. +- You have basic knowledge about `Rust Embedded <https://rust-embedded.github.io/book/>`__. +- You have rust installed using `rustup <https://doc.rust-lang.org/stable/book/ch01-01-installation.html>`__. +- Follow :doc:`Blinky tutorial <../blinky/blinky>` to create a + project with a basic application. You will extend that application in this + tutorial. + +Initialize Rust +~~~~~~~~~~~~~~~ + +The first step is to initialize a crate for developing your application in. You +can do this in the existing `blinky` directory. + +.. code-block:: console + + $ cargo init --lib apps/blinky + Created library package + $ tree apps/blinky + apps/blinky + ├── Cargo.toml + ├── pkg.yml + └── src + ├── lib.rs + └── main.c + + 1 directory, 4 files + +This creates a Cargo.toml configuration file and src/lib.rs. We will use these +files to place our application in. You may notice that the Rust application is +not configured as an app, but as an lib. This is needed later to allow linking +to the rest of mynewt. + +Setup the basics +~~~~~~~~~~~~~~~~ + +Now we want to actually convert the application code to Rust. Let's open `src/lib.rs` +and remove the contents. Then start with some basic setup: + +.. code-block:: rust + + #![no_std] + + extern crate panic_halt; + + #[no_mangle] + pub extern "C" fn main() { + + loop { + } + } + +The first line states that this program doesn't use the standard library. This +means that only the core library is linked to the program. See +`rust-embedded book <https://rust-embedded.github.io/book/intro/no-std.html>`__ +for more information. + +The next line specifies the panic handler. Panicking is an important feature of +Rust. To ease this tutorial we choose to halt the processor on panic. See +`rust-embedded book <https://docs.rust-embedded.org/book/start/panicking.html>`__ +for alternatives. + +Then we have the ``main`` function. It contains a endless loop as it should never +return, but doesn't do anything useful yet. It is marked ``no_mangle`` and ``extern "C"`` +to make sure it can be called from the mynewt C code. + +Converting sysinit +~~~~~~~~~~~~~~~~~~ + +The next step is to do the sysinit. This is implemented as a C macro, which is +incompatible with Rust. This could be solved by using a C library, but for this +tutorial we will simply execute the macro manually. + +.. code-block:: rust + :emphasize-lines: 3-7, 13-16 + + #![no_std] + + extern "C" { + fn sysinit_start(); + fn sysinit_app(); + fn sysinit_end(); + } + + extern crate panic_halt; + + #[no_mangle] + pub extern "C" fn main() { + /* Initialize all packages. */ + unsafe { sysinit_start(); } + unsafe { sysinit_app(); } + unsafe { sysinit_end(); } + + loop { + } + } + +First we manually define the three sysinit functions. This is similar to the +C header file. Then we execute the sysinit as the macro would do. + +We need the ``unsafe`` indication because the C code doesn't have the same memory +guarantees as Rust. Normally we need to build a safe Rust wrapper, but that is +out of scope for this tutorial. + +Doing GPIO and delays +~~~~~~~~~~~~~~~~~~~~~ + +Now it is time to do some GPIO and add a delay. Again we define the functions +and then use them in and around the loop. We need some constants that are +normally defined by the BSP or MCU. These constants need to move to a better +place later. + +.. code-block:: rust + :emphasize-lines: 7-9, 14, 16, 25, 28-29, 31-32 + + #![no_std] + + extern "C" { + fn sysinit_start(); + fn sysinit_app(); + fn sysinit_end(); + fn hal_gpio_init_out(pin: i32, val: i32) -> i32; + fn hal_gpio_toggle(pin: i32); + fn os_time_delay(osticks: u32); + } + + extern crate panic_halt; + + const OS_TICKS_PER_SEC: u32 = 128; + + const LED_BLINK_PIN: i32 = 23; + + #[no_mangle] + pub extern "C" fn main() { + /* Initialize all packages. */ + unsafe { sysinit_start(); } + unsafe { sysinit_app(); } + unsafe { sysinit_end(); } + + unsafe { hal_gpio_init_out(LED_BLINK_PIN, 1); } + + loop { + /* Wait one second */ + unsafe { os_time_delay(OS_TICKS_PER_SEC); } + + /* Toggle the LED */ + unsafe { hal_gpio_toggle(LED_BLINK_PIN); } + } + } + +Cargo build +~~~~~~~~~~~ + +Now that the application is converted we need to build it and link it the rest of mynewt. We start with Cargo.toml: + +.. code-block:: toml + :emphasize-lines: 7-8, 10-11 + + [package] + name = "rust-klok" + version = "0.1.0" + authors = ["Casper Meijn <cas...@meijn.net>"] + edition = "2018" + + [dependencies] + panic-halt = "0.2.0" + + [lib] + crate-type = ["staticlib"] + +This adds the ``panic-halt`` dependency, which is needed for the panic handler as +mentioned earlier. It also configures the crate as staticlib, which causes the +application to be build as .a-library. This will be needed in a later step. + +Next we need a script for running ``cargo`` and moving the library to the correct +place. Create a new file named ``apps/blinky/cargo_build.sh`` with the following contents: + +.. code-block:: bash + :emphasize-lines: 1-5 + + #!/bin/bash + set -eu + TARGET="thumbv7m-none-eabi" Review comment: Mynewt also supports many Cortex-M0 targets which are `thumbv6m-none-eabi`, not sure this would work in that case! ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org