using System; using System.Collections.Generic; using System.Text.Json.Nodes; namespace DeviceCtrlLibrary; /// /// 学生程序进程里的实训台传感器读数副本。权威状态在 Bun 服务器上(网页滑块和开关控制): /// 启动时从环境变量 SIM_BOARD 读入,之后服务器每次变化都通过标准输入推送过来。 /// SetData() 直接读这里,不需要等待网络往返。 /// public static class TrainingBoard { private static readonly object Lock = new(); // ADAM-4017 Vin0–Vin7(温度、湿度、光照、气压、空气质量、CO2、风速、预留) private static int[] _analog = { 25, 60, 500, 101, 60, 600, 3, 0 }; // ADAM-4150 DI0–DI6(人体红外、火焰、烟雾、红外对射、预留) private static bool[] _digital = new bool[7]; // 接线:设备 → 串口(教材布局图的接法,随实验而定,见 shared/protocol.ts 的 DEFAULT_WIRING) private static readonly Dictionary Wiring = new() { ["adam4017"] = "COM2", ["adam4150"] = "COM3", ["zigbee"] = "COM4", ["led"] = "COM5", }; static TrainingBoard() { var initial = Environment.GetEnvironmentVariable("SIM_BOARD"); if (!string.IsNullOrEmpty(initial) && JsonNode.Parse(initial) is JsonObject json) Update(json); } /// 平台内部使用:应用服务器推送的 {"analog":[…],"digital":[…],"clock":…,"wiring":{…}}(clock、wiring 不带时表示不变) public static void Update(JsonObject json) { if (json.ContainsKey("clock")) Sim.Host.SimClock.Update(json["clock"]); lock (Lock) { if (json["analog"] is JsonArray analog) for (var i = 0; i < analog.Count && i < _analog.Length; i++) _analog[i] = (int?)analog[i] ?? 0; if (json["digital"] is JsonArray digital) for (var i = 0; i < digital.Count && i < _digital.Length; i++) _digital[i] = (bool?)digital[i] ?? false; if (json["wiring"] is JsonObject wiring) foreach (var (device, port) in wiring) if (Wiring.ContainsKey(device) && port is not null) Wiring[device] = (string)port!; } } /// /// 程序打开的串口上有没有接这台设备。和真机一样,串口打开错了不报错,只是设备收不到命令、也不回应。 /// Windows 的串口名不分大小写 /// internal static bool Reaches(string device, string? portName) { if (string.IsNullOrWhiteSpace(portName)) return false; lock (Lock) return Wiring.TryGetValue(device, out var port) && string.Equals(port, portName.Trim(), StringComparison.OrdinalIgnoreCase); } internal static int ReadAnalog(int channel) { lock (Lock) return channel >= 0 && channel < _analog.Length ? _analog[channel] : 0; } internal static bool ReadDigital(int channel) { lock (Lock) return channel >= 0 && channel < _digital.Length && _digital[channel]; } }