?? tosserial.java
字號:
//$Id: TOSSerial.java,v 1.6 2007/05/24 19:55:12 rincon Exp $
/* "Copyright (c) 2000-2003 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement
* is hereby granted, provided that the above copyright notice, the following
* two paragraphs and the author appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
* OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
*/
//@author Cory Sharp <cssharp@eecs.berkeley.edu>
package net.tinyos.comm;
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class TOSSerial extends NativeSerial implements SerialPort {
/**
* Inner Class to handle serial event dispatching
*
*/
class EventDispatcher extends Thread {
private boolean m_run;
private boolean busy;
/**
* Constructor
*
*/
public EventDispatcher() {
busy = false;
m_run = true;
}
/**
* Start waiting for events
*
*/
public void open() {
synchronized (this) {
m_run = true;
this.notify();
}
}
/**
* Stop waiting for events
* Here's the deal: we're running a thread here that is calling
* a function waitForEvent() in the toscomm driver. We're now waiting for
* two events: DATA_AVAILABLE and OUTPUT_EMPTY. If you call cancelWait(),
* nothing happens until the waitForEvent() returns by getting an event
* anyway, so if our node isn't generating bytes on its own, we need to
* force it to make an event so we can get out of that function to avoid
* a driver crash.
*
* Previously, it never returned because there were no events. Now we
* make an event by adding notifyOn(OUTPUT_EMPTY) and then writing a
* standard 0x7E sync byte to the serial port and let it tell us that
* an event occured.
*
* When the waitForEvent() function finally exits, we are then able to
* tell it, "Oh yea, while you're at it, cancelWait()". Finally, the
* EventDispatcher is in a state where the driver is not sitting around
* waiting for an event to occur. At that point, we can shut down the
* NativeSerial by calling super.close() elsewhere.
*
* As far as I can tell, this is the only way to make this work without
* modifying the actual toscomm driver.
*
* The only other trick I can see to this is sometimes you can't connect
* immediately after you disconnect.. I added a wait(500) after a disconnect
* more toward my application layer to prevent my app from trying to
* reconnect immediately. My JUnit tests, for example, disconnect and
* reconnect very rapidly as you would expect.
*/
public void close() {
m_run = false;
synchronized (this) {
while (busy) {
write(0x7E);
cancelWait();
try {
// Wait for the waitForEvent() done event, if it doesn't work after
// 500 ms, then we try generating that OUTPUT_EMPTY event again.
wait(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* Dispatch the event if it really occured
*
* @param event
*/
private void dispatch_event(int event) {
if (didEventOccur(event)) {
SerialPortEvent ev = new SerialPortEvent(TOSSerial.this, event);
synchronized (m_listeners) {
Iterator i = m_listeners.iterator();
while (i.hasNext())
((SerialPortListener) i.next()).serialEvent(ev);
}
}
}
public void run() {
while (true) {
synchronized (this) {
while (!m_run) {
try {
busy = false;
synchronized (this) {
this.notify();
}
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
busy = true;
if (waitForEvent()) {
dispatch_event(SerialPortEvent.DATA_AVAILABLE);
dispatch_event(SerialPortEvent.OUTPUT_EMPTY);
}
}
}
}
/**
* Inner Serial Input Stream Class
*
*/
class SerialInputStream extends InputStream {
ByteQueue bq = new ByteQueue(128);
protected void gather() {
int navail = TOSSerial.this.available();
if (navail > 0) {
byte buffer[] = new byte[navail];
bq.push_back(buffer, 0, TOSSerial.this.read(buffer, 0, navail));
}
}
public int read() {
gather();
return bq.pop_front();
}
public int read(byte[] b) {
gather();
return bq.pop_front(b);
}
public int read(byte[] b, int off, int len) {
gather();
return bq.pop_front(b, off, len);
}
public int available() {
gather();
return bq.available();
}
}
/**
* Inner Serial Output Stream Class
*
*/
class SerialOutputStream extends OutputStream {
public void write(int b) {
TOSSerial.this.write(b);
}
public void write(byte[] b) {
TOSSerial.this.write(b, 0, b.length);
}
public void write(byte[] b, int off, int len) {
int nwritten = 0;
while (nwritten < len)
nwritten += TOSSerial.this.write(b, nwritten, len - nwritten);
}
}
private SerialInputStream m_in;
private SerialOutputStream m_out;
private Vector m_listeners = new Vector();
private EventDispatcher m_dispatch;
static String map_portname(String mapstr, String portname) {
// mapstr is of the form "from1=to1:from2=to2"
// If "from", "to", and "portname" all end port numbers, then the ports in
// "from" and "to" are used as a bias for the port in "portname", appended
// to the "to" string (without its original terminating digits). If more
// than one port mapping matches, the one with the smallest non-negative
// port number wins.
// For instance, if
// mapstr="com1=COM1:com10=\\.\COM10"
// then
// com1 => COM1
// com3 => COM3
// com10 => \\.\COM10
// com12 => \\.\COM12
// or if
// mapstr="com1=/dev/ttyS0:usb1=/dev/ttyS100"
// then
// com1 => /dev/ttyS0
// com3 => /dev/ttyS2
// usb1 => /dev/ttyS100
// usb3 => /dev/ttyS102
String maps[] = mapstr.split(":");
Pattern pkv = Pattern.compile("(.*?)=(.*?)");
Pattern pnum = Pattern.compile("(.*\\D)(\\d+)");
Matcher mport = pnum.matcher(portname);
int match_distance = -1;
String str_port_to = null;
for (int i = 0; i < maps.length; i++) {
Matcher mkv = pkv.matcher(maps[i]);
if (mkv.matches()) {
Matcher mfrom = pnum.matcher(mkv.group(1));
Matcher mto = pnum.matcher(mkv.group(2));
if (mfrom.matches() && mto.matches() && mport.matches()
&& mfrom.group(1).equalsIgnoreCase(mport.group(1))) {
int nfrom = Integer.parseInt(mfrom.group(2));
int nto = Integer.parseInt(mto.group(2));
int nport_from = Integer.parseInt(mport.group(2));
int nport_to = nport_from - nfrom + nto;
int ndist = nport_from - nfrom;
if ((ndist >= 0)
&& ((ndist < match_distance) || (match_distance == -1))) {
match_distance = ndist;
str_port_to = mto.group(1) + nport_to;
}
} else if (mkv.group(1).equalsIgnoreCase(portname)) {
match_distance = 0;
str_port_to = mkv.group(2);
}
}
}
return (str_port_to == null) ? portname : str_port_to;
}
/**
* Real Constructor of TOSSerial
*
* @param portname
*/
public TOSSerial(String portname) {
super(map_portname(NativeSerial.getTOSCommMap(), portname));
m_in = new SerialInputStream();
m_out = new SerialOutputStream();
m_dispatch = new EventDispatcher();
m_dispatch.start();
}
/**
* Open the serial port connection
*/
public boolean open() {
if (m_dispatch != null) {
m_dispatch.open();
}
return super.open();
}
/**
* Close the serial port connection
*/
public void close() {
if (m_dispatch != null) {
m_dispatch.close();
}
super.close();
}
public void addListener(SerialPortListener l) {
synchronized (m_listeners) {
if (!m_listeners.contains(l))
m_listeners.add(l);
}
}
public void removeListener(SerialPortListener l) {
synchronized (m_listeners) {
m_listeners.remove(l);
}
}
public InputStream getInputStream() {
return m_in;
}
public OutputStream getOutputStream() {
return m_out;
}
/**
* Finalize the serial port connection, do not expect to open it again
*/
public void finalize() {
// Be careful what you call here. The object may never have been
// created, so the underlying C++ object may not exist, and there's
// insufficient guarding to avoid a core dump. If you call other
// methods than super.close() or super.finalize(), be sure to
// add an if (swigCptr != 0) guard in NativeSerial.java.
if (m_dispatch != null) {
m_dispatch.close();
}
/*
* try { if (m_dispatch != null) { m_dispatch.join(); } } catch
* (InterruptedException e) { }
*/
super.close();
try {
if (m_in != null) {
m_in.close();
}
if (m_out != null) {
m_out.close();
}
} catch (IOException e) {
}
m_dispatch = null;
m_in = null;
m_out = null;
super.finalize();
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -