Newer
Older
casic-metering-readwriter / src / main / java / com / casic / missiles / service / impl / BusinessReadWriterServiceImpl.java
package com.casic.missiles.service.impl;

import com.casic.missiles.common.BusinessExceptionEnum;
import com.casic.missiles.config.ReadWriterConfig;
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.casic.missiles.utils.WebSocket;
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.API.entityclass.ScanTagParameter;
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.*;
import java.util.concurrent.*;

/**
 * @Description:
 * @Author: wangpeng
 * @Date: 2023/6/15 16:03
 */
@Slf4j
@Service("readWriterServiceBean")
public class BusinessReadWriterServiceImpl implements IBusinessReadWriterService {
    @Autowired
    private ForkJoinPool forkJoinPool;
    @Autowired
    private ReadWriterConfig readWriterConfig;
    @Autowired
    private WebSocket webSocket;

    public static SerialPort serialPort = null;

    @Override
    public ReturnDTO<Set<String>> tIdNewReadList() {
        //TCP连接方式(笔记本只有一个网口,内网还要连网线,该方案不可行),实际场景若有多个读写器连接需要设计读取实现方案,将ip入库或配置文件
//        CommonReader reader = new CommonReader("Reader1", GlobalData.ConnectType.TcpClient.name(), "192.168.1.201:9090");
        CommonReader reader = null;
        SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
        try {
            List<String> ports = serialPortUtil.findPort();
            log.info("RFID大读写器,当前可用串口:{}", ports);
            if (CollectionUtils.isEmpty(ports)) {
                return ReturnUtil.failed(BusinessExceptionEnum.NO_PROPERLY_CONNECTED.getMessage());
            }
            for (String port : ports) {
                //RS232连接方式
                CommonReader readerOne = new CommonReader("Reader1", "RS232", port + ":115200");
//                CommonReader readerOne = new CommonReader("Reader1", "RS232", port + "COM:115200");
//                CommonReader reader = new CommonReader("Reader1", "USB-HID", "");
                if (Objects.nonNull(readerOne)) {
                    reader = readerOne;
                    //RFID厂家最新协议采用GRP
                    reader.setProtocol(ProtocolVersion.GRP);
                    reader.setReaderProtocol(ProtocolVersion.GRP);
                    reader.setPortSum(4);//只对LRP的有效
                    boolean connect = reader.connect(false, new BaseReader.IConnectListener() {
                        @Override
                        public void callback(boolean b) {
                            log.info("大读写器设备连接状态:" + b);
                        }
                    });
                    if (!connect || reader.getIsConnected() == false) {
                        continue;
                    }
                    HashMap<Byte, Byte> map = new HashMap();
                    byte v = (byte) readWriterConfig.getPower();
                    map.put((byte)1, v);
                    map.put((byte)2, v);
                    map.put((byte)3, v);
                    map.put((byte)4, v);
                    reader.reader_SetPowerList(map);
                    break;
                }
            }
            if (reader.getIsConnected() == true) {
                boolean a = reader.BuzzerControl(true, false);
                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 (Exception e) {
            log.error("大读写器读取标签异常:{}", e.getMessage());
            log.info("关闭reader------------------------------------------------------");
            reader.disconnect();
            return ReturnUtil.failed(BusinessExceptionEnum.FAIL_READ_EPC_TID.getCode(), BusinessExceptionEnum.FAIL_READ_EPC_TID.getMessage());
        } finally {
            //不断开连接,读写器会每秒发送心跳
            if (Objects.nonNull(reader)) {
                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(readWriterConfig.getReceiveDuration());
            resultSet.addAll(CodeGunDataListener.dataSet);
            resultSet.remove("");
            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());
                log.info("有线扫码枪关闭串口连接==========================================");
                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);
    }

    @Override
    public ReturnDTO<Set<String>> tIdAndMiniAndGunReadList() {
        Set<String> resultSet = new HashSet<>();
        try {
            //异步请求大读写器
            ForkJoinTask<ReturnDTO<Set<String>>> taskResponse = forkJoinPool.submit(new RecursiveTask<ReturnDTO<Set<String>>>() {
                @SneakyThrows
                @Override
                protected ReturnDTO<Set<String>> compute() {
                    return tIdNewReadList();
                }
            });
            //异步请求小读写器
            ForkJoinTask<ReturnDTO<Set<String>>> miniTaskResponse = forkJoinPool.submit(new RecursiveTask<ReturnDTO<Set<String>>>() {
                @SneakyThrows
                @Override
                protected ReturnDTO<Set<String>> compute() {
                    return tIdMiniReadList();
                }
            });
            //有线扫码枪(二维码)识别设备id列表
//            Set<String> gunSet = queryGunReturnDTO(codeGunReadList());
            //大读写器识别tId列表
            Set<String> tIdsSet = null;
            tIdsSet = queryGunReturnDTO(taskResponse.get());
            resultSet.addAll(tIdsSet);
//            if (CollectionUtils.isEmpty(gunSet)) {
//                tIdsSet = queryGunReturnDTO(taskResponse.get());
//                resultSet.addAll(tIdsSet);
//            }

            //小读写器识别tId列表
            Set<String> minTIdsSet = queryGunReturnDTO(miniTaskResponse.get());
//            resultSet.addAll(gunSet);
            resultSet.addAll(minTIdsSet);
        } catch (Exception e) {
            log.info("识别出现异常:{}", e.getMessage());
        }
        return ReturnUtil.success(resultSet);
    }

    private Set<String> receiveNewTIds(CommonReader reader) throws InterruptedException {
        Set<String> tIds = new HashSet<>();
//        boolean a = reader.BuzzerControl(true, false);//蜂鸣器协议
//        boolean b = reader.reader_Inventory(param, (byte) 0x0001);
        //四个天线都开填0x0F,需要4个天线都连上才行
        ScanTagParameter param = new ScanTagParameter();
        param.antenna = readWriterConfig.getAntenna();
        param.isLoop = true;
        param.tidParameter = new byte[]{0, 8};
        param.writePower = readWriterConfig.getWritePower();
        param.readPower = readWriterConfig.getReadPower();
        boolean b = reader.reader_Inventory(param, (byte) 0x00);
        log.info("大读写器开始盘点:" + b);
        reader.OnTagDataReceivedHandle = (gateName, tagData) -> {
            if (tagData != null && tagData.getTID() != null) {
                String tid = Util.convertByteArrayToHexString(tagData.getTID());
                log.info("大读写器TID标签读取成功");
                webSocket.sendAllMessage(tid);
                tIds.add(tid);
            }
        };
        //连续读取3s
        TimeUnit.SECONDS.sleep(readWriterConfig.getReadDuration());
//        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(readWriterConfig.getMiniReadDuration());
        // 停止指令,空闲态
        MsgBaseStop msgBaseStop = new MsgBaseStop();
        client.sendSynMsg(msgBaseStop);
        if (0 == msgBaseStop.getRtCode()) {
            log.info("EPC、TID标签停止读取成功");
        } else {
            log.info("EPC、TID标签停止读取失败");
        }
        for (String tId : tIds) {
            webSocket.sendAllMessage(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;
    }

}