Skip to content
File renamed without changes.
2 changes: 1 addition & 1 deletion v5/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def build_requirements(self):
self.test_requires("boost-ext-ut/2.1.0")

def requirements(self):
self.requires("libhal/[^4.21.0]", transitive_headers=True)
self.requires("libhal/[^4.22.0]", transitive_headers=True)

def layout(self):
cmake_layout(self)
Expand Down
7 changes: 5 additions & 2 deletions v5/include/libhal-util/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ class bit_value
constexpr bit_value& operator=(T p_initial_value)
{
m_value = p_initial_value;
return *this;
}

/**
Expand Down Expand Up @@ -621,7 +622,7 @@ class bit_value
* @return The represented value as type U.
*/
template<std::integral U>
[[nodiscard]] constexpr auto to()
[[nodiscard]] constexpr auto to() const
{
return static_cast<U>(m_value);
}
Expand All @@ -631,11 +632,13 @@ class bit_value
*
* @return The represented value.
*/
[[nodiscard]] constexpr T get()
[[nodiscard]] constexpr T get() const
{
return m_value;
}

constexpr bool operator==(bit_value const&) const = default;

protected:
T m_value;
};
Expand Down
2 changes: 1 addition & 1 deletion v5/include/libhal-util/mock/usb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <libhal/units.hpp>
#include <libhal/usb.hpp>

#include "../usb/utils.hpp"
#include "../usb/constants.hpp"

namespace hal::v5::usb {
constexpr u8 interface_description_length = 9;
Expand Down
2 changes: 1 addition & 1 deletion v5/include/libhal-util/usb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#pragma once

#include "usb/constants.hpp"
#include "usb/descriptors.hpp"
#include "usb/endpoints.hpp"
#include "usb/enumerator.hpp"
#include "usb/utils.hpp"
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@
namespace hal::v5::usb {

namespace constants {

constexpr byte device_descriptor_size = 18;
constexpr byte configuration_descriptor_size = 9;
constexpr byte inferface_descriptor_size = 9;
constexpr byte interface_descriptor_size = 9;
constexpr byte endpoint_descriptor_size = 7;
constexpr byte interface_association_descriptor_size = 0x08;

constexpr byte standard_request_size = 8;

} // namespace constants

// Maybe move these enum classes into the constants namespace
Expand Down Expand Up @@ -64,6 +61,14 @@ enum class class_code : hal::byte
vendor_specific = 0xFF // Vendor Specific
};

enum class transfer_type : hal::byte
{
control = 0x00,
isochronous = 0x01,
bulk = 0x02,
interrupt = 0x03,
};

// Default types
enum class descriptor_type : hal::byte
{
Expand Down
105 changes: 97 additions & 8 deletions v5/include/libhal-util/usb/descriptors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <libhal/units.hpp>
#include <libhal/usb.hpp>

#include "utils.hpp"
#include "constants.hpp"

// TODO(#95): Device qualifer descriptor (happens between device and config)
// TODO(#96): USB 3.x Superspeed descriptors (BOS Descriptor, Device Capability,
Expand All @@ -38,7 +38,6 @@ namespace hal::v5::usb {
class device
{
public:
template<size_t>
friend class enumerator;

struct device_arguments
Expand Down Expand Up @@ -192,7 +191,6 @@ concept usb_interface_concept = std::derived_from<T, interface>;
class configuration
{
public:
template<size_t>
friend class enumerator;

struct bitmap
Expand Down Expand Up @@ -249,11 +247,11 @@ class configuration
u8 idx = 0;

// Anything marked with 0 is to be populated at enumeration time
m_packed_arr[idx++] = 0; // 0 Total Length
m_packed_arr[idx++] = 0;
m_packed_arr[idx++] = 0; // 0 Total Length 1/2
m_packed_arr[idx++] = 0; // 1 Total Length 2/2
m_packed_arr[idx++] = m_interfaces.size(); // 2 number of interfaces
m_packed_arr[idx++] = 0; // 3 Config number
m_packed_arr[idx++] = 0; // 4 Configuration name string index
m_packed_arr[idx++] = 0; // 4 Configuration string index

m_packed_arr[idx++] = p_info.attributes.to_byte(); // 5
m_packed_arr[idx++] = p_info.max_power; // 6
Expand Down Expand Up @@ -315,22 +313,113 @@ class configuration
m_packed_arr[3] = p_value;
}

[[nodiscard]] constexpr u8 configuration_index() const
[[nodiscard]] constexpr u8 configuration_string_index() const
{
return m_packed_arr[4];
}
constexpr void set_configuration_index(u8 p_index)
constexpr void set_configuration_string_index(u8 p_index)
{
m_packed_arr[4] = p_index;
}

std::pmr::vector<strong_ptr<interface>> m_interfaces;
std::array<hal::byte, 7> m_packed_arr;
};

struct interface_descriptor_info
{
u8 interface_number;
u8 alternate_setting;
u8 num_endpoints;
class_code interface_class;
u8 interface_subclass;
u8 interface_protocol;
u8 interface_string_index;
};

constexpr auto generate_interface_descriptor(interface_descriptor_info p_info)
{
static constexpr u8 b_length = 0;
static constexpr u8 b_descriptor_type = 1;
static constexpr u8 b_interface_number = 2;
static constexpr u8 b_alternate_setting = 3;
static constexpr u8 b_num_endpoints = 4;
static constexpr u8 b_interface_class = 5;
static constexpr u8 b_interface_sub_class = 6;
static constexpr u8 b_interface_protocol = 7;
static constexpr u8 i_interface = 8;

std::array<byte, constants::interface_descriptor_size> descriptor{};

descriptor[b_length] = static_cast<byte>(descriptor.size());
descriptor[b_descriptor_type] = static_cast<byte>(descriptor_type::interface);
descriptor[b_interface_number] = p_info.interface_number;
descriptor[b_alternate_setting] = p_info.alternate_setting;
descriptor[b_num_endpoints] = p_info.num_endpoints;
descriptor[b_interface_class] = static_cast<byte>(p_info.interface_class);
descriptor[b_interface_sub_class] = p_info.interface_subclass;
descriptor[b_interface_protocol] = p_info.interface_protocol;
descriptor[i_interface] = p_info.interface_string_index;

return descriptor;
}

template<typename T>
concept usb_endpoint_type = std::is_base_of_v<hal::usb::endpoint, T>;

constexpr auto generate_endpoint_descriptor(usb_endpoint_type auto& p_endpoint,
u8 p_interval)
{
using Endpoint = std::remove_reference_t<decltype(p_endpoint)>;
using hal::usb::bulk_in_endpoint;
using hal::usb::bulk_out_endpoint;
using hal::usb::interrupt_in_endpoint;
using hal::usb::interrupt_out_endpoint;

constexpr transfer_type type = [] {
if constexpr (std::is_base_of_v<bulk_in_endpoint, Endpoint> or
std::is_base_of_v<bulk_out_endpoint, Endpoint>) {
return transfer_type::bulk;
} else if constexpr (std::is_base_of_v<interrupt_in_endpoint, Endpoint> or
std::is_base_of_v<interrupt_out_endpoint, Endpoint>) {
return transfer_type::interrupt;
} else {
return transfer_type::control;
}
}();

static constexpr u8 b_length = 0;
static constexpr u8 b_descriptor_type = 1;
static constexpr u8 b_endpoint_address = 2;
static constexpr u8 bm_attributes = 3;
static constexpr u8 w_max_packet_size_lo = 4;
static constexpr u8 w_max_packet_size_hi = 5;
static constexpr u8 b_interval = 6;

std::array<byte, constants::endpoint_descriptor_size> descriptor{};

auto const ep_info = p_endpoint.info();

descriptor[b_length] = static_cast<byte>(descriptor.size());
descriptor[b_descriptor_type] = static_cast<byte>(descriptor_type::endpoint);
descriptor[b_endpoint_address] = ep_info.number;
descriptor[bm_attributes] = static_cast<byte>(type);

auto const max_packet_size_bytes = setup_packet::to_le_u16(ep_info.size);
descriptor[w_max_packet_size_lo] = max_packet_size_bytes[0];
descriptor[w_max_packet_size_hi] = max_packet_size_bytes[1];

descriptor[b_interval] = p_interval;

return descriptor;
}

} // namespace hal::v5::usb

namespace hal::usb {
using v5::usb::configuration;
using v5::usb::device;
using v5::usb::generate_endpoint_descriptor;
using v5::usb::generate_interface_descriptor;
using v5::usb::usb_interface_concept;
} // namespace hal::usb
Loading