154 lines
6.5 KiB
Java
154 lines
6.5 KiB
Java
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<String> 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<Ft546RegisterWrite> writes =
|
|
new ArrayList<Ft546RegisterWrite>();
|
|
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<Ft546RegisterWrite> writes =
|
|
new ArrayList<Ft546RegisterWrite>();
|
|
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<Ft546RegisterWrite> writes =
|
|
new ArrayList<Ft546RegisterWrite>();
|
|
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<Ft546RegisterWrite> writes,
|
|
Ft546DeviceProfile profile, String register,
|
|
Ft546RegisterWrite.DataType dataType,
|
|
boolean trigger, int... values) {
|
|
List<Integer> boxed = new ArrayList<Integer>(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<Integer> 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();
|
|
}
|
|
}
|