package com.ruoyi.ft546.protocol; import java.util.ArrayList; import java.util.List; import java.util.Set; public final class Ft546SrgvCommandEncoder { public Ft546EncodedCommand encode(Ft546SrgvCommandIntent intent, Ft546DeviceProfile profile, Set capabilities) { if (intent == null) { throw new IllegalArgumentException("intent must not be null"); } if (profile == null) { throw new IllegalArgumentException("profile must not be null"); } if (capabilities == null) { throw new IllegalArgumentException( "capabilities must not be null"); } int[] route = route(intent.getPathPoints()); Integer stage = intent.getTwoStageNumber(); if (stage == null) { if (!capabilities.contains("POINT_TO_POINT_COMMAND")) { throw new IllegalStateException( "POINT_TO_POINT_COMMAND is not enabled"); } return main(intent, profile, route); } if (!capabilities.contains("TWO_STAGE_ATOMIC_TASK")) { throw new IllegalStateException( "TWO_STAGE_ATOMIC_TASK is not enabled"); } if (stage.intValue() == 1) { return secondStageOne(intent, profile, route); } if (stage.intValue() == 2) { return secondStageTwo(intent, profile, route); } throw new IllegalArgumentException("stage must be 1 or 2"); } private static Ft546EncodedCommand main(Ft546SrgvCommandIntent intent, Ft546DeviceProfile profile, int[] route) { List writes = new ArrayList(); add(writes, profile, "path", Ft546RegisterWrite.DataType.INT32, false, route); add(writes, profile, "taskNo", Ft546RegisterWrite.DataType.INT32, false, intent.getTaskNo()); add(writes, profile, "taskType", Ft546RegisterWrite.DataType.INT16, false, intent.getTaskType()); add(writes, profile, "trigger", Ft546RegisterWrite.DataType.INT16, true, 1); if (intent.getTaskType() == 8) { if (intent.getCrossFloorTarget() == null) { throw new IllegalArgumentException( "crossFloorTarget is required"); } add(writes, profile, "crossFloorFlag", Ft546RegisterWrite.DataType.INT16, false, 1); add(writes, profile, "crossFloorTarget", Ft546RegisterWrite.DataType.INT16, false, intent.getCrossFloorTarget()); } return new Ft546EncodedCommand(intent, writes, 1); } private static Ft546EncodedCommand secondStageOne( Ft546SrgvCommandIntent intent, Ft546DeviceProfile profile, int[] route) { List writes = new ArrayList(); add(writes, profile, "secondPath", Ft546RegisterWrite.DataType.INT32, false, route); add(writes, profile, "secondStageFlag", Ft546RegisterWrite.DataType.INT16, true, 1); add(writes, profile, "secondTaskType", Ft546RegisterWrite.DataType.INT16, false, intent.getTaskType()); add(writes, profile, "secondTaskNo", Ft546RegisterWrite.DataType.INT32, false, intent.getTaskNo()); return new Ft546EncodedCommand(intent, writes, 1); } private static Ft546EncodedCommand secondStageTwo( Ft546SrgvCommandIntent intent, Ft546DeviceProfile profile, int[] route) { List writes = new ArrayList(); add(writes, profile, "secondPath", Ft546RegisterWrite.DataType.INT32, false, route); add(writes, profile, "secondStageFlag", Ft546RegisterWrite.DataType.INT16, true, 2); add(writes, profile, "secondComplete", Ft546RegisterWrite.DataType.INT16, false, 99); add(writes, profile, "secondTaskType", Ft546RegisterWrite.DataType.INT16, false, 9); add(writes, profile, "secondTaskNo", Ft546RegisterWrite.DataType.INT32, false, intent.getTaskNo()); return new Ft546EncodedCommand(intent, writes, 2); } private static void add(List writes, Ft546DeviceProfile profile, String register, Ft546RegisterWrite.DataType dataType, boolean trigger, int... values) { List boxed = new ArrayList(values.length); for (int value : values) { if (dataType == Ft546RegisterWrite.DataType.INT16 && (value < Short.MIN_VALUE || value > Short.MAX_VALUE)) { throw new IllegalArgumentException( register + " value is not an int16"); } boxed.add(value); } writes.add(new Ft546RegisterWrite(register(profile, register), dataType, boxed, writes.size() + 1, trigger)); } private static int[] route(List points) { if (points.size() < 2 || points.size() > 8) { throw new IllegalArgumentException( "legacy route must contain between 2 and 8 command points"); } int[] result = new int[8]; for (int index = 0; index < points.size(); index++) { Integer point = points.get(index); if (point == null || point.intValue() <= 0) { throw new IllegalArgumentException( "route node must be positive"); } if (point.intValue() > 999999) { throw new IllegalArgumentException( "route node exceeds six digits"); } result[index] = point.intValue(); } return result; } private static String register(Ft546DeviceProfile profile, String name) { String address = profile.getRegisters().get(name); if (address == null || address.trim().isEmpty()) { throw new IllegalArgumentException( "profile register is missing: " + name); } return address.trim(); } }