Compare commits
4 Commits
5b2a7bacaa
...
v0.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
| f9b5dffb64 | |||
|
|
51c49c38d8 | ||
| 9e4ee57ec2 | |||
| 10cbc36b6b |
@@ -60,7 +60,7 @@ If you don't have a `build.zig.zon` file, create one. If you do, just add `zig-g
|
||||
|
||||
.dependencies = .{
|
||||
.gpio = .{
|
||||
.url = "https://gitea.elara.ws/Elara6331/zig-gpio/archive/v0.0.1.tar.gz",
|
||||
.url = "https://gitea.elara.ws/Elara6331/zig-gpio/archive/v0.0.2.tar.gz",
|
||||
.hash = "1220e3af3194d1154217423d60124ae3a46537c2253dbfb8057e9b550526d2885df1",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -23,7 +24,7 @@ pub fn build(b: *std.Build) !void {
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
// Add the gpio module so it can be used by the package manager
|
||||
var gpio_module = b.createModule(.{ .source_file = .{ .path = "src/index.zig" } });
|
||||
const gpio_module = b.createModule(.{ .root_source_file = .{ .path = "src/index.zig" } });
|
||||
try b.modules.put(b.dupe("gpio"), gpio_module);
|
||||
|
||||
// Create a step to build all the examples
|
||||
@@ -40,7 +41,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe.addModule("gpio", gpio_module);
|
||||
exe.root_module.addImport("gpio", gpio_module);
|
||||
|
||||
const build_step = b.addInstallArtifact(exe, .{});
|
||||
step.dependOn(&build_step.step);
|
||||
@@ -61,7 +62,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe.addModule("gpio", gpio_module);
|
||||
exe.root_module.addImport("gpio", gpio_module);
|
||||
|
||||
const build_step = b.addInstallArtifact(exe, .{});
|
||||
step.dependOn(&build_step.step);
|
||||
|
||||
@@ -2,7 +2,7 @@ const std = @import("std");
|
||||
const gpio = @import("gpio");
|
||||
|
||||
pub fn main() !void {
|
||||
var iter_dir = try std.fs.openIterableDirAbsolute("/dev", .{});
|
||||
var iter_dir = try std.fs.openDirAbsolute("/dev", .{ .iterate = true });
|
||||
defer iter_dir.close();
|
||||
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
@@ -11,7 +11,7 @@ pub fn main() !void {
|
||||
while (try iter.next()) |entry| {
|
||||
if (!hasPrefix(entry.name, "gpiochip")) continue;
|
||||
|
||||
const fl = try iter_dir.dir.openFile(entry.name, .{});
|
||||
const fl = try iter_dir.openFile(entry.name, .{});
|
||||
var chip = try gpio.getChipByFd(fl.handle);
|
||||
defer chip.close(); // This will close the fd
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn main() !void {
|
||||
return error.InsufficientArguments;
|
||||
}
|
||||
|
||||
var path: []const u8 = if (hasPrefix(args[1], "gpiochip"))
|
||||
const 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] });
|
||||
@@ -32,7 +32,7 @@ pub fn main() !void {
|
||||
// Iterate over each argument starting from the second one
|
||||
for (args[2..args.len]) |argument| {
|
||||
// Parse each argument as an integer and add it to offsets
|
||||
var offset = try std.fmt.parseInt(u32, argument, 10);
|
||||
const offset = try std.fmt.parseUnsigned(u32, argument, 10);
|
||||
try offsets.append(offset);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn main() !void {
|
||||
|
||||
// If the argument has the "gpiochip" prefix,
|
||||
// just use it unchanged. Otherwise, add the prefix.
|
||||
var filename: []const u8 = if (hasGpiochip)
|
||||
const filename: []const u8 = if (hasGpiochip)
|
||||
argument
|
||||
else
|
||||
try std.mem.concat(alloc, u8, &.{ "gpiochip", argument });
|
||||
|
||||
53
src/cmd/set.zig
Normal file
53
src/cmd/set.zig
Normal file
@@ -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} <gpiochip> <line=value...>\n\n", .{args[0]});
|
||||
return error.InsufficientArguments;
|
||||
}
|
||||
|
||||
const 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
|
||||
const offset = try std.fmt.parseUnsigned(u32, argument[0..eqIndex], 10);
|
||||
const 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));
|
||||
}
|
||||
58
src/gpio.zig
58
src/gpio.zig
@@ -3,19 +3,19 @@ const gpio = @import("index.zig");
|
||||
|
||||
/// Opens the file at path and uses the file descriptor to get the gpiochip.
|
||||
pub fn getChip(path: []const u8) !Chip {
|
||||
var fl = try std.fs.openFileAbsolute(path, .{});
|
||||
const fl = try std.fs.openFileAbsolute(path, .{});
|
||||
return try getChipByFd(fl.handle);
|
||||
}
|
||||
|
||||
/// Same as `getChip` but the `path` parameter is null-terminated.
|
||||
pub fn getChipZ(path: [*:0]const u8) !Chip {
|
||||
var fl = try std.fs.openFileAbsoluteZ(path, .{});
|
||||
const fl = try std.fs.openFileAbsoluteZ(path, .{});
|
||||
return try getChipByFd(fl.handle);
|
||||
}
|
||||
|
||||
/// Returns a `chip` with the given file descriptor.
|
||||
pub fn getChipByFd(fd: std.os.fd_t) !Chip {
|
||||
var info = try gpio.uapi.getChipInfo(fd);
|
||||
pub fn getChipByFd(fd: std.posix.fd_t) !Chip {
|
||||
const info = try gpio.uapi.getChipInfo(fd);
|
||||
return Chip{
|
||||
.name = info.name,
|
||||
.label = info.label,
|
||||
@@ -35,7 +35,7 @@ pub const Chip = struct {
|
||||
/// If it isn't set, "zig-gpio" will be used instead.
|
||||
consumer: ?[gpio.uapi.MAX_NAME_SIZE]u8 = null,
|
||||
/// The file descriptor of the `gpiochip` device.
|
||||
handle: std.os.fd_t,
|
||||
handle: std.posix.fd_t,
|
||||
// The amount of lines available under this device.
|
||||
lines: u32,
|
||||
closed: bool = false,
|
||||
@@ -71,7 +71,7 @@ pub const Chip = struct {
|
||||
|
||||
/// Requests and returns a single line at the given `offset`, from the given `chip`.
|
||||
pub fn requestLine(self: Chip, offset: u32, flags: gpio.uapi.LineFlags) !Line {
|
||||
var l = try self.requestLines(&.{offset}, flags);
|
||||
const l = try self.requestLines(&.{offset}, flags);
|
||||
return Line{ .lines = l };
|
||||
}
|
||||
|
||||
@@ -108,14 +108,14 @@ pub const Chip = struct {
|
||||
pub fn close(self: *Chip) void {
|
||||
if (self.closed) return;
|
||||
self.closed = true;
|
||||
std.os.close(self.handle);
|
||||
std.posix.close(self.handle);
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a collection of lines requested from a `chip`.
|
||||
pub const Lines = struct {
|
||||
/// The file descriptor of the lines.
|
||||
handle: std.os.fd_t,
|
||||
handle: std.posix.fd_t,
|
||||
/// The amount of lines being controlled.
|
||||
num_lines: u32,
|
||||
/// The offsets of the lines being controlled.
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -223,7 +254,7 @@ pub const Lines = struct {
|
||||
pub fn close(self: *Lines) void {
|
||||
if (self.closed) return;
|
||||
self.closed = true;
|
||||
std.os.close(self.handle);
|
||||
std.posix.close(self.handle);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
20
src/uapi.zig
20
src/uapi.zig
@@ -176,20 +176,20 @@ pub const LineInfoChanged = extern struct {
|
||||
/// Returns an error based on the given return code
|
||||
fn handleErrno(ret: usize) !void {
|
||||
if (ret == 0) return;
|
||||
return switch (std.os.errno(ret)) {
|
||||
return switch (std.posix.errno(ret)) {
|
||||
.BUSY => error.DeviceIsBusy,
|
||||
.INVAL => error.InvalidArgument,
|
||||
.BADF => error.BadFileDescriptor,
|
||||
.NOTTY => error.InappropriateIOCTLForDevice,
|
||||
.IO => error.IOError,
|
||||
.FAULT => unreachable,
|
||||
else => |err| return std.os.unexpectedErrno(err),
|
||||
else => |err| return std.posix.unexpectedErrno(err),
|
||||
};
|
||||
}
|
||||
|
||||
/// Executes `GPIO_GET_CHIPINFO_IOCTL` on the given fd and returns the resulting
|
||||
/// `ChipInfo` value
|
||||
pub fn getChipInfo(fd: std.os.fd_t) !ChipInfo {
|
||||
pub fn getChipInfo(fd: std.posix.fd_t) !ChipInfo {
|
||||
const req = std.os.linux.IOCTL.IOR(0xB4, 0x01, ChipInfo);
|
||||
var info = std.mem.zeroes(ChipInfo);
|
||||
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&info)));
|
||||
@@ -198,7 +198,7 @@ pub fn getChipInfo(fd: std.os.fd_t) !ChipInfo {
|
||||
|
||||
/// Executes `GPIO_V2_GET_LINEINFO_IOCTL` on the given fd and returns the resulting
|
||||
/// `LineInfo` value
|
||||
pub fn getLineInfo(fd: std.os.fd_t, offset: u32) !LineInfo {
|
||||
pub fn getLineInfo(fd: std.posix.fd_t, offset: u32) !LineInfo {
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x05, LineInfo);
|
||||
var info = std.mem.zeroes(LineInfo);
|
||||
info.offset = offset;
|
||||
@@ -208,7 +208,7 @@ pub fn getLineInfo(fd: std.os.fd_t, offset: u32) !LineInfo {
|
||||
|
||||
/// Executes `GPIO_V2_GET_LINEINFO_WATCH_IOCTL` on the given fd and returns the resulting
|
||||
/// `LineInfo` value
|
||||
pub fn watchLineInfo(fd: std.os.fd_t, offset: u32) !LineInfo {
|
||||
pub fn watchLineInfo(fd: std.posix.fd_t, offset: u32) !LineInfo {
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x06, LineInfo);
|
||||
var info = std.mem.zeroes(LineInfo);
|
||||
info.offset = offset;
|
||||
@@ -217,14 +217,14 @@ pub fn watchLineInfo(fd: std.os.fd_t, offset: u32) !LineInfo {
|
||||
}
|
||||
|
||||
/// Executes `GPIO_GET_LINEINFO_UNWATCH_IOCTL` on the given fd
|
||||
pub fn unwatchLineInfo(fd: std.os.fd_t, offset: u32) !void {
|
||||
pub fn unwatchLineInfo(fd: std.posix.fd_t, offset: u32) !void {
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0C, u32);
|
||||
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&offset)));
|
||||
}
|
||||
|
||||
/// Executes `GPIO_V2_GET_LINE_IOCTL` on the given fd and returns the resulting
|
||||
/// line descriptor
|
||||
pub fn getLine(fd: std.os.fd_t, lr: LineRequest) !std.os.fd_t {
|
||||
pub fn getLine(fd: std.posix.fd_t, lr: LineRequest) !std.posix.fd_t {
|
||||
const lrp = &lr;
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x07, LineRequest);
|
||||
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(lrp)));
|
||||
@@ -233,7 +233,7 @@ pub fn getLine(fd: std.os.fd_t, lr: LineRequest) !std.os.fd_t {
|
||||
|
||||
/// Executes `GPIO_V2_LINE_GET_VALUES_IOCTL` on the given fd with the given mask,
|
||||
/// and returns a bitset representing all the line values.
|
||||
pub fn getLineValues(fd: std.os.fd_t, mask: LineValueBitset) !LineValueBitset {
|
||||
pub fn getLineValues(fd: std.posix.fd_t, mask: LineValueBitset) !LineValueBitset {
|
||||
var vals = LineValues{ .mask = mask };
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0E, LineValues);
|
||||
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&vals)));
|
||||
@@ -241,13 +241,13 @@ pub fn getLineValues(fd: std.os.fd_t, mask: LineValueBitset) !LineValueBitset {
|
||||
}
|
||||
|
||||
/// Executes `GPIO_V2_LINE_SET_VALUES_IOCTL` on the given fd
|
||||
pub fn setLineValues(fd: std.os.fd_t, lv: LineValues) !void {
|
||||
pub fn setLineValues(fd: std.posix.fd_t, lv: LineValues) !void {
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0F, LineValues);
|
||||
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&lv)));
|
||||
}
|
||||
|
||||
/// Executes `GPIO_V2_LINE_SET_CONFIG_IOCTL` on the given fd
|
||||
pub fn setLineConfig(fd: std.os.fd_t, lc: LineConfig) !void {
|
||||
pub fn setLineConfig(fd: std.posix.fd_t, lc: LineConfig) !void {
|
||||
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0D, LineConfig);
|
||||
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&lc)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user