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; }
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; }
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; }
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; }
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; }
/* 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; }
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; }
//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; }
/* 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; }
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; }
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; }