troth has quit [*.net *.split]
sauce has quit [*.net *.split]
<re_irc> <> Otherwise, using RefCell here and there is mostly unnoticed
troth has joined #rust-embedded
<re_irc> <> The problem arises when I want to store all elements (i2c, drivers). Then the values are moved and the references get invalid.
sauce has joined #rust-embedded
<re_irc> <> You can't have the drivers own a `&mut MyI2cBus` either unless you want to recreate each driver every time
Foxyloxy has quit [Ping timeout: 256 seconds]
<re_irc> <> I think thalesfragoso means take the &mut at every driver operation
<re_irc> <> Exactly.
<re_irc> <> Do you mean moving all to the same place ? I.e. self-referential ?
<re_irc> <> Yes.
<re_irc> <> I would really avoid that
<re_irc> <> And `static mut` won't really help with self-referential stuff
<re_irc> <> you can stick the i2c in a [Forever]( which gives you a `&'static` that you can give to all the drivers.
<re_irc> <> Interesting.
Foxyloxy has joined #rust-embedded
<re_irc> <> Pretty much the same thing as a &'a RefCell, since you will probably need a &mut in the end
<re_irc> <> The only plus os that you don't have an 'a everywhere
<re_irc> <> I don't think you can put a RefCell on a forever though
<re_irc> <> ofc you can lol
<re_irc> <> also with refcell you can still run into self-referential problems if you want to put the i2c and the drivers in the same struct
<re_irc> <> Don't you need it to be Sync ?
<re_irc> <> No, it's only accessible by the thread that .put() it there
<re_irc> <> Or no, of course, it only gives it once
<re_irc> <> (unless you steal from it, but that's unsafe)
<re_irc> <> Yeah, not sure why I thought it was a static instead of a static mut, heh
sheb has quit [Ping timeout: 240 seconds]
<re_irc> <> My overall concern is: I will manage to get it work somehow, but it's for sure that I will never understand it again when I have a look at it later.
<re_irc> <> You will also need to impl the i2c traits for `&'a RefCell<impl I2cTraits>`
<re_irc> <> Just run from self-referential, don't try to put everything at the same place if there are references
<re_irc> <> You will never be able to do self-referential with references
<re_irc> <> Doing with raw pointers is possible, but really sad to make it safe
<re_irc> <> pfffft, just use `Pin` and lots and lots of `unsafe` ☠️
<re_irc> <> Yeah, even with Pin, you need raw potatoes
<re_irc> <> Therefore I made the I2C static so I can put references to it.
<re_irc> <> I mean pointers
<re_irc> <> raw potatoes 🤣
<re_irc> <> 🥔
<re_irc> <> Even if it's static, it isn't in the same struct, so not sure why static is helping you
<re_irc> <> At most it gets rid of 'a
<re_irc> <> But I need more than one &mut and that doesn't work,
<re_irc> <> That doesn't work even with static mut, I mean, you can get it, but it's insta-UB
<re_irc> <> Hahaha
<re_irc> <> RefCell is the way you do "shared" &mut access
<re_irc> <> impl<'a, A: AddressMode, T: Write<A>> Write<A> for &'a core::cell::RefCell<T> {
<re_irc> <> ```rust
<re_irc> <> Should we put this in e-h?
<re_irc> <> type Error = T::Error;
<re_irc> <> that might work for i2c, but it'll interact badly with SPI chipselects
<re_irc> <> Yeah, just for i2c I mean
<re_irc> <> I'd say it's better to leave it for external crates then? like shared-bus
<re_irc> <> Or just don't do it
<re_irc> <> static RefCell does also not work because it's not Sync.
<re_irc> <> `static Forever<RefCell<YourSpi>>` does work
<re_irc> <> Is there any solution without external dependencies?
<re_irc> <> `static mut MaybeUninit<RefCell<YourSpi>>` does work too, but you have to use unsafe just once, to init it in main
<re_irc> <> use unsafe to init it and get the `&'static RefCell<YourSpi>`
<re_irc> <> once you've done that, no more unsafe is needed, just share the `&'static RefCell<YourSpi>`
<re_irc> <> you could also make it static with `Box::leak` but that requires alloc
<re_irc> <> if you're using alloc you could also use `Rc<RefCell<YourSpi>>`
<re_irc> <> or maybe copypaste `Forever` into your project, it's tiny
<re_irc> <> I'm about to embark on learning embedded with Rust. I settled on an stm32f407 discovery board and just received it, but saw that the book is being rewritten for microbit v2. Is it worth swapping it out before beginning?
<re_irc> <> the original book is written for an f3 discovery board which won't be a perfect match for your f4 either anyway; having the exact right hardware might make things easier so you don't have to work out how to modify it for what you're running, and the f407 will probably be useful/interesting in the future as it's fairly powerful
<re_irc> <> but, I wouldn't feel obliged to get a micro:bit either, you could try skimming through the books to get a feel for it? the old book is still valid
<re_irc> <> in case you missed it, the new book is previewable on while we finish reviewing/merging
<re_irc> <> thanks Adam. I think I'll try and power through it to get the f407 up and running with the examples or whatever I can make as an equivalent given different peripherals
<re_irc> <> the stmf407 is a super classic microcontroller and the stm32f4xx-hal ( has a lot of examples for using it
<re_irc> <> I just saw that - looks like a great board with fun examples for learning ;)
<re_irc> <> most of those should be pretty easy to get running on yours. if it has the same LCD as the F413, maybe this graphical example will just work too...
<re_irc> <> Oh nice! Thanks, I'll refer to these, too. Thanks for the help
sheb has joined #rust-embedded
sheb has quit [Remote host closed the connection]
sheb has joined #rust-embedded
<re_irc> <> This was announced today; might be interesting to folks here: The folks at Oxide are building out a new embedded OS framework and debugging system with some unique ideas
<re_irc> <> I look forward to giving it a try if I do something complicated enough
<re_irc> <> My current projects aren't... ambitious? enough to warrant any sort of OS beyond what you can do with RTIC, for example
<re_irc> <> I was actually going to give a shot at getting it running on an STM32F401 blackpill board. I've been using RTIC so far and I'm curious to see how things map over
<re_irc> <> I'm curious to see examples etc
<re_irc> <> I think these could qualify as examples:
<re_irc> <> also, fwiw they have a #hubris slack channel at that was shared at the Open Source Firmware Conference today
<re_irc> <> Would it be easier to move resources into interrupts if they were represented using closures?
<re_irc> <> that's kinda what does
<re_irc> <> Oops, the closure needs to be `Send`, not `Sync`. Still works tho
<re_irc> <> you could do a simpler version without the "scope" thing
<re_irc> <> I think you'd need `feature(type_alias_impl_trait)` and maybe some macro magic to store the closure in a `static` though
<re_irc> <> is it UB to transmute between `[u8; 16]` and `GenericArray<u8, U16>`?
<re_irc> <> and between `&mut [u8; 16]` and `&mut GenericArray<u8, U16>`?
<re_irc> <> AFAIK, no, they should be guaranteed to be the same
<re_irc> <> I think I used to do that in bbqueue
<re_irc> <> first one I believe so, but the second one seems a bit more cursed 🤔
<re_irc> <> though maybe it was inside of a MaybeUninit
<re_irc> <> How come?
<re_irc> <> Though doesn't GenericArray have some "from" methods that do exactly that?
<re_irc> <> They might be hidden behind some cursed trait interace
<re_irc> <> I feel like I've used that before for some of the RustCrypto stuff
<re_irc> <> I haven't found a way to convert between `[u8; 16]` and `GenericArray<u8, U16>` without `.unwrap()` :S
<re_irc> <> they probably get optimized away, but still, ugh
<re_irc> <> Lemme see if I can find where I used it
<re_irc> <> and `.encrypt_block()` needs a `&mut GenericArray<u8, U16>` anyway >_<
<re_irc> <> ```rust
<re_irc> <> fn curse(data: [u8; 16]) -> GenericArray<u8, U16> { unsafe { mem::transmute(data) } }
<re_irc> <> fn uncurse(data: GenericArray<u8, U16>) -> [u8; 16] { unsafe { mem::transmute(data) } }
<re_irc> <> fn curse_ref(data: &[u8; 16]) -> &GenericArray<u8, U16> { unsafe { mem::transmute(data) } }
<re_irc> <> 💀
<re_irc> <> that panics if the slice len is wrong (?)
<re_irc> <> vs with transmute it won't compile
<re_irc> <> Look, no transmute!
<re_irc> <> :|
<re_irc> <> lol.
<re_irc> <> so yeah, looks like transmute is just as sound
<re_irc> <> hehehe yeah, it has to be if they're doing pointer casts like that
<re_irc> <> still, wtf
troth has quit [Ping timeout: 256 seconds]
troth has joined #rust-embedded
<re_irc> <> duh, it does have From impls 🤦‍♂️
<re_irc> <> "look upon my macro-generated field of transmutes, and despair"
<re_irc> <> indeed
troth has quit [Ping timeout: 252 seconds]
troth has joined #rust-embedded
PyroPeter has quit [Ping timeout: 250 seconds]
PyroPeter has joined #rust-embedded
troth has quit [Ping timeout: 245 seconds]
troth has joined #rust-embedded
<re_irc> <> Shouldn't `cargo test` activate `#[cfg(doctest)]`?
creich_ has quit [Quit: Leaving]
creich has joined #rust-embedded
crabbedhaloablut has quit [Ping timeout: 276 seconds]
crabbedhaloablut has joined #rust-embedded
<re_irc> <> Yes: ITM instumentation/extension packet arbitration at least. Making it easy to catch the `cortex_m::iprint("arbitrary message/payload"`" on the host side. This is non-trivial according to the spec.
<re_irc> <> adamgreig: I'm neutral on whether it ends up in the WG or not. I'll maintain it either way.
<re_irc> <> But I'll gladly take the `itm` crate name so that there is no confusion for end-users on what crate to use.
<re_irc> <> What are the downsides to keeping it in the WG? That I need someone else in the cortex-m team to sign off my PRs?
<re_irc> <> I can foresee some changes in the close future (be it to error enum granularity or better function names, more logical iterators, etc) that I'd prefer to release quickly. If the crate were to join the WG it may then be better to wait for the eventual v1.0.0 release, or do so if the crate becomes a somewhat common dependency.
<re_irc> <> At the moment that would hinge on the future popularity of `cargo-rtic-scope` and if some API is added to `probe-rs` that makes the library a hard dependency.
dcz_ has joined #rust-embedded
<re_irc> <> Yes, no self-approval of PRs and all bigger decisions are subject to discussion and potentially voting.
<re_irc> <> (Of course also the WG best practises and requirements as well as the CoC do apply as well)
<re_irc> <> Not trying to sound negative here, just listing the implications. 😅 Depending on where you're standing some or even alll of the above might be viewed as a positive thing. And of course as a WG project is has the full backing of the team and good standing with the upstream Rust project.
dreamcat4 has joined #rust-embedded
<re_irc> <> Best approach from my standpoint would be to replace the `itm` crate for now and keep it out of the WG until it has stabilized a bit. This would be Q1 next year at the earliest. After that we can resume the discussion on whether to move it to the WG.
troth has quit [Ping timeout: 256 seconds]
troth has joined #rust-embedded
<re_irc> <> tmplt: Can you open an RFC for that?
tokomak has joined #rust-embedded
<re_irc> <>
sheb has quit [Quit: Leaving]
troth has quit [Ping timeout: 256 seconds]
<re_irc> <> I'm playing around with this now. I'd like to use a `RefCell<T>` but with static `RefCell<Option<T>>` is required because of the init. Is there a way to avoid that?
troth has joined #rust-embedded
<re_irc> <> You could wrap it in `MaybeUninit` or use const-fn inits
<re_irc> <> I'm trying `MaybeUninit` currently. Still fighting how to use it.
<re_irc> <> lazy_static might also be something to look at?
<re_irc> <> Design goal is to minimize dependencies.
<re_irc> <> ctrl-c, ctrl-v 😅
<re_irc> <> Can I ask why?
<re_irc> <> If I have `MaybeUninit<RefCell<T>>`, how do I get access to the RefCell.
<re_irc> <> I find a lot of people coming from other languages (esp. C and C++) try to do that, but it's a little atypical for Rust. Instead, we try to make sure that re-usable parts are contained and shared in crates.
<re_irc> <> Yes, but I try to avoid to have dependencies of small things that can be done directly in the code by the core library. There is also a security-related part on this.
<re_irc> <> Supply-chain attacks are popular these days.
<re_irc> <> > I try to avoid to have dependencies of small things that can be done directly in the code by the core library
<re_irc> <> Rust's core library is pretty minimal, and especially doesn't try to touch anything related directly to embedded
<re_irc> <> > There is also a security-related part on this
<re_irc> <> That's fair, but Rust packages are also entirely source-based (which means you can audit them), you can pin versions or commit your lock file (so versions never change unless you manually update them), package integrity is checked with SHA-256 sums, stored in the lock file , and dead code is eliminated.
<re_irc> <> Especially for `unsafe` abstractions, I would highly recommend sticking with popular, well-audited crates.
<re_irc> <> but hey, I can't tell you to do or not do something, but sometimes it's useful to re-calibrate expectations when you are in a new environment.
<re_irc> <> I'm sure you've already read this:
<re_irc> <> The essence is that noone will ever be able to audit the whole dependency tree.
<re_irc> <> I've been traumatized by both the Python package index and NPM. It could happen here too!!
<re_irc> <> (James' point about pinning versions and auditing, combined with careful selection of which deps you need mitigates this)
<re_irc> <> Yes, however all of those exploits are prevented by:
<re_irc> <> 1. auditing your dependencies, and don't use ones too big to audit
<re_irc> <> 2. pinning your dependencies
<re_irc> <> Especially in embedded, your tree is FAR less large and complex.
<re_irc> <> So, a key way to deal with this is to only use deps that have a small number of sub-deps
<re_irc> <> You get into trouble when *your dependencies have too many dependencies*
<re_irc> <> So, building a dependency graph only a few layers deep is fine
<re_irc> <> Nevertheless reducing the number of dependecies is something I don't regard as a mistake.
<re_irc> <> But if one of the branches gets too long, you get into trouble
<re_irc> <> Take my advice for what you paid for it, but I think you will find you'll hit diminishing returns if you eschew dependencies entirely.
<re_irc> <> Anyway, good luck with your exploration. Just my $0.02.
<re_irc> <> It's a tradeoff, but I'm more of sourcebox's mindset
<re_irc> <> Like I said, you're welcome to do as you like. I'm not a consultant anymore, so who am I to be advising anyway :)
<re_irc> <> This is all heavily in subjectivity land
<re_irc> <> Ultimately there is no right answer!
<re_irc> <> Ie, I'm not "anti-dependency" or anything, but I agree with sourcebox that you should carefully consider if you need each dep
<re_irc> <> And recognize that the downsides to adding deps are subtle, and emergent as you add more
<re_irc> <> The problem is, that the Rust package management is of course built with the best intentions in mind, but you can't imagine how creative people can get when they see a chance to abuse something for profit.
<re_irc> <> Security concerns aside, they can add headaches with changing APIs, DSLs, and mutual incompatibility
<re_irc> <> And the workarounds for their limitations might be comparable to or greater than not using them
<re_irc> <> Technically you can hide exploits in the standard library as well, and you can't even pin the version of that.
<re_irc> <> BTW: the Rust ecosystem is also one of the main reasons I'm trying to get into it. It's only about keeping it reasonable managable.
<re_irc> <> LOL, the discussion reminded me of `cargo-crev`, which intends to help solving the code review issue for dependencies. However, `cargo install cargo-crev` starts with downloading and compiling 439 dependencies :-)
<re_irc> <> I do C++ embedded for a living and try to convince colleagues to have a look into Rust. Dependency hell is of those things that they don't like.
<re_irc> <>
<re_irc> <> Tools like this are really needed and can improve security a lot.
<re_irc> <> But I think with Rust becoming more and more popular there is a limit of what can be reviewed in an aceptable time period.
<re_irc> <> I'm pretty sure developing everything from scratch takes more effort, especially when security is important.
<re_irc> <> There is no need to redo everything from scratch, it's more about reducing dependencies by having the essential parts in fewer crates.
<re_irc> <> E.g. the `num-traits` crate has so many dependents that I'm asking myself if having the stuff in the core library would not make sense.
<re_irc> <> According to 1795 crates use `num-traits`.
<re_irc> <> what do you mean? num-traits literally has a single optional dependency
<re_irc> <> The other way around.
<re_irc> <> oh, dependents, sorry, my bad
<re_irc> <> I promise I can read, most of the time
<re_irc> <> Once something is in the core library, you basically can't make breaking changes to it anymore
<re_irc> <> There's also another aspect: with C++, you basically learn the language, STL is not of much use for embedded anyway. With Rust, you have to learn a lot more in addition to get something running.
<re_irc> <> The only breaking change that `num-traits` has had is adding an `std` feature (which wouldn't be needed if it was in the standard library), but the point remains that they *could* release a new breaking version if they needed to.
<re_irc> <> My personal goal is to be able to get some small project running with Rust during next year. I'm not sure if I manage to do this yet.
<re_irc> <> AdamGrieg told me what a register was a year ago, and now I'm selling stuff
<re_irc> <> This is entirely doable
<re_irc> <> For me, it's currently a bit frustrating and I often think that I'm too stupid for it.
<re_irc> <> One of my main problems is that the architecture I'm used to in C++ does not translate to Rust and I don't find the corresponding alternatives.
<re_irc> <> Feel free to ask Qs etc or post your project requirements
<re_irc> <> Most of the examples I found on the web are quite simple and fall apart when it comes to real world situations.
<re_irc> <> I've noticed the same
<re_irc> <> I think the root cause is the OSS rust embedded community is v small
<re_irc> <> E.g. in C++ I'm used to have class `Board` which is in fact a container for everything that I can access on it, like buttons, LEDs, flash chip.
<re_irc> <> You could make a struct Board if you want. Not the approach I use, but doable
<re_irc> <> This board class in C++ is a static singleton, so there is no problem with referencing the members
<re_irc> <> A common convention with OSS Rust embedded is peripheral structs that handle initialization, config, operations etc using fields and methods
<re_irc> <> You don't have to use that, but it's worth trying
<re_irc> <> The projects I usually work on have a lot of buttons, leds and other stuff, so I think it makes sense to group that.
<re_irc> <> So, you have a variable for each peripheral you use, and these live statically, with some sort of guard like a Mutex or the RTIC framework
<re_irc> <> Would representing the buttons etc as struct fields work?
<re_irc> <> For LEDs, I often put them into an array, so I can iterate over them.
<re_irc> <> Hmm... I haven't used Rust arrays for things beyond numbers
<re_irc> <> But ... I think you could do the same thing here (?)
<re_irc> <> In practice, I usually handle button operations directly as interrupt sources, but that isn't appropriate for all uses
<re_irc> <> E.g. with LEDs, when you have a matrix with 10+ of them and these are used to illuminate buttons, you sometimes want to make them blink. And they should blink in sync, otherwise the user will go crazy.
<re_irc> <> Use a hardware timer for that
<re_irc> <> How you create these abstractions is up to you, and depends on the details of your project
<re_irc> <> We are talking about lots of LEDs and buttons. More than you have timers.
<re_irc> <> Sometimes even using DMA to provide soft pwm for individual brightness control.
<re_irc> <> So, in this case, you might have a state of which buttons are active. Maybe an atomic integer that represents each LED as a bit. Or some abstraction. Then you have a timer ISR that toggles all LEDs marked active when it runs
<re_irc> <> If you are trying to sync the LEDs as you said, you only need/want 1 timer
<re_irc> <> For this I don't use timers and ISRs at all. This is because I reserve these things for the really important parts.
<re_irc> <> Systick then
<re_irc> <> Or pick a MCU with more timers
<re_irc> <> Yes, SysTick-
<re_irc> <> Or cleverly use the timers for multiple things
<re_irc> <> LED blinking is not something that has to be precise, so driving it depending on SysTick is more than enough for this purpose.
<re_irc> <> sourcebox I might suggest you check out Knurling Sessions:
<re_irc> <> they are a guided walk-through of non-trivial projects, from scratch.
<re_irc> <> That looks cool
<re_irc> <> I'd also suggest that if you try to "write C++ in Rust", you are likely to run into an impedance mismatch. We definitely do things differently in Rust! But the way we do things are (generally) pretty well documented, either in code, or in written materials, like
<re_irc> <> James Munns: I already had a quick look into some of your stuff.
<re_irc> <> Hopefully you don't mean my personal stuff, because that's hopelessly complex and undocumented :)
<re_irc> <> Though Ferrous' stuff is generally pretty good!
<re_irc> <> I am aware that trying to write Rust like C++ is not the way to go.
<re_irc> <> My C++ stuff is not the must advanced thing ever. It just works, mainly because the compiler does not do any checks and I'm self-disciplined enough to keep it in a managable state.
<re_irc> <> So I'm trying to find out how to do it better in Rust. This is where I struggle.
<re_irc> <> Besides of trying to get into embedded with Rust, I'm also doing some GUI apps like this:
<re_irc> <> I wrote this big picture overview, with some code examples and links to simple firmware -
<re_irc> <> You are likely already familiar with most of the concepts
<re_irc> <> I have to say that these GUI stuff is way more easy to do than embedded, even with less knowledge.
<re_irc> <> I read this article and found it very good. It is one of the best articles describing the current state.
<re_irc> <> I appreciate the feedback
<re_irc> <> It was the first article I found that I can forward to someone who is interested to know where we currently are.
<re_irc> <> James Munns: As I said, in C++ I usually use a board class with members representing the components on the board. Is this concept reasonable in Rust too?
<re_irc> <> It's reasonable, but generally not as a global singleton
<re_irc> <> Well, not stored at global/static scope
<re_irc> <> but rather created as part of your initialization code, and passed around as necessary
<re_irc> <> Ok, in `main` I do a `Board::take()` like with peripherals.
<re_irc> <> Yeah, something like that!
<re_irc> <> I think the dwm1001 crate does that, let me find you an example
<re_irc> <> Code is
<re_irc> <> ```rust
<re_irc> <> static mut BOARD_TAKEN: bool = false;
<re_irc> <> pub fn take() -> Option<Self> {
<re_irc> <> In general, you would want to use atomics for the tracking variable, or ensure you are using a critical section for that.
<re_irc> <> That code is unsafe because it contains a potential data race.
<re_irc> <> You could have an interrupt call it between line 3 and 7, which would allow you to obtain two copies of the board.
<re_irc> <> But it's called only once at the start of main().
<re_irc> <> Rust doesn't like "it's safe if you hold it right"
<re_irc> <> if it's only called once, you don't need any of the runtime checks
<re_irc> <> i know.
<re_irc> <> In general: mutable statics are something to avoid entirely
<re_irc> <> BTW: this code is taken from some example, I think it was an official one.
<re_irc> <> If you link me to that example, I will fix it.
<re_irc> <> You could however use with a compare and swap to have it be correct, and not require unsafe
<re_irc> <> (assuming you are not using a thumbv6 target, which has no atomics, in which case, you might want the `atomic-polyfill` crate)
<re_irc> <> I don't find the source of it anymore, but this seems to be the least important problem in my code.
<re_irc> <> With this approach, the board variable is not static. This means, that any reference to a member inside is not possible.
<re_irc> <> I mean from inside it.
<re_irc> <> You can have references, just not `'static` references.
<re_irc> <> Do you mean a self-referential struct?
<re_irc> <> Yes.
<re_irc> <> In general, Rust doesn't do self-referential structs, as all types are trivially move-able, which would invalidate the self-reference
<re_irc> <> For the other cases, you have Pin
<re_irc> <> I don't believe Pin allows you to have self-referential structs, either.
<re_irc> <> no but at least you can have pointers and be sure they will be valid
<re_irc> <> sourcebox in general, it can be very useful to "break apart" large structs like that, for exactly this reason.
<re_irc> <> Ok, inside my board class I have an LED as member. This LED needs to have a reference to a driver (shift register). Where should this driver live?
<re_irc> <> I don't agree with this
<re_irc> <> You do you, but I'd go so far to say that mutable statics should be removed from the language.
<re_irc> <> they are almost universally a foot gun
<re_irc> <> I mean, they're necessary to build safe abstractions around... but otherwise, I agree
<re_irc> <> You should almost always use something like UnsafeCell, or something similar that makes it more clear that there will be spooky action at a distance
<re_irc> <> is a good discussion of this topic.
<re_irc> <> I don't know how else you expect to do things like circular DMA
<re_irc> <> I don't agree with removing `static mut`. The proposed alternatives like `RacyCell` are equally ultra-unsafe.
<re_irc> <> At least they properly use UnsafeCell, which makes it clear to the optimizer that it can trust nothing, and is less likely to emit UB from correct-looking unsafe code
<re_irc> <> You might consider having your driver own the shift register, taking a (mutable) reference on actions, or use an abstraction like `shared-bus` to safely share it between all LEDs.
<re_irc> <> `static mut` already has an "implied" UnsafeCell kinda
<re_irc> <> there's literally zero instances where a code using `static mut` is incorrect but the equivalent code using `RacyCell` is correct
<re_irc> <> they're both the same
<re_irc> <> equally wildly unsafe
<re_irc> <> The LED takes something that implements OutputPin, whatever that is. And this thing has to have a mutable reference to the shift register.
<re_irc> <> OutputPin is a trait (like an interface, or more like a Concept in modern C++)
<re_irc> <> So the shift register has to live somewhere. This is where I started some hours ago.
<re_irc> <> sourcebox: you might want to invert your design, create a led driver that wraps the register and pass Led objects to it when you want to do something
<re_irc> <> in this case, leds wouldn't implement OutputPin at all
<re_irc> <> you stick the shift register driver in a `static` like I told you yesterday
<re_irc> <> either using unsafe `static mut`/`UnsafeCell` directly, or using a safe wrapper like `Forever`
<re_irc> <> this gives you a `&static` that you can then use from everywhere without self-referential struct issues
<re_irc> <> I regard it as benefit of using traits that you then can pass anything. If the LED is connected directly to a pin on the MCU or using a shift register doesn't matter.
<re_irc> <> This is what I tried todo before the discussion went into another direction.
<re_irc> <> Currently I have
<re_irc> <> `static mut SHIFT_OUTPUT: MaybeUninit<RefCell<ShiftOutput>> = MaybeUninit::uninit();`
<re_irc> <> But now I'm stuck with the MaybeUninit part.
<re_irc> <> you can unsafely assume_init_mut() it and get back a reference to your RefCell
<re_irc> <> What will happen if the RefCell is still uninitialized? panic?
<re_irc> <> no it's undefined behaviour
<re_irc> <> A tiny bit simpler using MaybeUninit::write:
<re_irc> <> oh, nice
<re_irc> <> Thanks, at least this seems to compile.
<re_irc> <> Overall, I like this solution. With the following code I can setup 2 LEDs, one with direct MCU connection, the other via the shift register:
<re_irc> <> ```rust
<re_irc> <> let led1_pin = gpioa
<re_irc> <> .pa5
<re_irc> <> James Munns: you suggested to use AtomicBool for the BOARD_TAKEN variable. I changed that now. What's the deal with the Ordering options here?
<re_irc> <>
<re_irc> <> Not super intuitive. Same as with C++ if you've used atomics there
<re_irc> <> Isn't bool on Cortex-M atomic anyway?
<re_irc> <> reads and writes are atomic up to 32bits
<re_irc> <> but a read-modify-write is not
<re_irc> <> And AtomicU64 does not exist for Cortex-M.
<re_irc> <> if you want atomic read-modify-write you have to use AtomicBool
<re_irc> <> I only need load() and store()
tokomak has quit [Read error: Connection reset by peer]
<re_irc> <> You can use Acquire and Release as a default for those
<re_irc> <> if you want a TAKEN flag
<re_irc> <> if you only use load/store you can have main thread racing with an interrupt and both may succeed in taking the thing
<re_irc> <> you need the whole "read TAKEN, check it's false, write true" to be atomic
<re_irc> <> Yea. The compare_exchange etc methods help there
<re_irc> <> I see.
<re_irc> <> The intent is you minimize the number of atomic operations for a given task. Ideally 1
<re_irc> <> In practice it can't happen. But since I want to do it correctly...
<re_irc> <> So something else doesn't happen between your load and store etc
<re_irc> <> The atomic stuff is a bit unintuitive, but IMO worth it as a default for global primitives
<re_irc> <> If you are fine with unsafe code (which in general, should be avoided as much as possible), you can always make your initializer unsafe, slap a "SAFETY: only ever call this once" comment on it and be done with it.
<re_irc> <> What about this?
<re_irc> <> ```rust
<re_irc> <> if !BOARD_TAKEN
<re_irc> <> pub fn take() -> Option<Self> {
<re_irc> <> you probably want SeqCst
<re_irc> <> or maybe AcqRel
<re_irc> <> I *think* Relaxed can still race? but not sure
<re_irc> <> or maybe not because it's still atomic
<re_irc> <> much simpler to store(true, Ordering::Relaxed)
<re_irc> <> you only have a false->true transition, not the other way around, so you can keep writing true
<re_irc> <> That looks good.
<re_irc> <> > I *think* Relaxed can still race? but not sure
<re_irc> <> Should be fine in this case. The access itself is still atomic, so no race. But the ordering related to other operations is not defined. So you need stricter ordering if you want to make sure some operations done by another thread are already visible. In this case, all you care about it that exactly one thread enters the protected block, so ordering doesn't matter.
<re_irc> <> Overall, it's important to consider what concurrency problems, (race conditions etc) can occur based on your code. It's not always obvious, and gets tougher with more complex code.
<re_irc> <> Eg what interrupts, cores, DMA actions have access to what items
<re_irc> <> Does anyone know of any eSIM modules, or ever worked with them?
<re_irc> <> Aka eUICC
<re_irc> <> I agree. Had some hard fights with these things in the past ;-)
dcz_ has quit [Ping timeout: 256 seconds]