We are trying to connect FX9500 using LLRP tool kit code. We would like to receive read tag as soon as they come into range. From messages it looks like all add/set config are done properly, but can't receive events.
Attached are code and XML output of messages being exchanged. XML Messages are at : http://gadgetnapps.blogspot.in/2016/02/llrp-xml-messages.html
Thanks in advance.
public class LLRPHelloWorld {
private static String ipAddress = null;
private static int readerPort = -1;
private Socket connection;
private DataOutputStream out;
private static int ROSPEC_ID = 999;
private static Logger logger;
private ReadThread rt = null;
static AppCtx ctxMain;
public static void rfidMain(String ipAdString, int port, AppCtx ctx) {
logger = Logger.getLogger(LLRPHelloWorld.class);
ipAddress = ipAdString;
readerPort = port;
ctxMain = ctx;
try {
new LLRPHelloWorld();
logger.info("LLRP Hello World has terminated");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* The constructor creates a connection to the reader and sends LLRP
* messages. It first sends a GET_READER_CAPABILIITIES message and a
* SET_READER_CONFIG message. Then it creates an ROSpec with null start and
* stop triggers. After it enables and starts the ROSpec. It waits for a few
* seconds to receive tag reads before it disables and deletes the ROSpec.
* Finally it ends the LLRP connection.
*
* @param ctx
*
* @throws IOException
*/
public LLRPHelloWorld() throws IOException {
// Try to establish a connection to the reader
connection = new Socket(ipAddress, readerPort);
out = new DataOutputStream(connection.getOutputStream());
// Start up the ReaderThread to read messages form socket to Console
rt = new ReadThread(connection);
rt.start();
// Wait for the NotificationEvent the Reader sends whenever a
// connection attempt is made
pause(250);
LLRPMessage m = rt.getNextMessage();
READER_EVENT_NOTIFICATION readerEventNotification = (READER_EVENT_NOTIFICATION) m;
ReaderEventNotificationData red = readerEventNotification
.getReaderEventNotificationData();
if (red.getConnectionAttemptEvent() != null) {
logger.info("Connection attempt was successful");
} else {
logger.error("Connection attempt was unsucessful");
System.exit(-1);
}
// Create a GET_READER_CAPABILITIES Message and send it to the reader
GET_READER_CAPABILITIES getReaderCap = new GET_READER_CAPABILITIES();
getReaderCap.setRequestedData(new GetReaderCapabilitiesRequestedData(
GetReaderCapabilitiesRequestedData.All));
write(getReaderCap, "GET_READER_CAPABILITIES");
pause(250);
// Create a SET_READER_CONFIG Message and send it to the reader
SET_READER_CONFIG setReaderConfig = createSetReaderConfig();
write(setReaderConfig, "SET_READER_CONFIG");
pause(250);
// CREATE an ADD_ROSPEC Message and send it to the reader
ADD_ROSPEC addROSpec = new ADD_ROSPEC();
addROSpec.setROSpec(createROSpec());
write(addROSpec, "ADD_ROSPEC");
pause(250);
// Create an ENABLE_ROSPEC message and send it to the reader
ENABLE_ROSPEC enableROSpec = new ENABLE_ROSPEC();
enableROSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
write(enableROSpec, "ENABLE_ROSPEC");
pause(250);
boolean flg = true;
START_ROSPEC startROSpec = new START_ROSPEC();
startROSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
write(startROSpec, "START_ROSPEC");
while (flg) {
// Create a START_ROSPEC message and send it to the reader
LLRPMessage msg = rt.getNextMessage();
try {
System.err.println(msg+"--->"+msg.toXMLString());
} catch (InvalidLLRPMessageException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// pause(4000);
// System.err.println("main test 4s");
// Create a STOP_ROSPEC message and send it to the reader
// STOP_ROSPEC stopROSpec = new STOP_ROSPEC();
// stopROSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
// write(stopROSpec, "STOP_ROSPEC");
//
// pause(4000);
// startROSpec = new START_ROSPEC();
// startROSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
// write(startROSpec, "START_ROSPEC");
//
}
// Create a DISABLE_ROSPEC message and send it to the reader
DISABLE_ROSPEC disableROSpec = new DISABLE_ROSPEC();
disableROSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
write(disableROSpec, "DISABLE_ROSPEC");
pause(250);
// Create a DELTE_ROSPEC message and send it to the reader
DELETE_ROSPEC deleteROSpec = new DELETE_ROSPEC();
deleteROSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
write(deleteROSpec, "DELETE_ROSPEC");
pause(250);
// wait for one second before closing the connection
pause(1000);
// Create a CLOSE_CONNECTION message and send it to the reader
CLOSE_CONNECTION cc = new CLOSE_CONNECTION();
write(cc, "CloseConnection");
synchronized (rt) {
try {
logger.debug("Wait for the Reader to close the Connection");
rt.wait();
// KEEPALIVE_ACK
} catch (InterruptedException e) {
// Quit the Program
}
}
}
/**
* This method creates a ROSpec with null start and stop triggers
*
* @return
*/
private ROSpec createROSpec() {
// create a new rospec
ROSpec roSpec = new ROSpec();
roSpec.setPriority(new UnsignedByte(0));
roSpec.setCurrentState(new ROSpecState(ROSpecState.Disabled));//rathi
roSpec.setROSpecID(new UnsignedInteger(ROSPEC_ID));
// set up ROBoundary (start and stop triggers)
ROBoundarySpec roBoundarySpec = new ROBoundarySpec();
ROSpecStartTrigger startTrig = new ROSpecStartTrigger();
startTrig.setROSpecStartTriggerType(new ROSpecStartTriggerType(
ROSpecStartTriggerType.Immediate));
// PeriodicTriggerValue pt =new PeriodicTriggerValue();
// pt.setPeriod(new UnsignedInteger(1));
// pt.setOffset(new UnsignedInteger(0));
// startTrig.setPeriodicTriggerValue(pt);
roBoundarySpec.setROSpecStartTrigger(startTrig);
ROSpecStopTrigger stopTrig = new ROSpecStopTrigger();
stopTrig.setDurationTriggerValue(new UnsignedInteger(0));
stopTrig.setROSpecStopTriggerType(new ROSpecStopTriggerType(
ROSpecStopTriggerType.Null));
roBoundarySpec.setROSpecStopTrigger(stopTrig);
roSpec.setROBoundarySpec(roBoundarySpec);
// Add an AISpec
AISpec aispec = new AISpec();
// set AI Stop trigger to null
AISpecStopTrigger aiStopTrigger = new AISpecStopTrigger();
aiStopTrigger.setAISpecStopTriggerType(new AISpecStopTriggerType(
AISpecStopTriggerType.Null));//null
aiStopTrigger.setDurationTrigger(new UnsignedInteger(0));
aispec.setAISpecStopTrigger(aiStopTrigger);
UnsignedShortArray antennaIDs = new UnsignedShortArray();
antennaIDs.add(new UnsignedShort(0));
aispec.setAntennaIDs(antennaIDs);
InventoryParameterSpec inventoryParam = new InventoryParameterSpec();
inventoryParam.setProtocolID(new AirProtocols(
AirProtocols.EPCGlobalClass1Gen2));
inventoryParam.setInventoryParameterSpecID(new UnsignedShort(1));
aispec.addToInventoryParameterSpecList(inventoryParam);
roSpec.addToSpecParameterList(aispec);
return roSpec;
}
/**
* This method creates a SET_READER_CONFIG method
*
* @return
*/
private SET_READER_CONFIG createSetReaderConfig() {
SET_READER_CONFIG setReaderConfig = new SET_READER_CONFIG();
// Create a default RoReportSpec so that reports are sent at the end of
// ROSpecs
ROReportSpec roReportSpec = new ROReportSpec();
roReportSpec.setN(new UnsignedShort(0));
roReportSpec.setROReportTrigger(new ROReportTriggerType(
ROReportTriggerType.Upon_N_Tags_Or_End_Of_ROSpec));
//Enable keep alive
// KeepaliveSpec ka = new KeepaliveSpec();
// KeepaliveTriggerType ktype = new KeepaliveTriggerType();
// ktype.set(KeepaliveTriggerType.Periodic);
// ka.setPeriodicTriggerValue(new UnsignedInteger(100));
// ka.setKeepaliveTriggerType(ktype);
// setReaderConfig.setKeepaliveSpec(ka);
//
TagReportContentSelector tagReportContentSelector = new TagReportContentSelector();
tagReportContentSelector.setEnableAccessSpecID(new Bit(0));
tagReportContentSelector.setEnableAntennaID(new Bit(1));
tagReportContentSelector.setEnableChannelIndex(new Bit(0));
tagReportContentSelector.setEnableFirstSeenTimestamp(new Bit(0));
tagReportContentSelector.setEnableInventoryParameterSpecID(new Bit(1));
tagReportContentSelector.setEnableLastSeenTimestamp(new Bit(0));
tagReportContentSelector.setEnablePeakRSSI(new Bit(0));
tagReportContentSelector.setEnableROSpecID(new Bit(1));
tagReportContentSelector.setEnableSpecIndex(new Bit(0));
tagReportContentSelector.setEnableTagSeenCount(new Bit(0));
// tagReport.
C1G2EPCMemorySelector epcMemSel = new C1G2EPCMemorySelector();
epcMemSel.setEnableCRC(new Bit(0));
epcMemSel.setEnablePCBits(new Bit(0));
tagReportContentSelector
.addToAirProtocolEPCMemorySelectorList(epcMemSel);
roReportSpec.setTagReportContentSelector(tagReportContentSelector);
setReaderConfig.setROReportSpec(roReportSpec);
// Set default AccessReportSpec
AccessReportSpec accessReportSpec = new AccessReportSpec();
accessReportSpec.setAccessReportTrigger(new AccessReportTriggerType(
AccessReportTriggerType.End_Of_AccessSpec));
setReaderConfig.setAccessReportSpec(accessReportSpec);
// Set up reporting for AISpec events, ROSpec events, and GPI Events
ReaderEventNotificationSpec eventNoteSpec = new ReaderEventNotificationSpec();
EventNotificationState noteState = new EventNotificationState();
noteState.setEventType(new NotificationEventType(
NotificationEventType.AISpec_Event));
noteState.setNotificationState(new Bit(1));
eventNoteSpec.addToEventNotificationStateList(noteState);
noteState = new EventNotificationState();
noteState.setEventType(new NotificationEventType(
NotificationEventType.ROSpec_Event));
noteState.setNotificationState(new Bit(1));
eventNoteSpec.addToEventNotificationStateList(noteState);
noteState = new EventNotificationState();
noteState.setEventType(new NotificationEventType(
NotificationEventType.GPI_Event));
noteState.setNotificationState(new Bit(1));
eventNoteSpec.addToEventNotificationStateList(noteState);
noteState = new EventNotificationState();
noteState.setEventType(new NotificationEventType(
NotificationEventType.Antenna_Event));
noteState.setNotificationState(new Bit(1));
eventNoteSpec.addToEventNotificationStateList(noteState);
setReaderConfig.setReaderEventNotificationSpec(eventNoteSpec);
setReaderConfig.setResetToFactoryDefault(new Bit(0));
return setReaderConfig;
}
/**
* This method causes the calling thread to sleep for a specified number of
* milliseconds
*
* @param ms
*/
private void pause(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Send a llrp message to the reader
*
* @param msg
* Message to be send
* @param message
* Description for output purposes
*/
private void write(LLRPMessage msg, String message) {
try {
logger.info(" Sending message: \n" + msg.toXMLString());
out.write(msg.encodeBinary());
} catch (IOException e) {
logger.error("Couldn't send Command ", e);
} catch (InvalidLLRPMessageException e) {
logger.error("Couldn't send Command", e);
}
}
/**
*
* This class is a allows LLRP messages to be read on a separate thread
*
* @author Kyle Neumeier
* @author Andreas Huebner
*
*/
class ReadThread extends Thread {
/**
* The incoming data stream from the LLRP reader connection
*/
private DataInputStream inStream = null;
/**
* The socket for the connection to the LLRP Reader
*/
private Socket socket = null;
/**
* A queue to store incoming LLRP Messages
*/
private LinkedBlockingQueue<LLRPMessage> queue = null;
/**
* Thread for constant reading of the stream
*
* @param inStream
*/
public ReadThread(Socket socket) {
this.socket = socket;
this.queue = new LinkedBlockingQueue<LLRPMessage>();
try {
this.inStream = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
logger.error("Cannot get input stream", e);
}
}
@Override
public void run() {
int i = 0;
super.run();
if (socket.isConnected()) {
while (!socket.isClosed()) {
LLRPMessage message = null;
try {
message = read();
if (message != null) {
queue.put(message);
logger.info("Received Message: \n"
+ message);//.toXMLString());
if (message instanceof org.llrp.ltk.generated.messages.RO_ACCESS_REPORT) {
// logger.info("Received Message: \n"
// + message.toXMLString());
RO_ACCESS_REPORT re = (RO_ACCESS_REPORT) message;
java.util.List<TagReportData> list = re
.getTagReportDataList();
for (TagReportData tagReportData : list) {
if (tagReportData.getEPCParameter() instanceof EPC_96) {
EPC_96 epc = (EPC_96) tagReportData
.getEPCParameter();
System.err
.println("=====================================>>>>>>>>>>>>>>>>>"
+ epc.getEPC());
// sendWebMessage(epc.getEPC(),i++);
}
}
}
} else {
logger.info("closing socket");
socket.close();
}
} catch (IOException e) {
logger.error("Error while reading message", e);
} catch (InvalidLLRPMessageException e) {
logger.error("Error while reading message", e);
} catch (InterruptedException e) {
logger.error("Error while reading message", e);
}
}
}
}
private void sendWebMessage(Integer96_HEX epc, int i)
throws InterruptedException {
WebMessage cmd = new WebMessage();
String url;
if (i % 2 == 0)
url = ctxMain.getWorker().getAddLogUrl() + "/" + epc;
else
url = ctxMain.getWorker().getTransationUrl() + "/" + epc;
cmd.setUrl(url);
System.out.println(" id " + url);
cmd.setMessage(new String("{}"));
ctxMain.sendWebMessage(cmd);
}
/**
* Read everything from the stream until the socket is closed
*
* @throws InvalidLLRPMessageException
*/
public LLRPMessage read() throws IOException,
InvalidLLRPMessageException {
LLRPMessage m = null;
// The message header
byte[] first = new byte[6];
// the complete message
byte[] msg;
// Read in the message header. If -1 is read, there is no more
// data available, so close the socket
if (inStream.read(first, 0, 6) == -1) {
return null;
}
int msgLength = 0;
try {
// calculate message length
msgLength = calculateLLRPMessageLength(first);
} catch (IllegalArgumentException e) {
throw new IOException("Incorrect Message Length");
}
/*
* the rest of bytes of the message will be stored in here before
* they are put in the accumulator. If the message is short, all
* messageLength-6 bytes will be read in here at once. If it is
* long, the data might not be available on the socket all at once,
* so it make take a couple of iterations to read in all the bytes
*/
byte[] temp = new byte[msgLength - 6];
// all the rest of the bytes will be put into the accumulator
ArrayList<Byte> accumulator = new ArrayList<Byte>();
// add the first six bytes to the accumulator so that it will
// contain all the bytes at the end
for (byte b : first) {
accumulator.add(b);
}
// the number of bytes read on the last call to read()
int numBytesRead = 0;
// read from the input stream and put bytes into the accumulator
// while there are still bytes left to read on the socket and
// the entire message has not been read
while (((msgLength - accumulator.size()) != 0)
&& numBytesRead != -1) {
numBytesRead = inStream.read(temp, 0,
msgLength - accumulator.size());
for (int i = 0; i < numBytesRead; i++) {
accumulator.add(temp[i]);
}
}
if ((msgLength - accumulator.size()) != 0) {
throw new IOException("Error: Discrepency between message size"
+ " in header and actual number of bytes read");
}
msg = new byte[msgLength];
// copy all bytes in the accumulator to the msg byte array
for (int i = 0; i < accumulator.size(); i++) {
msg[i] = accumulator.get(i);
}
// turn the byte array into an LLRP Message Object
m = LLRPMessageFactory.createLLRPMessage(msg);
return m;
}
/**
* Send in the first 6 bytes of an LLRP Message
*
* @param bytes
* @return
*/
private int calculateLLRPMessageLength(byte[] bytes)
throws IllegalArgumentException {
long msgLength = 0;
int num1 = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
num1 = ((unsignedByteToInt(bytes[2])));
num1 = num1 << 32;
if (num1 > 127) {
throw new RuntimeException(
"Cannot construct a message greater than "
+ "2147483647 bytes (2^31 - 1), due to the fact that there are "
+ "no unsigned ints in java");
}
num2 = ((unsignedByteToInt(bytes[3])));
num2 = num2 << 16;
num3 = ((unsignedByteToInt(bytes[4])));
num3 = num3 << 8;
num4 = (unsignedByteToInt(bytes[5]));
msgLength = num1 + num2 + num3 + num4;
if (msgLength < 0) {
throw new IllegalArgumentException(
"LLRP message length is less than 0");
} else {
return (int) msgLength;
}
}
/**
* From http://www.rgagnon.com/javadetails/java-0026.html
*
* @param b
* @return
*/
private int unsignedByteToInt(byte b) {
return (int) b & 0xFF;
}
/**
* Receive the next Message
*
* @return returns the Message form the Queue and removes it. It blocks
* if there is no Message.
*/
public LLRPMessage getNextMessage() {
LLRPMessage m = null;
try {
m = queue.take();
} catch (InterruptedException e) {
// nothing
}
return m;
}
}
}
You have to need write report after the startRoSpec then you get tagids.
You can get class from : https://github.com/kaansey/JAVA-LLRP-RFIDTags