From b5d8b11ac7eba23b6194e10cb0363d071c9e965e Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Mon, 22 Jun 2026 11:06:59 +0900 Subject: [PATCH 01/16] refactor: Build prep for zig 0.16.0 --- .gitignore | 1 + build.zig | 43 ++++++++++++++++++++++++------------ build.zig.zon | 18 +++++++-------- src/Config.zig | 4 ++++ src/command.zig | 4 ++++ src/command/mcl.zig | 10 ++++++--- src/command/return_demo2.zig | 4 ++++ src/main.zig | 2 +- 8 files changed, 59 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 9d4e1db0..1267feed 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ zig-out/** zig-cache/** .zig-cache/** vendor/** +zig-pkg/** diff --git a/build.zig b/build.zig index b7d01915..356bd311 100644 --- a/build.zig +++ b/build.zig @@ -18,24 +18,39 @@ pub fn build(b: *std.Build) !void { "Enable building a mock version of the MELSEC data link library.", ) orelse (target.result.os.tag != .windows); - const mcl = b.dependency("mcl", .{ + const network = b.dependency("network", .{}); + const chrono = b.dependency("chrono", .{}); + const build_zig_zon = b.createModule(.{ + .root_source_file = b.path("build.zig.zon"), + .target = target, + .optimize = optimize, + }); + const mmc_api = b.dependency("mmc_api", .{ .target = target, .optimize = optimize, .mdfunc = mdfunc_lib_path, - .mdfunc_mock = mdfunc_mock_build, + .mock = mdfunc_mock_build, }); - const network_dep = b.dependency("network", .{}); - const chrono = b.dependency("chrono", .{}); + const imports: []const std.Build.Module.Import = &.{ + .{ .name = "build.zig.zon", .module = build_zig_zon }, + .{ .name = "chrono", .module = chrono.module("chrono") }, + .{ .name = "network", .module = network.module("network") }, + }; - const exe = b.addExecutable(.{ - .name = "mmc-cli", + const mod = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, + .imports = imports, + .error_tracing = true, }); - exe.root_module.addImport("network", network_dep.module("network")); - exe.root_module.addImport("mcl", mcl.module("mcl")); - exe.root_module.addImport("chrono", chrono.module("chrono")); + + const exe = b.addExecutable(.{ + .name = "mmc-cli", + .root_module = mod, + }); + + exe.root_module.addImport("mcl", mmc_api.module("mcl")); b.installArtifact(exe); @@ -51,14 +66,14 @@ pub fn build(b: *std.Build) !void { // Creates a step for unit testing. This only builds the test executable // but does not run it. - const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), + const mmc_api_mock = b.dependency("mmc_api", .{ .target = target, .optimize = optimize, + .mdfunc = mdfunc_lib_path, + .mock = true, }); - unit_tests.root_module.addImport("network", network_dep.module("network")); - unit_tests.root_module.addImport("mcl", mcl.module("mcl")); - unit_tests.root_module.addImport("chrono", chrono.module("chrono")); + const unit_tests = b.addTest(.{ .root_module = mod }); + unit_tests.root_module.addImport("mcl", mmc_api_mock.module("mcl")); const run_unit_tests = b.addRunArtifact(unit_tests); const test_step = b.step("test", "Run unit tests"); diff --git a/build.zig.zon b/build.zig.zon index e8b7a3e3..ba6b5ca8 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,20 +1,20 @@ .{ .name = .mmc_cli, .version = "0.2.4", - .fingerprint = 0x392c749893371ea5, - .minimum_zig_version = "0.14.0-dev.15+d4bc64038", + .fingerprint = 0x392c7498d8f608a5, + .minimum_zig_version = "0.16.0", .dependencies = .{ .network = .{ - .url = "https://github.com/mochalins/zig-network/archive/359fec9.tar.gz", - .hash = "12206c7cbba4130ac158f7759c81ae4186c3e9f914bc79b0544492d85405ba01aaa4", + .url = "https://github.com/mochalins/network/archive/084fed7.tar.gz", + .hash = "network-0.1.0-Pm-AgiMxAQCuaDrGAfSxVHeozUQ2gU3jINGLFxJ1Zpld", }, - .mcl = .{ - .url = "https://github.com/pmotionf/mcl/archive/4d1d168.tar.gz", - .hash = "mcl-0.3.1-r3NKp28IAQBOCnJLpdmMJEe4ZfvikMnLzA2XPwjREj8I", + .mmc_api = .{ + .url = "https://github.com/pmotionf/mmc-api/archive/0b50b4f8a934666d2934d3c24a46e2e06062838d.tar.gz", + .hash = "mmc_api-0.0.0-P5raR6VtMwCIvOPg-bEfOx5Fu4AdWLb5EG8Jo4ZuLCmq", }, .chrono = .{ - .url = "https://github.com/pmotionf/chrono/archive/620de75.tar.gz", - .hash = "chrono-0.1.0-uVd76GvCAwAvWrHupKdlB_UrmfZHRuVP-P4Xi_G8hz3R", + .url = "https://github.com/aaumar25/chrono/archive/adfc771.tar.gz", + .hash = "chrono-0.1.0-uVd76BPDAwAyXqy0OAP1MvUyfk72pvv7e6bU7s2TqV0h", }, }, .paths = .{""}, diff --git a/src/Config.zig b/src/Config.zig index c2bc266a..4a66f8bf 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -47,3 +47,7 @@ pub fn modules(self: *Config) []const ModuleConfig { pub fn deinit(self: *Config) void { self.parsed.deinit(); } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/command.zig b/src/command.zig index 4006ec66..0385d985 100644 --- a/src/command.zig +++ b/src/command.zig @@ -595,3 +595,7 @@ fn clear(_: [][]const u8) !void { fn exit(_: [][]const u8) !void { std.process.exit(1); } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/command/mcl.zig b/src/command/mcl.zig index 90da4dcd..d46d1aef 100644 --- a/src/command/mcl.zig +++ b/src/command/mcl.zig @@ -429,7 +429,7 @@ pub fn init(c: Config) !void { }, .short_description = "Wait until recovery of slider is complete.", .long_description = - \\Wait until slider recovery is complete and a slider is recognized. + \\Wait until slider recovery is complete and a slider is recognized. \\If an optional result variable name is provided, then store the \\recognized slider ID in the variable. , @@ -476,7 +476,7 @@ pub fn init(c: Config) !void { }, .short_description = "Move slider by a distance.", .long_description = - \\Move given slider by a provided distance. The slider ID must be + \\Move given slider by a provided distance. The slider ID must be \\currently recognized within the motion system, and the distance must \\be provided in millimeters as a whole or decimal number. The distance \\may be negative for backward movement. @@ -526,7 +526,7 @@ pub fn init(c: Config) !void { }, .short_description = "Move slider by a distance.", .long_description = - \\Move given slider by a provided distance. The slider ID must be + \\Move given slider by a provided distance. The slider ID must be \\currently recognized within the motion system, and the distance must \\be provided in millimeters as a whole or decimal number. The distance \\may be negative for backward movement. This command moves the slider @@ -2496,3 +2496,7 @@ fn sendCommand(station: Station) !void { .InvalidAxis => error.InvalidAxis, }; } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/command/return_demo2.zig b/src/command/return_demo2.zig index 236b1325..032c2755 100644 --- a/src/command/return_demo2.zig +++ b/src/command/return_demo2.zig @@ -360,3 +360,7 @@ fn beltMoveEnd(_: [][]const u8) !void { } } else return error.ReturnSystemDisconnected; } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/main.zig b/src/main.zig index e383fa08..b2df981a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -71,5 +71,5 @@ pub fn main() !void { } test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } From 8e6db7930de8bd4fdbd53b6f8c5ba3e96d97fb66 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Mon, 22 Jun 2026 13:20:50 +0900 Subject: [PATCH 02/16] refactor: Changes required for zig 0.16.0 --- build.zig | 6 +- build.zig.zon | 4 - src/Config.zig | 15 +-- src/command.zig | 222 +++++++++++++++++------------------ src/command/mcl.zig | 202 +++++++++++++++---------------- src/command/return_demo2.zig | 6 +- src/main.zig | 37 +++--- 7 files changed, 237 insertions(+), 255 deletions(-) diff --git a/build.zig b/build.zig index 356bd311..9a6c4a9d 100644 --- a/build.zig +++ b/build.zig @@ -18,7 +18,6 @@ pub fn build(b: *std.Build) !void { "Enable building a mock version of the MELSEC data link library.", ) orelse (target.result.os.tag != .windows); - const network = b.dependency("network", .{}); const chrono = b.dependency("chrono", .{}); const build_zig_zon = b.createModule(.{ .root_source_file = b.path("build.zig.zon"), @@ -29,12 +28,11 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, .mdfunc = mdfunc_lib_path, - .mock = mdfunc_mock_build, + .mdfunc_mock = mdfunc_mock_build, }); const imports: []const std.Build.Module.Import = &.{ .{ .name = "build.zig.zon", .module = build_zig_zon }, .{ .name = "chrono", .module = chrono.module("chrono") }, - .{ .name = "network", .module = network.module("network") }, }; const mod = b.createModule(.{ @@ -70,7 +68,7 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, .mdfunc = mdfunc_lib_path, - .mock = true, + .mdfunc_mock = true, }); const unit_tests = b.addTest(.{ .root_module = mod }); unit_tests.root_module.addImport("mcl", mmc_api_mock.module("mcl")); diff --git a/build.zig.zon b/build.zig.zon index ba6b5ca8..fe60e032 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -4,10 +4,6 @@ .fingerprint = 0x392c7498d8f608a5, .minimum_zig_version = "0.16.0", .dependencies = .{ - .network = .{ - .url = "https://github.com/mochalins/network/archive/084fed7.tar.gz", - .hash = "network-0.1.0-Pm-AgiMxAQCuaDrGAfSxVHeozUQ2gU3jINGLFxJ1Zpld", - }, .mmc_api = .{ .url = "https://github.com/pmotionf/mmc-api/archive/0b50b4f8a934666d2934d3c24a46e2e06062838d.tar.gz", .hash = "mmc_api-0.0.0-P5raR6VtMwCIvOPg-bEfOx5Fu4AdWLb5EG8Jo4ZuLCmq", diff --git a/src/Config.zig b/src/Config.zig index 4a66f8bf..141b3220 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -8,28 +8,23 @@ parsed: std.json.Parsed(Parse), pub const Module = enum { mcl, - return_demo2, }; const ModuleConfig = union(Module) { mcl: MclConfig, - return_demo2: ReturnDemo2Config, }; const Parse = struct { modules: []ModuleConfig, }; -pub fn parse(allocator: std.mem.Allocator, f: std.fs.File) !Config { - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena.deinit(); - const a = arena.allocator(); - const f_reader = f.reader(); - var json_reader = std.json.reader(a, f_reader); - +pub fn parse(io: std.Io, gpa: std.mem.Allocator, f: std.Io.File) !Config { + var file_reader = f.reader(io, &.{}); + var json_reader: std.json.Reader = .init(gpa, &file_reader.interface); + defer json_reader.deinit(); const _result = try std.json.parseFromTokenSource( Parse, - allocator, + gpa, &json_reader, .{}, ); diff --git a/src/command.zig b/src/command.zig index 0385d985..908c82e9 100644 --- a/src/command.zig +++ b/src/command.zig @@ -4,15 +4,15 @@ const std = @import("std"); const chrono = @import("chrono"); +const build_zig_zon = @import("build.zig.zon"); // Command modules. const mcl = @import("command/mcl.zig"); -const return_demo2 = @import("command/return_demo2.zig"); const Config = @import("Config.zig"); // Global registry of all commands, including from other command modules. -pub var registry: std.StringArrayHashMap(Command) = undefined; +pub var registry: std.array_hash_map.String(Command) = .empty; // Global "stop" flag to interrupt command execution. Command modules should // not use this atomic flag directly, but instead prefer to use the @@ -27,10 +27,13 @@ pub var variables: std.BufMap = undefined; // initialized will be deinitialized. var initialized_modules: std.EnumArray(Config.Module, bool) = undefined; -var command_queue: std.ArrayList(CommandString) = undefined; +var command_queue: std.ArrayList(CommandString) = .empty; -var timer: ?std.time.Timer = null; -var log_file: ?std.fs.File = null; +var timer: std.Io.Timestamp = .zero; +var clock: std.Io.Clock = .real; +var log_file: ?std.Io.File = null; +var io_command: std.Io = undefined; +var io_buf: [4096]u8 = undefined; const CommandString = struct { buffer: [1024]u8, @@ -47,7 +50,7 @@ pub const Command = struct { short_description: []const u8, /// Long description of command. long_description: []const u8, - execute: *const fn ([][]const u8) anyerror!void, + execute: *const fn (std.Io, std.mem.Allocator, [][]const u8) anyerror!void, pub const Parameter = struct { name: []const u8, @@ -58,45 +61,40 @@ pub const Command = struct { }; pub fn logFn( - comptime message_level: std.log.Level, - comptime scope: @TypeOf(.EnumLiteral), + comptime level: std.log.Level, + comptime scope: @EnumLiteral(), comptime format: []const u8, args: anytype, ) void { - const level_txt = comptime message_level.asText(); - const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; - + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); if (log_file) |f| { - var bw = std.io.bufferedWriter(f.writer()); - const writer = bw.writer(); - writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; - bw.flush() catch return; - } - - const stderr = std.io.getStdErr().writer(); - var bw = std.io.bufferedWriter(stderr); - const writer = bw.writer(); - - std.debug.lockStdErr(); - defer std.debug.unlockStdErr(); - nosuspend { - writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; - bw.flush() catch return; + const file_writer = f.writer(io_command, &io_buf); + var writer = file_writer.interface; + writer.print("{s}({t}):", .{ level.asText(), scope }) catch {}; + writer.print(format ++ "\n", args) catch {}; + writer.flush() catch return; } + var buffer: [64]u8 = undefined; + const stderr = std.debug.lockStderr(&buffer).terminal(); + defer std.debug.unlockStderr(); + return std.log.defaultLogFileTerminal( + level, + scope, + format, + args, + stderr, + ) catch {}; } -pub fn init() !void { - arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - allocator = arena.allocator(); - +pub fn init(io: std.Io, gpa: std.mem.Allocator) !void { + io_command = io; initialized_modules = std.EnumArray(Config.Module, bool).initFill(false); - registry = std.StringArrayHashMap(Command).init(allocator); - variables = std.BufMap.init(allocator); - command_queue = std.ArrayList(CommandString).init(allocator); + variables = std.BufMap.init(gpa); stop.store(false, .monotonic); - timer = try std.time.Timer.start(); - try registry.put("HELP", .{ + try registry.put(gpa, "HELP", .{ .name = "HELP", .parameters = &[_]Command.Parameter{ .{ .name = "command", .optional = true, .resolve = false }, @@ -109,7 +107,7 @@ pub fn init() !void { , .execute = &help, }); - try registry.put("VERSION", .{ + try registry.put(gpa, "VERSION", .{ .name = "VERSION", .short_description = "Display the version of the MMC CLI.", .long_description = @@ -118,7 +116,7 @@ pub fn init() !void { , .execute = &version, }); - try registry.put("LOAD_CONFIG", .{ + try registry.put(gpa, "LOAD_CONFIG", .{ .name = "LOAD_CONFIG", .parameters = &[_]Command.Parameter{ .{ .name = "file path", .optional = true }, @@ -131,7 +129,7 @@ pub fn init() !void { , .execute = &loadConfig, }); - try registry.put("WAIT", .{ + try registry.put(gpa, "WAIT", .{ .name = "WAIT", .parameters = &[_]Command.Parameter{ .{ .name = "duration", .resolve = true }, @@ -143,14 +141,14 @@ pub fn init() !void { , .execute = &wait, }); - try registry.put("CLEAR", .{ + try registry.put(gpa, "CLEAR", .{ .name = "CLEAR", .parameters = &.{}, .short_description = "Clear visible screen output.", .long_description = "Clear visible screen output.", .execute = &clear, }); - try registry.put("SET", .{ + try registry.put(gpa, "SET", .{ .name = "SET", .parameters = &[_]Command.Parameter{ .{ .name = "variable", .resolve = false }, @@ -163,7 +161,7 @@ pub fn init() !void { , .execute = &set, }); - try registry.put("GET", .{ + try registry.put(gpa, "GET", .{ .name = "GET", .parameters = &[_]Command.Parameter{ .{ .name = "variable", .resolve = false }, @@ -175,7 +173,7 @@ pub fn init() !void { , .execute = &get, }); - try registry.put("VARIABLES", .{ + try registry.put(gpa, "VARIABLES", .{ .name = "VARIABLES", .short_description = "Display all variables with their values.", .long_description = @@ -183,7 +181,7 @@ pub fn init() !void { , .execute = &printVariables, }); - try registry.put("TIMER_START", .{ + try registry.put(gpa, "TIMER_START", .{ .name = "TIMER_START", .short_description = "Start a monotonic system timer.", .long_description = @@ -193,7 +191,7 @@ pub fn init() !void { , .execute = &timerStart, }); - try registry.put("TIMER_READ", .{ + try registry.put(gpa, "TIMER_READ", .{ .name = "TIMER_READ", .short_description = "Read elapsed time from the system timer.", .long_description = @@ -203,7 +201,7 @@ pub fn init() !void { , .execute = &timerRead, }); - try registry.put("FILE", .{ + try registry.put(gpa, "FILE", .{ .name = "FILE", .parameters = &[_]Command.Parameter{.{ .name = "path" }}, .short_description = "Queue commands listed in the provided file.", @@ -218,7 +216,7 @@ pub fn init() !void { , .execute = &file, }); - try registry.put("SAVE_OUTPUT", .{ + try registry.put(gpa, "SAVE_OUTPUT", .{ .name = "SAVE_OUTPUT", .parameters = &[_]Command.Parameter{ .{ .name = "mode" }, @@ -239,7 +237,7 @@ pub fn init() !void { , .execute = &setLog, }); - try registry.put("EXIT", .{ + try registry.put(gpa, "EXIT", .{ .name = "EXIT", .short_description = "Exit the MMC command line utility.", .long_description = @@ -250,14 +248,13 @@ pub fn init() !void { }); } -pub fn deinit() void { +pub fn deinit(gpa: std.mem.Allocator) void { stop.store(true, .monotonic); defer stop.store(false, .monotonic); variables.deinit(); - command_queue.deinit(); + command_queue.deinit(gpa); deinitModules(); - registry.deinit(); - arena.deinit(); + registry.deinit(gpa); } pub fn queueEmpty() bool { @@ -277,23 +274,23 @@ pub fn checkCommandInterrupt() !void { } } -pub fn enqueue(input: []const u8) !void { +pub fn enqueue(gpa: std.mem.Allocator, input: []const u8) !void { var buffer = CommandString{ .buffer = undefined, .len = undefined, }; @memcpy(buffer.buffer[0..input.len], input); buffer.len = input.len; - try command_queue.insert(0, buffer); + try command_queue.insert(gpa, 0, buffer); } -pub fn execute() !void { +pub fn execute(io: std.Io, gpa: std.mem.Allocator) !void { const cb = command_queue.pop().?; std.log.info("Running command: {s}\n", .{cb.buffer[0..cb.len]}); - try parseAndRun(cb.buffer[0..cb.len]); + try parseAndRun(io, gpa, cb.buffer[0..cb.len]); } -fn parseAndRun(input: []const u8) !void { +fn parseAndRun(io: std.Io, gpa: std.mem.Allocator, input: []const u8) !void { var token_iterator = std.mem.tokenizeSequence(u8, input, " "); var command: *Command = undefined; var command_buf: [32]u8 = undefined; @@ -306,11 +303,11 @@ fn parseAndRun(input: []const u8) !void { } else return error.InvalidCommand; } else return; - var params: [][]const u8 = try allocator.alloc( + var params: [][]const u8 = try gpa.alloc( []const u8, command.parameters.len, ); - defer allocator.free(params); + defer gpa.free(params); for (command.parameters, 0..) |param, i| { const _token = token_iterator.peek(); @@ -353,13 +350,10 @@ fn parseAndRun(input: []const u8) !void { } } if (token_iterator.peek() != null) return error.UnexpectedParameter; - try command.execute(params); + try command.execute(io, gpa, params); } -var arena: std.heap.ArenaAllocator = undefined; -var allocator: std.mem.Allocator = undefined; - -fn help(params: [][]const u8) !void { +fn help(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { if (params[0].len > 0) { var command: *Command = undefined; var command_buf: [32]u8 = undefined; @@ -420,16 +414,15 @@ fn help(params: [][]const u8) !void { } } -fn version(_: [][]const u8) !void { - // TODO: Figure out better way to get version from `build.zig.zon`. - std.log.info("CLI Version: {s}\n", .{"0.2.4"}); +fn version(_: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { + std.log.info("CLI Version: {s}\n", .{build_zig_zon.version}); } -fn set(params: [][]const u8) !void { +fn set(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { try variables.put(params[0], params[1]); } -fn get(params: [][]const u8) !void { +fn get(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { if (variables.get(params[0])) |value| { std.log.info("Variable \"{s}\": {s}\n", .{ params[0], @@ -438,7 +431,7 @@ fn get(params: [][]const u8) !void { } else return error.UndefinedVariable; } -fn printVariables(_: [][]const u8) !void { +fn printVariables(_: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { var variables_it = variables.iterator(); while (variables_it.next()) |entry| { try checkCommandInterrupt(); @@ -446,39 +439,35 @@ fn printVariables(_: [][]const u8) !void { } } -fn timerStart(_: [][]const u8) !void { - if (timer) |*t| { - t.reset(); - } else { - return error.SystemTimerFailure; - } +fn timerStart(io: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { + timer = .now(io, clock); } -fn timerRead(_: [][]const u8) !void { - if (timer) |*t| { - var timer_value: f64 = @floatFromInt(t.read()); - timer_value = timer_value / std.time.ns_per_s; - // Only print to microsecond precision. - std.log.info("Timer: {d:.6}\n", .{timer_value}); - } else { - return error.SystemTimerFailure; - } +fn timerRead(io: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { + const duration = timer.untilNow(io, clock); + var timer_value: f64 = @floatFromInt(duration.toMicroseconds()); + timer_value = timer_value / std.time.ns_per_s; + // Only print to microsecond precision. + std.log.info("Timer: {d:.6}\n", .{timer_value}); } -fn file(params: [][]const u8) !void { - var f = try std.fs.cwd().openFile(params[0], .{}); - var reader = f.reader(); +fn file(io: std.Io, gpa: std.mem.Allocator, params: [][]const u8) !void { + var f = try std.Io.Dir.cwd().openFile(io, params[0], .{}); + var file_reader = f.reader(io, &.{}); + const reader = &file_reader.interface; const current_len: usize = command_queue.items.len; var new_line: CommandString = .{ .buffer = undefined, .len = 0 }; - while (try reader.readUntilDelimiterOrEof( - &new_line.buffer, - '\n', - )) |_line| { - try checkCommandInterrupt(); - const line = std.mem.trimRight(u8, _line, "\r"); + while (true) { + const _line = reader.takeDelimiterExclusive('\n') catch |e| switch (e) { + error.EndOfStream => return, + error.ReadFailed => return file_reader.err.?, + else => return e, + }; + const line = std.mem.trimEnd(u8, _line, "\r"); + @memcpy(new_line.buffer[0..line.len], line); new_line.len = line.len; std.log.info("Queueing command: {s}", .{line}); - try command_queue.insert(current_len, new_line); + try command_queue.insert(gpa, current_len, new_line); } } @@ -496,16 +485,16 @@ fn deinitModules() void { } } -fn loadConfig(params: [][]const u8) !void { +fn loadConfig(io: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { // De-initialize any previously initialized modules. deinitModules(); // Load config file. const file_path = if (params[0].len > 0) params[0] else "config.json"; - const config_file = try std.fs.cwd().openFile(file_path, .{}); + const config_file = try std.Io.Dir.cwd().openFile(io, file_path, .{}); var m_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const m_allocator = m_arena.allocator(); - var config = try Config.parse(m_allocator, config_file); + var config = try Config.parse(io, m_allocator, config_file); // Initialize only the modules specified in config file. const fields = @typeInfo(Config.Module).@"enum".fields; @@ -526,27 +515,29 @@ fn loadConfig(params: [][]const u8) !void { m_arena.deinit(); } -fn wait(params: [][]const u8) !void { - const duration: u32 = try std.fmt.parseInt(u32, params[0], 0); - var wait_timer = try std.time.Timer.start(); - while (wait_timer.read() < duration * std.time.ns_per_ms) { +fn wait(io: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { + const duration = try std.fmt.parseInt(i64, params[0], 0); + const timestamp: std.Io.Timestamp = .now(io, clock); + while (timestamp.untilNow(io, clock).toMilliseconds() < duration) { try checkCommandInterrupt(); } } -fn setLog(params: [][]const u8) !void { +fn setLog(io: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const mode_str = params[0]; const path = params[1]; var buf: [512]u8 = undefined; const file_path = if (path.len > 0) path else p: { - var timestamp: u64 = @intCast(std.time.timestamp()); + var timestamp: i64 = + std.Io.Timestamp.now(io, std.Io.Clock.real).toSeconds(); + // var timestamp: u64 = @intCast(std.time.timestamp()); timestamp += std.time.s_per_hour * 9; - const days_since_epoch: i32 = @intCast(timestamp / std.time.s_per_day); + const days_since_epoch: i32 = @intCast(@divFloor(timestamp, std.time.s_per_day)); const ymd = chrono.date.YearMonthDay.fromDaysSinceUnixEpoch(days_since_epoch); - const time_day: u32 = @intCast(timestamp % std.time.s_per_day); - const time = try chrono.Time.fromNumSecondsFromMidnight(time_day, 0); + const time_day: u32 = @intCast(@rem(timestamp, std.time.s_per_day)); + const time = chrono.Time.fromNumSecondsFromMidnight(time_day, 0) catch return; break :p try std.fmt.bufPrint( &buf, @@ -566,33 +557,32 @@ fn setLog(params: [][]const u8) !void { if (std.ascii.eqlIgnoreCase("stop", mode_str)) { if (log_file) |f| { - f.close(); + f.close(io); } log_file = null; } else if (std.ascii.eqlIgnoreCase("append", mode_str)) { if (log_file) |f| { - f.close(); + f.close(io); } - - log_file = try std.fs.cwd().createFile(file_path, .{ + log_file = try std.Io.Dir.cwd().createFile(io, file_path, .{ .truncate = false, }); } else if (std.ascii.eqlIgnoreCase("replace", mode_str)) { if (log_file) |f| { - f.close(); + f.close(io); } - log_file = try std.fs.cwd().createFile(file_path, .{}); + log_file = try std.Io.Dir.cwd().createFile(io, file_path, .{}); } else { return error.InvalidSaveOutputMode; } } -fn clear(_: [][]const u8) !void { - const stdout = std.io.getStdOut().writer(); - try stdout.writeAll("\x1bc"); +fn clear(io: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { + var stdout = std.Io.File.stdout().writer(io, &.{}); + try stdout.interface.writeAll("\x1bc"); } -fn exit(_: [][]const u8) !void { +fn exit(_: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { std.process.exit(1); } diff --git a/src/command/mcl.zig b/src/command/mcl.zig index d46d1aef..e6ff8149 100644 --- a/src/command/mcl.zig +++ b/src/command/mcl.zig @@ -3,7 +3,7 @@ const command = @import("../command.zig"); const mcl = @import("mcl"); var arena: std.heap.ArenaAllocator = undefined; -var allocator: std.mem.Allocator = undefined; +var gpa: std.mem.Allocator = undefined; var line_names: [][]u8 = undefined; var line_speeds: []u7 = undefined; var line_accelerations: []u7 = undefined; @@ -26,21 +26,21 @@ pub fn init(c: Config) !void { arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); errdefer arena.deinit(); - allocator = arena.allocator(); + gpa = arena.allocator(); - try mcl.init(allocator, .{ .lines = c.lines }); + try mcl.init(gpa, .{ .lines = c.lines }); - line_names = try allocator.alloc([]u8, c.line_names.len); - line_speeds = try allocator.alloc(u7, c.lines.len); - line_accelerations = try allocator.alloc(u7, c.lines.len); + line_names = try gpa.alloc([]u8, c.line_names.len); + line_speeds = try gpa.alloc(u7, c.lines.len); + line_accelerations = try gpa.alloc(u7, c.lines.len); for (0..c.lines.len) |i| { - line_names[i] = try allocator.alloc(u8, c.line_names[i].len); + line_names[i] = try gpa.alloc(u8, c.line_names[i].len); @memcpy(line_names[i], c.line_names[i]); line_speeds[i] = 40; line_accelerations[i] = 40; } - try command.registry.put("MCL_VERSION", .{ + try command.registry.put(gpa, "MCL_VERSION", .{ .name = "MCL_VERSION", .short_description = "Display the version of MCL.", .long_description = @@ -50,7 +50,7 @@ pub fn init(c: Config) !void { .execute = &mclVersion, }); errdefer _ = command.registry.orderedRemove("MCL_VERSION"); - try command.registry.put("CONNECT", .{ + try command.registry.put(gpa, "CONNECT", .{ .name = "CONNECT", .short_description = "Connect MCL with motion system.", .long_description = @@ -61,7 +61,7 @@ pub fn init(c: Config) !void { .execute = &mclConnect, }); errdefer _ = command.registry.orderedRemove("CONNECT"); - try command.registry.put("DISCONNECT", .{ + try command.registry.put(gpa, "DISCONNECT", .{ .name = "DISCONNECT", .short_description = "Disconnect MCL from motion system.", .long_description = @@ -71,7 +71,7 @@ pub fn init(c: Config) !void { .execute = &mclDisconnect, }); errdefer _ = command.registry.orderedRemove("DISCONNECT"); - try command.registry.put("SET_SPEED", .{ + try command.registry.put(gpa, "SET_SPEED", .{ .name = "SET_SPEED", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -86,7 +86,7 @@ pub fn init(c: Config) !void { .execute = &mclSetSpeed, }); errdefer _ = command.registry.orderedRemove("SET_SPEED"); - try command.registry.put("SET_ACCELERATION", .{ + try command.registry.put(gpa, "SET_ACCELERATION", .{ .name = "SET_ACCELERATION", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -101,7 +101,7 @@ pub fn init(c: Config) !void { .execute = &mclSetAcceleration, }); errdefer _ = command.registry.orderedRemove("SET_ACCELERATION"); - try command.registry.put("GET_SPEED", .{ + try command.registry.put(gpa, "GET_SPEED", .{ .name = "GET_SPEED", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -115,7 +115,7 @@ pub fn init(c: Config) !void { .execute = &mclGetSpeed, }); errdefer _ = command.registry.orderedRemove("GET_SPEED"); - try command.registry.put("GET_ACCELERATION", .{ + try command.registry.put(gpa, "GET_ACCELERATION", .{ .name = "GET_ACCELERATION", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -129,7 +129,7 @@ pub fn init(c: Config) !void { .execute = &mclGetAcceleration, }); errdefer _ = command.registry.orderedRemove("GET_ACCELERATION"); - try command.registry.put("PRINT_X", .{ + try command.registry.put(gpa, "PRINT_X", .{ .name = "PRINT_X", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -143,7 +143,7 @@ pub fn init(c: Config) !void { .execute = &mclStationX, }); errdefer _ = command.registry.orderedRemove("PRINT_X"); - try command.registry.put("PRINT_Y", .{ + try command.registry.put(gpa, "PRINT_Y", .{ .name = "PRINT_Y", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -157,7 +157,7 @@ pub fn init(c: Config) !void { .execute = &mclStationY, }); errdefer _ = command.registry.orderedRemove("PRINT_Y"); - try command.registry.put("PRINT_WR", .{ + try command.registry.put(gpa, "PRINT_WR", .{ .name = "PRINT_WR", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -171,7 +171,7 @@ pub fn init(c: Config) !void { .execute = &mclStationWr, }); errdefer _ = command.registry.orderedRemove("PRINT_WR"); - try command.registry.put("PRINT_WW", .{ + try command.registry.put(gpa, "PRINT_WW", .{ .name = "PRINT_WW", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -185,7 +185,7 @@ pub fn init(c: Config) !void { .execute = &mclStationWw, }); errdefer _ = command.registry.orderedRemove("PRINT_WW"); - try command.registry.put("AXIS_SLIDER", .{ + try command.registry.put(gpa, "AXIS_SLIDER", .{ .name = "AXIS_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -201,7 +201,7 @@ pub fn init(c: Config) !void { .execute = &mclAxisSlider, }); errdefer _ = command.registry.orderedRemove("AXIS_SLIDER"); - try command.registry.put("SLIDER_LOCATION", .{ + try command.registry.put(gpa, "SLIDER_LOCATION", .{ .name = "SLIDER_LOCATION", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -217,7 +217,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderLocation, }); errdefer _ = command.registry.orderedRemove("SLIDER_LOCATION"); - try command.registry.put("SLIDER_AXIS", .{ + try command.registry.put(gpa, "SLIDER_AXIS", .{ .name = "SLIDER_AXIS", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -232,7 +232,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderAxis, }); errdefer _ = command.registry.orderedRemove("SLIDER_AXIS"); - try command.registry.put("HALL_STATUS", .{ + try command.registry.put(gpa, "HALL_STATUS", .{ .name = "HALL_STATUS", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -247,7 +247,7 @@ pub fn init(c: Config) !void { .execute = &mclHallStatus, }); errdefer _ = command.registry.orderedRemove("HALL_STATUS"); - try command.registry.put("ASSERT_HALL", .{ + try command.registry.put(gpa, "ASSERT_HALL", .{ .name = "ASSERT_HALL", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -265,7 +265,7 @@ pub fn init(c: Config) !void { .execute = &mclAssertHall, }); errdefer _ = command.registry.orderedRemove("ASSERT_HALL"); - try command.registry.put("CLEAR_ERRORS", .{ + try command.registry.put(gpa, "CLEAR_ERRORS", .{ .name = "CLEAR_ERRORS", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -278,7 +278,7 @@ pub fn init(c: Config) !void { .execute = &mclClearErrors, }); errdefer _ = command.registry.orderedRemove("CLEAR_ERRORS"); - try command.registry.put("CLEAR_SLIDER_INFO", .{ + try command.registry.put(gpa, "CLEAR_SLIDER_INFO", .{ .name = "CLEAR_SLIDER_INFO", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -291,7 +291,7 @@ pub fn init(c: Config) !void { .execute = &mclClearSliderInfo, }); errdefer _ = command.registry.orderedRemove("CLEAR_SLIDER_INFO"); - try command.registry.put("RELEASE_AXIS_SERVO", .{ + try command.registry.put(gpa, "RELEASE_AXIS_SERVO", .{ .name = "RELEASE_AXIS_SERVO", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -306,7 +306,7 @@ pub fn init(c: Config) !void { .execute = &mclAxisReleaseServo, }); errdefer _ = command.registry.orderedRemove("RELEASE_AXIS_SERVO"); - try command.registry.put("STOP_TRAFFIC", .{ + try command.registry.put(gpa, "STOP_TRAFFIC", .{ .name = "STOP_TRAFFIC", .parameters = &.{ .{ .name = "line name" }, @@ -322,7 +322,7 @@ pub fn init(c: Config) !void { .execute = &mclTrafficStop, }); errdefer _ = command.registry.orderedRemove("STOP_TRAFFIC"); - try command.registry.put("ALLOW_TRAFFIC", .{ + try command.registry.put(gpa, "ALLOW_TRAFFIC", .{ .name = "ALLOW_TRAFFIC", .parameters = &.{ .{ .name = "line name" }, @@ -338,7 +338,7 @@ pub fn init(c: Config) !void { .execute = &mclTrafficAllow, }); errdefer _ = command.registry.orderedRemove("ALLOW_TRAFFIC"); - try command.registry.put("CALIBRATE", .{ + try command.registry.put(gpa, "CALIBRATE", .{ .name = "CALIBRATE", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -352,7 +352,7 @@ pub fn init(c: Config) !void { .execute = &mclCalibrate, }); errdefer _ = command.registry.orderedRemove("CALIBRATE"); - try command.registry.put("HOME_SLIDER", .{ + try command.registry.put(gpa, "HOME_SLIDER", .{ .name = "HOME_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -365,7 +365,7 @@ pub fn init(c: Config) !void { .execute = &mclHomeSlider, }); errdefer _ = command.registry.orderedRemove("HOME_SLIDER"); - try command.registry.put("WAIT_HOME_SLIDER", .{ + try command.registry.put(gpa, "WAIT_HOME_SLIDER", .{ .name = "WAIT_HOME_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -380,7 +380,7 @@ pub fn init(c: Config) !void { .execute = &mclWaitHomeSlider, }); errdefer _ = command.registry.orderedRemove("WAIT_HOME_SLIDER"); - try command.registry.put("ISOLATE", .{ + try command.registry.put(gpa, "ISOLATE", .{ .name = "ISOLATE", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -401,7 +401,7 @@ pub fn init(c: Config) !void { .execute = &mclIsolate, }); errdefer _ = command.registry.orderedRemove("ISOLATE"); - try command.registry.put("RECOVER_SLIDER", .{ + try command.registry.put(gpa, "RECOVER_SLIDER", .{ .name = "RECOVER_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -420,7 +420,7 @@ pub fn init(c: Config) !void { .execute = &mclRecoverSlider, }); errdefer _ = command.registry.orderedRemove("RECOVER_SLIDER"); - try command.registry.put("WAIT_RECOVER_SLIDER", .{ + try command.registry.put(gpa, "WAIT_RECOVER_SLIDER", .{ .name = "WAIT_RECOVER_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -436,7 +436,7 @@ pub fn init(c: Config) !void { .execute = &mclWaitRecoverSlider, }); errdefer _ = command.registry.orderedRemove("WAIT_RECOVER_SLIDER"); - try command.registry.put("MOVE_SLIDER_AXIS", .{ + try command.registry.put(gpa, "MOVE_SLIDER_AXIS", .{ .name = "MOVE_SLIDER_AXIS", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -451,7 +451,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPosMoveAxis, }); errdefer _ = command.registry.orderedRemove("MOVE_SLIDER_AXIS"); - try command.registry.put("MOVE_SLIDER_LOCATION", .{ + try command.registry.put(gpa, "MOVE_SLIDER_LOCATION", .{ .name = "MOVE_SLIDER_LOCATION", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -467,7 +467,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPosMoveLocation, }); errdefer _ = command.registry.orderedRemove("MOVE_SLIDER_LOCATION"); - try command.registry.put("MOVE_SLIDER_DISTANCE", .{ + try command.registry.put(gpa, "MOVE_SLIDER_DISTANCE", .{ .name = "MOVE_SLIDER_DISTANCE", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -484,7 +484,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPosMoveDistance, }); errdefer _ = command.registry.orderedRemove("MOVE_SLIDER_DISTANCE"); - try command.registry.put("SPD_MOVE_SLIDER_AXIS", .{ + try command.registry.put(gpa, "SPD_MOVE_SLIDER_AXIS", .{ .name = "SPD_MOVE_SLIDER_AXIS", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -500,7 +500,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderSpdMoveAxis, }); errdefer _ = command.registry.orderedRemove("SPD_MOVE_SLIDER_AXIS"); - try command.registry.put("SPD_MOVE_SLIDER_LOCATION", .{ + try command.registry.put(gpa, "SPD_MOVE_SLIDER_LOCATION", .{ .name = "SPD_MOVE_SLIDER_LOCATION", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -517,7 +517,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderSpdMoveLocation, }); errdefer _ = command.registry.orderedRemove("SPD_MOVE_SLIDER_LOCATION"); - try command.registry.put("SPD_MOVE_SLIDER_DISTANCE", .{ + try command.registry.put(gpa, "SPD_MOVE_SLIDER_DISTANCE", .{ .name = "SPD_MOVE_SLIDER_DISTANCE", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -535,7 +535,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderSpdMoveDistance, }); errdefer _ = command.registry.orderedRemove("SPD_MOVE_SLIDER_DISTANCE"); - try command.registry.put("WAIT_MOVE_SLIDER", .{ + try command.registry.put(gpa, "WAIT_MOVE_SLIDER", .{ .name = "WAIT_MOVE_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -549,7 +549,7 @@ pub fn init(c: Config) !void { .execute = &mclWaitMoveSlider, }); errdefer _ = command.registry.orderedRemove("WAIT_MOVE_SLIDER"); - try command.registry.put("PUSH_SLIDER_FORWARD", .{ + try command.registry.put(gpa, "PUSH_SLIDER_FORWARD", .{ .name = "PUSH_SLIDER_FORWARD", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -565,7 +565,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPushForward, }); errdefer _ = command.registry.orderedRemove("PUSH_SLIDER_FORWARD"); - try command.registry.put("PUSH_SLIDER_BACKWARD", .{ + try command.registry.put(gpa, "PUSH_SLIDER_BACKWARD", .{ .name = "PUSH_SLIDER_BACKWARD", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -581,7 +581,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPushBackward, }); errdefer _ = command.registry.orderedRemove("PUSH_SLIDER_BACKWARD"); - try command.registry.put("PULL_SLIDER_FORWARD", .{ + try command.registry.put(gpa, "PULL_SLIDER_FORWARD", .{ .name = "PULL_SLIDER_FORWARD", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -597,7 +597,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPullForward, }); errdefer _ = command.registry.orderedRemove("PULL_SLIDER_FORWARD"); - try command.registry.put("PULL_SLIDER_BACKWARD", .{ + try command.registry.put(gpa, "PULL_SLIDER_BACKWARD", .{ .name = "PULL_SLIDER_BACKWARD", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -613,7 +613,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderPullBackward, }); errdefer _ = command.registry.orderedRemove("PULL_SLIDER_BACKWARD"); - try command.registry.put("WAIT_PULL_SLIDER", .{ + try command.registry.put(gpa, "WAIT_PULL_SLIDER", .{ .name = "WAIT_PULL_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -626,7 +626,7 @@ pub fn init(c: Config) !void { , .execute = &mclSliderWaitPull, }); - try command.registry.put("STOP_PULL_SLIDER", .{ + try command.registry.put(gpa, "STOP_PULL_SLIDER", .{ .name = "STOP_PULL_SLIDER", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -639,7 +639,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderStopPull, }); errdefer _ = command.registry.orderedRemove("STOP_PULL_SLIDER"); - try command.registry.put("SLIDER_CHAIN_LINK", .{ + try command.registry.put(gpa, "SLIDER_CHAIN_LINK", .{ .name = "SLIDER_CHAIN_LINK", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -653,7 +653,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderChainLink, }); errdefer _ = command.registry.orderedRemove("SLIDER_CHAIN_LINK"); - try command.registry.put("SLIDER_CHAIN_UNLINK", .{ + try command.registry.put(gpa, "SLIDER_CHAIN_UNLINK", .{ .name = "SLIDER_CHAIN_UNLINK", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -667,7 +667,7 @@ pub fn init(c: Config) !void { .execute = &mclSliderChainUnlink, }); errdefer _ = command.registry.orderedRemove("SLIDER_CHAIN_UNLINK"); - try command.registry.put("SET_LEFT_CHAIN_ON", .{ + try command.registry.put(gpa, "SET_LEFT_CHAIN_ON", .{ .name = "SET_LEFT_CHAIN_ON", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -680,7 +680,7 @@ pub fn init(c: Config) !void { .execute = &mclSetLeftChainOn, }); errdefer _ = command.registry.orderedRemove("SET_LEFT_CHAIN_ON"); - try command.registry.put("SET_RIGHT_CHAIN_ON", .{ + try command.registry.put(gpa, "SET_RIGHT_CHAIN_ON", .{ .name = "SET_RIGHT_CHAIN_ON", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -693,7 +693,7 @@ pub fn init(c: Config) !void { .execute = &mclSetRightChainOn, }); errdefer _ = command.registry.orderedRemove("SET_RIGHT_CHAIN_ON"); - try command.registry.put("SET_LEFT_CHAIN_OFF", .{ + try command.registry.put(gpa, "SET_LEFT_CHAIN_OFF", .{ .name = "SET_LEFT_CHAIN_OFF", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -706,7 +706,7 @@ pub fn init(c: Config) !void { .execute = &mclSetLeftChainOff, }); errdefer _ = command.registry.orderedRemove("SET_LEFT_CHAIN_OFF"); - try command.registry.put("SET_RIGHT_CHAIN_OFF", .{ + try command.registry.put(gpa, "SET_RIGHT_CHAIN_OFF", .{ .name = "SET_RIGHT_CHAIN_OFF", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -719,7 +719,7 @@ pub fn init(c: Config) !void { .execute = &mclSetRightChainOff, }); errdefer _ = command.registry.orderedRemove("SET_RIGHT_CHAIN_OFF"); - try command.registry.put("MOVE_SLIDER_CHAIN", .{ + try command.registry.put(gpa, "MOVE_SLIDER_CHAIN", .{ .name = "MOVE_SLIDER_CHAIN", .parameters = &[_]command.Command.Parameter{ .{ .name = "line name" }, @@ -740,7 +740,7 @@ pub fn deinit() void { line_names = undefined; } -fn mclVersion(_: [][]const u8) !void { +fn mclVersion(_: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { std.log.info("MCL Version: {d}.{d}.{d}\n", .{ mcl.version.major, mcl.version.minor, @@ -748,7 +748,7 @@ fn mclVersion(_: [][]const u8) !void { }); } -fn mclConnect(_: [][]const u8) !void { +fn mclConnect(_: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { try mcl.open(); for (mcl.lines) |line| { for (line.stations) |station| { @@ -758,7 +758,7 @@ fn mclConnect(_: [][]const u8) !void { } } -fn mclDisconnect(_: [][]const u8) !void { +fn mclDisconnect(_: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { for (mcl.lines) |line| { for (line.stations) |station| { station.y.cc_link_enable = false; @@ -768,7 +768,7 @@ fn mclDisconnect(_: [][]const u8) !void { try mcl.close(); } -fn mclStationX(params: [][]const u8) !void { +fn mclStationX(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id = try std.fmt.parseInt(i16, params[1], 0); @@ -787,7 +787,7 @@ fn mclStationX(params: [][]const u8) !void { std.log.info("{}", .{line.stations[station_index].x}); } -fn mclStationY(params: [][]const u8) !void { +fn mclStationY(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id = try std.fmt.parseInt(i16, params[1], 0); @@ -806,7 +806,7 @@ fn mclStationY(params: [][]const u8) !void { std.log.info("{}", .{line.stations[station_index].y}); } -fn mclStationWr(params: [][]const u8) !void { +fn mclStationWr(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id = try std.fmt.parseInt(i16, params[1], 0); @@ -825,7 +825,7 @@ fn mclStationWr(params: [][]const u8) !void { std.log.info("{}", .{line.stations[station_index].wr}); } -fn mclStationWw(params: [][]const u8) !void { +fn mclStationWw(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id = try std.fmt.parseInt(i16, params[1], 0); @@ -844,7 +844,7 @@ fn mclStationWw(params: [][]const u8) !void { std.log.info("{}", .{line.stations[station_index].ww}); } -fn mclAxisSlider(params: [][]const u8) !void { +fn mclAxisSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id = try std.fmt.parseInt(i16, params[1], 0); const result_var: []const u8 = params[2]; @@ -879,7 +879,7 @@ fn mclAxisSlider(params: [][]const u8) !void { } } -fn mclAxisReleaseServo(params: [][]const u8) !void { +fn mclAxisReleaseServo(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: i16 = try std.fmt.parseInt(i16, params[1], 0); @@ -905,7 +905,7 @@ fn mclAxisReleaseServo(params: [][]const u8) !void { } } -fn mclClearErrors(params: [][]const u8) !void { +fn mclClearErrors(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: i16 = try std.fmt.parseInt(i16, params[1], 0); @@ -931,7 +931,7 @@ fn mclClearErrors(params: [][]const u8) !void { } } -fn mclClearSliderInfo(params: [][]const u8) !void { +fn mclClearSliderInfo(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: i16 = try std.fmt.parseInt(i16, params[1], 0); @@ -958,7 +958,7 @@ fn mclClearSliderInfo(params: [][]const u8) !void { } } -fn mclCalibrate(params: [][]const u8) !void { +fn mclCalibrate(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const line_idx: usize = try matchLine(line_names, line_name); const line: mcl.Line = mcl.lines[line_idx]; @@ -970,7 +970,7 @@ fn mclCalibrate(params: [][]const u8) !void { try sendCommand(station); } -fn mclHomeSlider(params: [][]const u8) !void { +fn mclHomeSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const line_idx: usize = try matchLine(line_names, line_name); const line: mcl.Line = mcl.lines[line_idx]; @@ -982,7 +982,7 @@ fn mclHomeSlider(params: [][]const u8) !void { try sendCommand(station); } -fn mclWaitHomeSlider(params: [][]const u8) !void { +fn mclWaitHomeSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const result_var: []const u8 = params[1]; @@ -1012,7 +1012,7 @@ fn mclWaitHomeSlider(params: [][]const u8) !void { } } -fn mclIsolate(params: [][]const u8) !void { +fn mclIsolate(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: u16 = try std.fmt.parseInt(u16, params[1], 0); @@ -1088,7 +1088,7 @@ fn mclIsolate(params: [][]const u8) !void { try sendCommand(station); } -fn mclSetSpeed(params: [][]const u8) !void { +fn mclSetSpeed(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_speed = try std.fmt.parseUnsigned(u8, params[1], 0); if (slider_speed < 1 or slider_speed > 100) return error.InvalidSpeed; @@ -1097,7 +1097,7 @@ fn mclSetSpeed(params: [][]const u8) !void { line_speeds[line_idx] = @intCast(slider_speed); } -fn mclSetAcceleration(params: [][]const u8) !void { +fn mclSetAcceleration(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_acceleration = try std.fmt.parseUnsigned(u8, params[1], 0); if (slider_acceleration < 1 or slider_acceleration > 100) @@ -1107,14 +1107,14 @@ fn mclSetAcceleration(params: [][]const u8) !void { line_accelerations[line_idx] = @intCast(slider_acceleration); } -fn mclGetSpeed(params: [][]const u8) !void { +fn mclGetSpeed(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const line_idx: usize = try matchLine(line_names, line_name); std.log.info("Line {s} speed: {d}%", .{ line_name, line_speeds[line_idx] }); } -fn mclGetAcceleration(params: [][]const u8) !void { +fn mclGetAcceleration(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const line_idx: usize = try matchLine(line_names, line_name); @@ -1124,7 +1124,7 @@ fn mclGetAcceleration(params: [][]const u8) !void { ); } -fn mclSliderLocation(params: [][]const u8) !void { +fn mclSliderLocation(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); if (slider_id == 0 or slider_id > 254) return error.InvalidSliderId; @@ -1156,7 +1156,7 @@ fn mclSliderLocation(params: [][]const u8) !void { } } -fn mclSliderAxis(params: [][]const u8) !void { +fn mclSliderAxis(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); if (slider_id == 0 or slider_id > 254) return error.InvalidSliderId; @@ -1182,7 +1182,7 @@ fn mclSliderAxis(params: [][]const u8) !void { } } -fn mclHallStatus(params: [][]const u8) !void { +fn mclHallStatus(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const line_idx: usize = try matchLine(line_names, line_name); const line: mcl.Line = mcl.lines[line_idx]; @@ -1208,7 +1208,7 @@ fn mclHallStatus(params: [][]const u8) !void { } } -fn mclAssertHall(params: [][]const u8) !void { +fn mclAssertHall(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis = try std.fmt.parseInt(mcl.Axis.Id.Line, params[2], 0); const side: mcl.Direction = @@ -1255,7 +1255,7 @@ fn mclAssertHall(params: [][]const u8) !void { } } -fn mclSliderPosMoveAxis(params: [][]const u8) !void { +fn mclSliderPosMoveAxis(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id: u16 = try std.fmt.parseInt(u16, params[1], 0); const axis_id: u16 = try std.fmt.parseInt(u16, params[2], 0); @@ -1313,7 +1313,7 @@ fn mclSliderPosMoveAxis(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderPosMoveLocation(params: [][]const u8) !void { +fn mclSliderPosMoveLocation(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id: u16 = try std.fmt.parseInt(u16, params[1], 0); const location_float: f32 = try std.fmt.parseFloat(f32, params[2]); @@ -1376,7 +1376,7 @@ fn mclSliderPosMoveLocation(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderPosMoveDistance(params: [][]const u8) !void { +fn mclSliderPosMoveDistance(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); const distance_float = try std.fmt.parseFloat(f32, params[2]); @@ -1445,7 +1445,7 @@ fn mclSliderPosMoveDistance(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderSpdMoveAxis(params: [][]const u8) !void { +fn mclSliderSpdMoveAxis(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id: u16 = try std.fmt.parseInt(u16, params[1], 0); const axis_id: u16 = try std.fmt.parseInt(u16, params[2], 0); @@ -1503,7 +1503,7 @@ fn mclSliderSpdMoveAxis(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderSpdMoveLocation(params: [][]const u8) !void { +fn mclSliderSpdMoveLocation(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id: u16 = try std.fmt.parseInt(u16, params[1], 0); const location_float: f32 = try std.fmt.parseFloat(f32, params[2]); @@ -1566,7 +1566,7 @@ fn mclSliderSpdMoveLocation(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderSpdMoveDistance(params: [][]const u8) !void { +fn mclSliderSpdMoveDistance(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); const distance_float = try std.fmt.parseFloat(f32, params[2]); @@ -1635,7 +1635,7 @@ fn mclSliderSpdMoveDistance(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderPushForward(params: [][]const u8) !void { +fn mclSliderPushForward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); if (slider_id == 0 or slider_id > 254) return error.InvalidSliderId; @@ -1687,7 +1687,7 @@ fn mclSliderPushForward(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderPushBackward(params: [][]const u8) !void { +fn mclSliderPushBackward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); if (slider_id == 0 or slider_id > 254) return error.InvalidSliderId; @@ -1740,7 +1740,7 @@ fn mclSliderPushBackward(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderPullForward(params: [][]const u8) !void { +fn mclSliderPullForward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const axis = try std.fmt.parseInt(u16, params[1], 0); const slider_id = try std.fmt.parseInt(u16, params[2], 0); @@ -1764,7 +1764,7 @@ fn mclSliderPullForward(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderPullBackward(params: [][]const u8) !void { +fn mclSliderPullBackward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const axis = try std.fmt.parseInt(u16, params[1], 0); const slider_id = try std.fmt.parseInt(u16, params[2], 0); @@ -1788,7 +1788,7 @@ fn mclSliderPullBackward(params: [][]const u8) !void { try sendCommand(station); } -fn mclSliderWaitPull(params: [][]const u8) !void { +fn mclSliderWaitPull(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const axis = try std.fmt.parseInt(i16, params[1], 0); const line_idx: usize = try matchLine(line_names, line_name); @@ -1813,7 +1813,7 @@ fn mclSliderWaitPull(params: [][]const u8) !void { } } -fn mclSliderStopPull(params: [][]const u8) !void { +fn mclSliderStopPull(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name = params[0]; const axis = try std.fmt.parseInt(i16, params[1], 0); const line_idx: usize = try matchLine(line_names, line_name); @@ -1835,7 +1835,7 @@ fn mclSliderStopPull(params: [][]const u8) !void { } } -fn mclWaitMoveSlider(params: [][]const u8) !void { +fn mclWaitMoveSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id = try std.fmt.parseInt(u16, params[1], 0); if (slider_id == 0 or slider_id > 254) return error.InvalidSliderId; @@ -1884,7 +1884,7 @@ fn mclWaitMoveSlider(params: [][]const u8) !void { } } -fn mclRecoverSlider(params: [][]const u8) !void { +fn mclRecoverSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis: u16 = try std.fmt.parseUnsigned(u16, params[1], 0); const new_slider_id: u16 = try std.fmt.parseUnsigned(u16, params[2], 0); @@ -1946,7 +1946,7 @@ fn mclRecoverSlider(params: [][]const u8) !void { try sendCommand(station); } -fn mclTrafficStop(params: [][]const u8) !void { +fn mclTrafficStop(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -1980,7 +1980,7 @@ fn mclTrafficStop(params: [][]const u8) !void { } } -fn mclTrafficAllow(params: [][]const u8) !void { +fn mclTrafficAllow(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2014,7 +2014,7 @@ fn mclTrafficAllow(params: [][]const u8) !void { } } -fn mclWaitRecoverSlider(params: [][]const u8) !void { +fn mclWaitRecoverSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis: u16 = try std.fmt.parseUnsigned(u16, params[1], 0); const result_var: []const u8 = params[2]; @@ -2053,7 +2053,7 @@ fn mclWaitRecoverSlider(params: [][]const u8) !void { } } -fn mclSliderChainLink(params: [][]const u8) !void { +fn mclSliderChainLink(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const first_axis: mcl.Axis.Id.Line = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2131,7 +2131,7 @@ fn mclSliderChainLink(params: [][]const u8) !void { } } -fn mclSliderChainUnlink(params: [][]const u8) !void { +fn mclSliderChainUnlink(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const first_axis: mcl.Axis.Id.Line = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2209,7 +2209,7 @@ fn mclSliderChainUnlink(params: [][]const u8) !void { } } -fn mclSetLeftChainOn(params: [][]const u8) !void { +fn mclSetLeftChainOn(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: mcl.Axis.Id.Line = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2252,7 +2252,7 @@ fn mclSetLeftChainOn(params: [][]const u8) !void { } } -fn mclSetRightChainOn(params: [][]const u8) !void { +fn mclSetRightChainOn(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: mcl.Axis.Id.Line = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2295,7 +2295,7 @@ fn mclSetRightChainOn(params: [][]const u8) !void { } } -fn mclSetLeftChainOff(params: [][]const u8) !void { +fn mclSetLeftChainOff(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: mcl.Axis.Id.Line = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2338,7 +2338,7 @@ fn mclSetLeftChainOff(params: [][]const u8) !void { } } -fn mclSetRightChainOff(params: [][]const u8) !void { +fn mclSetRightChainOff(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const axis_id: mcl.Axis.Id.Line = try std.fmt.parseUnsigned(mcl.Axis.Id.Line, params[1], 0); @@ -2381,7 +2381,7 @@ fn mclSetRightChainOff(params: [][]const u8) !void { } } -fn mclMoveSliderChain(params: [][]const u8) !void { +fn mclMoveSliderChain(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; const slider_id: u16 = try std.fmt.parseInt(u16, params[1], 0); const axis_id: u16 = try std.fmt.parseInt(u16, params[2], 0); diff --git a/src/command/return_demo2.zig b/src/command/return_demo2.zig index 032c2755..15580fe3 100644 --- a/src/command/return_demo2.zig +++ b/src/command/return_demo2.zig @@ -9,7 +9,7 @@ const Command = command.Command; pub const Config = struct {}; var arena: std.heap.ArenaAllocator = undefined; -var allocator: std.mem.Allocator = undefined; +var gpa: std.mem.Allocator = undefined; var clients_lock: std.Thread.RwLock = .{}; // All commands will be broadcasted to every client. @@ -47,10 +47,10 @@ const Client = struct { pub fn init(_: Config) !void { arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - allocator = arena.allocator(); + gpa = arena.gpa(); server_stop.store(false, .monotonic); clients_lock.lock(); - clients = std.ArrayList(Client).init(allocator); + clients = std.ArrayList(Client).init(gpa); clients_lock.unlock(); try network.init(); diff --git a/src/main.zig b/src/main.zig index b2df981a..b39bb164 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,18 +1,17 @@ const builtin = @import("builtin"); const std = @import("std"); -const network = @import("network"); const command = @import("command.zig"); pub const std_options: std.Options = .{ .logFn = command.logFn, }; -fn nextLine(reader: anytype, buffer: []u8) !?[]const u8 { - const line = (try reader.readUntilDelimiterOrEof( - buffer, - '\n', - )) orelse return null; - const result = std.mem.trimRight(u8, line, "\r"); +fn nextLine(reader: *std.Io.Reader) !?[]const u8 { + const line = reader.takeDelimiterExclusive('\n') catch |e| switch (e) { + error.EndOfStream => return null, + else => return e, + }; + const result = std.mem.trimEnd(u8, line, "\r"); return result; } @@ -26,7 +25,7 @@ fn stopCommand( return 1; } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { if (builtin.os.tag == .windows) { const windows = std.os.windows; try windows.SetConsoleCtrlHandler(&stopCommand, true); @@ -41,12 +40,17 @@ pub fn main() !void { } } - try command.init(); - defer command.deinit(); + const gpa = init.gpa; + // const arena = init.arena; + const io = init.io; - const stdin = std.io.getStdIn(); - var buffered_reader = std.io.bufferedReader(stdin.reader()); - const reader = buffered_reader.reader(); + try command.init(io, gpa); + defer command.deinit(gpa); + + const stdin = std.Io.File.stdin(); + var stdin_buf: [1024]u8 = undefined; + var file_reader = stdin.reader(io, &stdin_buf); + const reader = &file_reader.interface; command_loop: while (true) { if (command.stop.load(.monotonic)) { @@ -54,14 +58,13 @@ pub fn main() !void { command.stop.store(false, .monotonic); } if (command.queueEmpty()) { - var input_buffer: [1024]u8 = .{0} ** 1024; std.log.info("Please enter a command (HELP for info): ", .{}); - if (try nextLine(reader, &input_buffer)) |line| { - try command.enqueue(line); + if (try nextLine(reader)) |line| { + try command.enqueue(gpa, line); } else continue :command_loop; } - command.execute() catch |e| { + command.execute(io, gpa) catch |e| { std.log.err("{s}", .{@errorName(e)}); std.log.debug("{any}", .{@errorReturnTrace()}); command.queueClear(); From 7f81b0166de5877f94fb7be3aa5a6f429947aedf Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Mon, 22 Jun 2026 13:41:03 +0900 Subject: [PATCH 03/16] fix: Catch ctrl+C --- src/main.zig | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main.zig b/src/main.zig index b39bb164..219cbdc0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -17,27 +17,21 @@ fn nextLine(reader: *std.Io.Reader) !?[]const u8 { fn stopCommand( dwCtrlType: std.os.windows.DWORD, -) callconv(std.os.windows.WINAPI) std.os.windows.BOOL { - if (dwCtrlType == std.os.windows.CTRL_C_EVENT) { +) callconv(.winapi) std.os.windows.BOOL { + if (dwCtrlType == kernel32.CTRL_C_EVENT) { command.stop.store(true, .monotonic); - std.io.getStdIn().sync() catch {}; } - return 1; + return .fromBool(true); } pub fn main(init: std.process.Init) !void { if (builtin.os.tag == .windows) { - const windows = std.os.windows; - try windows.SetConsoleCtrlHandler(&stopCommand, true); - const handle = try windows.GetStdHandle(windows.STD_OUTPUT_HANDLE); - var mode: windows.DWORD = 0; - if (windows.kernel32.GetConsoleMode(handle, &mode) != windows.TRUE) { - return error.WindowsConsoleModeRetrievalFailure; - } - mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (windows.kernel32.SetConsoleMode(handle, mode) != windows.TRUE) { - return error.WindowsConsoleModeSetFailure; - } + const success = kernel32.SetConsoleCtrlHandler( + &stopCommand, + .fromBool(true), + ); + if (success.toBool() == false) + return error.FailingSetConsoleCtrlHandler; } const gpa = init.gpa; @@ -73,6 +67,22 @@ pub fn main(init: std.process.Init) !void { } } +/// Windows kernel32 functions. This struct is introduced here since zig 0.16.0 +/// removes support for kernel32. Only used functions and variables are +/// introduced in this struct. +const kernel32 = struct { + pub extern "kernel32" fn SetConsoleCtrlHandler( + HandlerRoutine: ?HANDLER_ROUTINE, + add: std.os.windows.BOOL, + ) callconv(.winapi) std.os.windows.BOOL; + + pub const HANDLER_ROUTINE = *const fn ( + dwCtrlType: std.os.windows.DWORD, + ) callconv(.winapi) std.os.windows.BOOL; + + pub const CTRL_C_EVENT: std.os.windows.DWORD = 0; +}; + test { std.testing.refAllDecls(@This()); } From d95159094f6c09414a1e0e407053d5ae0e1f354e Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Mon, 22 Jun 2026 14:34:32 +0900 Subject: [PATCH 04/16] fix: reading input line --- build.zig | 1 + src/Config.zig | 3 ++- src/command.zig | 3 ++- src/main.zig | 5 +---- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.zig b/build.zig index 9a6c4a9d..a12ba17f 100644 --- a/build.zig +++ b/build.zig @@ -17,6 +17,7 @@ pub fn build(b: *std.Build) !void { "mdfunc_mock", "Enable building a mock version of the MELSEC data link library.", ) orelse (target.result.os.tag != .windows); + std.log.info("mock: {}", .{mdfunc_mock_build}); const chrono = b.dependency("chrono", .{}); const build_zig_zon = b.createModule(.{ diff --git a/src/Config.zig b/src/Config.zig index 141b3220..c4886c5b 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -19,7 +19,8 @@ const Parse = struct { }; pub fn parse(io: std.Io, gpa: std.mem.Allocator, f: std.Io.File) !Config { - var file_reader = f.reader(io, &.{}); + var file_buffer: [4096]u8 = undefined; + var file_reader = f.reader(io, &file_buffer); var json_reader: std.json.Reader = .init(gpa, &file_reader.interface); defer json_reader.deinit(); const _result = try std.json.parseFromTokenSource( diff --git a/src/command.zig b/src/command.zig index 908c82e9..e56cc221 100644 --- a/src/command.zig +++ b/src/command.zig @@ -452,8 +452,9 @@ fn timerRead(io: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { } fn file(io: std.Io, gpa: std.mem.Allocator, params: [][]const u8) !void { + var file_buffer: [4096]u8 = undefined; var f = try std.Io.Dir.cwd().openFile(io, params[0], .{}); - var file_reader = f.reader(io, &.{}); + var file_reader = f.reader(io, &file_buffer); const reader = &file_reader.interface; const current_len: usize = command_queue.items.len; var new_line: CommandString = .{ .buffer = undefined, .len = 0 }; diff --git a/src/main.zig b/src/main.zig index 219cbdc0..29b1b156 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,10 +7,7 @@ pub const std_options: std.Options = .{ }; fn nextLine(reader: *std.Io.Reader) !?[]const u8 { - const line = reader.takeDelimiterExclusive('\n') catch |e| switch (e) { - error.EndOfStream => return null, - else => return e, - }; + const line = try reader.takeDelimiter('\n') orelse return null; const result = std.mem.trimEnd(u8, line, "\r"); return result; } From 72bfe53eab7ee8dd0d5014a7217ef73b32d00ae0 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Mon, 22 Jun 2026 16:47:25 +0900 Subject: [PATCH 05/16] fix: mock build --- build.zig | 14 ++++++++++++-- build.zig.zon | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index a12ba17f..6350c2e5 100644 --- a/build.zig +++ b/build.zig @@ -17,7 +17,6 @@ pub fn build(b: *std.Build) !void { "mdfunc_mock", "Enable building a mock version of the MELSEC data link library.", ) orelse (target.result.os.tag != .windows); - std.log.info("mock: {}", .{mdfunc_mock_build}); const chrono = b.dependency("chrono", .{}); const build_zig_zon = b.createModule(.{ @@ -25,12 +24,14 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, }); + const mmc_api = b.dependency("mmc_api", .{ .target = target, .optimize = optimize, .mdfunc = mdfunc_lib_path, .mdfunc_mock = mdfunc_mock_build, }); + const imports: []const std.Build.Module.Import = &.{ .{ .name = "build.zig.zon", .module = build_zig_zon }, .{ .name = "chrono", .module = chrono.module("chrono") }, @@ -71,7 +72,16 @@ pub fn build(b: *std.Build) !void { .mdfunc = mdfunc_lib_path, .mdfunc_mock = true, }); - const unit_tests = b.addTest(.{ .root_module = mod }); + + const test_mod = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .imports = imports, + .error_tracing = true, + }); + + const unit_tests = b.addTest(.{ .root_module = test_mod }); unit_tests.root_module.addImport("mcl", mmc_api_mock.module("mcl")); const run_unit_tests = b.addRunArtifact(unit_tests); diff --git a/build.zig.zon b/build.zig.zon index fe60e032..fc8bafe6 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,8 +5,8 @@ .minimum_zig_version = "0.16.0", .dependencies = .{ .mmc_api = .{ - .url = "https://github.com/pmotionf/mmc-api/archive/0b50b4f8a934666d2934d3c24a46e2e06062838d.tar.gz", - .hash = "mmc_api-0.0.0-P5raR6VtMwCIvOPg-bEfOx5Fu4AdWLb5EG8Jo4ZuLCmq", + .url = "https://github.com/pmotionf/mmc-api/archive/3141872.tar.gz", + .hash = "mmc_api-0.0.0-P5raR5htMwCKZFvooh7X-oX1KDmIXsAeVsil5XMH_uFD", }, .chrono = .{ .url = "https://github.com/aaumar25/chrono/archive/adfc771.tar.gz", From 79b2537789a245ad74d024057a283c89ee489bd9 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Tue, 23 Jun 2026 08:05:38 +0900 Subject: [PATCH 06/16] refactor: Implement nested write --- src/command/mcl.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/command/mcl.zig b/src/command/mcl.zig index e6ff8149..3f3dc28d 100644 --- a/src/command/mcl.zig +++ b/src/command/mcl.zig @@ -784,7 +784,7 @@ fn mclStationX(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const station_index: Station.Index = @intCast(axis / 3); try line.stations[station_index].pollX(); - std.log.info("{}", .{line.stations[station_index].x}); + std.log.info("{f}", .{line.stations[station_index].x}); } fn mclStationY(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { @@ -803,7 +803,7 @@ fn mclStationY(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const station_index: Station.Index = @intCast(axis / 3); try line.stations[station_index].pollY(); - std.log.info("{}", .{line.stations[station_index].y}); + std.log.info("{f}", .{line.stations[station_index].y}); } fn mclStationWr(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { @@ -822,7 +822,7 @@ fn mclStationWr(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const station_index: Station.Index = @intCast(axis / 3); try line.stations[station_index].pollWr(); - std.log.info("{}", .{line.stations[station_index].wr}); + std.log.info("{f}", .{line.stations[station_index].wr}); } fn mclStationWw(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { @@ -841,7 +841,7 @@ fn mclStationWw(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const station_index: Station.Index = @intCast(axis / 3); try line.stations[station_index].pollWw(); - std.log.info("{}", .{line.stations[station_index].ww}); + std.log.info("{f}", .{line.stations[station_index].ww}); } fn mclAxisSlider(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { From deeb248c231a0e22914a6e9cff61a3f19fe6343a Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Tue, 23 Jun 2026 08:14:20 +0900 Subject: [PATCH 07/16] fix: `FILE` command infinite loop --- src/command.zig | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/command.zig b/src/command.zig index e56cc221..5fc05157 100644 --- a/src/command.zig +++ b/src/command.zig @@ -459,11 +459,8 @@ fn file(io: std.Io, gpa: std.mem.Allocator, params: [][]const u8) !void { const current_len: usize = command_queue.items.len; var new_line: CommandString = .{ .buffer = undefined, .len = 0 }; while (true) { - const _line = reader.takeDelimiterExclusive('\n') catch |e| switch (e) { - error.EndOfStream => return, - error.ReadFailed => return file_reader.err.?, - else => return e, - }; + try checkCommandInterrupt(); + const _line = try reader.takeDelimiter('\n') orelse return; const line = std.mem.trimEnd(u8, _line, "\r"); @memcpy(new_line.buffer[0..line.len], line); new_line.len = line.len; From 9e28355d9fb7de93ccec6927457587e21cf8f466 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Tue, 23 Jun 2026 08:57:26 +0900 Subject: [PATCH 08/16] fix: `SAVE_OUTPUT` keep overwriting file --- src/command.zig | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/command.zig b/src/command.zig index 5fc05157..29dede4c 100644 --- a/src/command.zig +++ b/src/command.zig @@ -32,8 +32,9 @@ var command_queue: std.ArrayList(CommandString) = .empty; var timer: std.Io.Timestamp = .zero; var clock: std.Io.Clock = .real; var log_file: ?std.Io.File = null; +var file_writer: ?std.Io.File.Writer = null; var io_command: std.Io = undefined; -var io_buf: [4096]u8 = undefined; +var file_buf: [4096]u8 = undefined; const CommandString = struct { buffer: [1024]u8, @@ -66,16 +67,18 @@ pub fn logFn( comptime format: []const u8, args: anytype, ) void { - const io = std.Options.debug_io; - const prev = io.swapCancelProtection(.blocked); - defer _ = io.swapCancelProtection(prev); - if (log_file) |f| { - const file_writer = f.writer(io_command, &io_buf); - var writer = file_writer.interface; - writer.print("{s}({t}):", .{ level.asText(), scope }) catch {}; + if (file_writer) |*f| { + var writer = &f.interface; + writer.writeAll(level.asText()) catch {}; + if (scope != .default) writer.print("({t})", .{scope}) catch {}; + writer.writeAll(": ") catch {}; writer.print(format ++ "\n", args) catch {}; + std.debug.print("buf: {s}", .{writer.buffer[0..writer.end]}); writer.flush() catch return; } + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); var buffer: [64]u8 = undefined; const stderr = std.debug.lockStderr(&buffer).terminal(); defer std.debug.unlockStderr(); @@ -561,15 +564,19 @@ fn setLog(io: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { } else if (std.ascii.eqlIgnoreCase("append", mode_str)) { if (log_file) |f| { f.close(io); + file_writer = null; } log_file = try std.Io.Dir.cwd().createFile(io, file_path, .{ .truncate = false, }); + file_writer = log_file.?.writer(io, &file_buf); } else if (std.ascii.eqlIgnoreCase("replace", mode_str)) { if (log_file) |f| { f.close(io); + file_writer = null; } log_file = try std.Io.Dir.cwd().createFile(io, file_path, .{}); + file_writer = log_file.?.writer(io, &file_buf); } else { return error.InvalidSaveOutputMode; } From 7b647fb0b1d8585aa0c7ac845378d3166e9fa69a Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Tue, 23 Jun 2026 09:01:06 +0900 Subject: [PATCH 09/16] ci: Enable action targetting `chain_commands` --- .github/workflows/main.yml | 30 ------------ .github/workflows/release.yml | 84 ++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 43 ++++++++++++++++ .github/workflows/zig_version.js | 23 +++++++++ 4 files changed, 150 insertions(+), 30 deletions(-) delete mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/zig_version.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index f6bad0a2..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: CI - -on: - push: - branches: - - main - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - build: - strategy: - fail-fast: false - matrix: - os: [self-hosted] - runs-on: ${{ matrix.os }} - steps: - - name: Log masks - run: echo "::add-mask::$NAME_MASK" - - - uses: actions/checkout@v4 - - - name: Run zig fmt - if: matrix.os == 'self-hosted' - run: zig fmt --check . - - - name: Run tests - run: zig build test -Dmdfunc=$MDFUNC_PATH --summary all diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..70a9113d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,84 @@ +name: Release + +on: + workflow_run: + workflows: ["Test"] + types: [completed] + branches: + - main + workflow_dispatch: + +jobs: + release: + strategy: + matrix: + os: [Linux] + runs-on: [self-hosted, "${{ matrix.os }}"] + defaults: + run: + shell: bash + if: ${{ github.event.workflow_run.conclusion == 'success' }} + permissions: + contents: write + steps: + - name: Log masks on Linux + if: matrix.os == 'Linux' + run: echo "::add-mask::$NAME_MASK" + + - name: Log masks on Windows + if: matrix.os == 'Windows' + run: echo "::add-mask::$env:NAME_MASK" + + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: mlugg/setup-zig@v2 + with: + version: 0.15.2 + + - uses: actions/github-script@v7 + id: parse-version + env: + SHA: "${{env.parentSHA}}" + with: + script: | + const script = require('./.github/workflows/zig-version.js'); + await script({core}); + + - name: Check Existing Releases + id: check-version + run: | + echo "EXISTS=$( \ + if gh release view ${VERSION} | grep -q "${VERSION}"; \ + then echo "exists"; \ + else echo ""; \ + fi)" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Windows + if: ${{ steps.check-version.outputs.EXISTS == '' }} + run: | + zig build \ + -Doptimize=ReleaseSafe \ + -Dtarget=x86_64-windows-msvc + zip -j "windows-${NAME}-${VERSION}.zip" \ + "./zig-out/bin/${NAME}.exe" \ + "./zig-out/bin/${NAME}.pdb" + + - name: Build Linux + if: ${{ steps.check-version.outputs.EXISTS == '' }} + run: | + zig build -Doptimize=ReleaseSafe -Dtarget=x86_64-linux-gnu + zip -j "linux-${NAME}-${VERSION}.zip" \ + "./zig-out/bin/${NAME}" + + - name: Create release + if: ${{ steps.check-version.outputs.EXISTS == '' }} + run: | + gh release create --generate-notes "${VERSION}" \ + windows-${NAME}-${VERSION}.zip \ + linux-${NAME}-${VERSION}.zip + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..d9889761 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,43 @@ +name: Test + +on: + push: + branches: + - main + - chain_commands + pull_request: + branches: + - main + - chain_commands + workflow_dispatch: + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [Linux, Windows] + runs-on: [self-hosted, "${{ matrix.os }}"] + steps: + - name: Log masks on Linux + if: matrix.os == 'Linux' + run: echo "::add-mask::$NAME_MASK" + + - name: Log masks on Windows + if: matrix.os == 'Windows' + run: echo "::add-mask::$env:NAME_MASK" + + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: mlugg/setup-zig@v2 + with: + version: 0.15.2 + + - name: Run zig fmt + if: matrix.os == 'Linux' + run: zig fmt --check . + + - name: Run tests + run: zig build test -Dmdfunc_mock -freference-trace --summary all diff --git a/.github/workflows/zig_version.js b/.github/workflows/zig_version.js new file mode 100644 index 00000000..fbaa9cb6 --- /dev/null +++ b/.github/workflows/zig_version.js @@ -0,0 +1,23 @@ +const fs = require("fs").promises; + +module.exports = async ({ core }) => { + // Parse `build.zig.zon` for version + let version; + const name = "mmc-cli"; + const raw = await fs.readFile("./build.zig.zon"); + const lines = raw.toString().split("\n"); + lines.forEach((line) => { + line = line.trim(); + if (line.startsWith(".version")) { + const parts = line.split("="); + const version_raw = parts[1]; + const version_cleaned = version_raw + .replaceAll('"', "") + .replaceAll(",", ""); + version = version_cleaned.trim(); + } + }); + + core.exportVariable("NAME", name); + core.exportVariable("VERSION", version); +}; From 0609cd93a828d59df37dfd66b894cc920b9ddf18 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Tue, 23 Jun 2026 09:03:13 +0900 Subject: [PATCH 10/16] ci: Fix zig version --- .github/workflows/test.yml | 2 +- build.zig.zon | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d9889761..3a8ab3bf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: - uses: mlugg/setup-zig@v2 with: - version: 0.15.2 + version: 0.16.0 - name: Run zig fmt if: matrix.os == 'Linux' diff --git a/build.zig.zon b/build.zig.zon index fc8bafe6..67ca75e3 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,8 +5,8 @@ .minimum_zig_version = "0.16.0", .dependencies = .{ .mmc_api = .{ - .url = "https://github.com/pmotionf/mmc-api/archive/3141872.tar.gz", - .hash = "mmc_api-0.0.0-P5raR5htMwCKZFvooh7X-oX1KDmIXsAeVsil5XMH_uFD", + .url = "https://github.com/pmotionf/mmc-api/archive/01d85bdfcdaf2b4ac12fa348ed9ee27a12cc8fb0.tar.gz", + .hash = "mmc_api-0.0.0-P5raR89JMwDVAu4WHxFcHJZ4qZzQdC3_Ty7HePthz6A3", }, .chrono = .{ .url = "https://github.com/aaumar25/chrono/archive/adfc771.tar.gz", From 9abed650b84c50ef0e8414c420fac250cb592081 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Wed, 24 Jun 2026 09:55:47 +0900 Subject: [PATCH 11/16] fix: Shows error trace correctly --- src/main.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index 29b1b156..dedd5a1a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -57,7 +57,9 @@ pub fn main(init: std.process.Init) !void { } command.execute(io, gpa) catch |e| { std.log.err("{s}", .{@errorName(e)}); - std.log.debug("{any}", .{@errorReturnTrace()}); + if (@errorReturnTrace()) |error_trace| { + std.debug.dumpErrorReturnTrace(error_trace); + } command.queueClear(); continue :command_loop; }; From 8a25a09aafbcf6871e5070a0f100e5a58ef31fa4 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Wed, 24 Jun 2026 10:11:26 +0900 Subject: [PATCH 12/16] fix: `HALL_STATUS` with axis param behavior --- src/command/mcl.zig | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/command/mcl.zig b/src/command/mcl.zig index 3f3dc28d..789dfea2 100644 --- a/src/command/mcl.zig +++ b/src/command/mcl.zig @@ -1184,26 +1184,37 @@ fn mclSliderAxis(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { fn mclHallStatus(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; + const axis_id: ?mcl.Axis.Id.Line = if (params[1].len > 0) + try std.fmt.parseInt(mcl.Axis.Id.Line, params[1], 0) + else + null; const line_idx: usize = try matchLine(line_names, line_name); const line: mcl.Line = mcl.lines[line_idx]; + if (axis_id) |id| { + if (id == 0 or id > line.axes.len) { + return error.InvalidAxis; + } + } try line.pollX(); - - var axis: mcl.Axis.Id.Line = 1; - for (line.stations) |station| { - for (0..3) |_local_axis| { - const local_axis: mcl.Axis.Index.Station = @intCast(_local_axis); - const alarms = station.x.hall_alarm.axis(local_axis); - + if (axis_id) |id| { + const axis = line.axes[id - 1]; + const alarms = axis.station.x.hall_alarm.axis(axis.index.station); + if (alarms.back) { + std.log.info("Axis {} Hall Sensor: BACK - ON", .{axis.id.line}); + } + if (alarms.front) { + std.log.info("Axis {} Hall Sensor: FRONT - ON", .{axis.id.line}); + } + } else for (line.stations) |station| { + for (station.axes) |axis| { + const alarms = axis.station.x.hall_alarm.axis(axis.index.station); if (alarms.back) { - std.log.info("Axis {} Hall Sensor: BACK - ON", .{axis}); + std.log.info("Axis {} Hall Sensor: BACK - ON", .{axis.id.line}); } if (alarms.front) { - std.log.info("Axis {} Hall Sensor: FRONT - ON", .{axis}); + std.log.info("Axis {} Hall Sensor: FRONT - ON", .{axis.id.line}); } - - axis += 1; - if (axis > line.axes.len) break; } } } From 610ed11c5576bc5ef0b2311c2fc4c577d1eb7152 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Wed, 24 Jun 2026 10:21:12 +0900 Subject: [PATCH 13/16] fix: `ASSERT_HALL` reads wrong parameter --- src/command/mcl.zig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/command/mcl.zig b/src/command/mcl.zig index 789dfea2..50574176 100644 --- a/src/command/mcl.zig +++ b/src/command/mcl.zig @@ -1221,13 +1221,13 @@ fn mclHallStatus(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { fn mclAssertHall(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { const line_name: []const u8 = params[0]; - const axis = try std.fmt.parseInt(mcl.Axis.Id.Line, params[2], 0); + const axis = try std.fmt.parseInt(mcl.Axis.Id.Line, params[1], 0); const side: mcl.Direction = - if (std.ascii.eqlIgnoreCase("back", params[3]) or - std.ascii.eqlIgnoreCase("left", params[3])) + if (std.ascii.eqlIgnoreCase("back", params[2]) or + std.ascii.eqlIgnoreCase("left", params[2])) .backward - else if (std.ascii.eqlIgnoreCase("front", params[3]) or - std.ascii.eqlIgnoreCase("right", params[3])) + else if (std.ascii.eqlIgnoreCase("front", params[2]) or + std.ascii.eqlIgnoreCase("right", params[2])) .forward else return error.InvalidHallAlarmSide; @@ -1238,10 +1238,10 @@ fn mclAssertHall(_: std.Io, _: std.mem.Allocator, params: [][]const u8) !void { } var alarm_on: bool = true; - if (params[4].len > 0) { - if (std.ascii.eqlIgnoreCase("off", params[4])) { + if (params[3].len > 0) { + if (std.ascii.eqlIgnoreCase("off", params[3])) { alarm_on = false; - } else if (std.ascii.eqlIgnoreCase("on", params[4])) { + } else if (std.ascii.eqlIgnoreCase("on", params[3])) { alarm_on = true; } else return error.InvalidHallAlarmState; } From 36dce6025da50cb1ba0ca451f25747c43842b311 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Wed, 24 Jun 2026 10:22:26 +0900 Subject: [PATCH 14/16] feat: Add location to `PULL_SLIDER_XXX` --- src/command.zig | 1 - src/command/mcl.zig | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/command.zig b/src/command.zig index 29dede4c..b53598e1 100644 --- a/src/command.zig +++ b/src/command.zig @@ -73,7 +73,6 @@ pub fn logFn( if (scope != .default) writer.print("({t})", .{scope}) catch {}; writer.writeAll(": ") catch {}; writer.print(format ++ "\n", args) catch {}; - std.debug.print("buf: {s}", .{writer.buffer[0..writer.end]}); writer.flush() catch return; } const io = std.Options.debug_io; diff --git a/src/command/mcl.zig b/src/command/mcl.zig index 50574176..ac6c28d2 100644 --- a/src/command/mcl.zig +++ b/src/command/mcl.zig @@ -587,6 +587,7 @@ pub fn init(c: Config) !void { .{ .name = "line name" }, .{ .name = "axis" }, .{ .name = "slider" }, + .{ .name = "location" }, }, .short_description = "Pull incoming slider forward at axis.", .long_description = @@ -603,6 +604,7 @@ pub fn init(c: Config) !void { .{ .name = "line name" }, .{ .name = "axis" }, .{ .name = "slider" }, + .{ .name = "location" }, }, .short_description = "Pull incoming slider backward at axis.", .long_description = @@ -1755,8 +1757,13 @@ fn mclSliderPullForward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) ! const line_name = params[0]; const axis = try std.fmt.parseInt(u16, params[1], 0); const slider_id = try std.fmt.parseInt(u16, params[2], 0); + const location_float = try std.fmt.parseFloat(f32, params[3]); const line_idx: usize = try matchLine(line_names, line_name); const line = mcl.lines[line_idx]; + const location: Distance = .{ + .mm = @intFromFloat(location_float), + .um = @intFromFloat((location_float - @trunc(location_float)) * 1000), + }; if (axis == 0 or axis > line.axes.len) return error.InvalidAxis; @@ -1767,6 +1774,7 @@ fn mclSliderPullForward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) ! try waitCommandReady(station); station.ww.* = .{ .command_code = .PullAxisSliderForward, + .location_distance = location, .command_slider_number = slider_id, .target_axis_number = local_axis + 1, .speed_percentage = line_speeds[line_idx], @@ -1779,8 +1787,13 @@ fn mclSliderPullBackward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) const line_name = params[0]; const axis = try std.fmt.parseInt(u16, params[1], 0); const slider_id = try std.fmt.parseInt(u16, params[2], 0); + const location_float = try std.fmt.parseFloat(f32, params[3]); const line_idx: usize = try matchLine(line_names, line_name); const line = mcl.lines[line_idx]; + const location: Distance = .{ + .mm = @intFromFloat(location_float), + .um = @intFromFloat((location_float - @trunc(location_float)) * 1000), + }; if (axis == 0 or axis > line.axes.len) return error.InvalidAxis; @@ -1791,6 +1804,7 @@ fn mclSliderPullBackward(_: std.Io, _: std.mem.Allocator, params: [][]const u8) try waitCommandReady(station); station.ww.* = .{ .command_code = .PullAxisSliderBackward, + .location_distance = location, .command_slider_number = slider_id, .target_axis_number = local_axis + 1, .speed_percentage = line_speeds[line_idx], From 4201e530894323e6e05c68da36b8d80c9c2e7247 Mon Sep 17 00:00:00 2001 From: aaumar25 Date: Thu, 25 Jun 2026 14:24:43 +0900 Subject: [PATCH 15/16] scm: fix distance conversion on mmc-api --- build.zig.zon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 67ca75e3..9b3d400f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,8 +5,8 @@ .minimum_zig_version = "0.16.0", .dependencies = .{ .mmc_api = .{ - .url = "https://github.com/pmotionf/mmc-api/archive/01d85bdfcdaf2b4ac12fa348ed9ee27a12cc8fb0.tar.gz", - .hash = "mmc_api-0.0.0-P5raR89JMwDVAu4WHxFcHJZ4qZzQdC3_Ty7HePthz6A3", + .url = "https://github.com/pmotionf/mmc-api/archive/6ab55a0.tar.gz", + .hash = "mmc_api-0.0.0-P5raRwlKMwC_S8UFqtWX1Pv6puh_FhSGH-D57eDzAqws", }, .chrono = .{ .url = "https://github.com/aaumar25/chrono/archive/adfc771.tar.gz", From 55eef38911e15a30fcad349b346e55c36cd445b1 Mon Sep 17 00:00:00 2001 From: kf Date: Thu, 25 Jun 2026 17:43:35 +0900 Subject: [PATCH 16/16] fix: time_read output to seconds --- src/command.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command.zig b/src/command.zig index b53598e1..9b36ccaa 100644 --- a/src/command.zig +++ b/src/command.zig @@ -448,9 +448,9 @@ fn timerStart(io: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { fn timerRead(io: std.Io, _: std.mem.Allocator, _: [][]const u8) !void { const duration = timer.untilNow(io, clock); var timer_value: f64 = @floatFromInt(duration.toMicroseconds()); - timer_value = timer_value / std.time.ns_per_s; + timer_value = timer_value / std.time.us_per_s; // Only print to microsecond precision. - std.log.info("Timer: {d:.6}\n", .{timer_value}); + std.log.info("Elapsed time in seconds: {d:.6}\n", .{timer_value}); } fn file(io: std.Io, gpa: std.mem.Allocator, params: [][]const u8) !void {