[Tinyos-2-commits] CVS: tinyos-2.x/support/sdk/java/net/tinyos/comm
NativeSerial.java, 1.3, 1.4 TOSSerial.java, 1.5, 1.6
dmm
rincon at users.sourceforge.net
Thu May 24 12:55:14 PDT 2007
Update of /cvsroot/tinyos/tinyos-2.x/support/sdk/java/net/tinyos/comm
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv31871/comm
Modified Files:
NativeSerial.java TOSSerial.java
Log Message:
Previous problem: The EventDispatcher is stuck on the function waitForEvent() while we are attempting to close. Closing NativeSerial while the driver is still in the function waitForEvent() will crash everything. Calling cancelWait() in win32 does let waitForEvent() return until some event actually occurs, which is not the behavior I was expecting. The serial driver itself could be fixed to let cancelWait() actually force waitForEvent() to return false, but I don't want to touch it.
Solution: Force waitForEvent() to generate an event by adding a notification for OUTPUT_EMPTY. When we want to close the serial source, send a 0x7E byte to the serial port and wait for that OUTPUT_EMPTY event to get signaled. At that point, the EventDispatcher thread can continue execution and will cancelWait() properly. We aren't stuck in waitForEvent(), and only then can we shut down NativeSerial with confidence.
One other issue remaining is the fact that sometimes you can't reconnect to the source very quickly after a disconnect. Adding in a hacky wait(500) fixes the problem on disconnect, but I haven't included that anywhere because I haven't figured out exactly what is causing us to need to wait for a short period of time after a disconnect before reconnecting again.
Index: NativeSerial.java
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/support/sdk/java/net/tinyos/comm/NativeSerial.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** NativeSerial.java 18 May 2007 18:27:03 -0000 1.3
--- NativeSerial.java 24 May 2007 19:55:12 -0000 1.4
***************
*** 1,3 ****
-
package net.tinyos.comm;
--- 1,2 ----
***************
*** 11,32 ****
/**
! * Updated to include the open() method, which allows us to keep this
! * object while being temporarily disconnected from the serial port
*/
public class NativeSerial {
!
/** The handle to the serial port we're connected to */
! private long swigCPtr;
!
/** True if we have an open serial port connection */
! private boolean swigCMemOwn;
!
/** Name of the port */
private String myPortname = "";
-
/**
* Constructor
* @param portname
*/
--- 10,31 ----
/**
! * Updated to include the open() method, which allows us to keep this object
! * while being temporarily disconnected from the serial port
*/
public class NativeSerial {
!
/** The handle to the serial port we're connected to */
! protected long swigCPtr;
!
/** True if we have an open serial port connection */
! protected boolean swigCMemOwn;
!
/** Name of the port */
private String myPortname = "";
/**
* Constructor
+ *
* @param portname
*/
***************
*** 34,40 ****
this(TOSCommJNI.new_NativeSerial(portname), true);
}
!
/**
* Constructor
* @param cPtr
* @param cMemoryOwn
--- 33,40 ----
this(TOSCommJNI.new_NativeSerial(portname), true);
}
!
/**
* Constructor
+ *
* @param cPtr
* @param cMemoryOwn
***************
*** 45,60 ****
}
-
/**
! * Reconnect to this serial port
* @return true if the connection is made
*/
public boolean open() {
! if(!swigCMemOwn && !myPortname.matches("")) {
swigCPtr = TOSCommJNI.new_NativeSerial(myPortname);
swigCMemOwn = true;
return true;
}
!
return false;
}
--- 45,60 ----
}
/**
! * Reconnect to this serial port
! *
* @return true if the connection is made
*/
public boolean open() {
! if (!swigCMemOwn && !myPortname.matches("")) {
swigCPtr = TOSCommJNI.new_NativeSerial(myPortname);
swigCMemOwn = true;
return true;
}
!
return false;
}
***************
*** 64,72 ****
// constructor throws an exception. Ideally, we should guard all
// methods in the C++ code, but this is simpler.
if (swigCPtr != 0) {
TOSCommJNI.NativeSerial_close(swigCPtr);
}
}
!
protected NativeSerial() {
this(0, false);
--- 64,73 ----
// constructor throws an exception. Ideally, we should guard all
// methods in the C++ code, but this is simpler.
+
if (swigCPtr != 0) {
TOSCommJNI.NativeSerial_close(swigCPtr);
}
}
!
protected NativeSerial() {
this(0, false);
***************
*** 78,82 ****
public void delete() {
! if(swigCPtr != 0 && swigCMemOwn) {
swigCMemOwn = false;
TOSCommJNI.delete_NativeSerial(swigCPtr);
--- 79,83 ----
public void delete() {
! if (swigCPtr != 0 && swigCMemOwn) {
swigCMemOwn = false;
TOSCommJNI.delete_NativeSerial(swigCPtr);
***************
*** 89,94 ****
}
! public void setSerialPortParams(int baudrate, int databits, int stopbits, boolean parity) {
! TOSCommJNI.NativeSerial_setSerialPortParams(swigCPtr, baudrate, databits, stopbits, parity);
}
--- 90,97 ----
}
! public void setSerialPortParams(int baudrate, int databits, int stopbits,
! boolean parity) {
! TOSCommJNI.NativeSerial_setSerialPortParams(swigCPtr, baudrate, databits,
! stopbits, parity);
}
***************
*** 110,114 ****
public void notifyOn(int event, boolean enable) {
! TOSCommJNI.NativeSerial_notifyOn(swigCPtr, event, enable);
}
--- 113,119 ----
public void notifyOn(int event, boolean enable) {
! if (swigCPtr != 0) {
! TOSCommJNI.NativeSerial_notifyOn(swigCPtr, event, enable);
! }
}
***************
*** 118,130 ****
public boolean waitForEvent() {
! try {
! return TOSCommJNI.NativeSerial_waitForEvent(swigCPtr);
! } catch (Exception e) {
! return false;
}
}
public boolean cancelWait() {
! return TOSCommJNI.NativeSerial_cancelWait(swigCPtr);
}
--- 123,141 ----
public boolean waitForEvent() {
! if (swigCPtr != 0) {
! try {
! return TOSCommJNI.NativeSerial_waitForEvent(swigCPtr);
! } catch (Exception e) {
! return false;
! }
}
+ return false;
}
public boolean cancelWait() {
! if (swigCPtr != 0) {
! return TOSCommJNI.NativeSerial_cancelWait(swigCPtr);
! }
! return false;
}
***************
*** 169,174 ****
}
-
-
public int available() {
try {
--- 180,183 ----
Index: TOSSerial.java
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/support/sdk/java/net/tinyos/comm/TOSSerial.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** TOSSerial.java 18 May 2007 18:27:03 -0000 1.5
--- TOSSerial.java 24 May 2007 19:55:12 -0000 1.6
***************
*** 30,52 ****
public class TOSSerial extends NativeSerial implements SerialPort {
class EventDispatcher extends Thread {
! boolean m_run;
public EventDispatcher() {
m_run = true;
}
public void open() {
synchronized (this) {
- this.notify();
m_run = true;
}
}
public void close() {
m_run = false;
! cancelWait();
}
private void dispatch_event(int event) {
if (didEventOccur(event)) {
--- 30,115 ----
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)) {
***************
*** 64,69 ****
synchronized (this) {
! if (!m_run) {
try {
this.wait();
} catch (InterruptedException e) {
--- 127,136 ----
synchronized (this) {
! while (!m_run) {
try {
+ busy = false;
+ synchronized (this) {
+ this.notify();
+ }
this.wait();
} catch (InterruptedException e) {
***************
*** 72,87 ****
}
}
!
if (waitForEvent()) {
- dispatch_event(SerialPortEvent.BREAK_INTERRUPT);
- dispatch_event(SerialPortEvent.CARRIER_DETECT);
- dispatch_event(SerialPortEvent.CTS);
dispatch_event(SerialPortEvent.DATA_AVAILABLE);
- dispatch_event(SerialPortEvent.DSR);
- dispatch_event(SerialPortEvent.FRAMING_ERROR);
- dispatch_event(SerialPortEvent.OVERRUN_ERROR);
dispatch_event(SerialPortEvent.OUTPUT_EMPTY);
- dispatch_event(SerialPortEvent.PARITY_ERROR);
- dispatch_event(SerialPortEvent.RING_INDICATOR);
}
}
--- 139,147 ----
}
}
!
! busy = true;
if (waitForEvent()) {
dispatch_event(SerialPortEvent.DATA_AVAILABLE);
dispatch_event(SerialPortEvent.OUTPUT_EMPTY);
}
}
***************
*** 90,93 ****
--- 150,157 ----
}
+ /**
+ * Inner Serial Input Stream Class
+ *
+ */
class SerialInputStream extends InputStream {
ByteQueue bq = new ByteQueue(128);
***************
*** 122,125 ****
--- 186,193 ----
}
+ /**
+ * Inner Serial Output Stream Class
+ *
+ */
class SerialOutputStream extends OutputStream {
public void write(int b) {
***************
*** 206,209 ****
--- 274,282 ----
}
+ /**
+ * Real Constructor of TOSSerial
+ *
+ * @param portname
+ */
public TOSSerial(String portname) {
super(map_portname(NativeSerial.getTOSCommMap(), portname));
***************
*** 213,219 ****
m_dispatch.start();
}
!
/**
! * Open the serial port connection
*/
public boolean open() {
--- 286,292 ----
m_dispatch.start();
}
!
/**
! * Open the serial port connection
*/
public boolean open() {
***************
*** 223,232 ****
return super.open();
}
!
/**
* Close the serial port connection
*/
public void close() {
! if(m_dispatch != null) {
m_dispatch.close();
}
--- 296,305 ----
return super.open();
}
!
/**
* Close the serial port connection
*/
public void close() {
! if (m_dispatch != null) {
m_dispatch.close();
}
***************
*** 256,261 ****
/**
! * Finalize the serial port connection, do not expect to open it
! * again
*/
public void finalize() {
--- 329,333 ----
/**
! * Finalize the serial port connection, do not expect to open it again
*/
public void finalize() {
***************
*** 270,280 ****
/*
! try {
! if (m_dispatch != null) {
! m_dispatch.join();
! }
! } catch (InterruptedException e) {
! }
! */
super.close();
--- 342,348 ----
/*
! * try { if (m_dispatch != null) { m_dispatch.join(); } } catch
! * (InterruptedException e) { }
! */
super.close();
More information about the Tinyos-2-commits
mailing list