diff --git a/src/main/java/a8k/appbase/appret/AppRet.java b/src/main/java/a8k/appbase/appret/AppRet.java index 1c173e8..5048731 100644 --- a/src/main/java/a8k/appbase/appret/AppRet.java +++ b/src/main/java/a8k/appbase/appret/AppRet.java @@ -56,10 +56,11 @@ public class AppRet { } - public static AppRet message(String message) { + public static AppRet message(String message, T data) { AppRet r = new AppRet<>(); r.appRetType = AppRetType.MESSAGE; r.message = message; + r.dataType = null == data ? null : data.getClass().getSimpleName(); return r; } diff --git a/src/main/java/a8k/service/FrontEndEventRouter.java b/src/main/java/a8k/service/FrontEndEventRouter.java new file mode 100644 index 0000000..090fb2b --- /dev/null +++ b/src/main/java/a8k/service/FrontEndEventRouter.java @@ -0,0 +1,62 @@ +package a8k.service; + +import a8k.appbase.AppEventListener; +import a8k.appbase.appret.AppRet; +import a8k.controler.engineer.utils.EngineerPageTab; +import a8k.controler.engineer.utils.EnginnerPageAction; +import a8k.service.appeventbus.AppEventBusService; +import a8k.service.appeventbus.appevent.A8kHardwareReport; +import a8k.service.appeventbus.appevent.AppEvent; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.springframework.stereotype.Component; + +import java.util.Queue; + +@Component +@EngineerPageTab(name = "FrontEndEventRouter") +public class FrontEndEventRouter implements AppEventListener { + static Logger logger = org.slf4j.LoggerFactory.getLogger(FrontEndEventRouter.class); + + @Resource + AppEventBusService eventBus; + + private final Queue appEventQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); + + + @PostConstruct + public void init() { + eventBus.regListener(this); + } + + public Boolean filterEvent(AppEvent event) { + if (event instanceof A8kHardwareReport) { + return true; + } + return false; + } + + synchronized public AppEvent _pollAppEvent() { + return appEventQueue.poll(); + } + + @Override public void onAppEvent(AppEvent event) { + if (filterEvent(event)) { + return; + } + + appEventQueue.add(event); + if (appEventQueue.size() >= 10) { + logger.warn("too many events in queue, drop some"); + _pollAppEvent(); + } + } + + @EnginnerPageAction(name = "pollAppEvent") + public AppRet pollAppEvent() { + AppEvent event = _pollAppEvent(); + return AppRet.success(event); + } + +} diff --git a/src/main/java/a8k/service/UIEventProcesser.java b/src/main/java/a8k/service/UIEventProcesser.java deleted file mode 100644 index 2a1d0ca..0000000 --- a/src/main/java/a8k/service/UIEventProcesser.java +++ /dev/null @@ -1,4 +0,0 @@ -package a8k.service; - -public class UIEventProcesser { -} diff --git a/src/main/java/a8k/service/appeventbus/appevent/AppEvent.java b/src/main/java/a8k/service/appeventbus/appevent/AppEvent.java index df79f58..846e1ef 100644 --- a/src/main/java/a8k/service/appeventbus/appevent/AppEvent.java +++ b/src/main/java/a8k/service/appeventbus/appevent/AppEvent.java @@ -1,8 +1,8 @@ package a8k.service.appeventbus.appevent; public class AppEvent { - public String name; - public AppEvent(String name) { - this.name = name; + public String typeName; + public AppEvent(String typeName) { + this.typeName = typeName; } } diff --git a/src/main/java/a8k/service/appeventbus/appevent/NewAppIDCardDetectEvent.java b/src/main/java/a8k/service/appeventbus/appevent/NewAppIDCardDetectEvent.java new file mode 100644 index 0000000..f9a7ad8 --- /dev/null +++ b/src/main/java/a8k/service/appeventbus/appevent/NewAppIDCardDetectEvent.java @@ -0,0 +1,26 @@ +package a8k.service.appeventbus.appevent; + +import a8k.db.ProjectInfo; + +public class NewAppIDCardDetectEvent extends AppEvent { + Boolean newIdCardInfo; + ProjectInfo projectInfo; + + public NewAppIDCardDetectEvent() { + super(NewAppIDCardDetectEvent.class.getSimpleName()); + } + + public NewAppIDCardDetectEvent(Boolean newIdCardInfo, ProjectInfo projectInfo) { + super(NewAppIDCardDetectEvent.class.getSimpleName()); + this.newIdCardInfo = newIdCardInfo; + this.projectInfo = projectInfo; + } + + public Boolean getNewIdCardInfo() { + return newIdCardInfo; + } + + public ProjectInfo getProjectInfo() { + return projectInfo; + } +} diff --git a/src/main/java/a8k/service/hardware/canbus/A8kCanBusService.java b/src/main/java/a8k/service/hardware/canbus/A8kCanBusService.java index ee239fe..06586ea 100644 --- a/src/main/java/a8k/service/hardware/canbus/A8kCanBusService.java +++ b/src/main/java/a8k/service/hardware/canbus/A8kCanBusService.java @@ -165,29 +165,19 @@ public class A8kCanBusService { } - // virtual int32_t pipette_ctrl_move_to_ul(int32_t ul) override; // 丢弃 - // - // virtual int32_t pipette_ctrl_init_device() override; - // virtual int32_t pipette_ctrl_put_tip() override; - // virtual int32_t pipette_lld_prepare() override; - // virtual int32_t pipette_plld(int32_t zdpos, int32_t p_threshold) override; - // virtual int32_t pipette_clld(int32_t zdpos, int32_t c_threshold) override; - // virtual int32_t pipette_mlld(int32_t zdpos, int32_t c_threshold, int32_t p_threshold) override; - // virtual int32_t pipette_lld_is_detect_liquid(int32_t *liquid) override; - // - // virtual int32_t pipette_aspirate(int32_t ul) override; - // virtual int32_t pipette_distribut(int32_t ul) override; - // virtual int32_t pipette_shake_up(int32_t ul, int32_t times) override; - // - // virtual int32_t pipette_aspirate_llf(int32_t ul, int32_t zmotor_v) override; - // virtual int32_t pipette_distribut_llf(int32_t ul, int32_t zmotor_v) override; - // virtual int32_t pipette_shake_up_llf(int32_t ul, int32_t zmotor_v, int32_t times) override; - // - // virtual int32_t pipette_enable_zmotor(int32_t enable); - // virtual int32_t pipette_write_cmd_direct(uint8_t *tx, int32_t len, uint8_t *rx, int32_t *rxlen) override; - // virtual int32_t pipette_get_sensor_sample_data(int32_t index, int32_t *motor_pos, int32_t *cval, int32_t *pval) override; // - // virtual int32_t pipette_get_sensor_sample_data_num(int32_t *num) override; - // + public byte[] a8kIdcardReaderReadRaw() throws HardwareException { + int i = 0; + byte[] result = new byte[0]; + while (true) { + var rxPacket = callcmd(MId.A8kIdCardReader.toInt(), CmdId.a8000_idcard_reader_read_raw.toInt(), i++); + if (rxPacket.getCmdContent().length == 0) { + break; + } + result = ByteArray.concat(result, rxPacket.getCmdContent()); + } + return result; + } + public void pipetteCtrlInitDevice(MId id) throws HardwareException { callcmd(id.toInt(), CmdId.pipette_ctrl_init_device.toInt()); @@ -688,9 +678,9 @@ public class A8kCanBusService { while (true) { Boolean firstReadIO = priGetIOState(ioid); Boolean secondReadIO = priGetIOState(ioid); - if(firstReadIO == secondReadIO){ + if (firstReadIO == secondReadIO) { return firstReadIO; - }else{ + } else { logger.warn("getIOState {} not match, retry", ioid); } } diff --git a/src/main/java/a8k/service/hardware/canbus/protocol/CmdId.java b/src/main/java/a8k/service/hardware/canbus/protocol/CmdId.java index 7451ac6..f712e4a 100644 --- a/src/main/java/a8k/service/hardware/canbus/protocol/CmdId.java +++ b/src/main/java/a8k/service/hardware/canbus/protocol/CmdId.java @@ -111,8 +111,8 @@ public enum CmdId { temp_controler_set_fan_level(0x7004, "TEMP_CONTROLER_SET_FAN_LEVEL"),// temp_controler_enable_log(0x7005, "TEMP_CONTROLER_ENABLE_LOG"),// // - a8000_idcard_reader_read_raw(0x7100, "A8000_IDCARD_READER_READ_RAW", CmdId.ATTACH_IS_INT32, CmdId.ATTACH_IS_BYTES),// - a8000_idcard_write_raw(0x7101, "A8000_IDCARD_WRITE_RAW", CmdId.ATTACH_IS_BYTES, CmdId.ATTACH_IS_INT32),// + a8000_idcard_reader_read_raw(0x7100, "A8000_IDCARD_READER_READ_RAW", CmdId.ATTACH_IS_INT32, CmdId.ATTACH_IS_BYTES,false),// + a8000_idcard_write_raw(0x7101, "A8000_IDCARD_WRITE_RAW", CmdId.ATTACH_IS_BYTES, CmdId.ATTACH_IS_INT32,false),// a8000_idcard_erase(0x7102, "A8000_IDCARD_ERASE"),// a8000_idcard_earse_unlock(0x7103, "A8000_IDCARD_EARSE_UNLOCK"),// // diff --git a/src/main/java/a8k/service/project_mgr/ProjectItemMgrService.java b/src/main/java/a8k/service/project_mgr/ProjectItemMgrService.java index b6cd44c..f8c506e 100644 --- a/src/main/java/a8k/service/project_mgr/ProjectItemMgrService.java +++ b/src/main/java/a8k/service/project_mgr/ProjectItemMgrService.java @@ -2,6 +2,7 @@ package a8k.service.project_mgr; import a8k.appbase.AppEventListener; +import a8k.appbase.HardwareException; import a8k.appbase.ProjectInfoSimple; import a8k.appbase.appret.AppRet; import a8k.controler.engineer.utils.EngineerPageTab; @@ -13,6 +14,7 @@ import a8k.service.appeventbus.appevent.AppEvent; import a8k.service.hardware.canbus.A8kCanBusService; import a8k.service.hardware.canbus.protocol.A8kPacket; import a8k.service.hardware.canbus.protocol.CmdId; +import a8k.utils.wq.ZWorkQueue; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.slf4j.Logger; @@ -33,9 +35,11 @@ public class ProjectItemMgrService implements AppEventListener { @Resource AppEventBusService eventBus; + ZWorkQueue workQueue = new ZWorkQueue(2, 1); + @PostConstruct public void init() { - + eventBus.regListener(this); } @Override public void onAppEvent(AppEvent event) { @@ -44,10 +48,10 @@ public class ProjectItemMgrService implements AppEventListener { CmdId cmdId = CmdId.valueOf(packet.getCmdId()); if (CmdId.event_a8000_idcard_online.equals(cmdId)) { logger.info("插入ID卡"); + workQueue.addTask(this::readIDCard); } else if (CmdId.event_a8000_idcard_offline.equals(cmdId)) { logger.info("拔出ID卡"); } - } } @@ -64,13 +68,50 @@ public class ProjectItemMgrService implements AppEventListener { return result; } + Boolean isNewProjectInfo(ProjectInfo newpinfo) { + var pinfo = ProjectInfo.findOne(ProjectInfo.class, Map.of("lotName", newpinfo.lotName)); + return pinfo == null || newpinfo.updateChipVersion >= pinfo.updateChipVersion; + } - @EnginnerPageAction(name = "获取项目信息(简单)") - public AppRet> getProjectInfoSimple() { - return AppRet.success(dbGetProjectInfos()); + void readIDCard() { + //读取ID卡信息 + byte[] data = null; + try { + data = canBus.a8kIdcardReaderReadRaw(); + logger.info("ID卡信息:{}", data); + //TODO: + // 解析ID + // 构造ProjectInfo + // 判断是否是新的ProjectInfo (by call isNewProjectInfo) + // 构造NewAppIDCardDetectEvent + // 发送事件到事件总线上去,事件将由 FrontEndEventRouter 路由到前端 + // + } catch (HardwareException e) { + throw new RuntimeException(e); + } } + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // PUBLIC + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @EnginnerPageAction(name = "获取项目信息(简单)") + public AppRet> getProjectInfoSimple() { + return AppRet.success(dbGetProjectInfos()); + } + @EnginnerPageAction(name = "插入项目信息") + public AppRet InsertProjectInfo(ProjectInfo newpinfo) { + var pinfo = ProjectInfo.findOne(ProjectInfo.class, Map.of("lotName", newpinfo.lotName)); + if (pinfo != null && newpinfo.updateChipVersion < pinfo.updateChipVersion) { + return AppRet.message("新项目版本低于数据库中的项目版本,不更新",""); + } else { + if (pinfo != null) { + pinfo.delete(); + } + newpinfo.save(); + } + return AppRet.message("插入成功",""); + } } diff --git a/src/main/java/a8k/utils/ByteArray.java b/src/main/java/a8k/utils/ByteArray.java index 3892f65..0427dc3 100644 --- a/src/main/java/a8k/utils/ByteArray.java +++ b/src/main/java/a8k/utils/ByteArray.java @@ -97,6 +97,23 @@ public class ByteArray { } } + + public static byte[] concat(byte[]... arrays) { + int length = 0; + for (byte[] array : arrays) { + length += array.length; + } + + byte[] result = new byte[length]; + int destPos = 0; + for (byte[] array : arrays) { + System.arraycopy(array, 0, result, destPos, array.length); + destPos += array.length; + } + + return result; + } + // public static void main(String[] args) { // byte[] bytes = new byte[]{0x01, 0x02, 0x03, 0x04}; // System.out.println(toByteString(bytes)); diff --git a/src/main/java/a8k/utils/wq/ZWorkQueue.java b/src/main/java/a8k/utils/wq/ZWorkQueue.java new file mode 100644 index 0000000..f549b3e --- /dev/null +++ b/src/main/java/a8k/utils/wq/ZWorkQueue.java @@ -0,0 +1,56 @@ +package a8k.utils.wq; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ZWorkQueue { + static final Logger logger = LoggerFactory.getLogger(ZWorkQueue.class); + + private final LinkedBlockingQueue workQueue; + private final ExecutorService executor; + + int threadPoolSize; + + public ZWorkQueue(int queueSize, int threadPoolSize) { + workQueue = new LinkedBlockingQueue<>(queueSize); + executor = Executors.newFixedThreadPool(threadPoolSize); + this.threadPoolSize = threadPoolSize; + // 启动消费者线程 + startWorkerThreads(); + } + + private void startWorkerThreads() { + for (int i = 0; i < threadPoolSize; i++) { + executor.submit(() -> { + while (!Thread.currentThread().isInterrupted()) { + try { + // 从队列中获取任务 + Runnable task = workQueue.take(); + task.run(); + } catch (InterruptedException ignored) { + } catch (Exception e) { + logger.error("Error while running task", e); + } + } + }); + } + } + + public void addTask(Runnable task) { + try { + // 将任务添加到队列中 + workQueue.put(task); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + public void shutdown() { + // 关闭线程池 + executor.shutdown(); + } +} \ No newline at end of file