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..3a8ab3bf --- /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.16.0 + + - 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); +}; 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..6350c2e5 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 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, }); - const network_dep = b.dependency("network", .{}); - const chrono = b.dependency("chrono", .{}); - const exe = b.addExecutable(.{ - .name = "mmc-cli", + const imports: []const std.Build.Module.Import = &.{ + .{ .name = "build.zig.zon", .module = build_zig_zon }, + .{ .name = "chrono", .module = chrono.module("chrono") }, + }; + + const mod = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, + .imports = imports, + .error_tracing = true, + }); + + const exe = b.addExecutable(.{ + .name = "mmc-cli", + .root_module = mod, }); - 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")); + + exe.root_module.addImport("mcl", mmc_api.module("mcl")); b.installArtifact(exe); @@ -51,14 +66,23 @@ 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(.{ + const mmc_api_mock = b.dependency("mmc_api", .{ + .target = target, + .optimize = optimize, + .mdfunc = mdfunc_lib_path, + .mdfunc_mock = true, + }); + + const test_mod = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, + .imports = imports, + .error_tracing = 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 = test_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..9b3d400f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,20 +1,16 @@ .{ .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", - }, - .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/6ab55a0.tar.gz", + .hash = "mmc_api-0.0.0-P5raRwlKMwC_S8UFqtWX1Pv6puh_FhSGH-D57eDzAqws", }, .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..c4886c5b 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -8,28 +8,24 @@ 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_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( Parse, - allocator, + gpa, &json_reader, .{}, ); @@ -47,3 +43,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..9b36ccaa 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,14 @@ 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 file_writer: ?std.Io.File.Writer = null; +var io_command: std.Io = undefined; +var file_buf: [4096]u8 = undefined; const CommandString = struct { buffer: [1024]u8, @@ -47,7 +51,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 +62,41 @@ 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) ++ "): "; - - 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; + 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 {}; + 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(); + 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 +109,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 +118,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 +131,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 +143,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 +163,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 +175,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 +183,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 +193,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 +203,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 +218,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 +239,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 +250,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 +276,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 +305,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 +352,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 +416,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 +433,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 +441,33 @@ 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.us_per_s; + // Only print to microsecond precision. + std.log.info("Elapsed time in seconds: {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 file_buffer: [4096]u8 = undefined; + var f = try std.Io.Dir.cwd().openFile(io, params[0], .{}); + 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 }; - while (try reader.readUntilDelimiterOrEof( - &new_line.buffer, - '\n', - )) |_line| { + while (true) { try checkCommandInterrupt(); - const line = std.mem.trimRight(u8, _line, "\r"); + 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; 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,32 +557,39 @@ 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); + file_writer = null; } - - log_file = try std.fs.cwd().createFile(file_path, .{ + 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(); + f.close(io); + file_writer = null; } - log_file = try std.fs.cwd().createFile(file_path, .{}); + log_file = try std.Io.Dir.cwd().createFile(io, file_path, .{}); + file_writer = log_file.?.writer(io, &file_buf); } 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); } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/command/mcl.zig b/src/command/mcl.zig index 90da4dcd..ac6c28d2 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" }, @@ -429,14 +429,14 @@ 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. , .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" }, @@ -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. @@ -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" }, @@ -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 @@ -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,12 +581,13 @@ 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" }, .{ .name = "axis" }, .{ .name = "slider" }, + .{ .name = "location" }, }, .short_description = "Pull incoming slider forward at axis.", .long_description = @@ -597,12 +598,13 @@ 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" }, .{ .name = "axis" }, .{ .name = "slider" }, + .{ .name = "location" }, }, .short_description = "Pull incoming slider backward at axis.", .long_description = @@ -613,7 +615,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 +628,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 +641,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 +655,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 +669,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 +682,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 +695,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 +708,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 +721,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 +742,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 +750,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 +760,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 +770,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); @@ -784,10 +786,10 @@ fn mclStationX(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(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); @@ -803,10 +805,10 @@ fn mclStationY(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(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); @@ -822,10 +824,10 @@ fn mclStationWr(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(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); @@ -841,10 +843,10 @@ fn mclStationWw(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(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 +881,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 +907,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 +933,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 +960,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 +972,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 +984,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 +1014,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 +1090,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 +1099,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 +1109,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 +1126,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 +1158,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,41 +1184,52 @@ 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 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; } } } -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 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; @@ -1227,10 +1240,10 @@ fn mclAssertHall(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; } @@ -1255,7 +1268,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 +1326,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 +1389,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 +1458,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 +1516,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 +1579,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 +1648,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 +1700,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,12 +1753,17 @@ 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); + 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; @@ -1756,6 +1774,7 @@ fn mclSliderPullForward(params: [][]const u8) !void { 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], @@ -1764,12 +1783,17 @@ 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); + 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; @@ -1780,6 +1804,7 @@ fn mclSliderPullBackward(params: [][]const u8) !void { 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], @@ -1788,7 +1813,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 +1838,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 +1860,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 +1909,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 +1971,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 +2005,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 +2039,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 +2078,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 +2156,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 +2234,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 +2277,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 +2320,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 +2363,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 +2406,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); @@ -2496,3 +2521,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..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(); @@ -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..dedd5a1a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,52 +1,47 @@ 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 = try reader.takeDelimiter('\n') orelse return null; + const result = std.mem.trimEnd(u8, line, "\r"); return result; } 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() !void { +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; } - 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,22 +49,39 @@ 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()}); + if (@errorReturnTrace()) |error_trace| { + std.debug.dumpErrorReturnTrace(error_trace); + } command.queueClear(); continue :command_loop; }; } } +/// 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.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); }