|
|
@@ -0,0 +1,578 @@
|
|
|
+package cn.oleauto.iec104;
|
|
|
+
|
|
|
+import cn.hutool.core.convert.Convert;
|
|
|
+import cn.hutool.core.thread.ThreadUtil;
|
|
|
+import cn.oleauto.biz.domain.BizYkLog;
|
|
|
+import cn.oleauto.biz.domain.BizYtLog;
|
|
|
+import cn.oleauto.biz.service.IBizYkLogService;
|
|
|
+import cn.oleauto.biz.service.IBizYtLogService;
|
|
|
+import cn.oleauto.common.enums.ControlStepType;
|
|
|
+import cn.oleauto.common.enums.ControlType;
|
|
|
+import cn.oleauto.common.enums.MessageOwnerType;
|
|
|
+import cn.oleauto.common.enums.OperateStateType;
|
|
|
+import cn.oleauto.common.exception.ServiceException;
|
|
|
+import cn.oleauto.common.utils.StringUtils;
|
|
|
+import cn.oleauto.common.utils.spring.SpringUtils;
|
|
|
+import cn.oleauto.iec104.util.DataConverter;
|
|
|
+import cn.oleauto.iec60870.*;
|
|
|
+import cn.oleauto.iec60870.ie.*;
|
|
|
+import cn.oleauto.protocol.common.IChannel;
|
|
|
+import cn.oleauto.protocol.common.cache.DefaultMessageCache;
|
|
|
+import cn.oleauto.protocol.common.dto.ReportMessageDto;
|
|
|
+import cn.oleauto.protocol.common.dto.ReportValueDtoList;
|
|
|
+import cn.oleauto.protocol.common.event.DefaultEventArgs;
|
|
|
+import cn.oleauto.protocol.common.event.EventType;
|
|
|
+import cn.oleauto.protocol.common.event.TransmitMessageEventArgs;
|
|
|
+import cn.oleauto.protocol.common.mq.MQCenter;
|
|
|
+import cn.oleauto.protocol.common.protocol.AbstractProtocol;
|
|
|
+import cn.oleauto.protocol.common.transmit.TransmitState;
|
|
|
+import io.netty.buffer.ByteBufUtil;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import lombok.Data;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.util.ConcurrentReferenceHashMap;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.StringReader;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.concurrent.BlockingDeque;
|
|
|
+import java.util.concurrent.ConcurrentMap;
|
|
|
+import java.util.concurrent.LinkedBlockingDeque;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+public class ProtocolImpl extends AbstractProtocol{
|
|
|
+ private ConnectionSettings settings = new ConnectionSettings();
|
|
|
+ private DefaultMessageCache messageCache = new DefaultMessageCache(1024 * 20);
|
|
|
+ private Thread thParse;
|
|
|
+ private Thread thTask;
|
|
|
+ private volatile boolean isStop = false;
|
|
|
+ private volatile short sendSq = 0;
|
|
|
+ private volatile short recSq = 0;
|
|
|
+ private byte[] packageBuffer = new byte[255];
|
|
|
+ private static final int LAZY_AMOUNT = 256;
|
|
|
+ private BlockingDeque<LazyRequest> waitSendApdus = new LinkedBlockingDeque<>(LAZY_AMOUNT);
|
|
|
+ private ConcurrentMap<String, WaitResponseRequest> waitResponseMap = new ConcurrentReferenceHashMap<>();
|
|
|
+ private long last100 = 0;
|
|
|
+ private long last103 = 0;
|
|
|
+ private int tm100 = 120_000;
|
|
|
+ private int tm103 = 86400_000/2;
|
|
|
+
|
|
|
+ public ProtocolImpl(IChannel channel){
|
|
|
+ super(channel);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onTransmitConnected(DefaultEventArgs e) {
|
|
|
+ sendSq = recSq = 0;
|
|
|
+ messageCache.clear();
|
|
|
+ notifyTransmitState(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onTransmitDisconnected(DefaultEventArgs e) {
|
|
|
+ sendSq = recSq = 0;
|
|
|
+ messageCache.clear();
|
|
|
+ notifyTransmitState(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onTransmitSent(TransmitMessageEventArgs e) {
|
|
|
+ notifyMessage(EventType.PROTOCOL_SENT, e.getData());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onTransmitReceived(TransmitMessageEventArgs e) {
|
|
|
+ if(!messageCache.append(e.getData())){
|
|
|
+ log.warn("message cache is full, lost={}", ByteBufUtil.hexDump(e.getData()));
|
|
|
+ }
|
|
|
+ synchronized (this) {
|
|
|
+ notify();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int start(String config) {
|
|
|
+ log.info("protocol start channel={}", channel.getName());
|
|
|
+ if(thParse != null || thTask != null){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Properties properties = new Properties();
|
|
|
+ properties.load(new StringReader(config));
|
|
|
+ // 总召唤间隔
|
|
|
+ tm100 = Convert.toInt(properties.get("ti1000Interval"), tm100);
|
|
|
+ settings.setCotFieldLength(Convert.toInt(properties.get("cotFieldLength"), 2));
|
|
|
+ settings.setCommonAddressFieldLength(Convert.toInt(properties.get("commonAddressFieldLength"), 2));
|
|
|
+ settings.setIoaFieldLength(Convert.toInt(properties.get("ioaFieldLength"), 3));
|
|
|
+ settings.setCommonAddress(Convert.toInt(properties.get("commonAddress"), 1));
|
|
|
+ settings.setOriginAddress(Convert.toInt(properties.get("originAddress"), 0));
|
|
|
+
|
|
|
+ buildPointRelation();
|
|
|
+
|
|
|
+ thParse = new Thread(()->{
|
|
|
+ this.parseMessageTask();
|
|
|
+ });
|
|
|
+ thParse.setName("ch-" + channel.getName() + "-protocol-parse");
|
|
|
+ thParse.start();
|
|
|
+
|
|
|
+ thTask = new Thread(()->{
|
|
|
+ this.timerTask();
|
|
|
+ });
|
|
|
+ thTask.setName("ch-" + channel.getName() + "-protocol-task");
|
|
|
+ thTask.start();
|
|
|
+
|
|
|
+ messageCache.clear();
|
|
|
+ } catch (Exception ex){
|
|
|
+ log.error("start protocol failed, config={} ex={}",config, ex);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void stop() {
|
|
|
+ isStop = true;
|
|
|
+ thTask = null;
|
|
|
+ thParse = null;
|
|
|
+ messageCache.clear();
|
|
|
+ synchronized (this) {
|
|
|
+ notifyAll();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Object> decode(byte[] data) {
|
|
|
+ APdu apdu = APdu.decode(data, settings);
|
|
|
+ if(apdu.getApciType() == APdu.ApciType.I_FORMAT){
|
|
|
+ int theirSn = apdu.getSendSeqNumber();
|
|
|
+ if(recSq == theirSn){
|
|
|
+ decodeAsdu(apdu);
|
|
|
+ // 发回一个s帧
|
|
|
+ recSq = (short) (theirSn + 1);
|
|
|
+ sendLazyRequest(new LazyRequest(APdu.ApciType.S_FORMAT, null, null, null, 0, 0));
|
|
|
+ }
|
|
|
+ if(theirSn < recSq || (theirSn > recSq && Math.abs(theirSn - recSq) > 32700)){
|
|
|
+ // 重复的情况
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // 丢了报文
|
|
|
+ }
|
|
|
+ } else if(apdu.getApciType() == APdu.ApciType.S_FORMAT){
|
|
|
+ // 监视帧
|
|
|
+ } else {
|
|
|
+ // U帧
|
|
|
+ }
|
|
|
+ return List.of();
|
|
|
+ }
|
|
|
+ public void notifyMessage(EventType eventType, byte[] data){
|
|
|
+ String frame = switch (data[2] & 0x3){
|
|
|
+ case 3->"U";
|
|
|
+ case 1->"S";
|
|
|
+ default -> "I";
|
|
|
+ };
|
|
|
+ log.info("channel={} frame={} ti={} action={} bytes ={}", channel.getName(), frame, (data.length > 6? data[6]: 0), eventType, ByteBufUtil.hexDump(data));
|
|
|
+ String fun = data.length <= 6? frame : Byte.toString(data[6]);
|
|
|
+ MessageOwnerType owner = (eventType == EventType.TRANSMIT_RECEIVED || eventType == EventType.PROTOCOL_RECEIVED)? MessageOwnerType.DEVICE : MessageOwnerType.SYSTEM;
|
|
|
+ ReportMessageDto channelMessageDto = new ReportMessageDto(channel.getId(), null, owner, fun, data, System.currentTimeMillis());
|
|
|
+ MQCenter.getInstance().send(ReportMessageDto.REPORT_MESSAGE, channelMessageDto);
|
|
|
+ }
|
|
|
+ private void decodeAsdu(APdu apdu){
|
|
|
+ try {
|
|
|
+ ASdu asdu = ASdu.decode(apdu.getASduBuffer(), settings);
|
|
|
+ ASduType typeIdentification = asdu.getTypeIdentification();
|
|
|
+ switch (typeIdentification){
|
|
|
+ case C_SE_NC_1, C_SE_NA_1-> receiveYtResponse(asdu);
|
|
|
+ case C_SC_NA_1, C_DC_NA_1-> receiveYkResponse(asdu);
|
|
|
+ }
|
|
|
+ ReportValueDtoList realData = DataConverter.toRealData(this, asdu);
|
|
|
+ if(realData.size() > 0) {
|
|
|
+ notifyRealValue(realData);
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void receiveYtResponse(ASdu asdu){
|
|
|
+ String wrrId = getWaitResponseRequestId(asdu.getTypeIdentification().getId(), asdu.getInformationObjects()[0].getInformationObjectAddress(), "");
|
|
|
+ WaitResponseRequest waitResponseRequest = waitResponseMap.remove(wrrId);
|
|
|
+ if(waitResponseRequest != null && waitResponseRequest.extraObject instanceof BizYtLog bizYtLog){
|
|
|
+ CauseOfTransmission causeOfTransmission = asdu.getCauseOfTransmission();
|
|
|
+ bizYtLog.setState((CauseOfTransmission.ACTIVATION_CON == causeOfTransmission && !asdu.isNegativeConfirm())
|
|
|
+ ? OperateStateType.ES.getType()
|
|
|
+ : OperateStateType.EF.getType());
|
|
|
+ IBizYtLogService bean = SpringUtils.getBean(IBizYtLogService.class);
|
|
|
+ bean.updateBizYtLog(bizYtLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void receiveYkResponse(ASdu asdu) {
|
|
|
+ String wrrId = getWaitResponseRequestId(asdu.getTypeIdentification().getId(), asdu.getInformationObjects()[0].getInformationObjectAddress(), "");
|
|
|
+ WaitResponseRequest waitResponseRequest = waitResponseMap.remove(wrrId);
|
|
|
+ if(waitResponseRequest != null && waitResponseRequest.extraObject instanceof BizYkLog bizYkLog){
|
|
|
+ CauseOfTransmission causeOfTransmission = asdu.getCauseOfTransmission();
|
|
|
+ if(causeOfTransmission == CauseOfTransmission.ACTIVATION_CON){
|
|
|
+ if(asdu.isNegativeConfirm()){
|
|
|
+ if(StringUtils.equals(bizYkLog.getState(), OperateStateType.SE.getType())){
|
|
|
+ bizYkLog.setState(OperateStateType.SF.getType());
|
|
|
+ } else {
|
|
|
+ bizYkLog.setState(OperateStateType.EF.getType());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if(StringUtils.equals(bizYkLog.getState(), OperateStateType.SE.getType())){
|
|
|
+ bizYkLog.setState(OperateStateType.SS.getType());
|
|
|
+ } else {
|
|
|
+ bizYkLog.setState(OperateStateType.ES.getType());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if(causeOfTransmission == CauseOfTransmission.DEACTIVATION_CON){
|
|
|
+ if(asdu.isNegativeConfirm()){
|
|
|
+ bizYkLog.setState(OperateStateType.CF.getType());
|
|
|
+ } else {
|
|
|
+ bizYkLog.setState(OperateStateType.CS.getType());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ IBizYkLogService bean = SpringUtils.getBean(IBizYkLogService.class);
|
|
|
+ bean.updateBizYkLog(bizYkLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void write(Object obj) {
|
|
|
+ if(null == transmit || transmit.state() != TransmitState.CONNECTED){
|
|
|
+ throw new RuntimeException("没有连接上设备");
|
|
|
+ }
|
|
|
+ if(obj instanceof BizYtLog bizYtLog){
|
|
|
+ addYtToLazy(bizYtLog);
|
|
|
+ } else if(obj instanceof BizYkLog bizYkLog){
|
|
|
+ addYkToLazy(bizYkLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void parseMessageTask(){
|
|
|
+ log.info("start channel protocol paserTask, channel={}", channel.getName());
|
|
|
+ byte[] head = new byte[APdu.APCI_LENGTH];
|
|
|
+ while(!isStop){
|
|
|
+ boolean noData = true;
|
|
|
+ if(messageCache.pick(head)){
|
|
|
+ int i = 0;
|
|
|
+ for(; head[i] != APdu.START_FLAG && i < head.length; ++i){
|
|
|
+ }
|
|
|
+ if(i > 0){
|
|
|
+ // 首字节不是0x68,
|
|
|
+ messageCache.remove(i);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ int len = head[1] & 0xff;
|
|
|
+ if(len < APdu.MIN_APDU_LENGTH || len > APdu.MAX_APDU_LENGTH){
|
|
|
+ // 报文长度字节有错误了
|
|
|
+ messageCache.remove(2);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(len == APdu.MIN_APDU_LENGTH){
|
|
|
+ // 如果是U或者S帧
|
|
|
+ messageCache.remove(APdu.APCI_LENGTH);
|
|
|
+ decode(head);
|
|
|
+ }
|
|
|
+ else if(len + 2 <= messageCache.size()){
|
|
|
+ // I帧,并且数据够,则取出解析
|
|
|
+ byte[] message = new byte[len + 2];
|
|
|
+ messageCache.take(message);
|
|
|
+ notifyMessage(EventType.PROTOCOL_RECEIVED, message);
|
|
|
+ decode(message);
|
|
|
+ noData = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(noData){
|
|
|
+ synchronized (this) {
|
|
|
+ try {
|
|
|
+ this.wait(1000);
|
|
|
+ } catch (InterruptedException ex) {
|
|
|
+ log.warn("wait exception={}", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("end channel protocol paserTask, channel={}", channel.getName());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void timerTask(){
|
|
|
+ log.info("start channel protocol timerTask, channel={}", channel.getName());
|
|
|
+ while(!isStop){
|
|
|
+ try{
|
|
|
+ TransmitState transmitState = transmit.state();
|
|
|
+ if(transmitState == TransmitState.DISCONNECTED || transmitState == TransmitState.STARTED){
|
|
|
+ if(transmit.connect() == 0){
|
|
|
+ ThreadUtil.sleep(1000);
|
|
|
+ waitSendApdus.push(new LazyRequest(APdu.ApciType.STARTDT_ACT, null, null, null, System.currentTimeMillis(), 0));
|
|
|
+ }else{
|
|
|
+ ThreadUtil.sleep(10000);
|
|
|
+ }
|
|
|
+ ThreadUtil.sleep(10000);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ LazyRequest lazyRequest = waitSendApdus.poll();
|
|
|
+ if(lazyRequest != null){
|
|
|
+ sendLazyRequest(lazyRequest);
|
|
|
+ ThreadUtil.sleep(100);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Long curTm = System.currentTimeMillis();
|
|
|
+ clearWaitResponseRequest();
|
|
|
+ if(curTm - last100 > tm100){
|
|
|
+ send100();
|
|
|
+ last100 = curTm;
|
|
|
+ }
|
|
|
+ else if(curTm - last103 > tm103){
|
|
|
+ send103();
|
|
|
+ last103 = curTm;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThreadUtil.sleep(1000);
|
|
|
+ } catch (Exception ex)
|
|
|
+ {
|
|
|
+ log.error("protocol timerTask occur exception, channel={}, ex={}",channel.getName(), ex.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.info("end channel protocol timerTask, channel={}", channel.getName());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sendLazyRequest(LazyRequest lazyRequest) {
|
|
|
+ boolean exist = false;
|
|
|
+ long nowTm = System.currentTimeMillis();
|
|
|
+ if(StringUtils.isBlank(lazyRequest.wrpId) ) {
|
|
|
+ sendApdu(lazyRequest.apciType, lazyRequest.getAsdu());
|
|
|
+ return;
|
|
|
+ } else if(!waitResponseMap.containsKey(lazyRequest.wrpId)){
|
|
|
+ sendApdu(lazyRequest.apciType, lazyRequest.getAsdu());
|
|
|
+ }else {
|
|
|
+ if(nowTm - lazyRequest.beginTm > lazyRequest.tmOutMs){
|
|
|
+ exist = true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // 重新等发送
|
|
|
+ waitSendApdus.push(lazyRequest);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(lazyRequest.extraObject instanceof BizYtLog bizYtLog){
|
|
|
+ if(exist){
|
|
|
+ bizYtLog.setState(OperateStateType.AL.getType());
|
|
|
+ }
|
|
|
+ else if(bizYtLog.getTmOut() <= 0) {
|
|
|
+ bizYtLog.setState(OperateStateType.ES.getType());
|
|
|
+ } else {
|
|
|
+ bizYtLog.setState(OperateStateType.EX.getType());
|
|
|
+ waitResponseMap.put(lazyRequest.wrpId, new WaitResponseRequest(lazyRequest.wrpId, bizYtLog, nowTm));
|
|
|
+ }
|
|
|
+ IBizYtLogService bean = SpringUtils.getBean(IBizYtLogService.class);
|
|
|
+ bean.updateBizYtLog(bizYtLog);
|
|
|
+ } else if(lazyRequest.extraObject instanceof BizYkLog bizYkLog){
|
|
|
+ if(exist){
|
|
|
+ bizYkLog.setState(OperateStateType.AL.getType());
|
|
|
+ }
|
|
|
+ else if(Objects.equals(OperateStateType.SE.getType(), bizYkLog.getState())
|
|
|
+ && Objects.equals(bizYkLog.getControlStep(), ControlStepType.TWO.getType())) {
|
|
|
+ waitResponseMap.put(lazyRequest.wrpId, new WaitResponseRequest(lazyRequest.wrpId, bizYkLog, nowTm));
|
|
|
+ } else {
|
|
|
+ if(bizYkLog.getTmOut() <= 0){
|
|
|
+ bizYkLog.setState(OperateStateType.ES.getType());
|
|
|
+ } else {
|
|
|
+ waitResponseMap.put(lazyRequest.wrpId, new WaitResponseRequest(lazyRequest.wrpId, bizYkLog, nowTm));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IBizYkLogService bean = SpringUtils.getBean(IBizYkLogService.class);
|
|
|
+ bean.updateBizYkLog(bizYkLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void clearWaitResponseRequest() {
|
|
|
+ for(var val : waitResponseMap.values()){
|
|
|
+ if(val.extraObject instanceof BizYtLog bizYtLog){
|
|
|
+ if(System.currentTimeMillis() - val.tmMs > bizYtLog.getTmOut() * 1000){
|
|
|
+ if(waitResponseMap.remove(val.id) != null) {
|
|
|
+ bizYtLog.setState(OperateStateType.ET.getType());
|
|
|
+ IBizYtLogService bean = SpringUtils.getBean(IBizYtLogService.class);
|
|
|
+ bean.updateBizYtLog(bizYtLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if(val.extraObject instanceof BizYkLog bizYkLog){
|
|
|
+ if(System.currentTimeMillis() - val.tmMs > bizYkLog.getTmOut() * 1000) {
|
|
|
+ if(waitResponseMap.remove(val.id)!=null) {
|
|
|
+ if(StringUtils.equals(bizYkLog.getState(), OperateStateType.SE.getType())){
|
|
|
+ bizYkLog.setState(OperateStateType.ST.getType());
|
|
|
+ } else if(StringUtils.equals(bizYkLog.getState(), OperateStateType.CA.getType())){
|
|
|
+ bizYkLog.setState(OperateStateType.CT.getType());
|
|
|
+ } else {
|
|
|
+ bizYkLog.setState(OperateStateType.ET.getType());
|
|
|
+ }
|
|
|
+ IBizYkLogService bean = SpringUtils.getBean(IBizYkLogService.class);
|
|
|
+ bean.updateBizYkLog(bizYkLog);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sendApdu(APdu.ApciType type, ASdu aSdu){
|
|
|
+ byte[] sendBuf = null;
|
|
|
+ synchronized (packageBuffer) {
|
|
|
+ APdu apdu = null;
|
|
|
+ if(type == APdu.ApciType.I_FORMAT){
|
|
|
+ int asduLength = aSdu.encode(packageBuffer, 0, settings);
|
|
|
+ byte[] asduBufferCut = Arrays.copyOf(packageBuffer, asduLength);
|
|
|
+ apdu = new APdu(sendSq, recSq, type, asduBufferCut);
|
|
|
+ sendSq = (short)(sendSq+1);
|
|
|
+ } else {
|
|
|
+ apdu = new APdu(sendSq, recSq, type);
|
|
|
+ }
|
|
|
+ int len = apdu.encode(packageBuffer, settings);
|
|
|
+ sendBuf = Arrays.copyOf(packageBuffer, len);
|
|
|
+ }
|
|
|
+ if(sendBuf != null){
|
|
|
+ transmit.send(sendBuf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void send100(){
|
|
|
+ ASdu aSdu = new ASdu(ASduType.C_IC_NA_1,
|
|
|
+ false,
|
|
|
+ CauseOfTransmission.ACTIVATION,
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ 0,
|
|
|
+ 1,
|
|
|
+ new InformationObject(0, new IeQualifierOfInterrogation(20)));
|
|
|
+ sendApdu(APdu.ApciType.I_FORMAT, aSdu);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void send103() {
|
|
|
+ IeTime56 time = new IeTime56(System.currentTimeMillis());
|
|
|
+ InformationObject io = new InformationObject(0, time);
|
|
|
+ ASdu asdu = new ASdu(ASduType.C_CS_NA_1,
|
|
|
+ false,
|
|
|
+ CauseOfTransmission.ACTIVATION,
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ 0,
|
|
|
+ settings.getCommonAddress(),
|
|
|
+ io);
|
|
|
+ sendApdu(APdu.ApciType.I_FORMAT, asdu);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addYtToLazy(BizYtLog bizYtLog){
|
|
|
+ Integer iFunCode = Convert.toInt(bizYtLog.getFun());
|
|
|
+ if(iFunCode == null){
|
|
|
+ throw new ServiceException("fun value is invalid, val=" + bizYtLog.getFun());
|
|
|
+ }
|
|
|
+ Integer addr = Convert.toInt(bizYtLog.getAddrCode());
|
|
|
+ if(addr == null){
|
|
|
+ throw new ServiceException("addr code value is invalid, addrCode=" + bizYtLog.getAddrCode());
|
|
|
+ }
|
|
|
+ Float ytVal = Convert.toFloat(bizYtLog.getControlVal());
|
|
|
+ if(ytVal == null){
|
|
|
+ throw new ServiceException("yt value is invalid, val=" + bizYtLog.getControlVal());
|
|
|
+ }
|
|
|
+
|
|
|
+ IeQualifierOfSetPointCommand qualifier = new IeQualifierOfSetPointCommand(0, false);
|
|
|
+ InformationObject io;
|
|
|
+ ASduType aSduType = ASduType.typeFor(iFunCode);
|
|
|
+ if(aSduType == ASduType.C_SE_NC_1) {
|
|
|
+ IeShortFloat val = new IeShortFloat(ytVal);
|
|
|
+ io = new InformationObject(addr.intValue(), val, qualifier);
|
|
|
+ } else if(aSduType == ASduType.C_SE_NA_1) {
|
|
|
+ IeNormalizedValue val = new IeNormalizedValue(ytVal.intValue());
|
|
|
+ io = new InformationObject(addr.intValue(), val, qualifier);
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("fun value is invalid, val=" + bizYtLog.getFun());
|
|
|
+ }
|
|
|
+ ASdu aSdu = new ASdu(aSduType,
|
|
|
+ false,
|
|
|
+ CauseOfTransmission.ACTIVATION,
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ settings.getOriginAddress(),
|
|
|
+ settings.getCommonAddress(),
|
|
|
+ io);
|
|
|
+ String wrqId = getWaitResponseRequestId(aSduType.getId(), addr.intValue(), "");
|
|
|
+ waitSendApdus.push(new LazyRequest(APdu.ApciType.I_FORMAT, aSdu, bizYtLog, wrqId, System.currentTimeMillis(), bizYtLog.getTmOut() * 1000));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addYkToLazy(BizYkLog bizYkLog) {
|
|
|
+ Integer ykVal = null;
|
|
|
+ if(Objects.equals(bizYkLog.getControlVal(), ControlType.OPEN.getType())){
|
|
|
+ ykVal = 0;
|
|
|
+ } else if(Objects.equals(bizYkLog.getControlVal(), ControlType.CLOSE.getType())){
|
|
|
+ ykVal = 1;
|
|
|
+ }
|
|
|
+ if(ykVal == null){
|
|
|
+ log.error("yk value is invalid, val={}", bizYkLog.getControlVal());
|
|
|
+ throw new ServiceException("yk value is invalid, val=" + bizYkLog.getControlVal());
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer addr = Convert.toInt(bizYkLog.getAddrCode());
|
|
|
+ if(addr == null){
|
|
|
+ log.error("addr code value is invalid, addrCode={}", bizYkLog.getAddrCode());
|
|
|
+ throw new ServiceException("addr code value is invalid, addrCode=" + bizYkLog.getAddrCode());
|
|
|
+ }
|
|
|
+ boolean isSelect = OperateStateType.SE.getType().equals(bizYkLog.getState());
|
|
|
+
|
|
|
+ int fun = Convert.toInt(bizYkLog.getFun(), 45);
|
|
|
+ InformationElement val;
|
|
|
+ ASduType ti = ASduType.C_SC_NA_1;
|
|
|
+ if(fun == ASduType.C_DC_NA_1.getId()){
|
|
|
+ val = new IeDoubleCommand((ykVal.intValue()!=0? IeDoubleCommand.DoubleCommandState.ON: IeDoubleCommand.DoubleCommandState.OFF), 0, isSelect);
|
|
|
+ ti = ASduType.C_DC_NA_1;
|
|
|
+ } else {
|
|
|
+ val = new IeSingleCommand(ykVal.intValue()!=0, 0, isSelect);
|
|
|
+ }
|
|
|
+ CauseOfTransmission cot = StringUtils.equals(OperateStateType.CA.getType(), bizYkLog.getState())? CauseOfTransmission.DEACTIVATION: CauseOfTransmission.ACTIVATION;
|
|
|
+ InformationObject io = new InformationObject(addr, val);
|
|
|
+ ASdu aSdu = new ASdu(ti,
|
|
|
+ false,
|
|
|
+ cot,
|
|
|
+ false,
|
|
|
+ false,
|
|
|
+ settings.getOriginAddress(),
|
|
|
+ settings.getCommonAddress(),
|
|
|
+ io);
|
|
|
+ String wrqId = getWaitResponseRequestId(ti.getId(), addr.intValue(), "");
|
|
|
+ waitSendApdus.push(new LazyRequest(APdu.ApciType.I_FORMAT, aSdu, bizYkLog, wrqId, System.currentTimeMillis(), bizYkLog.getTmOut() * 1000));
|
|
|
+ }
|
|
|
+
|
|
|
+ static String getWaitResponseRequestId(int cmd, int ioa, String val){
|
|
|
+ return "" + cmd + "-" + ioa;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Data
|
|
|
+ @AllArgsConstructor
|
|
|
+ static class LazyRequest{
|
|
|
+ private APdu.ApciType apciType;
|
|
|
+ private ASdu asdu;
|
|
|
+ private Object extraObject;
|
|
|
+ private String wrpId;
|
|
|
+ private long beginTm;
|
|
|
+ private long tmOutMs;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Data
|
|
|
+ @AllArgsConstructor
|
|
|
+ static class WaitResponseRequest{
|
|
|
+ private String id;
|
|
|
+ private Object extraObject;
|
|
|
+ // 开始时间
|
|
|
+ private long tmMs;
|
|
|
+ }
|
|
|
+}
|