list) {
for (var val : list) {
add(val);
diff --git a/src/main/java/a8k/app/utils/ZSqliteJdbcHelper.java b/src/main/java/a8k/app/utils/ZSqliteJdbcHelper.java
index f1f8ea0..3db6206 100644
--- a/src/main/java/a8k/app/utils/ZSqliteJdbcHelper.java
+++ b/src/main/java/a8k/app/utils/ZSqliteJdbcHelper.java
@@ -9,7 +9,10 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.slf4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import javax.lang.model.element.TypeElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
@@ -222,6 +225,7 @@ public class ZSqliteJdbcHelper {
jdbcTemplate.update("delete from " + tableName + " where id = ?", id);
}
+
public static void addObj(JdbcTemplate jdbcTemplate, String tableName, Class> tClass, Object obj) {
StringBuilder sql = new StringBuilder("insert into " + tableName + "(");
StringBuilder values = new StringBuilder(" values(");
@@ -257,6 +261,8 @@ public class ZSqliteJdbcHelper {
args.add(idval);
jdbcTemplate.update(sql.toString(), args.toArray());
+
+
}
public static void updateObj(JdbcTemplate jdbcTemplate, String tableName, Class> tClass, Object obj) {
diff --git a/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java b/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java
index 358aab3..57e33fb 100644
--- a/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java
+++ b/src/main/java/a8k/extui/mgr/ExtApiPageGroupCfgMgr.java
@@ -1,6 +1,8 @@
package a8k.extui.mgr;
import a8k.app.utils.ZList;
+import a8k.extui.page.apptest.LisTestPage;
+import a8k.extui.page.apptest.PrinterDebugPage;
import a8k.extui.page.debug.*;
import a8k.extui.page.driver.*;
import a8k.extui.page.driver.pipette_module.*;
@@ -160,7 +162,14 @@ public class ExtApiPageGroupCfgMgr {
new Menu(WaterTempControllerTestPage.class, "控温系统测试"),
new Menu(PipetteGunHardwareTestPage.class, "移液枪硬件测试"),
new Menu(CodeScannerDriverCtrlPage.class, "扫码枪测试"),
- new Menu(ICCardReaderTestPage.class, "ID卡测试")
+ new Menu(ICCardReaderTestPage.class, "ID卡测试"),
+ new Menu(LISUartTestPage.class, "LIS串口测试"),
+ new Menu(PrinterDebugPage.class, "打印机测试")
+ )),
+
+ new Menu("APP测试", ZList.of(
+ new Menu(LisTestPage.class, "LIS测试"),
+ new Menu(PrinterDebugPage.class, "打印机测试")
)),
new Menu("光学标定与验证", ZList.of(
diff --git a/src/main/java/a8k/extui/page/apptest/LisTestPage.java b/src/main/java/a8k/extui/page/apptest/LisTestPage.java
new file mode 100644
index 0000000..5463bad
--- /dev/null
+++ b/src/main/java/a8k/extui/page/apptest/LisTestPage.java
@@ -0,0 +1,50 @@
+package a8k.extui.page.apptest;
+
+import a8k.app.dao.type.db.ReactionRecord;
+import a8k.app.factory.FakeReactionRecordFactory;
+import a8k.app.service.data.ProjInfoMgrService;
+import a8k.app.service.lis.LisCommunicationService;
+import a8k.app.type.exception.AppException;
+import a8k.extui.mgr.ExtApiPageMgr;
+import a8k.extui.type.ExtApiStatu;
+import a8k.extui.type.ExtUIPageCfg;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.stream.Stream;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class LisTestPage {
+ private final LisCommunicationService lisCommunicationService;
+ private final ProjInfoMgrService projInfoMgrService;
+ private final ExtApiPageMgr extApiPageMgr;
+
+
+ @ExtApiStatu(name = "", group = "LIS协议", order = 1)
+ public String getLisProtocol() {
+ return lisCommunicationService.getProtocolDetail();
+ }
+
+ @ExtApiStatu(name = "", group = "LIS连接状态", order = 2)
+ public Boolean getLisConnection() {
+ return lisCommunicationService.getConnectionState();
+ }
+
+ public void reportFakeData() throws AppException {
+ ReactionRecord record = FakeReactionRecordFactory.buildRecord(projInfoMgrService.getProjBuildInInfo(1));
+ lisCommunicationService.reportReactionRecord(record);
+ }
+
+
+
+ @PostConstruct
+ void init() {
+ ExtUIPageCfg page = new ExtUIPageCfg(this);
+ page.addFunction("上报记录", this::reportFakeData);
+ extApiPageMgr.addPage(page);
+ }
+}
diff --git a/src/main/java/a8k/extui/page/driver/PrinterDebugPage.java b/src/main/java/a8k/extui/page/apptest/PrinterDebugPage.java
similarity index 98%
rename from src/main/java/a8k/extui/page/driver/PrinterDebugPage.java
rename to src/main/java/a8k/extui/page/apptest/PrinterDebugPage.java
index bcb1107..d30b384 100644
--- a/src/main/java/a8k/extui/page/driver/PrinterDebugPage.java
+++ b/src/main/java/a8k/extui/page/apptest/PrinterDebugPage.java
@@ -1,4 +1,4 @@
-package a8k.extui.page.driver;
+package a8k.extui.page.apptest;
import a8k.OS;
import a8k.app.channel.iflytophald.channel.PrinterUartChannel;
diff --git a/src/main/java/a8k/extui/page/extapp/debug_assistant/FakeReactionRecordGeneratorPage.java b/src/main/java/a8k/extui/page/extapp/debug_assistant/FakeReactionRecordGeneratorPage.java
index 8b111f3..82d1f9c 100644
--- a/src/main/java/a8k/extui/page/extapp/debug_assistant/FakeReactionRecordGeneratorPage.java
+++ b/src/main/java/a8k/extui/page/extapp/debug_assistant/FakeReactionRecordGeneratorPage.java
@@ -76,11 +76,11 @@ public class FakeReactionRecordGeneratorPage {
if (!error) {
for (int i = 0; i < projInfo.buildIn.getSubProjNum(); i++) {
if (i == 0)
- reactionResults.add(new ReactionRecord.ReactionResult("Tn-I", "Tn-I", A8kOptType.FOPT,1.0, resultBuilder0.toResultUnitConverters()));
+ reactionResults.add(new ReactionRecord.ReactionResult("Tn-I", "Tn-I", A8kOptType.FOPT,9999.99, resultBuilder0.toResultUnitConverters()));
if (i == 1)
- reactionResults.add(new ReactionRecord.ReactionResult("CK-MB", "CK-MB", A8kOptType.FOPT,2.0, resultBuilder1.toResultUnitConverters()));
+ reactionResults.add(new ReactionRecord.ReactionResult("CK-MB", "CK-MB", A8kOptType.FOPT,9999.99, resultBuilder1.toResultUnitConverters()));
if (i == 2)
- reactionResults.add(new ReactionRecord.ReactionResult("Myoglobin", "MG", A8kOptType.FOPT,3.0, resultBuilder2.toResultUnitConverters()));
+ reactionResults.add(new ReactionRecord.ReactionResult("Myoglobin", "MG", A8kOptType.FOPT,9999.99, resultBuilder2.toResultUnitConverters()));
}
} else {
for (int i = 0; i < projInfo.buildIn.getSubProjNum(); i++) {
diff --git a/src/main/java/a8k/extui/page/hardwaretest/LISUartTestPage.java b/src/main/java/a8k/extui/page/hardwaretest/LISUartTestPage.java
new file mode 100644
index 0000000..f4e2b9d
--- /dev/null
+++ b/src/main/java/a8k/extui/page/hardwaretest/LISUartTestPage.java
@@ -0,0 +1,49 @@
+package a8k.extui.page.hardwaretest;
+
+import a8k.app.channel.iflytophald.channel.LisUartChannel;
+import a8k.app.type.lis.LISSerialBaudrateType;
+import a8k.extui.mgr.ExtApiPageMgr;
+import a8k.extui.type.ExtApiStatu;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class LISUartTestPage {
+ final private LisUartChannel lisUartChannel;
+ private final ExtApiPageMgr extApiPageMgr;
+
+ @ExtApiStatu(name = "", group = "波特率", order = 1)
+ public Integer getBaudRate() {
+ return lisUartChannel.getBaudRateDirect();
+ }
+
+ @ExtApiStatu(name = "", group = "回环模式", order = 1)
+ public Boolean getLoopbackMode() {
+ return lisUartChannel.isInLoopbackMode();
+ }
+
+ public void setBaudRate(LISSerialBaudrateType baudRate) {
+ lisUartChannel.setBaudRate(baudRate.baudrate);
+ }
+
+
+ public void setInLoopbackMode(Boolean val) {
+ lisUartChannel.setInLoopbackMode(val);
+ }
+
+ public void sendCommand(String msg) {
+ lisUartChannel.tx(msg);
+ }
+
+ @PostConstruct
+ public void init() {
+ var page = extApiPageMgr.newPage(this);
+ page.addFunction("设置波特率", this::setBaudRate);
+ page.addFunction("设置环回模式", this::setInLoopbackMode);
+ page.addFunction("发送命令", this::sendCommand);
+ extApiPageMgr.addPage(page);
+ }
+
+}
diff --git a/src/main/java/a8k/iflyutils/IftIpUtils.java b/src/main/java/a8k/iflyutils/IftIpUtils.java
new file mode 100644
index 0000000..79cd2b7
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/IftIpUtils.java
@@ -0,0 +1,57 @@
+package a8k.iflyutils;
+
+import a8k.iflyutils.netplan.exception.NetSettingIllegalException;
+
+public class IftIpUtils {
+
+ /**
+ * 将IP地址和子网掩码转换为CIDR表示法
+ * @param ipAddress IP地址
+ * @param netmask 子网掩码
+ * @return ipAddress/netmask的CIDR表示法
+ *
+ * demo:
+ * String ip = IftIpUtils.toCIDR("192.168.8.1", "255.255.255.0");
+ * ip == 192.168.8.1/24
+ *
+ */
+ public static String toCIDR(String ipAddress, String netmask) throws NetSettingIllegalException {
+ // 验证IP和子网掩码格式
+ if (!isValidIp(ipAddress) || !isValidIp(netmask)) {
+ throw new NetSettingIllegalException("无效的IP地址或子网掩码格式");
+ }
+ // 计算子网掩码对应的前缀长度
+ int prefixLength = netmaskToPrefixLength(netmask);
+ return ipAddress + "/" + prefixLength;
+ }
+
+ public static boolean isValidIp(String ip) {
+ return ip.matches("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
+ }
+
+ public static boolean isValidNetmask(String netmask) {
+ return netmask.matches("^((255|254|252|248|240|224|192|128|0)\\.){3}(255|254|252|248|240|224|192|128|0)$");
+ }
+
+ private static int netmaskToPrefixLength(String netmask) throws NetSettingIllegalException {
+ String[] octets = netmask.split("\\.");
+ int prefixLength = 0;
+
+ for (String octet : octets) {
+ int value = Integer.parseInt(octet);
+ // 检查是否为有效的子网掩码值
+ if (value != 0 && value != 128 && value != 192 && value != 224 &&
+ value != 240 && value != 248 && value != 252 && value != 254 && value != 255) {
+ throw new NetSettingIllegalException("无效的子网掩码");
+ }
+ // 计算前缀长度
+ prefixLength += Integer.bitCount(value);
+ }
+
+ return prefixLength;
+ }
+
+ public static void main(String[] args) {
+ }
+
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/NetplanConfigFactory.java b/src/main/java/a8k/iflyutils/netplan/NetplanConfigFactory.java
new file mode 100644
index 0000000..3265bb3
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/NetplanConfigFactory.java
@@ -0,0 +1,122 @@
+package a8k.iflyutils.netplan;
+
+import a8k.iflyutils.IftIpUtils;
+import a8k.iflyutils.netplan.exception.NetSettingIllegalException;
+import a8k.iflyutils.netplan.type.EthernetConfig;
+import a8k.iflyutils.netplan.type.NetplanConfig;
+import a8k.iflyutils.netplan.type.RendererType;
+import a8k.iflyutils.netplan.type.Route;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+
+public class NetplanConfigFactory {
+ /**
+ *
+ * 调试常用指令
+ * 查看当前dns
+ * cat /run/systemd/resolve/resolv.conf
+ * 应用配置
+ * netplan apply
+ *
+ *
+ */
+
+ RendererType renderer = RendererType.NetworkManager;
+
+
+ public String newDynamicEthernetConfig(String ethName, Boolean autoDns, List dnsList) throws NetSettingIllegalException, JsonProcessingException {
+
+ var mapper = createMapper();
+ Map top = new LinkedHashMap<>();
+
+ NetplanConfig config = new NetplanConfig();
+ config.version = 2;
+ config.renderer = renderer;
+ config.ethernets = new LinkedHashMap<>();
+ {
+ EthernetConfig ethConfig = new EthernetConfig();
+ ethConfig.addresses = null;
+ ethConfig.routes = null;
+ if (autoDns || dnsList == null || dnsList.isEmpty()) {
+ ethConfig.nameservers = null;
+ // ethConfig.accept_ra = true;
+ } else {
+ // ethConfig.accept_ra = false;
+ ethConfig.nameservers.addresses.addAll(dnsList);
+ }
+ ethConfig.dhcp4 = "yes";
+ config.ethernets.put(ethName, ethConfig);
+ }
+
+ top.put("network", config);
+ return mapper.writeValueAsString(top);
+ }
+
+ public String newStaticEthernetConfig(String ethName,
+ String ip,
+ String netmask,
+ String gateway,
+ List dnsList) throws NetSettingIllegalException, JsonProcessingException {
+
+ var mapper = createMapper();
+ Map top = new LinkedHashMap<>();
+
+ NetplanConfig config = new NetplanConfig();
+ config.version = 2;
+ config.renderer = renderer;
+ config.ethernets = new LinkedHashMap<>();
+ {
+ EthernetConfig ethConfig = new EthernetConfig();
+ ethConfig.addresses.add(IftIpUtils.toCIDR(ip, netmask));
+ ethConfig.nameservers.addresses.addAll(dnsList);
+ ethConfig.routes.add(new Route("0.0.0.0/0", gateway));
+ ethConfig.dhcp4 = "no";
+ config.ethernets.put(ethName, ethConfig);
+ }
+
+ top.put("network", config);
+ return mapper.writeValueAsString(top);
+ }
+
+ //
+ // PRIVATE
+ //
+ static private ObjectMapper createMapper() {
+ YAMLFactory yamlFactory = new YAMLFactory()
+ .enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
+ .enable(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE)
+ .enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR)
+ .disable(YAMLGenerator.Feature.INDENT_ARRAYS);
+ ObjectMapper mapper = new ObjectMapper(yamlFactory);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ return mapper;
+ }
+
+
+ public static void main(String[] args) throws NetSettingIllegalException, JsonProcessingException {
+ // 创建YAML映射工厂,配置输出选项
+ // 写入YAML文件
+ NetplanConfigFactory factory = new NetplanConfigFactory();
+ var netplanConfig = factory.newStaticEthernetConfig(
+ "eth1",
+ "192.168.8.10",
+ "255.255.255.0",
+ "192.168.8.1",
+ List.of("192.168.8.1")
+ );
+ System.out.println(netplanConfig);
+ System.out.println("===============================================================");
+ var netDConfig = factory.newDynamicEthernetConfig("eth1", false, List.of("8.8.8.8"));
+ System.out.println(netDConfig);
+
+
+ }
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/exception/NetSettingIllegalException.java b/src/main/java/a8k/iflyutils/netplan/exception/NetSettingIllegalException.java
new file mode 100644
index 0000000..64b4fc7
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/exception/NetSettingIllegalException.java
@@ -0,0 +1,7 @@
+package a8k.iflyutils.netplan.exception;
+
+public class NetSettingIllegalException extends Exception {
+ public NetSettingIllegalException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/type/EthernetConfig.java b/src/main/java/a8k/iflyutils/netplan/type/EthernetConfig.java
new file mode 100644
index 0000000..c82cc01
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/type/EthernetConfig.java
@@ -0,0 +1,15 @@
+package a8k.iflyutils.netplan.type;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EthernetConfig {
+ public List addresses = new ArrayList<>();
+ public Nameservers nameservers = new Nameservers();
+ public List routes = new ArrayList<>();
+ public String dhcp4 = "no";
+// @JsonProperty("accept-ra")
+// public Boolean accept_ra = true;
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/type/Nameservers.java b/src/main/java/a8k/iflyutils/netplan/type/Nameservers.java
new file mode 100644
index 0000000..d063a08
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/type/Nameservers.java
@@ -0,0 +1,8 @@
+package a8k.iflyutils.netplan.type;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Nameservers {
+ public List addresses = new ArrayList<>();
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/type/NetplanConfig.java b/src/main/java/a8k/iflyutils/netplan/type/NetplanConfig.java
new file mode 100644
index 0000000..702b9be
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/type/NetplanConfig.java
@@ -0,0 +1,10 @@
+package a8k.iflyutils.netplan.type;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class NetplanConfig {
+ public int version = 2;
+ public RendererType renderer = RendererType.NetworkManager;
+ public Map ethernets = new LinkedHashMap<>();
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/type/RendererType.java b/src/main/java/a8k/iflyutils/netplan/type/RendererType.java
new file mode 100644
index 0000000..07283dc
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/type/RendererType.java
@@ -0,0 +1,6 @@
+package a8k.iflyutils.netplan.type;
+
+public enum RendererType {
+ networkd,
+ NetworkManager;
+}
diff --git a/src/main/java/a8k/iflyutils/netplan/type/Route.java b/src/main/java/a8k/iflyutils/netplan/type/Route.java
new file mode 100644
index 0000000..fb851be
--- /dev/null
+++ b/src/main/java/a8k/iflyutils/netplan/type/Route.java
@@ -0,0 +1,12 @@
+package a8k.iflyutils.netplan.type;
+
+public class Route {
+ public String to;
+ public String via;
+ public Integer metric = null;
+
+ public Route(String to, String via) {
+ this.to = to;
+ this.via = via;
+ }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 709c708..e5cd703 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -1,17 +1,27 @@
-#server.port: 8082
+#WEB虚拟后端
+#server.port: 80
#iflytophald.ip: 127.0.0.1
+#iflytophald.enable: false
#device.runmode: "VirtualStateGenerateMode"
-#device.enableCanBus: false
+#PC调试
server.port: 80
device.runmode: "RealMode"
iflytophald.ip: 192.168.8.10
-device.enableCanBus: true
+iflytophald.enable: true
+
+#硬件测试
+#server.port: 8082
+#iflytophald.ip: 192.168.8.10
+#device.runmode: "RealMode"
+#iflytophald.enable: true
#server.port: 80
#device.runmode: "RealMode"
#iflytophald.ip: 127.0.0.1
+#iflytophald.enable: true
+
a8k.enableTemperatureCtrl: false