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
<JamesMunns[m]> then you could look at integrating ekv or sequential-storage, using your second bank as a backing storage?
<dirbaio[m]> stm32h743 has humongous 128kb flash sectors
<RockBoynton[m]> yes, I have been, ekv seems to only store bytes, and sequential-storage is only async, so I will have to implement embedded-storage-async for the stm32h7xx-hal's flash peripheral
<RockBoynton[m]> but I think sequential-storage can actually store structured rust data
<dirbaio[m]> > ekv seems to only store bytes
<dirbaio[m]> what do you mean?
<JamesMunns[m]> you'd typically pick a serializing format (like postcard or json or something), and write that "as bytes" to the storage
<dirbaio[m]> you can always serialize/deserialize to bytes with something like postcard yes
<JamesMunns[m]> Rust doesn't have a stable layout, so you can't generally just memcpy structs to flash and back
<dirbaio[m]> that's what sequential-storage is doing under the hood anyway
<JamesMunns[m]> (or very carefully write it with repr(c) structs, or your own direct serialization formats)
<dirbaio[m]> * sequential-storage is serializing your stuff under the hood anyway
<RockBoynton[m]> with serializing though, if I ever want to change a value of the config, I will have to rewrite the entire thing, no?
<JamesMunns[m]> with flash you generally need to erase the whole sector before writing anyway
<dirbaio[m]> if you're serializing the entire struct yes. if you're storing each value as a separate key in the key/value storage then no, you just change that key.
<JamesMunns[m]> flash is written by turning 1 bits into 0 bits. The only way to make them 1s again is by erasing the whole sector.
<RockBoynton[m]> This is quite a bit of data we are talking about here, on the order of 500 KB, so it definitely spans more than a few sectors, even for the stm embedded flash
<JamesMunns[m]> so what you'd like to do is have the 500KiB in place, and be able to change a few bytes in the middle, say from 1, 2, 3, 4 to 10, 11, 12, 13; without rewriting the whole thing?
<RockBoynton[m]> yes, with the understanding that it may have to rewrite more than that due to the physics limitations of NOR flash, but I don't want the application code to care about that if possible
<JamesMunns[m]> I don't think there are any libraries that make that Just Work today. and as dirbaio said, with 128K pages, you need to read that all into ram, change it, erase the page, then write it all back
<dirbaio[m]> and if device powers off in the middle of it, data is gone :D
<JamesMunns[m]> A different approach is to use ekv or s-s, and instead of one big 500K struct, have 100 or something much smaller fields
<JamesMunns[m]> then you can overwite a single field in an append-structured log
<RockBoynton[m]> with something like sequential-storage, I should be able to update a key's value and it will handle doing the minimal set of read/modify/write?
<RockBoynton[m]> the data is essentially a 2d array if that helps. I'm still trying to figure out how to best represent that most efficiently due to the physical and ergonomic limitations of storing things in a nonvolatile manner
<JamesMunns[m]> honestly, it sort of depends on your access patterns
<JamesMunns[m]> like, how much you need to load at once, how much you can afford to read/write at once, etc.
<RockBoynton[m]> I need to access the "table" basically as a for loop over the rows, then access some fields of the table to do some calculations
<RockBoynton[m]> but I will access it all at once during the actual use of it in the code and won't modify it in code logic, but this table needs to be read/written to flash in a serial interface as well
<JamesMunns[m]> Do you write it in the loop too? Or only occasionally, like writing params?
<RockBoynton[m]> no, only reading in the loop
<RockBoynton[m]> the only modification comes when we get a command over the serial interface to change something in the table (which should be rare)
<JamesMunns[m]> could be easiest to just have an A/B side, and some kind of counter to decide which is the newest. This is like a very coarse version of what sequential storage does
<JamesMunns[m]> so at boot, see which one has a valid CRC AND has the highest sequence number. pick that as primary, and the other one as secondary
<JamesMunns[m]> when you get a command, erase the secondary, write it completely, use the next sequence number, finally write the crc
<JamesMunns[m]> that way you always have 1 or 2 valid ones, and you pick which to use based on the highest sequence number
<JamesMunns[m]> you can use a u32 sequence number and not worry about rollovers because your flash won't last 4 billion erases
<RockBoynton[m]> is there a downside to just using sequential-storage? where the key is the row index and the value is the column? Or even the key is the (row, col) tuple and the value is the actual value?
<JamesMunns[m]> Could also work!
<JamesMunns[m]> depends on whether you can pay for paging in all the values you need in your loop
<RockBoynton[m]> well, I can just read them all into a 2d array (what I actually want) in RAM at bootup, right? Then if it changes, I can change it both places
sroemer has joined #rust-embedded
k86td has joined #rust-embedded
k86td has quit [Remote host closed the connection]
Foxyloxy has quit [Read error: Connection reset by peer]
Foxyloxy has joined #rust-embedded
PLUGLIFEDISTRO[m has joined #rust-embedded
<Darius> fucking spammers
rainingmessages has quit [Quit: bye]
Mattia[m] has quit [Quit: Idle timeout reached: 172800s]
sroemer has quit [Ping timeout: 252 seconds]
PLUGLIFEDISTRO[m has left #rust-embedded [#rust-embedded]
sroemer has joined #rust-embedded
sroemer has quit [Ping timeout: 248 seconds]
vollbrecht[m] has quit [Quit: Idle timeout reached: 172800s]
cinemaSundays has joined #rust-embedded
haobogu[m] has quit [Quit: Idle timeout reached: 172800s]
ivmarkov[m] has quit [Quit: Idle timeout reached: 172800s]
diondokter[m] has quit [Quit: Idle timeout reached: 172800s]
<TomB[m]> <JamesMunns[m]> "It strikes me as "what if you..." <- Right, like MMU at a pointer level kind of thing seemingly? So now every pointer I guess is double the size (on small devices this seems like a bad trade?), but I guess if you have untrusted code you want to try and put in a hardware sandbox maybe its ok
<TomB[m]> <JamesMunns[m]> "so what you'd like to do is have..." <- FeRAM is nicer for this sort of thing in all likelihood
<TomB[m]> * all likelihood, but the cost... 🤯
<TomB[m]> * all likelihood, but the cost... 🤯 Edit: And I see its only occasional updates, so nevermind
<dinkelhacker> Hey guys, I have a general rust question. If I have a struct that contains an array of structs and i need mutable references to individual elements of the array... what is the idiomatic way to avoid the multiple mutable borrow dilemma?
ryan-summers[m] has joined #rust-embedded
diondokter[m] has joined #rust-embedded
<diondokter[m]> dinkelhacker: That's hard... If it's not too many of them and not generic, you could destructure them
<ryan-summers[m]> FYI you can mutable-borrow-destructuring using the `let Foo { x: x0, y: y0} = &mut foo;`
<diondokter[m]> You could also look at the various split functions that the slice type has
spikespaz[m] has joined #rust-embedded
<spikespaz[m]> I have 255 command bytes which are basically opcodes for the PMBus protocol. These commands are defined on Table 31 in Appendix I on page 112 of [this document](https://pmbus.org/wp-content/uploads/2022/01/PMBus-Specification-Rev-1-3-1-Part-II-20150313.pdf)
<spikespaz[m]> Should these commands be in an enum as `#[repr(u8)]` or should they be constants?
<diondokter[m]> I always prefer an enum over constants
<dinkelhacker> diondokter[m]: The problem is that I can't access the slice directly. What i get is a reference to a trait objects that has methods to give me mutable references to the elements. Reason for that is that the actual struct is generic over the number of elements it will take.
<diondokter[m]> dinkelhacker: Yeah that's gonna be hard...
<diondokter[m]> Easiest, but ugly, solution would be to put all elements in mutexes or refcells. That way you don't need to hand out mutable references
<dinkelhacker> Well I don't want to lock each element but what about an array of UnsafeCell ?
<dinkelhacker> And then put the whole struct inside a mutex
<dinkelhacker> Or in my cas the reference to the trait object
<diondokter[m]> If you're super careful that could work
<dinkelhacker> I know that the underlying thing (which is static by the way) would only ever be accessed through the Mutex.
<dinkelhacker> or what did you refer to when you said I must be careful?
henrik_alser[m] has quit [Quit: Idle timeout reached: 172800s]
<diondokter[m]> <dinkelhacker> "or what did you refer to when..." <- You may only have one mutable reference to an object at a time. As long as you can guarantee that, you're good. (Among other things)
<spikespaz[m]> <diondokter[m]> "I always prefer an enum over..." <- For what reason
<diondokter[m]> spikespaz[m]: Keeps all options together. An API asking for a u8 is very unclear. But when it asks for an enum, I immediately know all the options I can give
i509vcb[m] has quit [Quit: Idle timeout reached: 172800s]
Henk[m] has quit [Quit: Idle timeout reached: 172800s]
<spikespaz[m]> But you can't give an arbitrary command. The payloads are different sizes, some commands are not write, some are not read. In no circumstance should a function, at the level of a PMBus abstraction, take any Command.
mabez[m] has quit [Quit: Idle timeout reached: 172800s]
danielb[m] has quit [Quit: Idle timeout reached: 172800s]
<diondokter[m]> <spikespaz[m]> "But you can't give an arbitrary..." <- Maybe take a look at my project: https://github.com/diondokter/device-driver
<diondokter[m]> With it you can pretty easily create a nice easy to use command interface
rmsyn[m] has quit [Quit: Idle timeout reached: 172800s]
cinemaSundays has quit [Quit: Connection closed for inactivity]
<spikespaz[m]> Under no circumstance should there be a function that takes an arbitrary `Command`. There is always a function that dispatches the command and wraps it with behavior. There is a contract that each of these commands is used in a particular manner, none of them are to be treated in the same manner.
<spikespaz[m]> The `pmbus` crate defines functions which use these command codes according to spec, and then a manufacturer crate can provide an extension trait that *adds* command functions. But generally, a `Command` enum is not useful.
adamgreig[m] has quit [Quit: Idle timeout reached: 172800s]
bartmassey[m] has quit [Quit: Idle timeout reached: 172800s]
i509vcb[m] has joined #rust-embedded
<i509vcb[m]> <diondokter[m]> "Maybe take a look at my project:..." <- > <@diondokter:matrix.org> Maybe take a look at my project: https://github.com/diondokter/device-driver
<i509vcb[m]> > With it you can pretty easily create a nice easy to use command interface
<i509vcb[m]> Trying to implement nrf70 on this would be interesting but that's a huge project lol
<diondokter[m]> spikespaz[m]: > <@spikespaz:envs.net> Under no circumstance should there be a function that takes an arbitrary `Command`. There is always a function that dispatches the command and wraps it with behavior.... (full message at <https://catircservices.org/_irc/v1/media/download/ASL67c0fZM1eH1tVuE5bPm3ma1rbKsK9K3q9mITlLCgGQ-FvzJxAOF5T3-zoiRAtaEWmjmULjU2uiy5uQw6LIvC_8AAAAAAAAGNhdGlyY3NlcnZpY2VzLm9yZy9mckhHRkdnWFh3TkFCWnFnQVh3aGZpaXQ>)
<diondokter[m]> i509vcb[m]: Ha, could be cool!
TitusRwantare[m] has joined #rust-embedded
<TitusRwantare[m]> spikespaz: what pmbus crate are you referencing?
<i509vcb[m]> Although for nrf70 I'm probably going to have to parse headers and generate structs that are not painful to use from Rust
<diondokter[m]> If you can generate the yaml or json it doesn't have to be that much work
<spikespaz[m]> TitusRwantare[m]: The one that I'm writing for my employer. He wants the commands to be an enum, and I am saying under no allowable circumstance is that useful.
<i509vcb[m]> diondokter[m]: The annoying part is dynamically sized structs
<diondokter[m]> i509vcb[m]: Ah right... Yeah my toolkit doesn't model that, at least not right now
<diondokter[m]> spikespaz[m]: You probably want a dispatch function per command from the sounds of it
<TitusRwantare[m]> I stuck the PMBus commands in an enum here:(warning: not rust) https://gitlab.com/qemu-project/qemu/-/blame/master/include/hw/i2c/pmbus_device.h?ref_type=heads#L15
<TitusRwantare[m]> and the oxide pmbus crate similarly uses a big ron file with all the commands.
<spikespaz[m]> diondokter[m]: That's what we have. I made that decision already, And because of that, an enum is useless.
hmw has quit [Ping timeout: 252 seconds]
hmw has joined #rust-embedded