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
starblue has quit [Ping timeout: 246 seconds]
starblue has joined #rust-embedded
crabbedhaloablut has quit [Ping timeout: 258 seconds]
crabbedhaloablut has joined #rust-embedded
emerent_ has joined #rust-embedded
emerent has quit [Killed (erbium.libera.chat (Nickname regained by services))]
emerent_ is now known as emerent
causal has quit [Quit: WeeChat 3.6]
crabbedhaloablut has quit [Remote host closed the connection]
dc740 has joined #rust-embedded
causal has joined #rust-embedded
<re_irc> <thebutlah> Several libraries take ownership of an I2C peripheral, but when they error the I2C gets dropped. What is commonly done in practice to reacquire the peripheral in this case without violating safety?
<re_irc> <thebutlah> * A library I am using takes ownership of an I2C peripheral, but in the case of an error on construction, he
<re_irc> <thebutlah> * the
<re_irc> <thebutlah> here is the function in question: https://docs.rs/mpu6050-dmp/latest/mpu6050_dmp/sensor/struct.Mpu6050.html#method.new
<re_irc> <thebutlah> is this a common problem?
dc740 has quit [Remote host closed the connection]
<re_irc> <almindor> thebutlah: If I understand this correctly the i2c gets returned in the error. You can just retry with it, it doesn't get dropped.
<re_irc> <datdenkikniet> I thought so too, but I don't think that holds: `Error<I2c> seems to only exist so that the associated Error type can be used (ref (https://docs.rs/mpu6050-dmp/latest/mpu6050_dmp/error/enum.Error.html)]
<re_irc> <datdenkikniet> * `Error<I2c>"seems to use"I2c` for the associated Error types
<re_irc> <datdenkikniet> * "Error\<I2c>"seems to use"I2c"
<re_irc> <datdenkikniet> * "Error<I2c>"seems
<re_irc> <almindor> ah you're right they just consume the i2c error from it and then fail hmm
<re_irc> <almindor> that's quite an antipattern
<re_irc> <almindor> i think you'd have to unsafe "take" again
<re_irc> <almindor> they should change it so "new" doesn't do any init functionality on its own so you can deconstruct if needed. The only reason "new" has an error case here is because they call "disable_sleep" on it which can fail on a register read
<re_irc> <datdenkikniet> Agreed, and if it's 100% necessary to get it out of sleep some type-state would solve that problem
<re_irc> <datdenkikniet> An alternative solution could be to simply pass an "&mut <your peripheral>", which likely also implement the traits if "<your peripheral>" does. May get a bit clumsy with lifetimes then, though
<re_irc> <datdenkikniet> Agreed, and if it's 100% necessary to get it out of sleep before doing other things some type-state would solve that problem
<re_irc> <datdenkikniet> An alternative solution with the current API could be to simply pass an "&mut <your peripheral>", which likely also implement the traits if "<your peripheral>" does. May get a bit clumsy with lifetimes then, though
<re_irc> <datdenkikniet> I thiink that works, but haven't actually checked
<re_irc> <almindor> yes, it does get clunky and you kinda want the ownership of the i2c device to prevent double use or bus mismatching
<re_irc> <datdenkikniet> `&mut` should give you the same guarantees so long as the instance that owns the i2c borrow exists, but definitly easier with an owned i2c instance
<re_irc> <almindor> in general I think any of the "peripherals" should be consumed by drivers in a way that: 1. constructs the driver with no errors and no init 2. allows "release(self) -> (peripheral1, peripheralX)" for reuse
<re_irc> <almindor> this way you never get hampered by the ownership limitations and at the same time if something does go wrong runtime you can deconstruct the driver and reuse the peripheral however you need
<re_irc> <almindor> this should be good enough in combination with proper embedded-hal bus implementations (spi/i2c) which are coming in v1
<re_irc> <datdenkikniet> Agreed, the bit I wrote was only to attempt to work with/around the current API
<re_irc> <thebutlah> almindor: I don't think a second "take()" is the solution, because other peripherals are still being used. Also, I don't think the peripherals will reappear after being dropped - once dropped, they are dropped for good unless I do some shenanigans with "transmute"
<re_irc> <thebutlah> I was thinking instead to change the "new" function:
<re_irc> <thebutlah> It would return an "Result<Self, InitError<I>>"
<re_irc> <almindor> the peripherals are there of course, there's an unsafe version of take which can be invoked multiple times
<re_irc> <almindor> in the end the peripherals are just pointers to dma registers
<re_irc> <almindor> if code can be fixed on the driver then by all means of course, I meant it as a recourse in case you're stuck with this
<re_irc> <thebutlah> almindor: oh true, there is "unsafe fn steal()"
<re_irc> <thebutlah> /// Error during initialization of sensor. Wraps [`Error`].
<re_irc> pub struct InitError<I2c>
<re_irc> where
<re_irc> I2c: WriteRead + Write,
<re_irc> <almindor> the whole ownership model that HAL crates use is strictly speaking "virtual". In the end each peripheral is just a pointer to some memory register address somewhere, but then we're entering C-level footgun territory
<re_irc> <thebutlah> does this seem reasonable? Or is it generally preferred to leave the driver just have an "is_initialized" field
<re_irc> <thebutlah> I feel like the correct way _is_ to return the peripheral in the error variant