Newer
Older
casic-metering-readwriter / src / main / java / com / casic / missiles / service / impl / BusinessReadWriterServiceImpl.java
wangpeng on 15 Jun 2023 12 KB first commit
package com.casic.missiles.service.impl;

import com.casic.missiles.common.BusinessExceptionEnum;
import com.casic.missiles.listeners.CodeGunDataListener;
import com.casic.missiles.model.ReturnDTO;
import com.casic.missiles.model.ReturnUtil;
import com.casic.missiles.service.IBusinessReadWriterService;
import com.casic.missiles.utils.SerialPortUtil;
import com.gg.reader.api.dal.GClient;
import com.gg.reader.api.dal.HandlerTagEpcLog;
import com.gg.reader.api.dal.HandlerTagEpcOver;
import com.gg.reader.api.protocol.gx.*;
import com.gg.reader.api.utils.UsbHidUtils;
import com.rfid.API.CommonReader;
import com.rfid.API.ProtocolVersion;
import com.rfid.API.Util;
import com.rfid.API.core.BaseReader;
import com.rfid.ui.GlobalData;
import gnu.io.SerialPort;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.hid4java.HidDevice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.*;

/**
 * @Description:
 * @Author: wangpeng
 * @Date: 2023/6/15 16:03
 */
@Slf4j
@Service
public class BusinessReadWriterServiceImpl implements IBusinessReadWriterService {
    @Autowired
    private ForkJoinPool forkJoinPool;

    public static SerialPort serialPort = null;

    @Override
    public ReturnDTO<Set<String>> tIdNewReadList() {
        CommonReader reader = new CommonReader("Reader1", GlobalData.ConnectType.TcpClient.name(), "192.168.1.201:9090");
        try {
//        CommonReader reader = new CommonReader("Reader1", "RS232", "COM20:115200");
//        CommonReader reader = new CommonReader("Reader1", "USB-HID", "");
            reader.setProtocol(ProtocolVersion.CRP);
            reader.setReaderProtocol(ProtocolVersion.CRP);
//            reader.setPortSum(4);//只对LRP的有效
            reader.connect(false, new BaseReader.IConnectListener() {
                @Override
                public void callback(boolean b) {
//                    log.info("大读写器设备连接状态:" + b);
                }
            });
            if (reader.getIsConnected() == true) {
                Set<String> tIds = receiveNewTIds(reader);
                if (CollectionUtils.isEmpty(tIds)) {
                    return ReturnUtil.failed(BusinessExceptionEnum.FAIL_READ_EPC_TID.getCode(), BusinessExceptionEnum.FAIL_READ_EPC_TID.getMessage());
                }
                return ReturnUtil.success(tIds);
            } else {
                return ReturnUtil.failed(BusinessExceptionEnum.READ_WRITER_NOT_CONNECTED.getCode(), BusinessExceptionEnum.READ_WRITER_NOT_CONNECTED.getMessage());
            }
        } catch (InterruptedException e) {
            log.error("大读写器读取标签异常:{}", e.getMessage());
            return ReturnUtil.failed(BusinessExceptionEnum.FAIL_READ_EPC_TID.getCode(), BusinessExceptionEnum.FAIL_READ_EPC_TID.getMessage());
        } finally {
            //不断开连接,读写器会每秒发送心跳
//            reader.disconnect();
        }
    }

    @Override
    public ReturnDTO<Set<String>> tIdMiniReadList() {
        GClient client = new GClient();
        Set<String> tIds = new HashSet<>();
        try {
            List<HidDevice> attachedHidDevices = UsbHidUtils.getAttachedHidDevices();
            if (CollectionUtils.isEmpty(attachedHidDevices)) {
                return ReturnUtil.failed(BusinessExceptionEnum.READ_WRITER_NOT_CONNECTED.getCode(), BusinessExceptionEnum.READ_WRITER_NOT_CONNECTED.getMessage());
            }
            //循环每个USB接口数据
            for (HidDevice hidDevice : attachedHidDevices) {
                if (client.openUsbHid(hidDevice)) {
                    tIds.addAll(receiveTIds(client));
                }
            }
            if (CollectionUtils.isEmpty(tIds)) {
                return ReturnUtil.failed(BusinessExceptionEnum.READ_WRITER_NOT_CONNECTED_OR_NO_TID.getCode(), BusinessExceptionEnum.READ_WRITER_NOT_CONNECTED_OR_NO_TID.getMessage());
            }
            return ReturnUtil.success(tIds);
        } catch (InterruptedException e) {
            log.error("读写器循环读取事件时间设置,异常信息:{}", e.getMessage());
            return ReturnUtil.failed();
        } finally {
            client.close();
        }
    }

    @Override
    public ReturnDTO<Set<String>> codeGunReadList() {
        SerialPortUtil serialPortUtil = null;
        Set<String> resultSet = new HashSet<>();
        try {
            //添加监听器
            serialPortUtil = SerialPortUtil.getSerialPortUtil();
            List<String> ports = serialPortUtil.findPort();
            log.info("有线扫码枪,当前可用串口:{}", ports);
            if (CollectionUtils.isEmpty(ports)) {
                return ReturnUtil.failed(BusinessExceptionEnum.NO_PROPERLY_CONNECTED.getMessage());
            }
            for (String port : ports) {
                //有线扫码枪已经设置的是一次读取一个,要是多个这里逻辑需要调整
                serialPort = serialPortUtil.openPort(port, 19200, SerialPort.DATABITS_8, SerialPort.PARITY_NONE, SerialPort.PARITY_ODD);
                serialPortUtil.addListener(serialPort, new CodeGunDataListener());
            }
            //监听器接收指定时间的数据
            TimeUnit.SECONDS.sleep(10);
            resultSet.addAll(CodeGunDataListener.dataSet);
            CodeGunDataListener.dataSet = new HashSet<>();
        } catch (Exception e) {
            log.error("有线扫码枪识别失败,异常:", e.getMessage());
            return ReturnUtil.failed(BusinessExceptionEnum.HANDLE_FAILED.getMessage());
        } finally {
            if (Objects.nonNull(serialPortUtil) && Objects.nonNull(serialPort)) {
                //删除监听器
                serialPortUtil.removeListener(serialPort, new CodeGunDataListener());
                serialPortUtil.closePort(serialPort);
            }
        }
        return ReturnUtil.success(resultSet);
    }

    @Override
    public ReturnDTO<Set<String>> gunAndTIdNewReadList() throws ExecutionException, InterruptedException {
        //异步请求大读写器
        ForkJoinTask<ReturnDTO<Set<String>>> taskResponse = forkJoinPool.submit(new RecursiveTask<ReturnDTO<Set<String>>>() {
            @SneakyThrows
            @Override
            protected ReturnDTO<Set<String>> compute() {
                return tIdNewReadList();
            }
        });
        //有线扫码枪(二维码)识别设备id列表
        Set<String> gunSet = queryGunReturnDTO(this.codeGunReadList());
        //大读写器识别tId列表
        Set<String> tIdsSet = queryGunReturnDTO(taskResponse.get());
        Set<String> resultSet = new HashSet<>();
        resultSet.addAll(tIdsSet);
        resultSet.addAll(gunSet);
        return ReturnUtil.success(resultSet);
    }

    @Override
    public ReturnDTO<Set<String>> tIdAndMiniReadList() throws ExecutionException, InterruptedException {
        //异步请求大读写器
        ForkJoinTask<ReturnDTO<Set<String>>> taskResponse = forkJoinPool.submit(new RecursiveTask<ReturnDTO<Set<String>>>() {
            @SneakyThrows
            @Override
            protected ReturnDTO<Set<String>> compute() {
                return tIdNewReadList();
            }
        });
        //小读写器识别tId列表
        ReturnDTO<Set<String>> minTIdReturnDTO = this.tIdMiniReadList();
        Set<String> minTIdsSet = new HashSet<>();
        if (ReturnUtil.success().getCode().equals(minTIdReturnDTO.getCode()) && Objects.nonNull(minTIdReturnDTO.getData())) {
            minTIdsSet.addAll(minTIdReturnDTO.getData());
        }
        //大读写器识别tId列表
        Set<String> tIdsSet = queryGunReturnDTO(taskResponse.get());
        Set<String> resultSet = new HashSet<>();
        resultSet.addAll(tIdsSet);
        resultSet.addAll(minTIdsSet);
        return ReturnUtil.success(resultSet);
    }

    private Set<String> receiveNewTIds(CommonReader reader) throws InterruptedException {
        Set<String> tIds = new HashSet<>();
//        boolean a = reader.BuzzerControl(true, false);//蜂鸣器协议
//        ScanTagParameter param = new ScanTagParameter();
//        param.antenna = 0x0001;
//        param.isLoop = true;//持续盘点
//        boolean b = reader.reader_Inventory(param, (byte) 0x0001);
        //四个天线都开填0x0F,需要4个天线都连上才行
        boolean b1 = reader.ScanTID(0x0001, true, 1111);
        log.info("大读写器开始盘点:" + b1);
        reader.OnTagDataReceivedHandle = (gateName, tagData) -> {
            if (tagData != null && tagData.getTID() != null) {
                String tid = Util.convertByteArrayToHexString(tagData.getTID());
                log.info("大读写器TID标签读取成功");
                tIds.add(tid);
            }
        };
        //连续读取3s
        TimeUnit.SECONDS.sleep(3);
//        reader.disconnect();
        boolean stop = reader.reader_StopInventory();
        return tIds;
    }

    private Set<String> receiveTIds(GClient client) throws InterruptedException {
        Set<String> tIds = new HashSet<>();
        //标签上报事件、结束事件订阅
        eventSubscribe(tIds, client);

        // 4个天线读卡, 读取EPC数据区以及TID数据区
        MsgBaseInventoryEpc msgBaseInventoryEpc = new MsgBaseInventoryEpc();
        msgBaseInventoryEpc.setAntennaEnable(EnumG.AntennaNo_1 | EnumG.AntennaNo_2 | EnumG.AntennaNo_3 | EnumG.AntennaNo_4);
        // 0: 单次读取模式,读写器尽在各个使能的天线上进行一轮读卡操作便结束读卡操作并自动进入空闲状态
        // 1: 连续读取模式,读写器一直进行读卡操作直到读写器收到停止指令后结束读卡
        msgBaseInventoryEpc.setInventoryMode(EnumG.InventoryMode_Inventory);
        ParamEpcReadTid tid = new ParamEpcReadTid();
        tid.setMode(EnumG.ParamTidMode_Auto);
        tid.setLen(6);
        msgBaseInventoryEpc.setReadTid(tid);
        client.sendSynMsg(msgBaseInventoryEpc);
        if (0 == msgBaseInventoryEpc.getRtCode()) {
            log.info("EPC、TID标签读取成功");
        } else {
            log.info("EPC、TID标签读取失败");
            client.close();
            return new HashSet<>();
        }
        //连续读取,让事件接收3秒,也可采用单次读取方式(没有连续读取识别效果好)
        TimeUnit.SECONDS.sleep(3);
        // 停止指令,空闲态
        MsgBaseStop msgBaseStop = new MsgBaseStop();
        client.sendSynMsg(msgBaseStop);
        if (0 == msgBaseStop.getRtCode()) {
            log.info("EPC、TID标签停止读取成功");
        } else {
            log.info("EPC、TID标签停止读取失败");
        }
        return tIds;
    }

    private void eventSubscribe(Set<String> set, GClient client) {
        // 订阅标签上报事件
        client.onTagEpcLog = new HandlerTagEpcLog() {
            @Override
            public void log(String readName, LogBaseEpcInfo logBaseEpcInfo) {
                // 回调内部如有阻塞,会影响API正常使用
                // 标签回调数量较多,请将标签数据先缓存起来再作业务处理
                if (null != logBaseEpcInfo && 0 == logBaseEpcInfo.getResult()) {
                    System.out.println(logBaseEpcInfo);
                    log.info("收到标签上报事件,{}", logBaseEpcInfo.toString());
                    set.add(logBaseEpcInfo.getTid());
                }
            }
        };
        // 上报结束事件
        client.onTagEpcOver = new HandlerTagEpcOver() {
            @Override
            public void log(String readName, LogBaseEpcOver logBaseEpcOver) {
                if (null != logBaseEpcOver) {
                    log.info("收到标签上报结束事件,{}", logBaseEpcOver.toString());
                }
            }
        };
    }

    private Set<String> queryGunReturnDTO(ReturnDTO<Set<String>> setReturnDTO) {
        Set<String> gunSet = new HashSet<>();
        ReturnDTO<Set<String>> gunReturnDTO = setReturnDTO;
        if (ReturnUtil.success().getCode().equals(gunReturnDTO.getCode()) && Objects.nonNull(gunReturnDTO.getData())) {
            gunSet.addAll(gunReturnDTO.getData());
        }
        return gunSet;
    }

}