<takkaryx[m]>
sorry, I don't actually know how to use it fully, I've just read about it.
<JamesMunns[m]>
weak linkage is probably not likely to work (ever?) for const fns
<JamesMunns[m]>
const fns are execcuted at compile time (by rustc) when used in const position, and weak linkage can take place much later, at linking time (by ldd, gcc-ld)
<JamesMunns[m]>
haobogu might be worth sharing what you're trying to do, and there might be another way to do it? From your example, maybe you're trying to set a "config" parameter in a crate, sort of like a `#define` in C?
<diondokter[m]>
(oh, btw haobogu I'll take another look at your PR this afternoon)
<JamesMunns[m]>
in which case, the typical way to do that is using something like the env! macro to grab an env var at compile time. defmt uses that pattern
<JamesMunns[m]>
You might find better answers elsewhere, but my general answer is: Rust doesn't have inheritance, and you won't be able to generally port patterns from other languages 1:1.
<JamesMunns[m]>
I can share some ways to sort of get closer, but you might hit other bumps along the way if you keep trying to implement inheritance-like patterns
<JamesMunns[m]>
Rust doesn't really have "base classes", and usually focuses more on composition than inheritance. if you maybe have a more specific example of what you're trying to do we might be able to suggest things, but you might also get more non-embedded support in the official discord or zulip, or the rust channel on matrix `#rust:matrix.org` I think?
<JamesMunns[m]>
* I can share some ways to sort of get closer, but you might hit other bumps along the way (that aren't easy or possible to do in Rust) if you keep trying to implement inheritance-like patterns
<JamesMunns[m]>
specifically in Rust, traits only cover methods, not fields. there's no way to require certain fields in traits. you can have get() and set() trait methods, but usually you wouldn't generally do this in idiomatic Rust code.
emerent_ has joined #rust-embedded
emerent is now known as Guest8560
Guest8560 has quit [Killed (osmium.libera.chat (Nickname regained by services))]
emerent_ is now known as emerent
<crespum[m]>
<JamesMunns[m]> "specifically in Rust, traits..." <- Thanks James, this was exactly what I initially tried, but it didn't feel _right_
<JamesMunns[m]>
yeah, it's very possible to get yourself in an "uncanny valley" when trying to do python (or other lang) things in Rust. It's an unsatisfying answer, but sometimes you need to unlearn patterns or learn patterns that are more "natural" in Rust, otherwise you will end up running into some pretty hard to solve challenges.
<crespum[m]>
Have you checked [this](https://matrix.to/#/!BHcierreUuwCMxVqOf:matrix.org/$3WQDmmJ4-wJ-IxudTE0x9uko4HXoy6-_hYBQC8VzG74?via=matrix.org&via=catircservices.org&via=tchncs.de)? To me (not a Rust guru at all) it also doesn't feel idiomatic...
<JamesMunns[m]>
I mean, it's hard to tell what you're trying to do. If you have a concrete example of what you're trying to abstract over, I can comment on that. But there's not a general "how to do inheritance" pattern I can suggest.
<JamesMunns[m]>
normally traits would have methods for the kind of thing you are doing. Like the embedded-hal traits: there are ones for sending data on a UART for example. the idea with traits is to encapsulate the implementation, with a common interface.
<JamesMunns[m]>
* normally traits would have methods for the kind of thing you are doing. Like the embedded-hal traits: there are ones for sending data on a UART for example. the idea with traits is to encapsulate (or abstract over) the implementation, with a common interface.
<crespum[m]>
I understand. I will give it another chance. Thanks again!
<diondokter[m]>
thejpster[m]: I've got one of them! (or a close family of it)
<diondokter[m]>
I tried running Rust on it, but gave up when the SVD didn't generate a nice PAC
<thejpster[m]>
Oh no. Shame.
<thejpster[m]>
What was wrong with the PAC?
<diondokter[m]>
Probably possible though, I just went on with other more interesting things
<diondokter[m]>
It's been a while, so I don't quite remember. Something weird about the interrupts I think and duplicate names of registers
kenny has quit [Quit: WeeChat 4.4.2]
kenny has joined #rust-embedded
cr1901_ has joined #rust-embedded
cr1901 has quit [Ping timeout: 260 seconds]
JamesSizeland[m] has joined #rust-embedded
<JamesSizeland[m]>
Does anyone know why docstrings don't show up properly when parsed and constructed through a proc_macro quote? They seem to appear correctly in the cargo expand but not as hover text on the output struct fields...
<diondokter[m]>
JamesSizeland[m]: Got an example? I've not seen this go wrong tbh
<danielb[m]>
do you emit docstrings as #[doc = ""] or /// foo?
<diondokter[m]>
That too yeah. In device-driver I emit them in the attribute form
<danielb[m]>
I think that's pretty much required when generating docs
<diondokter[m]>
Though with device-driver it usually does pretty well
<diondokter[m]>
Maybe let RA rebuild the build dependencies?
<JamesSizeland[m]>
I think it is an RA issue, at least I don't think I'm doing something wrong here. I've tried opening it on another machine in another editor and still not showing up. I'll see if there's a relevant issue for it.
<JamesSizeland[m]>
thanks!
davidmpye[m] has joined #rust-embedded
<davidmpye[m]>
Does anybody know if you can send things wrapped in an Option over Postcard-rpc? I am thinking of an endpoint to query the embedded device about whether a peripheral is present
<davidmpye[m]>
and it makes sense that you'd return Some(ThePeripheralStruct) or None if it wasnt present
<davidmpye[m]>
Likewise, for an endpoint do do something, can you return a Result
<davidmpye[m]>
*to do
barafael[m] has quit [Quit: Idle timeout reached: 172800s]
cgc17[m] has quit [Quit: Idle timeout reached: 172800s]
<dirbaio[m]>
(I want to see the full asm of core::str::from_utf8, to check my suspicions that it's mega bloated)
bitts[m] has joined #rust-embedded
<bitts[m]>
<davidmpye[m]> "Does anybody know if you can..." <- You can with postcard, so I would think so
<thejpster[m]>
Ferrous Systems needs another Advanced/Rust trainer because we’re very busy. If you like the idea of sharing your love of Embedded Rust with complete strangers, you should apply.
<thejpster[m]>
Especially if you speak German, as I don’t, and that’s a big market for us as you can imagine.
<danielb[m]>
<dirbaio[m]> "(I want to see the full asm of..." <- I don't have an answer for you, you'll sooner get an answer from rustc and --emit-asm, but anything that involves UTF8 validation should be terrible
<davidmpye[m]>
It's an implementation of a vending machine controller on a Pico, with a Pi talking to it. The vmc has a series of optional peripherals and I wanted a sensible way to pass information about them to the Pi
<dirbaio[m]>
ugh core::ffi::c_str::CStr::to_str
<JamesMunns[m]>
davidmpye[m]: is it optional per binary? or detected at runtime?
<danielb[m]>
dirbaio[m]: do you actually need utf8, or can you get away with ascii?
<dirbaio[m]>
yeah I don't need it. it's just places that convert from `&[u8]` to `&str` that do it the safe way because reasons
<dirbaio[m]>
I should just avoid `&str` even for things that are strings in theory
<danielb[m]>
would it work if you loop through string, verify that it's all u8::is_ascii and transmute?
<JamesMunns[m]>
danielb[m]: or `from_utf8_unchecked` :D
<danielb[m]>
JamesMunns[m]: but transmute is so much more arcane
<danielb[m]>
I expected unsafe precondition checks in there
<dirbaio[m]>
welp got rid of the utf8 validation, it went down only 800 bytes
<dirbaio[m]>
but it's really gone now
<dirbaio[m]>
so it wasn't that big
<danielb[m]>
or you're really not done getting rid of it 😅
<davidmpye[m]>
<JamesMunns[m]> "is it optional per binary? or..." <- Detected at runtime over a 9bit serial bus. They are devices like a contactless card reader or a coin acceptor. They might or might not be connected
<davidmpye[m]>
You poll the bus and if they're present they will reply, and then there's an opaque dance to initialise them and find out about them
<davidmpye[m]>
Most of the nuts and bolts at that level is done, it's just tying it together with the pi controlling it that needs to be done
jmogens[m] has joined #rust-embedded
<jmogens[m]>
Hello, using serde_json_core, how can I deserialize the JSON response from https://api-v3.mbta.com/predictions?filter[route]=87&filter[stop]=2576&page[limit]=1 to access the arrival_time value? This JSON response has a list, but the list is guaranteed to only have one element (controlled by the "[limit]=1" URL parameter.
<jmogens[m]>
* Hello, using serde\_json\_core, how can I deserialize the JSON response from https://api-v3.mbta.com/predictions?filter\[route\]=87&filter\[stop\]=2576&page\[limit\]=1 to access the arrival\_time value? This JSON response has a list, but the list is guaranteed to only have one element (controlled by the "page\[limit\]=1" URL parameter.
<JamesMunns[m]>
jmogens[m]: You could use heapless::Vec
<jmogens[m]>
I can give that a try. If I know that there will only be one Data in the Response, is it possible to tell serde_json_core to stop deserializing after the first Data element in the list or to drop other Data items that don't fit in the Response struct (similar to how serde_json_core will drop other values not defined in the Response struct)?
<JamesMunns[m]>
<jmogens[m]> "I can give that a try. If I know..." <- You can use a heapless Vec with capacity 1, deser will fail if you get more.
<danielb[m]>
do you have the serde feature enabled?
<jmogens[m]>
Doh! Didn't see anything about serde in docs.rs, but it's mentioned right in the github README for heapless...
hjeldin__[m] has joined #rust-embedded
<hjeldin__[m]>
so, i find myself in a bit of a pickle: i wrote an spi driver for a display (ili9341), then i implemented the DrawTarget trait from embedded-graphics. it kinda works, but it's slow as hell. i guess the issue is that the trait is sync and using write_blocking, while i'd like to use DMA by using spi.transfer, which is async. i guess my only course of action is to implement a command queue, right? then in the task i can pop the
<hjeldin__[m]>
draw call from the queue and transfer it asynchronously. would this be the right approach or am i missing something?
<dirbaio[m]>
Are you building with --release?
<hjeldin__[m]>
cargo run --release, yep
<dirbaio[m]>
Try setting opt-level to s or z, smaller code is often faster. Try enabling lto as well
<dirbaio[m]>
What microcontroller is it, are you running it at the max freq?
<dirbaio[m]>
And have you tried increasing the spi freq?
<hjeldin__[m]>
it's a stm32l476rg, currently running @ 80Mhz, spi is actually set at 2MHz so i might try increasing it. let me check
<hjeldin__[m]>
huh that made no difference
<danielb[m]>
how much did you increase it to?
<hjeldin__[m]>
set it to 32MHz, it should be noticeable i guess
<danielb[m]>
yeah although still not zippy I think
<danielb[m]>
usually you can try rendering into a framebuffer and DMAing that out separately, but I suspect you don't have the RAM for it
<hjeldin__[m]>
not nearly enough, yeah :D
<dirbaio[m]>
Are you using SpiDevice or SpiBus? The former does a CS toggle for every tramsfer which can make it slower
<dirbaio[m]>
which Hal?
<hjeldin__[m]>
i'm using embassy-stm32, do not know what happens under the hood. i only know that i need to handle the CS myself (in this configuration it's permanently set to low)
<dirbaio[m]>
SpiBus then
<dirbaio[m]>
*
<dirbaio[m]>
Hmm
<danielb[m]>
you can try and implement your own display interface, and buffer more than 64 bytes, but I'm not sure how much that would help
<danielb[m]>
DMA only helps if you buffer more and can swap two buffers, that way you can output data while e-g draws
<danielb[m]>
if you have to still wait for the transfer to complete, it's not a big win
<hjeldin__[m]>
but it might be able to squeeze the transfer between tasks?
<dirbaio[m]>
the "obvious" way to add async (changing spi.blocking_write() to spi.write().await won't help perf
<hjeldin__[m]>
and also embedded-graphics forces me to stay sync'd, so without a decoupled command queue i'm out of luck
<dirbaio[m]>
because when the spi write runs, it starts DMA then suspends, this lets other tasks run in the meantime, but it won't make your display task faster because it still won't parallelize cpu work and dma writes.
<dirbaio[m]>
so you'd need two tasks at least, and coordinating between them
<dirbaio[m]>
also an async context switch is ~100 cycles, and you'd need 2 (one out of your task and one back in) for each transfer. In that time you can send 100*2/80*32/8
<dirbaio[m]>
s//`/, s//` = 10 bytes/
<hjeldin__[m]>
jeez
<dirbaio[m]>
if your transfers are about that size or smaller, it's likely async will be a net perf loss 🥲
<dirbaio[m]>
and I think e-g does make transfers small like that (?)
<danielb[m]>
it depends what you draw, and how the display driver is implemented
<hjeldin__[m]>
yep
<dirbaio[m]>
the magic ideal solution would be like BufferedUart but for SPI 🥲
<dirbaio[m]>
there's a ringbuffer, cpu enqueues bytes, dma sends them
<danielb[m]>
also if the draw call ends up passing an iterator to display-interface, it's getting chopped up into 64-byte transfers
<danielb[m]>
display-interface doesn't provide very sophisticated implementations :)
<dirbaio[m]>
not flushing would allow overlapping some spi and cpu work
<hjeldin__[m]>
let me try
<hjeldin__[m]>
mmm it's still taking ~150ms to transfer 512 bytes
<danielb[m]>
wow that is terrible
<hjeldin__[m]>
i must be doing something wrong
<diondokter[m]>
Lol, are you sure you haven't left an old sleep(10) around :P
<danielb[m]>
sleep(10) // one future miracle perf improvement
<diondokter[m]>
Probably start logging. If you're using defmt you can also see the time of the log. See how long each single transaction takes. Are they all long? Is only one long?
<danielb[m]>
this would be very educational to check with a logic analyzer I think
<danielb[m]>
if write_command sets DC to high, enable_write_data is also just wasted time
<danielb[m]>
that is, fill_rect and draw_raw_iter don't need enable_write_data - won't save you much, but for you, every bit helps I think :D
<danielb[m]>
you should see if you can implement set_window without 5 separate SPI transfers
<danielb[m]>
* you should see if you can implement set_window without 5 separate SPI transfers - i.e., does the display really need DC=data to transfer the data of the commands?