From 10cbc36b6bd4a8f283239a0a2c0e9780fc6e054c Mon Sep 17 00:00:00 2001 From: Elara6331 Date: Mon, 25 Dec 2023 12:50:17 -0800 Subject: [PATCH] Add gpioset command --- build.zig | 1 + src/cmd/set.zig | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gpio.zig | 40 ++++++++++++++++++++++++++++++++++++- 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/cmd/set.zig diff --git a/build.zig b/build.zig index 0f66566..c1fa711 100644 --- a/build.zig +++ b/build.zig @@ -16,6 +16,7 @@ const commands = [_]Item{ .{ .name = "gpiodetect", .src = "src/cmd/detect.zig" }, .{ .name = "gpioinfo", .src = "src/cmd/info.zig" }, .{ .name = "gpioget", .src = "src/cmd/get.zig" }, + .{ .name = "gpioset", .src = "src/cmd/set.zig" }, }; pub fn build(b: *std.Build) !void { diff --git a/src/cmd/set.zig b/src/cmd/set.zig new file mode 100644 index 0000000..5bc44f7 --- /dev/null +++ b/src/cmd/set.zig @@ -0,0 +1,53 @@ +const std = @import("std"); +const gpio = @import("gpio"); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer std.debug.assert(gpa.deinit() == .ok); + const alloc = gpa.allocator(); + + var args = try std.process.argsAlloc(alloc); + defer std.process.argsFree(alloc, args); + + const stdout = std.io.getStdOut().writer(); + + if (args.len < 3) { + try stdout.print("Usage: {s} \n\n", .{args[0]}); + return error.InsufficientArguments; + } + + var path: []const u8 = if (hasPrefix(args[1], "gpiochip")) + try std.mem.concat(alloc, u8, &.{ "/dev/", args[1] }) + else + try std.mem.concat(alloc, u8, &.{ "/dev/gpiochip", args[1] }); + defer alloc.free(path); + + var chip = try gpio.getChip(path); + defer chip.close(); + try chip.setConsumer("gpioset"); + + var values = std.AutoArrayHashMap(u32, bool).init(alloc); + defer values.deinit(); + + // Iterate over each argument starting from the second one + for (args[2..args.len]) |argument| { + // Get the index of the equals sign in the argument + const eqIndex = std.mem.indexOf(u8, argument, "=") orelse return error.InvalidArgument; + // Parse each argument's offset and value, and add it to the values map + var offset = try std.fmt.parseUnsigned(u32, argument[0..eqIndex], 10); + var value = try std.fmt.parseUnsigned(u1, argument[eqIndex + 1 .. argument.len], 10); + try values.put(offset, value != 0); + } + + var lines = try chip.requestLines(values.keys(), .{ .output = true }); + defer lines.close(); + + var vals = gpio.uapi.LineValueBitset{ .mask = 0 }; + for (0.., values.values()) |i, val| vals.setValue(i, val); + try lines.setAllValues(vals); +} + +fn hasPrefix(s: []const u8, prefix: []const u8) bool { + if (s.len < prefix.len) return false; + return (std.mem.eql(u8, s[0..prefix.len], prefix)); +} diff --git a/src/gpio.zig b/src/gpio.zig index e22c229..3083d91 100644 --- a/src/gpio.zig +++ b/src/gpio.zig @@ -209,13 +209,44 @@ pub const Lines = struct { try gpio.uapi.setLineConfig(self.handle, lc); } + /// Sets the values of the lines at the given indices. + /// + /// Note that this function takes indices and not offsets. + /// The indices correspond to the index of the offset in your request. + /// For example, if you requested `&.{22, 20, 23}`, + /// `22` will correspond to `0`, `20` will correspond to `1`, + /// and `23` will correspond to `2`. + pub fn setValues(self: Lines, indices: []const u32, vals: gpio.uapi.LineValueBitset) !void { + if (self.closed) return error.LineClosed; + var lv = gpio.uapi.LineValues{ .bits = vals }; + for (indices) |index| { + if (index >= self.num_lines) return error.IndexOutOfRange; + lv.mask.set(index); + } + return try gpio.uapi.setLineValues(self.handle, lv); + } + + /// Sets the values of all the controlled lines + pub fn setAllValues(self: Lines, vals: gpio.uapi.LineValueBitset) !void { + if (self.closed) return error.LineClosed; + var lv = gpio.uapi.LineValues{ .bits = vals }; + + // Add all the indices to the bitset of values to set + var i: u32 = 0; + while (i < self.num_lines) : (i += 1) lv.mask.set(i); + + return try gpio.uapi.setLineValues(self.handle, lv); + } + /// Gets the values of all the controlled lines as a bitset pub fn getValues(self: Lines) !gpio.uapi.LineValueBitset { if (self.closed) return error.LineClosed; var vals = gpio.uapi.LineValueBitset{ .mask = 0 }; + + // Add all the indices to the bitset of values to get var i: u32 = 0; - // Add all the indices to the list of values to get while (i < self.num_lines) : (i += 1) vals.set(i); + return try gpio.uapi.getLineValues(self.handle, vals); } @@ -242,6 +273,13 @@ pub const Line = struct { try self.lines.setLow(&.{0}); } + // Sets the value of the line. + pub fn setValue(self: Line, value: bool) !void { + var vals = gpio.uapi.LineValueBitset{ .mask = 0 }; + vals.setValue(0, value); + try self.lines.setValues(&.{0}, vals); + } + /// Sets the configuration flags of the line. pub fn reconfigure(self: Line, flags: gpio.uapi.LineFlags) !void { try self.lines.reconfigure(&.{0}, flags);