diondokter / device-driver

A toolkit to create better Rust device drivers, faster
Apache License 2.0
94 stars 4 forks source link

Extend the 'command device' to support more complex devices #33

Open tulku opened 1 month ago

tulku commented 1 month ago

Hi! I like this crate a lot, and have used it to implement some drivers for devices that work with registers.

However, I now wanted to use it to write a driver for this device: MLX90393. Reading the datasheet it would probably be modeled as a 'command device' where the commands can have arguments and return information, but that type of command does not seem to be possible with device-driver.

I'll try modeling the device as a register device, and see if that works. How would you model this device? Does it make sense to expand the 'command device' to accommodate more complex commands?

Thanks

diondokter commented 1 month ago

Hi!

Interesting problem. Yeah the current commands are just for sending a non-register signal to the device. I made it to work for the s2-lp radio chip.

In theory there's no reason why commands shouldn't have associated data and return values. In principle then commands would be the same as registers, but just write-only and they return a different value (or nothing). But that doesn't exist right now...

I guess you could try to emulate it. Make your commands into write-only registers. In your device implementation you can look at the address and know it's a command and not a real register. You can then store the return value in your device struct that you can read directly from code or you can expose it as an extra virtual read-only register maybe...

Does that make sense?

Knowing this exists, I think I'm gonna draw up how I want to make things work in the future. I was thinking about doing a bunch of refactors anyways.

tulku commented 1 month ago

I am doing something similar, but using RO registers instead of WO ones. Semantically it looks less nice, but the sequence of <Write device address><Write register address><Read register content> (which is the i2c.write_read() method) matches the sequence on this device <Write device address><Write command number><Read status byte>. I am writing the registers like:

            register RESET {
                type RWType = RO;
                const ADDRESS: u8 = 0xF0;
                const SIZE_BITS: usize = 8;
                data: u8 = 0..2,
                rs: bool = 2,
                sed: bool = 3,
                error: bool = 4,
                sm_mode: bool = 5,
                woc_mode: bool = 6,
                burst_mode: bool = 7,
            },

I was not sure how to write the actual registers, where you need to send the READ / WRITE register command, then the register address then the contents in case of write, and finally read the status. I like the trick of changing what the method does by looking at the registered address and with that doing different things. I think that should work.

Thanks for the help!

diondokter commented 1 month ago

Read only can work too. But then you can't send data associated with the commands. Pick your poison I guess