-
Notifications
You must be signed in to change notification settings - Fork 174
Integrates driver framework #246
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
Merged
Merged
Changes from 15 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
ec2bf02
Initial commit
ikskuh 87d68b2
Initial commit: Keyboard and SSD1306 driver and some basic project st…
8a2f832
Introduces StreamDevice and DatagramDevice for the framework as a ref…
e2f3d28
Introduces DigitalIO as a base driver and ports KeyboardMatrix to it.
46265ac
Starts implementing the ST77xx driver
f8139a0
Adjusts to ZEG coding guidelines
1f606a9
Updates README.md
50f97ff
Adds some minor fixes.
fb73c5e
Update to 0.13.0
6786a26
Updates DigitalIO to make .read() may error (think: port expanders!),…
9dd9164
Adds a framebuffer type for the SSD1306
55308cd
Fixes some bugs in the SSD1306 driver, enables quicker image transfer.
4b935ce
Removes pre-merge cruft
2d6ef3f
Merges the MicroZig Driver Framework into MicroZig
c578eff
Adds missing build.zig
31c7fe8
Applies style guides more thoroughly
089a4be
Deletes empty driver files
6b65e8d
Refactors Keyboard_Matrix
47a33ae
Refactors Debounced_Button
13cbfd9
Refactors Rotary_Encoder
7c5bc9c
Renames ./driver to ./drivers, adds the drivers package to '@import(m…
7a1decf
Adds README to ./drivers
2bc0079
Adds missing build.zig.zon to driver framework.
a40b90f
Renames project to work around bug in boxzer
2222536
Merge branch 'main' into work/driver_framework
a4ea592
Ports SSD1306 and Datagram_Device to use/provide writev/readv functions
601d760
Prepares SSD1306 to be used with 4-wire SPI
d7284a4
Updates Stream_Device to provide writev/readv
ec68953
Adds a unit test for the Datagram_Device.Test_Device
031235a
Implements Stream_Device.Test_Device with a unit test to ensure prope…
2b686e3
Enables SSD1306 with 4-wire SPI mode.
621d8a6
Starts to implement device drivers for RP2 HAL
27cece2
Adds rp2.hal.GPIO_Device as a Digital_IO driver
6e7b86a
Introduces the SSD1306 dynamic mode support, which can serve all othe…
f12a0b2
Drops accidential file clone
520171f
Merge remote-tracking branch 'origin/main' into work/driver_framework
bc2e430
Attempts to fix boxzer CI failure
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,11 @@ | ||
| zig-out/ | ||
| zig-cache/ | ||
| .zig-cache/ | ||
| microzig-deploy/ | ||
| __pycache__/ | ||
| .direnv/ | ||
| .DS_Store | ||
| .gdbinit | ||
| .lldbinit | ||
| .direnv/ | ||
| __pycache__/ | ||
| .venv | ||
| .zig-cache/ | ||
| boxzer-out | ||
| microzig-deploy/ | ||
| zig-cache/ | ||
| zig-out/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| //! | ||
| //! An abstract datagram orientied device with runtime dispatch. | ||
| //! | ||
| //! Datagram devices behave similar to an SPI or Ethernet device where | ||
| //! packets with an ahead-of-time known length can be transferred in a | ||
| //! single transaction. | ||
| //! | ||
|
|
||
| const std = @import("std"); | ||
|
|
||
| const DatagramDevice = @This(); | ||
|
|
||
| const BaseError = error{ IoError, Timeout }; | ||
|
|
||
| pub const ConnectError = BaseError || error{DeviceBusy}; | ||
|
|
||
| /// Establishes a connection to the device (like activating a chip-select lane or similar). | ||
| /// NOTE: Call `.disconnect()` when the usage of the device is done to release it. | ||
| pub fn connect(dd: DatagramDevice) ConnectError!void { | ||
| if (dd.vtable.connectFn) |connectFn| { | ||
| return connectFn(dd.object); | ||
| } | ||
| } | ||
|
|
||
| /// Releases a device from the connection. | ||
| pub fn disconnect(dd: DatagramDevice) void { | ||
| if (dd.vtable.disconnectFn) |disconnectFn| { | ||
| return disconnectFn(dd.object); | ||
| } | ||
| } | ||
|
|
||
| pub const WriteError = BaseError || error{ Unsupported, NotConnected }; | ||
|
|
||
| /// Writes a single `datagram` to the device. | ||
| pub fn write(dd: DatagramDevice, datagram: []const u8) WriteError!void { | ||
| if (dd.vtable.writeFn) |writeFn| { | ||
| return writeFn(dd.object, datagram); | ||
| } else { | ||
| return error.Unsupported; | ||
| } | ||
| } | ||
|
|
||
| pub const ReadError = BaseError || error{ Unsupported, NotConnected }; | ||
|
|
||
| /// Reads a single `datagram` from the device. | ||
| pub fn read(dd: DatagramDevice, datagram: []u8) ReadError!void { | ||
| if (dd.vtable.readFn) |readFn| { | ||
| return readFn(dd.object, datagram); | ||
| } else { | ||
| return error.Unsupported; | ||
| } | ||
| } | ||
|
|
||
| object: ?*anyopaque, | ||
| vtable: *const VTable, | ||
|
|
||
| pub const VTable = struct { | ||
| connectFn: ?*const fn (?*anyopaque) ConnectError!void, | ||
|
ikskuh marked this conversation as resolved.
Outdated
|
||
| disconnectFn: ?*const fn (?*anyopaque) void, | ||
| writeFn: ?*const fn (?*anyopaque, datagram: []const u8) WriteError!void, | ||
| readFn: ?*const fn (?*anyopaque, datagram: []u8) ReadError!void, | ||
| }; | ||
|
|
||
| /// A device implementation that can be used to write unit tests. | ||
| pub const TestDevice = struct { | ||
| arena: std.heap.ArenaAllocator, | ||
| packets: std.ArrayList([]u8), | ||
|
|
||
| input_sequence: ?[]const []const u8, | ||
| input_sequence_pos: usize, | ||
|
|
||
| write_enabled: bool, | ||
|
|
||
| connected: bool, | ||
|
|
||
| pub fn init_receiver_only() TestDevice { | ||
| return init(null, true); | ||
| } | ||
|
|
||
| pub fn init_sender_only(input: []const []const u8) TestDevice { | ||
| return init(input, false); | ||
| } | ||
|
|
||
| pub fn init(input: ?[]const []const u8, write_enabled: bool) TestDevice { | ||
| return TestDevice{ | ||
| .arena = std.heap.ArenaAllocator.init(std.testing.allocator), | ||
| .packets = std.ArrayList([]u8).init(std.testing.allocator), | ||
|
|
||
| .input_sequence = input, | ||
| .input_sequence_pos = 0, | ||
|
|
||
| .write_enabled = write_enabled, | ||
|
|
||
| .connected = false, | ||
| }; | ||
| } | ||
|
|
||
| pub fn deinit(td: *TestDevice) void { | ||
| td.arena.deinit(); | ||
| td.packets.deinit(); | ||
| td.* = undefined; | ||
| } | ||
|
|
||
| pub fn expect_sent(td: TestDevice, expected_datagrams: []const []const u8) !void { | ||
| const actual_datagrams = td.packets.items; | ||
|
|
||
| try std.testing.expectEqual(expected_datagrams.len, actual_datagrams.len); | ||
| for (expected_datagrams, actual_datagrams) |expected, actual| { | ||
| try std.testing.expectEqualSlices(u8, expected, actual); | ||
| } | ||
| } | ||
|
|
||
| pub fn datagram_device(td: *TestDevice) DatagramDevice { | ||
| return DatagramDevice{ | ||
| .object = td, | ||
| .vtable = &vtable, | ||
| }; | ||
| } | ||
|
|
||
| fn connectFn(ctx: ?*anyopaque) ConnectError!void { | ||
|
ikskuh marked this conversation as resolved.
Outdated
|
||
| const td: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
| if (td.connected) | ||
| return error.DeviceBusy; | ||
| td.connected = true; | ||
| } | ||
|
|
||
| fn disconnectFn(ctx: ?*anyopaque) void { | ||
|
ikskuh marked this conversation as resolved.
Outdated
|
||
| const td: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
| if (!td.connected) { | ||
| std.log.err("disconnect when test device was not connected!", .{}); | ||
| } | ||
| td.connected = false; | ||
| } | ||
|
|
||
| fn writeFn(ctx: ?*anyopaque, datagram: []const u8) WriteError!void { | ||
|
ikskuh marked this conversation as resolved.
Outdated
|
||
| const td: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
|
|
||
| if (!td.connected) { | ||
| return error.NotConnected; | ||
| } | ||
|
|
||
| if (!td.write_enabled) { | ||
| return error.Unsupported; | ||
| } | ||
|
|
||
| const dg = td.arena.allocator().dupe(u8, datagram) catch return error.IoError; | ||
| errdefer td.arena.allocator().free(dg); | ||
|
|
||
| td.packets.append(dg) catch return error.IoError; | ||
| } | ||
|
|
||
| fn readFn(ctx: ?*anyopaque, datagram: []u8) ReadError!void { | ||
|
ikskuh marked this conversation as resolved.
Outdated
|
||
| const td: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
|
|
||
| if (!td.connected) { | ||
| return error.NotConnected; | ||
| } | ||
|
|
||
| const inputs = td.input_sequence orelse return error.Unsupported; | ||
|
|
||
| if (td.input_sequence_pos >= inputs.len) { | ||
| return error.IoError; | ||
| } | ||
|
|
||
| const packet = inputs[td.input_sequence_pos]; | ||
| td.input_sequence_pos += 1; | ||
|
|
||
| if (packet.len != datagram.len) | ||
| return error.IoError; | ||
|
|
||
| @memcpy(datagram, packet); | ||
| } | ||
|
|
||
| const vtable = VTable{ | ||
| .connectFn = connectFn, | ||
| .disconnectFn = disconnectFn, | ||
| .writeFn = writeFn, | ||
| .readFn = readFn, | ||
| }; | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| //! | ||
| //! An abstract digital input/output pin. | ||
| //! | ||
| //! Digital I/Os can be used to drive single-wire data | ||
| //! | ||
|
|
||
| const std = @import("std"); | ||
|
|
||
| const DigitalIO = @This(); | ||
|
ikskuh marked this conversation as resolved.
Outdated
|
||
| const BaseError = error{ IoError, Timeout }; | ||
|
|
||
| object: ?*anyopaque, | ||
| vtable: *const VTable, | ||
|
|
||
| pub const SetDirError = error{Unsupported}; | ||
| pub const SetBiasError = error{Unsupported}; | ||
| pub const WriteError = error{Unsupported}; | ||
| pub const ReadError = error{Unsupported}; | ||
|
|
||
| pub const State = enum(u1) { | ||
| low = 0, | ||
| high = 1, | ||
|
|
||
| pub inline fn invert(state: State) State { | ||
| return @as(State, @enumFromInt(~@intFromEnum(state))); | ||
| } | ||
|
|
||
| pub inline fn value(state: State) u1 { | ||
| return @intFromEnum(state); | ||
| } | ||
| }; | ||
| pub const Direction = enum { input, output }; | ||
|
|
||
| /// Sets the direction of the pin. | ||
| pub fn set_direction(dio: DigitalIO, dir: Direction) SetDirError!void { | ||
| return dio.vtable.set_direction_fn(dio.object, dir); | ||
| } | ||
|
|
||
| /// Sets if the pin has a bias towards either `low` or `high` or no bias at all. | ||
| /// Bias is usually implemented with pull-ups and pull-downs. | ||
| pub fn set_bias(dio: DigitalIO, bias: ?State) SetBiasError!void { | ||
| return dio.vtable.set_bias_fn(dio.object, bias); | ||
| } | ||
|
|
||
| /// Changes the state of the pin. | ||
| pub fn write(dio: DigitalIO, state: State) WriteError!void { | ||
| return dio.vtable.write_fn(dio.object, state); | ||
| } | ||
|
|
||
| /// Reads the state state of the pin. | ||
| pub fn read(dio: DigitalIO) ReadError!State { | ||
| return dio.vtable.read_fn(dio.object); | ||
| } | ||
|
|
||
| pub const VTable = struct { | ||
| set_direction_fn: *const fn (?*anyopaque, dir: Direction) SetDirError!void, | ||
| set_bias_fn: *const fn (?*anyopaque, bias: ?State) SetBiasError!void, | ||
| write_fn: *const fn (?*anyopaque, state: State) WriteError!void, | ||
| read_fn: *const fn (?*anyopaque) State, | ||
| }; | ||
|
|
||
| pub const TestDevice = struct { | ||
| state: State, | ||
| dir: Direction, | ||
|
|
||
| pub fn init(initial_dir: Direction, initial_state: State) TestDevice { | ||
| return TestDevice{ | ||
| .dir = initial_dir, | ||
| .state = initial_state, | ||
| }; | ||
| } | ||
|
|
||
| pub fn digital_io(dev: *TestDevice) DigitalIO { | ||
| return DigitalIO{ | ||
| .object = dev, | ||
| .vtable = &vtable, | ||
| }; | ||
| } | ||
|
|
||
| fn set_direction_fn(ctx: ?*anyopaque, dir: Direction) SetDirError!void { | ||
| const dev: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
| dev.dir = dir; | ||
| } | ||
|
|
||
| fn set_bias_fn(ctx: ?*anyopaque, bias: ?State) SetBiasError!void { | ||
| const dev: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
| _ = dev; | ||
| _ = bias; | ||
| } | ||
|
|
||
| fn write_fn(ctx: ?*anyopaque, state: State) WriteError!void { | ||
| const dev: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
| if (dev.dir != .output) | ||
| return error.Unsupported; | ||
| dev.state = state; | ||
| } | ||
|
|
||
| fn read_fn(ctx: ?*anyopaque) State { | ||
| const dev: *TestDevice = @ptrCast(@alignCast(ctx.?)); | ||
| return dev.state; | ||
| } | ||
|
|
||
| const vtable = VTable{ | ||
| .set_direction_fn = set_direction_fn, | ||
| .set_bias_fn = set_bias_fn, | ||
| .write_fn = write_fn, | ||
| .read_fn = read_fn, | ||
| }; | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| //! | ||
| //! An abstract stream orientied device with runtime dispatch. | ||
| //! | ||
| //! Stream devices behave similar to an UART and can send/receive data | ||
| //! in variying lengths without clear boundaries between transmissions. | ||
| //! | ||
|
|
||
| const std = @import("std"); | ||
|
|
||
| const StreamDevice = @This(); | ||
|
|
||
| object: ?*anyopaque, | ||
| vtable: *const VTable, | ||
|
|
||
| const BaseError = error{ IoError, Timeout }; | ||
|
|
||
| pub const ConnectError = BaseError || error{DeviceBusy}; | ||
| pub const WriteError = BaseError || error{ Unsupported, NotConnected }; | ||
| pub const ReadError = BaseError || error{ Unsupported, NotConnected }; | ||
|
|
||
| /// Establishes a connection to the device (like activating a chip-select lane or similar). | ||
| /// NOTE: Call `.disconnect()` when the usage of the device is done to release it. | ||
| pub fn connect(sd: StreamDevice) ConnectError!void { | ||
| if (sd.vtable.connectFn) |connectFn| { | ||
| return connectFn(sd.object); | ||
| } | ||
| } | ||
|
|
||
| /// Releases a device from the connection. | ||
| pub fn disconnect(sd: StreamDevice) void { | ||
| if (sd.vtable.disconnectFn) |disconnectFn| { | ||
| return disconnectFn(sd.object); | ||
| } | ||
| } | ||
|
|
||
| /// Writes some `bytes` to the device and returns the number of bytes written. | ||
| pub fn write(sd: StreamDevice, bytes: []const u8) WriteError!usize { | ||
| if (sd.vtable.writeFn) |writeFn| { | ||
| return writeFn(sd.object, bytes); | ||
| } else { | ||
| return error.Unsupported; | ||
| } | ||
| } | ||
|
|
||
| /// Reads some `bytes` to the device and returns the number of bytes read. | ||
| pub fn read(sd: StreamDevice, bytes: []u8) ReadError!usize { | ||
| if (sd.vtable.readFn) |readFn| { | ||
| return readFn(sd.object, bytes); | ||
| } else { | ||
| return error.Unsupported; | ||
| } | ||
| } | ||
|
|
||
| pub const Reader = std.io.Reader(StreamDevice, ReadError, reader_read); | ||
| pub fn reader(sd: StreamDevice) Reader { | ||
| return .{ .context = sd }; | ||
| } | ||
|
|
||
| fn reader_read(sd: StreamDevice, buf: []u8) ReadError!usize { | ||
| return sd.read(buf); | ||
| } | ||
|
|
||
| pub const Writer = std.io.Reader(StreamDevice, WriteError, writer_write); | ||
| pub fn writer(sd: StreamDevice) Writer { | ||
| return .{ .context = sd }; | ||
| } | ||
|
|
||
| fn writer_write(sd: StreamDevice, buf: []const u8) WriteError!usize { | ||
| return sd.write(buf); | ||
| } | ||
|
|
||
| pub const VTable = struct { | ||
| connect_fn: ?*const fn (?*anyopaque) ConnectError!void, | ||
| disconnect_fn: ?*const fn (?*anyopaque) void, | ||
| write_fn: ?*const fn (?*anyopaque, datagram: []const u8) WriteError!usize, | ||
| read_fn: ?*const fn (?*anyopaque, datagram: []u8) ReadError!usize, | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.