<i509vcb[m]>
Unfortunately now I need to clean up some more SVD extracted stuff...
m5zs7k has quit [Ping timeout: 276 seconds]
m5zs7k has joined #rust-embedded
emerent has quit [Ping timeout: 272 seconds]
emerent_ has joined #rust-embedded
emerent_ is now known as emerent
merayen has quit [Quit: leaving]
vollbrecht[m] has joined #rust-embedded
<vollbrecht[m]>
<takkaryx[m]> "jamesmunns: the bot seems to..." <- it seams that the bot only banned the user but did not delete the messages? E.g they are still in my feed James Munns dirbaio therealprof
gaivs[m] has quit [Quit: Idle timeout reached: 172800s]
<vollbrecht[m]>
<vollbrecht[m]> "it seams that the bot only..." <- cc: japaric ithinuel
<dirbaio[m]>
You have to modify the lib to add something like `read_uninit(&mut [MaybeUninit<u8>] `)`
<dirbaio[m]>
s/`//
<diondokter[m]>
RobertJrdens[m]: You can use nightly to build core yourself with the build-std flag
<sourcebox[m]>
My USB code does a lot of data copying which is not really that nice.
<dirbaio[m]>
Maybe you can allocate the buffer once and reuse it for all read operations, this way you will only do one init at boot and perf should be the same as with MaybeIninit
<dirbaio[m]>
s/MaybeIninit/MaybeUninit /
<sourcebox[m]>
Yes, that's also an option.
<sourcebox[m]>
I would also like to have a look if I can use embassy_sync::zerocopy_channel instead of the regular one, but I really don't understand how to use it. Are there some examples?
<sourcebox[m]>
Does it even contain a buffer?
<sourcebox[m]>
It's described as "zero-copy queue", so there must be a buffer.
<thejpster[m]>
<RobertJrdens[m]> "> <@thejpster:matrix.org> When..." <- There’s very few out there so basically whatever Digikey will sell you.
<sourcebox[m]>
Ok, I understand. You must provide the buffer yourself.
<thejpster[m]>
Farnell have 25 of the Renesas RA8M1 dev kit in stock. It’s a Cortex-M85. But you’re on your own with Rust drivers.
<AlexandrosLiarok>
I have been experimenting a bit with serde_brief and I really like it!
<JamesMunns[m]>
It looked well written, and the author also took the time to write up a wire spec as well, which was nice!
<AlexandrosLiarok>
you can just slap a derive(Serialize/Deserialize), it uses varint encoding for everything, and it also has an indices option which uses implicit per-level indices instead of the field names.
<JamesMunns[m]>
I'm guessing that requires that you never reorder items? I know there's also a more verbose "named" version as well
<AlexandrosLiarok>
yea I guess, It is not a huge deal you just need to be aware of it. And works nicely with forwards-backwards compatibility because it can just ignore unknown fields, and you can also slap a serde(default="...") to a new field.
<AlexandrosLiarok>
can you elaborate on the verbose named version ?
<JamesMunns[m]>
gotcha, so sending "new data" to an "old version" might still give troubles?
<AlexandrosLiarok>
no it should be okay because it can ignore unknown fields.
<JamesMunns[m]>
AlexandrosLiarok: I just saw this in the readme:
<JamesMunns[m]>
> By default, structs' field names and enums' variant names are encoded as strings. This can be configured to be encoded as unsigned integers of their indices instead. However, this has compatibility implications and some serde features do not work with the index representation. See the format specification for more info.
<AlexandrosLiarok>
yea it doesn't work if you use some serde enum representation variants.
<AlexandrosLiarok>
but I rarely use them myself.
<AlexandrosLiarok>
main footgun is switching enum variants around and adding fields midway.
<AlexandrosLiarok>
yea I am using with_indices right now.
<AlexandrosLiarok>
s/with_indices/`use_indices`/
<AlexandrosLiarok>
otherwise it falls back to disambiguating fields with full strings.
<AlexandrosLiarok>
* disambiguating fields/variants with
<AlexandrosLiarok>
there is no good solution for this unless you go the protobuf route and explicitely add id tags to all fields and variants.
<AlexandrosLiarok>
s//`/, s//`/, s/and variants//
<JamesMunns[m]>
It would be cool to see a side-by-side of CBOR/Postcard/Brief. Glad to see more options!
<AlexandrosLiarok>
main usecase for me is adding fields and make the new messages compatible with old versions.
<AlexandrosLiarok>
for this I think some kind of field is required on the wire format or the schema.
<AlexandrosLiarok>
* of field id is required
<JamesMunns[m]>
yeah, I know cbor encodes some kind of type id, and maybe a tag id for fields? the idea is that it should be as flexible as json
chrysn[m] has joined #rust-embedded
<chrysn[m]>
CBOR doesn't so much make statements about compatibility than just give options. Two typical ways to store things with fields are arrays (if you know that the same things are always in) and dicts. In an interchange format, you usually pick one, but then still have to decide whether a longer array or an unknown key in a dict means that it's an error, or whether it may be ignored by older receivers.
<chrysn[m]>
A common thing to do is to use numbers as dict keys, and then some convention like "positive numbers are mandatory to understand, negative may be ignored", but that's a convention a format may opt into.
<chrysn[m]>
I've rarely seen tags around fields, those are typically used either to tag a top-level object ("This is a COSE signed item"), or to give some more flexibility in items (eg. "this value is an IP address", which is convenient either when the key is not strict in types, or to disamiguate it from other types of identifiers that could be used in the same place).
<chrysn[m]>
<JamesMunns[m]> "It would be cool to see a side-..." <- Such comparisons work best if each format has someone tuning their implementations, happy to join the fray :-)
<JamesMunns[m]>
Gotcha! I wasn't necessarily going for perf/size comparisons, mostly just "this is what the data looks like on the wire" comparisons. Good to know re: cbor tho!
<chrysn[m]>
So was I: Implementations is yet another thing, but there are also multiple ways to express the same data on the wire.
* chrysn[m]
wonders whether he should use the 10 minutes before his next activities start to just sketch a few examples
<JamesMunns[m]>
chrysn[m]: Gotcha, yeah, there's "designing the wire format with knowledge of how it fits best in X format" vs "lol yolo here's some rust structs just encode for me"
<JamesMunns[m]>
i'd definitely be interested in collabing on that comparison tho, at least for cbor and postcard
<JamesMunns[m]>
for example you could sort of wrap many fields in postcard as a dict, and it would "appear" to be somewhat forwards/backwards compatible, but then you'd increase the size of all messages, as you're adding a key/tag to every field
<chrysn[m]>
(heh, it took the first heading; don't get your expectations too high, it's fixed in line 6)
<chrysn[m]>
* first heading as a title; don't
<chrysn[m]>
Happy to extend the examples there to challenges tossed to it -- "now let's assume" style maybe.
<JamesMunns[m]>
chrysn is it typical in rust cbor libraries to have interned string dictionaries?
<chrysn[m]>
no, that's something just being specified, but very quaint, seeing how defmt works
<chrysn[m]>
* no, that's something just being specified, but very convenient [ed: not oldfashioned, so much foa the use of dictionaries], seeing how defmt works
cr1901_ has joined #rust-embedded
<JamesMunns[m]>
Gotcha, yeah, I mean you can manually set it up in any format, but if the library doesn't do that for you, I'm not sure how many people would do it :p
cr1901 has quit [Ping timeout: 252 seconds]
<chrysn[m]>
well it's more frequently used when the format is defined from outside the program, but viewing it that way, yeah makes sense, gotta try that
<JamesMunns[m]>
Yeah, if the format defines it, I would expect it to be an enum that has a display impl or something similar
<chrysn[m]>
mh, the enums probably make little use of it so far as well
FreeKill[m] has joined #rust-embedded
<FreeKill[m]>
This might have no utility to anyone else! But at work, we're looking at evaluating user provided maths expressions. It seemed like an easy thing to get my beak wet with Rust in a way I might actually use...
<FreeKill[m]>
So this is an embedded shunting-yard algorithm implementation for that use-case 😄 It's generic in ways I like, and it was a lot of fun to write. I'm a little dreading having to do it again in C for work :P
jduck[m] has quit [Quit: Idle timeout reached: 172800s]
<FreeKill[m]>
(Ah this is a good way to learn that I don't know how to correctly add docs to a project...)
<JamesMunns[m]>
<FreeKill[m]> "(Ah this is a good way to..." <- you can use `//!` comments at the top of modules, and `///` comments on top of types or functions :D
<FreeKill[m]>
Yooooo who put RustWeek 2025 in my city? 😎
<FreeKill[m]>
Gonna have to submit to run Blood on the Clocktower for the 🦀s
<chrysn[m]>
(By default, it might update or extend that file as part of the build process -- or rules might be to err but make a suggestion to extend, or to just not pack something if it's not in there).
<JamesMunns[m]>
Not sure I follow, I'm kind of going the other direction right now, having data like schemas stored into .text, and letting callers request it, but not sending as part of every message
<JamesMunns[m]>
IMO this makes devices much easier to work with, even if it requires runtime storage
<JamesMunns[m]>
Could do the same with a pack file/dictionary, but I just generally avoid strings entirely
<JamesMunns[m]>
(I realize this is solving a different problem, but that's where my head is at right now)
<chrysn[m]>
The idea is that any context one might need to interpret something (and while CBOR is self describing, packing tables are still to be agreed on). It won't do much good if it's just a single binary that makes up its own packing tables. So even when the strings are interned the first time, the build process can produce a pack.cbor file, which is then used by receivers -- or maybe part of a versioned group of crates where whenever one
<chrysn[m]>
crate adds something, all programs can be rebuilt to udnerstand the packs.
<chrysn[m]>
Interned strings are really just one variation of that -- one could have the same about the mapping between field names and positions in an array, or more structural stuff.
<JamesMunns[m]>
For reference, having requestable schemas powers all of these features, with no sharing of build time generated context:
<JamesMunns[m]>
Re: packing, I wonder if you would be better off just shipping flate + a common/customizable dict
<chrysn[m]>
Ah, requestable features. Convenient and nice. As long as they are served by the program itself, it doesn't even need persisting; I'm more thinking about having the "RPC resource" point to a shared location, so that it may not even need to contain those data (think more like, say, XML DTDs).
<JamesMunns[m]>
JamesMunns[m]: In all of these cases, the server has no apriori knowledge of devices, all encoding/decoding is dynamic based on the reported schemas
<JamesMunns[m]>
chrysn[m]: Yep, all served by the end device
<chrysn[m]>
The good thing about the packing thing is that you don't need to expand it in memory. As long as you have the compressed data and the unpack data in memory (or the unpacked data isn't even relevant to you and they're just a function pointer), you can work on those w/o actually building the full decompressed CBOR.
<JamesMunns[m]>
Basically a standard `.well-known/schemas` endpoint
balbi[m] has quit [Quit: Idle timeout reached: 172800s]
<chrysn[m]>
But yeah, as long as you can just build compact structures, compression is really best avoided in favor of just compact structures. It's when you use a common format that different tools agree on that compression becomes more relevant, as different parties have different things to express. With a one-off schema, no need.
<JamesMunns[m]>
chrysn[m]: That's fair, esp if you have a specific low bandwidth link where the optimization effort is worth it
<JamesMunns[m]>
I'm currently working on problems of convenience, for faster/more flexible iteration, where you aren't shaving the last bytes of flash or bandwidth
<chrysn[m]>
JamesMunns[m]: Gotta relay that to the colleague who is interpreting our CoAP/CBOR stuff in a shell-ish way, he's bound to love it (but may know of it already)
<JamesMunns[m]>
So, trying to sacrifice as little overhead as possible, while still making things very easy to work with, without hand-optimizing every setup
<chrysn[m]>
How big do you schema descriptions get, ballpark?
<JamesMunns[m]>
chrysn[m]: I'm making this all up as I go, unless he's been following me lately :D
<JamesMunns[m]>
But schema on the side means I get the full "transcode to json" capability of cbor, while still using postcard(-rpc) for the actual wire traffic
<JamesMunns[m]>
For the cost of one "tell me about yourself" request on first connect :)
<JamesMunns[m]>
* "transcode to/from json"
<JamesMunns[m]>
chrysn[m]: Couple of dozen to a couple of hundred bytes per endpoint/type, depending on how deeply nested
<chrysn[m]>
Not bad :-)
<JamesMunns[m]>
chrysn[m]: Maybe 1-4k for a reasonable set of endpoints? It would also compress/dedupe really well, but I haven't put effort into it
<JamesMunns[m]>
I'm running on rp2040s with USB, so size is "lol rounding error" atm
<JamesMunns[m]>
I'd care more if I was transiting 6lowpan :D
<JamesMunns[m]>
btw, the next-up feature is building something like pretty-hal-machine on top of the system, so you can use embedded-hal(-async) drivers over the proxied network, so you can plug un an RP2040 (or many), use it's peripherals, but while operating from the desktop, where you can debug. I think this would be useful for people to develop drivers or even just experiment with external sensors, even without writing any firmware :)
<JamesMunns[m]>
There is some round trip latency (1-2ms, likely based on the polling rate of USB-FS), but imo for prototyping, it wont be noticable
danielb[m] has joined #rust-embedded
<danielb[m]>
thin hardware > thin client
<danielb[m]>
this is actually a pretty good idea
<JamesMunns[m]>
I mean it's been possible with pretty-hal-machine for a while, but this makes it much easier to handle multiple devices at once :)
<danielb[m]>
I don't think the picture clicked for me before
<JamesMunns[m]>
yeah, the general point is to allow this for *all* kinds of cards, so if you want to make quick one-offs that do something like "read three thermocouples", you just have to define a couple endpoints for that, throw data at the sdk, and it's easy to manage on the PC side.
<JamesMunns[m]>
but "support all embedded-hal traits" is also pretty easy to do for prototyping too, or for someone that doesn't want to write any firmware at all
<danielb[m]>
But this does require me to write a "HSP" for my particular board, right?
<danielb[m]>
so it's not like the PC side can configure the hardware
<JamesMunns[m]>
whatcha mean?
<JamesMunns[m]>
for the "phm firmware", it'll just work
<JamesMunns[m]>
if you are building something custom, or porting to another board, yeah it'd take some firmware work
<danielb[m]>
yeah I was wondering if it was possible to make something generic, where the PC can set up the peripherals instead of them being hardcoded in the firmware
<danielb[m]>
but that's just me bastardising the idea
<JamesMunns[m]>
ah, yeah, I'll probably just pick a standard set of pins, like 2 dedicated spi ports, 2 dedicated i2c ports, 2 dedicated uart ports, etc.
<JamesMunns[m]>
then you'd have to choose if pins were used for gpio or whatever interface. so the constructor would be failable
<JamesMunns[m]>
if you need more ports, use more MCUs :p
<danielb[m]>
> I'll probably just pick a standard set of pins
<danielb[m]>
Can you elaborate here?
<danielb[m]>
e.g. the ESP32-C6 has a single SPI controller available, can I make it work with this?