-
Notifications
You must be signed in to change notification settings - Fork 3
✨ (minor) Usb enumeration #92
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
base: main
Are you sure you want to change the base?
Conversation
d2cc07b to
c8f1daa
Compare
780ef28 to
f41be54
Compare
kammce
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rebase your project and fix your merge conflicts. Also, we moved the libhal-util code into v5 in preperation for v6 which will use libhal-v5. So we can remove the include files within the include directory and only keep the ones within v5/*
6b474f8 to
c9c62f1
Compare
For devices that use the libhal usb interface high level class. Handles configuration at the device and usb configuration level Handles multiple configurations and multiple interfaces.
Simulated host by sending enumerator requests and having it respond. Correct payloads were verified
Changed usb.hpp to be a shorthand for including all usb utils
For devices that use the libhal usb interface high level class. Handles configuration at the device and usb configuration level Handles multiple configurations and multiple interfaces.
Simulated host by sending enumerator requests and having it respond. Correct payloads were verified
Changed usb.hpp to be a shorthand for including all usb utils
c9c62f1 to
ff91bbf
Compare
kammce
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't reviewed everything. I'm posting what I have now because I'm not sure if github will lose my info.
| #include <libhal/units.hpp> | ||
| #include <libhal/usb.hpp> | ||
|
|
||
| #include "libhal-util/usb/utils.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use the standard <> for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can, I left it as "" because its the same repo that I am referencing and I am not a huge fan of relative path includes.
| std::array<u8, 9> m_packed_array = { | ||
| iface_desc_length, | ||
| iface_desc_type, | ||
| 0, // interface_number | ||
| 0, // alternate_setting | ||
| 1, // num_endpoints | ||
| 2, // interface_class | ||
| 3, // interface_sub_class | ||
| 4, // interface_protocol | ||
| 0 // interface name index | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be using the constexpr length as the template argument and using the object's size to set the first element.
See this example of this working: https://godbolt.org/z/1j3rqzr1W
The code change would look like this:
| std::array<u8, 9> m_packed_array = { | |
| iface_desc_length, | |
| iface_desc_type, | |
| 0, // interface_number | |
| 0, // alternate_setting | |
| 1, // num_endpoints | |
| 2, // interface_class | |
| 3, // interface_sub_class | |
| 4, // interface_protocol | |
| 0 // interface name index | |
| }; | |
| std::array<u8, iface_desc_length> m_packed_array = { | |
| sizeof(m_packed_array), | |
| iface_desc_type, | |
| 0, // interface_number | |
| 0, // alternate_setting | |
| 1, // num_endpoints | |
| 2, // interface_class | |
| 3, // interface_sub_class | |
| 4, // interface_protocol | |
| 0 // interface name index | |
| }; |
Now you don't have to worry about accidentially making a mistake which causes the sizes to be off. Like for example, accidentally putting 10 or 19 instead of 9 for the length.
| constexpr u8 iface_desc_length = 9; | ||
| constexpr u8 iface_desc_type = 0x4; | ||
| constexpr u8 str_desc_type = 0x3; | ||
| constexpr u8 iad_length = 0x08; | ||
| constexpr u8 iad_type = 0x0B; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer these written out fully. interface and string and I'm not sure what iad stands for off the top of my head, so spelling this out would be helpful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even for just a mock?
| template<typename T> | ||
| bool span_eq(std::span<T> const lhs, std::span<T> const rhs) | ||
| { | ||
| if (lhs.size() != rhs.size()) { | ||
| return false; | ||
| } | ||
|
|
||
| for (size_t i = 0; i < lhs.size(); i++) { | ||
| if (lhs[i] != rhs[i]) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| template<typename T> | ||
| bool span_ne(std::span<T> const lhs, std::span<T> const rhs) | ||
| { | ||
| return !(lhs == rhs); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does std::ranges::equals(lhs, rhs) not work in this situation?
| strong_ptr<std::array<configuration, num_configs>> const& p_configs, | ||
| u16 p_lang_str, // NOLINT | ||
| u8 p_starting_str_idx, | ||
| bool enumerate_immediately = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: I'm not a fan of the bool parameter here. And this is a pretty large number of parameters, so this looks like a good option for a struct parameter.
| strong_ptr<device> const& p_device, | ||
| strong_ptr<std::array<configuration, num_configs>> const& p_configs, | ||
| u16 p_lang_str, // NOLINT | ||
| u8 p_starting_str_idx, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should we allow the developer to choose this and why is it required? Is there some feature that gets unlocked from this depending on what value is set? Otherwise, this is laying a trap for someone when used. If you set this too low, they get an error. Set it too high, get an error. Or we can automate this and remove the error path completely.
| } | ||
|
|
||
| std::u16string_view name; | ||
| std::pmr::vector<strong_ptr<interface>> interfaces; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using hal::allocated_buffer<strong_ptr<interface>> instead of vector. We don't need to resize the array after construction, and thus all of its code needed to handle pushing and resizing can be eliminated. This way we pay for only what we needed which is a pointer, a length, and the allocator that created.
#include <libhal/allocated_buffer.hpp>It was meant for just buffers but its usable for any type. (maybe I should make an alias for it thats dynamic_array).
| if (enumerate_immediately) { | ||
| enumerate(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how I feel about this. My current opinion is that we should remove this as the operation isn't very async at the moment. Its like calling a scheduler and not expecting to get back control of the code beyond that point if the usb host is not connected.
| } | ||
| } | ||
|
|
||
| void enumerate() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is purely a suggestion but I think we might benefit from this rename:
| void enumerate() | |
| void enumerate_sync_prototype0() |
Why? We can provide this temporary API that we plan to deprecate in the future. This way we can work with the experimental stuff while preventing the API from being broken. This will allow us to publish the code and leave space for a better implementation in the future. Because making this async may require a breaking API change. Or a new API called enumerate2().
Implemented a USB enumerator that can be used in various projects. This is meant as a default and reference implementation of an enumerator using the libhal USB system.