From c7b2fa113c4038d97c6845232d2e5ac631369f0a Mon Sep 17 00:00:00 2001 From: Matthew Knight Date: Sat, 29 Aug 2026 23:43:35 -0700 Subject: [PATCH 1/3] Add an assert for microzig We don't get safety checks in release small, and release safe's optimizations often lead to larger binaries. This compitme configurable flag lets developers write tripwires and choose for themselves if they want to disable them. --- build.zig | 7 +++++++ core/src/microzig.zig | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/build.zig b/build.zig index 39562f9ab..52eea883e 100644 --- a/build.zig +++ b/build.zig @@ -278,6 +278,12 @@ pub fn MicroBuild(port_select: PortSelect) type { /// Dwarf format option for the firmware executable. dwarf_format: ?std.dwarf.Format = null, + + /// On embedded systems you're likely to use release-small for the + /// optimization mode in order to make your code fit on hardware. + /// This unfortunately turns off safety checks. Enabling this allows + /// you to have asserts run in release builds. + asserts: bool = false, }; /// Creates a new firmware for a given target. @@ -338,6 +344,7 @@ pub fn MicroBuild(port_select: PortSelect) type { config.addOption(?[]const u8, "board_name", if (maybe_board) |board| board.name else null); config.addOption(EndOfStack, "end_of_stack", end_of_stack); config.addOption(bool, "ram_image", target.ram_image); + config.addOption(bool, "asserts", options.asserts); const core_mod = b.createModule(.{ .root_source_file = mb.core_dep.path("src/microzig.zig"), diff --git a/core/src/microzig.zig b/core/src/microzig.zig index 4b348cad5..49d92f372 100644 --- a/core/src/microzig.zig +++ b/core/src/microzig.zig @@ -33,6 +33,18 @@ pub const mmio = @import("mmio.zig"); pub const utilities = @import("utilities.zig"); pub const Allocator = @import("allocator.zig"); +pub const AssertOptions = struct {}; + +pub fn assert(expr: bool, opts: AssertOptions) void { + _ = opts; + if (!config.asserts) + return; + + if (!expr) { + @panic("Assertion failed"); + } +} + /// The microzig default panic handler. Will disable interrupts and loop endlessly. pub const panic = std.debug.FullPanic(struct { pub fn panic_fn(message: []const u8, first_trace_address: ?usize) noreturn { From 744ee6ca5543e87642f7c582ca17283ac93fe9f0 Mon Sep 17 00:00:00 2001 From: Matthew Knight Date: Sat, 29 Aug 2026 23:52:05 -0700 Subject: [PATCH 2/3] Fix typo --- core/src/cpus/cortex_m.zig | 4 ++-- core/src/cpus/cortex_m/shared_types.zig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index ef3e1b906..2b0a49a9f 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -943,8 +943,8 @@ pub const debug = struct { context.xpsr, }); logger.err(" instruction bus error = {}", .{bfsr.instruction_bus_error}); - logger.err(" precice data bus error = {}", .{bfsr.precice_data_bus_error}); - logger.err(" imprecice data bus error = {}", .{bfsr.imprecice_data_bus_error}); + logger.err(" precise data bus error = {}", .{bfsr.precise_data_bus_error}); + logger.err(" imprecise data bus error = {}", .{bfsr.imprecise_data_bus_error}); logger.err(" unstacking exception error = {}", .{bfsr.unstacking_exception_error}); logger.err(" exception stacking error = {}", .{bfsr.exception_stacking_error}); if (has_fpu) diff --git a/core/src/cpus/cortex_m/shared_types.zig b/core/src/cpus/cortex_m/shared_types.zig index 33bc24735..da52d6248 100644 --- a/core/src/cpus/cortex_m/shared_types.zig +++ b/core/src/cpus/cortex_m/shared_types.zig @@ -183,14 +183,14 @@ pub const scb = struct { /// 0 = no precise data bus error /// 1 = a data bus error has occurred, and the PC value stacked for the exception return points to the instruction that caused the fault. /// When the processor sets this bit is 1, it writes the faulting address to the BFAR. - precice_data_bus_error: bool, // [1], RW + precise_data_bus_error: bool, // [1], RW /// Imprecise data bus error: /// 0 = no imprecise data bus error /// 1 = a data bus error has occurred, but the return address in the stack frame is not related to the instruction that caused the error. /// When the processor sets this bit to 1, it does not write a fault address to the BFAR. /// This is an asynchronous fault. Therefore, if it is detected when the priority of the current process is higher than the BusFault priority, the BusFault becomes pending and becomes active only when the processor returns from all higher priority processes. If a precise fault occurs before the processor enters the handler for the imprecise BusFault, the handler detects both IMPRECISERR set to 1 and one of the precise fault status bits set to 1. - imprecice_data_bus_error: bool, // [2], RW + imprecise_data_bus_error: bool, // [2], RW /// BusFault on unstacking for a return from exception: /// 0 = no unstacking fault From 78bc5e2e35fe6d86fb7be46234d85721f42e3374 Mon Sep 17 00:00:00 2001 From: Matthew Knight Date: Sat, 29 Aug 2026 23:55:28 -0700 Subject: [PATCH 3/3] USB improvements This patch makes a general EndianInt type, and moves it into core. I found it super useful for SCSI in the SYCL Badge. I also set up an abstraction so you can switch on the setup request with packet structs. --- core/src/core.zig | 2 + core/src/core/mem.zig | 19 +++ core/src/core/usb.zig | 42 +++--- core/src/core/usb/descriptor.zig | 65 +++++----- core/src/core/usb/descriptor/cdc.zig | 8 +- core/src/core/usb/drivers/CDC.zig | 23 ++-- core/src/core/usb/drivers/EchoExample.zig | 6 +- core/src/core/usb/drivers/hid.zig | 22 ++-- core/src/core/usb/types.zig | 122 ++++++++++-------- drivers/src/sensor/TLV493D.zig | 1 + examples/nordic/nrf5x/src/usb_hid.zig | 10 +- examples/raspberrypi/rp2xxx/src/usb_hid.zig | 10 +- modules/rtt/src/rtt.zig | 22 ++-- port/nordic/nrf5x/src/hal/usbd.zig | 22 ++-- port/raspberrypi/rp2xxx/src/hal.zig | 1 + .../raspberrypi/rp2xxx/src/hal/pio/common.zig | 2 +- port/raspberrypi/rp2xxx/src/hal/usb.zig | 14 +- port/wch/ch32v/src/hals/usbfs.zig | 48 +++---- port/wch/ch32v/src/hals/usbhs.zig | 54 ++++---- 19 files changed, 272 insertions(+), 221 deletions(-) create mode 100644 core/src/core/mem.zig diff --git a/core/src/core.zig b/core/src/core.zig index 74a647c1e..0a16b37cf 100644 --- a/core/src/core.zig +++ b/core/src/core.zig @@ -3,6 +3,8 @@ pub const heap = @import("core/heap.zig"); pub const usb = @import("core/usb.zig"); pub const arm_semihosting = @import("core/arm_semihosting.zig"); +pub const mem = @import("core/mem.zig"); + test "core tests" { _ = usb; _ = heap; diff --git a/core/src/core/mem.zig b/core/src/core/mem.zig new file mode 100644 index 000000000..046530ad0 --- /dev/null +++ b/core/src/core/mem.zig @@ -0,0 +1,19 @@ +const std = @import("std"); + +pub fn EndianInt(comptime T: type, e: std.lang.Endian) type { + return packed struct(T) { + raw: T, + + pub fn from(val: T) @This() { + return .{ .raw = std.mem.nativeTo(T, val, e) }; + } + + pub fn native(self: @This()) T { + return std.mem.toNative(T, self.raw, e); + } + + pub fn format(self: @This(), writer: *std.Io.Writer) !void { + try writer.print("{}", .{self.native()}); + } + }; +} diff --git a/core/src/core/usb.zig b/core/src/core/usb.zig index 497c7a817..a21e9e554 100644 --- a/core/src/core/usb.zig +++ b/core/src/core/usb.zig @@ -369,8 +369,8 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { const const_ep_handlers = ep_handlers; const DriverConfig = @Struct(.@"extern", null, &field_names, &field_types, &field_attrs); - const idx_in = @backingInt(types.Dir.In); - const idx_out = @backingInt(types.Dir.Out); + const idx_in = @backingInt(types.Dir.in); + const idx_out = @backingInt(types.Dir.out); break :blk .{ .device_descriptor = desc_device, .config_descriptor = extern struct { @@ -387,8 +387,8 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { .string_descriptors = const_alloc.string_descriptors(config.language), .handlers_itf = itf_handlers, .handlers_ep = struct { - In: ep_handlers_types[idx_in] = const_ep_handlers[idx_in], - Out: ep_handlers_types[idx_out] = const_ep_handlers[idx_out], + in: ep_handlers_types[idx_in] = const_ep_handlers[idx_in], + out: ep_handlers_types[idx_out] = const_ep_handlers[idx_out], }{}, .drivers_ep = ep_handler_drivers, .DriverAlloc = @Struct( @@ -444,15 +444,15 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { log.debug("on_setup_req", .{}); const ret = switch (setup.request_type.recipient) { - .Device => self.process_device_setup(device_itf, setup), - .Interface => self.process_interface_setup(setup), + .device => self.process_device_setup(device_itf, setup), + .interface => self.process_interface_setup(setup), else => nak, }; if (ret) |data| { if (data.len == 0) device_itf.ep_ack(.ep0) else { - const limited = data[0..@min(data.len, setup.length.into())]; + const limited = data[0..@min(data.len, setup.length.native())]; const len = device_itf.ep_writev(.ep0, &.{limited}); assert(len <= device_descriptor.max_packet_size0); self.tx_slice = limited[len..]; @@ -512,20 +512,20 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { fn process_device_setup(self: *@This(), device_itf: *DeviceInterface, setup: *const types.SetupPacket) ?[]const u8 { switch (setup.request_type.type) { - .Standard => { + .standard => { const request: types.SetupRequest = @fromBackingInt(setup.request); log.debug("Device setup: {any}", .{request}); switch (request) { - .GetStatus => { + .get_status => { const attr = config_descriptor.first.attributes; const status: types.DeviceStatus = comptime .create(attr.self_powered, false); return std.mem.asBytes(&status); }, - .SetAddress => self.new_address = @truncate(setup.value.into()), - .SetConfiguration => self.process_set_config(device_itf, setup.value.into()), - .GetDescriptor => return get_descriptor(setup.value.into()), - .SetFeature => { - const feature: types.FeatureSelector = @fromBackingInt(@intCast(setup.value.into() >> 8)); + .set_address => self.new_address = @truncate(setup.value.native()), + .set_configuration => self.process_set_config(device_itf, setup.value.native()), + .get_descriptor => return get_descriptor(setup.value.native()), + .set_feature => { + const feature: types.FeatureSelector = @fromBackingInt(@intCast(setup.value.native() >> 8)); switch (feature) { .DeviceRemoteWakeup, .EndpointHalt => {}, // TODO: https://github.com/ZigEmbeddedGroup/microzig/issues/453 @@ -548,7 +548,7 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { } fn process_interface_setup(self: *@This(), setup: *const types.SetupPacket) ?[]const u8 { - const itf_num: u8 = @truncate(setup.index.into()); + const itf_num: u8 = @truncate(setup.index.native()); switch (itf_num) { inline else => |itf| if (comptime itf < handlers_itf.len) { const drv = handlers_itf[itf]; @@ -567,10 +567,10 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { const desc_idx: u8 = @truncate(value); log.debug("Request for {any} descriptor {}", .{ desc_type, desc_idx }); return switch (desc_type) { - .Device => asBytes(&device_descriptor), - .DeviceQualifier => asBytes(comptime &device_descriptor.qualifier()), - .Configuration => asBytes(&config_descriptor), - .String => if (desc_idx < string_descriptors.len) + .device => asBytes(&device_descriptor), + .device_qualifier => asBytes(comptime &device_descriptor.qualifier()), + .configuration => asBytes(&config_descriptor), + .string => if (desc_idx < string_descriptors.len) string_descriptors[desc_idx].data else { log.warn( @@ -606,7 +606,7 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { // Open OUT endpoint first so that the driver can call ep_listen in init inline for (desc_info.field_names, desc_info.field_types) |field_name, field_type| { const desc = &@field(cfg, field_name); - if (comptime field_type == descriptor.Endpoint and desc.endpoint.dir == .Out) + if (comptime field_type == descriptor.Endpoint and desc.endpoint.dir == .out) device_itf.ep_open(desc); } @@ -620,7 +620,7 @@ pub fn DeviceController(config: Config, driver_args: config.DriverArgs()) type { // Open IN endpoint last so that callbacks can happen inline for (desc_info.field_names, desc_info.field_types) |field_name, field_type| { const desc = &@field(cfg, field_name); - if (comptime field_type == descriptor.Endpoint and desc.endpoint.dir == .In) + if (comptime field_type == descriptor.Endpoint and desc.endpoint.dir == .in) device_itf.ep_open(desc); } } diff --git a/core/src/core/usb/descriptor.zig b/core/src/core/usb/descriptor.zig index 81e21aa5f..581e68a70 100644 --- a/core/src/core/usb/descriptor.zig +++ b/core/src/core/usb/descriptor.zig @@ -1,4 +1,7 @@ const std = @import("std"); + +const EndianInt = @import("../mem.zig").EndianInt; + const types = @import("types.zig"); const assert = std.debug.assert; @@ -9,19 +12,19 @@ test "descriptor tests" { } pub const Type = enum(u8) { - Device = 0x01, - Configuration = 0x02, - String = 0x03, - Interface = 0x04, - Endpoint = 0x05, - DeviceQualifier = 0x06, - InterfaceAssociation = 0x0B, - BOS = 0x0F, - CsDevice = 0x21, - CsConfig = 0x22, - CsString = 0x23, - CsInterface = 0x24, - CsEndpoint = 0x25, + device = 0x01, + configuration = 0x02, + string = 0x03, + interface = 0x04, + endpoint = 0x05, + device_qualifier = 0x06, + interface_association = 0x0B, + bos = 0x0F, + cs_device = 0x21, + cs_config = 0x22, + cs_string = 0x23, + cs_interface = 0x24, + cs_endpoint = 0x25, _, }; @@ -38,7 +41,7 @@ pub const Device = extern struct { length: u8 = @sizeOf(@This()), /// Type of this descriptor, must be `DeviceQualifier`. - descriptor_type: Type = .DeviceQualifier, + descriptor_type: Type = .device_qualifier, /// Specification version as Binary Coded Decimal bcd_usb: types.Version, /// Class, subclass and protocol of device. @@ -58,7 +61,7 @@ pub const Device = extern struct { length: u8 = @sizeOf(@This()), /// Type of this descriptor, must be `Device`. - descriptor_type: Type = .Device, + descriptor_type: Type = .device, /// Specification version as Binary Coded Decimal bcd_usb: types.Version, /// Class, subclass and protocol of device. @@ -66,9 +69,9 @@ pub const Device = extern struct { /// Maximum length of data this device can move. max_packet_size0: u8, /// ID of product vendor. - vendor: types.U16_Le align(1), + vendor: EndianInt(u16, .little) align(1), /// ID of product. - product: types.U16_Le align(1), + product: EndianInt(u16, .little) align(1), /// Device version number as Binary Coded Decimal. bcd_device: types.Version, /// Index of manufacturer name in string descriptor table. @@ -123,11 +126,11 @@ pub const Configuration = extern struct { length: u8 = @sizeOf(@This()), /// Type of this descriptor, must be `Configuration`. - descriptor_type: Type = .Configuration, + descriptor_type: Type = .configuration, /// Total length of all descriptors in this configuration, concatenated. /// This will include this descriptor, plus at least one interface /// descriptor, plus each interface descriptor's endpoint descriptors. - total_length: types.U16_Le align(1), + total_length: EndianInt(u16, .little) align(1), /// Number of interface descriptors in this configuration. num_interfaces: u8, /// Number to use when requesting this configuration via a @@ -153,8 +156,8 @@ pub const String = struct { pub fn from_lang(comptime lang: Language) @This() { const ret: *const extern struct { length: u8 = @sizeOf(@This()), - descriptor_type: Type = .String, - lang: types.U16_Le align(1), + descriptor_type: Type = .string, + lang: EndianInt(u16, .little) align(1), } = comptime &.{ .lang = .from(@backingInt(lang)) }; return .{ .data = std.mem.asBytes(ret) }; } @@ -162,7 +165,7 @@ pub const String = struct { pub fn from_str(comptime string: []const u8) @This() { @setEvalBranchQuota(10000); const encoded: []const u8 = std.mem.sliceAsBytes(std.unicode.utf8ToUtf16LeStringLiteral(string)); - return .{ .data = &[2]u8{ encoded.len + 2, @backingInt(Type.String) } ++ encoded }; + return .{ .data = &[2]u8{ encoded.len + 2, @backingInt(Type.string) } ++ encoded }; } }; @@ -196,7 +199,7 @@ pub const Endpoint = extern struct { length: u8 = @sizeOf(@This()), /// Type of this descriptor, must be `Endpoint`. - descriptor_type: Type = .Endpoint, + descriptor_type: Type = .endpoint, /// Address of this endpoint, where the bottom 4 bits give the endpoint /// number (0..15) and the top bit distinguishes IN (1) from OUT (0). endpoint: types.Endpoint, @@ -204,7 +207,7 @@ pub const Endpoint = extern struct { /// control the transfer type using the values from `TransferType`. attributes: Attributes, /// Maximum packet size this endpoint can accept/produce. - max_packet_size: types.U16_Le align(1), + max_packet_size: EndianInt(u16, .little) align(1), /// Interval for polling interrupt/isochronous endpoints (which we don't /// currently support) in milliseconds. interval: u8, @@ -246,7 +249,7 @@ pub const Interface = extern struct { length: u8 = @sizeOf(@This()), /// Type of this descriptor, must be `Interface`. - descriptor_type: Type = .Interface, + descriptor_type: Type = .interface, /// ID of this interface. interface_number: u8, /// Allows a single `interface_number` to have several alternate interface @@ -269,8 +272,8 @@ pub const InterfaceAssociation = extern struct { } length: u8 = @sizeOf(@This()), - // Type of this descriptor, must be `InterfaceAssociation`. - descriptor_type: Type = .InterfaceAssociation, + // Type of this descriptor, must be `interface_association`. + descriptor_type: Type = .interface_association, // First interface number of the set of interfaces that follow this // descriptor. first_interface: u8, @@ -296,8 +299,8 @@ pub const BOS = struct { const data: []const u8 = ""; const header: []const u8 = std.mem.asBytes(&extern struct { length: u8 = @sizeOf(@This()), - descriptor_type: Type = .BOS, - total_length: types.U16_Le align(1) = .from(@sizeOf(@This()) + data.len), + descriptor_type: Type = .bos, + total_length: EndianInt(u16, .little) align(1) = .from(@sizeOf(@This()) + data.len), num_descriptors: u8 = @intCast(objects.len), }{}); return .{ .data = header ++ data }; @@ -364,7 +367,7 @@ pub const HID = extern struct { length: u8 = @sizeOf(@This()), /// Type of this descriptor - descriptor_type: Type = .CsDevice, + descriptor_type: Type = .cs_device, /// Numeric expression identifying the HID Class Specification release /// 1.11 seems to be the only one bcd_hid: types.Version = .v1_11, @@ -375,5 +378,5 @@ pub const HID = extern struct { /// Type of HID class report report_type: CsType = .Report, /// The total size of the Report descriptor - report_length: types.U16_Le align(1), + report_length: EndianInt(u16, .little) align(1), }; diff --git a/core/src/core/usb/descriptor/cdc.zig b/core/src/core/usb/descriptor/cdc.zig index cd487d172..03fd20d40 100644 --- a/core/src/core/usb/descriptor/cdc.zig +++ b/core/src/core/usb/descriptor/cdc.zig @@ -17,7 +17,7 @@ pub const Header = extern struct { length: u8 = @sizeOf(@This()), // Type of this descriptor, must be `ClassSpecific`. - descriptor_type: Type = .CsInterface, + descriptor_type: Type = .cs_interface, // Subtype of this descriptor, must be `Header`. descriptor_subtype: SubType = .Header, // USB Class Definitions for Communication Devices Specification release @@ -44,7 +44,7 @@ pub const CallManagement = extern struct { length: u8 = @sizeOf(@This()), // Type of this descriptor, must be `ClassSpecific`. - descriptor_type: Type = .CsInterface, + descriptor_type: Type = .cs_interface, // Subtype of this descriptor, must be `CallManagement`. descriptor_subtype: SubType = .CallManagement, // Capabilities. Should be 0x00 for use as a serial device. @@ -76,7 +76,7 @@ pub const AbstractControlModel = extern struct { length: u8 = @sizeOf(@This()), // Type of this descriptor, must be `ClassSpecific`. - descriptor_type: Type = .CsInterface, + descriptor_type: Type = .cs_interface, // Subtype of this descriptor, must be `AbstractControlModel`. descriptor_subtype: SubType = .AbstractControlModel, // Capabilities. Should be 0x02 for use as a serial device. @@ -91,7 +91,7 @@ pub const Union = extern struct { length: u8 = @sizeOf(@This()), // Type of this descriptor, must be `ClassSpecific`. - descriptor_type: Type = .CsInterface, + descriptor_type: Type = .cs_interface, // Subtype of this descriptor, must be `Union`. descriptor_subtype: SubType = .Union, // The interface number of the communication or data class interface diff --git a/core/src/core/usb/drivers/CDC.zig b/core/src/core/usb/drivers/CDC.zig index 7712e5dcb..f6ab55abb 100644 --- a/core/src/core/usb/drivers/CDC.zig +++ b/core/src/core/usb/drivers/CDC.zig @@ -1,6 +1,11 @@ const std = @import("std"); +const microzig = @import("../../../microzig.zig"); +const assert = microzig.assert; + +const mem = @import("../../mem.zig"); +const EndianInt = mem.EndianInt; + const usb = @import("../../usb.zig"); -const assert = std.debug.assert; const log = std.log.scoped(.usb_cdc); /// CDC PSTN Subclass Management Element Requests @@ -40,7 +45,7 @@ pub const LineCoding = extern struct { _, }; - bit_rate: usb.types.U32_Le, + bit_rate: EndianInt(u32, .little), stop_bits: StopBits, parity: Parity, data_bits: u8, @@ -127,7 +132,7 @@ pub const Descriptor = extern struct { // are expressed directly in milliseconds. Keep the intended // polling period at 16 ms for both speeds. .ep_notifi = .interrupt( - alloc.next_ep(.In), + alloc.next_ep(.in), 8, if (max_supported_packet_size > 64) 8 else 16, ), @@ -138,8 +143,8 @@ pub const Descriptor = extern struct { .interface_triple = .from(.CDC_Data, .Unused, .NoneRequired), .interface_s = alloc.string(strings.itf_data), }, - .ep_out = .bulk(alloc.next_ep(.Out), max_supported_packet_size), - .ep_in = .bulk(alloc.next_ep(.In), max_supported_packet_size), + .ep_out = .bulk(alloc.next_ep(.out), max_supported_packet_size), + .ep_in = .bulk(alloc.next_ep(.in), max_supported_packet_size), }, .alloc_bytes = 2 * max_supported_packet_size, }; @@ -215,7 +220,7 @@ pub fn flush(self: *@This()) bool { assert(self.tx_end == self.device.ep_writev( self.descriptor.ep_in.endpoint.num, &.{self.tx_data[0..self.tx_end]}, - )); + ), .{}); self.tx_end = 0; return true; } @@ -223,8 +228,8 @@ pub fn flush(self: *@This()) bool { // Called when the host selects a configuration. pub fn init(self: *@This(), desc: *const Descriptor, device: *usb.DeviceInterface, data: []u8) void { const len_half = @divExact(data.len, 2); - assert(len_half == desc.ep_in.max_packet_size.into()); - assert(len_half == desc.ep_out.max_packet_size.into()); + assert(len_half == desc.ep_in.max_packet_size.native(), .{}); + assert(len_half == desc.ep_out.max_packet_size.native(), .{}); self.* = .{ .device = device, .descriptor = desc, @@ -248,7 +253,7 @@ pub fn init(self: *@This(), desc: *const Descriptor, device: *usb.DeviceInterfac /// Called by DeviceController when the interface number matches this driver. pub fn class_request(self: *@This(), setup: *const usb.types.SetupPacket) ?[]const u8 { const mgmt_request: ManagementRequestType = @fromBackingInt(setup.request); - log.debug("cdc setup: {any} {} {}", .{ mgmt_request, setup.length.into(), setup.value.into() }); + log.debug("cdc setup: {any} {} {}", .{ mgmt_request, setup.length.native(), setup.value.native() }); return switch (mgmt_request) { .SetLineCoding => usb.ack, // we should handle data phase somehow to read sent line_coding diff --git a/core/src/core/usb/drivers/EchoExample.zig b/core/src/core/usb/drivers/EchoExample.zig index 51c40c9d0..f78a4bc6f 100644 --- a/core/src/core/usb/drivers/EchoExample.zig +++ b/core/src/core/usb/drivers/EchoExample.zig @@ -57,7 +57,7 @@ tx_ready: std.atomic.Value(bool), /// This function is called when the host chooses a configuration that contains this driver. `self` /// points to undefined memory. `data` is of the length specified in `Descriptor.create()`. pub fn init(self: *@This(), desc: *const Descriptor, device: *usb.DeviceInterface, data: []u8) void { - assert(data.len == desc.ep_in.max_packet_size.into()); + assert(data.len == desc.ep_in.max_packet_size.native()); self.* = .{ .device = device, .descriptor = desc, @@ -66,7 +66,7 @@ pub fn init(self: *@This(), desc: *const Descriptor, device: *usb.DeviceInterfac }; device.ep_listen( desc.ep_out.endpoint.num, - @intCast(desc.ep_out.max_packet_size.into()), + @intCast(desc.ep_out.max_packet_size.native()), ); } @@ -74,7 +74,7 @@ pub fn init(self: *@This(), desc: *const Descriptor, device: *usb.DeviceInterfac /// Data returned by this function is sent on endpoint 0. pub fn class_request(self: *@This(), setup: *const usb.types.SetupPacket) ?[]const u8 { _ = self; - log.debug("setup: {x}, {}, {}", .{ setup.request, setup.length.into(), setup.value.into() }); + log.debug("setup: {x}, {}, {}", .{ setup.request, setup.length.native(), setup.value.native() }); return usb.ack; } diff --git a/core/src/core/usb/drivers/hid.zig b/core/src/core/usb/drivers/hid.zig index 7ac5b6c2e..49205c845 100644 --- a/core/src/core/usb/drivers/hid.zig +++ b/core/src/core/usb/drivers/hid.zig @@ -151,8 +151,8 @@ pub const ReportItem = union(enum) { pub fn main_io(dir: usb.types.Dir, payload: InputOutput) @This() { return switch (dir) { - .In => .{ .main_input = payload }, - .Out => .{ .main_output = payload }, + .in => .{ .main_input = payload }, + .out => .{ .main_output = payload }, }; } @@ -356,12 +356,12 @@ pub fn InterruptDriver(options: InterruptDriverOptions) type { .report_length = .from(report_descriptor.len), }, .ep_out = .interrupt( - alloc.next_ep(.Out), + alloc.next_ep(.out), @sizeOf(OutReport), desc_options.poll_interval, ), .ep_in = .interrupt( - alloc.next_ep(.In), + alloc.next_ep(.in), @sizeOf(InReport), desc_options.poll_interval, ), @@ -389,23 +389,23 @@ pub fn InterruptDriver(options: InterruptDriverOptions) type { }; self.device.ep_listen( self.descriptor.ep_out.endpoint.num, - @intCast(self.descriptor.ep_out.max_packet_size.into()), + @intCast(self.descriptor.ep_out.max_packet_size.native()), ); } pub fn class_request(self: *@This(), setup: *const usb.types.SetupPacket) ?[]const u8 { log.debug("class_request {any}", .{setup}); switch (setup.request_type.type) { - .Standard => { - const hid_desc_type: usb.descriptor.HID.CsType = @fromBackingInt(@intCast(setup.value.into() >> 8)); + .standard => { + const hid_desc_type: usb.descriptor.HID.CsType = @fromBackingInt(@intCast(setup.value.native() >> 8)); const request_code: usb.types.SetupRequest = @fromBackingInt(setup.request); - if (request_code == .GetDescriptor and hid_desc_type == .HID) + if (request_code == .get_descriptor and hid_desc_type == .HID) return std.mem.asBytes(&self.descriptor.hid) - else if (request_code == .GetDescriptor and hid_desc_type == .Report) + else if (request_code == .get_descriptor and hid_desc_type == .Report) return report_descriptor; }, - .Class => { + .class => { const hid_request_type: RequestType = @fromBackingInt(setup.request); switch (hid_request_type) { .SetIdle => { @@ -480,7 +480,7 @@ pub fn InterruptDriver(options: InterruptDriverOptions) type { var report: OutReport = undefined; const ep_num = self.descriptor.ep_out.endpoint.num; const len = self.device.ep_readv(ep_num, &.{std.mem.asBytes(&report)}); - self.device.ep_listen(ep_num, @intCast(self.descriptor.ep_out.max_packet_size.into())); + self.device.ep_listen(ep_num, @intCast(self.descriptor.ep_out.max_packet_size.native())); log.debug("received report {} {any}", .{ len, report }); diff --git a/core/src/core/usb/types.zig b/core/src/core/usb/types.zig index c80c6e014..658b3f706 100644 --- a/core/src/core/usb/types.zig +++ b/core/src/core/usb/types.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const EndianInt = @import("../mem.zig").EndianInt; pub const ClassSubclassProtocol = extern struct { /// Class of device, giving a broad functional area. @@ -292,14 +293,14 @@ pub const TransferType = enum(u2) { /// The types of USB SETUP requests that we understand. pub const SetupRequest = enum(u8) { - GetStatus = 0x00, - ClearFeature = 0x02, - SetFeature = 0x03, - SetAddress = 0x05, - GetDescriptor = 0x06, - SetDescriptor = 0x07, - GetConfiguration = 0x08, - SetConfiguration = 0x09, + get_status = 0x00, + clear_feature = 0x01, + set_feature = 0x03, + set_address = 0x05, + get_descriptor = 0x06, + set_descriptor = 0x07, + get_configuration = 0x08, + set_configuration = 0x09, _, }; @@ -330,8 +331,8 @@ pub const FeatureSelector = enum(u8) { /// and IN (device-to-host). In the vast majority of cases, OUT is represented /// by a 0 byte, and IN by an `0x80` byte. pub const Dir = enum(u1) { - Out = 0, - In = 1, + out = 0, + in = 1, }; pub const Endpoint = packed struct(u8) { @@ -360,11 +361,11 @@ pub const Endpoint = packed struct(u8) { dir: Dir, pub inline fn out(num: Num) @This() { - return .{ .num = num, .dir = .Out }; + return .{ .num = num, .dir = .out }; } pub inline fn in(num: Num) @This() { - return .{ .num = num, .dir = .In }; + return .{ .num = num, .dir = .in }; } }; @@ -373,20 +374,23 @@ pub const RequestType = packed struct(u8) { type: Type, direction: Dir, - const Type = enum(u2) { - Standard, - Class, - Vendor, - Other, + pub const Type = enum(u2) { + standard, + class, + vendor, + other, }; - const Recipient = enum(u5) { - Device, - Interface, - Endpoint, - Other, + pub const Recipient = enum(u5) { + device, + interface, + endpoint, + other, _, // Reserved }; + + // The standard requests + pub const set_address: RequestType = .{}; }; /// Layout of an 8-byte USB SETUP packet. @@ -398,12 +402,54 @@ pub const SetupPacket = packed struct(u64) { /// conflict. request: u8, /// A simple argument of up to 16 bits, specific to the request. - value: U16_Le, - index: U16_Le, + value: EndianInt(u16, .little), + index: EndianInt(u16, .little), /// If data will be transferred after this request (in the direction given /// by `request_type`), this gives the number of bytes (OUT) or maximum /// number of bytes (IN). - length: U16_Le, + length: EndianInt(u16, .little), + + pub fn format(self: SetupPacket, writer: *std.Io.Writer) !void { + try writer.print("request_type={} request={} value={} index={} length={}", .{ + self.request_type, + self.request, + self.value.native(), + self.index.native(), + self.length.native(), + }); + } + + pub fn to_standard_request(pkt: *const SetupPacket) *const StandardRequest { + return @ptrCast(pkt); + } + + /// A grouping of the first two fields so we can switch on them. + pub const StandardRequest = packed struct(u16) { + recipient: RequestType.Recipient, + type: RequestType.Type = .standard, + direction: Dir, + request: SetupRequest, + + // zig fmt: off + pub const clear_feature_device: StandardRequest = .{ .direction = .out, .recipient = .device, .request = .clear_feature }; + pub const clear_feature_interface: StandardRequest = .{ .direction = .out, .recipient = .interface, .request = .clear_feature }; + pub const clear_feature_endpoint: StandardRequest = .{ .direction = .out, .recipient = .endpoint, .request = .clear_feature }; + pub const set_address: StandardRequest = .{ .direction = .out, .recipient = .device, .request = .set_address }; + pub const set_configuration: StandardRequest = .{ .direction = .out, .recipient = .device, .request = .set_configuration }; + pub const set_descriptor: StandardRequest = .{ .direction = .out, .recipient = .device, .request = .set_descriptor }; + pub const set_feature_device: StandardRequest = .{ .direction = .out, .recipient = .device, .request = .set_feature }; + pub const set_feature_interface: StandardRequest = .{ .direction = .out, .recipient = .interface, .request = .set_feature }; + pub const set_feature_endpoint: StandardRequest = .{ .direction = .out, .recipient = .endpoint, .request = .set_feature }; + pub const set_interface: StandardRequest = .{ .direction = .out, .recipient = .interface, .request = .set_interface }; + pub const get_configuration: StandardRequest = .{ .direction = .in, .recipient = .device, .request = .get_configuration }; + pub const get_descriptor: StandardRequest = .{ .direction = .in, .recipient = .device, .request = .get_descriptor }; + pub const get_interface: StandardRequest = .{ .direction = .in, .recipient = .interface, .request = .get_interface }; + pub const get_status_device: StandardRequest = .{ .direction = .in, .recipient = .device, .request = .get_status }; + pub const get_status_interface: StandardRequest = .{ .direction = .in, .recipient = .interface, .request = .get_status }; + pub const get_status_endpoint: StandardRequest = .{ .direction = .in, .recipient = .endpoint, .request = .get_status }; + pub const synch_frame: StandardRequest = .{ .direction = .in, .recipient = .endpoint, .request = .synch_frame }; + // zig fmt: on + }; }; /// Represents USB or device version, in binary coded decimal. @@ -436,29 +482,3 @@ pub const Version = extern struct { /// Represents packet length. pub const Len = u11; - -/// u16 value, little endian regardless of native endianness. -pub const U16_Le = packed struct(u16) { - value_le: u16, - - pub fn from(val: u16) @This() { - return .{ .value_le = std.mem.nativeToLittle(u16, val) }; - } - - pub fn into(self: @This()) u16 { - return std.mem.littleToNative(u16, self.value_le); - } -}; - -/// u32 value, little endian regardless of native endianness. -pub const U32_Le = packed struct(u32) { - value_le: u32, - - pub fn from(val: u32) @This() { - return .{ .value_le = std.mem.nativeToLittle(u32, val) }; - } - - pub fn into(self: @This()) u32 { - return std.mem.littleToNative(u32, self.value_le); - } -}; diff --git a/drivers/src/sensor/TLV493D.zig b/drivers/src/sensor/TLV493D.zig index 9976e342a..d1366d120 100644 --- a/drivers/src/sensor/TLV493D.zig +++ b/drivers/src/sensor/TLV493D.zig @@ -433,6 +433,7 @@ pub const TLV493D = struct { /// Map I2C_Device errors to device errors fn map_error(err: I2C_Device.InterfaceError) Error { + std.log.info("mapping error: {}", .{err}); return switch (err) { I2C_Device.Error.NoAcknowledge, I2C_Device.Error.Timeout, diff --git a/examples/nordic/nrf5x/src/usb_hid.zig b/examples/nordic/nrf5x/src/usb_hid.zig index 83f56a547..717850901 100644 --- a/examples/nordic/nrf5x/src/usb_hid.zig +++ b/examples/nordic/nrf5x/src/usb_hid.zig @@ -93,29 +93,29 @@ const Keyboard = usb.drivers.hid.InterruptDriver(.{ .usage_range = .{ 0xE0, 0xE7 }, .count = 8, .Child = bool, - .dir = .In, + .dir = .in, .type = .dynamic, } }, // Reserved 8 bits - .{ .data_static = .{ .In, u8 } }, + .{ .data_static = .{ .in, u8 } }, // Output: indicator LEDs .{ .data = .{ .usage = .{ .global_page = .led }, .usage_range = .{ 1, 5 }, .count = 5, .Child = bool, - .dir = .Out, + .dir = .out, .type = .dynamic, } }, // Padding - .{ .data_static = .{ .Out, u3 } }, + .{ .data_static = .{ .out, u3 } }, // Input: up to 6 pressed key codes .{ .data = .{ .usage = .{ .global_page = .keyboard }, .usage_range = .{ 0x00, 0xff }, .count = 6, .Child = u8, - .dir = .In, + .dir = .in, .type = .selector, } }, // End diff --git a/examples/raspberrypi/rp2xxx/src/usb_hid.zig b/examples/raspberrypi/rp2xxx/src/usb_hid.zig index a6262915c..90bc4d18e 100644 --- a/examples/raspberrypi/rp2xxx/src/usb_hid.zig +++ b/examples/raspberrypi/rp2xxx/src/usb_hid.zig @@ -86,29 +86,29 @@ const Keyboard = usb.drivers.hid.InterruptDriver(.{ .usage_range = .{ 0xE0, 0xE7 }, .count = 8, .Child = bool, - .dir = .In, + .dir = .in, .type = .dynamic, } }, // Reserved 8 bits - .{ .data_static = .{ .In, u8 } }, + .{ .data_static = .{ .in, u8 } }, // Output: indicator LEDs .{ .data = .{ .usage = .{ .global_page = .led }, .usage_range = .{ 1, 5 }, .count = 5, .Child = bool, - .dir = .Out, + .dir = .out, .type = .dynamic, } }, // Padding - .{ .data_static = .{ .Out, u3 } }, + .{ .data_static = .{ .out, u3 } }, // Input: up to 6 pressed key codes .{ .data = .{ .usage = .{ .global_page = .keyboard }, .usage_range = .{ 0x00, 0xff }, .count = 6, .Child = u8, - .dir = .In, + .dir = .in, .type = .selector, } }, // End diff --git a/modules/rtt/src/rtt.zig b/modules/rtt/src/rtt.zig index c20d90992..b9ce179ed 100644 --- a/modules/rtt/src/rtt.zig +++ b/modules/rtt/src/rtt.zig @@ -35,9 +35,9 @@ const Header = extern struct { pub const channel = struct { pub const Mode = enum(usize) { - NoBlockSkip = 0, - NoBlockTrim = 1, - BlockIfFull = 2, + no_block_skip = 0, + no_block_trim = 1, + block_if_full = 2, _, }; @@ -161,15 +161,15 @@ pub const channel = struct { exclusive_access.lock_fn(exclusive_access.context); defer exclusive_access.unlock_fn(exclusive_access.context); switch (self.mode()) { - .NoBlockSkip => { + .no_block_skip => { if (bytes.len <= self.available_space()) { return self.write_available(bytes); } else return 0; }, - .NoBlockTrim => { + .no_block_trim => { return self.write_available(bytes); }, - .BlockIfFull => { + .block_if_full => { return self.write_blocking(bytes); }, _ => unreachable, @@ -182,15 +182,15 @@ pub const channel = struct { exclusive_access.lock_fn(exclusive_access.context); defer exclusive_access.unlock_fn(exclusive_access.context); switch (self.mode()) { - .NoBlockSkip => { + .no_block_skip => { if (bytes.len <= self.available_space()) { _ = self.write_available(bytes); } }, - .NoBlockTrim => { + .no_block_trim => { _ = self.write_available(bytes); }, - .BlockIfFull => { + .block_if_full => { _ = self.write_blocking(bytes); }, _ => unreachable, @@ -488,8 +488,8 @@ fn ControlBlock(comptime up_channels: []const channel.Config, comptime down_chan /// Compile time configuration of RTT instance pub const Config = struct { - up_channels: []const channel.Config = &[_]channel.Config{.{ .name = "Terminal", .buffer_size = 1024, .mode = .NoBlockSkip }}, - down_channels: []const channel.Config = &[_]channel.Config{.{ .name = "Terminal", .buffer_size = 16, .mode = .BlockIfFull }}, + up_channels: []const channel.Config = &[_]channel.Config{.{ .name = "Terminal", .buffer_size = 1024, .mode = .no_block_skip }}, + down_channels: []const channel.Config = &[_]channel.Config{.{ .name = "Terminal", .buffer_size = 16, .mode = .block_if_full }}, /// Optionally supply a custom implementation of exclusive access protection (lock/unlock), /// defaults to original Segger lock implementation when not provided, disables lock protection when /// provided with null. diff --git a/port/nordic/nrf5x/src/hal/usbd.zig b/port/nordic/nrf5x/src/hal/usbd.zig index fc58ee7f5..fa6583410 100644 --- a/port/nordic/nrf5x/src/hal/usbd.zig +++ b/port/nordic/nrf5x/src/hal/usbd.zig @@ -29,7 +29,7 @@ const PowerState = union(enum) { }; const EP0_State = struct { - direction: usb.types.Dir = .Out, + direction: usb.types.Dir = .out, remaining_size: u16 = 0, in_pending: bool = false, in_start_frame: u11 = 0, @@ -148,10 +148,10 @@ pub const USBD = struct { .length = .from(@as(u16, @intCast(peripherals.USBD.WLENGTHH.raw)) << 8 | @as(u16, @intCast(peripherals.USBD.WLENGTHL.raw))), }; self.ep0_state.direction = switch (peripherals.USBD.BMREQUESTTYPE.read().DIRECTION) { - .HostToDevice => .Out, - .DeviceToHost => .In, + .HostToDevice => .out, + .DeviceToHost => .in, }; - self.ep0_state.remaining_size = setup.length.into(); + self.ep0_state.remaining_size = setup.length.native(); controller.on_setup_req(&self.interface, &setup); } @@ -163,9 +163,9 @@ pub const USBD = struct { peripherals.USBD.EVENTS_EP0DATADONE.write_raw(0); self.ep0_state.in_pending = false; switch (self.ep0_state.direction) { - .In => controller.on_buffer(&self.interface, .in(.ep0)), + .in => controller.on_buffer(&self.interface, .in(.ep0)), // Control-OUT with data-phase is unhandled in the controller - .Out => peripherals.USBD.TASKS_EP0STATUS.write_raw(1), + .out => peripherals.USBD.TASKS_EP0STATUS.write_raw(1), } } @@ -377,12 +377,12 @@ pub const USBD = struct { const i = @backingInt(ep.num); const mask: u32 = @as(u32, 1) << i; switch (ep.dir) { - .In => { - self.eps_in[i].max_packet_size = desc.max_packet_size.into(); + .in => { + self.eps_in[i].max_packet_size = desc.max_packet_size.native(); peripherals.USBD.EPINEN.write_raw(peripherals.USBD.EPINEN.raw | mask); }, - .Out => { - self.eps_out[i].max_packet_size = desc.max_packet_size.into(); + .out => { + self.eps_out[i].max_packet_size = desc.max_packet_size.native(); peripherals.USBD.EPOUTEN.write_raw(peripherals.USBD.EPOUTEN.raw | mask); }, } @@ -390,7 +390,7 @@ pub const USBD = struct { const attr = desc.attributes; log.debug( "ep_open {t} {t}: {{ type: {t}, sync: {t}, usage: {t}, size: {} }}", - .{ ep.num, ep.dir, attr.transfer_type, attr.synchronisation, attr.usage, desc.max_packet_size.into() }, + .{ ep.num, ep.dir, attr.transfer_type, attr.synchronisation, attr.usage, desc.max_packet_size.native() }, ); } diff --git a/port/raspberrypi/rp2xxx/src/hal.zig b/port/raspberrypi/rp2xxx/src/hal.zig index 486df59ed..a289515f8 100644 --- a/port/raspberrypi/rp2xxx/src/hal.zig +++ b/port/raspberrypi/rp2xxx/src/hal.zig @@ -38,6 +38,7 @@ pub const time = @import("hal/time.zig"); pub const uart = @import("hal/uart.zig"); pub const usb = @import("hal/usb.zig"); pub const watchdog = @import("hal/watchdog.zig"); +pub const hw = @import("hal/hw.zig"); comptime { // HACK: tests can't access microzig. maybe there's a better way to do this. diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig index 127822eac..dfa5a0102 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig @@ -105,7 +105,7 @@ pub fn PinMapping(comptime Count: type) type { low: gpio.Pin, high: gpio.Pin, - fn count(range: @This()) Count { + pub fn count(range: @This()) Count { return @intCast(@backingInt(range.high) - @backingInt(range.low) + 1); } }; diff --git a/port/raspberrypi/rp2xxx/src/hal/usb.zig b/port/raspberrypi/rp2xxx/src/hal/usb.zig index 98041f2e6..517cfe23a 100644 --- a/port/raspberrypi/rp2xxx/src/hal/usb.zig +++ b/port/raspberrypi/rp2xxx/src/hal/usb.zig @@ -57,8 +57,8 @@ fn PerEndpoint(T: type) type { fn get(self: *volatile @This(), dir: usb.types.Dir) *volatile T { return switch (dir) { - .In => &self.in, - .Out => &self.out, + .in => &self.in, + .out => &self.out, }; } }; @@ -147,7 +147,7 @@ pub fn Polled(config: Config) type { const ep_num = shift / 2; const ep: usb.types.Endpoint = comptime .{ .num = @fromBackingInt(ep_num), - .dir = if (shift % 2 == 0) .In else .Out, + .dir = if (shift % 2 == 0) .in else .out, }; // We should only get here if we've been notified that @@ -402,7 +402,7 @@ pub fn Polled(config: Config) type { const attr = desc.attributes; log.debug( "ep open {t} {t} {{ type: {t}, sync: {t}, usage: {t}, size: {} }}", - .{ ep.num, ep.dir, attr.transfer_type, attr.synchronisation, attr.usage, desc.max_packet_size.into() }, + .{ ep.num, ep.dir, attr.transfer_type, attr.synchronisation, attr.usage, desc.max_packet_size.native() }, ); const self: *@This() = @fieldParentPtr("interface", itf); @@ -411,7 +411,7 @@ pub fn Polled(config: Config) type { const ep_hard = self.hardware_endpoint_get_by_address(ep); - assert(desc.max_packet_size.into() <= max_supported_packet_size); + assert(desc.max_packet_size.native() <= max_supported_packet_size); buffer_control[@backingInt(ep.num)].get(ep.dir).modify(.{ .PID_0 = 1 }); @@ -432,7 +432,7 @@ pub fn Polled(config: Config) type { fn endpoint_alloc(self: *@This(), desc: *const usb.descriptor.Endpoint) ![]align(64) u8 { // round up size to multiple of 64 - var size = try std.math.divCeil(u16, desc.max_packet_size.into(), 64) * 64; + var size = try std.math.divCeil(u16, desc.max_packet_size.native(), 64) * 64; // double buffered Bulk endpoint if (desc.attributes.transfer_type == .Bulk) size *= 2; @@ -481,7 +481,7 @@ pub fn ResetDriver(bootsel_activity_led: ?u5, interface_disable_mask: u32) type _ = self; switch (setup.request) { 0x01 => { - const value = setup.value.into(); + const value = setup.value.native(); const mask = @as(u32, 1) << if (value & 0x100 != 0) @intCast(value >> 9) else diff --git a/port/wch/ch32v/src/hals/usbfs.zig b/port/wch/ch32v/src/hals/usbfs.zig index 2362f71ff..b933f18c1 100644 --- a/port/wch/ch32v/src/hals/usbfs.zig +++ b/port/wch/ch32v/src/hals/usbfs.zig @@ -225,9 +225,9 @@ pub fn Polled(comptime cfg: Config) type { fn on_bus_reset_local(self: *Self) void { // Clear state inline for (0..cfg.max_endpoints_count) |i| { - self.endpoints[i][@backingInt(types.Dir.Out)].rx_armed = false; - self.endpoints[i][@backingInt(types.Dir.Out)].rx_last_len = 0; - self.endpoints[i][@backingInt(types.Dir.In)].tx_busy = false; + self.endpoints[i][@backingInt(types.Dir.out)].rx_armed = false; + self.endpoints[i][@backingInt(types.Dir.out)].rx_last_len = 0; + self.endpoints[i][@backingInt(types.Dir.in)].tx_busy = false; } // Default: NAK all non-EP0 endpoints. @@ -242,7 +242,7 @@ pub fn Polled(comptime cfg: Config) type { } fn read_setup_from_ep0(self: *Self) types.SetupPacket { - const ep0 = self.st(.ep0, .Out); + const ep0 = self.st(.ep0, .out); assert(ep0.buf.len >= 8); const words_ptr: *align(4) const [2]u32 = @ptrCast(ep0.buf.ptr); return @bitCast(words_ptr.*); @@ -253,16 +253,16 @@ pub fn Polled(comptime cfg: Config) type { fn call_on_buffer(self: *Self, dir: types.Dir, ep: u4, controller: anytype) void { // controller.on_buffer requires comptime ep parameter switch (dir) { - .In => switch (ep) { + .in => switch (ep) { inline 0...15 => |i| { const num: types.Endpoint.Num = @fromBackingInt(i); - controller.on_buffer(&self.interface, .{ .num = num, .dir = .In }); + controller.on_buffer(&self.interface, .{ .num = num, .dir = .in }); }, }, - .Out => switch (ep) { + .out => switch (ep) { inline 0...15 => |i| { const num: types.Endpoint.Num = @fromBackingInt(i); - controller.on_buffer(&self.interface, .{ .num = num, .dir = .Out }); + controller.on_buffer(&self.interface, .{ .num = num, .dir = .out }); }, }, } @@ -315,7 +315,7 @@ pub fn Polled(comptime cfg: Config) type { const setup: types.SetupPacket = self.read_setup_from_ep0(); Regs.R8_UEP0_T_CTRL.modify(.{ .RB_UEP_T_TOG = TOG_DATA1 }); set_rx_ctrl(0, RES_ACK, TOG_DATA1, false); - const st_in = self.st(.ep0, .In); + const st_in = self.st(.ep0, .in); st_in.tx_busy = false; controller.on_setup_req(&self.interface, &setup); }, @@ -335,17 +335,17 @@ pub fn Polled(comptime cfg: Config) type { // EP0 OUT is always armed; accept status ZLP. if (ep == 0) { - const st_out = self.st(.ep0, .Out); + const st_out = self.st(.ep0, .out); st_out.rx_last_len = len; const next = toggle_next(current_rx_tog(0)); set_rx_ctrl(0, RES_ACK, next, false); // stay ACK - self.call_on_buffer(.Out, 0, controller); + self.call_on_buffer(.out, 0, controller); return; } const num: types.Endpoint.Num = @fromBackingInt(ep); - const st_out = self.st(num, .Out); + const st_out = self.st(num, .out); // Only read if previously armed (ep_listen) if (!st_out.rx_armed) { @@ -360,13 +360,13 @@ pub fn Polled(comptime cfg: Config) type { const n = @min(@as(usize, len), st_out.buf.len); st_out.rx_last_len = @as(u16, @intCast(n)); - self.call_on_buffer(.Out, ep, controller); + self.call_on_buffer(.out, ep, controller); } // IN => into host from device fn handle_in(self: *Self, ep: u4, controller: anytype) void { const num: types.Endpoint.Num = @fromBackingInt(ep); - const st_in = self.st(num, .In); + const st_in = self.st(num, .in); if (!st_in.tx_busy) return; @@ -376,7 +376,7 @@ pub fn Polled(comptime cfg: Config) type { set_tx_ctrl(ep, RES_NAK, next, false); // Notify controller/drivers of IN completion. - self.call_on_buffer(.In, ep, controller); + self.call_on_buffer(.in, ep, controller); // After EP0 IN completes, re-arm EP0 OUT for the next SETUP. // SETUP packets always use DATA0 toggle; the WCH USBFS hardware @@ -402,11 +402,11 @@ pub fn Polled(comptime cfg: Config) type { assert(ep_i < cfg.max_endpoints_count); log.debug("ep_open ep{} dir={}", .{ ep_i, e.dir }); - const mps: u16 = desc.max_packet_size.into(); + const mps: u16 = desc.max_packet_size.native(); assert(mps > 0 and mps <= 64); - const out_st = self.st(e.num, .Out); - const in_st = self.st(e.num, .In); + const out_st = self.st(e.num, .out); + const in_st = self.st(e.num, .in); const first_open = out_st.buf.len == 0; // We "open" the endpoint for both directions at once because the DMA buffers @@ -439,8 +439,8 @@ pub fn Polled(comptime cfg: Config) type { set_tx_ctrl(ep_i, RES_NAK, TOG_DATA0, false); } switch (e.dir) { - .Out => set_rx_ctrl(ep_i, RES_NAK, TOG_DATA0, false), - .In => set_tx_ctrl(ep_i, RES_NAK, TOG_DATA0, false), + .out => set_rx_ctrl(ep_i, RES_NAK, TOG_DATA0, false), + .in => set_tx_ctrl(ep_i, RES_NAK, TOG_DATA0, false), } const tx_len: *volatile Reg_U8 = &EP_Regs[ep_i].UEP_T_LEN; @@ -459,7 +459,7 @@ pub fn Polled(comptime cfg: Config) type { // EP0 OUT is always armed; ignore listen semantics here. if (ep_num == .ep0) { - const st0 = self.st(.ep0, .Out); + const st0 = self.st(.ep0, .out); st0.rx_limit = @as(u16, @intCast(len)); return; } @@ -468,7 +468,7 @@ pub fn Polled(comptime cfg: Config) type { if (ep_i >= cfg.max_endpoints_count) @panic("ep_listen called for invalid endpoint"); - const st_out = self.st(ep_num, .Out); + const st_out = self.st(ep_num, .out); if (st_out.buf.len == 0) @panic("ep_listen called for endpoint with no buffer allocated"); @@ -488,7 +488,7 @@ pub fn Polled(comptime cfg: Config) type { fn ep_readv(itf: *usb.DeviceInterface, ep_num: types.Endpoint.Num, data: []const []u8) types.Len { const self: *Self = @fieldParentPtr("interface", itf); - const st_out = self.st(ep_num, .Out); + const st_out = self.st(ep_num, .out); assert(st_out.buf.len != 0); const want: usize = @as(usize, st_out.rx_last_len); @@ -521,7 +521,7 @@ pub fn Polled(comptime cfg: Config) type { const ep_i: u4 = epn(ep_num); assert(ep_i < cfg.max_endpoints_count); - const st_in = self.st(ep_num, .In); + const st_in = self.st(ep_num, .in); assert(st_in.buf.len != 0); if (st_in.tx_busy) { diff --git a/port/wch/ch32v/src/hals/usbhs.zig b/port/wch/ch32v/src/hals/usbhs.zig index 9bd6bd5b1..c23ce2322 100644 --- a/port/wch/ch32v/src/hals/usbhs.zig +++ b/port/wch/ch32v/src/hals/usbhs.zig @@ -212,9 +212,9 @@ pub fn Polled(comptime cfg: Config) type { fn on_bus_reset_local(self: *Self) void { // Clear state inline for (0..cfg.max_endpoints_count) |i| { - self.endpoints[i][@backingInt(types.Dir.Out)].rx_armed = false; - self.endpoints[i][@backingInt(types.Dir.Out)].rx_last_len = 0; - self.endpoints[i][@backingInt(types.Dir.In)].tx_busy = false; + self.endpoints[i][@backingInt(types.Dir.out)].rx_armed = false; + self.endpoints[i][@backingInt(types.Dir.out)].rx_last_len = 0; + self.endpoints[i][@backingInt(types.Dir.in)].tx_busy = false; } // Default: NAK all non-EP0 endpoints. @@ -229,7 +229,7 @@ pub fn Polled(comptime cfg: Config) type { } fn read_setup_from_ep0(self: *Self) types.SetupPacket { - const ep0 = self.st(.ep0, .Out); + const ep0 = self.st(.ep0, .out); assert(ep0.buf.len >= 8); const words_ptr: *align(4) const [2]u32 = @ptrCast(ep0.buf.ptr); return @bitCast(words_ptr.*); @@ -240,16 +240,16 @@ pub fn Polled(comptime cfg: Config) type { fn call_on_buffer(self: *Self, dir: types.Dir, ep: u4, controller: anytype) void { // controller.on_buffer requires comptime ep parameter switch (dir) { - .In => switch (ep) { + .in => switch (ep) { inline 0...15 => |i| { const num: types.Endpoint.Num = @fromBackingInt(i); - controller.on_buffer(&self.interface, .{ .num = num, .dir = .In }); + controller.on_buffer(&self.interface, .{ .num = num, .dir = .in }); }, }, - .Out => switch (ep) { + .out => switch (ep) { inline 0...15 => |i| { const num: types.Endpoint.Num = @fromBackingInt(i); - controller.on_buffer(&self.interface, .{ .num = num, .dir = .Out }); + controller.on_buffer(&self.interface, .{ .num = num, .dir = .out }); }, }, } @@ -311,7 +311,7 @@ pub fn Polled(comptime cfg: Config) type { // After SETUP, EP0 IN data stage starts with DATA1. set_tx_ctrl(0, RES_NAK, TOG_DATA1, false); set_rx_ctrl(0, RES_ACK, TOG_DATA1, false); - self.st(.ep0, .In).tx_busy = false; + self.st(.ep0, .in).tx_busy = false; controller.on_setup_req(&self.interface, &setup); @@ -354,7 +354,7 @@ pub fn Polled(comptime cfg: Config) type { log.debug("Setup: {any}", .{setup}); set_tx_ctrl(0, RES_NAK, TOG_DATA1, false); set_rx_ctrl(0, RES_ACK, TOG_DATA1, false); - self.st(.ep0, .In).tx_busy = false; + self.st(.ep0, .in).tx_busy = false; controller.on_setup_req(&self.interface, &setup); } }, @@ -374,17 +374,17 @@ pub fn Polled(comptime cfg: Config) type { // EP0 OUT is always armed; accept status ZLP. if (ep == 0) { - const st_out = self.st(.ep0, .Out); + const st_out = self.st(.ep0, .out); st_out.rx_last_len = len; const next = toggle_next(current_rx_tog(0)); set_rx_ctrl(0, RES_ACK, next, false); // stay ACK - self.call_on_buffer(.Out, 0, controller); + self.call_on_buffer(.out, 0, controller); return; } const num: types.Endpoint.Num = @fromBackingInt(ep); - const st_out = self.st(num, .Out); + const st_out = self.st(num, .out); // Only read if previously armed (ep_listen) if (!st_out.rx_armed) { @@ -400,13 +400,13 @@ pub fn Polled(comptime cfg: Config) type { const n = @min(@as(usize, len), st_out.buf.len); st_out.rx_last_len = @as(u16, @intCast(n)); - self.call_on_buffer(.Out, ep, controller); + self.call_on_buffer(.out, ep, controller); } // IN => into host from device fn handle_in(self: *Self, ep: u4, controller: anytype) void { const num: types.Endpoint.Num = @fromBackingInt(ep); - const st_in = self.st(num, .In); + const st_in = self.st(num, .in); if (!st_in.tx_busy) { set_tx_ctrl(ep, RES_NAK, current_tx_tog(ep), false); @@ -419,7 +419,7 @@ pub fn Polled(comptime cfg: Config) type { set_tx_ctrl(ep, RES_NAK, next, false); // Notify controller/drivers of IN completion. - self.call_on_buffer(.In, ep, controller); + self.call_on_buffer(.in, ep, controller); } // ---- VTable functions ------------------------------------------------ @@ -438,13 +438,13 @@ pub fn Polled(comptime cfg: Config) type { assert(ep_i < cfg.max_endpoints_count); log.info("ep_open called for ep{}", .{ep_i}); - const mps: u16 = desc.max_packet_size.into(); + const mps: u16 = desc.max_packet_size.native(); assert(mps > 0 and mps <= 2047); // EP0 shares a single DMA buffer for both directions. if (e.num == .ep0) { - const out_st = self.st(.ep0, .Out); - const in_st = self.st(.ep0, .In); + const out_st = self.st(.ep0, .out); + const in_st = self.st(.ep0, .in); const dma: *volatile Reg_U32 = EP0_DMA; if (dma.raw == 0) { log.warn("EP0 DMA is null!", .{}); @@ -476,7 +476,7 @@ pub fn Polled(comptime cfg: Config) type { const ptr_val: u32 = @as(u32, @intCast(@intFromPtr(st_ep.buf.ptr))); - if (e.dir == .Out) { + if (e.dir == .out) { const rx_dma: *volatile Reg_U32 = &UEP_RX_DMA[ep_i - 1]; rx_dma.raw = ptr_val; const max_len: *volatile Reg_U16 = &UEP_MAX_LEN[ep_i]; @@ -497,19 +497,19 @@ pub fn Polled(comptime cfg: Config) type { // TODO: make this a function, too ugly here var cfg_raw: u32 = Regs.UEP_CONFIG__UHOST_CTRL.raw; if (e.num != .ep0) { - if (e.dir == .In) cfg_raw |= (@as(u32, 1) << ep_i) else cfg_raw |= (@as(u32, 1) << (16 + @as(u5, ep_i))); + if (e.dir == .in) cfg_raw |= (@as(u32, 1) << ep_i) else cfg_raw |= (@as(u32, 1) << (16 + @as(u5, ep_i))); } Regs.UEP_CONFIG__UHOST_CTRL.raw = cfg_raw; // Endpoint type ISO marking (only for ISO endpoints). if (e.num != .ep0 and desc.attributes.transfer_type == .Isochronous) { var type_raw: u32 = Regs.UEP_TYPE.raw; - if (e.dir == .In) type_raw |= (@as(u32, 1) << ep_i) else type_raw |= (@as(u32, 1) << (16 + @as(u5, ep_i))); + if (e.dir == .in) type_raw |= (@as(u32, 1) << ep_i) else type_raw |= (@as(u32, 1) << (16 + @as(u5, ep_i))); Regs.UEP_TYPE.raw = type_raw; } // EP0 OUT always ACK - if (e.num == .ep0 and e.dir == .Out) { + if (e.num == .ep0 and e.dir == .out) { self.arm_ep0_out_always(); } @@ -522,7 +522,7 @@ pub fn Polled(comptime cfg: Config) type { // EP0 OUT is always armed; ignore listen semantics here. if (ep_num == .ep0) { - const st0 = self.st(.ep0, .Out); + const st0 = self.st(.ep0, .out); st0.rx_limit = @as(u16, @intCast(len)); // set_rx_ctrl(0, RES_ACK, TOG_DATA0, true); return; @@ -532,7 +532,7 @@ pub fn Polled(comptime cfg: Config) type { if (ep_i >= cfg.max_endpoints_count) @panic("ep_listen called for invalid endpoint"); - const st_out = self.st(ep_num, .Out); + const st_out = self.st(ep_num, .out); if (st_out.buf.len == 0) @panic("ep_listen called for endpoint with no buffer allocated"); @@ -555,7 +555,7 @@ pub fn Polled(comptime cfg: Config) type { fn ep_readv(itf: *usb.DeviceInterface, ep_num: types.Endpoint.Num, data: []const []u8) types.Len { const self: *Self = @fieldParentPtr("interface", itf); - const st_out = self.st(ep_num, .Out); + const st_out = self.st(ep_num, .out); assert(st_out.buf.len != 0); const want: usize = @as(usize, st_out.rx_last_len); @@ -587,7 +587,7 @@ pub fn Polled(comptime cfg: Config) type { const ep_i: u4 = epn(ep_num); assert(ep_i < cfg.max_endpoints_count); - const st_in = self.st(ep_num, .In); + const st_in = self.st(ep_num, .in); assert(st_in.buf.len != 0); if (st_in.tx_busy) {