3030import com .digi .xbee .api .connection .IConnectionInterface ;
3131import com .digi .xbee .api .connection .bluetooth .AbstractBluetoothInterface ;
3232import com .digi .xbee .api .connection .ConnectionType ;
33+ import com .digi .xbee .api .connection .serial .AbstractSerialPort ;
3334import com .digi .xbee .api .connection .serial .SerialPortParameters ;
3435import com .digi .xbee .api .exceptions .ATCommandException ;
3536import com .digi .xbee .api .exceptions .BluetoothAuthenticationException ;
@@ -115,6 +116,8 @@ public abstract class AbstractXBeeDevice {
115116 // Constants.
116117 private static String COMMAND_MODE_CHAR = "+" ;
117118 private static String COMMAND_MODE_OK = "OK\r " ;
119+ private static String COMMAND_MODE_EXIT = "ATCN\r " ;
120+ private static String COMMAND_MODE_AP = "ATAP\r " ;
118121
119122 private static int TIMEOUT_RESET = 5000 ;
120123 protected static int TIMEOUT_READ_PACKET = 3000 ;
@@ -151,7 +154,7 @@ public abstract class AbstractXBeeDevice {
151154 protected final static int TIMEOUT_BEFORE_COMMAND_MODE = 1200 ;
152155
153156 /**
154- * Timeout to wait after entering in command mode: {@value} ms.
157+ * Timeout to wait after entering and exiting command mode: {@value} ms.
155158 *
156159 * <p>It is used to determine the operating mode of the module (this
157160 * library only supports API modes, not transparent mode).</p>
@@ -161,7 +164,7 @@ public abstract class AbstractXBeeDevice {
161164 *
162165 * @see XBeeDevice#determineOperatingMode()
163166 */
164- protected final static int TIMEOUT_ENTER_COMMAND_MODE = 1500 ;
167+ protected final static int DEFAULT_GUARD_TIME = 1500 ;
165168
166169 // Variables.
167170 protected IConnectionInterface connectionInterface ;
@@ -3148,7 +3151,7 @@ protected void open() throws XBeeException {
31483151 if (operatingMode == OperatingMode .UNKNOWN ) {
31493152 close ();
31503153 throw new InvalidOperatingModeException ("Could not determine operating mode." );
3151- } else if (operatingMode = = OperatingMode .AT ) {
3154+ } else if (operatingMode != OperatingMode . API && operatingMode ! = OperatingMode .API_ESCAPE ) {
31523155 close ();
31533156 throw new InvalidOperatingModeException (operatingMode );
31543157 }
@@ -3212,16 +3215,23 @@ protected OperatingMode determineOperatingMode() throws OperationNotSupportedExc
32123215 // It is necessary to wait at least 1 second to enter in
32133216 // command mode after sending any data to the device.
32143217 Thread .sleep (TIMEOUT_BEFORE_COMMAND_MODE );
3215- // Try to enter in AT command mode, if so the module is in AT mode.
3216- boolean success = enterATCommandMode ();
3217- if (success )
3218- return OperatingMode .AT ;
3218+ // Try to enter in AT command mode and get the actual mode.
3219+ if (enterATCommandMode ()) {
3220+ operatingMode = getActualMode ();
3221+ logger .debug (toString () + "Using {}." , operatingMode .getName ());
3222+ // Update the data reader with the correct mode.
3223+ dataReader .setXBeeReaderMode (operatingMode );
3224+ return operatingMode ;
3225+ }
32193226 } catch (TimeoutException e1 ) {
32203227 logger .error (e1 .getMessage (), e1 );
32213228 } catch (InvalidOperatingModeException e1 ) {
32223229 logger .error (e1 .getMessage (), e1 );
32233230 } catch (InterruptedException e1 ) {
32243231 logger .error (e1 .getMessage (), e1 );
3232+ } finally {
3233+ // Exit AT command mode.
3234+ exitATCommandMode ();
32253235 }
32263236 } catch (InvalidOperatingModeException e ) {
32273237 logger .error ("Invalid operating mode" , e );
@@ -3246,7 +3256,7 @@ protected OperatingMode determineOperatingMode() throws OperationNotSupportedExc
32463256 private boolean enterATCommandMode () throws InvalidOperatingModeException , TimeoutException {
32473257 if (!connectionInterface .isOpen ())
32483258 throw new InterfaceNotOpenException ();
3249- if (operatingMode != OperatingMode .AT )
3259+ if (operatingMode == OperatingMode .API || operatingMode == OperatingMode . API_ESCAPE )
32503260 throw new InvalidOperatingModeException ("Invalid mode. Command mode can be only accessed while in AT mode." );
32513261
32523262 // Enter in AT command mode (send '+++'). The process waits 1,5 seconds for the 'OK\n'.
@@ -3258,7 +3268,7 @@ private boolean enterATCommandMode() throws InvalidOperatingModeException, Timeo
32583268 connectionInterface .writeData (COMMAND_MODE_CHAR .getBytes ());
32593269
32603270 // Wait some time to let the module generate a response.
3261- Thread .sleep (TIMEOUT_ENTER_COMMAND_MODE );
3271+ Thread .sleep (DEFAULT_GUARD_TIME );
32623272
32633273 // Read data from the device (it should answer with 'OK\r').
32643274 int readBytes = connectionInterface .readData (readData );
@@ -3272,14 +3282,68 @@ private boolean enterATCommandMode() throws InvalidOperatingModeException, Timeo
32723282
32733283 // Read data was 'OK\r'.
32743284 return true ;
3275- } catch (IOException e ) {
3276- logger .error (e .getMessage (), e );
3277- } catch (InterruptedException e ) {
3285+ } catch (IOException | InterruptedException e ) {
32783286 logger .error (e .getMessage (), e );
32793287 }
32803288 return false ;
32813289 }
32823290
3291+ /**
3292+ * Exits AT command mode. The XBee device has to be in command mode.
3293+ *
3294+ * @throws InterfaceNotOpenException if this device connection is not open.
3295+ *
3296+ * @since 1.3.1
3297+ */
3298+ private void exitATCommandMode () {
3299+ if (!connectionInterface .isOpen ())
3300+ throw new InterfaceNotOpenException ();
3301+
3302+ try {
3303+ // Send the exit ('ATCN\r') command.
3304+ connectionInterface .writeData (COMMAND_MODE_EXIT .getBytes ());
3305+ // Wait the guard time.
3306+ Thread .sleep (DEFAULT_GUARD_TIME );
3307+ } catch (IOException | InterruptedException e ) {
3308+ logger .error (e .getMessage (), e );
3309+ }
3310+ }
3311+
3312+ /**
3313+ * Gets and returns the actual operating mode of the XBee device reading
3314+ * the {@code AP} parameter in AT command mode.
3315+ *
3316+ * @return The actual operating mode of the XBee device or
3317+ * {@code OperatingMode.UNKNOWN} if the mode could not be read.
3318+ *
3319+ * @throws InterfaceNotOpenException if this device connection is not open.
3320+ *
3321+ * @since 1.3.1
3322+ */
3323+ private OperatingMode getActualMode () throws InvalidOperatingModeException {
3324+ if (!connectionInterface .isOpen ())
3325+ throw new InterfaceNotOpenException ();
3326+
3327+ byte [] readData = new byte [256 ];
3328+ try {
3329+ // Clear the serial input stream.
3330+ if (connectionInterface instanceof AbstractSerialPort )
3331+ ((AbstractSerialPort )connectionInterface ).purge ();
3332+ // Send the 'AP' command.
3333+ connectionInterface .writeData (COMMAND_MODE_AP .getBytes ());
3334+ Thread .sleep (100 );
3335+ // Read the 'AP' answer.
3336+ int readBytes = connectionInterface .readData (readData );
3337+ if (readBytes == 0 )
3338+ return OperatingMode .UNKNOWN ;
3339+ // Return the corresponding operating mode for the AP answer.
3340+ return OperatingMode .get (Integer .parseInt (new String (readData ).trim (), 16 ));
3341+ } catch (IOException | NumberFormatException | InterruptedException e ) {
3342+ logger .error (e .getMessage (), e );
3343+ }
3344+ return OperatingMode .UNKNOWN ;
3345+ }
3346+
32833347 /**
32843348 * Returns whether the connection interface associated to this device is
32853349 * already open.
0 commit comments