org.rifidi.emulator.reader.llrp.report.LLRPReportController.java Source code

Java tutorial

Introduction

Here is the source code for org.rifidi.emulator.reader.llrp.report.LLRPReportController.java

Source

/*
 *  LLRPReportController.java
 *
 *  Created:   Jun 20, 2006
 *  Project:   RiFidi Emulator - A Software Simulation Tool for RFID Devices
 *              http://www.rifidi.org
 *              http://rifidi.sourceforge.net
 *  Copyright:   Pramari LLC and the Rifidi Project
 *  License:   Lesser GNU Public License (LGPL)
 *              http://www.opensource.org/licenses/lgpl-license.html
 */
package org.rifidi.emulator.reader.llrp.report;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rifidi.emulator.io.comm.Communication;
import org.rifidi.emulator.io.comm.CommunicationException;
import org.rifidi.emulator.io.comm.ip.tcpclient.TCPClientCommunication;
import org.rifidi.emulator.io.comm.ip.tcpserver.TCPServerCommunication;
import org.rifidi.emulator.reader.llrp.module.LLRPReaderSharedResources;
import org.rifidi.tags.enums.TagGen;
import org.rifidi.tags.impl.RifidiTag;

import edu.uark.csce.llrp.AntennaID;
import edu.uark.csce.llrp.C1G2CRC;
import edu.uark.csce.llrp.C1G2PC;
import edu.uark.csce.llrp.ChannelIndex;
import edu.uark.csce.llrp.CloseConnectionResponse;
import edu.uark.csce.llrp.ConnectionCloseEvent;
import edu.uark.csce.llrp.EPC96;
import edu.uark.csce.llrp.EPCData;
import edu.uark.csce.llrp.FirstSeenTimestampUTC;
import edu.uark.csce.llrp.FirstSeenTimestampUptime;
import edu.uark.csce.llrp.InventoryParameterSpecID;
import edu.uark.csce.llrp.KeepAlive;
import edu.uark.csce.llrp.LLRPStatus;
import edu.uark.csce.llrp.LastSeenTimestampUTC;
import edu.uark.csce.llrp.LastSeenTimestampUptime;
import edu.uark.csce.llrp.PeakRSSI;
import edu.uark.csce.llrp.ROAccessReport;
import edu.uark.csce.llrp.ReaderEventNotification;
import edu.uark.csce.llrp.ReaderEventNotificationData;
import edu.uark.csce.llrp.SpecIndex;
import edu.uark.csce.llrp.TagReportData;
import edu.uark.csce.llrp.TagSeenCount;
import edu.uark.csce.llrp.UTCTimestamp;

/**
 * This class will form a report when triggered, and send it out over the
 * communication it has been given.
 * 
 * @author Matthew Dean - matt@pramari.com
 */
public class LLRPReportController {

    /**
     * The logger for this class.
     */
    private static Log logger = LogFactory.getLog(LLRPReportController.class);

    /**
     * The communication that this ReportController has.
     */
    private Communication comm;

    private boolean locked = false;

    /**
     * Makes a new LLRPReportController.
     * 
     * @param comm
     */
    LLRPReportController() {
    }

    /**
     * Sends a report of tags TagList using the parameters specified in format.
     * 
     * @param tagList
     *            The list of tags that will be sent out.
     * @param format
     *            The format that defines how the report looks.
     * @param ROSpecID
     *            The ROSpec that generated the report.
     * @param maxNumTRDs
     *            The maximum number of TagReportData parameters per report.
     *            This corresponds to the N tag trigger in the RoReportSpec. If
     *            N =0, it will send all reports. If there are more TRDs
     *            collected than N, then we will send more than one report.
     */
    public void sendAllReports(LLRPReaderSharedResources llrpsr, int maxNumTRDs) {

        ArrayList<TagReportData> listOfData = llrpsr.getTagReportDataEntries().getAllDataEntries();
        if (maxNumTRDs == 0 || (maxNumTRDs > listOfData.size())) {
            sendNTRDs(listOfData, listOfData.size());
        } else {
            while (listOfData.size() > maxNumTRDs) {
                sendNTRDs(listOfData, maxNumTRDs);
            }
            sendNTRDs(listOfData, listOfData.size());
        }
    }

    /**
     * This methods sends 
     * @param listOfData
     * @param numToSend
     */
    private void sendNTRDs(ArrayList<TagReportData> listOfData, int numToSend) {
        byte[] retVal = null;
        ROAccessReport report = new ROAccessReport();
        if (numToSend >= listOfData.size()) {
            for (TagReportData trd : listOfData) {
                report.addTagReportDataParam(trd);
            }
            listOfData.clear();
        } else {
            ArrayList<TagReportData> toDelete = new ArrayList<TagReportData>();
            for (int i = 0; i < numToSend; i++) {
                report.addTagReportDataParam(listOfData.get(i));
                toDelete.add(listOfData.get(i));
            }
            for (TagReportData trd : toDelete) {
                listOfData.remove(trd);
            }
        }

        try {
            retVal = report.serialize();
            if (comm.isConnected() && !this.locked) {
                logger.debug("Sending a report...");
                comm.sendBytes(retVal);
            } else {
                logger.error("There is a lost report");
            }
        } catch (CommunicationException e) {
            logger.error("There was a problem when " + "trying to send the report message");
        } catch (IOException e) {
            logger.error("There was a problem when " + "trying to serialize the Report message");
            e.printStackTrace();
        }
    }

    public void sendReport(TagReportData trd) {
        byte[] retVal = null;
        ROAccessReport report = new ROAccessReport();
        report.addTagReportDataParam(trd);
        try {
            retVal = report.serialize();
            if (comm.isConnected() && !this.locked) {
                logger.debug("Sending a Report...");
                comm.sendBytes(retVal);
            } else {
                logger.error("Could not send report");
            }
        } catch (CommunicationException e) {
            logger.error("There was a problem when " + "trying to send the report message");
        } catch (IOException e) {
            logger.error("There was a problem when " + "trying to serialize the Report message");
            e.printStackTrace();
        }
    }

    public static TagReportData formatTagReport(ROReportFormat format, RifidiTag tag, int ROSpecID, int specIndex,
            LLRPReaderSharedResources llrpsr) {

        if (format == null) {
            format = llrpsr.getProperties().roReportFormat_Global;
        }

        TagReportData trd = new TagReportData();

        byte[] bytes = tag.getTag().readId();
        if (bytes.length == 12) {
            EPC96 epcdata = new EPC96();
            epcdata.setData(bytes);
            trd.setEPCDataParam(epcdata);
        } else {
            // EPCTag
            EPCData epcdata = new EPCData();
            epcdata.setData(bytes);
            trd.setEPCDataParam(epcdata);
        }

        if (format.enableAntennaID) {
            AntennaID aid = new AntennaID();
            aid.setAntennaID((short) (tag.getAntennaLastSeen() + 1));
            trd.setAntennaIDParam(aid);
        }
        if (format.enableChannelIndex) {
            /* TODO: get channel index from property map */
            logger.debug("Channel Index reporting " + "not yet supported.  Default is 0");
            ChannelIndex ci = new ChannelIndex();
            ci.setChannelIndex((short) 0);
            trd.setChannelIndexParam(ci);
        }
        if (format.enableFirstSeenTimestamp) {
            long readTime = tag.getDiscoveryDate().getTime();

            if (llrpsr.getProperties().hasUTCClockCapabilities) {
                FirstSeenTimestampUTC fstutc = new FirstSeenTimestampUTC();
                fstutc.setMicroseconds(readTime * 1000);
                trd.setFirstSeenTimestampUTCParam(fstutc);

            } else {
                FirstSeenTimestampUptime fstu = new FirstSeenTimestampUptime();

                fstu.setMicroseconds(llrpsr.getUptime(readTime) * 1000);
                trd.setFirstSeenTimestampUptimeParam(fstu);

            }

        }
        if (format.enableInventoryParamaterSpecID) {
            /* TODO: IPSpecID not yet supported */
            logger.debug("Inventory Paramater SpecID" + " not yet supported.  Default is 0");
            InventoryParameterSpecID ipsid = new InventoryParameterSpecID();
            ipsid.setInventoryParamSpecID((short) 0);
            trd.setInventoryParameterSpecIDParam(ipsid);

        }
        if (format.enableLastSeenTimestamp) {
            long readTime = tag.getLastSeenDate().getTime();

            if (llrpsr.getProperties().hasUTCClockCapabilities) {
                LastSeenTimestampUTC lstutc = new LastSeenTimestampUTC();
                lstutc.setMicroseconds(readTime * 1000);
                trd.setLastSeenTimestampUTCParam(lstutc);

            } else {
                LastSeenTimestampUptime lstu = new LastSeenTimestampUptime();
                lstu.setMicroseconds(llrpsr.getUptime(readTime) * 1000);
                trd.setLastSeenTimestampUptimeParam(lstu);
            }

        }
        if (format.enablePeakRSSI) {
            /* TODO: get peakRSSI from property map */
            logger.debug("PeakRSSI reporting not yet supported.  Default is 0");
            PeakRSSI prssi = new PeakRSSI();
            prssi.setPeakRSSI((byte) 0);
            trd.setPeakRSSIParam(prssi);

        }
        if (format.enableROSpecID) {
            edu.uark.csce.llrp.ROSpecID rosid = new edu.uark.csce.llrp.ROSpecID();
            rosid.setROSpecID(ROSpecID);
            trd.setROSpecIDParam(rosid);

        }
        if (format.enableSpecIndex) {
            SpecIndex si = new SpecIndex();

            si.setSpecIndex((short) specIndex);
            trd.setSpecIndexParam(si);

        }
        if (format.enableTagSeenCount) {
            TagSeenCount tsc = new TagSeenCount();
            tsc.setTagCount(tag.getReadCount().shortValue());
            trd.setTagSeenCountParam(tsc);
        }

        if (tag.getTagGen() == TagGen.GEN2) {
            /* TODO: hardcoded Air Protocol Tag Data for C1G2 */
            if (format.enableCRC) {
                C1G2CRC crc = new C1G2CRC();
                // TODO
                // crc.setCRC(Short.parseShort(tag.getCRC()));
                crc.setCRC((short) 0);
                trd.addAirProtocolTagDataParam(crc);
            }
            if (format.enablePC) {
                C1G2PC pc = new C1G2PC();
                // pc.setPC((short) tag.getTagProtocol());
                pc.setPC((short) 0);
                trd.addAirProtocolTagDataParam(pc);
            }
        }
        return trd;
    }

    /**
     * Sends out an event notification message
     * 
     * @param event
     * @return true if sent successfully, false otherwise
     */
    public boolean sendEvent(ReaderEventNotificationData event) {
        ReaderEventNotification ren = new ReaderEventNotification();
        ren.setReaderEventNotificationDataParam(event);
        UTCTimestamp utcTimestamp = new UTCTimestamp();
        utcTimestamp.setMicroseconds(System.currentTimeMillis() * 1000);
        event.setTimestampParam(utcTimestamp);

        try {
            byte[] message = ren.serialize();
            if (comm.isConnected() && !this.locked)
                comm.sendBytes(message);
            else {
                // TODO Handle with lost events. Invent a Buffer architecture
                logger.error("There is a lost event");
            }
            return true;
        } catch (IOException e) {
            logger.debug(e.getMessage());
            return false;
        } catch (CommunicationException e) {
            logger.debug(e.getMessage());
            return false;
        }
    }

    public boolean sendCloseMessage() {
        this.lock();
        CloseConnectionResponse ccr = new CloseConnectionResponse();
        LLRPStatus status = new LLRPStatus();
        status.setErrorCode((short) 0);
        ccr.setLLRPStatusParam(status);

        ReaderEventNotification ren = new ReaderEventNotification();
        ReaderEventNotificationData rend = new ReaderEventNotificationData();
        ConnectionCloseEvent cce = new ConnectionCloseEvent();
        rend.setConnectionCloseEventParam(cce);
        ren.setReaderEventNotificationDataParam(rend);

        try {
            byte[] message = ccr.serialize();
            byte[] event = ren.serialize();
            if (comm.isConnected()) {
                comm.sendBytes(message);
                comm.sendBytes(event);
                /*
                 * TODO: this sleep is required because sometimes the
                 * communication shuts down before the event can be sent out,
                 * which is a big problem. However, this is a hack, because
                 * something else could put a message on the buffer during this
                 * sleep time, and then a message would be sent out after the
                 * close connection event, which violates the spec. Another
                 * problem is that the 1 second this thread sleeps may not be
                 * long enough, it depends on the thread scheduler, which is
                 * bad.
                 */
                if (comm instanceof TCPServerCommunication) {
                    TCPServerCommunication tsc = (TCPServerCommunication) comm;
                    Thread.sleep(500);
                    tsc.suspendAddingToSendBuffer();
                    Thread.sleep(500);
                    logger.debug("disconnecting...");
                    comm.disconnect();
                    tsc.resumeAddingToSendBuffer();
                } else if (comm instanceof TCPClientCommunication) {
                    TCPClientCommunication tsc = (TCPClientCommunication) comm;
                    Thread.sleep(500);
                    tsc.suspendAddingToSendBuffer();
                    Thread.sleep(500);
                    logger.debug("disconnecting...");
                    comm.disconnect();
                    tsc.resumeAddingToSendBuffer();
                }
            } else {
                // TODO Handle with lost events. Invent a Buffer architecture
                logger.error("close connection cannot send");
            }
            return true;
        } catch (IOException e) {
            logger.debug(e.getMessage());
            return false;
        } catch (CommunicationException e) {
            logger.debug(e.getMessage());
            return false;
        } catch (InterruptedException e) {
            logger.debug("Problem while disconnecting");
            return false;
        }

    }

    /**
     * This method sends out a Keepalive message.
     * 
     * @return true if send was successful, false otherwise
     */
    public boolean sendKeepAlive() {
        KeepAlive ka = new KeepAlive();

        try {
            byte[] message = ka.serialize();
            if (comm.isConnected())
                comm.sendBytes(message);
            else {
                // TODO Handle with lost events. Invent a Buffer architecture
                logger.error("keepalive could not be sent");
            }
            return true;
        } catch (IOException e) {
            logger.debug(e.getMessage());
            return false;
        } catch (CommunicationException e) {
            logger.debug(e.getMessage());
            return false;
        }

    }

    /**
     * Gets the UTC Time.
     * 
     * @param dateString
     * @param timeString
     * @return time in milliseconds
     */
    @SuppressWarnings("deprecation")
    private static long getUTCTimeInMillis(String dateString, String timeString) {

        /*
         * TODO: baindaid solution until radio saves and returns java date and
         * time objects
         */
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");

        Date date, time = null;
        try {
            date = dateFormat.parse(dateString);
            time = timeFormat.parse(timeString);
        } catch (ParseException e) {
            logger.error("There was a problem converting the date or time string into a Date object");
            date = new Date();
            time = new Date();
        }

        GregorianCalendar gc = new GregorianCalendar(date.getYear(), date.getMonth(), date.getDate(),
                time.getHours(), time.getMinutes(), time.getSeconds());

        return gc.getTimeInMillis();
    }

    /**
     * @return the comm
     */
    public Communication getComm() {
        return comm;
    }

    /**
     * @param comm
     *            the comm to set
     */
    public void setComm(Communication comm) {
        this.comm = comm;
    }

    public void unlock() {
        locked = false;
    }

    public void lock() {
        locked = true;
    }
}