OK, I've done quite a bit more debugging on this.
I first tried re-issuing the checkInterface command, and found that this 
did not recover the IOIO state.  Neither did issuing a SoftReset().  
But HardReset() does recover the link.  It causes my app to get 
re-launched, but that's an acceptable tradeoff for not being able to 
connect to IOIO at all.
I'm attaching the patch file here.   Changes are to IOIOImpl.java and 
IncomingState.java
Some explanation:
I found that when stuck in this state, it's the call to 
waitForInterfaceSupport that is hung, waiting on the state to change to 
Connected.  So I now ensure I'm already in the Connected state before 
calling that method, so I know it won't hang.  I issue the checkInterface 
in a loop ,checking for the state change manually before allowing it to 
proceed.   The check is via a new method in IncomingState.java called 
isEstablished().   I'm waiting 100ms after issuing HardReset, to give the 
system time to recover.

Also, I noticed some Null Pointer Exceptions inside handleSoftReset() when 
I was doing rapid power cycling.  I now have pointer checks at each step of 
that routine.

I'm not sure if you want to accept this change, but it's a decent 
workaround for me, so I thought I'd share this update.  If you think it's 
worthwhile, then we should probably limit the number of retry attempts, and 
throw an exception if the limit is reached.  In my experience, recovery is 
needed once per 10 or 20 cycles, and one retry is all that's ever needed.

On Sunday, February 1, 2015 at 2:04:24 AM UTC-5, Ytai wrote:
>
> This is not a valid protocol. One thing that might explain this is that 
> the IOIO got some corrupt data, which caused it to close the connection and 
> immediately re-open it.
> The leading 0x01 you're seeing is part of a meta protocol used only in AOA 
> mode that works around the fact that AOA doesn't have the notion of opening 
> and closing a connection to the accessory.
> Since I don't believe it is very likely that data actually got *corrupted* at 
> the USB level, it is more likely that a byte got discarded somewhere along 
> the AOA stack, be it in the IOIO software / firmware or in the Android 
> protocol stack.
> If you want to dig deeper, you can try building the IOIO firmware with 
> logging enabled, which would give you some diagnostics over a serial (UART) 
> connection on one of the pins. This will allow you to know what things look 
> like from the IOIO side.
>
> On Sat, Jan 31, 2015 at 6:01 PM, Paul McMahon <[email protected] 
> <javascript:>> wrote:
>
>> Ytai,
>> I'm attaching 2 files here, a good example and bad one.  Each log shows 
>> the accessory connection processing, as well as the bytes passing back and 
>> forth across the interface.
>>
>> In both cases, I see the IOIO wake up with the "establish connection" 
>> stream, which includes all the version numbers.
>> Then the phone sends the CHECK_INTERFACE code 0x02, and the IOIO0003 
>> string.  In the passing case, IOIO responds with 0x2 0x1, indicating a 
>> version match, and we're off and running.
>> In the bad case, IOIO responds with 0x1 and sends the initial string all 
>> over again.
>>
>> I haven't looked at the firmware code, but maybe you can tell me what 
>> that response is indicating?
>>
>> thanks.
>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"ioio-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/ioio-users.
For more options, visit https://groups.google.com/d/optout.
diff --git a/IOIOLib/src/ioio/lib/impl/IOIOImpl.java b/IOIOLib/src/ioio/lib/impl/IOIOImpl.java
index 8af478b..99a9ca8 100644
--- a/IOIOLib/src/ioio/lib/impl/IOIOImpl.java
+++ b/IOIOLib/src/ioio/lib/impl/IOIOImpl.java
@@ -50,10 +50,12 @@
 import ioio.lib.impl.IncomingState.DisconnectListener;
 import ioio.lib.spi.Log;
 
 import java.io.IOException;
 
+import android.os.SystemClock;
+
 public class IOIOImpl implements IOIO, DisconnectListener {
 	private static final String TAG = "IOIOImpl";
 	private boolean disconnect_ = false;
 
 	private static final byte[] REQUIRED_INTERFACE_ID = new byte[] { 'I', 'O',
@@ -182,11 +184,19 @@
 	}
 
 	private void checkInterfaceVersion() throws IncompatibilityException,
 			ConnectionLostException, InterruptedException {
 		try {
-			protocol_.checkInterface(REQUIRED_INTERFACE_ID);
+			while( true ) {
+				protocol_.checkInterface(REQUIRED_INTERFACE_ID);
+				SystemClock.sleep(20);
+				if( !incomingState_.isEstablished() )
+					break;
+				protocol_.hardReset();
+				SystemClock.sleep(100);
+			}
+
 		} catch (IOException e) {
 			throw new ConnectionLostException(e);
 		}
 		if (!incomingState_.waitForInterfaceSupport()) {
 			state_ = State.INCOMPATIBLE;
diff --git a/IOIOLib/src/ioio/lib/impl/IncomingState.java b/IOIOLib/src/ioio/lib/impl/IncomingState.java
index 76cc9a5..c2e646c 100644
--- a/IOIOLib/src/ioio/lib/impl/IncomingState.java
+++ b/IOIOLib/src/ioio/lib/impl/IncomingState.java
@@ -217,37 +217,49 @@
 		}
 	}
 
 	@Override
 	public void handleSoftReset() {
-		// logMethod("handleSoftReset");
-		for (InputPinState pinState : intputPinStates_) {
-			pinState.closeCurrentListener();
-		}
-		for (DataModuleState uartState : uartStates_) {
-			uartState.closeCurrentListener();
-		}
-		for (DataModuleState twiState : twiStates_) {
-			twiState.closeCurrentListener();
-		}
-		for (DataModuleState spiState : spiStates_) {
-			spiState.closeCurrentListener();
-		}
-		for (DataModuleState incapState : incapStates_) {
-			incapState.closeCurrentListener();
-		}
-		icspState_.closeCurrentListener();
+		// Upon rapid power cycling, sometimes this gets called when some of these
+		// pointers are still null.  Added protection against Null Pointer Exceptions
+		if( intputPinStates_ != null )
+			for (InputPinState pinState : intputPinStates_) {
+				pinState.closeCurrentListener();
+			}
+		if( uartStates_ != null )
+			for (DataModuleState uartState : uartStates_) {
+				uartState.closeCurrentListener();
+			}
+		if( twiStates_ != null )
+			for (DataModuleState twiState : twiStates_) {
+				twiState.closeCurrentListener();
+			}
+		if( spiStates_ != null )
+			for (DataModuleState spiState : spiStates_) {
+				spiState.closeCurrentListener();
+			}
+		if( incapStates_ != null )
+			for (DataModuleState incapState : incapStates_) {
+				incapState.closeCurrentListener();
+			}
+		if( icspState_ != null )
+			icspState_.closeCurrentListener();
 	}
 
 	@Override
 	synchronized public void handleCheckInterfaceResponse(boolean supported) {
 		// logMethod("handleCheckInterfaceResponse", supported);
 		connection_ = supported ? ConnectionState.CONNECTED
 				: ConnectionState.UNSUPPORTED_IID;
 		notifyAll();
 	}
 
+	// Public access, to determine if we're in the Established state
+	synchronized public boolean isEstablished() {
+		return connection_ == ConnectionState.ESTABLISHED;
+	}
+
 	@Override
 	public void handleSetChangeNotify(int pin, boolean changeNotify) {
 		// logMethod("handleSetChangeNotify", pin, changeNotify);
 		if (changeNotify) {
 			intputPinStates_[pin].openNextListener();

Reply via email to