]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
Previous problem: The EventDispatcher is stuck on the function waitForEvent() while...
authorrincon <rincon>
Thu, 24 May 2007 19:55:12 +0000 (19:55 +0000)
committerrincon <rincon>
Thu, 24 May 2007 19:55:12 +0000 (19:55 +0000)
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.

support/sdk/java/net/tinyos/comm/NativeSerial.java
support/sdk/java/net/tinyos/comm/TOSSerial.java
support/sdk/java/net/tinyos/packet/SerialByteSource.java

index d775820b7579e4fc20d5fcad45926a7b75c8f401..1782edcfde00fc800600526af71998cf9ade02f9 100644 (file)
@@ -1,4 +1,3 @@
-
 package net.tinyos.comm;
 
 /* ----------------------------------------------------------------------------
@@ -10,32 +9,33 @@ package net.tinyos.comm;
  * ----------------------------------------------------------------------------- */
 
 /**
- * Updated to include the open() method, which allows us to keep this
- * object while being temporarily disconnected from the serial port
+ * 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;
-  
+  protected long swigCPtr;
+
   /** True if we have an open serial port connection */
-  private boolean swigCMemOwn;
-  
+  protected boolean swigCMemOwn;
+
   /** Name of the port */
   private String myPortname = "";
-  
 
   /**
    * Constructor
+   * 
    * @param portname
    */
   public NativeSerial(String portname) {
     this(TOSCommJNI.new_NativeSerial(portname), true);
   }
-  
+
   /**
    * Constructor
+   * 
    * @param cPtr
    * @param cMemoryOwn
    */
@@ -44,18 +44,18 @@ public class NativeSerial {
     swigCPtr = cPtr;
   }
 
-
   /**
-   * Reconnect to this serial port 
+   * Reconnect to this serial port
+   * 
    * @return true if the connection is made
    */
   public boolean open() {
-    if(!swigCMemOwn && !myPortname.matches("")) {
+    if (!swigCMemOwn && !myPortname.matches("")) {
       swigCPtr = TOSCommJNI.new_NativeSerial(myPortname);
       swigCMemOwn = true;
       return true;
     }
-    
+
     return false;
   }
 
@@ -63,11 +63,12 @@ public class NativeSerial {
     // We can come here with swigCptr == 0 from finalize if the C++
     // 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);
   }
@@ -77,7 +78,7 @@ public class NativeSerial {
   }
 
   public void delete() {
-    if(swigCPtr != 0 && swigCMemOwn) {
+    if (swigCPtr != 0 && swigCMemOwn) {
       swigCMemOwn = false;
       TOSCommJNI.delete_NativeSerial(swigCPtr);
     }
@@ -88,8 +89,10 @@ public class NativeSerial {
     return (obj == null) ? 0 : obj.swigCPtr;
   }
 
-  public void setSerialPortParams(int baudrate, int databits, int stopbits, boolean parity) {
-    TOSCommJNI.NativeSerial_setSerialPortParams(swigCPtr, baudrate, databits, stopbits, parity);
+  public void setSerialPortParams(int baudrate, int databits, int stopbits,
+      boolean parity) {
+    TOSCommJNI.NativeSerial_setSerialPortParams(swigCPtr, baudrate, databits,
+        stopbits, parity);
   }
 
   public int getBaudRate() {
@@ -109,7 +112,9 @@ public class NativeSerial {
   }
 
   public void notifyOn(int event, boolean enable) {
-    TOSCommJNI.NativeSerial_notifyOn(swigCPtr, event, enable);
+    if (swigCPtr != 0) {
+      TOSCommJNI.NativeSerial_notifyOn(swigCPtr, event, enable);
+    }
   }
 
   public boolean isNotifyOn(int event) {
@@ -117,15 +122,21 @@ public class NativeSerial {
   }
 
   public boolean waitForEvent() {
-    try {
-      return TOSCommJNI.NativeSerial_waitForEvent(swigCPtr);
-    } catch (Exception e) {
-      return false;
+    if (swigCPtr != 0) {
+      try {
+        return TOSCommJNI.NativeSerial_waitForEvent(swigCPtr);
+      } catch (Exception e) {
+        return false;
+      }
     }
+    return false;
   }
 
   public boolean cancelWait() {
-    return TOSCommJNI.NativeSerial_cancelWait(swigCPtr);
+    if (swigCPtr != 0) {
+      return TOSCommJNI.NativeSerial_cancelWait(swigCPtr);
+    }
+    return false;
   }
 
   public boolean didEventOccur(int event) {
@@ -168,8 +179,6 @@ public class NativeSerial {
     TOSCommJNI.NativeSerial_sendBreak(swigCPtr, millis);
   }
 
-
-
   public int available() {
     try {
       return TOSCommJNI.NativeSerial_available(swigCPtr);
index 5fbac78b7589cdb6398545f2dae8857e3f1fcf45..91655c49d9479394bec09ab94a0c12d5ed1408dd 100644 (file)
@@ -29,25 +29,88 @@ import java.util.regex.*;
 
 public class TOSSerial extends NativeSerial implements SerialPort {
 
+  /**
+   * Inner Class to handle serial event dispatching
+   * 
+   */
   class EventDispatcher extends Thread {
-    boolean m_run;
+    private boolean m_run;
+
+    private boolean busy;
 
+    /**
+     * Constructor
+     * 
+     */
     public EventDispatcher() {
+      busy = false;
       m_run = true;
     }
 
+    /**
+     * Start waiting for events
+     * 
+     */
     public void open() {
       synchronized (this) {
-        this.notify();
         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;
-      cancelWait();
+      
+      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);
@@ -63,32 +126,33 @@ public class TOSSerial extends NativeSerial implements SerialPort {
       while (true) {
 
         synchronized (this) {
-          if (!m_run) {
+          while (!m_run) {
             try {
+              busy = false;
+              synchronized (this) {
+                this.notify();
+              }
               this.wait();
             } catch (InterruptedException e) {
               e.printStackTrace();
             }
           }
         }
-        
+
+        busy = true;
         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);
         }
       }
     }
 
   }
 
+  /**
+   * Inner Serial Input Stream Class
+   * 
+   */
   class SerialInputStream extends InputStream {
     ByteQueue bq = new ByteQueue(128);
 
@@ -121,6 +185,10 @@ public class TOSSerial extends NativeSerial implements SerialPort {
     }
   }
 
+  /**
+   * Inner Serial Output Stream Class
+   * 
+   */
   class SerialOutputStream extends OutputStream {
     public void write(int b) {
       TOSSerial.this.write(b);
@@ -205,6 +273,11 @@ public class TOSSerial extends NativeSerial implements SerialPort {
     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();
@@ -212,9 +285,9 @@ public class TOSSerial extends NativeSerial implements SerialPort {
     m_dispatch = new EventDispatcher();
     m_dispatch.start();
   }
-  
+
   /**
-   * Open the serial port connection 
+   * Open the serial port connection
    */
   public boolean open() {
     if (m_dispatch != null) {
@@ -222,12 +295,12 @@ public class TOSSerial extends NativeSerial implements SerialPort {
     }
     return super.open();
   }
-  
+
   /**
    * Close the serial port connection
    */
   public void close() {
-    if(m_dispatch != null) {
+    if (m_dispatch != null) {
       m_dispatch.close();
     }
     super.close();
@@ -255,8 +328,7 @@ public class TOSSerial extends NativeSerial implements SerialPort {
   }
 
   /**
-   * Finalize the serial port connection, do not expect to open it 
-   * again
+   * 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
@@ -269,13 +341,9 @@ public class TOSSerial extends NativeSerial implements SerialPort {
     }
 
     /*
-    try {
-      if (m_dispatch != null) {
-        m_dispatch.join();
-      }
-    } catch (InterruptedException e) {
-    }
-    */
+     * try { if (m_dispatch != null) { m_dispatch.join(); } } catch
+     * (InterruptedException e) { }
+     */
 
     super.close();
 
index 73357f41ce15a8f3c345f8f31a444001aebe9ad0..2baa2536b7780c1bdc1c25dbbd814353f613704e 100644 (file)
@@ -51,27 +51,27 @@ public class SerialByteSource extends StreamByteSource implements
   }
 
   public void openStreams() throws IOException {
-    //if (serialPort == null) {
-      try {
-        serialPort = new TOSSerial(portName);
-      } catch (Exception e) {
-        throw new IOException("Could not open " + portName + ": "
-            + e.getMessage());
-      }
-      /*
-    } else {
-      if (!serialPort.open()) {
-        throw new IOException("Could not re-open " + portName);
-      }
+    // if (serialPort == null) {
+    try {
+      serialPort = new TOSSerial(portName);
+    } catch (Exception e) {
+      throw new IOException("Could not open " + portName + ": "
+          + e.getMessage());
     }
-    */
+    /*
+     * } else { if (!serialPort.open()) { throw new IOException("Could not
+     * re-open " + portName); } }
+     */
 
     try {
       // serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
       serialPort.setSerialPortParams(baudRate, 8, SerialPort.STOPBITS_1, false);
-
       serialPort.addListener(this);
+      
       serialPort.notifyOn(SerialPortEvent.DATA_AVAILABLE, true);
+      serialPort.notifyOn(SerialPortEvent.OUTPUT_EMPTY, true);
+
+      
     } catch (Exception e) {
       serialPort.close();
       throw new IOException("Could not configure " + portName + ": "
@@ -122,8 +122,10 @@ public class SerialByteSource extends StreamByteSource implements
   }
 
   public void serialEvent(SerialPortEvent ev) {
-    synchronized (sync) {
-      sync.notify();
+    if (ev.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
+      synchronized (sync) {
+        sync.notify();
+      }
     }
   }