org.rifidi.edge.adapter.awid.awid2010.gpio.AwidGPIOSession.java Source code

Java tutorial

Introduction

Here is the source code for org.rifidi.edge.adapter.awid.awid2010.gpio.AwidGPIOSession.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Transcends, LLC.
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU 
 * General Public License as published by the Free Software Foundation; either version 2 of the 
 * License, or (at your option) any later version. This program is distributed in the hope that it will 
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You 
 * should have received a copy of the GNU General Public License along with this program; if not, 
 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 
 * USA. 
 * http://www.gnu.org/licenses/gpl-2.0.html
 *******************************************************************************/
package org.rifidi.edge.adapter.awid.awid2010.gpio;

import java.io.IOException;
import java.util.BitSet;
import java.util.HashSet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rifidi.edge.adapter.awid.awid2010.communication.commands.AbstractAwidCommand;
import org.rifidi.edge.sensors.AbstractCommandConfiguration;
import org.rifidi.edge.sensors.AbstractSensor;
import org.rifidi.edge.sensors.ByteMessage;
import org.rifidi.edge.sensors.CannotExecuteException;
import org.rifidi.edge.sensors.sessions.AbstractPubSubIPSensorSession;
import org.rifidi.edge.sensors.sessions.IPSessionEndpoint;
import org.rifidi.edge.sensors.sessions.MessageParsingStrategy;
import org.rifidi.edge.sensors.sessions.MessageParsingStrategyFactory;

/**
 * This is a Session that is used for the GPIO functionality for the AWID TCP/IP
 * MPR reader. The AWID reader uses a separate software unit for GPI/O from the
 * unit that handles tag reads. The GPI/O process runs on port 4001 on the
 * reader, so a separate TCP/IP session is needed. The AWID has four input lines
 * and four output lines.
 * 
 * The AWID reader will send back asynchronous notifications when an input line
 * changes state. For this reason, this session extends
 * AbstractPubSubIPSensorSession, which allows this session to process incoming
 * messages as they happen. These notification events are given to esper.
 * 
 * There are also three request/response type messages that are available
 * (namely 'Output Command', 'Flash On/Off Control', and 'GPIO Status'). So this
 * session first checks if the incoming message is a GPI notification. If it is,
 * it will give the notification event to esper. If it is not, it will queue the
 * message so that the process that sent the request can call receiveMessage to
 * get the response.
 * 
 * @author Kyle Neumeier - kyle@pramari.com
 * 
 */
public class AwidGPIOSession extends AbstractPubSubIPSensorSession implements IPSessionEndpoint {

    private static final Log logger = LogFactory.getLog(AwidGPIOSession.class);

    /**
     * The current status of the GPI ports. This object is shared, so make sure
     * to synchronize before accessing
     */
    private final BitSet GPIPorts = new BitSet(4);
    /** Queue for messages that are not GPI Notification messages. */
    private final LinkedBlockingQueue<ByteMessage> messageQueue;

    /**
     * Create a new session for interacting with the AWID reader's GPIO module
     * 
     * @param sensor
     * @param ID
     * @param host
     * @param port
     */
    public AwidGPIOSession(AbstractSensor<?> sensor, String ID, String host, int port) {
        super(sensor, ID, host, port, 1000, 3, new HashSet<AbstractCommandConfiguration<?>>());
        messageQueue = new LinkedBlockingQueue<ByteMessage>();
    }

    /**
     * 
     * @param ports
     * @throws CannotExecuteException
     */
    public void setOutputPort(BitSet ports) throws CannotExecuteException {
        try {
            SetOutputPortCommand command = new SetOutputPortCommand(ports);
            command.setReaderSession(this);
            super.submitAndBlock(command, 5, TimeUnit.SECONDS);
        } catch (Exception e) {
            throw new CannotExecuteException(e);
        }

    }

    /**
     * 
     * @param port
     * @return
     * @throws CannotExecuteException
     */
    public boolean testInputPort(int port) throws CannotExecuteException {
        try {
            TestInputPortsCommand command = new TestInputPortsCommand(GPIPorts);
            command.setReaderSession(this);
            super.submitAndBlock(command, 5, TimeUnit.SECONDS);
            return GPIPorts.get(port);
        } catch (Exception e) {
            throw new CannotExecuteException(e);
        }
    }

    /**
     * A custom Awid GPIO command that flashes a line high for a given amount of
     * time and a given number of times
     * 
     * @param pin
     *            The line to set
     * @param onTime
     *            The amount of time in 100Ms to set high
     * @param offTime
     *            the amount of time in 100Ms to set low
     * @param totalCount
     *            The number of times to flash.
     */
    private void flashOutputPort(byte pin, byte onTime, byte offTime, byte totalCount)
            throws CannotExecuteException {
        GPOFlashCommand awidCommand = new GPOFlashCommand(pin, onTime, offTime, totalCount);
        FlashControlCommand command = new FlashControlCommand(awidCommand);
        command.setReaderSession(this);
        super.submit(command);
    }

    /**
     * 
     * @param ports
     * @param finalPorts
     * @param timeOn
     * @param timeOff
     * @param repeat
     * @throws CannotExecuteException
     */
    public void flashOutput(final BitSet ports, final BitSet finalPorts, final int timeOn, final int timeOff,
            final int repeat) throws CannotExecuteException {
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    for (int i = 0; i < 4; i++) {
                        if (ports.get(i)) {
                            flashOutputPort((byte) i, (byte) timeOn, (byte) timeOff, (byte) repeat);
                        }
                    }
                    setOutputPort(finalPorts);
                } catch (CannotExecuteException e) {
                    logger.warn("Cannot Flash Output: " + e.getMessage());
                }
            }
        });
        t.start();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.edge.sensors.sessions.AbstractIPSensorSession#sendMessage
     * (org.rifidi.edge.sensors.messages.ByteMessage)
     */
    public void sendMessage(AbstractAwidCommand message) throws IOException {
        super.sendMessage(new ByteMessage(message.getCommand()));
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.edge.core.sensors.sessions.AbstractIPSensorSession#
     * getMessageParsingStrategyFactory()
     */
    @Override
    protected MessageParsingStrategyFactory getMessageParsingStrategyFactory() {
        return new MessageParsingStrategyFactory() {

            @Override
            public MessageParsingStrategy createMessageParser() {
                return new AwidGPIOMessageParsingStrategy();
            }
        };
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.edge.sensors.sessions.AbstractIPSensorSession#onConnect()
     */
    @Override
    protected boolean onConnect() throws IOException {
        super.subscribe(this);
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.edge.sensors.sessions.AbstractIPSensorSession#disconnect
     * ()
     */
    @Override
    public void disconnect() {
        super.disconnect();
        super.unsubscribe(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.edge.sensors.sessions.pubsub.IPSessionEndpoint#handleMessage
     * (org.rifidi.edge.sensors.messages.ByteMessage)
     */
    @Override
    public void handleMessage(ByteMessage message) {
        // first check to see if the message is a GPI Notification
        if (isInputChangedMessage(message)) {
            // TODO: put GPIEvent on esper
        } else {
            // if it's not, put the message on the queue.
            messageQueue.add(message);
        }
    }

    /**
     * Receive a message. This method blocks for the given amount of time. If
     * the time expires the method will return.
     * 
     * @param timeout
     *            in milisecons
     * @return The Message that was recieved
     * @throws IOException
     *             If there was a problem recieving the message or if a Timeout
     *             happened.
     */
    public ByteMessage receiveMessage(long timeout) throws IOException {
        try {
            return messageQueue.poll(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException();
        }
    }

    /**
     * A helper method to check if the incoming message is a "Input Response"
     * Message from the Awid reader informing us that a GPI has changed states.
     * 
     * The messages look like this:
     * 
     * [length][0xFF][pin][hi][crc][crc]
     * 
     * Because the second byte (0xFF) is the same as the responses to 'Output
     * command' and 'flash on/off control', we have to look at the third byte.
     * If the third byte is 0,1,2,or 3, then the message is an Input Response.
     * Otherwise, it is another kind of response message.
     * 
     * @param The
     *            message received from the AWID reader
     * @return true if the message is an input changed message.
     */
    private boolean isInputChangedMessage(ByteMessage message) {
        if (message.message.length == 6) {
            if (message.message[1] == (byte) 0xFF) {
                if (message.message[2] == (byte) 0x00 || message.message[2] == (byte) 0x01
                        || message.message[2] == (byte) 0x02 || message.message[2] == (byte) 0x03) {
                    return true;
                }
            }
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.edge.sensors.sessions.AbstractIPSensorSession#toString()
     */
    @Override
    public String toString() {
        return "[GPIO Session " + super.toString() + "]";
    }
}