using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using AutoFocusTool.Serial; namespace AutoFocusTool.Devices { /// /// 多舱室设备发现。复刻原工程开机枚举逻辑: /// 1) 枚举相机 0..9,逐个 Init 读序列号,建 index→SN 字典; /// 2) 扫描 COM 口(跳过 COM1/COM2),逐个握手得 houseSn + 读 EEPROM 的 CCDSN; /// 3) 用 CCDSN 把舱室配对到相机 index。 /// /// 注意:相机 index 与 COM 口每次开机可能变,必须现场重扫,不能写死。 /// 两条总线相互独立,可只扫其一。 /// public class DeviceScanner { public Action Log; /// 枚举相机 0..maxCameras-1,返回能读到序列号的相机列表。 public List ScanCameras(int maxCameras = 10) { var list = new List(); for (int i = 0; i < maxCameras; i++) { Camera.Camera cam = null; try { cam = new Camera.Camera(i, 100, 100, 100); // 小尺寸快速探测 int init = cam.Init(); if (init != 0) { Log?.Invoke($"相机#{i} 初始化失败(code={init}),跳过"); continue; } int sr = cam.ReadSerial(); string sn = cam.SerialNumber; if (sr == 0 && !string.IsNullOrWhiteSpace(sn)) { list.Add(new CameraDevice { Index = i, SerialNumber = sn.Trim() }); Log?.Invoke($"发现 相机#{i} SN={sn.Trim()}"); } else { Log?.Invoke($"相机#{i} 读序列号失败(code={sr})"); } } catch (Exception ex) { Log?.Invoke($"相机#{i} 探测异常: {ex.Message}"); } finally { try { cam?.UnInit(); cam?.Dispose(); } catch { } } } Log?.Invoke($"相机枚举完成,共 {list.Count} 台"); return list; } /// /// 扫描所有 COM 口(跳过 COM1/COM2),握手得 houseSn、读 CCDSN。 /// 返回握手成功的舱室列表(此时 CcdIndex 还未配对)。 /// public List ScanHouses() { var houses = new List(); string[] ports = SerialPort.GetPortNames() .Where(p => p != null && p.ToUpper().StartsWith("COM")) .Where(p => p.ToUpper() != "COM1" && p.ToUpper() != "COM2") .Distinct() .ToArray(); Log?.Invoke($"待探测串口: {string.Join(", ", ports)}"); foreach (var port in ports) { HouseMotor motor = null; try { motor = new HouseMotor(port) { Log = Log }; if (!motor.Open()) { Log?.Invoke($"{port} 打开失败,跳过"); continue; } int houseSn = motor.ShakeHands(); if (houseSn < 0) { Log?.Invoke($"{port} 握手无回复,非舱室口"); continue; } int ccdSnInt = motor.ReadCCDSN(); var hd = new HouseDevice { HouseSn = houseSn, PortName = port, CcdSn = ccdSnInt < 0 ? "" : ccdSnInt.ToString(), }; houses.Add(hd); Log?.Invoke($"发现 舱室{houseSn} @ {port} CCDSN={hd.CcdSn}"); } catch (Exception ex) { Log?.Invoke($"{port} 探测异常: {ex.Message}"); } finally { try { motor?.Close(); motor?.Dispose(); } catch { } } } Log?.Invoke($"舱室扫描完成,共 {houses.Count} 个"); return houses; } /// /// 完整扫描:先枚举相机,再扫舱室,用 CCDSN 配对相机 index。 /// public List ScanAll() { var cameras = ScanCameras(); var houses = ScanHouses(); foreach (var h in houses) { if (string.IsNullOrEmpty(h.CcdSn)) continue; var cam = cameras.FirstOrDefault(c => c.SerialNumber == h.CcdSn); if (cam != null) { h.CcdIndex = cam.Index; Log?.Invoke($"配对: 舱室{h.HouseSn} ←→ 相机#{cam.Index}"); } else { Log?.Invoke($"舱室{h.HouseSn} 的 CCDSN={h.CcdSn} 在相机列表中未找到"); } } return houses.OrderBy(h => h.HouseSn).ToList(); } } }