-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
more Any*
types
#247
base: master
Are you sure you want to change the base?
more Any*
types
#247
Conversation
thanks for the PR ! my question that i just throw in the room - Including the Input -& Output variants on the pin opens the scope a lot for the AnyPin. Wouldn't it maybe nicer if we just create something like an "AnyPeripheralPin" that can contain the specific Peripheral variants it is usable with, but gates the usage of such pin for normal gpio usage where the user should use AnyIoPin ? |
As in an enum over |
could you elaborate a bit more what you mean by "dynamically-assigned peripherals in my current project" |
I just mean the peripherals, like i2c, gpio, pwm channels, timers, etc. in my project are configured at runtime based on a json file stored in nvs. I basically needed a pool mapping each index to a gpio pin, pwm channel, etc. that I can take from at runtime. But there didn't seem to be anything for that (for these things) since every individual pwm channel, timer, etc. are distinct types and cannot be boxed as their overarching trait object (and even if they could, it'd be less efficient). So I added more generic concrete types for them based on the The pool approach I used might be useful for others, but I figured that might be a bit against the grain for the rest of the crate. It's basically a |
hmmm, i feel like it would be nicer if you have some deserializer that directly crates the pins from your input.json, you are not bound to use the Peripheral::take() approach, technically you can unsafely create them by yourself if you made sure you didn't used them beforehand, and for the rest just use them as normal. |
But for a deserializer to work I'd still have to have a concrete type that any pin, pwm, timer, etc. can map to, so I'd still need the stuff in this PR anyway. Also even if I didn't use them elsewhere, the json could contain the same pin multiple times - it's user-provided, and the users are middle/high school students, so I can't trust them to configure things safely. So I'd have to do extra work after the fact to make sure each is unique, and checking that is similar to the pool approach anyway. But that aside, I also just like the pool approach since it involves no unsafe code (my project so far has no unsafe code - I'm actually pretty impressed Rust has so much safe tooling for embedded). |
i definitely see your problem, and i am not saying that your proposal is a bad one. I just want to explore the complete option space, and think about all alternatives. This way you could itterate over the collections and find the pins you need. Than you could create your own System Peripheral Struct at runtime out of that |
That's kind of what I was thinking, but maybe slightly different. I was thinking the It'd be great if we could just do the array version for everything like |
I think instead of using an array we may should use something like an heapless vec https://docs.rs/heapless/latest/heapless/struct.Vec.html |
That would work and then we can take elements out of it without having to do the |
Sorry for the delay here, I plan to look at this over the upcoming weekend. |
@dragazo Sorry for the delay. I'm finally looking into this as I (also) might need to introduce an What I don't understand is the following:
I think you suggest (in addition to what we already have):
So my question is - what is the value of the So if you can explain this use case as to why you need this extra level of indirection? |
Here's one speculation I have by reading the earlier comments: you are essentially implementing an Now this is a great use case I agree, yet a niche one. For all other use cases (and I would assume, these are like 99.9% of the use cases), the wiring of the external hardware to the ESP32 is a compile time thing, because the firmware is very specific to the use case. Now, the existing If you can confirm that. |
Right, it's just so that we can opt into runtime checking. As it stands, that was impossible despite all the underlying APIs just using pin numbers under the hood. This PR just takes the concrete pins and wraps up their permissions/capabilities so that we can still have all the same checking as |
Is it possible to implement this functionality outside of |
It would be possible but annoying to do outside of esp-idf-hal because of the permissions checking part. I added logic to the already-existing macros that generate the concrete types to just also take the permissions and use them to generate the dynamic wrapper. If you did that outside of esp-idf-hal you'd have to at least duplicate all of the permissions for every pin on every esp chip. That would basically come down to copying all of the macros from esp-idf-hal and replacing the existing definitions with a template to generate the dynamic one with permissions. And of course that would need to be updated for new chips independently of esp-idf-hal for any new targets down the road. If rust would ever add generic specialization to stable there would be a better story for this, but currently it would be very messy. |
But your solution still seems incomplete. For one, I bet you currently have a very large I mean... if you have these large |
Actually I don't have any kind of big matches for that. All I do is convert the concrete pins into I'll also clarify I'm perfectly fine just using my fork if this isn't something we want in esp-idf-hal proper. I was just going to contribute it back if anyone wanted it. |
Yeah. 48 lines of
Sure. I'm just thinking loud if there is a way to not merge your PR (as it is very big yet a niche use case), yet with no or minimal changes allow you to get rid of these 48 lines, plus whatever you do for the other peripherals. And most importantly, avoid the need to fork I think the absolute minimum for all things not GPIO is to ensure, that all Peripheral traits' methods do have a But once you have that, I'm still thinking you should be creating your peripherals out of thin air. Perhaps you can even create a |
The other problem with an array of pins, i.e. |
Well an array isn't going to construct itself when this crate doesn't support that...
Well that's the point of this PR, as an opt-in option. Without this PR this is flat out impossible currently.
Well like I said, doing this outside of the macros in this crate would be an unmaintainable nightmare. Unless you're suggesting I forego even runtime capability checking, which I would never do.
This PR already does that (not with ADC specifically, but the ones that I added like |
Alright. I'll give it one last shot. :)
But your PR does not address that either! Even with your PR applied, people in your situation still have to do the "48 Hopefully now it is clearer why I was saying below that your patch is incomplete - because even with it applied, there are these boilerplate lines of
(I'll skip that as this is not so important really and we'll just digress.)
ESP IDF already does capability checking at runtime and will return an
Of course it does. I'm not saying it doesn't. Read the whole paragraph. I'm saying that you don't need the full scope of this PR to build a "dynamic", safe API. And one aspect of building this dynamic but safe API is that you have to swallow the typed |
Well I was planning on just adding the core |
Until this happens, how does one create an array of ADCPins on the same ADC? Is it possible at all? |
@gmalette I believe without something like this PR, that is currently impossible. Granted, I don't think I included anything for ADC specifically (I kind of just added what I needed at the time), but it would probably be an easy addition. I can look into adding it when I get some time, but probably as a separate PR if this one gets accepted. |
I have mentioned in the comments above that this PR has a much bigger scope than
|
Well by "something like this PR" I just meant another PR that just adds |
Adds some more
Any*
types that I needed for dynamically-assigned peripherals in my current project. Note that some traits were changed fromfn () -> T
tofn (&self) -> T
to facilitate this, so some of this is a breaking change.