using System.ComponentModel; using Dabit.Mcp.Services; using DibdProtocol.Protocol; using Microsoft.Extensions.Logging; using ModelContextProtocol.Server; namespace Dabit.Mcp.Tools; /// /// 표출신호(HUB75 패턴) 설정 도구. ⚠️ 쓰기 — F16 영역(70+ 모델 의존). /// 대표 신호만 이름으로 지원하고, 그 외는 send_custom_signal로 raw 코드 전송. /// [McpServerToolType] public sealed class SignalTools { private readonly LedControlService _led; private readonly ILogger _log; public SignalTools(LedControlService led, ILogger log) { _led = led; _log = log; } // 대표 표출신호 → HexData 4바이트 (정본 DisplaySignalData 일부). 전체 70+는 send_custom_signal로. private static readonly Dictionary SignalHexData = new(StringComparer.OrdinalIgnoreCase) { ["16D-P16D1S11"] = new byte[] { 0x00, 0x10, 0x01, 0x11 }, ["16D-P16D1S10-1"] = new byte[] { 0x00, 0x10, 0x01, 0x01 }, ["08D-P32D1S11"] = new byte[] { 0x00, 0x08, 0x01, 0x11 }, ["08D-P64D1S21"] = new byte[] { 0x00, 0x08, 0x01, 0x21 }, ["04D-P32D2S11"] = new byte[] { 0x00, 0x04, 0x02, 0x11 }, ["04D-P64D1S11"] = new byte[] { 0x00, 0x04, 0x01, 0x11 }, ["32D-P16D1S11"] = new byte[] { 0x00, 0x20, 0x01, 0x11 }, }; [McpServerTool] [Description("전광판 표출신호(HUB75 패턴)를 이름으로 설정한다. ⚠️ 쓰기 — 잘못 설정하면 화면이 깨진다. " + "지원: 16D-P16D1S11, 16D-P16D1S10-1, 08D-P32D1S11, 08D-P64D1S21, 04D-P32D2S11, 04D-P64D1S11, 32D-P16D1S11. " + "목록에 없으면 send_custom_signal을 쓴다. (08D-P64D1S21은 138 IC 스캔 고정)")] public async Task SetDisplaySignal( [Description("신호 이름. 예: \"16D-P16D1S11\"")] string signalName, [Description("색 순서 0~6 (기본 0)")] int colorOrder = 0, CancellationToken ct = default) { if (!SignalHexData.TryGetValue(signalName.Trim(), out var hd)) return $"지원하지 않는 신호 '{signalName}'. 지원 목록: {string.Join(", ", SignalHexData.Keys)}. 또는 send_custom_signal 사용."; var colorHex = (byte)(Math.Clamp(colorOrder, 0, 6) + 1); // 정본: idx+1 byte[] payload = { hd[0], hd[1], hd[2], hd[3], colorHex, 0x01 }; // scanHex 기본 0x01(138 IC) var resp = await _led.SendHexAsync(HexCommand.SetHub75Pattern, payload, ct, 5000); var (ok, msg) = LedControlService.CheckWriteStatus(HexCommand.SetHub75Pattern, resp); return ok ? $"표출신호 '{signalName}' 설정 (color={colorOrder})." : $"표출신호 설정 실패 — {msg}"; } [McpServerTool] [Description("사용자 지정 표출신호 코드를 직접 전송한다(고급). ⚠️ 쓰기 — 코드 형식을 정확히 알 때만 사용. 잘못된 값은 화면을 깨뜨릴 수 있다.")] public async Task SendCustomSignal( [Description("신호 코드 문자열. 예: \"8121\"")] string code, CancellationToken ct = default) { if (string.IsNullOrWhiteSpace(code) || code.Contains('/') || code.Contains("![") || code.Contains("!]")) return "유효한 신호 코드가 아닙니다 ('/', '![', '!]' 불가)."; // 정본: ASCII msgType "44", data 맨 앞 공백 1개 필수 var resp = await _led.SendAsciiAsync("44", " " + code.Trim(), ct, 5000); if (resp is null) return "전송 실패 — 연결 또는 통신 오류."; return resp.Result == "F" ? "전광판이 거부했습니다 (Result=F)." : $"사용자 표출신호 '{code}' 전송."; } }