lupyuen / pinetime-rust-mynewt

PineTime Smart Watch firmware based on Rust and Apache Mynewt OS
https://lupyuen.github.io/articles/sneak-peek-of-pinetime-smart-watch-and-why-its-perfect-for-teaching-iot
Apache License 2.0
210 stars 54 forks source link

Firmware to update MCUBoot Bootloader #29

Closed lupyuen closed 3 years ago

lupyuen commented 3 years ago

Hi thanks for helping to create the Rust+Mynewt firmware for updating the MCUBoot Bootloader :-)

  1. Try writing some Rust code in https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/lib.rs

  2. Check whether GitHub Actions will compile it. You need to enable GitHub Actions in your repo... just click "Actions" to enable it

  3. Edit the Rust code in lib.rs to read the bytes from a binary file (i.e. the bootloader binary)

    Use the include_bytes! macro as shown here...

    https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/app/src/chip8.rs#L88

    You may put the binary file in the same folder as lib.rs.

  4. Next step is to write the bytes into flash ROM. But we'll do this one step at a time :-)

To test your firmware without a PineTime, use Remote PineTime...

https://github.com/lupyuen/remote-pinetime-bot/blob/master/README.md

Lemme know if you get stuck. Thanks again :-)

Killerpug commented 3 years ago

So I think I include the file with include_bytes! and I also tried to print to console but failed hahah :) no_std is a huge constraint so I don't know how to convert &[u8;x](byte slice array I think) to str without std crate (just as a debug log). Any advice? IDK if I should keep trying to print this because that was like a side/debug task or shall we continue with my only 1 new line of code :D.

lupyuen commented 3 years ago

No worries :-) We can use semihosting to show debug output. I'll post the steps in a while...

lupyuen commented 3 years ago

To dump a binary array to Semihosting Log

Call console::dump...

https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/rust/mynewt/src/sys/console.rs#L67-L68

///  Write "length" number of bytes from "buffer" to the output buffer in hex format.
pub fn dump(buffer: *const u8, len: u32) { ...

Remember to call console::flush after console::dump

Semihosting Logging is really slow, so perhaps we can dump the first 16 bytes and the last 16 bytes of the array.

Or print a crypto hash of the array. We'll probably need this for integrity checking.

To enable Semihosting Log

Semihosting is disabled by default. To enable it, edit

https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/targets/nrf52_my_sensor/pkg.yml

And change the line...

 - -DDISABLE_SEMIHOSTING   #  Uncomment to disable Arm Semihosting

To...

# - -DDISABLE_SEMIHOSTING   #  Uncomment to disable Arm Semihosting

And your debug messages will appear in the Remote PineTime Log Channel:

https://t.me/remotepinetimelog

Lemme know if you're not sure of anything thanks :-)

Killerpug commented 3 years ago

Thanks for the instructions, pretty clear. Here is the commit 41a5e8a and snippet of the semihosting log validating that the file is actually being loaded, I displayed the first and last 16 bytes, seems ok. I learned a little about references in Rust :). One question: What crate in the repo has the crypto hash functionality? what's next :D?

imagen

lupyuen commented 3 years ago

Looks great! Can you find something no_std from the Rust Core Library that computes hashes? If there isn't any, then try crates.io?

Lemme post more steps for writing the bootloader to flash memory in a while...

lupyuen commented 3 years ago

To write the bootloader to Flash ROM we need to call the Mynewt functions hal_flash_erase and hal_flash_write like this...

From https://github.com/lupyuen/pinetime-rust-mynewt/blob/master/libs/pinetime_boot/src/pinetime_boot.c#L154-L165

        hal_flash_erase(  //  Erase...
            0,            //  Internal Flash ROM
            (uint32_t) relocated_vector_table,  //  At the relocated address
            0x100         //  Assume that we erase an entire page
        );
        hal_flash_write(  //  Write...
            0,            //  Internal Flash ROM
            (uint32_t) relocated_vector_table,  //  To the relocated address
            vector_table, //  From the original address
            0x100         //  Assume that we copy an entire page
        );

Mynewt doc for hal_flash_erase: https://mynewt.apache.org/latest/os/modules/hal/hal_flash/hal_flash.html#c.hal_flash_erase

Mynewt doc for hal_flash_write: https://mynewt.apache.org/latest/os/modules/hal/hal_flash/hal_flash.html#c.hal_flash_write

The first parameter for hal_flash_erase and hal_flash_write should be 0, since we're writing to Internal Flash ROM.

The last parameter for hal_flash_erase and hal_flash_write should be 0x1000 (instead of 0x100), since we can write at most 4 KB in a sector at a time.

For NOR Flash we must always erase a sector before writing. So inside a loop we call hal_flash_erase then hal_flash_write for every 4 KB sector.

We will need to declare the Mynewt functions as...

extern {
hal_flash_erase(flash_id: u8, address: u32, num_bytes: u32) -> i32;
hal_flash_write(flash_id: u8, address: u32, src: *core::ffi::c_void, num_bytes: u32) -> i32;
}

This article may be helpful:

https://lupyuen.github.io/pinetime-rust-mynewt/articles/spiflash

Killerpug commented 3 years ago

My build keeps failing :( https://github.com/Killerpug/pinetime-rust-mynewt/commit/5ebc2bfdf5f107ade04c83bbc83e07379fd6424e, here is what the log says about not finding the functions https://github.com/Killerpug/pinetime-rust-mynewt/runs/1317090619?check_suite_focus=true. what's happening?

lupyuen commented 3 years ago

The code I gave you was in C... we need to convert to Rust. You need help with that?

Killerpug commented 3 years ago

Yes please, I thought it was just using the C functions in Rust code. How can you convert those into Rust :o? I appreciate any help :)

lupyuen commented 3 years ago

Hi: Thank you so much for helping out :-) I'm sorry I have to drop this Bootloader Enhancement due to a health bug (I have hypertension)

Meanwhile I'll be slowing working on 2 projects (that are less stressful)...

  1. PineTime Watch Faces in WebAssembly and Rust

  2. LVGL Scripting in Rhai and Rust

If you're keen on learning Embedded Rust, you might wanna follow the two projects above.

Thanks again for all your support :-)