package com.zd.laboratory.utils;

public class CRCCHECK {

    //开锁后缀
    private static final String OPEN_LOCK_ORDER_SUFFIX=" 05 00 01 EE 00";
    //关锁后缀
    private static final String CLOSE_LOCK_ORDER_SUFFIX=" 05 00 01 DD 00";
    //读锁后缀
    private static final String READ_LOCK_ORDER_SUFFIX=" 01 00 01 00 01";

    /**
     * CRC16_MODBUS：多项式x16+x15+x2+1（0x8005），初始值0xFFFF，低位在前，高位在后，结果与0x0000异或
     * 以上计算步骤中的多项式0xA001是0x8005按位颠倒后的结果。
     * 0x8408是0x1021按位颠倒后的结果。
     * @param s 需要输入十六进制字符串
     * @return 结果数据CRC16 modbus格式
     */
    private static String getCRC16Result(String s){
        int CRC = 0x0000ffff;
        for (int i=0;i<s.length();i=i+2){
            int CRCL=CRC&0x000000FF;//低八位
            int CRCH=CRC&0x0000FF00;//高八位
            String CRCIn = s.substring(i,i+2);
            int a = Integer.parseInt(CRCIn,16);//待处理数据转16进制
            CRC=CRCH+CRCL^a;
            for(int j=0;j<8;j++){
                if((CRC&0x0001)==0){
                    CRC=CRC>>1;
                }else {
                    CRC>>=1;
                    CRC=CRC^0xA001;
                }
            }
        }
        //      交换
        int CRCL=CRC&0x000000FF;//低八位
        int CRCH=CRC&0x0000FF00;//高八位
        CRC=CRCL<<8|CRCH>>8;//最好用按位与，别用加
        String hexString=Integer.toHexString(CRC).toUpperCase();
        //给crc加空格格式
        String regex = "(.{2})";
        hexString=hexString.replaceAll(regex, "$1 ");
        return hexString;
    }

    public static void main(String args[]){
        Integer bit=2;
        System.out.println(getOpenLockOrder(bit));
        System.out.println(getCloseLockOrder(bit));
        System.out.println(getReadLockOrder(bit));
        System.out.println(getLockStatus("02 01 01 00 51 CC"));
        System.out.println(getLockStatus("02 01 01 01 90 0C"));
        System.out.println(getBitByCommand("FE 01 01 01 90 0C"));
    }

    /**
     * 根据地址位动态生成开锁指令
     * @param bit
     * @return
     */
    public static String getOpenLockOrder(Integer bit){
        return getCommandByType(bit,1);
    }

    /**
     * 根据地址位动态生成关锁指令
     * @param bit
     * @return
     */
    public static String getCloseLockOrder(Integer bit){
        return getCommandByType(bit,2);
    }

    /**
     * 根据地址位动态生成读指令
     * @param bit
     * @return
     */
    public static String getReadLockOrder(Integer bit){
        return getCommandByType(bit,3);
    }

    private static String getCommandByType(Integer bit,Integer type){
        String command=getCommand(bit);
        if(type==1){
            command=command+OPEN_LOCK_ORDER_SUFFIX;
        }
        if(type==2){
            command=command+CLOSE_LOCK_ORDER_SUFFIX;
        }
        if(type==3){
            command=command+READ_LOCK_ORDER_SUFFIX;
        }
        String commandRep = command.replace(" ","");
        String crcRes=getCRC16Result(commandRep);
        String finalCommand=command+" "+crcRes;
        return finalCommand;
    }

    /**
     * 通用的地址位表头计算
     * @param bit
     * @return
     */
    public static String getCommand(Integer bit){
        String cls=Integer.toHexString(bit).toUpperCase();
        String changeCls="";
        if(cls.length()>1){
            changeCls=cls;
        }
        if(cls.length()==1){
            changeCls="0"+cls;
        }
        return changeCls;
    }

    /**
     * 解析锁的状态
     * @param command
     * @return 1开锁状态 0关锁状态
     */
    public static int getLockStatus(String command){
        String commandStr=command.replace(" ","");
        String statusStr=commandStr.substring(6,8);
        int status=Integer.valueOf(statusStr);
        return status;
    }

    /**
     * 根据指令解析出地址位bit
     * @param command
     * @return
     */
    public static long getBitByCommand(String command){
        String commandStr=command.replace(" ","");
        String statusStr=commandStr.substring(0,2);
        long status=Long.parseLong(statusStr,16);
        return status;
    }
}
