void * deviceThread(void *pData) { const char *dlsym_error; CDeviceItem *pDevItem = (CDeviceItem *)pData; if (NULL == pDevItem) { syslog(LOG_CRIT, "No device item defined. Aborting device thread!"); return NULL; } // Must have a valid pointer to the control object CControlObject *pCtrlObj = pDevItem->m_pCtrlObject; if (NULL == pCtrlObj) { syslog(LOG_CRIT, "No control object defined. Aborting device thread!"); return NULL; } // We need to create a clientobject and add this object to the list CClientItem *pClientItem = pDevItem->m_pClientItem = new CClientItem; if (NULL == pClientItem) { return NULL; } // This is now an active Client pClientItem->m_bOpen = true; if (VSCP_DRIVER_LEVEL1 == pDevItem->m_driverLevel) { pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_DRIVER_LEVEL1; } else if (VSCP_DRIVER_LEVEL2 == pDevItem->m_driverLevel) { pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_DRIVER_LEVEL2; } else if (VSCP_DRIVER_LEVEL3 == pDevItem->m_driverLevel) { pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_DRIVER_LEVEL3; } char datebuf[80]; time_t now = time(NULL); vscp_getTimeString(datebuf, sizeof(datebuf), &now); pClientItem->m_strDeviceName = pDevItem->m_strName; pClientItem->m_strDeviceName += "|Started at "; pClientItem->m_strDeviceName += datebuf; syslog(LOG_DEBUG, "Devicethread: Starting %s", pClientItem->m_strDeviceName.c_str()); // Add the client to the Client List pthread_mutex_lock(&pCtrlObj->m_clientList.m_mutexItemList); if (!pCtrlObj->addClient(pClientItem, pDevItem->m_interface_guid.getClientID())) { // Failed to add client delete pDevItem->m_pClientItem; pDevItem->m_pClientItem = NULL; pthread_mutex_unlock(&pCtrlObj->m_clientList.m_mutexItemList); syslog(LOG_ERR, "Devicethread: Failed to add client. Terminating thread."); return NULL; } pthread_mutex_unlock(&pCtrlObj->m_clientList.m_mutexItemList); // Client now have GUID set to server GUID + channel id // If device has a non NULL GUID replace the client GUID preserving // the channel id with that GUID if (!pClientItem->m_guid.isNULL()) { memcpy( pClientItem->m_guid.m_id, pDevItem->m_interface_guid.getGUID(), 12); } void *hdll; if (VSCP_DRIVER_LEVEL3 != pDevItem->m_driverLevel) { // Load dynamic library hdll = dlopen(pDevItem->m_strPath.c_str(), RTLD_LAZY); if (!hdll) { syslog(LOG_ERR, "Devicethread: Unable to load dynamic library. path = %s", pDevItem->m_strPath.c_str()); return NULL; } } else { // Level III driver // Startup Level III driver std::string executable = pDevItem->m_strPath; pid_t pid = fork(); if (pid == -1) { syslog(LOG_ERR, "Failed to start level III driver %s (fork).", pDevItem->m_strName.c_str()); } else if (pid == 0) { // we're in child // Set process group to child process' pid. Then killing -pid // of the parent will kill the process and all of its children. setsid(); // Arguments: TODO // user // password // config parameters... // execvp( *argv, const_cast<char**>(argv) ); // Wait on child int status; waitpid(pid, &status, 0); } } if (VSCP_DRIVER_LEVEL1 == pDevItem->m_driverLevel) { // Now find methods in library syslog( LOG_INFO, "Loading level I driver: %s", pDevItem->m_strName.c_str()); // * * * * CANAL OPEN * * * * pDevItem->m_proc_CanalOpen = (LPFNDLL_CANALOPEN)dlsym(hdll, "CanalOpen"); const char *dlsym_error = dlerror(); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_DEBUG, "%s : Unable to get dl entry for CanalOpen.", pDevItem->m_strName.c_str()); return NULL; } // * * * * CANAL CLOSE * * * * pDevItem->m_proc_CanalClose = (LPFNDLL_CANALCLOSE)dlsym(hdll, "CanalClose"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalClose.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL GETLEVEL * * * * pDevItem->m_proc_CanalGetLevel = (LPFNDLL_CANALGETLEVEL)dlsym(hdll, "CanalGetLevel"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetLevel.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL SEND * * * * pDevItem->m_proc_CanalSend = (LPFNDLL_CANALSEND)dlsym(hdll, "CanalSend"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalSend.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL DATA AVAILABLE * * * * pDevItem->m_proc_CanalDataAvailable = (LPFNDLL_CANALDATAAVAILABLE)dlsym(hdll, "CanalDataAvailable"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalDataAvailable.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL RECEIVE * * * * pDevItem->m_proc_CanalReceive = (LPFNDLL_CANALRECEIVE)dlsym(hdll, "CanalReceive"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalReceive.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL GET STATUS * * * * pDevItem->m_proc_CanalGetStatus = (LPFNDLL_CANALGETSTATUS)dlsym(hdll, "CanalGetStatus"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetStatus.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL GET STATISTICS * * * * pDevItem->m_proc_CanalGetStatistics = (LPFNDLL_CANALGETSTATISTICS)dlsym(hdll, "CanalGetStatistics"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetStatistics.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL SET FILTER * * * * pDevItem->m_proc_CanalSetFilter = (LPFNDLL_CANALSETFILTER)dlsym(hdll, "CanalSetFilter"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalSetFilter.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL SET MASK * * * * pDevItem->m_proc_CanalSetMask = (LPFNDLL_CANALSETMASK)dlsym(hdll, "CanalSetMask"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalSetMask.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL GET VERSION * * * * pDevItem->m_proc_CanalGetVersion = (LPFNDLL_CANALGETVERSION)dlsym(hdll, "CanalGetVersion"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetVersion.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL GET DLL VERSION * * * * pDevItem->m_proc_CanalGetDllVersion = (LPFNDLL_CANALGETDLLVERSION)dlsym(hdll, "CanalGetDllVersion"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetDllVersion.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // * * * * CANAL GET VENDOR STRING * * * * pDevItem->m_proc_CanalGetVendorString = (LPFNDLL_CANALGETVENDORSTRING)dlsym(hdll, "CanalGetVendorString"); dlsym_error = dlerror(); if (dlsym_error) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetVendorString.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } // ****************************** // Generation 2 Methods // ****************************** // * * * * CANAL BLOCKING SEND * * * * pDevItem->m_proc_CanalBlockingSend = (LPFNDLL_CANALBLOCKINGSEND)dlsym(hdll, "CanalBlockingSend"); dlsym_error = dlerror(); if (dlsym_error) { syslog(LOG_ERR, "%s: Unable to get dl entry for CanalBlockingSend. Probably " "Generation 1 driver.", pDevItem->m_strName.c_str()); pDevItem->m_proc_CanalBlockingSend = NULL; } // * * * * CANAL BLOCKING RECEIVE * * * * pDevItem->m_proc_CanalBlockingReceive = (LPFNDLL_CANALBLOCKINGRECEIVE)dlsym(hdll, "CanalBlockingReceive"); dlsym_error = dlerror(); if (dlsym_error) { syslog(LOG_ERR, "%s: Unable to get dl entry for CanalBlockingReceive. " "Probably Generation 1 driver.", pDevItem->m_strName.c_str()); pDevItem->m_proc_CanalBlockingReceive = NULL; } // * * * * CANAL GET DRIVER INFO * * * * pDevItem->m_proc_CanalGetdriverInfo = (LPFNDLL_CANALGETDRIVERINFO)dlsym(hdll, "CanalGetDriverInfo"); dlsym_error = dlerror(); if (dlsym_error) { syslog(LOG_ERR, "%s: Unable to get dl entry for CanalGetDriverInfo. " "Probably Generation 1 driver.", pDevItem->m_strName.c_str()); pDevItem->m_proc_CanalGetdriverInfo = NULL; } // Open the device pDevItem->m_openHandle = pDevItem->m_proc_CanalOpen( (const char *)pDevItem->m_strParameter.c_str(), pDevItem->m_DeviceFlags); // Check if the driver opened properly if (pDevItem->m_openHandle <= 0) { syslog(LOG_ERR, "Failed to open driver. Will not use it! [%s] ", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level I Driver open.", pDevItem->m_strName.c_str()); } // Get Driver Level pDevItem->m_driverLevel = pDevItem->m_proc_CanalGetLevel(pDevItem->m_openHandle); // * * * Level I Driver * * * // Check if blocking driver is available if (NULL != pDevItem->m_proc_CanalBlockingReceive) { // * * * * Blocking version * * * * if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level I blocking version.", pDevItem->m_strName.c_str()); } ///////////////////////////////////////////////////////////////////////////// // Device write worker thread ///////////////////////////////////////////////////////////////////////////// if (pthread_create(&pDevItem->m_level1WriteThread, NULL, deviceLevel1WriteThread, pDevItem)) { syslog(LOG_CRIT, "%s: Unable to run the device write worker thread.", pDevItem->m_strName.c_str()); // pDevItem->m_openHandle = pDevItem->m_proc_CanalOpen(); dlclose(hdll); return NULL; } ///////////////////////////////////////////////////////////////////////////// // Device read worker thread ///////////////////////////////////////////////////////////////////////////// if (pthread_create(&pDevItem->m_level1ReceiveThread, NULL, deviceLevel1ReceiveThread, pDevItem)) { syslog(LOG_CRIT, "%s: Unable to run the device read worker thread.", pDevItem->m_strName.c_str()); pDevItem->m_bQuit = true; pthread_join(pDevItem->m_level1WriteThread, NULL); // pDevItem->m_openHandle = pDevItem->m_proc_CanalOpen(); dlclose(hdll); return NULL; } // Just sit and wait until the end of the world as we know it... while (!pDevItem->m_bQuit) { sleep(1); } // Signal worker threads to quit pDevItem->m_bQuit = true; if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level I work loop ended.", pDevItem->m_strName.c_str()); } // Wait for workerthreads to abort pthread_join(pDevItem->m_level1WriteThread, NULL); pthread_join(pDevItem->m_level1ReceiveThread, NULL); } else { // * * * * Non blocking version * * * * if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level I NON Blocking version.", pDevItem->m_strName.c_str()); } bool bActivity; while (pDevItem->m_bQuit) { bActivity = false; ///////////////////////////////////////////////////////////////////////////// // Receive from device ///////////////////////////////////////////////////////////////////////////// canalMsg msg; if (pDevItem->m_proc_CanalDataAvailable( pDevItem->m_openHandle)) { if (CANAL_ERROR_SUCCESS == pDevItem->m_proc_CanalReceive(pDevItem->m_openHandle, &msg)) { bActivity = true; // There must be room in the receive queue if (pCtrlObj->m_maxItemsInClientReceiveQueue > pCtrlObj->m_clientOutputQueue.size()) { vscpEvent *pvscpEvent = new vscpEvent; if (NULL != pvscpEvent) { // Set driver GUID if set /*if ( pDevItem->m_interface_guid.isNULL() ) { pDevItem->m_interface_guid.writeGUID( pvscpEvent->GUID ); } else { // If no driver GUID set use interface GUID pItem->m_guid.writeGUID( pvscpEvent->GUID ); }*/ // Convert CANAL message to VSCP event vscp_convertCanalToEvent( pvscpEvent, &msg, pClientItem->m_guid.m_id); pvscpEvent->obid = pClientItem->m_clientID; pthread_mutex_lock( &pCtrlObj->m_mutexClientOutputQueue); pCtrlObj->m_clientOutputQueue.push_back( pvscpEvent); sem_post(&pCtrlObj->m_semClientOutputQueue); pthread_mutex_unlock( &pCtrlObj->m_mutexClientOutputQueue); } } } } // data available // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Send messages (if any) in the output queue // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Check if there is something to send if (pClientItem->m_clientInputQueue.size()) { bActivity = true; std::deque<vscpEvent *>::iterator it; pthread_mutex_lock(&pClientItem->m_mutexClientInputQueue); vscpEvent *pqueueEvent = pClientItem->m_clientInputQueue.front(); pthread_mutex_lock(&pClientItem->m_mutexClientInputQueue); // Trow away Level II event on Level I interface if ((CLIENT_ITEM_INTERFACE_TYPE_DRIVER_LEVEL1 == pClientItem->m_type) && (pqueueEvent->vscp_class > 512)) { // Remove the event and the node pClientItem->m_clientInputQueue.pop_front(); syslog(LOG_ERR, "Level II event on Level I queue thrown away. " "class=%d, type=%d", pqueueEvent->vscp_class, pqueueEvent->vscp_type); vscp_deleteVSCPevent(pqueueEvent); continue; } canalMsg canalMsg; vscp_convertEventToCanal(&canalMsg, pqueueEvent); if (CANAL_ERROR_SUCCESS == pDevItem->m_proc_CanalSend(pDevItem->m_openHandle, &canalMsg)) { // Remove the event and the node pClientItem->m_clientInputQueue.pop_front(); delete pqueueEvent; } else { // Another try // pCtrlObj->m_semClientOutputQueue.Post(); // vscp_deleteVSCPevent(pqueueEvent); TODO ???? } } // events if (!bActivity) { usleep(100000); // 100 ms } bActivity = false; } // while working - non blocking } // if blocking/non blocking if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level I Work loop ended.", pDevItem->m_strName.c_str()); } // Close CANAL channel pDevItem->m_proc_CanalClose(pDevItem->m_openHandle); if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level I Closed.", pDevItem->m_strName.c_str()); } level1_driver_exit: pDevItem->m_bQuit = true; pthread_join(pDevItem->m_level1WriteThread, NULL); pthread_join(pDevItem->m_level1ReceiveThread, NULL); dlclose(hdll); } else if (VSCP_DRIVER_LEVEL2 == pDevItem->m_driverLevel) { // Now find methods in library syslog(LOG_INFO, "Loading level II driver: <%s>", pDevItem->m_strName.c_str()); // * * * * VSCP OPEN * * * * if (NULL == (pDevItem->m_proc_VSCPOpen = (LPFNDLL_VSCPOPEN)dlsym(hdll, "VSCPOpen"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPOpen.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP CLOSE * * * * if (NULL == (pDevItem->m_proc_VSCPClose = (LPFNDLL_VSCPCLOSE)dlsym(hdll, "VSCPClose"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPClose.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP BLOCKINGSEND * * * * if (NULL == (pDevItem->m_proc_VSCPBlockingSend = (LPFNDLL_VSCPBLOCKINGSEND)dlsym(hdll, "VSCPBlockingSend"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPBlockingSend.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP BLOCKINGRECEIVE * * * * if (NULL == (pDevItem->m_proc_VSCPBlockingReceive = (LPFNDLL_VSCPBLOCKINGRECEIVE)dlsym( hdll, "VSCPBlockingReceive"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPBlockingReceive.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP GETLEVEL * * * * if (NULL == (pDevItem->m_proc_VSCPGetLevel = (LPFNDLL_VSCPGETLEVEL)dlsym(hdll, "VSCPGetLevel"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPGetLevel.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP GET DLL VERSION * * * * if (NULL == (pDevItem->m_proc_VSCPGetDllVersion = (LPFNDLL_VSCPGETDLLVERSION)dlsym(hdll, "VSCPGetDllVersion"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPGetDllVersion.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP GET VENDOR STRING * * * * if (NULL == (pDevItem->m_proc_VSCPGetVendorString = (LPFNDLL_VSCPGETVENDORSTRING)dlsym( hdll, "VSCPGetVendorString"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPGetVendorString.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP GET DRIVER INFO * * * * if (NULL == (pDevItem->m_proc_CanalGetdriverInfo = (LPFNDLL_VSCPGETVENDORSTRING)dlsym(hdll, "VSCPGetDriverInfo"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPGetDriverInfo.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP GET WEB PAGE TEMPLATE * * * * if (NULL == (pDevItem->m_proc_VSCPGetWebPageTemplate = (LPFNDLL_VSCPGETWEBPAGETEMPLATE)dlsym( hdll, "VSCPGetWebPageTemplate"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPGetWebPageTemplate.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP GET WEB PAGE INFO * * * * if (NULL == (pDevItem->m_proc_VSCPGetWebPageInfo = (LPFNDLL_VSCPGETWEBPAGEINFO)dlsym(hdll, "VSCPGetWebPageInfo"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPGetWebPageInfo.", pDevItem->m_strName.c_str()); return NULL; } // * * * * VSCP WEB PAGE UPDATE * * * * if (NULL == (pDevItem->m_proc_VSCPWebPageupdate = (LPFNDLL_VSCPWEBPAGEUPDATE)dlsym(hdll, "VSCPWebPageupdate"))) { // Free the library syslog(LOG_ERR, "%s: Unable to get dl entry for VSCPWebPageupdate.", pDevItem->m_strName.c_str()); return NULL; } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: Discovered all methods\n", pDevItem->m_strName.c_str()); } // Username, password, host and port can be set in configuration file. // Read in them here if they are. std::string strHost("127.0.0.1"); short port = 9598; std::deque<std::string> tokens; vscp_split(tokens, pDevItem->m_strParameter, ";"); if (false == tokens.empty()) { CVariable variable; // Get prefix std::string prefix = tokens.front(); tokens.pop_front(); // Check if username is specified in the configuration file CUserItem *pAdminUser = pDevItem->m_pCtrlObject->m_userList.getUser(USER_ID_ADMIN); if (pCtrlObj->m_variables.find( pDevItem->m_strName + "_username", pAdminUser, variable)) { std::string str; if (VSCP_DAEMON_VARIABLE_CODE_STRING == variable.getType()) { str = variable.getValue(); pCtrlObj->m_driverUsername = str; } } // Check if password is specified in the configuration file if (pCtrlObj->m_variables.find( pDevItem->m_strName + "_password", pAdminUser, variable)) { std::string str; if (VSCP_DAEMON_VARIABLE_CODE_STRING == variable.getType()) { str = variable.getValue(); pCtrlObj->m_driverPassword = str; } } // Check if host is specified in the configuration file if (pCtrlObj->m_variables.find( pDevItem->m_strName + "_host", pAdminUser, variable)) { std::string str; if (VSCP_DAEMON_VARIABLE_CODE_STRING == variable.getType()) { str = variable.getValue(); strHost = str; } } // Check if host is specified in the configuration file if (pCtrlObj->m_variables.find( pDevItem->m_strName + "_port", pAdminUser, variable)) { std::string str; if (VSCP_DAEMON_VARIABLE_CODE_INTEGER == variable.getType()) { str = variable.getValue(); port = vscp_readStringValue(str); } } } // Open up the driver pDevItem->m_openHandle = pDevItem->m_proc_VSCPOpen( pCtrlObj->m_driverUsername.c_str(), (const char *)pCtrlObj->m_driverPassword.c_str(), (const char *)strHost.c_str(), port, (const char *)pDevItem->m_strName.c_str(), (const char *)pDevItem->m_strParameter.c_str()); if (0 == pDevItem->m_openHandle) { // Free the library syslog(LOG_ERR, "%s: [Device tread] Unable to open VSCP " "driver (check username/password/path/" "rights). Possible additional info from driver " "in syslog.", pDevItem->m_strName.c_str()); return NULL; } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II Open.", pDevItem->m_strName.c_str()); } ///////////////////////////////////////////////////////////////////////////// // Device write worker thread ///////////////////////////////////////////////////////////////////////////// if (pthread_create(&pDevItem->m_level2WriteThread, NULL, deviceLevel2WriteThread, pDevItem)) { syslog(LOG_CRIT, "%s: Unable to run the device Level II write worker thread.", pDevItem->m_strName.c_str()); dlclose(hdll); return NULL; // TODO close dll } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II Write thread created.", pDevItem->m_strName.c_str()); } ///////////////////////////////////////////////////////////////////////////// // Device read worker thread ///////////////////////////////////////////////////////////////////////////// if (pthread_create(&pDevItem->m_level2ReceiveThread, NULL, deviceLevel2ReceiveThread, pDevItem)) { syslog(LOG_CRIT, "%s: Unable to run the device Level II read worker thread.", pDevItem->m_strName.c_str()); pDevItem->m_bQuit = true; pthread_join(pDevItem->m_level2WriteThread, NULL); dlclose(hdll); return NULL; // TODO close dll, kill other thread } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II Write thread created.", pDevItem->m_strName.c_str()); } // Just sit and wait until the end of the world as we know it... while (!pDevItem->m_bQuit) { sleep(1); } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II Closing.", pDevItem->m_strName.c_str()); } // Close channel pDevItem->m_proc_VSCPClose(pDevItem->m_openHandle); if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II Closed.", pDevItem->m_strName.c_str()); } level2_driver_exit: pDevItem->m_bQuit = true; pthread_join(pDevItem->m_level2WriteThread, NULL); pthread_join(pDevItem->m_level2ReceiveThread, NULL); // Unload dll dlclose(hdll); if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II Done waiting for threads.", pDevItem->m_strName.c_str()); } } else if (VSCP_DRIVER_LEVEL3 == pDevItem->m_driverLevel) { if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level III Start server loop.", pDevItem->m_strName.c_str()); } // Just sit and wait until the end of the world as we know it... while (!pDevItem->m_bQuit) { sleep(1); } if (pCtrlObj->m_debugFlags[0] & VSCP_DEBUG1_DRIVER) { syslog(LOG_DEBUG, "%s: [Device tread] Level II End server loop.", pDevItem->m_strName.c_str()); } } // Remove messages in the client queues pthread_mutex_lock(&pCtrlObj->m_clientList.m_mutexItemList); pCtrlObj->removeClient(pClientItem); pthread_mutex_unlock(&pCtrlObj->m_clientList.m_mutexItemList); return NULL; }
void clientThreadLevel2( void *pThreadObject ) { char *p; char buf[ MAX_PATH ]; vscpEvent *pEvent; dllnode *pNode; CControlObject *pctrlObject = NULL; HANDLE hMap; // http://msdn.microsoft.com/msdnmag/issues/0300/security/default.aspx // here we use a SECURITY_DESCRIPTOR to say // that we don't want *any DACL at all* SECURITY_DESCRIPTOR sd; InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE); SECURITY_ATTRIBUTES sa = { sizeof sa, &sd, TRUE }; _clientstruct clientInfo; memcpy( &clientInfo, (_clientstruct *)pThreadObject, sizeof( _clientstruct ) ); pctrlObject = clientInfo.m_pctrlObject; // We need to create a clientobject and add this object to the list CClientItem *pClientItem = new CClientItem; if ( NULL == pClientItem ) { delete (_clientstruct *)pThreadObject; // Delete the client structure ExitThread( -1 ); } // This is a Level II Client pClientItem->m_ClientLevel = CLIENT_ITEM_LEVEL2; // We need to get the shared memory sprintf( buf, CANAL_LISTEN_CLIENT_SHM_TEMPLATE, clientInfo.m_shmid ); if ( NULL == ( hMap = ::OpenFileMapping( FILE_MAP_WRITE, TRUE, buf ) ) ) { delete (_clientstruct *)pThreadObject; // Delete the client structure ExitThread( -1 ); } struct __shmCanalLevelII *pLevel2 = (struct __shmCanalLevelII *)MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 ); if ( NULL == pLevel2 ) { delete (_clientstruct *)pThreadObject; // Delete the client structure CloseHandle( hMap ); ExitThread( -1 ); } void *pDataArea= pLevel2->m_data; vscpEvent *pEventArea = &pLevel2->m_VSCP_Event; pLevel2->m_command = VSCP_COMMAND_NOOP; // Create the client command semaphore HANDLE hSemCmd; sprintf( buf, CANAL_CLIENT_COMMAND_SEM_TEMPLATE, clientInfo.m_shmid ); if ( NULL == ( hSemCmd = CreateSemaphore( &sa, 0, 1, buf ) ) ) { delete (_clientstruct *)pThreadObject; // Delete the client structure CloseHandle( hMap ); ExitThread( -1 ); } // Create the client Done semaphore HANDLE hSemDone; sprintf( buf, CANAL_CLIENT_DONE_SEM_TEMPLATE, clientInfo.m_shmid ); if ( NULL == ( hSemDone = CreateSemaphore( &sa, 0, 1, buf ) ) ) { delete (_clientstruct *)pThreadObject; // Delete the client structure CloseHandle( hSemCmd ); CloseHandle( hMap ); ExitThread( -1 ); } // Share the command semaphore pLevel2->m_semCmd = clientInfo.m_shmid; // Add the client to the Client List pctrlObject->m_wxClientMutex.Lock(); pctrlObject->addClient( pClientItem ); pctrlObject->m_wxClientMutex.Unlock(); pLevel2->m_test = 0xaa55; // Confirm to client that we are here pClientItem->m_bOpen = true; while ( pClientItem->m_bOpen && !pctrlObject->m_bQuit ) { // Wait for command from client if ( WAIT_OBJECT_0 != WaitForSingleObject( hSemCmd, 500 ) ) { continue; } switch( pLevel2->m_command ) { // * * * * O P E N * * * * case VSCP_COMMAND_OPEN: wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread2: Open"); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * C L O S E * * * * case VSCP_COMMAND_CLOSE: wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread2: Close"); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; pClientItem->m_bOpen = false; break; // * * * * S E N D * * * * case VSCP_COMMAND_SEND: wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread2: Send %X", pClientItem->m_clientID ); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; pNode = new dllnode; if ( NULL != pNode ) { pEvent = new vscpEvent; // Create new VSCP Message if ( NULL != pEvent ) { // Save the originating clients id so // this client dont get the message back pNode->obid = pClientItem->m_clientID; // Copy message memcpy( pEvent, pEventArea, sizeof( vscpEvent ) ); // And data... if ( pEvent->sizeData > 0 ) { // Copy in data pEvent->pdata = new uint8_t[ pEvent->sizeData ]; if ( NULL != pEvent->pdata ) { memcpy( pEvent->pdata, pDataArea ,pEvent->sizeData ); } } else { // No data pEvent->pdata = NULL; } // Check if GUID of interface should be used // as packet GUID if ( pLevel2->m_cmdArg1 ) { memcpy( pEvent->GUID, pClientItem->m_GUID, 16 ); } // Statistics pClientItem->m_statistics.cntTransmitData += pEvent->sizeData; pClientItem->m_statistics.cntTransmitFrames++; // We use the message id as the sort key for the message // in the queue. The high part of this id is the priority // for the message. // The non-id part should possibly be nulled but this depends // on if we regard the message as "sent" or not. If not, a // message with a lower id should be transfered first over the // bus. pNode->Key = pEvent->head; pNode->pKey = &pNode->Key; pNode->pObject = pEvent; // There must be room in the send queue if ( pctrlObject->m_maxItemsInSendQueue > pctrlObject->m_sendLevel2Queue.nCount ) { pctrlObject->m_wxQ2OutMutex.Lock(); if ( !dll_addNode( &pctrlObject->m_sendLevel2Queue, pNode ) ) { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_SEND_STORAGE; } else { pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; SetEvent( pctrlObject->m_hEventSendQ2 ); } pctrlObject->m_wxQ2OutMutex.Unlock(); } else { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_BUFFER_FULL; if ( NULL != pNode ) { if ( NULL != pNode->pObject ) { if ( NULL != pEvent->pdata ) delete [] pEvent->pdata; delete pEvent; } delete pNode; } } } else { delete pNode; pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_SEND_MSG_ALLOCATON; } } // dllNode break; // * * * * R E C E I V E * * * * case VSCP_COMMAND_RECEIVE: wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread2: Receive - before client lock %X", pClientItem->m_clientID ); pClientItem->m_wxMsgMutex.Lock(); if ( !pClientItem->m_bOpen ) { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { dllnode *pNode; vscpEvent *pEvent = (vscpEvent *)pEventArea; if ( NULL != ( pNode = pClientItem->m_inputQueue.pHead ) ) { // There is a message available pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; // Copy message memcpy( pEvent, pNode->pObject, sizeof( vscpEvent ) ); // If there is data it also must be copied if ( ( pEvent->sizeData > 0 ) && ( NULL != pEvent->pdata ) ) { memcpy( pDataArea, pEvent->pdata, pEvent->sizeData ); } // Remove the old data if ( NULL != pEvent->pdata ) delete pEvent->pdata; pEvent->pdata = NULL; // Data stored in message // Remove the node dll_removeNode( &pClientItem->m_inputQueue, pNode ); // If queue empty reset receive flag if ( NULL == ( pNode = pClientItem->m_inputQueue.pHead ) ) { ResetEvent( pClientItem->m_hEventReceive ); } } } pClientItem->m_wxMsgMutex.Unlock(); break; // * * * * D A T A A V A I L A B L E * * * * case VSCP_COMMAND_CHECKDATA: //wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread%n: Data Available %X", pClientItem->m_clientID. pClientItem->m_inputQueue.nCount); pClientItem->m_wxMsgMutex.Lock(); if ( !pClientItem->m_bOpen ) { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; unsigned int *pnMsg = (unsigned int *)pDataArea; //*pnMsg = dll_getNodeCount( &pClientItem->m_inputQueue ); *pnMsg = pClientItem->m_inputQueue.nCount; } pClientItem->m_wxMsgMutex.Unlock(); break; // * * * * S T A T U S * * * * case VSCP_COMMAND_STATUS: if ( !pClientItem->m_bOpen ) { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; // Status memcpy( pDataArea, &pClientItem->m_status, sizeof( canalStatus ) ); } break; // * * * * S T A T I S T I C S * * * * case VSCP_COMMAND_STATISTICS: if ( !pClientItem->m_bOpen ) { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { memcpy( pDataArea, &pClientItem->m_statistics, sizeof( &pClientItem->m_statistics ) ); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; } break; // * * * * F I L T E R * * * * case VSCP_COMMAND_FILTER: if ( !pClientItem->m_bOpen ) { pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { // Set filter memcpy( &pClientItem->m_filter, pDataArea, sizeof( vscpEventFilter ) ); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; } break; // * * * * V E R S I O N * * * * case VSCP_COMMAND_VERSION: // Get version p = (char *)pDataArea; *( p + POS_VSCPD_MAJOR_VERSION ) = CANAL_MAIN_VERSION; *( p + POS_VSCPD_MINOR_VERSION ) = CANAL_MINOR_VERSION; *( p + POS_VSCPD_SUB_VERSION ) = CANAL_SUB_VERSION; pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * G E T I / F G U I D * * * * case VSCP_COMMAND_GET_GUID: memcpy( pDataArea, pClientItem->m_GUID, 16 ); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * S E T I / F G U I D * * * * case VSCP_COMMAND_SET_GUID: memcpy( pClientItem->m_GUID, pDataArea, 16 ); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * G E T C H A N N E L I D * * * * case VSCP_COMMAND_GET_CHID: break; // * * * * N O O P * * * * case VSCP_COMMAND_NOOP: wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread2: NOOP %X", pClientItem->m_clientID); pLevel2->m_Response = CANAL_RESPONSE_SUCCESS; break; default: wxLogTrace("wxTRACE_Canald_LevelII", "ClientThread2: Unknown command %X", pClientItem->m_clientID); pLevel2->m_Response = CANAL_RESPONSE_ERROR; pLevel2->m_ResponseCode = CANAL_IFERROR_UNKNOWN_COMMAND; break; } // We are Done ReleaseSemaphore( hSemDone, 1, NULL ); } // while running wxLogTrace( "wxTRACE_Canald_LevelII", "ClientThread2: About to end. ClientId = %X", pClientItem->m_clientID ); // Remove messages in the client queues pctrlObject->removeClient( pClientItem ); wxLogDebug("ClientThread2: Removed client item."); delete (_clientstruct *)pThreadObject; CloseHandle( hMap ); CloseHandle( hSemCmd ); CloseHandle( hSemDone ); wxLogDebug("ClientThread2: Exit."); ExitThread( 0 ); }
void clientThreadLevel1( void *pThreadObject ) { char buf[ MAX_PATH ]; char *p; canalMsg *pMsg; dllnode *pNode; CControlObject *pctrlObject = NULL; HANDLE hMap; wxLogDebug("Level I Client Started"); // http://msdn.microsoft.com/msdnmag/issues/0300/security/default.aspx // here we use a SECURITY_DESCRIPTOR to say // that we don't want *any DACL at all* SECURITY_DESCRIPTOR sd; InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE); SECURITY_ATTRIBUTES sa = { sizeof sa, &sd, TRUE }; _clientstruct clientInfo; memcpy( &clientInfo, (_clientstruct *)pThreadObject, sizeof( _clientstruct ) ); pctrlObject = clientInfo.m_pctrlObject; // We need to create a clientobject and add this object to the list CClientItem *pClientItem = new CClientItem; if ( NULL == pClientItem ) { delete (_clientstruct *)pThreadObject; // Delete the client structure ExitThread( -1 ); } wxLogDebug("Level I Client 1"); // This is a Level II Client pClientItem->m_ClientLevel = CLIENT_ITEM_LEVEL1; // We need to get the shared memory sprintf( buf, CANAL_LISTEN_CLIENT_SHM_TEMPLATE, clientInfo.m_shmid ); if ( NULL == ( hMap = ::OpenFileMapping( FILE_MAP_WRITE, TRUE, buf ) ) ) { delete (_clientstruct *)pThreadObject; // Delete the client structure ExitThread( -1 ); } wxLogDebug("Level I Client 5"); struct __shmCanalLevelI *pLevel1 = (struct __shmCanalLevelI *)MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 ); if ( NULL == pLevel1 ) { delete (_clientstruct *)pThreadObject; // Delete the client structure CloseHandle( hMap ); ExitThread( -1 ); } wxLogDebug("Level I Client 6"); void *pDataArea= pLevel1->m_data; pLevel1->m_command = CANAL_COMMAND_NOOP; // Create the client command semaphore HANDLE hSemCmd; sprintf( buf, CANAL_CLIENT_COMMAND_SEM_TEMPLATE, clientInfo.m_shmid ); if ( NULL == ( hSemCmd = CreateSemaphore( &sa, 0, 1, buf ) ) ) { delete (_clientstruct *)pThreadObject; // Delete the client structure CloseHandle( hMap ); ExitThread( -1 ); } wxLogDebug("Level I Client 7"); // Create the client Done semaphore HANDLE hSemDone; sprintf( buf, CANAL_CLIENT_DONE_SEM_TEMPLATE, clientInfo.m_shmid ); if ( NULL == ( hSemDone = CreateSemaphore( &sa, 0, 1, buf ) ) ) { delete (_clientstruct *)pThreadObject; // Delete the client structure CloseHandle( hSemCmd ); CloseHandle( hMap ); ExitThread( -1 ); } wxLogDebug("Level I Client 7"); // Share the command semaphore pLevel1->m_semCmd = clientInfo.m_shmid; // Add the client to the Client List pctrlObject->m_wxClientMutex.Lock(); pctrlObject->addClient( pClientItem ); pctrlObject->m_wxClientMutex.Unlock(); pLevel1->m_test = 0xaa55; // Confirm to client that we are here pClientItem->m_bOpen = true; while ( pClientItem->m_bOpen && !pctrlObject->m_bQuit ) { // Wait for command from client if ( WAIT_OBJECT_0 != WaitForSingleObject( hSemCmd, 500 ) ) { continue; } switch( pLevel1->m_command ) { // * * * * O P E N * * * * case CANAL_COMMAND_OPEN: pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * C L O S E * * * * case CANAL_COMMAND_CLOSE: pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; pClientItem->m_bOpen = false; break; // * * * * S E N D * * * * case CANAL_COMMAND_SEND: pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; pNode = new dllnode; if ( NULL != pNode ) { pMsg = new canalMsg; // Create new Canal Message if ( NULL != pMsg ) { // Save the originating clients id so // this client dont get the message back pNode->obid = pClientItem->m_clientID; // Copy message memcpy( pMsg, pDataArea, sizeof( canalMsg ) ); // Statistics pClientItem->m_statistics.cntTransmitData += pMsg->sizeData; pClientItem->m_statistics.cntTransmitFrames++; // We use the message id as the sort key for the message // in the queue. The high part of this id is the priority // for the message. // The non-id part should possibly be nulled but this depends // on if we regard the message as "sent" or not. If not, a // message with a lower id should be transfered first over the // bus. pNode->Key = pMsg->id; pNode->pKey = &pNode->Key; pNode->pObject = pMsg; // There must be room in the send queue if ( pctrlObject->m_maxItemsInSendQueue > pctrlObject->m_sendLevel1Queue.nCount ) { pctrlObject->m_wxQ1OutMutex.Lock(); if ( !dll_addNode( &pctrlObject->m_sendLevel1Queue, pNode ) ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_SEND_STORAGE; } else { pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; SetEvent( pctrlObject->m_hEventSendQ1 ); } pctrlObject->m_wxQ1OutMutex.Unlock(); } else { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_BUFFER_FULL; if ( NULL != pNode ) { if ( NULL != pNode->pObject ) { delete pMsg; } delete pNode; } } } else { delete pNode; pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_SEND_MSG_ALLOCATON; } } // dllNode break; // * * * * R E C E I V E * * * * case CANAL_COMMAND_RECEIVE: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { pctrlObject->m_wxClientMutex.Lock(); dllnode *pNode; canalMsg *pMsg = (canalMsg *)pDataArea; if ( NULL != ( pNode = pClientItem->m_inputQueue.pHead ) ) { // There is a message available pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; memcpy( pMsg, pNode->pObject, sizeof( canalMsg ) ); // Remove the node dll_removeNode( &pClientItem->m_inputQueue, pNode ); // If queue empty reset receive flag if ( NULL == ( pNode = pClientItem->m_inputQueue.pHead ) ) { ResetEvent( pClientItem->m_hEventReceive ); } } pctrlObject->m_wxClientMutex.Unlock(); } break; // * * * * D A T A A V A I L A B L E * * * * case CANAL_COMMAND_CHECKDATA: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; unsigned int *pnMsg = (unsigned int *)pDataArea; //*pnMsg = dll_getNodeCount( &pClient->m_inputQueue ); *pnMsg = pClientItem->m_inputQueue.nCount; } break; // * * * * S T A T U S * * * * case CANAL_COMMAND_STATUS: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; // Status memcpy( pDataArea, &pClientItem->m_status, sizeof( canalStatus ) ); } break; // * * * * S T A T I S T I C S * * * * case CANAL_COMMAND_STATISTICS: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { memcpy( pDataArea, &pClientItem->m_statistics, sizeof( &pClientItem->m_statistics ) ); pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; } break; // * * * * F I L T E R * * * * case CANAL_COMMAND_FILTER: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { // Set filter memcpy( &pClientItem->m_filter, pDataArea, sizeof( pClientItem->m_filter ) ); pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; } break; // * * * * M A S K * * * * case CANAL_COMMAND_MASK: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { // Set mask memcpy( &pClientItem->m_mask, pDataArea, sizeof( pClientItem->m_mask ) ); pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; } break; // * * * * B A U D R A T E * * * * case CANAL_COMMAND_BAUDRATE: if ( !pClientItem->m_bOpen ) { pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_CHANNEL_CLOSED; } else { // Set baudrate // ============ // We don't have yo do more here the baudrate change // is just simulated in the pipe interface pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; } break; // * * * * V E R S I O N * * * * case CANAL_COMMAND_VERSION: // Get version p = (char *)pDataArea; *( p + POS_VSCPD_MAJOR_VERSION ) = CANAL_MAIN_VERSION; *( p + POS_VSCPD_MINOR_VERSION ) = CANAL_MINOR_VERSION; *( p + POS_VSCPD_SUB_VERSION ) = CANAL_SUB_VERSION; pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * D L L - V E R S I O N * * * * case CANAL_COMMAND_DLL_VERSION: // Get DLL version // This application returns the vscp daemon // version. p = (char *)pDataArea; *( p + POS_VSCPD_MAJOR_VERSION ) = VSCPD_MAJOR_VERSION; *( p + POS_VSCPD_MINOR_VERSION ) = VSCPD_MINOR_VERSION; *( p + POS_VSCPD_SUB_VERSION ) = VSCPD_SUB_VERSION; *( p + POS_VSCPD_SUB_VERSION + 1 ) = 0; pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * V E N D O R S T R I N G * * * * case CANAL_COMMAND_VENDOR_STRING: // Get vendor string pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; p = (char *)pDataArea; strcpy( p, VENDOR_STRING ); break; // * * * * L E V E L * * * * case CANAL_COMMAND_LEVEL: // Get i/f supported levels p = (char *)pDataArea; *( p + 0 ) = 0; *( p + 1 ) = 0; *( p + 2 ) = 0; *( p + 3 ) = CANAL_LEVEL_STANDARD; pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; break; // * * * * N O O P * * * * case CANAL_COMMAND_NOOP: pLevel1->m_Response = CANAL_RESPONSE_SUCCESS; break; default: pLevel1->m_Response = CANAL_RESPONSE_ERROR; pLevel1->m_ResponseCode = CANAL_IFERROR_UNKNOWN_COMMAND; break; } // We are Done ReleaseSemaphore( hSemDone, 1, NULL ); } // while running // Client not needed anymore pctrlObject->removeClient( pClientItem ); delete (_clientstruct *)pThreadObject; CloseHandle( hMap ); CloseHandle( hSemCmd ); CloseHandle( hSemDone ); ExitThread( 0 ); }