ChanServ changed the topic of #rust-embedded to: Welcome to the Rust Embedded IRC channel! Bridged to #rust-embedded:matrix.org and logged at https://libera.irclog.whitequark.org/rust-embedded, code of conduct at https://www.rust-lang.org/conduct.html
Foxyloxy has quit [Ping timeout: 240 seconds]
Foxyloxy has joined #rust-embedded
Foxyloxy has quit [Ping timeout: 272 seconds]
Foxyloxy has joined #rust-embedded
Foxyloxy has quit [Ping timeout: 256 seconds]
Foxyloxy has joined #rust-embedded
<re_irc> <sajattack> better or worse than Makefiles which use docker?
Foxyloxy has quit [Ping timeout: 256 seconds]
Foxyloxy has joined #rust-embedded
Foxyloxy has quit [Ping timeout: 250 seconds]
Foxyloxy has joined #rust-embedded
Foxyloxy has quit [Read error: Connection reset by peer]
Foxyloxy has joined #rust-embedded
Foxyloxy has quit [Ping timeout: 256 seconds]
Foxyloxy has joined #rust-embedded
emerent has quit [Ping timeout: 256 seconds]
emerent has joined #rust-embedded
Foxyloxy has quit [*.net *.split]
limpkin has quit [*.net *.split]
sknebel has quit [*.net *.split]
Rahix has quit [*.net *.split]
richardeoin has quit [*.net *.split]
Foxyloxy has joined #rust-embedded
richardeoin has joined #rust-embedded
Rahix has joined #rust-embedded
sknebel has joined #rust-embedded
limpkin has joined #rust-embedded
crabbedhaloablut has quit [*.net *.split]
crabbedhaloablut has joined #rust-embedded
cr1901 has quit [Quit: Leaving]
cr1901 has joined #rust-embedded
cr1901 has quit [Remote host closed the connection]
mrkajetanp has quit [Ping timeout: 240 seconds]
<re_irc> <eldruin> PSA: Here is the roadmap for the traits that have been removed (https://github.com/rust-embedded/embedded-hal/issues/357) from "embedded-hal" ahead of the 1.0.0 release. This includes the input capture, PWM, QEI, timer and watchdog traits. Please participate in the issues for each trait/module if you are interested in having them back.
<re_irc> pub enum DapState<
<re_irc> <korken89> Trait masters, does anyone know how to solve this:
<re_irc> CONTEXT: Context,
<re_irc> JTAG: jtag::Jtag<CONTEXT>,
<re_irc> <korken89> It seems to want a "PhantomData"
<re_irc> <chrysn (@chrysn:matrix.org)> eldruin: I don't quite see why the unbound types are so much of an issue. Wouldn't the users just declare their requirements on the peripherals' types?
<re_irc> <chrysn (@chrysn:matrix.org)> e.g., on anything time related, they'd require that a timer has a TryFromcore::time::Duration, thus limiting the timers to those that actually implement the conversion, and most will, and those that can't (or fail) become visible as build-time (or run-time in case the TryFrom errs; future maybe-const traits might improve that) erros.
<re_irc> For example, if somebody creates a device driver that receives a `CountDown` struct, it needs to specify what its `Time` type should be. If they choose a type coming from `fugit`, somebody else cannot use this driver if the HAL implementation for the MCU they are using only provides `CountDown` with `Time` types defined in `embedded-time`. It is also not possible to implement `CountDown` for `Time` types defined by `fugit` in a...
<re_irc> <eldruin> I do not have the time to discuss this right now but I added an example to the roadmap issue:
<re_irc> I would suggest that you comment on the relevant issues and/or tomorrow in our weekly meeting. Your participation would certainly be valuable.
<re_irc> ... straight-forward way due to the orphan rule.
<re_irc> <eldruin> * > For example, if somebody creates a device driver that receives a "CountDown" struct, it needs to specify what its "Time" type should be. If they choose a type coming from "fugit", somebody else cannot use this driver if the HAL implementation for the MCU they are using only provides "CountDown" with "Time" types defined in "embedded-time". It is also not possible to implement "CountDown" for "Time" types defined by "fu
<re_irc> <chrysn (@chrysn:matrix.org)> Thanks, I'll come back to that there or on the meeting.
<re_irc> <eldruin> I do not have the time to discuss this right now but I added an example to the roadmap issue:
<re_irc> > For example, if somebody creates a device driver that receives a "CountDown" struct, it needs to specify what its "Time" type should be. If they choose a type coming from "fugit", somebody else cannot use this driver if the HAL implementation for the MCU they are using only provides "CountDown" with "Time" types defined in "embedded-time". It is also not possible for the user to implement "CountDown" for "Time" types defined by...
<re_irc> ... "fugit" in a straight-forward way due to the orphan rule.
<re_irc> > In summary, it is not possible for anybody to start a countdown for a certain duration in a generic way, without it being tied to a particular time implementation and thus forcing everybody to use that one.
<re_irc> I would suggest that you comment on the relevant issues and/or tomorrow in our weekly meeting. Your participation would certainly be valuable.
mrkajetanp has joined #rust-embedded
starblue1 has quit [Ping timeout: 272 seconds]
starblue1 has joined #rust-embedded
cr1901 has joined #rust-embedded
<re_irc> <adamgreig> eldruin: amazing timing, we got all three PRs into one bors commit :D https://github.com/rust-embedded/embedonomicon/commit/6c669e29fc8ba533df6c36befabc62d3eedc4793
<re_irc> <eldruin> hahaha indeed perfectly synchronized
Foxyloxy has quit [Quit: Textual IRC Client: www.textualapp.com]
Foxyloxy has joined #rust-embedded
<re_irc> <dngrs (spookyvision@github)> > It is also not possible for the user to implement CountDown for Time types defined by fugit in a straight-forward way due to the orphan rule.
<re_irc> Indeed I've been inconvenienced by that in the past. Hoping a better solution will emerge!
ni has quit [Quit: WeeChat 3.0]
ni has joined #rust-embedded
gsalazar has joined #rust-embedded
cr1901_ has joined #rust-embedded
cr1901 has quit [Ping timeout: 240 seconds]
dreamcat4 has joined #rust-embedded
gsalazar has quit [Remote host closed the connection]
gsalazar has joined #rust-embedded
<re_irc> <chmanie> I am writing a driver for a configurable adc/dac and I would like to employ typestates, just like in the HALs. Sadly it doesn't seem to be easy as I only have one SPI instance that I wouldn't be able to share between ports. Is there a way to do this without drifting off into unsafe territory and reimplementing a lot of the SPI functionality? I really would like the driver to be portable
<re_irc> <James Munns> Any examples of what kind of state you're trying to represent?
<re_irc> <dirbaio> you can share the SPI with RefCell or shared_bus
<re_irc> <dirbaio> the ADC ports will be "Port<'a>" isntead of just "Port" though
<re_irc> <dirbaio> you can share the SPI with RefCell or shared_bus, between all theports
<re_irc> <dirbaio> you can share the SPI with RefCell or shared_bus, between all the adc ports
<re_irc> <James Munns> Ideally, that gets abstracted away in the "T: spi::Transfer" bound or whatever tho
<re_irc> <James Munns> not sure what chmanie is trying to represent in type state tho
<re_irc> <chmanie> James yeah, the chip basically allows for configuration of the individual ports that then influence their capabilities. So I'd have one type (struct) per mode with different methods
<re_irc> <James Munns> Yeah! Let me write you up a quick example
<re_irc> <chmanie> Thank you!
<re_irc> <chmanie> shared_bus seems promising for one, thanks dirbaio
<re_irc> <chmanie> Even though that seems more targeted to actually sharing the bus between drivers, it might work for my case
<re_irc> <James Munns> so, with this kind of layout, it shouldn't matter WHAT kind of SPI port you use, as long as it impls "embedded_hal::blocking::spi::Transfer", which both a "native" and a "shared bus" SPI impl would do
<re_irc> <James Munns> Lemme know if it doesn't make sense, or if I totally missed the point somewhere :D
<re_irc> <chmanie> It totally does make sense, only maybe I didn't get my point across well. The thing is, I really have 19 individual ports that can have 12 different modes each. In your example it seems to me that it would configure the entire Adc to one mode. Well I have that only 12^19 different Modes for the whole chip :D
<re_irc> <James Munns> ohhhhhhh
<re_irc> <chmanie> I hope that makes sense
<re_irc> <James Munns> yeah... you could use type states for that, but it would get... nasty.
<re_irc> <chmanie> Yeah I thought so :(
<re_irc> <chmanie> But I really appreciate your example, it should be added to the embedded rust typestate docs
<re_irc> <James Munns> and since you'll probably be checking/changing that at runtime, you might be better off with something like:
<re_irc> Normal,
<re_irc> enum Mode {
<re_irc> Turbo,
<re_irc> <dirbaio> allow splitting the Adc into 19 AdcPort structs, then each gets its own typestate
<re_irc> <James Munns> Yeah, that's a good solution too
<re_irc> <James Munns> but like, if you're changing modes at all at runtime (outside of initial setup), you almost certainly want an enum instead of a typestate
<re_irc> <dirbaio> does the API of a port change depending on the mode though? with ADCs usually all you can do is "measure() -> Voltage"
<re_irc> <James Munns> Heh, I wrote most of https://docs.rust-embedded.org/book/static-guarantees/design-contracts.html (or did, at some point), so I was going for something similar :D
<re_irc> <dirbaio> if it doesnt change, then typestates are more trouble than they're worth
<re_irc> <dirbaio> * the API
<re_irc> <chmanie> dirbaio, it's actually a DAC/ADC/GPIO expander thing. MAX11300
<re_irc> <dirbaio> ahhh, makes sense then 👍️
<re_irc> <chmanie> I wanted to split it up into 20 (sorry, it's 20) structs using typestates but then I get back to the original question. How could I share the SPI instance between all of them? Is that where RefCell or the shared_bus come in?
<re_irc> <James Munns> yeah, exactly!
<re_irc> <dirbaio> yup!
<re_irc> <James Munns> shared_bus lets you take one "T: Transfer", and split it into many handles that all implement "T: Transfer" (with various sharing schemes)
<re_irc> <chmanie> Okay, cool. I'll try my luck. If it's bad, I'll just do runtime checks (even though I like the typestate programming a lot)
<re_irc> <James Munns> As someone who helped push/document typestate programming a lot: It is a _very_ cool tool, but with _very_ sharp edges
<re_irc> <chmanie> Haha
<re_irc> <James Munns> like, you almost always want a "runtime checked" version to fall back on
<re_irc> <James Munns> e.g. for something like, "depending on a user command, switch this GPIO between input and output mode"
<re_irc> <dirbaio> also, often you need to share the SPI bus _and_ some other data
<re_irc> in that case you can share a "&RefCell<AdcState>" instead, where that struct contains both: "struct AdcState<T: Transfer>{ spi: T, shared_data: u8 }"
<re_irc> <James Munns> typestate is AWESOME for static configuration, but AWFUL if you ever need to dynamically change anything
<re_irc> <chmanie> Yeah, the chip for example also allows for changing modes on the fly. That would mean I'd need to cover all state transitions. Maybe this is a bit too much for now :)
<re_irc> <James Munns> it's less about covering all the transitions. that's _relatively_ easy.
<re_irc> <James Munns> the hard part is: if your user wants to switch at run time, they HAVE to use something like:
<re_irc> Dac(AdcDac<..., DAC>),
<re_irc> enum DacOrAdc {
<re_irc> Adc(AdcDac<..., ADC>),
<re_irc> }
<re_irc> <James Munns> and re-implement pass-through methods that match on every case they ever want to use it
<re_irc> <dirbaio> the dreaded typestate enum spaghetti 🍝
<re_irc> <chmanie> Ooof
<re_irc> <James Munns> Which to be fair, is probably roughly the same actual cost as runtime checking (e.g. asserting mode is correct before using the ".get_voltage()" ADC method, for example), but is much less intuitive
<re_irc> <James Munns> it's sort of a hard game to play though. Type state is the best way to elide all runtime checks, but honestly sometimes you want to do stuff at runtime
<re_irc> <James Munns> The best pattern I've found is to add ANOTHER typestate, like "AdcDac<..., RUNTIME>", which you can treat as whatever, and has all the runtime checks in it
<re_irc> <dirbaio> if you have two modes which are "Adc" and "TurboAdc" whose ".get_voltage()" would otherwise be the same, the compiler will still duplicate all the code
<re_irc> <chmanie> Hmm, that's interesting
<re_irc> <dirbaio> all the "AdcDac" fns get duplicated
<re_irc> <James Munns> Yeah, that's the other catch, though you can work around that (by having inner "unchecked" methods that both variants call)
<re_irc> <dirbaio> +for each state
<re_irc> <James Munns> Anyway, it's definitely worth giving it a try! But it's good to know that benefits come with different costs (which you may or may not care about)
<re_irc> <chmanie> This has been very educational, thanks you two! I'll try to see how it looks (and start with just a few modes in the beginning). It'll be good training nevertheless
<re_irc> <James Munns> chmanie make sure you come back and let us know what you learned! Or even write a blog post about it! I think there's room for a lot more discussion of the options and tradeoffs here, even if you decide not to use type states deeply or at all!