From 942de4e8a5e8bfc3b67d48e6801c5e64570a30d9 Mon Sep 17 00:00:00 2001 From: copper280z Date: Mon, 9 Jun 2025 22:27:20 -0400 Subject: [PATCH 1/3] add flash driver interface --- drivers/base/flash.zig | 168 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 drivers/base/flash.zig diff --git a/drivers/base/flash.zig b/drivers/base/flash.zig new file mode 100644 index 000000000..1c5a5b767 --- /dev/null +++ b/drivers/base/flash.zig @@ -0,0 +1,168 @@ +const std = @import("std"); + +const logger = std.log.scoped(.flash); + +const BaseError = error{ Unsupported, InvalidSector }; +const WriteError = BaseError || error{ SectorOverrun, WriteDisabled }; +const ReadError = BaseError || error{ReadDisabled}; + +pub const VTable = struct { + init_fn: ?*const fn (*anyopaque) BaseError!void, + deinit_fn: ?*const fn (*anyopaque) BaseError!void, + enable_write_fn: ?*const fn (*anyopaque) BaseError!void, + disable_write_fn: ?*const fn (*anyopaque) BaseError!void, + erase_fn: ?*const fn (*anyopaque, sector: u8) WriteError!void, + write_fn: ?*const fn (*anyopaque, sector: u8, data: []u8) WriteError!void, + read_fn: ?*const fn (*anyopaque, offset: u32, data: []u8) ReadError!usize, + // find_sector_fn: ?*const fn (*anyopaque, offset: u32) BaseError!u32, + sector_size_fn: ?*const fn (*anyopaque, sector: u8) BaseError!u32, +}; + +const Flash_Device = @This(); +ptr: *anyopaque, +vtable: VTable, +pub fn init(flash: Flash_Device) BaseError!void { + if (flash.vtable.init_fn) |initFn| { + return initFn(flash.ptr); + } +} +pub fn deinit(flash: Flash_Device) BaseError!void { + if (flash.vtable.deinit_fn) |deinitFn| { + return deinitFn(flash.ptr); + } +} +pub fn enableWrite(flash: Flash_Device) BaseError!void { + if (flash.vtable.enable_write_fn) |enable_write_fn| { + return try enable_write_fn(flash.ptr); + } +} +pub fn disableWrite(flash: Flash_Device) BaseError!void { + if (flash.vtable.disable_write_fn) |disable_write_fn| { + return try disable_write_fn(flash.ptr); + } +} +pub fn eraseSector(flash: Flash_Device, sector: u8) WriteError!void { + const erase_fn = flash.vtable.erase_fn orelse return error.Unsupported; + return erase_fn(flash.ptr, sector); +} +pub fn write(flash: Flash_Device, sector: u8, data: []u8) WriteError!void { + const sector_size = try flash.sectorSize(sector); + if (data.len > sector_size) return error.SectorOverrun; + try flash.eraseSector(sector); + const write_fn = flash.vtable.write_fn orelse return error.Unsupported; + return write_fn(flash.ptr, sector, data); +} +pub fn read(flash: Flash_Device, offset: u32, data: []u8) ReadError!usize { + const read_fn = flash.vtable.read_fn orelse return error.Unsupported; + return read_fn(flash.ptr, offset, data); +} +// pub fn findSector(flash: Flash_Device, offset: u32) BaseError!u8 { + +// } +pub fn sectorSize(flash: Flash_Device, sector: u8) BaseError!u32 { + const sector_size_fn = flash.vtable.sector_size_fn orelse return error.Unsupported; + return sector_size_fn(flash.ptr, sector); +} + +pub const TestDevice = struct { + arena: std.heap.ArenaAllocator, + write_enabled: bool = false, + read_enabled: bool = false, + sector_size: u32 = 16384, + num_sectors: u8 = 4, + + pub fn flash_device(td: *TestDevice) Flash_Device { + return Flash_Device{ .vtable = vtable, .ptr = td }; + } + + pub fn init(ctx: *anyopaque) BaseError!void { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + _ = td; + } + pub fn deinit(ctx: *anyopaque) BaseError!void { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + td.arena.deinit(); + } + pub fn enableWrite(ctx: *anyopaque) BaseError!void { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + std.debug.print("Enable flash Write\n", .{}); + td.read_enabled = true; + td.write_enabled = true; + } + pub fn disableWrite(ctx: *anyopaque) BaseError!void { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + std.debug.print("Disable flash Write\n", .{}); + td.read_enabled = false; + td.write_enabled = false; + } + pub fn erase(ctx: *anyopaque, sector: u8) WriteError!void { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + if (td.write_enabled) { + std.debug.print("Erasing sector: {}\n", .{sector}); + } else { + return error.WriteDisabled; + } + } + + pub fn write(ctx: *anyopaque, sector: u8, data: []u8) WriteError!void { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + if (td.write_enabled) { + std.debug.print("Writing offset: {}, data length: {}\n", .{ sector, data.len }); + } else { + return error.WriteDisabled; + } + } + pub fn read(ctx: *anyopaque, offset: u32, data: []u8) ReadError!usize { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + if (td.write_enabled) { + std.debug.print("Reading offset: {}\n", .{offset}); + const length = data.len; + for (0..length) |i| { + data[i] = @intCast(i % 256); + } + return length; + } else { + return error.ReadDisabled; + } + } + pub fn sectorSize(ctx: *anyopaque, sector: u8) BaseError!u32 { + const td: *TestDevice = @ptrCast(@alignCast(ctx)); + if (sector < td.num_sectors) { + return td.sector_size; + } else { + return error.InvalidSector; + } + } + const vtable = VTable{ + .init_fn = TestDevice.init, + .deinit_fn = TestDevice.deinit, + .enable_write_fn = TestDevice.enableWrite, + .disable_write_fn = TestDevice.disableWrite, + .erase_fn = TestDevice.erase, + .write_fn = TestDevice.write, + .read_fn = TestDevice.read, + .sector_size_fn = TestDevice.sectorSize, + }; +}; + +test TestDevice { + var td: TestDevice = .{ + .arena = std.heap.ArenaAllocator.init(std.testing.allocator), + }; + + td.sector_size = 10; + + const fd = td.flash_device(); + try fd.init(); + var buffer: [3]u8 = .{ 42, 43, 44 }; + try std.testing.expectError(error.WriteDisabled, fd.write(0, buffer[0..])); + try std.testing.expectError(error.ReadDisabled, fd.read(0, buffer[0..])); + + try fd.enableWrite(); + + try fd.write(0, buffer[0..]); + try std.testing.expectEqual(buffer.len, fd.read(0x123, buffer[0..])); + var big_buf: [11]u8 = undefined; + @memset(big_buf[0..], 123); + try std.testing.expectError(error.SectorOverrun, fd.write(0, big_buf[0..])); +} From 0d23c18483ceb4a1ced2559bc737791603959da1 Mon Sep 17 00:00:00 2001 From: copper280z Date: Fri, 11 Jul 2025 07:32:46 -0400 Subject: [PATCH 2/3] Rename to Block_Memory and remove init/deinit functions from interface. Add to framework.zig. --- drivers/base/{flash.zig => Block_Memory.zig} | 63 +++++++------------- drivers/framework.zig | 2 + 2 files changed, 23 insertions(+), 42 deletions(-) rename drivers/base/{flash.zig => Block_Memory.zig} (69%) diff --git a/drivers/base/flash.zig b/drivers/base/Block_Memory.zig similarity index 69% rename from drivers/base/flash.zig rename to drivers/base/Block_Memory.zig index 1c5a5b767..003d4b885 100644 --- a/drivers/base/flash.zig +++ b/drivers/base/Block_Memory.zig @@ -2,64 +2,53 @@ const std = @import("std"); const logger = std.log.scoped(.flash); -const BaseError = error{ Unsupported, InvalidSector }; -const WriteError = BaseError || error{ SectorOverrun, WriteDisabled }; -const ReadError = BaseError || error{ReadDisabled}; +pub const BaseError = error{ Unsupported, InvalidSector }; +pub const WriteError = BaseError || error{ SectorOverrun, WriteDisabled }; +pub const ReadError = BaseError || error{ReadDisabled}; pub const VTable = struct { - init_fn: ?*const fn (*anyopaque) BaseError!void, - deinit_fn: ?*const fn (*anyopaque) BaseError!void, enable_write_fn: ?*const fn (*anyopaque) BaseError!void, disable_write_fn: ?*const fn (*anyopaque) BaseError!void, - erase_fn: ?*const fn (*anyopaque, sector: u8) WriteError!void, - write_fn: ?*const fn (*anyopaque, sector: u8, data: []u8) WriteError!void, + erase_fn: ?*const fn (*anyopaque, sector: u32) WriteError!void, + write_fn: ?*const fn (*anyopaque, sector: u32, data: []u8) WriteError!void, read_fn: ?*const fn (*anyopaque, offset: u32, data: []u8) ReadError!usize, // find_sector_fn: ?*const fn (*anyopaque, offset: u32) BaseError!u32, - sector_size_fn: ?*const fn (*anyopaque, sector: u8) BaseError!u32, + sector_size_fn: ?*const fn (*anyopaque, sector: u32) BaseError!u32, }; -const Flash_Device = @This(); +pub const Block_Memory = @This(); ptr: *anyopaque, vtable: VTable, -pub fn init(flash: Flash_Device) BaseError!void { - if (flash.vtable.init_fn) |initFn| { - return initFn(flash.ptr); - } -} -pub fn deinit(flash: Flash_Device) BaseError!void { - if (flash.vtable.deinit_fn) |deinitFn| { - return deinitFn(flash.ptr); - } -} -pub fn enableWrite(flash: Flash_Device) BaseError!void { + +pub fn enableWrite(flash: Block_Memory) BaseError!void { if (flash.vtable.enable_write_fn) |enable_write_fn| { return try enable_write_fn(flash.ptr); } } -pub fn disableWrite(flash: Flash_Device) BaseError!void { +pub fn disableWrite(flash: Block_Memory) BaseError!void { if (flash.vtable.disable_write_fn) |disable_write_fn| { return try disable_write_fn(flash.ptr); } } -pub fn eraseSector(flash: Flash_Device, sector: u8) WriteError!void { +pub fn eraseSector(flash: Block_Memory, sector: u32) WriteError!void { const erase_fn = flash.vtable.erase_fn orelse return error.Unsupported; return erase_fn(flash.ptr, sector); } -pub fn write(flash: Flash_Device, sector: u8, data: []u8) WriteError!void { +pub fn write(flash: Block_Memory, sector: u32, data: []u8) WriteError!void { const sector_size = try flash.sectorSize(sector); if (data.len > sector_size) return error.SectorOverrun; try flash.eraseSector(sector); const write_fn = flash.vtable.write_fn orelse return error.Unsupported; return write_fn(flash.ptr, sector, data); } -pub fn read(flash: Flash_Device, offset: u32, data: []u8) ReadError!usize { +pub fn read(flash: Block_Memory, offset: u32, data: []u8) ReadError!usize { const read_fn = flash.vtable.read_fn orelse return error.Unsupported; return read_fn(flash.ptr, offset, data); } -// pub fn findSector(flash: Flash_Device, offset: u32) BaseError!u8 { +// pub fn findSector(flash: Block_Memory, offset: u32) BaseError!u8 { // } -pub fn sectorSize(flash: Flash_Device, sector: u8) BaseError!u32 { +pub fn sectorSize(flash: Block_Memory, sector: u32) BaseError!u32 { const sector_size_fn = flash.vtable.sector_size_fn orelse return error.Unsupported; return sector_size_fn(flash.ptr, sector); } @@ -71,17 +60,8 @@ pub const TestDevice = struct { sector_size: u32 = 16384, num_sectors: u8 = 4, - pub fn flash_device(td: *TestDevice) Flash_Device { - return Flash_Device{ .vtable = vtable, .ptr = td }; - } - - pub fn init(ctx: *anyopaque) BaseError!void { - const td: *TestDevice = @ptrCast(@alignCast(ctx)); - _ = td; - } - pub fn deinit(ctx: *anyopaque) BaseError!void { - const td: *TestDevice = @ptrCast(@alignCast(ctx)); - td.arena.deinit(); + pub fn block_memory(td: *TestDevice) Block_Memory { + return Block_Memory{ .vtable = vtable, .ptr = td }; } pub fn enableWrite(ctx: *anyopaque) BaseError!void { const td: *TestDevice = @ptrCast(@alignCast(ctx)); @@ -134,8 +114,6 @@ pub const TestDevice = struct { } } const vtable = VTable{ - .init_fn = TestDevice.init, - .deinit_fn = TestDevice.deinit, .enable_write_fn = TestDevice.enableWrite, .disable_write_fn = TestDevice.disableWrite, .erase_fn = TestDevice.erase, @@ -146,14 +124,15 @@ pub const TestDevice = struct { }; test TestDevice { + const allocator = std.heap.ArenaAllocator.init(std.testing.allocator); + defer allocator.deinit(); var td: TestDevice = .{ - .arena = std.heap.ArenaAllocator.init(std.testing.allocator), + .arena = allocator, }; td.sector_size = 10; - const fd = td.flash_device(); - try fd.init(); + const fd = td.Block_Memory(); var buffer: [3]u8 = .{ 42, 43, 44 }; try std.testing.expectError(error.WriteDisabled, fd.write(0, buffer[0..])); try std.testing.expectError(error.ReadDisabled, fd.read(0, buffer[0..])); diff --git a/drivers/framework.zig b/drivers/framework.zig index 0b42e9f93..f132f266f 100644 --- a/drivers/framework.zig +++ b/drivers/framework.zig @@ -200,6 +200,7 @@ pub const base = struct { pub const Stream_Device = @import("base/Stream_Device.zig"); pub const Digital_IO = @import("base/Digital_IO.zig"); pub const Clock_Device = @import("base/Clock_Device.zig"); + pub const Block_Memory = @import("base/Block_Memory.zig"); }; test { @@ -229,4 +230,5 @@ test { _ = base.Datagram_Device; _ = base.Stream_Device; _ = base.Digital_IO; + _ = base.Block_Memory; } From 1197fe3873397fa8ef7c1501423818a1ab6fce40 Mon Sep 17 00:00:00 2001 From: copper280z Date: Fri, 11 Jul 2025 07:37:41 -0400 Subject: [PATCH 3/3] fix test device function argument types --- drivers/base/Block_Memory.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/base/Block_Memory.zig b/drivers/base/Block_Memory.zig index 003d4b885..ebb197cd2 100644 --- a/drivers/base/Block_Memory.zig +++ b/drivers/base/Block_Memory.zig @@ -75,7 +75,7 @@ pub const TestDevice = struct { td.read_enabled = false; td.write_enabled = false; } - pub fn erase(ctx: *anyopaque, sector: u8) WriteError!void { + pub fn erase(ctx: *anyopaque, sector: u32) WriteError!void { const td: *TestDevice = @ptrCast(@alignCast(ctx)); if (td.write_enabled) { std.debug.print("Erasing sector: {}\n", .{sector}); @@ -84,7 +84,7 @@ pub const TestDevice = struct { } } - pub fn write(ctx: *anyopaque, sector: u8, data: []u8) WriteError!void { + pub fn write(ctx: *anyopaque, sector: u32, data: []u8) WriteError!void { const td: *TestDevice = @ptrCast(@alignCast(ctx)); if (td.write_enabled) { std.debug.print("Writing offset: {}, data length: {}\n", .{ sector, data.len }); @@ -105,7 +105,7 @@ pub const TestDevice = struct { return error.ReadDisabled; } } - pub fn sectorSize(ctx: *anyopaque, sector: u8) BaseError!u32 { + pub fn sectorSize(ctx: *anyopaque, sector: u32) BaseError!u32 { const td: *TestDevice = @ptrCast(@alignCast(ctx)); if (sector < td.num_sectors) { return td.sector_size; @@ -132,7 +132,7 @@ test TestDevice { td.sector_size = 10; - const fd = td.Block_Memory(); + const fd = td.block_memory(); var buffer: [3]u8 = .{ 42, 43, 44 }; try std.testing.expectError(error.WriteDisabled, fd.write(0, buffer[0..])); try std.testing.expectError(error.ReadDisabled, fd.read(0, buffer[0..]));