我使用的UHF读写器动态库是32位的,所以需要jdk也是32位的,不然运行就会报错。上位机应用程序通过UHFREADER86.DLL操作EPCC1-G2格式电子标签读写器
安装32位JDK
可以去官网下载jdk-1.8(x86)的安装包
创建java项目
可以创建java基础项目。也可以使用springboot项目,我这边使用的是springboot
导入jna依赖包
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.7.0</version>
</dependency>
放置动态库
springboot项目可直接放在resource目录下,也可以自行创建目录
动态库调用的几个方法
使用jna调取C语言的动态库,找到文档中需要调用的方法
1. 连接读写器设备方法:
int OpenComPort(int Port, unsigned char *ComAdr, unsigned char Baud,int *FrmHandle);
2. 关闭指定连接设备
int CloseSpecComPort(int FrmHandle);
3. 带缓存的询查方法
int InventoryBuffer_G2(unsigned char *ComAdr, unsigned char QValue, unsigned char Session,unsigned char MaskMem,unsigned char *MaskAdr,unsigned char MaskLen,unsigned char * MaskData, unsigned char MaskFlag, unsigned char AdrTID, unsigned char LenTID, unsigned char TIDFlag, unsigned char Target, unsigned char InAnt, unsigned char Scantime, unsigned char Fastflag, int * BufferCount, int *TagNum,int FrmHandle);
4. 读取缓存数据方法
int ReadBuffer_G2(unsigned char *ComAdr, int *Totallen, int *CardNum, unsigned char *pEPCList, int FrmHandle);
5. 查询缓存的标签数量
Int GetBufferCnt_G2(unsigned char *ComAdr , int *Count,int FrmHandle);
6. 清理缓存数据
Int ClearBuffer_G2(unsigned char *ComAdr ,int FrmHandle);
java使用jna调用
编写jna调用类
package com.ljd.bowei.service;
import com.ljd.bowei.common.util.StrUtil;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
/**
* <p> 描述:UHF 读写器动态库使用 </p>
* 4.其他返回值定义
* #define InventoryReturnEarly_G2 0x01 询查时间结束前返回
* #define InventoryTimeOut_G2 0x02 指定的询查时间溢出
* #define InventoryMoreData_G2 0x03 本条消息之后,还有消息
* #define ReadermoduleMCUFull_G2 0x04 读写模块存储空间已满
* #define AccessPasswordError 0x05 访问密码错误
* #define DestroyPasswordError 0x09 销毁密码错误
* #define DestroyPasswordCannotZero 0x0a 销毁密码不能为全0
* #define TagNotSupportCMD 0x0b 电子标签不支持该命令
* #define AccessPasswordCannotZero 0x0c 对该命令,访问密码不能为0
* #define TagProtectedCannotSetAgain 0x0d 电子标签已经被设置了读保护,不能再次设置
* #define TagNoProtectedDonotNeedUnlock 0x0e 电子标签没有被设置读保护,不需要解锁
* #define ByteLockedWriteFail 0x10 有字节空间被锁定,写入失败
* #define CannotLock 0x11 不能锁定
* #define LockedCannotLockAgain 0x12 已经锁定,不能再次锁定
* #define ParameterSaveFailCanUseBeforeNoPower 0x13 参数保存失败,但设置的值在读写模块断电前有效
* #define CannotAdjust 0x14 无法调整
* #define InventoryReturnEarly_6B 0x15 询查时间结束前返回
* #define InventoryTimeOut_6B 0x16 指定的询查时间溢出
* #define InventoryMoreData_6B 0x17 本条消息之后,还有消息
* #define ReadermoduleMCUFull_6B 0x18 读写模块存储空间已满
* #define NotSupportCMDOrAccessPasswordCannotZero 0x19 电子不支持该命令或者访问密码不能为0
* #define CMDExecuteErr 0xF9 命令执行出错
* #define GetTagPoorCommunicationCannotOperation 0xFA 有电子标签,但通信不畅,无法操作
* #define NoTagOperation 0xFB 无电子标签可操作
* #define TagReturnErrorCode 0xFC 电子标签返回错误代码
* #define CMDLengthWrong 0xFD 命令长度错误
* #define IllegalCMD 0xFE 不合法的命令
* #define ParameterError 0xFF 参数错误
* #define CommunicationErr 0x30 通讯错误
* #define RetCRCErr 0x31 CRC校验错误
* #define RetDataErr 0x32 返回数据长度有错误
* #define CommunicationBusy 0x33 通讯繁忙,设备正在执行其他指令
* #define ExecuteCmdBusy 0x34 繁忙,指令正在执行
* #define ComPortOpened 0x35 端口已打开
* #define ComPortClose 0x36 端口已关闭
* #define InvalidHandle 0x37 无效句柄
* #define InvalidPort 0x38 无效端口
* #define RecmdErr 0XEE返回指令错误
* 5.错误代码定义
* #define OtherError 0x00 其它错误,全部捕捉未被其它代码覆盖的错误
* #define MemoryOutPcNotSupport 0x03 存储器超限或不被支持的PC值,规定存储位置不存在或标签不支持PC值
* #define MemoryLocked 0x04 存储器锁定,存储位置锁定或永久锁定,且不可写入
* #define NoPower 0x0b 电源不足,标签电源不足,无法执行存储写入操作
* #define NotSpecialError 0x0f 非特定错误,标签不支持特定错误代码
*
* @author wlp
* @version 1.0.0
* @date 2021/11/4 17:25
*/
public interface UHFReaderLibrary extends Library {
UHFReaderLibrary INSTANCE = Native.load( "/UHFReader86.dll", UHFReaderLibrary.class);
/**
* <p> 方法描述: 连接到指定串口
* 该函数用于指定串口初始化,并通过连接串口和读写器以创建通信连接。数据传输协议是默认波特率57600bps,8位数据,1位停止位,没有奇偶校验位。
* 在调用其它函数之前,您必须先连接串口和读写器。
* </p>
*
* @param Port 同上
* @param ComAdr 同上
* @param Baud 同上
* @param FrmHandle 同上
* @return int 如果该函数调用成功,返回一个零值
* @author wlp
* @date 2021/11/4 17:37
*/
int OpenComPort(int Port, PointerByReference ComAdr, String Baud, IntByReference FrmHandle);
/**
* <p> 方法描述: 关闭指定串口 该函数用于关闭指定串口。</p>
*
* @param FrmHandle 输入变量,与读写器连接端口对应的句柄,应用程序通过该句柄可以操作连接在相应端口的读写器。
* @return int 如果该函数调用成功,返回一个零值。否则,返回非零值请查看其他返回值定义,返回的错误代码请查看错误代码定义。
* @author wlp
* @date 2021/11/4 17:38
*/
int CloseSpecComPort(int FrmHandle);
/**
* <p> 方法描述: 该命令用于获取读写器存储区中所有标签信息。响应完成后,缓存中的数据并不丢失,可以多次提取。</p>
*
* @param ComAdr 输入变量,读写器地址;
* @param Totallen 输出变量,返回的pEPCList数组字节大小;
* @param CardNum 输出变量,返回的标签张数;
* @param pEPCList 输出数组,大小是Totallen个字节,读取的标签信息;
* 缓存中每个电子标签的EPC/TID数据。
* pEPCList
* Ant Len EPC/TID RSSI Count
* 0xXX 0xXX nBytes 0xXX 0xXX
* @param FrmHandle 输入变量,返回与读写器连接端口对应的句柄,应用程序通过该句柄可以操作连接在相应端口的读写器。如果打开不成功,返回的句柄值为-1。
* @return int
* @author wlp
* @date 2021/11/4 18:53
*/
int ReadBuffer_G2(PointerByReference ComAdr, IntByReference Totallen, IntByReference CardNum, byte[] pEPCList, int FrmHandle);
/**
* <p> 方法描述: 该命令用于清空读写器存储区中所有标签信息。</p>
*
* @param ComAdr 输入变量,读写器地址
* @param FrmHandle 输入变量,返回与读写器连接端口对应的句柄,应用程序通过该句柄可以操作连接在相应端口的读写器。如果打开不成功,返回的句柄值为-1。
* @return int 如果该函数调用成功,返回一个零值。
* @author wlp
* @date 2021/11/4 18:51
*/
int ClearBuffer_G2(PointerByReference ComAdr, int FrmHandle);
/**
* <p> 方法描述: 该命令用于获取缓存区中的标签数量</p>
*
* @param ComAdr 输入变量,读写器地址.;
* @param Count 输出变量,缓存区中的标签数量;
* @param FrmHandle 输入变量,返回与读写器连接端口对应的句柄,应用程序通过该句柄可以操作连接在相应端口的读写器。如果打开不成功,返回的句柄值为-1。
* @return int
* @author wlp
* @date 2021/11/5 15:46
*/
int GetBufferCnt_G2(PointerByReference ComAdr, IntByReference Count, int FrmHandle);
/**
* <p> 方法描述: 带缓存询查命令,询查命令的作用是检查有效范围内是否有符合协议的电子标签存在</p>
*
* @param ComAdr 输入变量,读写器地址。
* @param QValue 输入变量,Q值,范围0-15;
* @param Session 输入变量,Session值,范围0-3;
* @param MaskMem 输入变量,一个字节,掩码区。0x01:EPC存储区;0x02:TID存储区;0x03:用户存储区。
* @param MaskAdr 输入数组,2个字节,掩码的起始位地址(单位:Bits)。范围0~16383。
* @param MaskLen 一个字节,掩码的位长度(单位:Bits)。
* @param MaskData 输入数组,掩码数据。MaskData数据字节长度是MaskLen/8。如果MaskLen不是8的整数倍,则MaskData数据字节长度为[MaskLen/8]取整再加1。不够的在低位补0。
* @param MaskFlag 输入变量,一个字节,掩码标记位,MaskFlag=1掩码,MaskFlag=0不掩码。
* @param AdrTID 输入变量,询查TID区的起始字地址。
* @param LenTID 输入变量,询查TID区的数据字数。LenTID取值为0~15。
* @param TIDFlag 输入变量, TIDFlag=1:表示询查TID区; TIDFlag=0:表示询查EPC;
* @param Target 1个字节,查询EPC标签时使用的Target值 0x00:Target值使用A; 0x01:Target值使用B;
* @param InAnt 1个字节,本次要进行查询的天线号,本模块固定0x80;
* @param Scantime 1个字节,本次命令查询的最大时间,范围3-255(*100ms);
* @param FastFlag 快速查询的标志位,为0时不启用,为1时启用,此时要指定Target,Inant,Scantime 3个参数。
* @param BufferCount 输出变量,缓存中记录的标签总数,相同 EPC/TID数据的标签将被视为同一张标签。若未清空缓存,标签数量为多次询查操作的数量累加。
* @param TagNum 输出变量,本次询查中读取标签的次数,不区分是否多次读取同一张标签。
* @param FrmHandle 输入变量,返回与读写器连接端口对应的句柄,应用程序通过该句柄可以操作连接在相应端口的读写器。如果打开不成功,返回的句柄值为-1。
* @return int 如果该函数调用成功,返回值:
* 0x01 询查时间结束前返回
* 0x02 询查时间结束使得询查退出
* 0x03 如果读到的标签数量无法在一条消息内传送完,将分多次发送。如果Status为0x0D,则表示这条数据结束后,还有数据。
* 0x04 还有电子标签未读取,电子标签数量太多,MCU存储不了
* 返回其他值,请查看其他返回值定义,返回的错误代码请查看错误代码定义。
* @author wlp
* @date 2021/11/5 16:19
*/
int InventoryBuffer_G2(PointerByReference ComAdr, byte QValue, byte Session, byte MaskMem, byte[] MaskAdr,
byte MaskLen, byte[] MaskData, byte MaskFlag, byte AdrTID, byte LenTID, byte TIDFlag,
byte Target, int InAnt, int Scantime, byte FastFlag, IntByReference BufferCount,
IntByReference TagNum, int FrmHandle);
}
class Test {
public static void main(String[] args) throws InterruptedException {
UHFReaderLibrary instance = UHFReaderLibrary.INSTANCE;
IntByReference frmHandle = new IntByReference();
PointerByReference comAdr = new PointerByReference();
// 打开连接
int openNum = instance.OpenComPort(4, comAdr, "57600", frmHandle);
if (openNum == 0) {
System.out.println("连接成功");
} else {
System.out.println("连接失败---》" + Integer.toHexString(openNum));
}
// 询查参数
byte[] MaskAdr = new byte[2];
byte[] MaskData = new byte[100];
byte QValue = 4;
byte Session = 1;
byte MaskMem = 0;
byte MaskLen = 0;
byte MaskFlag = 0;
byte AdrTID = 0;
byte LenTID = 6;
byte TIDFlag = 0;
byte Target = 0;
int InAnt = 0x80;
int Scantime = 3;
byte Fastflag = 1;
IntByReference BufferCount = new IntByReference();
IntByReference TagNum = new IntByReference();
// 调用询查方法
int InventoryBuffer_G2 = instance.InventoryBuffer_G2(comAdr, QValue, Session, MaskMem, MaskAdr, MaskLen, MaskData,
MaskFlag, AdrTID, LenTID, TIDFlag, Target, InAnt, Scantime, Fastflag, BufferCount, TagNum, frmHandle.getValue());
Thread.sleep(3000);
System.out.println("缓存中记录的标签总数---->" + BufferCount.getValue());
System.out.println("本次询查中读取标签的次数---->" + TagNum.getValue());
// 获取缓存中的标签数
IntByReference Count = new IntByReference();
instance.GetBufferCnt_G2(comAdr, Count, frmHandle.getValue());
System.out.println("缓存区中的标签数量---->" + Count.getValue());
IntByReference Totallen1 = new IntByReference(16);
byte[] pEPCList = new byte[Totallen1.getValue()];
IntByReference CardNum1 = new IntByReference();
// 读取缓存数据
int readNum = instance.ReadBuffer_G2(comAdr, Totallen1, CardNum1, pEPCList, frmHandle.getValue());
System.out.println("读取数据失败--->" + Integer.toHexString(readNum));
System.out.println(bytesToHexString(pEPCList));
// 清除缓存
instance.ClearBuffer_G2(comAdr, frmHandle.getValue());
int closeNum = instance.CloseSpecComPort(frmHandle.getValue());
if (closeNum == 0) {
System.out.println("关闭连接成功");
} else {
System.out.println("关闭连接失败" + Integer.toHexString(closeNum));
}
}
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (byte b : src) {
int v = b & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}
最后得到的数据:010cc2046700a208200806800009dc01
epc的格式 | ||||
Ant | Len | EPC/TID | RSSI | Count |
0xXX | 0xXX | nBytes | 0xXX | 0xXX |
解析后的标签epc: c2046700a208200806800009