<d3zd3z[m]>
The rtic book (rtic.rs) seems to be describing 2.0 of rtic, yet crates.io only seems aware of a 1.1 version. Is there documentation for the released version?
<d3zd3z[m]>
Or stepping back, is rtic how I should be doing concurrency? My firmware is working ok so far, just with a main loop, and spinning and polling, but I'd like to use interrupts for USB processing and the likes, and ideally be able to have a bit of scheduling. RTIC looks like a good fit, but I'm not sure what of it I should be using.
<d3zd3z[m]>
Trying to create a basic rtic on rp2040. It seems that as soon as I put variables in Shared, the first thing that tries to do a critical_section::acquire hangs forever there.
M9names[m] has joined #rust-embedded
<M9names[m]>
Do you release the spinlocks like the Eric example does?
<lulf[m]>
lulf[m]: Maybe others have a generic i2c example to share
zyla[m] has joined #rust-embedded
<zyla[m]>
<andresovela[m]> "But now I have no idea how to..." <- You don't have to define it. The bound `I2C: embedded_hal::i2c::ErrorType<Error = E>` constrains `E` to be `<I2C as embedded_hal::i2c::ErrorType>::Error`.
<fu5ha[m]>
Blegh sorry formatting. Apparently editing a message on matrix mobile is a bad idea
<andresovela[m]>
Let me try that
<andresovela[m]>
It's telling me to use a fully qualified path, but I don't really get it
<fu5ha[m]>
*
<fu5ha[m]>
`E` is no longer generic. You've named the generic type `I2C` to be `I2cDeviceOnSharedBus` and you previously defined `E` to be equal to
<fu5ha[m]>
`<I2C as I2c>::Error` so you can just substitute the generic that you've named and you get `<I2cDeviceOnSharedBus as I2c>::Error` which is just a single type. So get rid of the `E` generic on your impl block and just replace it with that
<andresovela[m]>
The type is nasty
<fu5ha[m]>
You want `<I2cDeviceOnSharedBus as embedded_hal_async::i2c::ErrorType>::Error` probably
<andresovela[m]>
That seems to have done the trick :D
IlPalazzo-ojiisa has joined #rust-embedded
starblue has quit [Ping timeout: 255 seconds]
starblue has joined #rust-embedded
Guest7221 has left #rust-embedded [Error from remote client]
aflanagan has joined #rust-embedded
Guest7221 has joined #rust-embedded
<d3zd3z[m]>
<M9names[m]> "Do you release the spinlocks..." <- > <@9names:matrix.org> Do you release the spinlocks like the Eric example does?
<d3zd3z[m]>
Thanks, I just had to move HEAP and HEAP_MEM to both be outside of the function, and just do the init in init.
<d3zd3z[m]>
So, deeper question, I have a resource that I need both to be owned as a resource, but someone needs a `&dyn Trait` to it. As I understand lifetimes, these can't be in the same resource structure. Normally I'd solve this by Boxing, which does seem to work, but may not be the best.
<korken89[m]>
A trampoline with the trait bound should work
<korken89[m]>
So `cx.shared.my_resource.lock(|r| my_method_with_trait_bound(&mut r))`
<korken89[m]>
Then my_resource can have a concrete type and my_method_with_trait_bound can use it
<korken89[m]>
You can probably even do `&mut r as &mut dyn MyTrait`
<d3zd3z[m]>
The 'dyn also needs to be given to a resource.
<d3zd3z[m]>
In fact, I can make it work by having that resource just own it. But, the types quickly get very complicated.
<d3zd3z[m]>
And, for the case of an array of gpio's are actually impossible to declare.
<korken89[m]>
Yeah, I don't think that's going to be nice
<d3zd3z[m]>
My pre-rtic code just relies on main not exiting, but that doesn't work here, with the init function returning things.
<korken89[m]>
Rather than dyn trait I'd recommend you to use an erased pin
<korken89[m]>
That's what I generally do when I need arrays of pins
aflanagan has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<d3zd3z[m]>
<korken89[m]> "Rather than dyn trait I'd..." <- `degrade` seems specific to your hal. I'm trying to see what the rp2040-hal is expecting me to use.
<dirbaio[m]>
since the spinlocks are in SIO, which is not part of core0, they don't get reset
<d3zd3z[m]>
So, the reason this didn't show up pre-rtic is that I was using the rp2040-specific entry, whereas with rtic, it is using the generic cortex-m entry. There is a small block of code in the rp2040_hal that does this initialization. So, it is reasonable to do it this way here.
<dirbaio[m]>
yep, rp-hal added their own entry macro to do the "reset spinlocks" thing as a workaround
<dirbaio[m]>
but it's just that, a workaround
<d3zd3z[m]>
Seems like this would go away if using something like a J-Link which runs a wire to the chip reset.
Noah[m] has joined #rust-embedded
<Noah[m]>
hmm we should also use the wire if its available. but depending on where in the process its not possible
<d3zd3z[m]>
Yeah, it isn't on the debug header that I designed to match the pico-probe. But, I could do that in a future board.
jannic[m] has quit [Quit: Idle timeout reached: 172800s]
adamgreig[m] has quit [Quit: Idle timeout reached: 172800s]
<thejpster[m]>
Anyone else see a big size regresssion for hello-world on ARMv7E-M between 1.72.1 and 1.73??
<cr1901>
(ignore the repo name, I do ARM testing too)
<cr1901>
I have the Rust source code checked out locally and build it once a week, so I have all the infrastructure to bisect (although cargo-bisect-rustc will probably work too since it's been less than 90 days since the regression)
<dirbaio[m]>
cargo-bisect-rustc might help too. my guess is it'll just point at one of these "update LLVM" commits :P
<cr1901>
Yes, that is usually what happens wrt msp430 regressions, so then I end up having to bisect LLVM too :'D
<newam[m]>
it's probably just LLVM adding / skipping a pass that it did previously.
<newam[m]>
I think the rustc godbolt can show the LLVM passes now if you're interested.
<dirbaio[m]>
also try opt-level=s. my experience is z is too conservative when inlining, which actually increases code size bloat because inlining allows optimizing more stuff away
<JamesMunns[m]>
<thejpster[m]> "4992 --> 6588 !" <- Also, tbf: this is a large percentage increase, but not necessarily a very large total increase. Worth checking if you see similar results on a nontrivial project. That's why I included the panic format commit - formatting can easily influence a 1.5KiB change IMO
jasperw has quit [Ping timeout: 255 seconds]
<cr1901>
The size has also gotten worse since 1.73... on nightly (960754090), it's using 8000+ bytes now
<JamesMunns[m]>
Went to see if I could see it in https://perf.rust-lang.org/index.html, hard to tell because the size metrics aren't stripped, so they are all relatively huge
<JamesMunns[m]>
Things seem to actually go down since July 1st, but again, the actual firmware is noise vs the debug info, and we may not actually have a bin crate in the perf tests, only a lib crate (stm32f4)
aflanagan has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
aflanagan has joined #rust-embedded
<cr1901>
I cannot duplicate the 4992 result at all. Not anything close to it. What is the _exact_ command-line you're using?
Guest7221 has left #rust-embedded [Error from remote client]
Guest7221 has joined #rust-embedded
<thejpster[m]>
cargo +1.72 build --bin hello
<thejpster[m]>
in the nrf52-code/radio-apps folder
<thejpster[m]>
I'm on macOS for Apple Silicon, if it matters
<JamesMunns[m]>
That's from Lokathor, who has been pretty vocal about it.
Guest7221 has left #rust-embedded [Error from remote client]
<d3zd3z[m]>
Is there any kind of pre-existing utilities for clearing the I and D caches on Cortex-M, or do I need to access cortex_m::peripherals::cbp directly?
<dirbaio[m]>
voladdress is not affected by the dereferenceable issue because it wraps a pointer
<dirbaio[m]>
ie you use `VolAddress`, not `&VolAddress`
<dirbaio[m]>
and you don't do "structs matching the layout of registers"
<dirbaio[m]>
honestly it's simpler to generate code using raw pointers directly though, imo
GrantM11235[m] has joined #rust-embedded
<GrantM11235[m]>
<dirbaio[m]> "voladdress is not affected by..." <- Actually it wraps a NonZeroUsize. Is there any difference (providence or whatever) between doing a single int-to-ptr cast on construction vs doing the cast for every access?
<dirbaio[m]>
lol
<JamesMunns[m]>
There was talk of "establish providence" for volatiles in the rust memory model, dunno if that's been stabilized tho
<JamesMunns[m]>
the goal was to be able to say something like "I promise this is a pointer to something outside of memory known to the compiler", basically guarantee it's a MIMO value, not a local/stack/heap variable
<dirbaio[m]>
in general using usizes for ptrs is a no-no
<dirbaio[m]>
though it's true in this case that for device memory, the very first ptr comes from a usize, so perhaps it's fine
<firefrommoonligh>
Latest drone-device - maybe my first DC-DC design that didn't get the magic smoke
<firefrommoonligh>
The magic smoke, in this case, thankfully didn't cause the demon fire which is assocaited with it at the relatively higher voltages involved
<firefrommoonligh>
* The magic smoke, in this case, thankfully didn't occur, nor ignite the demon fire which is associated with it at the relatively higher voltages involved
<JamesMunns[m]>
it's always good to remember that Rust's memory model is aiming at being "a stricter subset of what compilers actually understand", so that if you are good according to Rust's model, you are certainly good on whatever backend you use.
<JamesMunns[m]>
Even if Miri says "oh no", LLVM might still say "cool whatever" (for now)
<firefrommoonligh>
The actual rust firmware here is pretty straightfoward: Just reading from 14 ADC channels and outputting it over CAN
<JamesMunns[m]>
JamesMunns[m]: > <@jamesmunns:beeper.com> it's always good to remember that Rust's memory model is aiming at being "a stricter subset of what compilers actually understand", so that if you are good according to Rust's model, you are certainly good on whatever backend you use.... (full message at <https://catircservices.org/_matrix/media/v3/download/catircservices.org/UKqXRYxLsLBSPtnxsHyvzhlA>)
<JamesMunns[m]>
* but still - if you fall afoul of rust's rules, today's success may not predict future results (like all UB, tbh).
<JamesMunns[m]>
However, stuff like MIMO and non-basic understanding of provenance is still not totally specified, afaik.
<JamesMunns[m]>
s/providence/provenance/
<GrantM11235[m]>
Would it be useful for chiptool to use nonnull instead of regular ptrs?
<JamesMunns[m]>
As a total gut guess: I would say it probably doesn't matter. But I have nothing to back that up with. If you found out somewhere that NonNull is actually special in that regard, i'm totally interested
<JamesMunns[m]>
afaik nonnull/nonzero is only used for niche-packing, e.g. `Option<NonZero/Null>` can be `== sizeof::<NonZero/Null>()`
<GrantM11235[m]>
I guess my question is: does anyone use `Option<ChiptoolReg>`
<JamesMunns[m]>
Ah, (my answer was wrt provenance, rather than general usage/perf)
<GrantM11235[m]>
Yeah, providence should be the same. There is also covariance, but I don't think that matters when you are just using integers/integer-wrappers
<GrantM11235[m]>
Actually I think covariance only matters for `NonNull<T>` when T has a lifetime. In this case it would just be `()`
<JamesMunns[m]>
(also a note, I was saying providence before, when I meant provenance, it's been a long day 😅)
<JamesMunns[m]>
(provenance is the origin or source of something, providence is divine assistance - we might need both here)
<dirbaio[m]>
try probe-rs run instead of probe-run
<mameluc[m]>
ok Ill try. I have some problems installing probe-rs that I have to figure out
<dirbaio[m]>
cargo install probe-rs --features cli doesn't work? what error does it give?
<mameluc[m]>
ah yes, it was actually about the cli thing
<mameluc[m]>
okay now it fails more consistently at the start 😅
<dirbaio[m]>
progress! :D
<dirbaio[m]>
stm32wl?
<dirbaio[m]>
* is it stm32wl?
<mameluc[m]>
you know it 😅
<mameluc[m]>
wle so single core
<dirbaio[m]>
ahh
<newam[m]>
Yup, that's the problem target 😅
<dirbaio[m]>
was about to suggest a workaround for the multicore one which is currently broken. but afaik the singlecore one should work :|
<newam[m]>
Is this a devboard?
<mameluc[m]>
yeah it has been working fine on other boards with the same chip
<newam[m]>
Which board and what probe?
<mameluc[m]>
yeah its my own board. Something broken. Works with HSI but not HSE
<mameluc[m]>
and the flashing is flaky
<newam[m]>
You can turn on verbose logging and get more information from what's going on at the bus level, but if it's only this one board I'd say it's a hardware issue
<mameluc[m]>
I am using a module by Minew and my board is just power and pins. I am using a tag-connect connector that I didn't use before
<mameluc[m]>
tried reducing speed
<newam[m]>
Hmmm you said it runs for 5ms, does it actually get something from the target (verbose logs can show this)? If it does connect are you changing clock speeds in early boot?
<newam[m]>
There are some clock configurations that don't jive with some debuggers
<mameluc[m]>
I get defmt log, everything seems to be working fine until it stops
<mameluc[m]>
if I reduce the program to just blinking a led it stays running
<newam[m]>
Ah, so there is life. Yeah definitely check clocking/power/resets.
<mameluc[m]>
and the speed thing I meant I reduced SWO speed
<mameluc[m]>
I don't fully understand the reset mechanism
<newam[m]>
hardware reset should be fine if you're able to connect to the target, when I say "resets" I mean something related to the CPU, debug logic, or things that manage clocking/power
<newam[m]>
you're using embassy though, so unless you're driving the registers directly or doing other low-level things that shouldn't really be a problem.
<mameluc[m]>
yeah and this code is working on another module with the same chip
<newam[m]>
ah, hmmm.
<mameluc[m]>
I have also changed the module (in case of hw failure in this particular one)
<newam[m]>
same chip, but same hardware on this working module?
<mameluc[m]>
well same setup with a crystal, I don't know more than that as I have not opened it up
neceve has joined #rust-embedded
<mameluc[m]>
different RF stuff but that should not be the problem
<dirbaio[m]>
I refactored the stm32wl rcc recently, I hope I didn't break anything 😊
<mameluc[m]>
Minew module doesn't work
<mameluc[m]>
wio-e5 module works
<dirbaio[m]>
maybe double-check whether flash latency setting is right, i've seen that cause similar flakiness
<dirbaio[m]>
are you doing flash write/erase operations?
<newam[m]>
mameluc[m]: never say never :D
<newam[m]>
I once accidentally wired up a STM32WL such that it shorted in some RF switch configurations. Not my brightest moment.
<mameluc[m]>
dirbaio[m]: yes but later in the program. it should not have gotten that far
<mameluc[m]>
newam[m]: > <@newam:matrix.org> never say never :D
<mameluc[m]>
true :D
<mameluc[m]>
> I once accidentally wired up a STM32WL such that it shorted in some RF switch configurations. Not my brightest moment.
<mameluc[m]>
I checked the power buses in case there was shorts but I couldn't see anything with my scope
<mameluc[m]>
also no exessive current spikes
<mameluc[m]>
thanks for all the help. I just confirmed that it works with MSI, except it gets stuck on RNG stuff but at least the program runs and probe-rs doesn't complain
<dsvsdveg[m]>
Is it possible to have code review? :)
<mameluc[m]>
I can review any code. I give points for crative emoji use
azzentys117[m] has joined #rust-embedded
<azzentys117[m]>
Question: Is there a common Rust based community on matrix or related?
<mameluc[m]>
rust:matrix.org
<dirbaio[m]>
#rust:matrix.org
<mameluc[m]>
ah ,thats how you do it :D
<mameluc[m]>
it was too high traffic for me
<azzentys117[m]>
I was trying to use use match to do some bitmasked matches, a friend said that I can ask over there.
<azzentys117[m]>
If anyone has any ideas here, they are appreciated.
<azzentys117[m]>
I just separate and carry around masked values.
<mameluc[m]>
are the u4 and u8 the same bits as u12?
<azzentys117[m]>
Yes, they are.
<mameluc[m]>
I was just thinking that your match is doing two things. Matching the right command and figuring out what values to pass
<mameluc[m]>
if you always passed all the bits to all commands they could figure out what they want to do with the data themselves
<GrantM11235[m]>
I don't think you need the CommandConstruct type, you can just convert a u16 (or two u8s) directly into a Command
<azzentys117[m]>
> they could figure out what they want to do with the data themselves
<azzentys117[m]>
mameluc: I kinda don't want to do that. I could make another function to "pass" proper value. Each command ends up with what particular data it picks from the command.
<azzentys117[m]>
* > they could figure out what they want to do with the data themselves
<azzentys117[m]>
mameluc: I kinda don't want to do that. I could make another function to "pass" proper value. Each command ends up with what particular data it picks from the command.
<azzentys117[m]>
* > they could figure out what they want to do with the data themselves
<azzentys117[m]>
mameluc: I kinda don't want to do that. I could make another function to "pass" proper value. Each command ends up with what particular data it picks from the command.
<azzentys117[m]>
Thanks for the advice!
<mameluc[m]>
yeah thats cool whatever makes sense and is readable
<andresovela[m]>
I could probably make do without std, but I don't see why I should make my life miserable when I can just test using std
<mameluc[m]>
I was just asking bc I was thinking the same thing and in the end I did not need std stuff for testing my particular firmware. I just tested the logic without std and the code was ofc no_std
<GrantM11235[m]>
I think this is why people usually recommend separating you binary crate from your library code
<andresovela[m]>
Separating as in?
<GrantM11235[m]>
Make two crates. One is a library that has all your code that doesn't depend directly on the hardware. The second crate is a binary that uses that library and also has hardware-specific stuff
<andresovela[m]>
That I have already
<andresovela[m]>
But they're in the same workspace
<andresovela[m]>
They all see the same .cargo/config.toml I guess
<GrantM11235[m]>
Also, don't use workspaces, it causes these problems. The library crate shouldn't specify the target in config.toml
<andresovela[m]>
Meh, it'd be really annoying to not have all the crates I use in my project in one repo
<GrantM11235[m]>
You can keep the crates in one git repo without using a workspace
<andresovela[m]>
Ah I think I know what you mean
<andresovela[m]>
I'm not using a cargo workspace
<mameluc[m]>
path = "../othercrate" is your friend
<andresovela[m]>
But when I run cargo test it still compiles using the thumbv6m-none-eabi target that I set in my cargo/config.tom
<andresovela[m]>
s//`/, s//`/, s/tom/toml/
<andresovela[m]>
mameluc[m]: Yeah that's what I do
<mameluc[m]>
put cargo/config in the subcrate?
<andresovela[m]>
But I do want to normally build using the target for my MCU
<andresovela[m]>
It's just for cargo test that I want to use my laptop's target
<GrantM11235[m]>
That example is overly complicated because it also includes running some tests on the mcu
<andresovela[m]>
If I understand correctly, they're suggesting to create another crate just for tests?
<mameluc[m]>
yes
<mameluc[m]>
also another crate for logic that is not bound to embedded stuff if you have a lot of that
<andresovela[m]>
That I have
<andresovela[m]>
Several crates actually
<andresovela[m]>
But it seems overkill to have to create a new crate for every crate I want to test
<mameluc[m]>
then one embedded crate that is the actual firmware. To test that stuff you need to run stuff on hardware
<GrantM11235[m]>
<andresovela[m]> "It's just for cargo test that..." <- You need to kinda invert your thinking. You "normally" want to build for your laptop (for tests), the exception is when you are building the binary for your mcu
<andresovela[m]>
Surely there must be an easier way
<mameluc[m]>
andresovela[m]: why not all the tests in the same crate?
<andresovela[m]>
GrantM11235[m]: Not really, I "normally" want to build for my MCU, I'd run tests only every now and then
<andresovela[m]>
mameluc[m]: I guess you can do that, but feels yucky
<andresovela[m]>
Ideally you'd be able to have the test for crate foo in crate foo
<andresovela[m]>
s/test/tests/
<mameluc[m]>
put on some plastic gloves 👍️
<GrantM11235[m]>
andresovela[m]: What I mean is that you should only set the target in the cargo config for your MCU binary crate
<andresovela[m]>
Hmm
<andresovela[m]>
Let me see what happens if I move it
<GrantM11235[m]>
So when you build your mcu binary, it is compiled for thumbv6, but your other library crates will be compiled for your laptop when you run their tests
<andresovela[m]>
Hmm I actually don't know where to move it to
<GrantM11235[m]>
Put it in whichever crate has the main.rs that runs on your mcu
<GrantM11235[m]>
You can't have your libraries nested inside the directory of your main crate like that
<dsvsdveg[m]>
<mameluc[m]> "rust:matrix.org" <- are they any ethereum rust or ethereum matrix?
<dsvsdveg[m]>
or blockchain matrix
<andresovela[m]>
Sure you can, I see it all the time
<GrantM11235[m]>
You need the libraries to be next to the main crate. Your top level directory should contain foo, bar, drivers, and my-main-mcu-binary
<mameluc[m]>
dsvsdveg[m]: there is a search function in element
<andresovela[m]>
But ok, I'll try it
<GrantM11235[m]>
cargo looks for config files in parent directories also, so when you do cargo test from one of your libraries, it sees the config that is meant to be for your mcu binary
<andresovela[m]>
Okay yeah it looks like that did the trick :)
<sparky[m]>
temp comes out mostly as 0.0, while pressure seems to be absurdly small... like 1.9198516e23. it also only works in release mode cause of wrapping. unsure if its expected to wrap or not though
<GrantM11235[m]>
The first byte should be the low byte of T1, but you are using it as the high byte
Foxyloxy has joined #rust-embedded
<GrantM11235[m]>
(same for all the other u16 and i16 values)
<mameluc[m]>
maybe use u16::from_be_bytes(bytes)
<mameluc[m]>
or le, too tired to figure out which one :D
cyrozap_ has joined #rust-embedded
thomas25- has joined #rust-embedded
crabbedhaloablut has quit []
lulf[m]1 has joined #rust-embedded
<GrantM11235[m]>
Its LE
<sparky[m]>
GrantM11235[m]: thats def a huge problem. ofc i didnt pay attention to that when writing it up... thanks for pointing that out. ill have to work through that
<GrantM11235[m]>
For some reason the datasheet lists it in reverse order 🙃
HumanG33k has joined #rust-embedded
lulf[m] has quit [Ping timeout: 264 seconds]
Foxyloxy_ has quit [Ping timeout: 264 seconds]
cyrozap has quit [Ping timeout: 264 seconds]
HumanGeek has quit [Ping timeout: 264 seconds]
<sparky[m]>
sadly, doesnt seem swapping the order for the u16s/i16s made any difference in the algo outputting total nonsense. still 0.0 for temp, and similar results for pressure to before
thomas25 has quit [Ping timeout: 264 seconds]
<GrantM11235[m]>
The shifts and casts are also a bit sketchy when it comes to signed values, i16::from_le_bytes would definitely be clearer
<sparky[m]>
GrantM11235[m]: which would be lsb,msb when supplying it?
<sparky[m]>
zero change in output when swapping to from_le_bytes. def cleaner, so ill keep it but still busted output lol
<sparky[m]>
thanks for the suggestion to make it way more readable
<GrantM11235[m]>
Page 55 says you need to convert the integer values to floats, with some division
<sparky[m]>
<GrantM11235[m]> "Page 55 says you need to convert..." <- ugh... right. i saw that, but totally ignored it. so, `u16 / f32 -> f32` is what i should use to convert them with the float being the 2^-8 number for par_t1?
<sparky[m]>
> <@grantm11235:matrix.org> Page 55 says you need to convert the integer values to floats, with some division
<sparky[m]>
* ugh... right. i saw that, but totally ignored it. so, `f32::from(u16/i16/u8/i8) / f32 -> f32` is what i should use to convert them with the float being the 2^-8 number for par\_t1?
<sparky[m]>
i just swapped the struct to be all f32, and am doing this t1: f32::from(u16::from_le_bytes([value[0], value[1]])) / 2.0.powf(-8.0),
<sparky[m]>
this is where is constructed after all, and theres no use for data without the coefficient applied
<GrantM11235[m]>
You can save ram by storing the values as 8 and 16 bit, and it should be super fast to convert on the fly and divide by powers of 2
<sparky[m]>
ill keep that in mind if i happen to need it then. personal use driver on a picow with no_std, so RAM isnt the most pressing concern i have
<sparky[m]>
for now... i want to see it work and im on like, hour 8 of non-stop focus on the issue lol
IlPalazzo-ojiisa has quit [Quit: Leaving.]
<GrantM11235[m]>
yeah, it's only 21 bytes vs 56 bytes, so it doesn't really make much difference
<sparky[m]>
hmm... powf isnt a function on floats?
<sparky[m]>
seems a bit off that theres so many missing float ops for core? guess its just that no ones bothered to try and get it drafted and in or is there some really deep reason as to why?
<GrantM11235[m]>
I think they are usually provided by a libc