2025-02-11 07:55:25 -07:00
|
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
pub fn main() !void {
|
2025-02-11 16:28:27 -07:00
|
|
|
var input = Signal{ .digital = 1, .analog = 0.5 };
|
|
|
|
|
|
|
|
var battery1 = Battery{ .value = -0.5 };
|
|
|
|
var battery2 = Battery{ .value = 0.5 };
|
|
|
|
var battery3 = Battery{ .value = -1.0 };
|
|
|
|
|
|
|
|
var or1_inputs = [_]*Signal{ &input, &input, undefined };
|
|
|
|
var or1 = Or{ .inputs = &or1_inputs, .arithmetic_mode = true };
|
|
|
|
var or2_inputs = [_]*Signal{ &or1.output, &or1.output, undefined };
|
|
|
|
var or2 = Or{ .inputs = &or2_inputs, .arithmetic_mode = true };
|
|
|
|
|
|
|
|
var or3_inputs = [_]*Signal{ &input, &battery1.output };
|
|
|
|
var or3 = Or{ .inputs = &or3_inputs };
|
|
|
|
var or4_inputs = [_]*Signal{ &or1.output, &battery1.output };
|
|
|
|
var or4 = Or{ .inputs = &or4_inputs };
|
|
|
|
var or5_inputs = [_]*Signal{ &or2.output, &battery1.output };
|
|
|
|
var or5 = Or{ .inputs = &or5_inputs };
|
|
|
|
|
|
|
|
var or6_inputs = [_]*Signal{ &battery2.output, &or3.output };
|
|
|
|
var or6 = Or{ .inputs = &or6_inputs, .arithmetic_mode = true };
|
|
|
|
var and1_inputs = [_]*Signal{ &battery3.output, &or6.output };
|
2025-02-12 01:04:53 -07:00
|
|
|
var and1 = And{ .inputs = &and1_inputs, .arithmetic_mode = true };
|
2025-02-11 16:28:27 -07:00
|
|
|
var or7_inputs = [_]*Signal{ &battery2.output, &or4.output };
|
|
|
|
var or7 = Or{ .inputs = &or7_inputs, .arithmetic_mode = true };
|
|
|
|
var and2_inputs = [_]*Signal{ &battery3.output, &or7.output };
|
2025-02-12 01:04:53 -07:00
|
|
|
var and2 = And{ .inputs = &and2_inputs, .arithmetic_mode = true };
|
2025-02-11 16:28:27 -07:00
|
|
|
var or8_inputs = [_]*Signal{ &battery2.output, &or5.output };
|
|
|
|
var or8 = Or{ .inputs = &or8_inputs, .arithmetic_mode = true };
|
|
|
|
|
|
|
|
or1_inputs[2] = &and1.output;
|
|
|
|
or2_inputs[2] = &and2.output;
|
|
|
|
|
|
|
|
battery1.process();
|
|
|
|
battery2.process();
|
|
|
|
battery3.process();
|
|
|
|
or3.process();
|
|
|
|
or6.process();
|
|
|
|
and1.process();
|
|
|
|
or1.process();
|
|
|
|
or4.process();
|
|
|
|
or7.process();
|
|
|
|
and2.process();
|
|
|
|
or2.process();
|
|
|
|
or5.process();
|
|
|
|
or8.process();
|
|
|
|
|
2025-02-12 01:37:16 -07:00
|
|
|
std.debug.print("Input:\n{}\n\n", .{input});
|
2025-02-12 01:04:53 -07:00
|
|
|
std.debug.print("{}\n{}\n\n", .{ or1.output, or2.output });
|
|
|
|
std.debug.print("{}\n{}\n{}\n\n", .{ or3.output, or4.output, or5.output });
|
|
|
|
std.debug.print("{}\n{}\n{}\n{}\n{}\n\n", .{ or6.output, and1.output, or7.output, and2.output, or8.output });
|
2025-02-11 07:55:25 -07:00
|
|
|
}
|
|
|
|
|
2025-02-11 13:46:37 -07:00
|
|
|
pub const Signal = struct {
|
|
|
|
digital: i2 = 0,
|
|
|
|
analog: f32 = 0.0,
|
|
|
|
color: u24 = 0,
|
|
|
|
|
|
|
|
pub fn format(
|
|
|
|
self: Signal,
|
|
|
|
comptime fmt: []const u8,
|
|
|
|
options: std.fmt.FormatOptions,
|
|
|
|
writer: anytype,
|
|
|
|
) !void {
|
|
|
|
_ = .{ fmt, options };
|
|
|
|
try writer.writeAll("Signal(");
|
|
|
|
if (self.digital < 0) try writer.writeByte('-') else try writer.writeByte('+');
|
|
|
|
try writer.print("{d} / {d:0>1.4})", .{
|
|
|
|
@abs(self.digital),
|
|
|
|
self.analog,
|
|
|
|
});
|
|
|
|
}
|
2025-02-11 11:22:34 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
pub const Battery = struct {
|
2025-02-11 13:07:08 -07:00
|
|
|
value: f32,
|
|
|
|
|
2025-02-11 16:28:27 -07:00
|
|
|
output: Signal = .{},
|
|
|
|
|
|
|
|
pub fn process(self: *Battery) void {
|
|
|
|
self.output.digital = @intFromFloat(std.math.sign(self.value));
|
|
|
|
self.output.analog = self.value;
|
2025-02-11 13:07:08 -07:00
|
|
|
}
|
2025-02-11 08:14:55 -07:00
|
|
|
};
|
|
|
|
|
2025-02-11 13:46:37 -07:00
|
|
|
pub const Not = struct {
|
|
|
|
input: *Signal,
|
|
|
|
output: Signal = .{},
|
2025-02-11 11:43:39 -07:00
|
|
|
|
2025-02-11 13:46:37 -07:00
|
|
|
invert_output: bool = true,
|
2025-02-11 11:43:39 -07:00
|
|
|
|
2025-02-11 13:46:37 -07:00
|
|
|
pub fn process(self: *Not) void {
|
|
|
|
if (self.invert_output) {
|
2025-02-11 16:28:27 -07:00
|
|
|
self.output.digital = 1 - @as(i2, @intCast(@abs(self.input.digital)));
|
2025-02-11 13:46:37 -07:00
|
|
|
self.output.analog = 1.0 - @abs(self.input.analog);
|
|
|
|
} else {
|
|
|
|
self.output.digital = self.input.digital;
|
|
|
|
self.output.analog = self.input.analog;
|
|
|
|
}
|
2025-02-12 01:04:53 -07:00
|
|
|
self.output.analog = std.math.clamp(self.output.analog, -1.0, 1.0);
|
2025-02-11 13:46:37 -07:00
|
|
|
}
|
|
|
|
};
|
2025-02-11 11:43:39 -07:00
|
|
|
|
2025-02-11 16:28:27 -07:00
|
|
|
pub const And = struct {
|
|
|
|
inputs: []*Signal,
|
|
|
|
output: Signal = .{},
|
2025-02-11 11:43:39 -07:00
|
|
|
|
2025-02-11 16:28:27 -07:00
|
|
|
// if false, is in Minimum Input mode
|
|
|
|
// if true, is in Multiply Inputs mode
|
|
|
|
arithmetic_mode: bool = false,
|
|
|
|
|
|
|
|
// TODO check implementation
|
|
|
|
pub fn process(self: *And) void {
|
|
|
|
if (self.arithmetic_mode) {
|
|
|
|
self.output.digital = self.inputs[0].digital;
|
|
|
|
self.output.analog = self.inputs[0].analog;
|
|
|
|
for (self.inputs[1..]) |input| {
|
2025-02-12 01:37:16 -07:00
|
|
|
self.output.digital = 0; // TODO
|
2025-02-11 16:28:27 -07:00
|
|
|
self.output.analog *= input.analog;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.output.digital = self.inputs[0].digital;
|
|
|
|
self.output.analog = self.inputs[0].analog;
|
|
|
|
for (self.inputs[1..]) |input| {
|
2025-02-12 01:37:16 -07:00
|
|
|
self.output.digital = 0; // TODO
|
2025-02-12 01:04:53 -07:00
|
|
|
self.output.analog = switch (std.math.order(@abs(self.output.analog), @abs(input.analog))) {
|
|
|
|
.lt => self.output.analog,
|
|
|
|
.eq => @min(self.output.analog, input.analog), // TODO what does this *actually* do?
|
|
|
|
.gt => input.analog,
|
|
|
|
};
|
2025-02-11 16:28:27 -07:00
|
|
|
}
|
|
|
|
}
|
2025-02-12 01:04:53 -07:00
|
|
|
self.output.analog = std.math.clamp(self.output.analog, -1.0, 1.0);
|
2025-02-11 16:28:27 -07:00
|
|
|
}
|
|
|
|
};
|
2025-02-11 11:43:39 -07:00
|
|
|
|
2025-02-12 01:04:53 -07:00
|
|
|
test "min" {
|
|
|
|
var a = Signal{ .analog = 0.0 };
|
|
|
|
var b = Signal{ .analog = 1.0 };
|
|
|
|
|
|
|
|
var inputs = [_]*Signal{ &a, &b };
|
|
|
|
var and1 = And{ .inputs = &inputs };
|
|
|
|
|
|
|
|
and1.process();
|
|
|
|
try std.testing.expectEqual(0.0, and1.output.analog);
|
|
|
|
|
|
|
|
a.analog = -0.5;
|
|
|
|
b.analog = -0.2;
|
|
|
|
and1.process();
|
|
|
|
try std.testing.expectEqual(-0.2, and1.output.analog);
|
|
|
|
}
|
|
|
|
|
2025-02-11 16:28:27 -07:00
|
|
|
pub const Or = struct {
|
|
|
|
inputs: []*Signal,
|
|
|
|
output: Signal = .{},
|
2025-02-11 11:43:39 -07:00
|
|
|
|
2025-02-11 16:28:27 -07:00
|
|
|
// if false, is in Maximum Input mode
|
|
|
|
// if true, is in Add Inputs mode
|
|
|
|
arithmetic_mode: bool = false,
|
|
|
|
|
|
|
|
// TODO check implementation
|
|
|
|
pub fn process(self: *Or) void {
|
|
|
|
if (self.arithmetic_mode) {
|
|
|
|
self.output.digital = self.inputs[0].digital;
|
|
|
|
self.output.analog = self.inputs[0].analog;
|
|
|
|
for (self.inputs[1..]) |input| {
|
2025-02-12 01:37:16 -07:00
|
|
|
self.output.digital = 0; // TODO
|
2025-02-11 16:28:27 -07:00
|
|
|
self.output.analog += input.analog;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.output.digital = self.inputs[0].digital;
|
|
|
|
self.output.analog = self.inputs[0].analog;
|
|
|
|
for (self.inputs[1..]) |input| {
|
2025-02-12 01:37:16 -07:00
|
|
|
self.output.digital = 0; // TODO
|
2025-02-12 01:04:53 -07:00
|
|
|
self.output.analog = switch (std.math.order(@abs(self.output.analog), @abs(input.analog))) {
|
|
|
|
.lt => input.analog,
|
|
|
|
.eq => @max(self.output.analog, input.analog), // TODO what does this *actually* do?
|
|
|
|
.gt => self.output.analog,
|
|
|
|
};
|
2025-02-11 16:28:27 -07:00
|
|
|
}
|
|
|
|
}
|
2025-02-12 01:04:53 -07:00
|
|
|
self.output.analog = std.math.clamp(self.output.analog, -1.0, 1.0);
|
2025-02-11 16:28:27 -07:00
|
|
|
}
|
|
|
|
};
|
2025-02-12 01:04:53 -07:00
|
|
|
|
|
|
|
test "max" {
|
|
|
|
var a = Signal{ .analog = 0.0 };
|
|
|
|
var b = Signal{ .analog = 1.0 };
|
|
|
|
|
|
|
|
var inputs = [_]*Signal{ &a, &b };
|
|
|
|
var or1 = Or{ .inputs = &inputs };
|
|
|
|
|
|
|
|
or1.process();
|
|
|
|
try std.testing.expectEqual(1.0, or1.output.analog);
|
|
|
|
|
|
|
|
a.analog = -0.5;
|
|
|
|
b.analog = -0.2;
|
|
|
|
or1.process();
|
|
|
|
try std.testing.expectEqual(-0.5, or1.output.analog);
|
|
|
|
}
|