diff --git a/src/main/java/a8k/OS.java b/src/main/java/a8k/OS.java index 8181dad..f4bfca3 100644 --- a/src/main/java/a8k/OS.java +++ b/src/main/java/a8k/OS.java @@ -1,5 +1,6 @@ package a8k; +import cn.hutool.core.io.FileUtil; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -56,6 +57,7 @@ public class OS { return os.contains("windows"); } + public static LinuxCommandResult executeLinuxCommand(String command, long timeout, TimeUnit unit) throws IOException, InterruptedException { if (isRunOnWindows()) { @@ -129,7 +131,8 @@ public class OS { } public static void main(String[] args) { - System.out.println("LOCAL IP: " + OS.getLocalIp()); + // System.out.println("LOCAL IP: " + OS.getLocalIp()); + // System.out.println("LOCAL IP: " + OS.readSN()); } } diff --git a/src/main/java/a8k/app/channel/iflytophald/type/protocol/OutputIOId.java b/src/main/java/a8k/app/channel/iflytophald/type/protocol/OutputIOId.java index 58b5d04..e65756e 100644 --- a/src/main/java/a8k/app/channel/iflytophald/type/protocol/OutputIOId.java +++ b/src/main/java/a8k/app/channel/iflytophald/type/protocol/OutputIOId.java @@ -1,7 +1,8 @@ package a8k.app.channel.iflytophald.type.protocol; public enum OutputIOId { - RecycleBinOverflowPPSPowerCtrl("废料仓-光栅电源",ModuleType.Board, MId.PlatesBoxTCMBoard, 0,false),//废料桶光栅电源 + RecycleBinOverflowPPSPowerCtrl("废料仓-光栅电源", ModuleType.Board, MId.PlatesBoxTCMBoard, 0, false),//废料桶光栅电源 + BeepCtrl("蜂鸣器", ModuleType.Board, MId.IncubatorTCMBoard, 0, false),//蜂鸣器 ; final public String chname; diff --git a/src/main/java/a8k/app/constant/AppVersion.java b/src/main/java/a8k/app/constant/AppVersion.java index 2ce2257..f0e1784 100644 --- a/src/main/java/a8k/app/constant/AppVersion.java +++ b/src/main/java/a8k/app/constant/AppVersion.java @@ -1,5 +1,5 @@ package a8k.app.constant; public class AppVersion { - public static final String APP_VERSION = "1.0.1"; + public static final String APP_VERSION = "1.0.3"; } diff --git a/src/main/java/a8k/app/controler/api/v1/app/ctrl/OsCtrlControler.java b/src/main/java/a8k/app/controler/api/v1/app/ctrl/OsCtrlControler.java index 0744478..ba1033d 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/ctrl/OsCtrlControler.java +++ b/src/main/java/a8k/app/controler/api/v1/app/ctrl/OsCtrlControler.java @@ -1,7 +1,8 @@ package a8k.app.controler.api.v1.app.ctrl; import a8k.OS; -import a8k.app.service.peripheral_ctrl.BeepCtrlService; +import a8k.app.service.os.OSBeepCtrlService; +import a8k.app.service.os.OSDeviceInfoMgrService; import a8k.app.type.exception.AppException; import a8k.app.channel.iflytophald.type.protocol.A8kEcode; import a8k.app.service.statemgr.DeviceWorkStateMgrService; @@ -26,6 +27,7 @@ public class OsCtrlControler { static public class OsInfoPack { public String ip; public String sn; + public String assetId; public String appVersion; public String mcuVersion; } @@ -33,7 +35,8 @@ public class OsCtrlControler { private final GStateMgrService gstate; private final DeviceWorkStateMgrService deviceWorkStateMgrService; - private final BeepCtrlService beepCtrlService; + private final OSBeepCtrlService beepCtrlService; + private final OSDeviceInfoMgrService osDeviceInfoMgrService; /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * 系统控制 @@ -45,6 +48,8 @@ public class OsCtrlControler { appVersion = gstate.getAppVersion(); mcuVersion = gstate.getMcuVersion(); sn = gstate.getSn(); + assetId = gstate.getAssetId(); + ip = OS.getLocalIp(); }}); } @@ -65,21 +70,22 @@ public class OsCtrlControler { @Operation(summary = "打开蜂鸣器") @PostMapping("/startBeepWarning") public ApiRet startBeepWarning() { - beepCtrlService.startBeepWarning(); + beepCtrlService.triggerBeep(); return ApiRet.success(); } @Operation(summary = "关闭蜂鸣器") @PostMapping("/stopBeepWarning") public ApiRet stopBeepWarning() { - beepCtrlService.stopBeepWarning(); + beepCtrlService.stopBeep(); return ApiRet.success(); } @Operation(summary = "获取蜂鸣器状态") @PostMapping("/getBeepWarningStatus") public ApiRet getBeepWarningStatus() { - return ApiRet.success(beepCtrlService.isBeepWarning()); + return ApiRet.success(beepCtrlService.getBeepState()); } + } diff --git a/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceInfoControler.java b/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceInfoControler.java index 2d68728..3805555 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceInfoControler.java +++ b/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceInfoControler.java @@ -1,10 +1,13 @@ package a8k.app.controler.api.v1.app.setting; +import a8k.app.service.os.OSDeviceInfoMgrService; +import a8k.app.type.exception.AppException; import a8k.app.type.ui.ApiRet; import a8k.app.service.statemgr.GStateMgrService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; @@ -17,15 +20,18 @@ import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value = "/api/v1/app/DeviceInfo/") @ResponseBody +@RequiredArgsConstructor public class DeviceInfoControler { @Resource GStateMgrService gstate; + private final OSDeviceInfoMgrService osDeviceInfoMgrService; + public static class DeviceInfo { public String appVersion; public String mcuVersion; public String sn; - public String factorySN; + public String assetId; public String ip; } @@ -36,7 +42,7 @@ public class DeviceInfoControler { info.appVersion = gstate.getAppVersion(); info.mcuVersion = gstate.getMcuVersion(); info.sn = gstate.getSn(); - info.factorySN = gstate.getFactorySn(); + info.assetId = gstate.getAssetId(); info.ip = gstate.getLocalIp(); return ApiRet.success(info); } @@ -60,4 +66,15 @@ public class DeviceInfoControler { return ApiRet.success(gstate.getLocalIp()); } + @Operation(summary = "设置SN") + @PostMapping("/setSN") + public ApiRet setSN(String sn) throws AppException { + return ApiRet.success(osDeviceInfoMgrService.setSN(sn)); + } + + @Operation(summary = "设置ASSET_ID") + @PostMapping("/setAssetId") + public ApiRet setAssetId(String assetId) throws AppException { + return ApiRet.success(osDeviceInfoMgrService.setAssetId(assetId)); + } } diff --git a/src/main/java/a8k/app/service/appsetup/AppEnvInitializer.java b/src/main/java/a8k/app/service/appsetup/AppEnvInitializer.java new file mode 100644 index 0000000..0b27145 --- /dev/null +++ b/src/main/java/a8k/app/service/appsetup/AppEnvInitializer.java @@ -0,0 +1,27 @@ +package a8k.app.service.appsetup; + +import a8k.OS; +import a8k.app.service.os.OSDeviceInfoMgrService; +import a8k.app.service.statemgr.GStateMgrService; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +public class AppEnvInitializer { + private final GStateMgrService gStateMgrService; + private final OSDeviceInfoMgrService osDeviceInfoMgrService; + + @PostConstruct + void init() { + log.info("AppEnvInitializer init"); + gStateMgrService.setSn(osDeviceInfoMgrService.readSN()); + gStateMgrService.setAssetId(osDeviceInfoMgrService.readAssetId()); + gStateMgrService.setDeviceInited(false); + // 其他初始化逻辑 + log.info("AppEnvInitializer init completed"); + } +} diff --git a/src/main/java/a8k/app/service/os/OSBeepCtrlService.java b/src/main/java/a8k/app/service/os/OSBeepCtrlService.java new file mode 100644 index 0000000..3605883 --- /dev/null +++ b/src/main/java/a8k/app/service/os/OSBeepCtrlService.java @@ -0,0 +1,116 @@ +package a8k.app.service.os; + +import a8k.OS; +import a8k.app.channel.iflytophald.channel.A8kCanBusService; +import a8k.app.channel.iflytophald.driver.OutputIOCtrlDriver; +import a8k.app.channel.iflytophald.type.protocol.OutputIOId; +import a8k.app.service.statemgr.GStateMgrService; +import a8k.app.teststate.VirtualDevice; +import a8k.app.type.exception.AppException; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class OSBeepCtrlService { + + + private final A8kCanBusService a8kCanBusService; + boolean beepState = false;//beep底层状态 + boolean beepStateIsSync = false;//底层状态是否同步 + boolean hardwareErrorFlag = false;//硬件错误标志 + + Boolean beepTrigger = false; // 蜂鸣器是否启用 + Thread beepThread = new Thread(this::beepLoopThread); + + + private final OutputIOCtrlDriver outputIOCtrlDriver; + private final GStateMgrService gStateMgrService; + private final VirtualDevice virtualDevice; + + public synchronized void triggerBeep() { + beepTrigger = true; + log.info("触发蜂鸣器"); + } + + public synchronized void stopBeep() { + beepTrigger = false; + log.info("停止蜂鸣器"); + beepThread.interrupt(); + } + + public synchronized boolean getBeepState() { + return beepTrigger; + } + + private void beepLoopThread() { + while (true) { + if (hardwareErrorFlag) { + OS.forceSleep(3000); + } else { + OS.forceSleep(100); + } + + if (!a8kCanBusService.isConnect()) { + OS.forceSleep(1000); + continue; + } + + if (!beepStateIsSync) { + setBeepState(beepState); + } + + + if (beepTrigger) { + setBeepState(true); + sleep(10); + setBeepState(false); + + sleep(300); + + setBeepState(true); + sleep(10); + setBeepState(false); + + sleep(1000); + } else { + if (beepState) { + setBeepState(false); + } + } + } + } + + private void sleep(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ignored) { + } + } + + private void setBeepState(Boolean state) { + beepState = state; + log.info("设置蜂鸣器状态: {}", state); + if (virtualDevice.isEnable()) { + log.info("虚拟设备模式下,蜂鸣器状态设置为: {}", state); + return; + } + + try { + outputIOCtrlDriver.setIOState(OutputIOId.BeepCtrl, state); + beepStateIsSync = true; + hardwareErrorFlag = false; + } catch (AppException e) { + beepStateIsSync = false; + hardwareErrorFlag = true; + } + } + + @PostConstruct + void init() { + beepThread.start(); + } +} diff --git a/src/main/java/a8k/app/service/os/OSDeviceInfoMgrService.java b/src/main/java/a8k/app/service/os/OSDeviceInfoMgrService.java new file mode 100644 index 0000000..10197c3 --- /dev/null +++ b/src/main/java/a8k/app/service/os/OSDeviceInfoMgrService.java @@ -0,0 +1,96 @@ +package a8k.app.service.os; + +import a8k.OS; +import a8k.app.channel.iflytophald.type.protocol.A8kEcode; +import a8k.app.service.statemgr.GStateMgrService; +import a8k.app.type.exception.AppException; +import cn.hutool.core.io.FileUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RequiredArgsConstructor +@EnableScheduling +public class OSDeviceInfoMgrService { + /** + * + * 设备ID设置与读取 + * + * 编码参考: + * https://iflytop1.feishu.cn/wiki/L1n0wKWDtiBTC3kLLjycjvD8nib?fromScene=spaceOverview + */ + + private final GStateMgrService gStateMgrService; + + String snOnWindows = "W-SN-00001"; + String assetIdOnWindows = "W-AId-00001"; + + + public String readSN() { + if (OS.isRunOnWindows()) { + return snOnWindows; + } + try { + return FileUtil.readUtf8String("/iflytop/env/sn"); + } catch (Exception e) { + log.error("读取SN失败: {}", e.getMessage()); + return "error"; + } + } + + public String readAssetId() { + if (OS.isRunOnWindows()) { + return assetIdOnWindows; + } + try { + return FileUtil.readUtf8String("/iflytop/env/assetId"); + } catch (Exception e) { + log.error("读取AssetId失败: {}", e.getMessage()); + return "error"; + } + } + + public String setSN(String sn) throws AppException { + if (sn == null || sn.isEmpty()) { + throw AppException.of(A8kEcode.CODEERROR, "SN不能为空"); + } + if (OS.isRunOnWindows()) { + snOnWindows = sn; + gStateMgrService.setSn(snOnWindows); + return snOnWindows; + } else { + try { + FileUtil.writeUtf8String(sn, "/iflytop/env/sn"); + gStateMgrService.setSn(sn); + return sn; + } catch (Exception e) { + throw AppException.of(A8kEcode.CODEERROR, e.getMessage()); + } + } + + } + + public String setAssetId(String assetId) throws AppException { + if (assetId == null || assetId.isEmpty()) { + throw AppException.of(A8kEcode.CODEERROR, "AssetId不能为空"); + } + if (OS.isRunOnWindows()) { + assetIdOnWindows = assetId; + gStateMgrService.setAssetId(assetIdOnWindows); + return assetIdOnWindows; + } else { + try { + FileUtil.writeUtf8String(assetId, "/iflytop/env/assetId"); + gStateMgrService.setSn(assetId); + return assetId; + } catch (Exception e) { + throw AppException.of(A8kEcode.CODEERROR, e.getMessage()); + } + } + + } + +} diff --git a/src/main/java/a8k/app/service/peripheral_ctrl/BeepCtrlService.java b/src/main/java/a8k/app/service/peripheral_ctrl/BeepCtrlService.java deleted file mode 100644 index b800002..0000000 --- a/src/main/java/a8k/app/service/peripheral_ctrl/BeepCtrlService.java +++ /dev/null @@ -1,27 +0,0 @@ -package a8k.app.service.peripheral_ctrl; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -@RequiredArgsConstructor -public class BeepCtrlService { - Boolean beepWarning = true; // 假设蜂鸣器默认开启状态 - - public void startBeepWarning() { - log.info("打开蜂鸣器"); - beepWarning = true; - } - - public void stopBeepWarning() { - log.info("关闭蜂鸣器"); - beepWarning = false; - - } - - public Boolean isBeepWarning() { - return beepWarning; // 假设蜂鸣器总是开启状态 - } -} diff --git a/src/main/java/a8k/app/service/statemgr/GStateMgrService.java b/src/main/java/a8k/app/service/statemgr/GStateMgrService.java index 52e7a7e..60078bc 100644 --- a/src/main/java/a8k/app/service/statemgr/GStateMgrService.java +++ b/src/main/java/a8k/app/service/statemgr/GStateMgrService.java @@ -98,8 +98,12 @@ public class GStateMgrService { this.gState.sn = sn; } - public synchronized String getFactorySn() { - return this.gState.factorySN; + public synchronized String getAssetId() { + return this.gState.assetId; + } + + public synchronized void setAssetId(String assetId) { + this.gState.assetId = assetId; } public synchronized Boolean isInMode(DeviceRunMode... modes) { @@ -140,6 +144,13 @@ public class GStateMgrService { return this.gState.localIP; } + synchronized public void setAppEnvInited() { + this.gState.appEnvInited = true; + } + + synchronized public boolean isAppEnvInited() { + return this.gState.appEnvInited; + } @PostConstruct public void init() { diff --git a/src/main/java/a8k/app/type/GState.java b/src/main/java/a8k/app/type/GState.java index 3459506..b086dd5 100644 --- a/src/main/java/a8k/app/type/GState.java +++ b/src/main/java/a8k/app/type/GState.java @@ -25,7 +25,7 @@ public class GState { //设备SN public String sn = "TEST001";// // - public String factorySN = "TEST001";// + public String assetId = "TEST001";// 资产ID // public Boolean fatalError = false; // @@ -34,4 +34,10 @@ public class GState { public String localIP = "";//设备IP public SensorState sensorState = new SensorState(); + + /** + * 该变量,由AppEnvInitializer初始化完成后设置为true + * 主要负责初始化一些全局的配置和环境变量 + */ + public boolean appEnvInited = false; //应用环境是否初始化完成 } diff --git a/src/main/java/a8k/extui/page/driver/OutputIOCtrlDebugPage.java b/src/main/java/a8k/extui/page/driver/OutputIOCtrlDebugPage.java deleted file mode 100644 index ff35eae..0000000 --- a/src/main/java/a8k/extui/page/driver/OutputIOCtrlDebugPage.java +++ /dev/null @@ -1,28 +0,0 @@ -package a8k.extui.page.driver; - -import a8k.app.type.exception.AppException; -import a8k.app.channel.iflytophald.driver.OutputIOCtrlDriver; -import a8k.app.channel.iflytophald.type.protocol.OutputIOId; -import a8k.extui.mgr.ExtApiPageMgr; -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class OutputIOCtrlDebugPage { - final private ExtApiPageMgr extApiPageMgr; - final private OutputIOCtrlDriver outputIOCtrlDriver; - - - public void setIOState(Boolean state) throws AppException { - outputIOCtrlDriver.setIOState(OutputIOId.RecycleBinOverflowPPSPowerCtrl, state); - } - - @PostConstruct - void init() { - var page = extApiPageMgr.newPage(this); - page.addFunction("废料仓光栅控制", this::setIOState).setParamVal("state", ()->true); - extApiPageMgr.addPage(page); - } -} diff --git a/src/main/java/a8k/extui/page/hardwaretest/OutputIOCtrlTestPage.java b/src/main/java/a8k/extui/page/hardwaretest/OutputIOCtrlTestPage.java index 09d6e14..5edc5f9 100644 --- a/src/main/java/a8k/extui/page/hardwaretest/OutputIOCtrlTestPage.java +++ b/src/main/java/a8k/extui/page/hardwaretest/OutputIOCtrlTestPage.java @@ -14,15 +14,19 @@ public class OutputIOCtrlTestPage { final private ExtApiPageMgr extApiPageMgr; final private OutputIOCtrlDriver outputIOCtrlDriver; - - public void setIOState(Boolean state) throws AppException { + public void setRecycleBinOverflowPPSPowerCtrlIOState(Boolean state) throws AppException { outputIOCtrlDriver.setIOState(OutputIOId.RecycleBinOverflowPPSPowerCtrl, state); } + public void setBeepCtrlIOState(Boolean state) throws AppException { + outputIOCtrlDriver.setIOState(OutputIOId.BeepCtrl, state); + } + @PostConstruct void init() { var page = extApiPageMgr.newPage(this); - page.addFunction("废料仓光栅控制", this::setIOState).setParamVal("state", ()->true); + page.addFunction("废料仓光栅控制", this::setRecycleBinOverflowPPSPowerCtrlIOState).setParamVal("state", () -> true); + page.addFunction("蜂鸣器控制", this::setBeepCtrlIOState).setParamVal("state", () -> true); extApiPageMgr.addPage(page); } }