PINE64
official software project ? (Rust for IOT ?) - Printable Version

+- PINE64 (https://forum.pine64.org)
+-- Forum: PineTime (https://forum.pine64.org/forumdisplay.php?fid=134)
+--- Forum: Development Discussion on PineTime (https://forum.pine64.org/forumdisplay.php?fid=136)
+--- Thread: official software project ? (Rust for IOT ?) (/showthread.php?tid=8375)



official software project ? (Rust for IOT ?) - abdel - 11-19-2019

Hi

I don't have yet my dev kit, but I have just started to check for the current status.
Am I wrong if I say that there is no official project for now and people are testing things/setting up their dev setup on their side ?

Look like the most advanced project is Lup Yuen Lee's rust project (https://twitter.com/MisterTechBlog), but he seems to not use this forum.
So maybe this project is kind of official ?
I was first very surprised to see he is working in rust language. 
I always thought that rust is a very good language but not for IOT because of the code size and lack of full control. (just compare a hello world in rust and C (in release mode) and check the code size). After few research I saw that this big size come from libraries that are statically linked. In barre metal we dont use external library like libstd, so we are fine.
But I then dont have an answer to my question: is rust code bigger than C ? If yes is it acceptable ?
I have nothing against rust, it can be an opportunity to learn (I like the philosophy behind rust, and I have planed to learn it in the future), but when doing IOT stuff it's better to have full control on what we are doing. And in C you can understand what is happening in low level (assembly code). I suppose I wont be able to do that in rust.
Also in C you have full control of the FW size and of your structure. Is it also the case in rust ? I read in the net that Rust references can be fat ... 

One argument of  Lup Yuen Lee to use rust is that, rust protect us on memory corruption. But on very small system it's better to avoid use of heap (malloc/free). You dont need that. And you may even end up by fragmenting your few RAM because of different size object allocation.
And in rust if you use things like map or vector, are you then indireclty use the heap ? If yes, is there any issue on RAM fragmentation ?

One more thing: There is 512KB of ROM. In case of FW update which I suppose has to be done via bluetooth., where can we save the blob we receive ? We may have to split in 2 the ROM, right ? If it's the case then the FW code has to fit in 256 KB (less if we count the bootstrap). Is the rust code able to fit ?
Or maybe you prefer to have a smart bootloader with DFU and bluetooth inside the bootloader ?

Again I have nothing against rust, and will be happy to learn it sooner that I was expecting, but then I would like to know if someone is comfortable enough to handle this kind of issue ?


RE: official software project ? (Rust for IOT ?) - pfeerick - 11-19-2019

I have this feeling from looking at the video of the code Lup Yuen Lee was demoing that it ended up around the 165k mark... so not insignificant... but considering it was a RTOS plus Rust, display drivers, touch drivers, who knows what else plus it was a debug build, not a release build, and it's still early days... so there is plenty of room for improvement. If I have to learn Rust to program the thing, so be it... my preference being C++.


RE: official software project ? (Rust for IOT ?) - abdel - 11-19-2019

Ok, so it sould be ok then. I will investigate more when I will have my device


RE: official software project ? (Rust for IOT ?) - lupyuen - 11-20-2019

Hi All: I'm here (the writer of that long PineTime article), so glad the forum is still alive :-)

Here's the build size as of today, which includes the Rust driver touch controller...

Code:
+ newt size -v nrf52_my_sensor
Size of Application Image: app
Mem FLASH: 0x8000-0x42000
Mem RAM: 0x20000000-0x20010000
 FLASH     RAM
   799     299 *fill*
   228       0 apps_my_sensor_app.a
  2302       0 crypto_tinycrypt.a
   401       0 encoding_base64.a
   948       0 encoding_json.a
   440     444 hw_bsp_nrf52.a
    52       0 hw_cmsis-core.a
   154       0 hw_hal.a
  6806     154 hw_mcu_nordic_nrf52xxx.a
     2       0 hw_sensor_creator.a
  1516     256 hw_sensor.a
  8546    8220 kernel_os.a
  2562      50 libc_baselibc.a
   298       0 libs_mynewt_rust.a
 56133     402 libs_rust_app.a
 13400       0 libs_rust_libcore.a
   736      42 libs_semihosting_console.a
   974     225 libs_sensor_coap.a
  1157     209 libs_sensor_network.a
   677     212 libs_temp_stub.a
  2397     394 net_oic.a
 35496    2103 nimble_controller.a
  4026    1209 nimble_drivers_nrf52.a
 44242    2785 nimble_host.a
  1814     648 nimble_host_store_config.a
   692    1096 nimble_transport_ram.a
   712      42 sys_config.a
   334     128 sys_flash_map.a
     2       0 sys_log_modlog.a
   686      29 sys_mfg.a
    30       5 sys_sysinit.a
   120       0 util_mem.a
   164       0 nrf52_my_sensor-sysinit-app.a
   166       0 libg.a
   808       0 libgcc.a

objsize
  text    data     bss     dec     hex filename
189780     352   18200  208332   32dcc /Users/Luppy/mynewt/stm32bluepill-mynewt-sensor/bin/targets/nrf52_my_sensor/app/apps/my_sensor_app/my_sensor_app.elf

Current ROM size is 189 KB, that's less than half of the 512 KB total available ROM. What's taking up the ROM?

libs_rust_app.a (56 KB): This is the Rust application + third-party (non-system) Rust libraries, including the Embedded Graphics library. The large size is probably due to the font embedded in the library.


nimble_host.a (44 KB): This is the NimBLE Bluetooth Stack host code that runs the Bluetooth iBeacon logic. (Similar to Nordic SoftDevice)

nimble_controller.a (35 KB): This is the NimBLE Bluetooth Driver code for the nRF52 2.4 GHz transceiver. (Similar to Nordic SoftDevice)

libs_rust_libcore.a (13 KB): This is the Rust Core Library. System functions needed by Rust.  Similar to stdlib and stdio.

Rest of the code is from the Mynewt OS, written in C.

So right now the Bluetooth Stack (written in C) is actually a little bigger than the combined Rust code. And the Rust code is bloated really because of the graphical UI. 

In any case, we still got plenty of ROM space to use. I think eventually we should offload the font data to the SPI Flash memory (8 MB)

About the Bootloader and Doing Direct Firmware Upgrade (DFU) via Bluetooth...

I'm now using a Stub Bootloader. It doesn't do anything, it just jumps to the Application Code.

The proper bootloader to use is MCUboot (also used in Zephyr OS). It supports swapping of Application Code Images and can rollback in case of problems. Which means we need to store 2 copies of the Application Code: Old (before upgrade) and New (after upgrade).

How shall we fit 2 copies of Application Code into 512 KB ROM? We could offload the font data and other graphical assets into the SPI Flash (8 MB). Any user-developed Watch Apps that run on top of the system Rust Application could also be offloaded to the SPI Flash.

Or we could store both copies of Application Code into the SPI Flash. Which means the bootloader will need to overwrite the ROM by SPI Flash during upgrades and rollback. More work for the bootloader.

Or we could upgrade PineTime from nRF32832 to nRF52840 to double the ROM size (1 MB!). This makes PineTime more expensive of course.

Application Code Images are digitally signed to ensure they are authentic, so it's possible to receive Application Code updates via Bluetooth.

About the Assembly Code generated by the Rust Compiler...

The Rust Compiler generates Assembly Code that's surprisingly readable, almost like C! (I browse the Assembly Code sometimes to check for performance issues)  Check this out...

https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/logs/libapp-demangle.S#L2143-L3018

This Assembly Code corresponds to this Rust code for rendering the UI...

https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/display.rs#L44-L145

That disassembly was generated by "objdump" from the compiled Rust ".o" files. The Rust Compiler generates machine code that's as clean as the C Compiler, no function prologues and epilogues. 

This is the same machine code that goes into the actual PineTime Firmware.  Here's the "objdump" disassembly of the PineTime nRF52 Firmware, look at lines 22030 to 22872...

https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/logs/my_sensor_app.elf.lst#L22030-L22827

Another example: Here's an Interrupt Handler written in Rust: 

https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/touch_sensor.rs#L72-L80 

And here's the "objdump" disassembly of the compiled ".o" file: 

https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/logs/libapp-demangle.S#L861-L899


About Static vs Dynamic Memory Allocation...

I'm also a stubborn believer that all memory in embedded devices should be Statically Allocated, budgeted way in advance. (And if we didn't budget enough, it's our fault!)

The Rust code I have written is based on the "[no_std]" convention: No heap, no dynamic memory allocation ("Box"), no standard library for String() support (which uses heap).

Which causes some pain because some Rust libraries insist on using the "[std]" convention with heap support. So you see this weird code below for formatting numbers as strings... The write!() macro insists on using a heap-based string for storing the formatted output. Thus we fake it by passing an "arrayvec::ArrayString", which comes from an external library that uses a fixed-size array ("buf_x") to simulate a heap-based string...

From https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/display.rs#L98-L123
Code:
/// Display the touched (X, Y) coordinates
pub fn show_touch(x: u16, y: u16) -> MynewtResult<()> {
   //  Format coordinates as text
   let mut buf_x = ArrayString::<[u8; 20]>::new();
   write!(&mut buf_x, "  X = {}  ", x)
       .expect("show touch fail");
   let text_x = fonts::Font12x16::<Rgb565>
       ::render_str(&buf_x)
       .stroke(Some(Rgb565::from((0xff, 0xff, 0xff))))  //  White
       .fill(Some(Rgb565::from((0x00, 0x00, 0x00))))    //  Black
       .translate(Coord::new(40, 100));
   //  Render text to display
   unsafe {
       DISPLAY.draw(text_x);    
   }



RE: official software project ? (Rust for IOT ?) - pfeerick - 11-20-2019

Hi there, writer of that long article! Big Grin

Love your work, look forward to seeing more of your exploration of the PineTime... means I can learn more about them while I wait for GA of the Dev kits.

The breakdown of FLASH memory usage... looks quite reasonable, considering the current state of development. And as you said, there's still that SPI Flash that assets such as fonts, graphics, even apps, can be offloaded to.

The MCUboot mechanism sounds very much like the eboot one used on the ESP8266/ESP32... i.e. allowing OTA updates via multiple application slots.

Anyway, nice to see you on the forum! Smile


RE: official software project ? (Rust for IOT ?) - Luke - 11-20-2019

@lupyuen Welcome to the forums Smile amazing work


RE: official software project ? (Rust for IOT ?) - lupyuen - 11-20-2019

Thanks everyone for the warm welcome!  Smile I think there's plenty of room for all kinds of PineTime environments: C, TinyGo, MicroPython, Rust, ... Most important thing is that we share our porting experiences so that we may all learn!

Now I know that Rust can be intimidating. (Some members of the Rust Community weren't exactly as welcoming as the folks here.) But I feel that Rust is great for practical embedded development.

I don't believe in 100% pure functional programming in Rust (because that's unrealistic). And I don't believe in piling on so many Type Abstractions that make Embedded Rust impossible to learn.

Like I always tell my IoT students... Don't be afraid to challenge me on anything that I say  Smile 

So feel free to ask me anything... And suggest how I can make things better. BTW just call me Lup  Smile