Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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"),
Expand Down
2 changes: 2 additions & 0 deletions core/src/core.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 19 additions & 0 deletions core/src/core/mem.zig
Original file line number Diff line number Diff line change
@@ -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()});
}
};
}
42 changes: 21 additions & 21 deletions core/src/core/usb.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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(
Expand Down Expand Up @@ -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..];
Expand Down Expand Up @@ -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
Expand All @@ -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];
Expand All @@ -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(
Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}
}
Expand Down
65 changes: 34 additions & 31 deletions core/src/core/usb/descriptor.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const std = @import("std");

const EndianInt = @import("../mem.zig").EndianInt;

const types = @import("types.zig");
const assert = std.debug.assert;

Expand All @@ -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,
_,
};

Expand All @@ -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.
Expand All @@ -58,17 +61,17 @@ 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.
device_triple: types.ClassSubclassProtocol,
/// 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.
Expand Down Expand Up @@ -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
Expand All @@ -153,16 +156,16 @@ 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) };
}

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 };
}
};

Expand Down Expand Up @@ -196,15 +199,15 @@ 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,
/// Endpoint attributes; the most relevant part is the bottom 2 bits, which
/// 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,
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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 };
Expand Down Expand Up @@ -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,
Expand All @@ -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),
};
8 changes: 4 additions & 4 deletions core/src/core/usb/descriptor/cdc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down
Loading
Loading