Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,10 @@ jobs:
if: matrix.os == 'Linux'
run: zig fmt --check .

- name: Run module tests
- name: Run Linux tests
if: matrix.os == 'Linux'
run: zig build test --summary all

- name: Run Windows tests
if: matrix.os == 'Windows'
run: zig build test -Dmdfunc=$MDFUNC_PATH --summary all
56 changes: 56 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,60 @@ pub fn build(b: *std.Build) !void {
);

gen_proto.dependOn(&protoc_step.step);

// ***** Building for legacy MCL interface *****
const mdfunc_lib_path = b.option(
[]const u8,
"mdfunc",
"Specify the path to the MELSEC static library artifact.",
) orelse if (target.result.cpu.arch == .x86_64)
"vendor/mdfunc/lib/x64/MdFunc32.lib"
else
"vendor/mdfunc/lib/mdfunc32.lib";

const mdfunc_mock_build = b.option(
bool,
"mdfunc_mock",
"Enable building a mock version of the MELSEC data link library.",
) orelse (target.result.os.tag != .windows);

const mdfunc = b.dependency("mdfunc", .{
.target = target,
.optimize = optimize,
.mdfunc = mdfunc_lib_path,
.mock = mdfunc_mock_build,
});

_ = b.addModule("mcl", .{
.root_source_file = b.path("src/mcl/mcl.zig"),
.imports = &.{
.{ .name = "build.zig.zon", .module = build_zig_zon },
.{ .name = "mdfunc", .module = mdfunc.module("mdfunc") },
},
.target = target,
.optimize = optimize,
});

const mdfunc_mock = b.dependency("mdfunc", .{
.target = target,
.optimize = optimize,
.mdfunc = mdfunc_lib_path,
.mock = true,
});

const test_mod = b.createModule(.{
.root_source_file = b.path("src/mcl/mcl.zig"),
.imports = &.{
.{ .name = "build.zig.zon", .module = build_zig_zon },
.{ .name = "mdfunc", .module = mdfunc_mock.module("mdfunc") },
},
.target = target,
.optimize = optimize,
});

const mcl_test = b.addTest(.{
.root_module = test_mod,
});
const run_mcl_tests = b.addRunArtifact(mcl_test);
test_step.dependOn(&run_mcl_tests.step);
}
4 changes: 4 additions & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
.url = "https://github.com/Arwalk/zig-protobuf/archive/7673d62.tar.gz",
.hash = "protobuf-3.0.0-0e82auyUKACQqyLICPhWm6kJoAru5DNP-idAJMP1W94r",
},
.mdfunc = .{
.url = "https://github.com/pmotionf/mdfunc.zig/archive/6d70ce0.tar.gz",
.hash = "mdfunc-0.0.5-k9D_qBiuAADEPbD9zlxCm_bwaA41w9vCZuVH-ENIdkFe",
},
},
.paths = .{""},
}
35 changes: 35 additions & 0 deletions src/mcl/Axis.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! This module provides convenient indexing of system axes, both in terms of
//! line-level indexing and local station-level indexing.
const Axis = @This();

const std = @import("std");

const MclStation = @import("Station.zig");

station: *const MclStation,
index: Index,
id: Id,

pub const Index = struct {
station: Station,
line: Line,

/// Local axis index within station.
pub const Station = std.math.IntFittingRange(0, 2);
/// Axis index within line.
pub const Line = std.math.IntFittingRange(0, 64 * 4 * 3 - 1);
};

pub const Id = struct {
station: Station,
line: Line,

/// Local axis ID within station.
pub const Station = std.math.IntFittingRange(1, 3);
/// Axis ID within line.
pub const Line = std.math.IntFittingRange(1, 64 * 4 * 3);
};

test {
std.testing.refAllDecls(@This());
}
73 changes: 73 additions & 0 deletions src/mcl/Config.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const Config = @This();

const std = @import("std");
const cclink = @import("cclink.zig");
const mcl = @import("mcl.zig");

lines: []Line,

pub const Line = struct {
/// Total number of axes in line.
axes: mcl.Axis.Id.Line,

/// CC-Link Station ranges.
ranges: []Range,

pub const Range = struct {
/// CC-Link Channel.
channel: cclink.Channel,
/// CC-Link Station ID. Start of range, inclusive.
start: cclink.Id,
/// CC-Link Station ID. End of range, inclusive.
end: cclink.Id,
};
};

pub fn validate(c: Config) !void {
if (c.lines.len == 0 or c.lines.len > 64 * 4) {
return error.ConfigInvalidNumberOfLines;
}

var total_stations_num: usize = 0;
var used_cc_link_stations: [64 * 4]bool = .{false} ** (64 * 4);

for (c.lines) |line| {
var total_line_stations: usize = 0;
if (line.axes == 0 or line.axes > 64 * 4 * 3) {
return error.ConfigInvalidLineAxes;
}

const required_stations: usize = (line.axes - 1) / 3 + 1;

for (line.ranges) |range| {
if (range.start == 0 or range.start > 64) {
return error.ConfigInvalidLineRangeStart;
}
if (range.end < range.start or range.end > 64) {
return error.ConfigInvalidLineRangeEnd;
}
const channel_offset: usize =
64 * @as(usize, @intFromEnum(range.channel));
for (range.start - 1..range.end) |range_index| {
if (used_cc_link_stations[channel_offset + range_index]) {
return error.ConfigOverlappingLineStationRanges;
}
used_cc_link_stations[channel_offset + range_index] = true;
total_stations_num += 1;
total_line_stations += 1;
}
}

if (total_line_stations != required_stations) {
return error.ConfigInvalidLineAxesForStations;
}
}

if (total_stations_num == 0 or total_stations_num > 64 * 4) {
return error.ConfigInvalidTotalNumberOfStations;
}
}

test {
std.testing.refAllDecls(@This());
}
Loading
Loading