コード例 #1
0
ファイル: devicethread.cpp プロジェクト: gvsurenderreddy/vscp
void *deviceThread::Entry()
{
    // Must have a valid pointer to the device item
    if (NULL == m_pDeviceItem) return NULL;

    // Must have a valid pointer to the control object
    if (NULL == m_pCtrlObject) return NULL;

    // We need to create a clientobject and add this object to the list
    m_pDeviceItem->m_pClientItem = new CClientItem;
    if (NULL == m_pDeviceItem->m_pClientItem) {
        return NULL;
    }

    // This is now an active Client
    m_pDeviceItem->m_pClientItem->m_bOpen = true;
    if ( VSCP_DRIVER_LEVEL2 == m_pDeviceItem->m_driverLevel ) {
        m_pDeviceItem->m_pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_DRIVER_LEVEL2;
    }
    else {
        m_pDeviceItem->m_pClientItem->m_type = CLIENT_ITEM_INTERFACE_TYPE_DRIVER_LEVEL1;
    }
    m_pDeviceItem->m_pClientItem->m_strDeviceName = m_pDeviceItem->m_strName;
    m_pDeviceItem->m_pClientItem->m_strDeviceName += _(" Started at ");
    wxDateTime now = wxDateTime::Now();
    m_pDeviceItem->m_pClientItem->m_strDeviceName += now.FormatISODate();
    m_pDeviceItem->m_pClientItem->m_strDeviceName += _(" ");
    m_pDeviceItem->m_pClientItem->m_strDeviceName += now.FormatISOTime();

    m_pCtrlObject->logMsg(m_pDeviceItem->m_pClientItem->m_strDeviceName + _("\n"),
                            DAEMON_LOGMSG_DEBUG);

    // Add the client to the Client List
    m_pCtrlObject->m_wxClientMutex.Lock();
    m_pCtrlObject->addClient(m_pDeviceItem->m_pClientItem);
    m_pCtrlObject->m_wxClientMutex.Unlock();

    // Load dynamic library
    if (!m_wxdll.Load(m_pDeviceItem->m_strPath, wxDL_LAZY)) {
        m_pCtrlObject->logMsg(_("Unable to load dynamic library.\n") );
        return NULL;
    }

    if (VSCP_DRIVER_LEVEL1 == m_pDeviceItem->m_driverLevel) {

        // Now find methods in library

        {
            wxString str;
            str = _("Loading level I driver: ");
            str += m_pDeviceItem->m_strName;
            str += _("\n");
            m_pCtrlObject->logMsg(str);
            wxLogDebug(str);
        }

        // * * * * CANAL OPEN * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalOpen =
            (LPFNDLL_CANALOPEN) m_wxdll.GetSymbol(_T("CanalOpen")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalOpen.\n") );
            return NULL;
        }

        // * * * * CANAL CLOSE * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalClose =
            (LPFNDLL_CANALCLOSE) m_wxdll.GetSymbol(_T("CanalClose")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalClose.\n") );
            return NULL;
        }

        // * * * * CANAL GETLEVEL * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetLevel =
            (LPFNDLL_CANALGETLEVEL) m_wxdll.GetSymbol(_T("CanalGetLevel")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetLevel.\n") );
            return NULL;
        }

        // * * * * CANAL SEND * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalSend =
            (LPFNDLL_CANALSEND) m_wxdll.GetSymbol(_T("CanalSend")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalSend.\n") );
            return NULL;
        }

        // * * * * CANAL DATA AVAILABLE * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalDataAvailable =
            (LPFNDLL_CANALDATAAVAILABLE) m_wxdll.GetSymbol(_T("CanalDataAvailable")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalDataAvailable.\n") );
            return NULL;
        }


        // * * * * CANAL RECEIVE * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalReceive =
            (LPFNDLL_CANALRECEIVE) m_wxdll.GetSymbol(_T("CanalReceive")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalReceive.\n") );
            return NULL;
        }

        // * * * * CANAL GET STATUS * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetStatus =
            (LPFNDLL_CANALGETSTATUS) m_wxdll.GetSymbol(_T("CanalGetStatus")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetStatus.\n") );
            return NULL;
        }

        // * * * * CANAL GET STATISTICS * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetStatistics =
            (LPFNDLL_CANALGETSTATISTICS) m_wxdll.GetSymbol(_T("CanalGetStatistics")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetStatistics.\n") );
            return NULL;
        }

        // * * * * CANAL SET FILTER * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalSetFilter =
            (LPFNDLL_CANALSETFILTER) m_wxdll.GetSymbol(_T("CanalSetFilter")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalSetFilter.\n") );
            return NULL;
        }

        // * * * * CANAL SET MASK * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalSetMask =
            (LPFNDLL_CANALSETMASK) m_wxdll.GetSymbol(_T("CanalSetMask")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalSetMask.\n") );
            return NULL;
        }

        // * * * * CANAL GET VERSION * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetVersion =
            (LPFNDLL_CANALGETVERSION) m_wxdll.GetSymbol(_T("CanalGetVersion")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetVersion.\n") );
            return NULL;
        }

        // * * * * CANAL GET DLL VERSION * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetDllVersion =
            (LPFNDLL_CANALGETDLLVERSION) m_wxdll.GetSymbol(_T("CanalGetDllVersion")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetDllVersion.\n") );
            return NULL;
        }

        // * * * * CANAL GET VENDOR STRING * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetVendorString =
            (LPFNDLL_CANALGETVENDORSTRING) m_wxdll.GetSymbol(_T("CanalGetVendorString")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetVendorString.\n") );
            return NULL;
        }


        // ******************************
        //     Generation 2 Methods
        // ******************************


        // * * * * CANAL BLOCKING SEND * * * *
        m_pDeviceItem->m_proc_CanalBlockingSend = NULL;
        if (m_wxdll.HasSymbol(_T("CanalBlockingSend"))) {
            if (NULL == (m_pDeviceItem->m_proc_CanalBlockingSend =
                (LPFNDLL_CANALBLOCKINGSEND) m_wxdll.GetSymbol(_T("CanalBlockingSend")))) {
                m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalBlockingSend. Probably Generation 1 driver.\n") );
                m_pDeviceItem->m_proc_CanalBlockingSend = NULL;
            }
        }
        else {
            m_pCtrlObject->logMsg(_T("CanalBlockingSend not available. \n\tNon blocking operations set.\n") );
        }

        // * * * * CANAL BLOCKING RECEIVE * * * *
        m_pDeviceItem->m_proc_CanalBlockingReceive = NULL;
        if (m_wxdll.HasSymbol(_T("CanalBlockingReceive"))) {
            if (NULL == (m_pDeviceItem->m_proc_CanalBlockingReceive =
                (LPFNDLL_CANALBLOCKINGRECEIVE) m_wxdll.GetSymbol(_T("CanalBlockingReceive")))) {
                m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalBlockingReceive. Probably Generation 1 driver.\n") );
                m_pDeviceItem->m_proc_CanalBlockingReceive = NULL;
            }
        }
        else {
            m_pCtrlObject->logMsg(_T("CanalBlockingReceive not available. \n\tNon blocking operations set.\n"));
        }

        // * * * * CANAL GET DRIVER INFO * * * *
        m_pDeviceItem->m_proc_CanalGetdriverInfo = NULL;
        if (m_wxdll.HasSymbol(_T("CanalGetDriverInfo"))) {
            if (NULL == (m_pDeviceItem->m_proc_CanalGetdriverInfo =
                (LPFNDLL_CANALGETDRIVERINFO) m_wxdll.GetSymbol(_T("CanalGetDriverInfo")))) {
                m_pCtrlObject->logMsg(_T("Unable to get dl entry for CanalGetDriverInfo. Probably Generation 1 driver.\n") );
                m_pDeviceItem->m_proc_CanalGetdriverInfo = NULL;
            }
        }

        // Open the device
        m_pDeviceItem->m_openHandle =
            m_pDeviceItem->m_proc_CanalOpen((const char *) m_pDeviceItem->m_strParameter.mb_str(wxConvUTF8),
                                                m_pDeviceItem->m_DeviceFlags);

        // Check if the driver opened properly
        if (m_pDeviceItem->m_openHandle <= 0) {
            wxString errMsg = _T("Failed to open driver. Will not use it! \n\t[ ")
                + m_pDeviceItem->m_strName + _T(" ]\n");
            m_pCtrlObject->logMsg( errMsg );
            return NULL;
        }
        else {
            wxString wxstr =
                wxString::Format(_("Driver %s opended.\n"),
                                    (const char *)m_pDeviceItem->m_strName.mbc_str() );
            m_pCtrlObject->logMsg( wxstr );
        }

        // Get Driver Level
        m_pDeviceItem->m_driverLevel =
                m_pDeviceItem->m_proc_CanalGetLevel(m_pDeviceItem->m_openHandle);


        //  * * * Level I Driver * * *

        // Check if blocking driver is available
        if (NULL != m_pDeviceItem->m_proc_CanalBlockingReceive) {

            // * * * * Blocking version * * * *

            /////////////////////////////////////////////////////////////////////////////
            // Device write worker thread
            /////////////////////////////////////////////////////////////////////////////
            m_pwriteThread = new deviceCanalWriteThread;

            if (m_pwriteThread) {
                m_pwriteThread->m_pMainThreadObj = this;
                wxThreadError err;
                if (wxTHREAD_NO_ERROR == (err = m_pwriteThread->Create())) {
                    m_pwriteThread->SetPriority(WXTHREAD_MAX_PRIORITY);
                    if (wxTHREAD_NO_ERROR != (err = m_pwriteThread->Run())) {
                        m_pCtrlObject->logMsg(_("Unable to run device write worker thread.\n") );
                    }
                }
                else {
                    m_pCtrlObject->logMsg(_("Unable to create device write worker thread.\n") );
                }
            }
            else {
                m_pCtrlObject->logMsg(_("Unable to allocate memory for device write worker thread.\n") );
            }

            /////////////////////////////////////////////////////////////////////////////
            // Device read worker thread
            /////////////////////////////////////////////////////////////////////////////
            m_preceiveThread = new deviceCanalReceiveThread;

            if (m_preceiveThread) {
                m_preceiveThread->m_pMainThreadObj = this;
                wxThreadError err;
                if (wxTHREAD_NO_ERROR == (err = m_preceiveThread->Create())) {
                    m_preceiveThread->SetPriority(WXTHREAD_MAX_PRIORITY);
                    if (wxTHREAD_NO_ERROR != (err = m_preceiveThread->Run())) {
                        m_pCtrlObject->logMsg(_("Unable to run device receive worker thread.\n") );
                    }
                }
                else {
                    m_pCtrlObject->logMsg(_("Unable to create device receive worker thread.\n") );
                }
            }
            else {
                m_pCtrlObject->logMsg(_("Unable to allocate memory for device receive worker thread.\n") );
            }

            // Just sit and wait until the end of the world as we know it...
            while (!m_pDeviceItem->m_bQuit) {
                wxSleep(1);
            }

            m_preceiveThread->m_bQuit = true;
            m_pwriteThread->m_bQuit = true;
            m_preceiveThread->Wait();
            m_pwriteThread->Wait();
        }
        else {

            // * * * * Non blocking version * * * *

            bool bActivity;
            while (!TestDestroy() && !m_pDeviceItem->m_bQuit) {

                bActivity = false;
                /////////////////////////////////////////////////////////////////////////////
                //                           Receive from device						   //
                /////////////////////////////////////////////////////////////////////////////
                canalMsg msg;
                if (m_pDeviceItem->m_proc_CanalDataAvailable(m_pDeviceItem->m_openHandle)) {

                    if (CANAL_ERROR_SUCCESS ==
                        m_pDeviceItem->m_proc_CanalReceive(m_pDeviceItem->m_openHandle, &msg)) {

                        bActivity = true;

                        // There must be room in the receive queue
                        if (m_pCtrlObject->m_maxItemsInClientReceiveQueue >
                            m_pCtrlObject->m_clientOutputQueue.GetCount()) {

                            vscpEvent *pvscpEvent = new vscpEvent;
                            if (NULL != pvscpEvent) {

                                // Convert CANAL message to VSCP event
                                vscp_convertCanalToEvent( pvscpEvent,
                                                            &msg,
                                                            m_pDeviceItem->m_pClientItem->m_guid.m_id );

                                pvscpEvent->obid = m_pDeviceItem->m_pClientItem->m_clientID;

                                m_pCtrlObject->m_mutexClientOutputQueue.Lock();
                                m_pCtrlObject->m_clientOutputQueue.Append(pvscpEvent);
                                m_pCtrlObject->m_semClientOutputQueue.Post();
                                m_pCtrlObject->m_mutexClientOutputQueue.Unlock();

                            }
                        }
                    }
                } // data available


                // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                //             Send messages (if any) in the outqueue
                // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

                // Check if there is something to send
                if (m_pDeviceItem->m_pClientItem->m_clientInputQueue.GetCount()) {

                    bActivity = true;

                    CLIENTEVENTLIST::compatibility_iterator nodeClient;

                    m_pDeviceItem->m_pClientItem->m_mutexClientInputQueue.Lock();
                    nodeClient = m_pDeviceItem->m_pClientItem->m_clientInputQueue.GetFirst();
                    vscpEvent *pqueueEvent = nodeClient->GetData();
                    m_pDeviceItem->m_pClientItem->m_mutexClientInputQueue.Unlock();

                    canalMsg canalMsg;
                    vscp_convertEventToCanal(&canalMsg, pqueueEvent);
                    if (CANAL_ERROR_SUCCESS ==
                        m_pDeviceItem->m_proc_CanalSend(m_pDeviceItem->m_openHandle, &canalMsg)) {
                        // Remove the node
                        delete pqueueEvent;
                        m_pDeviceItem->m_pClientItem->m_clientInputQueue.DeleteNode(nodeClient);
                    }
                    else {
                        // Another try
                        //m_pCtrlObject->m_semClientOutputQueue.Post();
                        vscp_deleteVSCPevent(pqueueEvent);
                        m_pDeviceItem->m_pClientItem->m_clientInputQueue.DeleteNode(nodeClient);
                    }

                } // events

                if (!bActivity) {
                    ::wxMilliSleep(100);
                }

                bActivity = false;

            } // while working - non blocking

        } // if blocking/non blocking


        // Close CANAL channel
        m_pDeviceItem->m_proc_CanalClose(m_pDeviceItem->m_openHandle);

        // Library is unloaded in destructor

        // Remove messages in the client queues
        m_pCtrlObject->m_wxClientMutex.Lock();
        m_pCtrlObject->removeClient(m_pDeviceItem->m_pClientItem);
        m_pCtrlObject->m_wxClientMutex.Unlock();

        if (NULL != m_preceiveThread) {
            m_preceiveThread->Wait();
            delete m_preceiveThread;
        }

        if (NULL != m_pwriteThread) {
            m_pwriteThread->Wait();
            delete m_pwriteThread;
        }

    }
    else if (VSCP_DRIVER_LEVEL2 == m_pDeviceItem->m_driverLevel) {

        // Now find methods in library
        {
            wxString str;
            str = _("Loading level II driver: <");
            str += m_pDeviceItem->m_strName;
            str += _(">");
            str += _("\n");
            m_pCtrlObject->logMsg(str);
        }

        // * * * * VSCP OPEN * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPOpen =
            (LPFNDLL_VSCPOPEN) m_wxdll.GetSymbol(_T("VSCPOpen")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPOpen.\n"));
            return NULL;
        }

        // * * * * VSCP CLOSE * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPClose =
            (LPFNDLL_VSCPCLOSE) m_wxdll.GetSymbol(_T("VSCPClose")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPClose.\n"));
            return NULL;
        }

        // * * * * VSCP BLOCKINGSEND * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPBlockingSend =
            (LPFNDLL_VSCPBLOCKINGSEND) m_wxdll.GetSymbol(_T("VSCPBlockingSend")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPBlockingSend.\n"));
            return NULL;
        }

        // * * * * VSCP BLOCKINGRECEIVE * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPBlockingReceive =
            (LPFNDLL_VSCPBLOCKINGRECEIVE) m_wxdll.GetSymbol(_T("VSCPBlockingReceive")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPBlockingReceive.\n"));
            return NULL;
        }

        // * * * * VSCP GETLEVEL * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPGetLevel =
            (LPFNDLL_VSCPGETLEVEL) m_wxdll.GetSymbol(_T("VSCPGetLevel")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPGetLevel.\n"));
            return NULL;
        }

        // * * * * VSCP GET DLL VERSION * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPGetDllVersion =
            (LPFNDLL_VSCPGETDLLVERSION) m_wxdll.GetSymbol(_T("VSCPGetDllVersion")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPGetDllVersion.\n"));
            return NULL;
        }

        // * * * * VSCP GET VENDOR STRING * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPGetVendorString =
            (LPFNDLL_VSCPGETVENDORSTRING) m_wxdll.GetSymbol(_T("VSCPGetVendorString")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPGetVendorString.\n"));
            return NULL;
        }

        // * * * * VSCP GET DRIVER INFO * * * *
        if (NULL == (m_pDeviceItem->m_proc_CanalGetdriverInfo =
            (LPFNDLL_VSCPGETVENDORSTRING) m_wxdll.GetSymbol(_T("VSCPGetDriverInfo")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPGetDriverInfo.\n"));
            return NULL;
        }

        // * * * * VSCP GET WEB PAGE TEMPLATE * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPGetWebPageTemplate =
            (LPFNDLL_VSCPGETWEBPAGETEMPLATE) m_wxdll.GetSymbol(_T("VSCPGetWebPageTemplate")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPGetWebPageTemplate.\n"));
            return NULL;
        }

        // * * * * VSCP GET WEB PAGE INFO * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPGetWebPageInfo =
            (LPFNDLL_VSCPGETWEBPAGEINFO) m_wxdll.GetSymbol(_T("VSCPGetWebPageInfo")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPGetWebPageInfo.\n"));
            return NULL;
        }

        // * * * * VSCP WEB PAGE UPDATE * * * *
        if (NULL == (m_pDeviceItem->m_proc_VSCPWebPageupdate =
            (LPFNDLL_VSCPWEBPAGEUPDATE) m_wxdll.GetSymbol(_T("VSCPWebPageupdate")))) {
            // Free the library
            m_pCtrlObject->logMsg(_T("Unable to get dl entry for VSCPWebPageupdate.\n"));
            return NULL;
        }

        m_pCtrlObject->logMsg(_("Discovered all methods\n"));

        // Username, password, host and port can be set in configuration file. Read in them here
        // if they are.
        wxString strHost(_("127.0.0.1:9598"));

        wxStringTokenizer tkz(m_pDeviceItem->m_strParameter, _(";"));
        if (tkz.HasMoreTokens()) {

            CVSCPVariable *pVar;

            // Get prefix
            wxString prefix = tkz.GetNextToken();

            // Check if username is specified in the configuration file
            pVar = m_pCtrlObject->m_VSCP_Variables.find(m_pDeviceItem->m_strName + _("_username"));
            if (NULL != pVar) {
                wxString str;
                if (VSCP_DAEMON_VARIABLE_CODE_STRING == pVar->getType()) {
                    pVar->getValue( str );
                    m_pCtrlObject->m_driverUsername = str;
                }
            }

            // Check if password is specified in the configuration file
            pVar = m_pCtrlObject->m_VSCP_Variables.find(m_pDeviceItem->m_strName + _("_password"));
            if (NULL != pVar) {
                wxString str;
                if (VSCP_DAEMON_VARIABLE_CODE_STRING == pVar->getType()) {
                    pVar->getValue( str );
                    m_pCtrlObject->m_driverPassword = str;
                }
            }

            // Check if host is specified in the configuration file
            pVar = m_pCtrlObject->m_VSCP_Variables.find(m_pDeviceItem->m_strName + _("_host"));
            if (NULL != pVar) {
                wxString str;
                if (VSCP_DAEMON_VARIABLE_CODE_STRING == pVar->getType()) {
                    pVar->getValue( str );
                    strHost = str;
                }
            }

        }

        // Open up the driver
        m_pDeviceItem->m_openHandle =
            m_pDeviceItem->m_proc_VSCPOpen( m_pCtrlObject->m_driverUsername.mbc_str(),
                                                ( const char * )m_pCtrlObject->m_driverPassword.mbc_str(),
                                                ( const char * )strHost.mbc_str(),
                                                0,
                                                ( const char * )m_pDeviceItem->m_strName.mbc_str(),
                                                ( const char * )m_pDeviceItem->m_strParameter.mbc_str() );

        if ( 0 == m_pDeviceItem->m_openHandle ) {
            // Free the library
            m_pCtrlObject->logMsg( _T( "Unable to open the library.\n" ) );
            return NULL;
        }

        /////////////////////////////////////////////////////////////////////////////
        // Device write worker thread
        /////////////////////////////////////////////////////////////////////////////

        m_pwriteLevel2Thread = new deviceLevel2WriteThread;

        if (m_pwriteLevel2Thread) {
            m_pwriteLevel2Thread->m_pMainThreadObj = this;
            wxThreadError err;
            if (wxTHREAD_NO_ERROR == (err = m_pwriteLevel2Thread->Create())) {
                m_pwriteLevel2Thread->SetPriority(WXTHREAD_MAX_PRIORITY);
                if (wxTHREAD_NO_ERROR != (err = m_pwriteLevel2Thread->Run())) {
                    m_pCtrlObject->logMsg(_("Unable to run device write worker thread."));
                }
            }
            else {
                m_pCtrlObject->logMsg(_("Unable to create device write worker thread."));
            }
        }
        else {
            m_pCtrlObject->logMsg(_("Unable to allocate memory for device write worker thread."));
        }

        /////////////////////////////////////////////////////////////////////////////
        // Device read worker thread
        /////////////////////////////////////////////////////////////////////////////

        m_preceiveLevel2Thread = new deviceLevel2ReceiveThread;

        if (m_preceiveLevel2Thread) {
            m_preceiveLevel2Thread->m_pMainThreadObj = this;
            wxThreadError err;
            if (wxTHREAD_NO_ERROR == (err = m_preceiveLevel2Thread->Create())) {
                m_preceiveLevel2Thread->SetPriority(WXTHREAD_MAX_PRIORITY);
                if (wxTHREAD_NO_ERROR != (err = m_preceiveLevel2Thread->Run())) {
                    m_pCtrlObject->logMsg(_("Unable to run device receive worker thread."));
                }
            }
            else {
                m_pCtrlObject->logMsg(_("Unable to create device receive worker thread.") );
            }
        }
        else {
            m_pCtrlObject->logMsg(_("Unable to allocate memory for device receive worker thread.") );
        }

        // Just sit and wait until the end of the world as we know it...
        while (!TestDestroy() && !m_pDeviceItem->m_bQuit) {
            wxSleep(200);
        }

        m_preceiveLevel2Thread->m_bQuit = true;
        m_pwriteLevel2Thread->m_bQuit = true;

        // Close channel
        m_pDeviceItem->m_proc_VSCPClose(m_pDeviceItem->m_openHandle);

        // Library is unloaded in destructor

        // Remove messages in the client queues
        m_pCtrlObject->m_wxClientMutex.Lock();
        m_pCtrlObject->removeClient(m_pDeviceItem->m_pClientItem);
        m_pCtrlObject->m_wxClientMutex.Unlock();

        if (NULL != m_preceiveLevel2Thread) {
            m_preceiveLevel2Thread->Wait();
            delete m_preceiveLevel2Thread;
        }

        if (NULL != m_pwriteLevel2Thread) {
            m_pwriteLevel2Thread->Wait();
            delete m_pwriteLevel2Thread;
        }

    }




    //
    // =====================================================================================
    //




    return NULL;
}
コード例 #2
0
void *
deviceLevel1ReceiveThread(void *pData)
{
    canalMsg msg;
    // Level1MsgOutList::compatibility_iterator nodeLevel1;

    CDeviceItem *pDevItem = (CDeviceItem *)pData;
    if (NULL == pDevItem) {
        syslog(
          LOG_CRIT,
          "deviceLevel1ReceiveThread quitting due to NULL DevItem object.");
        return NULL;
    }

    // Blocking receive method must have been found
    if (NULL == pDevItem->m_proc_CanalBlockingReceive) {
        return NULL;
    }

    while (!pDevItem->m_bQuit) {

        if (CANAL_ERROR_SUCCESS == pDevItem->m_proc_CanalBlockingReceive(
                                     pDevItem->m_openHandle, &msg, 500)) {

            // There must be room in the receive queue
            if (pDevItem->m_pCtrlObject->m_maxItemsInClientReceiveQueue >
                pDevItem->m_pCtrlObject->m_clientOutputQueue.size()) {

                vscpEvent *pvscpEvent = new vscpEvent;
                if (NULL != pvscpEvent) {

                    memset(pvscpEvent, 0, sizeof(vscpEvent));

                    // 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
                        pDevItem->m_guid.writeGUID(
                    pvscpEvent->GUID );
                    }*/

                    // Convert CANAL message to VSCP event
                    vscp_convertCanalToEvent(
                      pvscpEvent, &msg, pDevItem->m_pClientItem->m_guid.m_id);

                    pvscpEvent->obid = pDevItem->m_pClientItem->m_clientID;

                    // If no GUID is set,
                    //      - Set driver GUID if it is defined
                    //      - Set to interface GUID if not.

                    uint8_t ifguid[16];

                    // Save nickname
                    uint8_t nickname_lsb = pvscpEvent->GUID[15];

                    // Set if to use
                    memcpy(ifguid, pvscpEvent->GUID, 16);
                    ifguid[14] = 0;
                    ifguid[15] = 0;

                    // If if is set to zero use interface id
                    if (vscp_isGUIDEmpty(ifguid)) {

                        // 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
                            pDevItem->m_pClientItem->m_guid.writeGUID(
                              pvscpEvent->GUID);
                        }

                        // Preserve nickname
                        pvscpEvent->GUID[15] = nickname_lsb;
                    }

                    // =========================================================
                    //                   Outgoing translations
                    // =========================================================

                    // Level I measurement events to Level II measurement float
                    if (pDevItem->m_translation & VSCP_DRIVER_OUT_TR_M1M2F) {
                        vscp_convertLevel1MeasuremenToLevel2Double(pvscpEvent);
                    }
                    // Level I measurement events to Level II measurement string
                    else if (pDevItem->m_translation &
                             VSCP_DRIVER_OUT_TR_M1M2S) {
                        vscp_convertLevel1MeasuremenToLevel2String(pvscpEvent);
                    }

                    // Level I events to Level I over Level II events
                    if (pDevItem->m_translation & VSCP_DRIVER_OUT_TR_ALL512) {
                        pvscpEvent->vscp_class += 512;
                        uint8_t *p = new uint8_t[16 + pvscpEvent->sizeData];
                        if (NULL != p) {
                            memset(p, 0, 16 + pvscpEvent->sizeData);
                            memcpy(
                              p + 16, pvscpEvent->pdata, pvscpEvent->sizeData);
                            pvscpEvent->sizeData += 16;
                            delete[] pvscpEvent->pdata;
                            pvscpEvent->pdata = p;
                        }
                    }

                    pthread_mutex_lock(
                      &pDevItem->m_pCtrlObject->m_mutexClientOutputQueue);
                    pDevItem->m_pCtrlObject->m_clientOutputQueue.push_back(
                      pvscpEvent);
                    sem_post(&pDevItem->m_pCtrlObject->m_semClientOutputQueue);
                    pthread_mutex_unlock(
                      &pDevItem->m_pCtrlObject->m_mutexClientOutputQueue);
                }
            }
        }
    }

    return NULL;
}
コード例 #3
0
ファイル: devicethread.cpp プロジェクト: gvsurenderreddy/vscp
void *deviceCanalReceiveThread::Entry()
{
    canalMsg msg;
    CanalMsgOutList::compatibility_iterator nodeCanal;

    // Must be a valid main object pointer
    if (NULL == m_pMainThreadObj) return NULL;

    // Blocking receive method must have been found
    if (NULL == m_pMainThreadObj->m_pDeviceItem->m_proc_CanalBlockingReceive) return NULL;

    while (!TestDestroy() && !m_bQuit) {

        if (CANAL_ERROR_SUCCESS ==
                m_pMainThreadObj->m_pDeviceItem->m_proc_CanalBlockingReceive(
                                                            m_pMainThreadObj->m_pDeviceItem->m_openHandle, &msg, 500 ) ) {

            // There must be room in the receive queue
            if (m_pMainThreadObj->m_pCtrlObject->m_maxItemsInClientReceiveQueue >
                    m_pMainThreadObj->m_pCtrlObject->m_clientOutputQueue.GetCount()) {

                vscpEvent *pvscpEvent = new vscpEvent;
                if (NULL != pvscpEvent) {

                    memset( pvscpEvent, 0, sizeof( vscpEvent ) );

                    // Convert CANAL message to VSCP event
                    vscp_convertCanalToEvent( pvscpEvent,
                                                &msg,
                                                m_pMainThreadObj->m_pDeviceItem->m_pClientItem->m_guid.m_id );

                    pvscpEvent->obid = m_pMainThreadObj->m_pDeviceItem->m_pClientItem->m_clientID;

                    // If no GUID is set,
                    //      - Set driver GUID if it is defined
                    //      - Set to interface GUID if not.

                    uint8_t ifguid[16];

                    // Save nickname
                    uint8_t nickname_lsb = pvscpEvent->GUID[15];

                    // Set if to use
                    memcpy( ifguid, pvscpEvent->GUID, 16 );
                    ifguid[14] = 0;
                    ifguid[15] = 0;

                    // If if is set to zero use interface id
                    if ( vscp_isGUIDEmpty( ifguid ) ) {

                        // Set driver GUID if set
                        if ( !m_pMainThreadObj->m_pDeviceItem->m_interface_guid.isNULL() ) {
                            m_pMainThreadObj->m_pDeviceItem->m_interface_guid.writeGUID( pvscpEvent->GUID );
                        }
                        else {
                            // If no driver GUID set use interface GUID
                            m_pMainThreadObj->m_pDeviceItem->m_pClientItem->m_guid.writeGUID( pvscpEvent->GUID );
                        }

                        // Preserve nickname
                        pvscpEvent->GUID[15] = nickname_lsb;

                    }

                    m_pMainThreadObj->m_pCtrlObject->m_mutexClientOutputQueue.Lock();
                    m_pMainThreadObj->m_pCtrlObject->m_clientOutputQueue.Append(pvscpEvent);
                    m_pMainThreadObj->m_pCtrlObject->m_semClientOutputQueue.Post();
                    m_pMainThreadObj->m_pCtrlObject->m_mutexClientOutputQueue.Unlock();

                }
            }
        }
    }

    return NULL;
}
コード例 #4
0
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;
}