| | |
| | | import com.zy.core.network.fake.ZyStationV4FakeSegConnect; |
| | | import com.zy.core.network.real.ZyStationRealConnect; |
| | | import com.zy.core.network.real.ZyStationV3RealConnect; |
| | | import com.zy.core.network.real.ZyStationV4RealConnect; |
| | | import com.zy.core.network.real.ZyStationV5RealConnect; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import java.util.Collections; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.ThreadFactory; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.UUID; |
| | | |
| | | /** |
| | | * 输送站连接驱动 |
| | |
| | | |
| | | private static final ZyStationFakeSegConnect zyStationFakeSegConnect = new ZyStationFakeSegConnect(); |
| | | private static final ZyStationV4FakeSegConnect zyStationV4FakeSegConnect = new ZyStationV4FakeSegConnect(); |
| | | private static final long SEND_LOCK_WARN_MS = 500L; |
| | | private static final long SEND_COST_WARN_MS = 5_000L; |
| | | private static final long SEND_LOCK_POLL_MS = 20L; |
| | | private static final long SEND_LOCK_EXPIRE_SECONDS = 15L; |
| | | |
| | | private volatile boolean connected = false; |
| | | private volatile boolean connecting = false; |
| | |
| | | if (deviceConfig.getFake() == 0) { |
| | | if ("ZyStationV3Thread".equals(deviceConfig.getThreadImpl())) { |
| | | connectApi = new ZyStationV3RealConnect(deviceConfig, redisUtil); |
| | | } else if ("ZyStationV4Thread".equals(deviceConfig.getThreadImpl())) { |
| | | connectApi = new ZyStationV4RealConnect(deviceConfig, redisUtil); |
| | | } else if ("ZyStationV5Thread".equals(deviceConfig.getThreadImpl())) { |
| | | connectApi = new ZyStationV5RealConnect(deviceConfig, redisUtil); |
| | | } else { |
| | | connectApi = new ZyStationRealConnect(deviceConfig, redisUtil); |
| | | } |
| | |
| | | if ("ZyStationV3Thread".equals(deviceConfig.getThreadImpl())) { |
| | | zyStationFakeSegConnect.addFakeConnect(deviceConfig, redisUtil); |
| | | connectApi = zyStationFakeSegConnect; |
| | | } else if ("ZyStationV4Thread".equals(deviceConfig.getThreadImpl())) { |
| | | } else if ("ZyStationV5Thread".equals(deviceConfig.getThreadImpl())) { |
| | | zyStationV4FakeSegConnect.addFakeConnect(deviceConfig, redisUtil); |
| | | connectApi = zyStationV4FakeSegConnect; |
| | | } else { |
| | | fakeConfigUnsupported = true; |
| | | zyStationConnectApi = null; |
| | | log.error("旧版输送站 fake 已移除,deviceNo={}, threadImpl={}, 请切换到 ZyStationV3Thread 或 ZyStationV4Thread", |
| | | log.error("旧版输送站 fake 已移除,deviceNo={}, threadImpl={}, 请切换到 ZyStationV3Thread 或 ZyStationV5Thread", |
| | | deviceConfig.getDeviceNo(), deviceConfig.getThreadImpl()); |
| | | return false; |
| | | } |
| | |
| | | if (!connected || connecting || connectApi == null) { |
| | | return new CommandResponse(false, "设备未连接,命令下发失败"); |
| | | } |
| | | while (true) { |
| | | Object lock = redisUtil.get(RedisKeyType.STATION_EXECUTE_COMMAND_LOCK.key); |
| | | if(lock != null) { |
| | | String lockKey = buildStationExecuteLockKey(); |
| | | String lockToken = UUID.randomUUID().toString(); |
| | | long lockWaitStart = System.currentTimeMillis(); |
| | | int waitRounds = 0; |
| | | if (redisUtil != null) { |
| | | while (true) { |
| | | if (redisUtil.trySetStringIfAbsent(lockKey, lockToken, SEND_LOCK_EXPIRE_SECONDS)) { |
| | | break; |
| | | } |
| | | waitRounds++; |
| | | try { |
| | | Thread.sleep(500); |
| | | }catch (Exception e) { |
| | | Thread.sleep(SEND_LOCK_POLL_MS); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | }else { |
| | | redisUtil.set(RedisKeyType.STATION_EXECUTE_COMMAND_LOCK.key, "lock", 60 * 5); |
| | | break; |
| | | } |
| | | } |
| | | CommandResponse commandResponse = connectApi.sendCommand(deviceConfig.getDeviceNo(), command); |
| | | redisUtil.del(RedisKeyType.STATION_EXECUTE_COMMAND_LOCK.key); |
| | | return commandResponse; |
| | | long lockWaitCost = System.currentTimeMillis() - lockWaitStart; |
| | | if (lockWaitCost >= SEND_LOCK_WARN_MS) { |
| | | log.warn("输送命令等待设备发送锁超时,deviceNo={}, taskNo={}, stationId={}, targetStaNo={}, waitMs={}, waitRounds={}, lockKey={}", |
| | | deviceConfig == null ? null : deviceConfig.getDeviceNo(), |
| | | command == null ? null : command.getTaskNo(), |
| | | command == null ? null : command.getStationId(), |
| | | command == null ? null : command.getTargetStaNo(), |
| | | lockWaitCost, |
| | | waitRounds, |
| | | lockKey); |
| | | } |
| | | long sendStart = System.currentTimeMillis(); |
| | | try { |
| | | return connectApi.sendCommand(deviceConfig.getDeviceNo(), command); |
| | | } finally { |
| | | releaseDeviceSendLock(lockKey, lockToken); |
| | | long sendCostMs = System.currentTimeMillis() - sendStart; |
| | | if (sendCostMs >= SEND_COST_WARN_MS) { |
| | | log.warn("输送命令底层发送耗时过长,deviceNo={}, taskNo={}, stationId={}, targetStaNo={}, sendCostMs={}", |
| | | deviceConfig == null ? null : deviceConfig.getDeviceNo(), |
| | | command == null ? null : command.getTaskNo(), |
| | | command == null ? null : command.getStationId(), |
| | | command == null ? null : command.getTargetStaNo(), |
| | | sendCostMs); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String buildStationExecuteLockKey() { |
| | | Integer deviceNo = deviceConfig == null ? null : deviceConfig.getDeviceNo(); |
| | | return RedisKeyType.STATION_EXECUTE_COMMAND_LOCK.key + ":" + deviceNo; |
| | | } |
| | | |
| | | private void releaseDeviceSendLock(String lockKey, String lockToken) { |
| | | if (redisUtil == null || lockKey == null) { |
| | | return; |
| | | } |
| | | try { |
| | | redisUtil.compareAndDelete(lockKey, lockToken); |
| | | } catch (Exception e) { |
| | | log.warn("释放输送设备发送锁失败,lockKey={}", lockKey, e); |
| | | } |
| | | } |
| | | |
| | | public CommandResponse sendOriginCommand(String address, short[] data) { |
| | |
| | | return connectApi.sendOriginCommand(address, data); |
| | | } |
| | | |
| | | public boolean clearTaskBufferSlot(Integer stationId, Integer slotIdx) { |
| | | ZyStationConnectApi connectApi = zyStationConnectApi; |
| | | if (!connected || connecting || connectApi == null) { |
| | | return false; |
| | | } |
| | | CommandResponse response = connectApi.clearTaskBufferSlot(deviceConfig.getDeviceNo(), stationId, slotIdx); |
| | | return response != null && Boolean.TRUE.equals(response.getResult()); |
| | | } |
| | | |
| | | public byte[] readOriginCommand(String address, int length) { |
| | | ZyStationConnectApi connectApi = zyStationConnectApi; |
| | | if (!connected || connecting || connectApi == null) { |