connectivity/com.nokia.carbide.remoteConnections.discovery.pccs/src/com/nokia/carbide/remoteconnections/discovery/pccs/pccsnative/PCCSConnection.java
changeset 1021 6594b07c89c8
parent 942 2ed87b202d5c
child 1025 0970d96e01ad
--- a/connectivity/com.nokia.carbide.remoteConnections.discovery.pccs/src/com/nokia/carbide/remoteconnections/discovery/pccs/pccsnative/PCCSConnection.java	Wed Feb 24 21:01:05 2010 -0600
+++ b/connectivity/com.nokia.carbide.remoteConnections.discovery.pccs/src/com/nokia/carbide/remoteconnections/discovery/pccs/pccsnative/PCCSConnection.java	Thu Feb 25 11:24:34 2010 -0600
@@ -39,6 +39,7 @@
 import com.nokia.carbide.remoteconnections.discovery.pccs.Messages;
 import com.nokia.carbide.remoteconnections.discovery.pccs.pccsnative.IConnAPILibrary.IConnAPIDeviceCallback;
 import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
+
 import com.sun.jna.Pointer;
 import com.sun.jna.WString;
 import com.sun.jna.ptr.IntByReference;
@@ -47,8 +48,7 @@
 public class PCCSConnection {
 
 	private static final String NOT_KNOWN = "not known"; //$NON-NLS-1$ // used for all string structure elements that come back from PCCS as null
-	private boolean DEBUG = false;
-	private boolean SWITCH_TO_RNDIS = false; // false for 2.x, true for 3.x
+	private boolean DEBUG = true;
 	private String DONT_ASK_AGAIN_KEY = "DontAskAgain"; //$NON-NLS-1$
 	
 	/**
@@ -60,52 +60,46 @@
 		 * @see com.nokia.carbide.remoteconnections.discovery.pccs.pccsnative.IConnAPILibrary.IConnAPIDeviceCallback#invoke(int, com.sun.jna.ptr.ShortByReference)
 		 */
 		public int invoke(final int dwStatus, final ShortByReference pstrSerialNumber) {
-			Display.getDefault().asyncExec(
-				new Runnable ()	{
-					public void run() {
-						// check for NULL, since I am seeing bogus events coming from PCCS before the real one
-						//  and the serial number is not filled in. If the serial number is null,
-						//  everything else will be null (according to the PCCS docs)
-						//  TODO: bug in PCCS API: 
-						if (DEBUG) System.out.printf("DeviceNotificationCallback %x %s\n", dwStatus, (pstrSerialNumber == null ? "serNum: null" : pstrSerialNumber.getPointer().getString(0, true))); //$NON-NLS-1$ //$NON-NLS-2$
-						String serialNumber = NOT_KNOWN;
-						if (pstrSerialNumber != null) {
-							serialNumber = pstrSerialNumber.getPointer().getString(0, true);
-						}
+			// check for NULL, since I am seeing bogus events coming from PCCS before the real one
+			//  and the serial number is not filled in. If the serial number is null,
+			//  everything else will be null (according to the PCCS docs)
+			//  TODO: bug in PCCS API: 
+			if (DEBUG) System.out.printf("DeviceNotificationCallback %x %s\n", dwStatus, (pstrSerialNumber == null ? "serNum: null" : pstrSerialNumber.getPointer().getString(0, true))); //$NON-NLS-1$ //$NON-NLS-2$
+			String serialNumber = NOT_KNOWN;
+			if (pstrSerialNumber != null) {
+				serialNumber = pstrSerialNumber.getPointer().getString(0, true);
+			}
 
-						DeviceEventListener.DeviceEvent eventType = DeviceEventListener.DeviceEvent.DEVICE_LIST_UPDATED;
-						// decode dwStatus per PCCS docs
-						switch(DMAPIDefinitions.GET_CONAPI_CB_STATUS(dwStatus)) {
-						case DMAPIDefinitions.CONAPI_DEVICE_LIST_UPDATED:
-							eventType = DeviceEventListener.DeviceEvent.DEVICE_LIST_UPDATED;
-							break;
-						case DMAPIDefinitions.CONAPI_DEVICE_ADDED:
-							eventType = DeviceEventListener.DeviceEvent.DEVICE_ADDED;
-							break;
-						case DMAPIDefinitions.CONAPI_DEVICE_REMOVED:
-							eventType = DeviceEventListener.DeviceEvent.DEVICE_REMOVED;
-							break;
-						case DMAPIDefinitions.CONAPI_DEVICE_UPDATED:
-							switch(DMAPIDefinitions.GET_CONAPI_CB_INFO(dwStatus)) {
-							case DMAPIDefinitions.CONAPI_CONNECTION_ADDED:
-								eventType = DeviceEventListener.DeviceEvent.DEVICE_UPDATED_ADDEDCONNECTION;
-								break;
-							case DMAPIDefinitions.CONAPI_CONNECTION_REMOVED:
-								eventType = DeviceEventListener.DeviceEvent.DEVICE_UPDATED_REMOVEDCONNECTION;
-								break;
-							case DMAPIDefinitions.CONAPI_DEVICE_RENAMED:
-								eventType = DeviceEventListener.DeviceEvent.DEVICE_UPDATED_RENAMED;
-								break;
-							}
-						}
-						// fire events
-						Iterator<DeviceEventListener> iter = listeners.iterator();
-						while (iter.hasNext()) {
-							iter.next().onDeviceEvent(eventType, serialNumber);
-						}
-					}
+			DeviceEventListener.DeviceEvent eventType = DeviceEventListener.DeviceEvent.DEVICE_LIST_UPDATED;
+			// decode dwStatus per PCCS docs
+			switch(DMAPIDefinitions.GET_CONAPI_CB_STATUS(dwStatus)) {
+			case DMAPIDefinitions.CONAPI_DEVICE_LIST_UPDATED:
+				eventType = DeviceEventListener.DeviceEvent.DEVICE_LIST_UPDATED;
+				break;
+			case DMAPIDefinitions.CONAPI_DEVICE_ADDED:
+				eventType = DeviceEventListener.DeviceEvent.DEVICE_ADDED;
+				break;
+			case DMAPIDefinitions.CONAPI_DEVICE_REMOVED:
+				eventType = DeviceEventListener.DeviceEvent.DEVICE_REMOVED;
+				break;
+			case DMAPIDefinitions.CONAPI_DEVICE_UPDATED:
+				switch(DMAPIDefinitions.GET_CONAPI_CB_INFO(dwStatus)) {
+				case DMAPIDefinitions.CONAPI_CONNECTION_ADDED:
+					eventType = DeviceEventListener.DeviceEvent.DEVICE_UPDATED_ADDEDCONNECTION;
+					break;
+				case DMAPIDefinitions.CONAPI_CONNECTION_REMOVED:
+					eventType = DeviceEventListener.DeviceEvent.DEVICE_UPDATED_REMOVEDCONNECTION;
+					break;
+				case DMAPIDefinitions.CONAPI_DEVICE_RENAMED:
+					eventType = DeviceEventListener.DeviceEvent.DEVICE_UPDATED_RENAMED;
+					break;
 				}
-			);
+			}
+			// fire events
+			Iterator<DeviceEventListener> iter = listeners.iterator();
+			while (iter.hasNext()) {
+				iter.next().onDeviceEvent(eventType, serialNumber);
+			}
 			return PCCSErrors.CONA_OK;
 		}
 	}
@@ -115,10 +109,15 @@
 	private DeviceNotificationCallback pfnCallback = new DeviceNotificationCallback();
 	public static final int PCCS_NOT_FOUND = 1;
 	public static final int PCCS_WRONG_VERSION = 2;
+	private static final int DMAPI_VERSION = DMAPIDefinitions.DMAPI_VERSION_34;
 	
 	private APIHANDLE dmHandle = APIHANDLE.INVALID_HANDLE_VALUE;
 	private APIHANDLE mcHandle = APIHANDLE.INVALID_HANDLE_VALUE;
 	private APIHANDLE upHandle = APIHANDLE.INVALID_HANDLE_VALUE;
+	private boolean dontAskAgain;
+	private boolean doSwitch;
+	
+	private Collection<String> noSwitchConnections = new ArrayList<String>();
 	
 	private void storeDontAskAgain() {
 		Activator.getDefault().getPreferenceStore().setValue(DONT_ASK_AGAIN_KEY, true);
@@ -131,43 +130,47 @@
 	private boolean dontAskAgain() {
 		return Activator.getDefault().getPreferenceStore().getBoolean(DONT_ASK_AGAIN_KEY);
 	}
-	/**
-	 * 
-	 */
+
 	public PCCSConnection() {
 	}
 
 	public void open() throws CoreException {
 		if (library == null) {
-			library = ConnAPILibrary.getInstance();
+			try {
+				library = IConnAPILibrary.INSTANCE;
+			} catch (UnsatisfiedLinkError e) {
+				String msg;
+				if (Activator.isSymSEELayout()) {
+					msg = Messages.ConnAPILibrary_PCCS_Not_Found_Error + Activator.getLoadErrorURL();
+				} else {
+					msg = Messages.ConnAPILibrary_PCSuite_Not_Found_Error + Activator.getLoadErrorURL();
+				}
+				throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCSConnection.PCCS_NOT_FOUND, msg, e));
+			} catch (NoClassDefFoundError e) {
+				String msg;
+				if (Activator.isSymSEELayout()) {
+					msg = Messages.ConnAPILibrary_PCCS_Not_Found_Error + Activator.getLoadErrorURL();
+				} else {
+					msg = Messages.ConnAPILibrary_PCSuite_Not_Found_Error + Activator.getLoadErrorURL();
+				}
+				throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCSConnection.PCCS_NOT_FOUND, msg, e));
+			}
 		}
 		// this uses the MCAPI only to enable required media
 		ensureMediaEnabled();
 		
 		// load DMAPI
-		loadDMAPI();
+		initDMAPI();
+		dmHandle = loadDMAPI();
+		if (!APIHANDLE.INVALID_HANDLE_VALUE.equals(dmHandle)) {
+			startDMNotifications(dmHandle);
+		}
 	}
 	
-	private void ensureMediaEnabled() throws CoreException {
-		// open the MCAPI
-		loadMCAPI();
-		// TODO:
-		// get media
-		// enable media
-		// close MCAPI
-		closeMCAPI();
-	}
-
-	/**
-	 * Initializes the Device Management API (DMAPI) for use.
-	 * 
-	 * @throws CoreException
-	 */
-	private void loadDMAPI() throws CoreException {
-
-		int dwResult = library.DMAPI_Initialize(DMAPIDefinitions.DMAPI_VERSION_34, null);
+	private void initDMAPI() throws CoreException {
+		int dwResult = library.DMAPI_Initialize(DMAPI_VERSION, null);
     	if (dwResult != PCCSErrors.CONA_OK) {
-    		library.DMAPI_Terminate(null);
+    		terminateDMAPI();
     		String msg;
     		if (Activator.isSymSEELayout()) {
         		msg = String.format("PCCS DMAPI_Initialize API returned error on initialization %x", dwResult); //$NON-NLS-1$
@@ -179,38 +182,14 @@
     		}
     		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCS_WRONG_VERSION, msg, null));
     	}
-    	
-    	// initialize common API
-//    	dwResult = library.CFAPI_Initialize(DMAPIDefinitions.CFAPI_VERSION_10, null); unnecessary
-//    	if (dwResult != PCCSErrors.CONA_OK) {
-//    		library.DMAPI_Terminate(null);
-//    		String msg = String.format("PCCS CFAPI_Initialize API returned error on initialization %x", dwResult);
-//    		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, dwResult, msg, null));
-//    	}
-    	
-    	// open a DM handle
-    	dmHandle = APIHANDLE.INVALID_HANDLE_VALUE;
-    	LPAPIHANDLE pHandle = new LPAPIHANDLE();
-    	dwResult = library.CONAOpenDM(pHandle);
-    	
+		if (DEBUG) System.out.println("initDMAPI"); //$NON-NLS-1$
+	}
+	private void startDMNotifications(APIHANDLE handle) throws CoreException {
+    	// register a call back
+    	int dwResult = library.CONARegisterNotifyCallback(handle, PCCSTypeDefinitions.API_REGISTER, pfnCallback);
     	if (dwResult != PCCSErrors.CONA_OK) {
-    		library.DMAPI_Terminate(null);
-    		String msg = String.format(Messages.PCCSConnection_PCCS_CONAOpenDM_Error, dwResult);
-    		if (dwResult == PCCSErrors.ECONA_NOT_ENOUGH_MEMORY) {
-    			msg = Messages.PCCSConnection_PCCS_Not_Enough_Memory_Error;
-    		}
-    		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, dwResult, msg, null));
-    	} else {
-    		dmHandle = pHandle.getValue();
-    	}
-    	
-    	// register a call back
-    	dwResult = library.CONARegisterNotifyCallback(dmHandle, PCCSTypeDefinitions.API_REGISTER, pfnCallback);
-    	if (dwResult != PCCSErrors.CONA_OK) {
-//    		System.out.printf("CONAOpenDM returned: %x\n", dwResult);
-    		library.DMAPI_Terminate(null);
-    		library.CONACloseDM(dmHandle);
-        	dmHandle = APIHANDLE.INVALID_HANDLE_VALUE;
+    		library.CONACloseDM(handle);
+        	handle = APIHANDLE.INVALID_HANDLE_VALUE;
 
         	String msg = String.format(Messages.PCCSConnection_PCCS_CONARegisterNotifyCallback_Error, dwResult);
     		if (dwResult == PCCSErrors.ECONA_INVALID_POINTER) {
@@ -218,6 +197,80 @@
     		}
     		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, dwResult, msg, null));
     	}
+		if (DEBUG) System.out.println("startDMNotifications"); //$NON-NLS-1$
+	
+	}
+	private void ensureMediaEnabled() throws CoreException {
+		// open the MCAPI
+		loadMCAPI();
+		// get media list
+		IntBuffer pdwCount = IntBuffer.allocate(1);
+		CONAPI_MEDIA.ByReference ppMedia = new CONAPI_MEDIA.ByReference();
+
+		int dwResult = library.CONAMMGetMedia(mcHandle, pdwCount, ppMedia);
+		if (DEBUG)
+			System.out.printf("CONAMMGetMedia dwResult = %x\tpdwCount = %d\n", dwResult, pdwCount.get(0)); //$NON-NLS-1$
+
+		int count = pdwCount.get(0);
+		
+		Pointer pMedia = ppMedia.getPointer();
+		Pointer nativePointer = pMedia.getPointer(0); // save this for freeing media
+		int size = ppMedia.size();
+		
+		if (count > 0) {
+			CONAPI_MEDIA media[] = new CONAPI_MEDIA[count];
+			for (int i = 0; i < count; i++) {
+				// get pointer from offset of native pointer
+				Pointer sharedP = nativePointer.share(0 + i*size);
+				media[i] = new CONAPI_MEDIA(sharedP);
+				// and read the data from native memory
+				media[i].read();
+			}
+			for (int i = 0; i < count; i++) {
+				if (MCAPIDefinitions.CONAPI_GET_MEDIA_TYPE(media[i].dwMedia) == MCAPIDefinitions.CONAPI_MEDIA_USB) {
+					if (MCAPIDefinitions.CONAPI_IS_MEDIA_UNACTIVE(media[i].dwState)) {
+						media[i].dwState = MCAPIDefinitions.CONAPI_MEDIA_ACTIVE;
+						dwResult = library.CONAMMSetMedia(mcHandle, media);
+						if (DEBUG)
+							System.out.printf("CONAMMSetMedia dwResult = %x\n", dwResult); //$NON-NLS-1$
+					}
+				}
+			}
+			dwResult = library.CONAMMFreeMediaStructures(count, nativePointer);
+			if (DEBUG)
+				System.out.printf("CONAMMFreeMediaStructures dwResult = %x\n", dwResult); //$NON-NLS-1$
+		}
+
+		// close MCAPI
+		closeMCAPI();
+	}
+
+	/**
+	 * Opens Device Management API (DMAPI) for use. Note: initDMAPI must be called prior to this.<br>
+	 * initDMAPI need be called only once, but this can be called whenever we need a handle to
+	 * the DMAPI.
+	 * 
+	 * @throws CoreException
+	 */
+	private APIHANDLE loadDMAPI() throws CoreException {
+
+    	// open a DM handle
+    	APIHANDLE handle = APIHANDLE.INVALID_HANDLE_VALUE;
+    	LPAPIHANDLE pHandle = new LPAPIHANDLE();
+    	int dwResult = library.CONAOpenDM(pHandle);
+    	
+    	if (dwResult != PCCSErrors.CONA_OK) {
+    		String msg = String.format(Messages.PCCSConnection_PCCS_CONAOpenDM_Error, dwResult);
+    		if (dwResult == PCCSErrors.ECONA_NOT_ENOUGH_MEMORY) {
+    			msg = Messages.PCCSConnection_PCCS_Not_Enough_Memory_Error;
+    		}
+    		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, dwResult, msg, null));
+    	} else {
+    		handle = pHandle.getValue();
+    	}
+    	
+		if (DEBUG) System.out.printf("loadDMAPI handle=%s\n", handle.toString()); //$NON-NLS-1$
+    	return handle;
 	}
 
 	private void loadMCAPI() throws CoreException {
@@ -249,6 +302,7 @@
     	} else {
     		mcHandle = pHandle.getValue();
     	}
+		if (DEBUG) System.out.println("\n-----loadMCAPI"); //$NON-NLS-1$
 	}
 
 	private void loadUPAPI() throws CoreException {
@@ -288,27 +342,40 @@
 		if (library == null)
 			return;
 
+		stopDMNotifications(dmHandle);
+		
 		// DMAPI should only one be open
-		closeDMAPI();		
+		dmHandle = closeDMAPI(dmHandle);
+		
+		terminateDMAPI();
 	}
 	
+	private void terminateDMAPI() {
+    	// Terminate Device management API
+    	int dwResult = library.DMAPI_Terminate(null);
+		if (DEBUG) System.out.println("terminateDMAPI"); //$NON-NLS-1$
+	}
+	private void stopDMNotifications(APIHANDLE handle) {
+		int dwResult = PCCSErrors.CONA_OK;
+		if (!APIHANDLE.INVALID_HANDLE_VALUE.equals(handle)) {
+			// unregister callback
+			dwResult = library.CONARegisterNotifyCallback(handle, PCCSTypeDefinitions.API_UNREGISTER, pfnCallback);
+		}		
+		if (DEBUG) System.out.println("stopDMNotifications"); //$NON-NLS-1$
+	}
 	/**
 	 * Closes the DMAPI.
 	 * @throws CoreException
 	 */
-	private void closeDMAPI() throws CoreException {
+	private APIHANDLE closeDMAPI(APIHANDLE handle) throws CoreException {
 		int dwResult = PCCSErrors.CONA_OK;
-		if (!APIHANDLE.INVALID_HANDLE_VALUE.equals(dmHandle)) {
-			// unregister callback
-			dwResult = library.CONARegisterNotifyCallback(dmHandle, PCCSTypeDefinitions.API_UNREGISTER, pfnCallback);
+		if (!APIHANDLE.INVALID_HANDLE_VALUE.equals(handle)) {
 			// close DM connection
-			dwResult = library.CONACloseDM(dmHandle);
-        	dmHandle = APIHANDLE.INVALID_HANDLE_VALUE;
-        	// Terminate Common Functions API
-//        	dwResult = library.CFAPI_Terminate(null); unnecessary
-        	// Terminate Device management API
-        	dwResult = library.DMAPI_Terminate(null);
+			dwResult = library.CONACloseDM(handle);
+			if (DEBUG) System.out.printf("closeDMAPI ret=%x handle=%s\n", dwResult, handle.toString()); //$NON-NLS-1$
+			handle = APIHANDLE.INVALID_HANDLE_VALUE;
 		}
+		return handle;
 	}
 
 	private void closeMCAPI() {
@@ -320,12 +387,12 @@
         	// Terminate Device management API
     		dwResult = library.MCAPI_Terminate(null);
 		}
+		if (DEBUG) System.out.println("closeMCAPI----\n"); //$NON-NLS-1$
 	}
 	
 	private void closeUPAPI() {
 		int dwResult = PCCSErrors.CONA_OK;
 		if (!APIHANDLE.INVALID_HANDLE_VALUE.equals(upHandle)) {
-//		if (upHandle.getValue() != APIHANDLE.INVALID_HANDLE_VALUE) {
 			// close DM connection
 			dwResult = library.UPAPI_CloseUSBPersonality(upHandle);
 			if (dwResult != PCCSErrors.CONA_OK) {
@@ -341,42 +408,6 @@
 		if (DEBUG) System.out.println("closeUPAPI----\n"); //$NON-NLS-1$
 	}
 
-	public void getMediaList() {
-		if (!APIHANDLE.INVALID_HANDLE_VALUE.equals(mcHandle)) {
-			IntBuffer pdwCount = IntBuffer.allocate(1);
-			
-			CONAPI_MEDIA.ByReference[] ppMedia = (CONAPI_MEDIA.ByReference[])new CONAPI_MEDIA.ByReference().toArray(10);
-			
-			int dwResult = library.CONAMMGetMedia(mcHandle, pdwCount, ppMedia);
-			if (DEBUG) System.out.printf("dwResult = %x\tpdwCount = %d\n", dwResult, pdwCount.get(0)); //$NON-NLS-1$
-			int size = pdwCount.get(0);
-			CONAPI_MEDIA[] pMedia = CONAPI_MEDIA.newArray(10);
-			Pointer p0 = ppMedia[0].getPointer().getPointer(0);
-			Pointer p1 = ppMedia[1].getPointer().getPointer(0);
-			CONAPI_MEDIA media0 = ppMedia[0].newInstance();
-			CONAPI_MEDIA media1 = ppMedia[1].newInstance();
-			if (dwResult == PCCSErrors.CONA_OK) {
-				for (int i = 0; i < size; i++) {
-	//				if (DEBUG) {
-	//					System.out.printf("dwSize=%d\tdwMedia=%x\tpstrDescription=%s\n", 
-	//							media.dwMedia, 
-	//							media.dwMedia, 
-	//							(media.pstrDescription == null) ? "null" : media.pstrDescription.getPointer().getString(0, true));
-	//					System.out.printf("dwState=%d\tdwOptions=%x\tdwMediaData=%d\tpstrID=%s\n", 
-	//							media.dwState,
-	//							media.dwOptions,
-	//							media.dwMediaData,
-	//							(media.pstrID == null) ? "null" : media.pstrID.getPointer().getString(0, true));
-	//				}
-	//
-				}
-				dwResult = library.CONAMMFreeMediaStructures(size, pMedia);
-				if (dwResult != PCCSErrors.CONA_OK) {
-					if (DEBUG) System.out.printf("CONAMMFreeMediaStructures = %x\n", dwResult); //$NON-NLS-1$
-				}
-			}
-		}
-	} 
 	/**
 	 * All devices detected are gotten here - BT, USB, etc.
 	 *  No checking of a valid connection is done here
@@ -385,20 +416,34 @@
 	 */
 	private DeviceInfo[] getCompleteDeviceList() {
 		DeviceInfo[] deviceInfo = null;
-		
+		APIHANDLE handle = APIHANDLE.INVALID_HANDLE_VALUE;
+		try {
+			handle = loadDMAPI();
+		} catch (CoreException e) {
+			return deviceInfo;
+		}
 		IntByReference pdwCount = new IntByReference(0);
-		int dwResult = library.CONAGetDeviceCount(dmHandle, pdwCount);
+		int dwResult = library.CONAGetDeviceCount(handle, pdwCount);
 		if (DEBUG) System.out.printf("CONAGetDeviceCount: %x number of devices: %d\n", dwResult, pdwCount.getValue()); //$NON-NLS-1$
-		if (dwResult != PCCSErrors.CONA_OK)
+		if (dwResult != PCCSErrors.CONA_OK) {
+			try {
+				closeDMAPI(handle);
+			} catch (CoreException e) {
+			}
 			return deviceInfo;
+		}
 		
 		int deviceCount = pdwCount.getValue();
 		if (deviceCount > 0) {
 			
 			CONAPI_DEVICE[] pDevices = (CONAPI_DEVICE[])new CONAPI_DEVICE().toArray(deviceCount);
-			dwResult = library.CONAGetDevices(dmHandle, pdwCount, pDevices);
+			dwResult = library.CONAGetDevices(handle, pdwCount, pDevices);
 			if (DEBUG) System.out.printf("CONAGetDevices: %x number of devices: %d\n", dwResult, deviceCount); //$NON-NLS-1$
 			if (dwResult != PCCSErrors.CONA_OK) {
+				try {
+					closeDMAPI(handle);
+				} catch (CoreException e) {
+				}
 				return deviceInfo;
 			}
 			
@@ -475,10 +520,20 @@
 			}
 			dwResult = library.CONAFreeDeviceStructure(deviceCount, pDevices);
 		}
-		
+		try {
+			closeDMAPI(handle);
+		} catch (CoreException e) {
+		}
+
 		return deviceInfo;
 	}
 
+	/**
+	 * Gets the complete list of connections and weeds out "good" connections (i.e., non-debuggable)
+	 * 
+	 * @return
+	 * @throws CoreException
+	 */
 	public synchronized Collection<DeviceConnection> getGoodConnectionList() throws CoreException {
 		DeviceInfo[] deviceList = getCompleteDeviceList();
 		Collection<DeviceConnection> goodConnections = new ArrayList<DeviceConnection>();
@@ -493,33 +548,48 @@
 			return goodConnections;
 		}
 		boolean upapiOpen = true;
-		Collection<DeviceUSBPersonalityInfo> personalityList = getAllDeviceUSBPersonalities();
-		// sometimes on a phone connected to USB, this is failing at least a couple of times
-		//   so retry a number of times
-		// if there are no USB connections, this failure is expected
-		if (personalityList == null || personalityList.size() == 0) {
-			if (DEBUG) System.out.printf("Error 1 getting USB personalities\n"); //$NON-NLS-1$
-			closeUPAPI();
-			upapiOpen = false;
-			for (int i = 2; i < 6; i++) {
-				try {
-					Thread.sleep(1000);
-				} catch (InterruptedException e) {
+		int numUSBPersonalities = 0;
+		for (DeviceInfo device : deviceList) {
+			Collection<DeviceConnectionInfo> connectionList = device.connections;
+			for (DeviceConnectionInfo connInfo : connectionList) {
+				if (connInfo.media.equals("usb")) {
+					numUSBPersonalities++;
 				}
-				try {
-					loadUPAPI();
-					upapiOpen = true;
-				} catch (CoreException e) {
-					Activator.logError(e);
-				}
-				if (upapiOpen)
-					personalityList = getAllDeviceUSBPersonalities();
-				if (personalityList == null || personalityList.size() == 0) {
-					if (DEBUG) System.out.printf("Error %d getting USB personalities\n", i); //$NON-NLS-1$
-					closeUPAPI();
-					upapiOpen = false;
-				} else {
-					break;
+			}
+		}
+		if (DEBUG)
+			System.out.println("numUSBPersonalities: " + numUSBPersonalities);
+		
+		Collection<DeviceUSBPersonalityInfo> personalityList = null;
+		if (numUSBPersonalities > 0) {
+			personalityList = getAllDeviceUSBPersonalities();
+			// sometimes on a phone connected to USB, this is failing at least a couple of times
+			//   so retry a number of times
+			// if there are no USB connections, this failure is expected
+			if (personalityList == null || personalityList.size() < numUSBPersonalities) {
+				if (DEBUG) System.out.printf("Error 1 getting USB personalities: %d of %d total\n", (personalityList != null) ? personalityList.size() : 0, numUSBPersonalities); //$NON-NLS-1$
+				closeUPAPI();
+				upapiOpen = false;
+				for (int i = 2; i < 6; i++) {
+					try {
+						Thread.sleep(1000);
+					} catch (InterruptedException e) {
+					}
+					try {
+						loadUPAPI();
+						upapiOpen = true;
+					} catch (CoreException e) {
+						Activator.logError(e);
+					}
+					if (upapiOpen)
+						personalityList = getAllDeviceUSBPersonalities();
+					if (personalityList == null || personalityList.size() < numUSBPersonalities) {
+						if (DEBUG) System.out.printf("Error %d getting USB personalities: %d of %d total\n", (personalityList != null) ? personalityList.size() : 0, numUSBPersonalities); //$NON-NLS-1$
+						closeUPAPI();
+						upapiOpen = false;
+					} else {
+						break;
+					}
 				}
 			}
 		}
@@ -531,6 +601,8 @@
 			upapiOpen = true;
 		}
 		
+		forgetAllNoSwitchConnectionsNotInCurrentList(personalityList);
+		
 		// go through each connected device and check for good connection modes (e.g. USB in debuggable mode)
 		if (DEBUG) System.out.printf("getGoodConnectionList: sizeof deviceList: %d\n", deviceList.length); //$NON-NLS-1$
 		for (DeviceInfo device : deviceList) {
@@ -582,6 +654,34 @@
 		return goodConnections;
 	}
 	/**
+	 * Forget all previous "no-switch-personality" devices that are not in current list (e.g., device is now disconnected)
+	 * 
+	 * @param personalityList
+	 */
+	private void forgetAllNoSwitchConnectionsNotInCurrentList(
+			Collection<DeviceUSBPersonalityInfo> personalityList) {
+		if (personalityList == null || personalityList.isEmpty()) {
+			if (DEBUG) System.out.println("forgetAllNoSwitchConnectionsNotInCurrentList: all");
+			noSwitchConnections.clear();
+		} else if (noSwitchConnections == null || noSwitchConnections.isEmpty()) {
+			if (DEBUG) System.out.println("forgetAllNoSwitchConnectionsNotInCurrentList: noSwitchConnections already empty");
+				return;
+		} else {
+			for (String id : new ArrayList<String>(noSwitchConnections)) {
+				boolean found = false;
+				for (DeviceUSBPersonalityInfo personality : personalityList) {
+					if (id.equals(personality.deviceID)) {
+						found = true;
+					}
+				}
+				if (!found) {
+					if (DEBUG) System.out.println("forgetAllNoSwitchConnectionsNotInCurrentList: " + id);
+					noSwitchConnections.remove(id);
+				}
+			}
+		}		
+	}
+	/**
 	 * Find a matching device in the personality list (all USB devices).<p>
 	 * Might have to use a combination of the serial number and device ID to match with ID's from personality.
 	 *
@@ -620,6 +720,13 @@
 					return personality;
 				}
 			}
+			// sometimes the serial number is part of the address!
+			if (!address.equals(NOT_KNOWN) && !personality.serialNumber.equals(NOT_KNOWN)) {
+				if (address.endsWith(personality.serialNumber)) {
+					if (DEBUG) System.out.println("findPersonality: address contains serialNumber");
+					return personality;
+				}
+			}
 		}
 		if (DEBUG) System.out.println("findPersonality end return null"); //$NON-NLS-1$
 		return null;
@@ -650,6 +757,7 @@
 			connInfo.mode = "serial"; //$NON-NLS-1$
 			connInfo.port = getUSBComPort(connInfo.address);
 			// good personality
+			forgetNoSwitchConnections(personality.deviceID);
 			return true;
 		}
 
@@ -669,37 +777,80 @@
 			return false;
 		}
 
-		// ask to switch
-		askToSwitchPersonality(device, personality, goodCode, goodDesc);
+		if (!noSwitchConnectionsContains(personality.deviceID))
+			// ask to switch
+			askToSwitchPersonality(device, personality, goodCode, goodDesc);
 
 		// was bad personality - if we switched, it will be good next notification
 		if (DEBUG) System.out.println("isGoodUSBPersonality: return false"); //$NON-NLS-1$
 		return false;
 	}
-	private void askToSwitchPersonality(DeviceInfo device,
-			DeviceUSBPersonalityInfo personality, int goodCode, String goodDesc) {
+	
+	/**
+	 * Search previous "no-switch-personality" list for a new device (e.g., user already said no before - don't ask again unless he reconnects)
+	 *  
+	 * @param deviceID
+	 * @return
+	 */
+	private boolean noSwitchConnectionsContains(String deviceID) {
+		if (!noSwitchConnections.isEmpty()) {
+			for (String id : noSwitchConnections) {
+				if (id.equals(deviceID)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	/**
+	 * Forget one device in previous "no-switch-personality" list (e.g., device is now in a good personality and doesn't need switching)
+	 * 
+	 * @param deviceID
+	 */
+	private void forgetNoSwitchConnections(String deviceID) {
+		if (noSwitchConnections.isEmpty()) {
+			if (DEBUG) System.out.println("forgetNoSwitchConnections empty");
+			return;
+		}
+		for (String id : new ArrayList<String>(noSwitchConnections)) {
+			if (id.equals(deviceID)) {
+				if (DEBUG) System.out.println("forgetNoSwitchConnections: " + deviceID);
+				noSwitchConnections.remove(id);
+			}
+		}
+	}
+	private void askToSwitchPersonality(final DeviceInfo device,
+			final DeviceUSBPersonalityInfo personality, final int goodCode, final String goodDesc) {
+		
+		doSwitch = false;
+		Display.getDefault().syncExec(
+			new Runnable() {
 
-		// ask the user and switch
-		String fmt = Messages.PCCSConnection_Switch_Message1 +
-		Messages.PCCSConnection_Swtich_Message2 +
-		Messages.PCCSConnection_Switch_Message3 +
-		Messages.PCCSConnection_Switch_Message4;
-		String message = MessageFormat.format(fmt,
-				device.friendlyName,
-				personality.currentPersonalityDescription,
-				goodDesc);
+				public void run() {
+					// ask the user and switch
+					String fmt = Messages.PCCSConnection_Switch_Message1 +
+					Messages.PCCSConnection_Swtich_Message2 +
+					Messages.PCCSConnection_Switch_Message3 +
+					Messages.PCCSConnection_Switch_Message4;
+					String message = MessageFormat.format(fmt,
+							device.friendlyName,
+							personality.currentPersonalityDescription,
+							goodDesc);
 
-		MessageDialogWithToggle dlg = MessageDialogWithToggle.openYesNoQuestion(
-				WorkbenchUtils.getSafeShell(), 
-				Messages.PCCSConnection_Switch_Message_Title, 
-				message, 
-				Messages.PCCSConnection_DontAsk_CheckText, 
-				false, 
-				null, 
-				null);
-		boolean dontAskAgain = dlg.getToggleState();
-		boolean doSwitch = (dlg.getReturnCode() == IDialogConstants.YES_ID);
-		
+					MessageDialogWithToggle dlg = MessageDialogWithToggle.openYesNoQuestion(
+							WorkbenchUtils.getSafeShell(), 
+							Messages.PCCSConnection_Switch_Message_Title, 
+							message, 
+							Messages.PCCSConnection_DontAsk_CheckText, 
+							false, 
+							null, 
+							null);
+					dontAskAgain = dlg.getToggleState();
+					doSwitch = (dlg.getReturnCode() == IDialogConstants.YES_ID);
+					
+				}
+			}
+		);
 		if (doSwitch) {
 			WString pstrDeviceId = new WString(personality.deviceID);
 			int dwResult = library.UPAPI_SetPersonality(upHandle, pstrDeviceId, goodCode);
@@ -707,6 +858,15 @@
 				if (DEBUG)
 					System.out.printf("UPAPI_SetPersonality failed: %x\n", dwResult); //$NON-NLS-1$
 			}
+		} else {
+			// remember this device so we don't ask again unless it changes personality or is reconnected
+			rememberNoSwitchConnections(personality.deviceID);
+			// also log an info message to error log regarding this
+			String fmt = Messages.PCCSConnection_Switch_Message1 + Messages.PCCSConnection_Swtich_Message2;
+			String message = MessageFormat.format(fmt, 	device.friendlyName,
+							personality.currentPersonalityDescription,
+							goodDesc);
+			Activator.logMessage(message, IStatus.INFO);
 		}
 		// store don't ask again only if selected
 		if (dontAskAgain)
@@ -714,12 +874,22 @@
 	}
 
 	/**
+	 * Device is bad personality and user said 'no' to switch (we won't ask again for this device unless it is reconnected or now in a good mode)
+	 * 
+	 * @param deviceID
+	 */
+	private void rememberNoSwitchConnections(String deviceID) {
+		if (DEBUG) System.out.println("rememberNoSwitchConnections: " + deviceID);
+		noSwitchConnections.add(deviceID);
+	}
+	/**
 	 * This function assumes the UPAPI has already been loaded by the caller
 	 * @return - list of personalities
 	 */
 	private Collection<DeviceUSBPersonalityInfo> getAllDeviceUSBPersonalities() {
 		Collection<DeviceUSBPersonalityInfo> p = new ArrayList<DeviceUSBPersonalityInfo>();
 		boolean apiError = false;
+
 		// how many USB devices are connected
 		IntBuffer pdwDeviceCount = IntBuffer.allocate(1);
 		int dwResult = library.UPAPI_QueryDeviceCount(upHandle, pdwDeviceCount);
@@ -771,7 +941,7 @@
 			if (DEBUG)
 				System.out.printf("UPAPI_QueryDeviceCount dwResult = %x\n", dwResult); //$NON-NLS-1$
 		}
-		if (DEBUG) System.out.printf("getAllDeviceUSBPersonalities return p size : %s\n", p.size()); //$NON-NLS-1$
+		if (DEBUG) System.out.printf("getAllDeviceUSBPersonalities return size : %s\n", p.size()); //$NON-NLS-1$
 		return p;
 	}
 	private boolean getPersonalityDescriptors(
@@ -846,134 +1016,6 @@
 		return apiError;
 	}
 
-	/**
-	 * @return null if no device found.
-	 * @throws CoreException
-	 * @deprecated Use {@link #getGoodConnectionList()} instead.
-	 */
-	public DeviceInfo[] getDeviceList() throws CoreException {
-		
-		DeviceInfo[] deviceInfo = null;
-		
-		int dwResult = PCCSErrors.CONA_OK;
-		IntByReference pdwCount = new IntByReference(0);
-		dwResult = library.CONAGetDeviceCount(dmHandle, pdwCount);
-		if (DEBUG) System.out.printf("CONAGetDeviceCount: %x number of devices: %d\n", dwResult, pdwCount.getValue()); //$NON-NLS-1$
-
-		int deviceCnt = pdwCount.getValue();
-		if (dwResult != PCCSErrors.CONA_OK || deviceCnt == 0)
-			return deviceInfo;
-		
-		// array of structs in contiguous memory required !
-		CONAPI_DEVICE[] pDevices = (CONAPI_DEVICE[])new CONAPI_DEVICE().toArray(deviceCnt);
-		dwResult = library.CONAGetDevices(dmHandle, pdwCount, pDevices);
-		if (DEBUG) System.out.printf("CONAGetDevices: %x number of devices: %d\n", dwResult, deviceCnt); //$NON-NLS-1$
-		
-		if (dwResult == PCCSErrors.CONA_OK) {
-			// extract to regular java types
-			if (deviceCnt > 0) {
-				deviceInfo = new DeviceInfo[deviceCnt];
-				CONAPI_DEVICE[] devices = pDevices;
-				for (int i = 0; i < deviceCnt; i++) {
-					deviceInfo[i] = new DeviceInfo();
-					if (devices[i].pstrSerialNumber != null) {
-						deviceInfo[i].serialNumber = devices[i].pstrSerialNumber.getPointer().getString(0, true);
-					} else {
-						// TODO: docs say if ser num == null --> device unsupported, but this is a bug in PCCS
-						deviceInfo[i].serialNumber = NOT_KNOWN; //$NON-NLS-1$
-					}
-					if (devices[i].pstrFriendlyName != null) {
-						deviceInfo[i].friendlyName = devices[i].pstrFriendlyName.getPointer().getString(0, true);
-					} else {
-						deviceInfo[i].friendlyName = NOT_KNOWN; //$NON-NLS-1$
-					}
-					if (devices[i].pstrModel != null) {
-						deviceInfo[i].model = devices[i].pstrModel.getPointer().getString(0, true);
-					} else {
-						deviceInfo[i].model = NOT_KNOWN; //$NON-NLS-1$
-					}
-					if (devices[i].pstrManufacturer != null) {
-						deviceInfo[i].mfr = devices[i].pstrManufacturer.getPointer().getString(0, true);
-					} else {
-						deviceInfo[i].mfr = NOT_KNOWN; //$NON-NLS-1$
-					}
-					int numItems = deviceInfo[i].numberOfConnections = devices[i].dwNumberOfItems;
-					
-					CONAPI_CONNECTION_INFO[] conn = null;
-					if (numItems > 0)
-						 conn = (CONAPI_CONNECTION_INFO[])devices[i].pItems.toArray(numItems);
-					for (int j = 0; j < numItems; j++) {
-						DeviceConnectionInfo connInfo = new DeviceConnectionInfo();
-						connInfo.deviceID = conn[j].dwDeviceID;
-						switch(conn[j].dwMedia){
-						case PCCSTypeDefinitions.API_MEDIA_BLUETOOTH:
-							connInfo.media = "bluetooth"; //$NON-NLS-1$
-							break;
-						case PCCSTypeDefinitions.API_MEDIA_IRDA:
-							connInfo.media = "irda"; //$NON-NLS-1$
-							break;
-						case PCCSTypeDefinitions.API_MEDIA_SERIAL:
-							connInfo.media = "serial-ca42"; //$NON-NLS-1$
-							break;
-						default:
-						case PCCSTypeDefinitions.API_MEDIA_USB:
-							connInfo.media = "usb"; //$NON-NLS-1$
-							break;
-						}
-						if (conn[j].pstrDeviceName != null) {
-							connInfo.deviceName = conn[j].pstrDeviceName.getPointer().getString(0,true);
-							if (deviceInfo[i].friendlyName.equals(NOT_KNOWN)) { //$NON-NLS-1$
-								// use device name as friendly name (latter was null)
-								deviceInfo[i].friendlyName = connInfo.deviceName;
-							}
-						} else {
-							connInfo.deviceName = NOT_KNOWN; //$NON-NLS-1$
-						}
-						// Bomb if friendly name is not known or address is not known
-						//   since these are essential to a connection
-						if (conn[j].pstrAddress == null || deviceInfo[i].friendlyName.equals(NOT_KNOWN)) //$NON-NLS-1$
-							continue;
-						
-						connInfo.address = conn[j].pstrAddress.getPointer().getString(0, true);
-						connInfo.state = conn[j].dwState;
-						
-						if (connInfo.media.equals("usb")) { //$NON-NLS-1$
-							if (checkUSBMode(deviceInfo[i], connInfo)){ 
-								connInfo.port = getUSBComPort(connInfo.address);
-							} else {
-								// don't store - not in good USB personality mode
-								continue;
-							}
-						} else if (connInfo.media.equals("bluetooth")) { //$NON-NLS-1$
-							// TODO: implement BT
-							connInfo.port = getBTComPort(connInfo.address);
-						} else {
-							// IRDA and Serial(CA42) probably will not come here anyway
-							connInfo.port = null;
-						}
-						if (connInfo.port != null)
-							deviceInfo[i].connections.add(connInfo);
-					}
-				}
-			}
-			dwResult = library.CONAFreeDeviceStructure(deviceCnt, pDevices);
-			if (DEBUG) System.out.printf("CONAFreeDeviceStructure: %x\n", dwResult); //$NON-NLS-1$
-		}
-		return deviceInfo;
-	}
-
-	/**
-	 * 
-	 * @param deviceInfo
-	 * @param connInfo
-	 * @return
-	 * 
-	 * @deprecated not used anymore
-	 */
-	private boolean checkUSBMode(DeviceInfo deviceInfo,
-			DeviceConnectionInfo connInfo) {
-		return true;
-	}
 
 	private String getBTComPort(String address) {
 		// TODO Auto-generated method stub
@@ -1053,4 +1095,89 @@
 		//  string = personality description for code from device
 		Map<Integer, String> supportedPersonalities;
 	}
+	public void testPrerequisites() throws CoreException {
+		try {
+			if (library == null)
+				library = IConnAPILibrary.INSTANCE;
+		} catch (UnsatisfiedLinkError e) {
+			String msg;
+			if (Activator.isSymSEELayout()) {
+				msg = Messages.ConnAPILibrary_PCCS_Not_Found_Error + Activator.getLoadErrorURL();
+			} else {
+				msg = Messages.ConnAPILibrary_PCSuite_Not_Found_Error + Activator.getLoadErrorURL();
+			}
+			throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCSConnection.PCCS_NOT_FOUND, msg, e));
+		} catch (NoClassDefFoundError e) {
+			String msg;
+			if (Activator.isSymSEELayout()) {
+				msg = Messages.ConnAPILibrary_PCCS_Not_Found_Error + Activator.getLoadErrorURL();
+			} else {
+				msg = Messages.ConnAPILibrary_PCSuite_Not_Found_Error + Activator.getLoadErrorURL();
+			}
+			throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCSConnection.PCCS_NOT_FOUND, msg, e));
+		}
+		testDMAPI();
+		testUPAPI();
+		testMCAPI();
+	}
+	/*
+	 * Tests version of DMAPI and leaves it closed
+	 */
+	private void testDMAPI() throws CoreException {
+		int dwResult = library.DMAPI_Initialize(DMAPI_VERSION, null);
+		library.DMAPI_Terminate(null);
+    	if (dwResult != PCCSErrors.CONA_OK) {
+    		String msg;
+    		if (Activator.isSymSEELayout()) {
+        		msg = String.format("PCCS DMAPI_Initialize API returned error on initialization %x", dwResult); //$NON-NLS-1$
+        		if (dwResult == PCCSErrors.ECONA_UNSUPPORTED_API_VERSION) {
+        			msg = Messages.PCCSConnection_PCCS_Version_Error + Activator.getLoadErrorURL();
+        		}
+    		} else {
+    			msg = Messages.PCCSConnection_PCSuite_Version_Error + Activator.getLoadErrorURL();
+    		}
+    		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCS_WRONG_VERSION, msg, null));
+    	}
+	}
+	/*
+	 * Test version of UPAPI and leaves it closed
+	 */
+	private void testUPAPI() throws CoreException {
+		int dwResult = PCCSErrors.CONA_OK;
+		dwResult = library.UPAPI_Initialize(UPAPIDefinitions.UPAPI_VERSION_10, null);
+		library.UPAPI_Terminate(null);
+    	if (dwResult != PCCSErrors.CONA_OK) {
+    		String msg;
+    		msg = String.format("PCCS UPAPI_Initialize API returned error on initialization %x", dwResult); //$NON-NLS-1$
+    		if (DEBUG) System.out.println(msg);
+    		if (Activator.isSymSEELayout()) {
+        		if (dwResult == PCCSErrors.ECONA_UNSUPPORTED_API_VERSION) {
+        			msg = Messages.PCCSConnection_PCCS_Version_Error + Activator.getLoadErrorURL();
+        		}
+    		} else {
+    			msg = Messages.PCCSConnection_PCSuite_Version_Error + Activator.getLoadErrorURL();
+    		}
+    		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCS_WRONG_VERSION, msg, null));
+    	}
+	}
+	/*
+	 * Test version of MCAPI and leaves it closed
+	 */
+	private void testMCAPI() throws CoreException {
+		int dwResult = PCCSErrors.CONA_OK;
+		dwResult = library.MCAPI_Initialize(MCAPIDefinitions.MCAPI_VERSION_32, null);
+		library.MCAPI_Terminate(null);
+    	if (dwResult != PCCSErrors.CONA_OK) {
+    		String msg;
+    		if (Activator.isSymSEELayout()) {
+        		msg = String.format("PCCS MCAPI_Initialize API returned error on initialization %x", dwResult); //$NON-NLS-1$
+        		if (dwResult == PCCSErrors.ECONA_UNSUPPORTED_API_VERSION) {
+        			msg = Messages.PCCSConnection_PCCS_Version_Error + Activator.getLoadErrorURL();
+        		}
+    		} else {
+    			msg = Messages.PCCSConnection_PCSuite_Version_Error + Activator.getLoadErrorURL();
+    		}
+    		throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PCCS_WRONG_VERSION, msg, null));
+    	}
+	}
 }