Skip to content

Commit 2e3682d

Browse files
authored
Flash driver interface (ZigEmbeddedGroup#589)
1 parent ed8e54c commit 2e3682d

2 files changed

Lines changed: 149 additions & 0 deletions

File tree

drivers/base/Block_Memory.zig

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
const std = @import("std");
2+
3+
const logger = std.log.scoped(.flash);
4+
5+
pub const BaseError = error{ Unsupported, InvalidSector };
6+
pub const WriteError = BaseError || error{ SectorOverrun, WriteDisabled };
7+
pub const ReadError = BaseError || error{ReadDisabled};
8+
9+
pub const VTable = struct {
10+
enable_write_fn: ?*const fn (*anyopaque) BaseError!void,
11+
disable_write_fn: ?*const fn (*anyopaque) BaseError!void,
12+
erase_fn: ?*const fn (*anyopaque, sector: u32) WriteError!void,
13+
write_fn: ?*const fn (*anyopaque, sector: u32, data: []u8) WriteError!void,
14+
read_fn: ?*const fn (*anyopaque, offset: u32, data: []u8) ReadError!usize,
15+
// find_sector_fn: ?*const fn (*anyopaque, offset: u32) BaseError!u32,
16+
sector_size_fn: ?*const fn (*anyopaque, sector: u32) BaseError!u32,
17+
};
18+
19+
pub const Block_Memory = @This();
20+
ptr: *anyopaque,
21+
vtable: VTable,
22+
23+
pub fn enable_write(mem: Block_Memory) BaseError!void {
24+
if (mem.vtable.enable_write_fn) |enable_write_fn| {
25+
return try enable_write_fn(mem.ptr);
26+
}
27+
}
28+
pub fn disable_write(mem: Block_Memory) BaseError!void {
29+
if (mem.vtable.disable_write_fn) |disable_write_fn| {
30+
return try disable_write_fn(mem.ptr);
31+
}
32+
}
33+
pub fn erase_sector(mem: Block_Memory, sector: u32) WriteError!void {
34+
const erase_fn = mem.vtable.erase_fn orelse return error.Unsupported;
35+
return erase_fn(mem.ptr, sector);
36+
}
37+
pub fn write(mem: Block_Memory, sector: u32, data: []u8) WriteError!void {
38+
const sector_capacity = try mem.sector_size(sector);
39+
if (data.len > sector_capacity) return error.SectorOverrun;
40+
try mem.erase_sector(sector);
41+
const write_fn = mem.vtable.write_fn orelse return error.Unsupported;
42+
return write_fn(mem.ptr, sector, data);
43+
}
44+
pub fn read(mem: Block_Memory, offset: u32, data: []u8) ReadError!usize {
45+
const read_fn = mem.vtable.read_fn orelse return error.Unsupported;
46+
return read_fn(mem.ptr, offset, data);
47+
}
48+
// pub fn findSector(flash: Block_Memory, offset: u32) BaseError!u8 {
49+
50+
// }
51+
pub fn sector_size(mem: Block_Memory, sector: u32) BaseError!u32 {
52+
const sector_size_fn = mem.vtable.sector_size_fn orelse return error.Unsupported;
53+
return sector_size_fn(mem.ptr, sector);
54+
}
55+
56+
pub const TestDevice = struct {
57+
arena: std.heap.ArenaAllocator,
58+
write_enabled: bool = false,
59+
read_enabled: bool = false,
60+
sector_capacity: u32 = 16384,
61+
num_sectors: u8 = 4,
62+
63+
pub fn block_memory(td: *TestDevice) Block_Memory {
64+
return Block_Memory{ .vtable = vtable, .ptr = td };
65+
}
66+
pub fn enable_write(ctx: *anyopaque) BaseError!void {
67+
const td: *TestDevice = @ptrCast(@alignCast(ctx));
68+
std.debug.print("Enable flash Write\n", .{});
69+
td.read_enabled = true;
70+
td.write_enabled = true;
71+
}
72+
pub fn disable_write(ctx: *anyopaque) BaseError!void {
73+
const td: *TestDevice = @ptrCast(@alignCast(ctx));
74+
std.debug.print("Disable flash Write\n", .{});
75+
td.read_enabled = false;
76+
td.write_enabled = false;
77+
}
78+
pub fn erase(ctx: *anyopaque, sector: u32) WriteError!void {
79+
const td: *TestDevice = @ptrCast(@alignCast(ctx));
80+
if (td.write_enabled) {
81+
std.debug.print("Erasing sector: {}\n", .{sector});
82+
} else {
83+
return error.WriteDisabled;
84+
}
85+
}
86+
87+
pub fn write(ctx: *anyopaque, sector: u32, data: []u8) WriteError!void {
88+
const td: *TestDevice = @ptrCast(@alignCast(ctx));
89+
if (td.write_enabled) {
90+
std.debug.print("Writing offset: {}, data length: {}\n", .{ sector, data.len });
91+
} else {
92+
return error.WriteDisabled;
93+
}
94+
}
95+
pub fn read(ctx: *anyopaque, offset: u32, data: []u8) ReadError!usize {
96+
const td: *TestDevice = @ptrCast(@alignCast(ctx));
97+
if (td.write_enabled) {
98+
std.debug.print("Reading offset: {}\n", .{offset});
99+
const length = data.len;
100+
for (0..length) |i| {
101+
data[i] = @intCast(i % 256);
102+
}
103+
return length;
104+
} else {
105+
return error.ReadDisabled;
106+
}
107+
}
108+
pub fn sector_size(ctx: *anyopaque, sector: u32) BaseError!u32 {
109+
const td: *TestDevice = @ptrCast(@alignCast(ctx));
110+
if (sector < td.num_sectors) {
111+
return td.sector_capacity;
112+
} else {
113+
return error.InvalidSector;
114+
}
115+
}
116+
const vtable = VTable{
117+
.enable_write_fn = TestDevice.enable_write,
118+
.disable_write_fn = TestDevice.disable_write,
119+
.erase_fn = TestDevice.erase,
120+
.write_fn = TestDevice.write,
121+
.read_fn = TestDevice.read,
122+
.sector_size_fn = TestDevice.sector_size,
123+
};
124+
};
125+
126+
test TestDevice {
127+
const allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
128+
defer allocator.deinit();
129+
var td: TestDevice = .{
130+
.arena = allocator,
131+
};
132+
133+
td.sector_capacity = 10;
134+
135+
const fd = td.block_memory();
136+
var buffer: [3]u8 = .{ 42, 43, 44 };
137+
try std.testing.expectError(error.WriteDisabled, fd.write(0, buffer[0..]));
138+
try std.testing.expectError(error.ReadDisabled, fd.read(0, buffer[0..]));
139+
140+
try fd.enable_write();
141+
142+
try fd.write(0, buffer[0..]);
143+
try std.testing.expectEqual(buffer.len, fd.read(0x123, buffer[0..]));
144+
var big_buf: [11]u8 = undefined;
145+
@memset(big_buf[0..], 123);
146+
try std.testing.expectError(error.SectorOverrun, fd.write(0, big_buf[0..]));
147+
}

drivers/framework.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ pub const base = struct {
206206
pub const Stream_Device = @import("base/Stream_Device.zig");
207207
pub const Digital_IO = @import("base/Digital_IO.zig");
208208
pub const Clock_Device = @import("base/Clock_Device.zig");
209+
pub const Block_Memory = @import("base/Block_Memory.zig");
209210
pub const I2C_Device = @import("base/I2C_Device.zig");
210211
};
211212

@@ -238,6 +239,7 @@ test {
238239
_ = base.Datagram_Device;
239240
_ = base.Stream_Device;
240241
_ = base.Digital_IO;
242+
_ = base.Block_Memory;
241243
_ = base.Clock_Device;
242244
_ = base.I2C_Device;
243245
}

0 commit comments

Comments
 (0)