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
IlPalazzo-ojiisa has quit [Remote host closed the connection]
emerent has quit [Ping timeout: 252 seconds]
emerent has joined #rust-embedded
m5zs7k has quit [Quit: m5zs7k]
m5zs7k has joined #rust-embedded
notgull has quit [Ping timeout: 255 seconds]
notgull has joined #rust-embedded
waveguide[m] has quit [Quit: Idle timeout reached: 172800s]
FlixtheNewbie[m] has quit [Quit: Idle timeout reached: 172800s]
crabbedhaloablut has joined #rust-embedded
Guest7221 has joined #rust-embedded
therealprof[m] has quit [Quit: Idle timeout reached: 172800s]
Guest7221 has left #rust-embedded [Error from remote client]
Guest7221 has joined #rust-embedded
Guest7221 has left #rust-embedded [Error from remote client]
Guest7221 has joined #rust-embedded
lehmrob has joined #rust-embedded
lehmrob has quit [Ping timeout: 255 seconds]
lehmrob has joined #rust-embedded
IlPalazzo-ojiisa has joined #rust-embedded
notgull has quit [Ping timeout: 240 seconds]
notgull has joined #rust-embedded
lehmrob has quit [Ping timeout: 252 seconds]
lehmrob has joined #rust-embedded
dav1d has quit [Quit: Ping timeout (120 seconds)]
dav1d has joined #rust-embedded
corecode has quit [Quit: ZNC - http://znc.in]
corecode_ has joined #rust-embedded
sparky[m] has quit [Quit: Idle timeout reached: 172800s]
lehmrob has quit [Ping timeout: 258 seconds]
<Jonas[m]1> I did some range testing today. Using Embassy + nrf-softcore on an Adafruit Feather nRF52840 Express as a peripheral and a Samsung Galaxy Tab S9 as Android device. I had a working connection when I was about 358 meters away.
<dirbaio[m]> that's a lot :D
<Jonas[m]1> dirbaio[m]: yes, and no hardware is custom.
<dirbaio[m]> line-of-sight and/or rural environment I guess?
<dirbaio[m]> in dense city environment it's much worse
<dirbaio[m]> * much worse ๐Ÿฅฒ
<Jonas[m]1> yes, it was line-of-sight over a lake. But it is still impressive without any custom hardware.
<dirbaio[m]> we're evaluating the nrf21540 at work :P
<dirbaio[m]> if you don't get enough range because you're in a dense city with tons of devices screaming in 2.4ghz, solution is to scream more than them ๐Ÿ‘ฟ
<Jonas[m]1> dirbaio[m]: oh, this is an add-on IC to get better signal strength and sensitivity!? I did not know about that one. Thanks.
<dirbaio[m]> Jonas[m]1: yup! :D
<dirbaio[m]> dirbaio[m]: sadly it's not fully supported by the old softdevice
<dirbaio[m]> dirbaio[m]: it requires enabling rx_en, tx_en pins at the right time to turn on the LNA or PA
<dirbaio[m]> dirbaio[m]: which the SD does support, but not with the right timing :(
<Jonas[m]1> dirbaio[m]: ah, right. So still not easy to use with Rust and Embassy, if I understand you correct :)
<dirbaio[m]> Jonas[m]1: would require making a binding over their new "softdevice controller" lib
<dirbaio[m]> dirbaio[m]: and it's harder because it speaks raw HCI, we'd need to provide our own BLE host stack..
<dirbaio[m]> dirbaio[m]: it's something that needs doing anyway
<dirbaio[m]> dirbaio[m]: because the old softdevice is in "maintenance mode" by nordic
<Jonas[m]1> dirbaio[m]: it would be interesting to have a full Rust BLE stack on nrf chips :)
<dirbaio[m]> Jonas[m]1: yeah
<dirbaio[m]> dirbaio[m]: also it'd be reusable for stm32, rpi pico w, esp32
<dirbaio[m]> dirbaio[m]: there's https://github.com/bjoernQ/bleps
corecode_ is now known as corecode
<Jonas[m]1> dirbaio[m]: oh, interesting.
<Jonas[m]1> It seem to be higher levels of the stack? or is it also Controller?
<dirbaio[m]> Jonas[m]1: Host
<Jonas[m]1> dirbaio[m]: As what I understand, I have only found nrf chips that document the lower levels so it would be possible to write a full Rust stack. Many others does not document the PHY.
<dirbaio[m]> Jonas[m]1: old softdevice is Controller+Host
<dirbaio[m]> new softdevice is just Controller, nwe need our own host
<dirbaio[m]> s/host/Host/
<Jonas[m]1> dirbaio[m]: ah, alright.
<dirbaio[m]> Jonas[m]1: it's possible to write a controller from scratch too
<dirbaio[m]> dirbaio[m]: one attempt, abandoned https://github.com/jonas-schievink/rubble
<Jonas[m]1> dirbaio[m]: yes, at least for nrf ships :=
<dirbaio[m]> dirbaio[m]: that's much MUCH harder to do
<dirbaio[m]> dirbaio[m]: especially if you want low-power and certification
<Jonas[m]1> dirbaio[m]: Right, but I only use it for hobby, no intent for certification or money :)
ilpalazzo-ojiis4 has quit [Quit: Idle timeout reached: 172800s]
raulvt[m] has quit [Quit: Idle timeout reached: 172800s]
nyanko[m] has joined #rust-embedded
<nyanko[m]> question: in embassy (for example) what do interrupt handlers actually look like? or more generally, when some event happens, how does embassy actually know what task it goes to? my understanding of the way interrupts work on most hardware (with vectored interrupts) is that each IRQ can have exactly one handler, but if that's the case, how does embassy allow one to await multiple events that correspond to the same IRQ?
<dirbaio[m]> when a task waits on something, it stores a waker in a global variable
<dirbaio[m]> when the interrupt fires, the handler wakes the waker. this tells the executor that task needs polling again.
<dirbaio[m]> (the HAL registers the handlers for you, with bind_interrupts!)
<dirbaio[m]> when several tasks are waiting on things on the same interrupt, it still works, you just need multiple wakers
<dirbaio[m]> for example uart has a waker for rx and a waker for tx. when the irq fires, the handler checks what happened and wakes the needed wakers
<dirbaio[m]> example:
EEPROMToast[m] has joined #rust-embedded
<EEPROMToast[m]> Who here mixes their rust with a little aluminum powder? ๐Ÿคฃ
<nyanko[m]> <dirbaio[m]> "when a task waits on something..." <- > <@dirbaio:matrix.org> when a task waits on something, it stores a waker in a global variable
<nyanko[m]> > when the interrupt fires, the handler wakes the waker. this tells the executor that task needs polling again.
<nyanko[m]> i see! that makes a lot more sense, thanks.
starblue has joined #rust-embedded
korken89[m] has quit [Quit: Idle timeout reached: 172800s]
rahsayngahn has joined #rust-embedded
rahsayngahn has quit [K-Lined]
korken89[m] has joined #rust-embedded
<korken89[m]> Alright I tested salty a bit more, it's ~3x slower than x25519 from Emil at about the same size
<korken89[m]> Maybe dirbaio is interested in that result :)
<korken89[m]> Hard to beat Emil :D
<dirbaio[m]> told you ๐Ÿ™ƒ
<korken89[m]> Yeah, not doubting you just wanted to know how much faster his impl is :D
<dirbaio[m]> it's mad fast
<dirbaio[m]> salty implements the filed arithmetic in asm, then everything else in Rust
<Lumpio-> Why does it register a waker even when it doesn't return Pending ๐Ÿค”
<dirbaio[m]> s/filed/field/
<dirbaio[m]> emil implements everything in asm, which allows the field arithmetic functions to use a custom ABI that allows passing field elements in registers
<dirbaio[m]> and the main thing in asm too, not sure how much that contributes to speed tho beyond just the custom abi
<korken89[m]> Quite cool
jsolano has quit [Quit: leaving]
jsolano has joined #rust-embedded
<dirbaio[m]> Lumpio-: you have to do it that way, otherwise you can have a race condition deadlock if an interrupt happens at the right moment:... (full message at <https://catircservices.org/_matrix/media/v3/download/catircservices.org/YrcDMqeGBsDOBASgORlwhMri>)
<dirbaio[m]> interrupt didn't wake the waker because it wasn't registered yet, task returns Pending and hangs forever
<Lumpio-> oh neat
<Lumpio-> So the interrupt gets ignored if there is no currently registered waker, and it doesn't store the fact that it happened in case somebody registers one later (or leave the flag on)
<korken89[m]> Talking about Emils impls, you did not have the time to break out the verification impl you did dirbaio ? :D
<dirbaio[m]> not yet
jsolano_ has joined #rust-embedded
<dirbaio[m]> Lumpio-: exactly
jsolano_ has quit [Client Quit]
<Lumpio-> okay
jsolano_ has joined #rust-embedded
jsolano_ has quit [Client Quit]
<dirbaio[m]> it could do the "flag" thing yeah, but it'd have extra runtime cost
jsolano_ has joined #rust-embedded
<Lumpio-> I guess yes
<dirbaio[m]> it's faster to ensure correct order... it's a bit footgunny, but that's what HALs are for, handle the footguns on behalf of the users :)
<Lumpio-> Still never tried embassy
<Lumpio-> Maybe I will when I come up with my next Rust project (unless it's generic IoT crap I actually really like ESP32 std support for that)
jsolano_ has quit [Client Quit]
jsolano has quit [Quit: leaving]
<dirbaio[m]> esp32's nostd/embassy support is rapidly improving tho :D
jsolano has joined #rust-embedded
<Lumpio-> I know but it was like
<Lumpio-> Download some random network protocol crate from crates.io and it _just works_
<Lumpio-> I'm sure the IDF library it's built on is a rickety bridge to be walking on but, it _just worked_
<dirbaio[m]> ahh right, being able to use any not-no-std crate sounds awesome indeed
<dirbaio[m]> with heavy heap usage though
<Lumpio-> Oh yes
<Lumpio-> But it's got heaps of heap
<dirbaio[m]> shipping something to production with unpredictable memory usage scares me :D
<Lumpio-> like _hundreds_ of kilobytes
<dirbaio[m]> but it's the standard for generic iot indeed...
<dirbaio[m]> reliability be damned
<dirbaio[m]> or even worse, embedded linux
<Lumpio-> You can literally std::thread::spawn on ESP32
<Lumpio-> And it Just Worksยฎ
<dirbaio[m]> ๐Ÿ’€
<Lumpio-> Of course in reality it spawns like a FreeRTOS task but close enough eh
<dirbaio[m]> heap-allocated stacks yay
<Lumpio-> I don't even know how big of a stack it allocates
<Lumpio-> but it worked
jsolano has quit [Quit: leaving]
<dirbaio[m]> yolo
<dirbaio[m]> :D
<Lumpio-> Actually I think they might have extended the thread builder
jsolano has joined #rust-embedded
<Lumpio-> Yes you cna actually like thread::Builder::new().stack_size(1234).spawn(...)
<Lumpio-> wait that's part of the stdlib
<Lumpio-> too
<Lumpio-> But yes still ends up on the heap of course!
<Lumpio-> Maybe I'll play with Rust again once I'm done playing with fpgas
jsolano has quit [Quit: leaving]
M9names[m] has joined #rust-embedded
<M9names[m]> Oh right, supposed to save my spooky stories for Halloween.
<M9names[m]> > or even worse, embedded linux
<M9names[m]> Embedded Linux running a 2.4 kernel on a target with no mmu connected to the internet ๐Ÿ‘ป ๐Ÿ‘ป ๐Ÿ‘ป
d3zd3z[m] has joined #rust-embedded
<d3zd3z[m]> Anyone here very familiar with Cortex-m fault handling? I have a device where if the flash is not fully programmed, reads will result in a fault. I'd like to some how recover from this, for example to be able to complete a flash operation that was started when power was lost
crabbedhaloablut has quit []
<d3zd3z[m]> The cortex-m-rt crate let's me register my own handlers, but they aren't allowed to return, so I'm not quite sure the best way I could return back to my code.
diondokter[m] has joined #rust-embedded
<diondokter[m]> d3zd3z[m]: I normally just let it reboot
ian_rees[m] has quit [Quit: Idle timeout reached: 172800s]
<JamesMunns[m]> AFAIK, the answer is currently "it doesn't provide a way for you to do that". Which means you probably would have to manually clear whatever error condition exists, then pop the exception stack frame off. You'd probably want that to be partially or wholly ASM IMO.
explodingwaffle1 has quit [Quit: Idle timeout reached: 172800s]
FreeKill[m] has quit [Quit: Idle timeout reached: 172800s]
barafael[m] has quit [Quit: Idle timeout reached: 172800s]
<d3zd3z[m]> Rebooting would be "silly", since the vendor has apparently decided this is the only way to tell if a given page of flash has been written. There isn't a condition to clear, other than not retrying the ld instruction that just failed. Ideally, I'd set a global atomic to indicate the failure, adjust the PC past the offending instruction, and then return from the handler. Oh, and if the atomic didn't indicate we were doing this,
<d3zd3z[m]> treat it as an ordinary fault.
<d3zd3z[m]> It seems that cortex-m-rt 0.7 does let me use a non-trampoline version of the handler, which would mean I could probably handle this with inline assembly, but the lpc55-hal specifies cortex-m-rt 0.6, which doesn't. Whee
<dirbaio[m]> cortex-m 0.6 is old lol. you might want to look into updating it
<dirbaio[m]> anyway you can always define the symbol yourself directly without using the #[exception] mcaro
<dirbaio[m]> s/#/`#/, s//`/, s/mcaro/macro/
<adamgreig[m]> does it always hardfault? trampoline was only ever for hardfault
<adamgreig[m]> if you can make it a different fault like busfault/memfault or something you can have your own non-trampoline handler even in 0.6
<dirbaio[m]> i'd guess BusFault, but BusFault is upgraded to HardFault by default unless you configure something
<adamgreig[m]> (by default most faults are turned into hardfault if not specifically enabled)
<adamgreig[m]> yea, so maybe it's possible to just enable busfaults and then catch that
<adamgreig[m]> at least then you don't have to handle any other types of faults
<adamgreig[m]> (and if your busfault handler faults, it will be promoted to a hardfault, convenient way to make sure it dies if it's doing something stupid)
danielb[m] has joined #rust-embedded
<danielb[m]> Running a partially flashed firmware sounds bizarre to me. Is this really something vendors want us to do?
<danielb[m]> Or am I missing something?
<adamgreig[m]> it might not be firmware but some config data or other stuff stored in flash, that was being written before a power failure
<adamgreig[m]> like maybe a bootloader or a device receiving a new config over a comms interface or something
<adamgreig[m]> the flash might have some error detecting code that can be used to check if a page was properly written
<danielb[m]> Ah fair enough I didn't catch that part
<d3zd3z[m]> Or in my case, a bootloader that is upgrading the firmware. It needs to recover if power is lost.
<dirbaio[m]> wouldn't the bootlaoder "know" it has a half-written firmware and avoid booting it?
<d3zd3z[m]> Not if the power is lost? The only place it has to store any state is in the flash it is operating on. Well crafted, it only has to know one place, but there will always be one thing it can't know for certain if it finished.
<dirbaio[m]> ahh right ๐Ÿคฃ
<d3zd3z[m]> It will indeed avoid booting it, that isn't the issue, but it needs to read from that flash to try and figure out where it left off.
<dirbaio[m]> even if you write some metadata somewhere to track status of the upgrade
<d3zd3z[m]> BTW, what I'm working on is basically https://github.com/mcu-tools/mcuboot, but perhaps mcuboot-rs.
<dirbaio[m]> that metadata could be half-written too
<dirbaio[m]> oof
<d3zd3z[m]> Yup, see the fun.
<d3zd3z[m]> That's what changes the bootloader from "that doesn't seem very hard", to "oh, yeah that", followed by "oh, yeah that, too", followed by "ugh, that is hard".
<dirbaio[m]> ๐Ÿ˜ญ I see I see
<d3zd3z[m]> When I first started working on the C mcuboot, it wasn't particularly tested. I wrote a simulator (in rust) to simulate all of the places power could be lost. Many dozens of fixes later, it now passes most of those tests.
<d3zd3z[m]> It's also sad when the hardware vendors themselves don't even figure out what is needed to reliably access flash.
<dirbaio[m]> have you seen embassy-boot? :D
<d3zd3z[m]> I have, it has some useful things to look at.
<d3zd3z[m]> Still also trying to debug why my attempt to chain to the next application doesn't work very well.
TomB[m] has joined #rust-embedded
<TomB[m]> <d3zd3z[m]> "When I first started working..." <- That's pretty neat, I didn't know you wrote a sim in rust for that, but makes good sense to try and fuzz the bootloader in a way, simulating failure points
<d3zd3z[m]> It's kind of amazing just how hard it is to get things right, especially things like robustly swapping the code between two partitions.
<TomB[m]> I recall understanding at one point why it does that rather than having like a boot image index ("boot image 0, if it fails boot image 1) kind of thing, I guess because then the images need to be built with an understanding of which slot they are being built for?
<JamesMunns[m]> You could do:
<JamesMunns[m]> * flash the binary
<JamesMunns[m]> * flash the len + crc32 of the binary at end of flash
<JamesMunns[m]> (or in some header location that is consistent)
<JamesMunns[m]> don't write the CRC + len until after the rest is flashed. if bootloader loads and crc check fails, assume bootload failed in progress
<adamgreig[m]> but if the flashing failed during the write to the crc+len, you still get a fault
<TomB[m]> mcutool has digital signing and hashing I believe already as part of the image metadata (its been awhile since I used) which is really nice, but the default mode is this swap mode, where it, at least when I used it, it had two slots, but only one slot was the boot slot
<JamesMunns[m]> adamgreig[m]: Yes? that's an incomplete bootload to me
<JamesMunns[m]> OH
<TomB[m]> so it had this whole image swap routine, which was effective, and meant you didn't need to worry about building things for a particular spot in flash
<adamgreig[m]> sure, but I mean, that's the problem here, the firmware goes to a busfault/hardfault handler that can't be returned from
<TomB[m]> but... it did mean there was this whole image swap routine which I wondered how robust it could be
<JamesMunns[m]> it's an ECC fault on read?
<JamesMunns[m]> > reads will result in a fault
<JamesMunns[m]> Ah, missed that, sorrt
<JamesMunns[m]> s/sorrt/sorry/
<d3zd3z[m]> Image swap can be quite robust, but it is hard. I'd say the mcuboot code gets there, maybe 95%, with some extra complexity that is unnecessarily, and some places it needs complexity. I've been wanting to try some new things there, but the C code has gotten rather crufty over the years, and it is really hard to make changes to it.
<JamesMunns[m]> > <@adamgreig:matrix.org> but if the flashing failed during the write to the crc+len, you still get a fault
<JamesMunns[m]> * Yes? that's an incomplete bootload to me
<JamesMunns[m]> edit: i'm wrong, context below
<TomB[m]> well I never had it fail on me, and I was certainly one of those people that should've had it fail if it could
<d3zd3z[m]> The LPC 55s69 has a rather weird flash device that is almost sector based, erase and write are on 512-byte boundaries.
<d3zd3z[m]> Do you actively test removing power while doing uprades?
<TomB[m]> well I was constantly yanking the usb plug of the nordic board while doing upgrades over ble
<TomB[m]> so I suppose so
<d3zd3z[m]> And, it may be decent. Being in rust is certainly a better starting point for making it robust.
<TomB[m]> wasn't exactly what I'd call formal testing
<d3zd3z[m]> But, the sim I wrote for mcuboot tests something like 100k places that a flash operation can be interrupted. That'd be really hard to do on a real device.
<dirbaio[m]> how does the sim work? it actually interrupts the code? or it saves a "trace" of all flash writes to later reconstruct interrupted images?
<dirbaio[m]> I wanted to do something like that for ekv, but ran out of brain fuel
<JamesMunns[m]> dirbaio[m]: The latter is how I was thinking about doing that recently, but ended up with something much more limited.
<JamesMunns[m]> Also very interested to hear how mcuboot does it
<TomB[m]> dirbaio[m]: mcuboot has a hardware API layer, guessing the sim implements this with simulated flash given the code tree
<TomB[m]> * code tree, https://github.com/mcu-tools/mcuboot/tree/main/sim but yeah I'm curious about it too!
Mathias[m] has joined #rust-embedded
<Mathias[m]> d3zd3z: There is a way to read the Flash that does not fault, see in section 5 (and in particular `consistency_check()` page) of UM11126. References are for rev 2.5.
<d3zd3z[m]> As far as I can tell, that only tries reading if you think you already know what is supposed to be there.
<d3zd3z[m]> It seems intended for verifying after doing a write.
<d3zd3z[m]> The authors of the docs at least didn't seem to consider that power might fail during an operation.
<d3zd3z[m]> Another case, there might be an image in the upgrade slot. I don't know what that image would be, but I'd like to check if it is present without faulting.
<Mathias[m]> If I take James's example the CRC is written last (+ possibly a value that can't ever be 0xFF or 0x00) and you read this part with a device-specific function that might be slow but won't fault. This way you know that the flashing finished. ECC failures might still occur, but that would be because the flash is degraded, not because update was interrupted.