|
|
|
|
@ -0,0 +1,434 @@
|
|
|
|
|
package com.zhehekeji.web.service.RFID;
|
|
|
|
|
|
|
|
|
|
import lombok.SneakyThrows;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
import java.net.InetSocketAddress;
|
|
|
|
|
import java.net.Socket;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* sick扫码枪
|
|
|
|
|
*/
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class RFIDSocketNew {
|
|
|
|
|
|
|
|
|
|
public byte cmd;
|
|
|
|
|
private Socket socket;
|
|
|
|
|
|
|
|
|
|
private OutputStream os;
|
|
|
|
|
|
|
|
|
|
private InputStream is;
|
|
|
|
|
|
|
|
|
|
private Queue<Byte> buffer;
|
|
|
|
|
|
|
|
|
|
private boolean running;
|
|
|
|
|
|
|
|
|
|
private int step;
|
|
|
|
|
|
|
|
|
|
private int length;
|
|
|
|
|
|
|
|
|
|
private int index;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 读到的所有code标签
|
|
|
|
|
*/
|
|
|
|
|
private Set<String> tags = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
private List<Byte> byteList = new ArrayList<>(30);
|
|
|
|
|
|
|
|
|
|
public Set<String> getTags() {
|
|
|
|
|
return tags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RFIDSocketNew(String ip, int port, String cmd) {
|
|
|
|
|
if (cmd.equals("6C")) {
|
|
|
|
|
this.cmd = (byte) CMD.INVENTORY;
|
|
|
|
|
} else {
|
|
|
|
|
this.cmd = (byte) CMD.REAL_TIME_INVENTORY;
|
|
|
|
|
}
|
|
|
|
|
socket = new Socket();
|
|
|
|
|
os = null;
|
|
|
|
|
is = null;
|
|
|
|
|
try {
|
|
|
|
|
socket.connect(new InetSocketAddress(ip, port), 3000);
|
|
|
|
|
os = socket.getOutputStream();
|
|
|
|
|
is = socket.getInputStream();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
log.error("RFIDSocket time out,ip:{},info:{}", ip, e);
|
|
|
|
|
|
|
|
|
|
close();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void startCheck() {
|
|
|
|
|
Thread thread = new Thread(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
if (!running) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
byte[] antChanges = new byte[6];
|
|
|
|
|
antChanges[0] = (byte) 0xa0;
|
|
|
|
|
antChanges[1] = (byte) 0x04;
|
|
|
|
|
antChanges[2] = (byte) 0x01;
|
|
|
|
|
antChanges[3] = (byte) 0x74;
|
|
|
|
|
if (i % 2 == 0) {
|
|
|
|
|
//切换天线 使用天线0
|
|
|
|
|
antChanges[4] = (byte) 0x00;
|
|
|
|
|
antChanges[5] = (byte) 0xe7;
|
|
|
|
|
} else {
|
|
|
|
|
//切换天线 使用天线1
|
|
|
|
|
antChanges[4] = (byte) 0x01;
|
|
|
|
|
antChanges[5] = (byte) 0xe6;
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
try {
|
|
|
|
|
os.write(antChanges);
|
|
|
|
|
Thread.sleep(10);
|
|
|
|
|
} catch (InterruptedException | IOException e) {
|
|
|
|
|
log.error("send cmd error:{}", e);
|
|
|
|
|
}
|
|
|
|
|
byte[] bytes = new byte[5];
|
|
|
|
|
bytes[0] = (byte) 0xa0;
|
|
|
|
|
bytes[1] = (byte) 0x03;
|
|
|
|
|
bytes[2] = (byte) 0x01;
|
|
|
|
|
bytes[3] = cmd;
|
|
|
|
|
bytes[4] = (byte) 0xac;
|
|
|
|
|
try {
|
|
|
|
|
os.write(bytes);
|
|
|
|
|
Thread.sleep(70);
|
|
|
|
|
} catch (InterruptedException | IOException e) {
|
|
|
|
|
log.warn("send rfid cmd error:{}", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
thread.start();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void readData() {
|
|
|
|
|
running = true;
|
|
|
|
|
buffer = new LinkedList();
|
|
|
|
|
|
|
|
|
|
Thread thread = new Thread(new Runnable() {
|
|
|
|
|
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
while (true) {
|
|
|
|
|
if (!running) {
|
|
|
|
|
System.out.println("stop");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
int count = 0;
|
|
|
|
|
byte[] header = new byte[1];
|
|
|
|
|
byte[] lenBuf = new byte[1];
|
|
|
|
|
// 1. 读取头部(0xA0)
|
|
|
|
|
int headerRead = is.read(header);
|
|
|
|
|
if (headerRead == -1) {
|
|
|
|
|
System.out.println("连接已关闭或没有更多数据");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (header[0] != (byte) 0xA0) {
|
|
|
|
|
System.out.println("无效数据包头: 0x" + String.format("%02X", header[0]));
|
|
|
|
|
continue; // 跳过非有效数据包
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 读取长度字段
|
|
|
|
|
int lenRead = is.read(lenBuf);
|
|
|
|
|
if (lenRead == -1) {
|
|
|
|
|
System.out.println("连接中断,无法读取长度字段");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int dataLength = lenBuf[0] & 0xFF; // 将byte转为无符号int
|
|
|
|
|
|
|
|
|
|
// 3. 读取data部分
|
|
|
|
|
int totalRead = 0;
|
|
|
|
|
// 3. 构造完整数据包 buffer:head(1) + len(1) + data(dataLength)
|
|
|
|
|
byte[] fullPacket = new byte[1 + 1 + dataLength];
|
|
|
|
|
fullPacket[0] = (byte) 0xA0;
|
|
|
|
|
fullPacket[1] = lenBuf[0];
|
|
|
|
|
|
|
|
|
|
// 4. 读取剩余部分(data)
|
|
|
|
|
while (totalRead < dataLength) {
|
|
|
|
|
int bytesRead = is.read(fullPacket, 2 + totalRead, dataLength - totalRead);
|
|
|
|
|
if (bytesRead == -1) {
|
|
|
|
|
System.out.println("连接中断,数据未完全读取");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
totalRead += bytesRead;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (totalRead != dataLength) {
|
|
|
|
|
System.out.println("数据包不完整,跳过");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 成功读取一个完整数据包,可以进行处理
|
|
|
|
|
tags.add(parse(fullPacket));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
thread.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void clear() {
|
|
|
|
|
byteList.clear();
|
|
|
|
|
step = 0;
|
|
|
|
|
length = 0;
|
|
|
|
|
index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void close() {
|
|
|
|
|
running = false;
|
|
|
|
|
try {
|
|
|
|
|
is.close();
|
|
|
|
|
socket.close();
|
|
|
|
|
os.close();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
log.error("warn rfid close:{}", e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// public static void main(String[] args) throws IOException, InterruptedException {
|
|
|
|
|
// RFIDSocketNew rfid = new RFIDSocketNew("127.0.0.1",5002);
|
|
|
|
|
// rfid.startCheck();
|
|
|
|
|
// rfid.readData();
|
|
|
|
|
// Thread.sleep(30000);
|
|
|
|
|
// rfid.close();
|
|
|
|
|
// System.out.println(rfid.getTags());
|
|
|
|
|
//// 03 01 B0 AC
|
|
|
|
|
//
|
|
|
|
|
// byte[]bytes = new byte[5];
|
|
|
|
|
// bytes[0] = (byte)0xa0;
|
|
|
|
|
// bytes[1] = (byte)0x03;
|
|
|
|
|
// bytes[2] = (byte)0x01;
|
|
|
|
|
// bytes[3] = (byte)0xb0;
|
|
|
|
|
// bytes[4] = (byte) calculateChecksum(bytes);
|
|
|
|
|
//// int b = ;
|
|
|
|
|
// System.out.println((byte)0xac);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算与C语言中一致的校验和:补码求和方式
|
|
|
|
|
*
|
|
|
|
|
* @param buffer 输入字节数组(不包含 Check 字段)
|
|
|
|
|
* @return 校验和(0x00 ~ 0xFF 的无符号值,以 int 形式返回)
|
|
|
|
|
*/
|
|
|
|
|
public static byte[] calculateChecksum(byte[] buffer) {
|
|
|
|
|
// 1. 创建子数组,排除最后一个字节
|
|
|
|
|
byte[] data = new byte[buffer.length - 1];
|
|
|
|
|
System.arraycopy(buffer, 0, data, 0, data.length);
|
|
|
|
|
|
|
|
|
|
// 2. 计算校验和
|
|
|
|
|
int sum = 0;
|
|
|
|
|
for (byte b : data) {
|
|
|
|
|
sum += b & 0xFF; // 转为无符号 int
|
|
|
|
|
}
|
|
|
|
|
sum &= 0xFF; // 取低8位
|
|
|
|
|
int checksum = (~sum + 1) & 0xFF; // 补码 + 屏蔽高位
|
|
|
|
|
|
|
|
|
|
// 3. 写入校验和到 buffer 最后一个位置
|
|
|
|
|
buffer[buffer.length - 1] = (byte) checksum;
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean calculateCheck(byte[] buffer) {
|
|
|
|
|
int sum = 0;
|
|
|
|
|
for (int i = 0; i < buffer.length - 1; i++) {
|
|
|
|
|
sum += buffer[ i] & 0xFF; // 将 byte 转换为无符号 int(0~255)
|
|
|
|
|
}
|
|
|
|
|
sum &= 0xFF; // 取低8位
|
|
|
|
|
int checksum = (~sum + 1) & 0xFF; // 补码 + 屏蔽高位
|
|
|
|
|
return sum == buffer[buffer.length - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析RFID返回的数据包
|
|
|
|
|
*
|
|
|
|
|
* @param packet byte数组,包含完整数据包
|
|
|
|
|
*/
|
|
|
|
|
public static String parse6C(byte[] packet) {
|
|
|
|
|
if (packet == null || packet.length < 8) {
|
|
|
|
|
System.out.println("数据包为空或长度不足");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 1: 检查 Head 是否为 0xA0
|
|
|
|
|
if (packet[0] != (byte) 0xA0) {
|
|
|
|
|
System.out.println("无效的数据包头: " + java.lang.String.format("%02X", packet[0]));
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: 获取 Len 字段
|
|
|
|
|
int len = packet[1] & 0xFF; // 不包含 Len 自身
|
|
|
|
|
if (packet.length != 2 + len) { // Head(1) + Len(1) + 数据(len) + Check(1)
|
|
|
|
|
System.out.println("数据包长度不匹配");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 3: 验证校验和
|
|
|
|
|
if (!calculateCheck(packet)) {
|
|
|
|
|
System.out.println("校验失败,数据可能损坏");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 4: 解析各个字段
|
|
|
|
|
int offset = 2; // Head + Len = 偏移2
|
|
|
|
|
|
|
|
|
|
byte address = packet[offset++];
|
|
|
|
|
byte cmd = packet[offset++];
|
|
|
|
|
byte freqAnt = packet[offset++];
|
|
|
|
|
|
|
|
|
|
// 提取 FreqAnt 的高6位(频点) 和 低2位(天线号)
|
|
|
|
|
int freqPoint = (freqAnt & 0xFC) >>> 2; // 高6位
|
|
|
|
|
int antennaNo = (freqAnt & 0x03); // 低2位
|
|
|
|
|
|
|
|
|
|
// Step 5: PC字段(2字节)
|
|
|
|
|
byte[] pcBytes = new byte[2];
|
|
|
|
|
System.arraycopy(packet, offset, pcBytes, 0, 2);
|
|
|
|
|
offset += 2;
|
|
|
|
|
|
|
|
|
|
// Step 6: RSSI(1字节)
|
|
|
|
|
byte rssiByte = packet[offset + 1];
|
|
|
|
|
int rssi = rssiByte & 0xFF; // 转无符号int
|
|
|
|
|
|
|
|
|
|
// Step 7: EPC(剩余字段)
|
|
|
|
|
int epcLength = len - 5; // Len - (Address + Cmd + FreqAnt + PC + RSSI)
|
|
|
|
|
byte[] epcBytes = new byte[epcLength];
|
|
|
|
|
System.arraycopy(packet, offset, epcBytes, 0, epcLength);
|
|
|
|
|
offset += epcLength;
|
|
|
|
|
|
|
|
|
|
// Step 8: 输出解析结果
|
|
|
|
|
System.out.println("Head: " + java.lang.String.format("%02X", packet[0] & 0xFF));
|
|
|
|
|
System.out.println("Len: " + len);
|
|
|
|
|
System.out.println("Address: " + java.lang.String.format("%02X", address & 0xFF));
|
|
|
|
|
System.out.println("Cmd: " + java.lang.String.format("%02X", cmd & 0xFF));
|
|
|
|
|
System.out.println("FreqAnt: " + java.lang.String.format("%02X", freqAnt & 0xFF));
|
|
|
|
|
System.out.println(" 频点: " + freqPoint);
|
|
|
|
|
System.out.println(" 天线号: " + antennaNo);
|
|
|
|
|
System.out.println("PC: " + bytesToHex(pcBytes));
|
|
|
|
|
System.out.println("EPC: " + bytesToHex(epcBytes));
|
|
|
|
|
System.out.println("RSSI: " + rssi + " dBm");
|
|
|
|
|
System.out.println("Check: " + java.lang.String.format("%02X", packet[packet.length - 1] & 0xFF));
|
|
|
|
|
return bytesToHex(epcBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 校验和验证方法:对除Check外的所有字节求和后补码
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将 byte[] 转换为 Hex 字符串
|
|
|
|
|
*/
|
|
|
|
|
private static String bytesToHex(byte[] bytes) {
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
for (byte b : bytes) {
|
|
|
|
|
sb.append(java.lang.String.format("%02X ", b & 0xFF));
|
|
|
|
|
}
|
|
|
|
|
return sb.toString().trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String parse(byte[] byteArray) {
|
|
|
|
|
if (byteArray == null ) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cmd == CMD.REAL_TIME_INVENTORY) {
|
|
|
|
|
return parse6C(byteArray);
|
|
|
|
|
} else {
|
|
|
|
|
return parse6B(byteArray);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析RFID返回的数据包
|
|
|
|
|
*
|
|
|
|
|
* @param packet byte数组,包含完整数据包
|
|
|
|
|
*/
|
|
|
|
|
public static String parse6B(byte[] packet) {
|
|
|
|
|
if (packet == null || packet.length < 8) { // 最小长度:Head(1)+Len(1)+Address(1)+Cmd(1)+AntID(1)+UID(8)+Check(1)=12
|
|
|
|
|
System.out.println("数据包为空或长度不足");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 1: 检查 Head 是否为 0xA0
|
|
|
|
|
if (packet[0] != (byte) 0xA0) {
|
|
|
|
|
System.out.println("无效的数据包头: " + java.lang.String.format("%02X", packet[0]));
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: 获取 Len 字段
|
|
|
|
|
int len = packet[1] & 0xFF; // 不包含 Len 自身
|
|
|
|
|
if (packet.length != 2 + len) { // Head(1) + Len(1) + 数据(len) + Check(1)
|
|
|
|
|
System.out.println("数据包长度不匹配");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 3: 验证校验和
|
|
|
|
|
// if (!calculateCheck(packet)) {
|
|
|
|
|
// System.out.println("校验失败,数据可能损坏");
|
|
|
|
|
// return "";
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Step 4: 解析各个字段
|
|
|
|
|
int offset = 2; // Head + Len = 偏移2
|
|
|
|
|
|
|
|
|
|
byte address = packet[offset++];
|
|
|
|
|
byte cmd = packet[offset++];
|
|
|
|
|
byte antId = packet[offset++];
|
|
|
|
|
|
|
|
|
|
// Step 5: UID(8字节)
|
|
|
|
|
byte[] uidBytes = new byte[8];
|
|
|
|
|
System.arraycopy(packet, offset, uidBytes, 0, 8);
|
|
|
|
|
offset += 8;
|
|
|
|
|
|
|
|
|
|
// Step 6: 输出解析结果
|
|
|
|
|
System.out.println("Head: " + java.lang.String.format("%02X", packet[0] & 0xFF));
|
|
|
|
|
System.out.println("Len: " + len);
|
|
|
|
|
System.out.println("Address: " + java.lang.String.format("%02X", address & 0xFF));
|
|
|
|
|
System.out.println("Cmd: " + java.lang.String.format("%02X", cmd & 0xFF));
|
|
|
|
|
System.out.println("AntID: " + java.lang.String.format("%02X", antId & 0xFF));
|
|
|
|
|
System.out.println("UID: " + bytesToHex(uidBytes));
|
|
|
|
|
System.out.println("Check: " + java.lang.String.format("%02X", packet[packet.length - 1] & 0xFF));
|
|
|
|
|
return bytesToHex(uidBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
// A0 0A FF 89 05 01 02 03 04 05 01
|
|
|
|
|
|
|
|
|
|
System.out.println(parse6B(calculateChecksum(new byte[]{(byte) 0xA0, 0x0C, (byte) 0xFF, (byte) 0xb0, 0x05, 0x01,0x01, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01,0x00})));
|
|
|
|
|
|
|
|
|
|
RFIDSocketNew rfidSocket = new RFIDSocketNew("127.0.0.1", 6000,"6B");
|
|
|
|
|
|
|
|
|
|
// rfidSocket.startCheck();
|
|
|
|
|
rfidSocket.readData();
|
|
|
|
|
try {
|
|
|
|
|
Thread.sleep(30000);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
}
|
|
|
|
|
rfidSocket.close();
|
|
|
|
|
System.out.println(rfidSocket.getTags());
|
|
|
|
|
}
|
|
|
|
|
}
|