int CCONV CPhidgetDictionary_getKey(CPhidgetDictionaryHandle dict, const char *key, char *val, int vallen)
{
	int result, size;
	char err[1024], *keywrap;
	TESTPTRS(dict, key)
	TESTPTR(val)

	CThread_mutex_lock(&dict->lock);
	if(!CPhidget_statusFlagIsSet(dict->status, PHIDGET_SERVER_CONNECTED_FLAG))
	{
		CThread_mutex_unlock(&dict->lock);
		return EPHIDGET_NETWORK_NOTCONNECTED;
	}

	//The get command returns a list of keys - since we want just a single key, lets wrap in ^ and $
	//other reg exp tags are allowed and will be honoured
	size = (int)strlen(key);
	keywrap = (char *)malloc(size+3);
	snprintf(keywrap, size+3, "^%s$",key);

	CThread_mutex_lock(&dict->networkInfo->server->pdc_lock);
	result = pdc_get(dict->networkInfo->server->pdcs, keywrap, val, vallen, err, sizeof(err));
	CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);

	free(keywrap);

	CThread_mutex_unlock(&dict->lock);

	if(result == 0) return EPHIDGET_UNEXPECTED;
	return EPHIDGET_OK;
}
int CCONV CPhidgetManager_close(CPhidgetManagerHandle phidm)
{
	TESTPTR(phidm)

	CThread_mutex_lock(&phidm->openCloseLock);
	if (!CPhidget_statusFlagIsSet(phidm->status, PHIDGET_OPENED_FLAG))
	{
		LOG(PHIDGET_LOG_WARNING, "Close was called on an already closed Manager handle.");
		CThread_mutex_unlock(&phidm->openCloseLock);
		return EPHIDGET_OK;
	}

	if(phidm->state == PHIDGETMANAGER_ACTIVE || phidm->state == PHIDGETMANAGER_ACTIVATING)
	{
		phidm->state = PHIDGETMANAGER_INACTIVE;
		CPhidget_clearStatusFlag(&phidm->status, PHIDGET_ATTACHED_FLAG, &phidm->lock);
		if(CPhidget_statusFlagIsSet(phidm->status, PHIDGET_REMOTE_FLAG))
		{
			//Only free the list phidgets if this is an openRemoteIP - not for openRemote
			int freeList = phidm->networkInfo->mdns ? PFALSE : PTRUE;
			unregisterRemoteManager(phidm);

			CList_emptyList((CListHandle *)&phidm->AttachedPhidgets, freeList, CPhidget_free);
		}
		else
		{
			CThread_mutex_lock(&managerLock);
			ActivePhidgetManagers--;
			CList_removeFromList((CListHandle *)&localPhidgetManagers, phidm, CPhidgetManager_areEqual, PFALSE, NULL);
			CThread_mutex_unlock(&managerLock);
		}
	}
	
	//if there are no more active phidgets or managers, wait for the central thread to exit
	if(!ActiveDevices && !ActivePhidgetManagers)
	{
		JoinCentralThread();
		//Shut down USB
#if defined(_LINUX) && !defined(_ANDROID)
		CUSBUninit();
#endif
	}

	CPhidget_clearStatusFlag(&phidm->status, PHIDGET_OPENED_FLAG, &phidm->lock);
	CThread_mutex_unlock(&phidm->openCloseLock);
	return EPHIDGET_OK;
}
Beispiel #3
0
int CCONV CPhidgetDictionary_set_OnKeyChange_Handler(CPhidgetDictionaryHandle dict, CPhidgetDictionaryListenerHandle *dictlistener, const char *pattern, 
	int(CCONV *fptr)(CPhidgetDictionaryHandle dict, void *userPtr, const char *key, const char *val, CPhidgetDictionary_keyChangeReason reason),
	void *userPtr)
{
	CPhidgetDictionaryListenerHandle dict_listener;
	char errdesc[1024];
	int result;

	TESTPTRS(dict, pattern)
	TESTPTR(dictlistener)

	CThread_mutex_lock(&dict->lock);
	if(!CPhidget_statusFlagIsSet(dict->status, PHIDGET_SERVER_CONNECTED_FLAG))
	{
		CThread_mutex_unlock(&dict->lock);
		return EPHIDGET_NETWORK_NOTCONNECTED;
	}
		
	if(!(dict_listener = malloc(sizeof(CPhidgetDictionaryListener))))
	{
		CThread_mutex_unlock(&dict->lock);
		return EPHIDGET_NOMEMORY;
	}
	ZEROMEM(dict_listener, sizeof(CPhidgetDictionaryListener));
	
	dict_listener->dict = dict;
	dict_listener->fptr = fptr;
	dict_listener->userPtr = userPtr;
	
	CThread_mutex_lock(&dict->networkInfo->server->pdc_lock);
	if (!(dict_listener->listen_id = pdc_listen(dict->networkInfo->server->pdcs, pattern, dict_event_handler, dict_listener, errdesc, sizeof (errdesc))))
	{
		LOG(PHIDGET_LOG_DEBUG,"pdc_listen: %s", errdesc);
		free(dict_listener);
		CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);
		CThread_mutex_unlock(&dict->lock);
		return EPHIDGET_UNEXPECTED;
	}
	CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);
	
	CThread_mutex_lock(&dict->listenersLock);
	if((result = CList_addToList((CListHandle *)&dict->listeners, dict_listener, CPhidgetDictionaryListener_areEqual)))
	{
		CThread_mutex_unlock(&dict->listenersLock);
		CThread_mutex_lock(&dict->networkInfo->server->pdc_lock);
		pdc_ignore(dict->networkInfo->server->pdcs, dict_listener->listen_id, NULL, 0);
		CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);
		free(dict_listener);
		CThread_mutex_unlock(&dict->lock);
		return result;
	}
	CThread_mutex_unlock(&dict->listenersLock);
	CThread_mutex_unlock(&dict->lock);

	*dictlistener = dict_listener;
	
	return EPHIDGET_OK;
}
Beispiel #4
0
int CPhidgetDetachEvent(CPhidgetHandle phid) {
	int result = 0;
	CPhidgetList *trav = 0;
	CPhidgetManagerList *trav2 = 0;
	CPhidgetHandle travPhid = 0;
	TESTPTR(phid)
	CPhidget_clearStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, NULL);
	CPhidget_setStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, NULL);
	for(trav2 = localPhidgetManagers; trav2; trav2 = trav2->next)
	{
		if (trav2->phidm->fptrDetachChange && trav2->phidm->state == PHIDGETMANAGER_ACTIVE)
			trav2->phidm->fptrDetachChange((CPhidgetHandle)phid, trav2->phidm->fptrDetachChangeptr);
	}
	CPhidget_clearStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, NULL);

	CThread_mutex_lock(&activeDevicesLock);
	for (trav=ActiveDevices; trav; trav = trav->next)
	{	
		if((CPhidget_areExtraEqual(phid, trav->phid) && CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) 
			|| CPhidgetHandle_areEqual(phid, trav->phid))
		{
			CPhidget_setStatusFlag(&trav->phid->status, PHIDGET_DETACHING_FLAG, &trav->phid->lock);
			if(trav->phid->specificDevice == 2)
				trav->phid->specificDevice = 0;

			trav->phid->writeStopFlag = PTRUE;
			CThread_set_event(&trav->phid->writeAvailableEvent); //if it's waiting on this event - signal NOW

			result = CUSBCloseHandle(trav->phid);
			CThread_join(&trav->phid->writeThread);
			CThread_join(&trav->phid->readThread);

			//because trav can be freed during the detach call, don't use it in or after the call
			travPhid = trav->phid;
			CThread_mutex_unlock(&activeDevicesLock);
			if (travPhid->fptrDetach)
				travPhid->fptrDetach((CPhidgetHandle)travPhid, travPhid->fptrDetachptr);

			travPhid->deviceIDSpec = 0;

			CPhidgetFHandle_free(travPhid->CPhidgetFHandle);
			travPhid->CPhidgetFHandle = NULL;
			
			CPhidget_clearStatusFlag(&travPhid->status, PHIDGET_DETACHING_FLAG, &travPhid->lock);
			CPhidget_clearStatusFlag(&travPhid->status, PHIDGET_USB_ERROR_FLAG, &travPhid->lock);
			goto found_to_detach;
		}

	}
	CThread_mutex_unlock(&activeDevicesLock);

found_to_detach:
	result = CList_removeFromList((CListHandle *)&AttachedDevices, phid, CPhidget_areExtraEqual, TRUE, CPhidget_free);

	return result;
}
int CCONV CPhidgetManager_open(CPhidgetManagerHandle phidm)
{
	int result = EPHIDGET_OK;
	
	TESTPTR(phidm)
	
#if defined(_IPHONE)
	return EPHIDGET_UNSUPPORTED;
#endif
	
#if defined(_ANDROID)
	if(!ANDROID_USB_GOOD)
		return EPHIDGET_UNSUPPORTED;
#endif
	
	CThread_mutex_lock(&phidm->openCloseLock);
	if (CPhidget_statusFlagIsSet(phidm->status, PHIDGET_OPENED_FLAG))
	{
		LOG(PHIDGET_LOG_WARNING, "Open was called on an already opened Manager handle.");
		CThread_mutex_unlock(&phidm->openCloseLock);
		return EPHIDGET_OK;
	}

	if(!phidgetLocksInitialized)
	{
		CThread_mutex_init(&activeDevicesLock);
		CThread_mutex_init(&attachedDevicesLock);
		phidgetLocksInitialized = PTRUE;
	}

	if(phidm->state == PHIDGETMANAGER_INACTIVE)
	{
		CThread_mutex_lock(&managerLock);
	
		CList_addToList((CListHandle *)&localPhidgetManagers, phidm, CPhidgetManager_areEqual);
		
#ifdef _MACOSX
		phidm->state = PHIDGETMANAGER_ACTIVE;
#else
		phidm->state = PHIDGETMANAGER_ACTIVATING;
#endif
		
		CPhidget_setStatusFlag(&phidm->status, PHIDGET_ATTACHED_FLAG, &phidm->lock);

		ActivePhidgetManagers++;

		CThread_mutex_unlock(&managerLock);

		result = StartCentralThread();
	}

	CPhidget_setStatusFlag(&phidm->status, PHIDGET_OPENED_FLAG, &phidm->lock);
	CThread_mutex_unlock(&phidm->openCloseLock);
	return result;
}
Beispiel #6
0
int CCONV CPhidgetManager_close(CPhidgetManagerHandle phidm)
{
	TESTPTR(phidm)

	CThread_mutex_lock(&phidm->openCloseLock);
	if (!CPhidget_statusFlagIsSet(phidm->status, PHIDGET_OPENED_FLAG))
	{
		LOG(PHIDGET_LOG_WARNING, "Close was called on an already closed Manager handle.");
		CThread_mutex_unlock(&phidm->openCloseLock);
		return EPHIDGET_OK;
	}

	if(phidm->state == PHIDGETMANAGER_ACTIVE || phidm->state == PHIDGETMANAGER_ACTIVATING)
	{
		phidm->state = PHIDGETMANAGER_INACTIVE;
		CPhidget_clearStatusFlag(&phidm->status, PHIDGET_ATTACHED_FLAG, &phidm->lock);
		if(CPhidget_statusFlagIsSet(phidm->status, PHIDGET_REMOTE_FLAG))
		{
			unregisterRemoteManager(phidm);
		}
		else
		{
			CThread_mutex_lock(&managerLock);
			ActivePhidgetManagers--;
			CList_removeFromList((CListHandle *)&localPhidgetManagers, phidm, CPhidgetManager_areEqual, PFALSE, NULL);
			CThread_mutex_unlock(&managerLock);
		}
	}
	
	//if there are no more active phidgets or managers, wait for the central thread to exit
	if(!ActiveDevices && !ActivePhidgetManagers)
	{
		JoinCentralThread();
	}

	CPhidget_clearStatusFlag(&phidm->status, PHIDGET_OPENED_FLAG, &phidm->lock);
	CThread_mutex_unlock(&phidm->openCloseLock);
	return EPHIDGET_OK;
}
Beispiel #7
0
void CPhidgetManager_free(void *arg)
{
	CPhidgetManagerHandle phidm = (CPhidgetManagerHandle)arg;
	if(!phidm) return;

	if(CPhidget_statusFlagIsSet(phidm->status, PHIDGET_REMOTE_FLAG))
	{
		CList_emptyList((CListHandle *)phidm->AttachedPhidgets, PTRUE, CPhidget_free);
	}

	CThread_mutex_destroy(&phidm->lock);
	CThread_mutex_destroy(&phidm->openCloseLock);

	free(phidm); phidm = NULL;
	return;
}
Beispiel #8
0
/* Async add - errors returned to a registered error handler */
int CCONV CPhidgetDictionary_addKey(CPhidgetDictionaryHandle dict, const char *key, const char *val, int persistent)
{
	TESTPTR(dict)
	TESTPTRS(key, val)

	CThread_mutex_lock(&dict->lock);
	if(!CPhidget_statusFlagIsSet(dict->status, PHIDGET_SERVER_CONNECTED_FLAG))
	{
		CThread_mutex_unlock(&dict->lock);
		return EPHIDGET_NETWORK_NOTCONNECTED;
	}

	pdc_async_set(dict->networkInfo->server->pdcs, key, val, (int)strlen(val), persistent?0:1, internal_async_network_error_handler, dict);

	CThread_mutex_unlock(&dict->lock);

	return EPHIDGET_OK;
}
int CCONV CPhidgetDictionary_removeKey(CPhidgetDictionaryHandle dict, const char *pattern)
{
	int result;
	char err[1024];
	TESTPTRS(dict, pattern)

	CThread_mutex_lock(&dict->lock);
	if(!CPhidget_statusFlagIsSet(dict->status, PHIDGET_SERVER_CONNECTED_FLAG))
	{
		CThread_mutex_unlock(&dict->lock);
		return EPHIDGET_NETWORK_NOTCONNECTED;
	}

	CThread_mutex_lock(&dict->networkInfo->server->pdc_lock);
	result = pdc_remove(dict->networkInfo->server->pdcs, pattern, err, sizeof(err));
	CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);

	CThread_mutex_unlock(&dict->lock);

	if(result == 0) return EPHIDGET_UNEXPECTED;
	return EPHIDGET_OK;
}
Beispiel #10
0
int CCONV CPhidgetDictionary_close(CPhidgetDictionaryHandle dict)
{
	int result = EPHIDGET_OK;
	TESTPTR(dict)

	CThread_mutex_lock(&dict->openCloseLock);
	if (!CPhidget_statusFlagIsSet(dict->status, PHIDGET_OPENED_FLAG))
	{
		LOG(PHIDGET_LOG_WARNING, "Close was called on an already closed Dictionary handle.");
		CThread_mutex_unlock(&dict->openCloseLock);
		return EPHIDGET_OK;
	}

	if((result = unregisterRemoteDictionary(dict)) != EPHIDGET_OK)
	{
		CThread_mutex_unlock(&dict->openCloseLock);
		return result;
	}

	CPhidget_clearStatusFlag(&dict->status, PHIDGET_OPENED_FLAG, &dict->lock);
	CThread_mutex_unlock(&dict->openCloseLock);
	return EPHIDGET_OK;
}
Beispiel #11
0
//This can be called even when not connected to a server
int CCONV CPhidgetDictionary_remove_OnKeyChange_Handler(CPhidgetDictionaryListenerHandle keylistener)
{
	int result = 0;
	char errdesc[1024];
	CPhidgetDictionaryHandle dict;

	TESTPTR(keylistener)
	dict = keylistener->dict;

	CThread_mutex_lock(&dict->lock);

	if(CPhidget_statusFlagIsSet(dict->status, PHIDGET_SERVER_CONNECTED_FLAG))
	{
		CThread_mutex_lock(&dict->networkInfo->server->pdc_lock);
		if(!(result = pdc_ignore(dict->networkInfo->server->pdcs, keylistener->listen_id, errdesc, sizeof (errdesc))))
		{
			LOG(PHIDGET_LOG_WARNING,"pdc_ignore: %s",errdesc);
			CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);
			CThread_mutex_unlock(&dict->lock);
			return EPHIDGET_UNEXPECTED;
		}
		CThread_mutex_unlock(&dict->networkInfo->server->pdc_lock);
	}

	CThread_mutex_lock(&dict->listenersLock);
	if((result = CList_removeFromList((CListHandle *)&dict->listeners, keylistener, 
		CPhidgetDictionaryListener_areEqual, PTRUE, CPhidgetDictionaryListener_free)))
	{
		CThread_mutex_unlock(&dict->listenersLock);
		CThread_mutex_unlock(&dict->lock);
		return result;
	}
	CThread_mutex_unlock(&dict->listenersLock);
	CThread_mutex_unlock(&dict->lock);

	return EPHIDGET_OK;
}
Beispiel #12
0
/* The internal event handlers for PhidgetManager - these should be called directly from the usb functions...
 * these run in the context of the central thread
 * if AddDevice returns EPHIDGET_DUPLICATE, the user callback is not run (good)
 */
int CPhidgetAttachEvent(CPhidgetHandle phid) {
	int result = 0;
	CPhidgetList *trav = 0;
	CPhidgetManagerList *trav2 = 0;
	CPhidgetHandle travPhid = 0;
	TESTPTR(phid)
	result = CList_addToList((CListHandle *)&AttachedDevices, phid, CPhidget_areEqual);
	if(result == EPHIDGET_DUPLICATE)
	{
		return EPHIDGET_OK;
	}
	else if(result) 
	{
		return result;
	}
	
	for(trav2 = localPhidgetManagers; trav2; trav2 = trav2->next)
	{
		if (trav2->phidm->fptrAttachChange && trav2->phidm->state == PHIDGETMANAGER_ACTIVE)
			trav2->phidm->fptrAttachChange((CPhidgetHandle)phid, trav2->phidm->fptrAttachChangeptr);
	}

	result = EPHIDGET_OK;

	CThread_mutex_lock(&activeDevicesLock);
	//first look for this specific device
	for (trav=ActiveDevices; trav; trav = trav->next)
	{
		if((trav->phid->serialNumber == phid->serialNumber)
			&& (trav->phid->deviceID == phid->deviceID)
			&& !CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
		{
			travPhid = trav->phid;
			CThread_mutex_unlock(&activeDevicesLock);
			//Prevent close from being called during attachActiveDevice
			CThread_mutex_lock(&travPhid->openCloseLock);
			result = attachActiveDevice(travPhid, phid);
			CThread_mutex_unlock(&travPhid->openCloseLock);
			return result;
		}
	}
	//second look for a general device
	for (trav=ActiveDevices; trav; trav = trav->next)
	{
		if(CPhidget_areEqual(trav->phid, phid)
			&& !CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
		{
			travPhid = trav->phid;
			CThread_mutex_unlock(&activeDevicesLock);
			//Prevent close from being called during attachActiveDevice
			CThread_mutex_lock(&travPhid->openCloseLock);
			result = attachActiveDevice(travPhid, phid);
			CThread_mutex_unlock(&travPhid->openCloseLock);
			//If one doesn't work, try the next one - this would happen if the first one in opened elsewhere
			if(result != EPHIDGET_OK) 
			{
				CThread_mutex_lock(&activeDevicesLock);
				continue;
			}
			return result;
		}
	}
	CThread_mutex_unlock(&activeDevicesLock);
	return result;
}
Beispiel #13
0
int CCONV CPhidgetManager_getAttachedDevices(CPhidgetManagerHandle phidm, CPhidgetHandle *phidArray[], int *count)
{
	CPhidgetList *trav = 0;
	int i = 0;

	TESTPTRS(phidArray, count)
	TESTPTR(phidm)

	*count = 0;
	if(CPhidget_statusFlagIsSet(phidm->status, PHIDGET_REMOTE_FLAG))
	{		
		for (trav=phidm->AttachedPhidgets; trav; trav = trav->next)
		{
			if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
				(*count)++;
		}
		
		if(*count==0)
		{
			*phidArray = NULL;
		}
		else
		{
			*phidArray = (CPhidgetHandle *)malloc(sizeof(**phidArray) * *count);
			if (!*phidArray)
				return EPHIDGET_NOMEMORY;
			ZEROMEM(*phidArray, sizeof(**phidArray) * *count);

			for (trav=phidm->AttachedPhidgets, i=0; trav; trav = trav->next)
			{
				if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
				{
					(*phidArray)[i] = trav->phid;
					i++;
				}
			}
		}
	}
	else
	{
		CThread_mutex_lock(&attachedDevicesLock);
		for (trav=AttachedDevices; trav; trav = trav->next)
		{
			if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
				(*count)++;
		}
		if(*count==0)
		{
			*phidArray = NULL;
		}
		else
		{
			*phidArray = (CPhidgetHandle *)malloc(sizeof(**phidArray) * *count);
			if (!*phidArray)
			{
				CThread_mutex_unlock(&attachedDevicesLock);
				return EPHIDGET_NOMEMORY;
			}
			ZEROMEM(*phidArray, sizeof(**phidArray) * *count);

			for (trav=AttachedDevices, i=0; trav; trav = trav->next)
			{
				if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
				{
					(*phidArray)[i] = trav->phid;
					i++;
				}
			}
		}

		CThread_mutex_unlock(&attachedDevicesLock);
	}
	return EPHIDGET_OK; 
}
Beispiel #14
0
int CPhidgetManager_poll()
{
	CPhidgetList *curList = 0, *detachList = 0;
	CPhidgetList *trav = 0;
	CPhidgetHandle foundPhidget;
			
	if(!managerLockInitialized)
	{
		CThread_mutex_init(&managerLock);
		managerLockInitialized = PTRUE;
	}
	
	CThread_mutex_lock(&managerLock);
	CThread_mutex_lock(&attachedDevicesLock);

	sendInitialEvents();

	CUSBBuildList(&curList);


	for (trav=AttachedDevices; trav; trav = trav->next)
	{		
		if(CList_findInList((CListHandle)curList, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND)
		{
			CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual);
		}
	}
	for (trav=curList; trav; trav = trav->next)
	{
		if(CList_findInList((CListHandle)AttachedDevices, trav->phid, CPhidget_areExtraEqual, NULL) ==
		    EPHIDGET_NOTFOUND)
		{
			CPhidgetAttachEvent(trav->phid);
		}
		
		//if PHIDGET_USB_ERROR_FLAG is set, cycle device through a detach
		//if it's ok, it will re-attach
		//this can't yet handle unexpected timeouts (because we don't have a definitive list of expected timeouts)
		if(CList_findInList((CListHandle)ActiveDevices, trav->phid, CPhidget_areEqual, (void **)&foundPhidget) ==
		    EPHIDGET_OK)
		{		
			if(CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_ATTACHED_FLAG))
			{
				if(CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_USB_ERROR_FLAG))
				{
					LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling device through a detach");
					CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual);
				}
			}
		}
	}
	for (trav=detachList; trav; trav = trav->next)
	{
		CPhidgetDetachEvent(trav->phid);
	}
	CList_emptyList((CListHandle *)&detachList, FALSE, NULL);
	CList_emptyList((CListHandle *)&curList, FALSE, NULL);

	CThread_mutex_unlock(&attachedDevicesLock);
	CThread_mutex_unlock(&managerLock);
	return EPHIDGET_OK;
}
int CPhidgetManager_poll()
{
	CPhidgetList *curList = 0, *detachList = 0;
	CPhidgetList *trav = 0, *trav2 = 0;
	CPhidgetHandle foundPhidget;
			
	if(!managerLockInitialized)
	{
		CThread_mutex_init(&managerLock);
		managerLockInitialized = PTRUE;
	}
	
	CThread_mutex_lock(&managerLock);
	CThread_mutex_lock(&attachedDevicesLock);

	sendInitialEvents();

	CUSBBuildList(&curList);


	for (trav=AttachedDevices; trav; trav = trav->next)
	{		
		if(CList_findInList((CListHandle)curList, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND)
		{
			CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual);
		}
	}
	for (trav=curList; trav; trav = trav->next)
	{
		if(CList_findInList((CListHandle)AttachedDevices, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND)
		{
			CPhidgetAttachEvent(trav->phid);
		}
		
		//if PHIDGET_USB_ERROR_FLAG is set, cycle device through a detach
		//if it's ok, it will re-attach
		
		CThread_mutex_lock(&activeDevicesLock);
		if(CList_findInList((CListHandle)ActiveDevices, trav->phid, CPhidget_areEqual, (void **)&foundPhidget) == EPHIDGET_OK)
		{		
			if(CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_ATTACHED_FLAG)
				&& CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_USB_ERROR_FLAG))
			{
				LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling device through a detach");
				CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual);
				
				//if this is a composite device, we must find it's pair and detach that as well.
				//same serial, but different interface num
				for (trav2=curList; trav2; trav2 = trav2->next)
				{
					if(trav->phid->serialNumber == trav2->phid->serialNumber
					&& trav->phid->deviceDef->pdd_iid != trav2->phid->deviceDef->pdd_iid)
					{
						LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling composite device 2nd interface through a detach");
						CList_addToList((CListHandle *)&detachList, trav2->phid, CPhidget_areEqual);
					}
				}
			}
		}
		
		
		CThread_mutex_unlock(&activeDevicesLock);
	}
	for (trav=detachList; trav; trav = trav->next)
	{
		CPhidgetDetachEvent(trav->phid);
	}
	CList_emptyList((CListHandle *)&detachList, FALSE, NULL);
	CList_emptyList((CListHandle *)&curList, FALSE, NULL);

	CThread_mutex_unlock(&attachedDevicesLock);
	CThread_mutex_unlock(&managerLock);
	return EPHIDGET_OK;
}