All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rapplogic.xbee.api.InputStreamThread Maven / Gradle / Ivy

/**
 * Copyright (c) 2008 Andrew Rapp. All rights reserved.
 *  
 * This file is part of XBee-API.
 *  
 * XBee-API 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 3 of the License, or
 * (at your option) any later version.
 *  
 * XBee-API 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 XBee-API.  If not, see .
 */

package com.rapplogic.xbee.api;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.Logger;

import com.rapplogic.xbee.XBeeConnection;
import com.rapplogic.xbee.util.ByteUtils;

/**
 * Reads data from the input stream and hands off to PacketParser for packet parsing.
 * Notifies XBee class when a new packet is parsed
 * 

* @author andrew * */ public class InputStreamThread implements Runnable { private final static Logger log = Logger.getLogger(InputStreamThread.class); private Thread thread; private ExecutorService listenerPool; private volatile boolean done = false; private final XBeeConnection connection; private XBeeConfiguration conf; public XBeeConnection getXBeeConnection() { return connection; } private final BlockingQueue responseQueue = new LinkedBlockingQueue(); // TODO use weak references private final List packetListenerList = new LinkedList(); public List getPacketListenerList() { return packetListenerList; } public BlockingQueue getResponseQueue() { return responseQueue; } public InputStreamThread(final XBeeConnection connection, XBeeConfiguration conf) { this.connection = connection; this.conf = conf; // Create an executor to deliver incoming packets to listeners. We'll use a single // thread with an unbounded queue. listenerPool = Executors.newSingleThreadExecutor(); thread = new Thread(this); thread.setName("InputStreamThread"); thread.start(); log.debug("starting packet parser thread"); } private void addResponse(final XBeeResponse response) throws InterruptedException { if (conf.getResponseQueueFilter() != null) { if (conf.getResponseQueueFilter().accept(response)) { this.addToResponseQueue(response); } } else { this.addToResponseQueue(response); } listenerPool.submit(new Runnable() { public void run() { // must synchronize to avoid java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(Unknown Source) // this occurs if packet listener add/remove is called while we are iterating synchronized (packetListenerList) { for (PacketListener pl : packetListenerList) { try { if (pl != null) { pl.processResponse(response); } else { log.warn("PacketListener is null, size is " + packetListenerList.size()); } } catch (Throwable th) { log.warn("Exception in packet listener", th); } } } } }); } private void addToResponseQueue(final XBeeResponse response) throws InterruptedException{ if (conf.getMaxQueueSize() == 0) { // warn return; } // trim the queue while (responseQueue.size() >= conf.getMaxQueueSize()) { log.info("Response queue has reached the maximum size of " + conf.getMaxQueueSize() + " packets. Trimming a packet from head of queue to make room"); responseQueue.poll(); } responseQueue.put(response); } public void run() { int val = -1; XBeeResponse response = null; PacketParser packetStream = null; try { while (!done) { try { if (connection.getInputStream().available() > 0) { log.debug("About to read from input stream"); val = connection.getInputStream().read(); log.debug("Read " + ByteUtils.formatByte(val) + " from input stream"); if (val == XBeePacket.SpecialByte.START_BYTE.getValue()) { packetStream = new PacketParser(connection.getInputStream()); response = packetStream.parsePacket(); if (log.isInfoEnabled()) { log.info("Received packet from XBee: " + response); // log.debug("Received packet: int[] packet = {" + ByteUtils.toBase16(response.getRawPacketBytes(), ", ") + "};"); } // success this.addResponse(response); } else { log.warn("expected start byte but got this " + ByteUtils.toBase16(val) + ", discarding"); } } else { log.debug("No data available.. waiting for new data event"); // we will wait here for RXTX to notify us of new data synchronized (this.connection) { // There's a chance that we got notified after the first in.available check if (connection.getInputStream().available() > 0) { continue; } // wait until new data arrives this.connection.wait(); } } } catch (Exception e) { if (e instanceof InterruptedException) throw ((InterruptedException)e); log.error("Error while parsing packet:", e); if (e instanceof IOException) { // this is thrown by RXTX if the serial device unplugged while we are reading data; if we are waiting then it will waiting forever log.error("Serial device IOException.. exiting"); break; } } } } catch(InterruptedException ie) { // We've been told to stop -- the user called the close() method log.info("Packet parser thread was interrupted. This occurs when close() is called"); } catch (Throwable t) { log.error("Error in input stream thread.. exiting", t); } finally { try { if (connection != null) { connection.close(); } if (listenerPool != null) { try { listenerPool.shutdownNow(); } catch (Throwable t) { log.warn("Failed to shutdown listner thread pool", t); } } } catch (Throwable t) { log.error("Error in input stream thread finally", t); } } log.info("InputStreamThread is exiting"); } public void setDone(boolean done) { this.done = done; } public void interrupt() { if (thread != null) { try { thread.interrupt(); } catch (Exception e) { log.warn("Error interrupting parser thread", e); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy