RusPiRo / ruspiro-tutorials

RusPiRo Tutorial Corner - Doing Raspberry Pi bare metal development the 'Rust way'...
13 stars 2 forks source link

Few questions #9

Closed bitkis closed 4 years ago

bitkis commented 4 years ago

Hi Andre,

Few questions regarding the project I have at this point:

  1. a Raspberry Pi OS written as much as possible in Rust

    Can that be taken as a ultimate goal of the project?

  2. Do you have a road map (perhaps informal) in mind? A set of features to be implemented?
  3. Do you need/want help with any of those features?
  4. One of the things I thought about while looking through the project was possible gdbstub integration. Do you think it could be useful? Just a thought, not saying that's the most needed one.

... more to come...

--Boris

2ndTaleStudio commented 4 years ago

Hey Boris,

thanks for your interest in this project 😄

Let me answer your questions ...

  1. a Raspberry Pi OS written as much as possible in Rust -> Can that be taken as a ultimate goal of the project?

Yup. This is the overarching goal, even though it might not become a multipurpose OS like UNix/Linux/Windows but tailormade for specific use cases.

  1. Do you have a road map (perhaps informal) in mind? A set of features to be implemented?

Well, yes I do have this in mind and some parts in a kind of written form, but nothing publicly available 😉 The high-level features:

  1. Do you need/want help with any of those features?

I do appreciate your interest and sure, if you'd like to spend some sparetime supporting this project I'd be glad to hand over some topics and speed up the implementation 😄

  1. One of the things I thought about while looking through the project was possible gdbstub integration. Do you think it could be useful? Just a thought, not saying that's the most needed one.

Um, well I'm not quite sure if this would be one of the next logical steps to go. Debugging a bare-metal OS on the Raspberry PI would typically require some JTAG setup and a correponding tool to connect the RPI GPIO Pins through an USB port to the hostmachine (PC / Mac) to use a debugger their. Maybe I'm not getting the gdbstub integration right and miss it's advantages at this stage 😧

BR André

bitkis commented 4 years ago

Hey André,

Yup. This is the overarching goal, even though it might not become a multipurpose OS like UNix/Linux/Windows but tailormade for specific use cases.

Yeah, analogy with VxWorks comes in mind... Still it might be good to talk a bit about those specific use cases. Robotics? DAQ/experiment control? Any other?

  • async processing shall be first-class-citicen

yes. Single core, single stack at this point?

  • the OS shall support the setup, creation and configuration of robots (or the like) driven by the Raspberry Pi

Well, what does this mean in terms of the OS features? Have you ever considered integration of embedded-hal? That would enable further integration of support for numerous peripheral devices (https://crates.io/crates/embedded-hal/reverse_dependencies)

  • the OS / Robot shall be able to be extended "on-the-fly" with new behaviors/capabilities via bluetooth/WLAN in case you attach a new sensor, servo or the like to it.

I thought about that too :) As far as I know at this point, we'll need to go extra miles to combine that with async support. E.g., see https://github.com/bkolobara/async-wormhole

  • the OS will in the first versions not distinguish between kernel and user modes but to allow other features to be executed safely virtualization may be required as well.

I don't think kernel/user space separation would make any sense here. Virtualization also doesn't sound right to me in this context. Maybe WASM/WASI is something to look at? Anyway, for the first version(s), I'd suggest perhaps signed native plugins.

I do appreciate your interest and sure, if you'd like to spend some sparetime supporting this project I'd be glad to hand over some topics and speed up the implementation 😄

Yes, I'd like to help as far time permits. Be aware however, I'm a year behind you with respect to Rust.

Um, well I'm not quite sure if this would be one of the next logical steps to go. Debugging a bare-metal OS on the Raspberry PI would typically require some JTAG setup and a correponding tool to connect the RPI GPIO Pins through an USB port to the hostmachine (PC / Mac) to use a debugger their. Maybe I'm not getting the gdbstub integration right and miss it's advantages at this stage 😧

Well, not every bug deserves JTAG setup, not every developer has a spare JTAG dongle. gdbstub allows us to run remote gdb sessions over a serial line or eth/TCP. Good for cases when code Instrumentation is too cumbersome, and JTAG setup is too much. Just something to think about... :)

(hmm... what JTAG probe do you use?)

One more idea I had: a REPL CLI on the console -- scripting (rhai?) + export of selected core and driver functions. Similar setup was very useful for debugging and verification when I worked with VxWorks. Just yet another thought...

--Boris

2ndTaleStudio commented 4 years ago

Hey, thanks for your valuable thoughts here 👍

Still it might be good to talk a bit about those specific use cases. Robotics? DAQ/experiment control? Any other?

Well - the main driver is that I've a 3D model of Wall-E already partially printed and I'm targeting this Robot to be fully controlled by this OS. It's kind of a first learning version that could guide me on the way to further iterate and improve for other use cases.

yes. Single core, single stack at this point?

As the Raspberry Pi already comes with 4 cores the OS will already utilize all of them.

Well, what does this mean in terms of the OS features?

I did checked on the embedded-hal crate but I'm not yet quite sure if this will really support me on the way forward. Certain design decisions are yet to be made and some directions might not be possible or hindered by using this HAL. I do need some more experience in trying stuff out to be sure on this. But yeah, if driver crates already exists for specific sensors, and the like it might be worth evaluating.

async-wormhole sounds interesting and might be useful, but as far as I've seen it requires [std] and ThreadLocalStatics which would be a no-go for the current project. I'm not intending to implement a whole thread model or the like as my first investigations shows that 4 cores async execution could also do the trick and does it well in a cooperative model, where the implementation focusses on disallowing long-running-blocking-code.

I don't think kernel/user space separation would make any sense here.

Yeah, kinda the same for me. WASM is a good idea though. As a stable plug-in mechanism is challenging in Rust due to the not yet stablizied ABI this could be an alterntive.

Yes, I'd like to help as far time permits. Be aware however, I'm a year behind you with respect to Rust.

Great to hear 👍 - as this is a learning project for me as well there is no need to excuse 😉

(hmm... what JTAG probe do you use?)

It's a ARM-USB-TINY-H that I've honestly never got to work with my windows machine and bought while having lots of trouble with my first C/C++ bare metal implementations. But thanks to Rust there is quite less need to analyse memory leaks / dangling pointers as they just can't exist as long as safe code is concerned.

One more idea I had: a REPL CLI on the console

This sounds interesting and can be useful when testing out new behaviors of the Robot from the PC/Mac for example. It might also evolve into the way how behaviors of the robot are implemented. However, I'm afraid that the OS is still in very early stage and I'm not sure if this would fit already into it.

As one addititonal remark: I'm currently - still in a private repo - refactoring many things based on the learnings already gathered and have decided to step away from aarch32 support and concentrating on aarch64 only going forward. This will be floating back into the ruspiro-* crates that will than be used by the planned OS.

BR André

bitkis commented 4 years ago

Single core, single stack at this point?

As the Raspberry Pi already comes with 4 cores the OS will already utilize all of them.

I meant the first version

async-wormhole sounds interesting and might be useful, but as far as I've seen it requires [std] and ThreadLocalStatics which would be a no-go for the current project.

Sure. Sorry for not making myself clear. This it what I wanted to bring into attention:

Sometimes, when running inside an async environment you need to call into JIT generated code
(e.g. wasm) and .await from there. Because the JIT code is not available at compile time, the Rust
compiler can't do their "create a state machine" magic. In the end you can't have .await statements
in non-async functions.

The same, I believe, holds for any plugin, not necessarily JIT code.

Yet another point here is that async-wormhole's predecessor, libfringe, does support bare metal operation.

Yes, I'd like to help as far time permits. Be aware however, I'm a year behind you with respect to Rust.

Great to hear 👍 - as this is a learning project for me as well there is no need to excuse 😉

So, let's make a plan?

2ndTaleStudio commented 4 years ago

So, let's make a plan?

Yes, sure. I'll create a new repo in this organization with the actual OS project name " naupli-os" 😉 and will open a new issue there to prepare the plan and discuss the details if you don't mind. I'll add you as a contributor to this repo to ensure you can smoothly work on this as well.

bitkis commented 4 years ago

Yes, I'm all set :)

Andrė, I not sure I like the I2C implementation and APIs. For me, something like the following would make better sense:

impl I2c {
    // START - ADDR - (H -> D) - STOP
    // `(H -> D)` denotes data being sent from the host to the device
    pub fn async write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), I2cError> { /* .. */}

    // START - ADDR - (D -> H) - STOP 
    // `(D -> H)` denotes data being sent from the device to the host
    pub fn async read(&mut self, addr: u8, buf: &mut [u8]) -> Result<(), I2cError> { /* .. */ }

    // START - ADDR - (H -> D) - reSTART - ADDR - (D -> H) - STOP
    // `reSTART` denotes a "repeated START"
    pub fn async write_then_read(&mut self, addr: u8, tx_buf: &[u8], rx_buf: &mut [u8]) -> Result<(), I2cError> { /* .. */ }
}

Could you elaborate a bit on the current design choices?

2ndTaleStudio commented 4 years ago

Hey,

well the API you are proposing is a bit more like an UART API that just sends arbitrary data to the device. However, the I²C bus specification - as far as I have understood it - defines quite well that the I²C is used to access attached devices, where the device has to have an address and data can be read from specific device registers. So the API treis to reflect that and ensures that it provides functions to access a specific register of the device attached to the bus at it's address. Furthermore the register at the device are only 8 bits wide. Another specific option is that a device can be configured to automatically increase the register once data has been read or written. This allows to read and write data in larger bulks and not only 8 Bits. As 16 Bits register sizes are quite common (so the device provides an 8bit low and a 8 bit high part) the bulk function for the 16Bit variant has made its way into a specialized function.

With this in mind the signature pub fn async write(&mut self, addr: u8, bytes: &[u8]) would not be sufficient in all cases as it misses the register value and the fact that bulk read/writes with more than 8 bit is only possible if the device is configured and does support this. However, I'm open to adjust and refactor the API if there are better options available. And to further add to this, there are alos devices that allows writting specific data that does not contain any register which is typically used to reset the device - this is reflected with the write_u8 function.

bitkis commented 4 years ago

Hey Andrė,

I2C is not a "slave register access" protocol, it's a message passing protocol. I have experience designing and implementing a full blown communication protocol on the top of I2C. The purpose of it was to enable microcontrollers within a complex, dynamic system talk to each other. Surely, it was "arbitrary" data passing.

As far as slave (device) register access goes, from I2C prospective it's usually a two (sometimes three) -step process.

  1. Set (write) page -- optional, required for some devices only
  2. Set (write) register address (offset)
  3. Read/write data

Register address can be u8 or u16. I never ran into such of u32, but, technically, there is nothing preventing it. The last thing, nothing prevents&[u8] to have capacity 1 either, right?

The API I proposed are low level API, we can build registry access API on the top of that

2ndTaleStudio commented 4 years ago

Hey Boris,

thanks for shedding additional light into the I²C Bus. My knowledge here is mainly based on the Raspberry Pi BCM Peripheral specification document. This states that the built-in BCM controller is Master Only (The Broadcom Serial Control bus is a proprietary bus compliant with the Philips® I2C bus/interface):

• I2C single master only operation (supports clock stretching wait states) • Both 7-bit and 10-bit addressing is supported.

I've currently only implemented to IMU sensors giving acceleragion and gyrosscope data. There is was quite convinent to read for example in a bulk data from all axis which summed up into reading 24Bits (having the register increment configured).

However, if you are already experienced in this domain I'm happy to get you inputs and proposals on the design. We could also use different API layers for optimal abstraction of the interface. One low-level as you proposed and on top the slave access mainly driven based on registers if this makes sense. As the RPi has only one I²C master there might be also design decisions to be made how to configure this one to support the variaty of slaves able to connect to it.

If you don't mind you could fork the ruspiro-i2c repo and sketch a proposal of your API 😉

bitkis commented 4 years ago

If you don't mind you could fork the ruspiro-i2c repo and sketch a proposal of your API 😉

Sure, will do. However I think we need to decide on https://github.com/RusPiRo/Naupli-OS/issues/1#issuecomment-694607561 first -- I might be wrong but I see that as one of the major design decisions to make in this project

2ndTaleStudio commented 4 years ago

Closing this issue as the discussion will continue within the specific project repo.