/*****************************************************************************
 * Copyright (C) Cinterion Wireless Modules GmbH
 *****************************************************************************
 * Project: Quinn-CE-USB-Driver
 *****************************************************************************
 * Author : Siemens AG Berlin COM WM RD SW
 *****************************************************************************
 * $Workfile: D:/develop/ccviews/ctna0152_ms-d_view/z_ms-d/src/working/Quinn/HcUsbDrv/UsbWatchdog.cpp $
 * $Revision: /main/ms-d/5 $
 * $Date: 2010-12-13 14:23:25 $
 * $Author: ctna0152 $
 *****************************************************************************
 * Target:
 *  Microsoft Windows CE 5.0
 *****************************************************************************
 * Description:
 *  Quinn-USB-Driver: Implementation of the class CUsbDriver
 *  doing the global USB driver handling.
 *****************************************************************************
 *
 * $Log: D:/develop/ccviews/ctna0152_ms-d_view/z_ms-d/src/working/Quinn/HcUsbDrv/UsbWatchdog.cpp$ 
 * 
 * /main/ms-d/5   2010-12-13 14:23:25   ctna0152 
 * changed debug messages 
 * 
 * /main/ms-d/4   2009-02-18 11:49:49   ctna0256 
 * Set copyright text 
 * 
 * /main/ms-d/3   2008-08-20 11:39:59   ctna0450 
 * Prepared for new disclaimer handling 
 * 
 * /main/ms-d/2   2008-03-03 11:17:17   ht37010 
 * changed debug messages
 * increased watchdog thread priority 
 * 
 * /main/ms-d/1   2007-12-18 15:45:04   ht37010 
 *
 * /main/ms-d/1   2007-07-31 11:33:43   ht37010 
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Cinterion Wireless Modules GmbH
// Copyright (C) 2006-2008 Siemens AG
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

#include "precomp.h"

CUsbWatchDog::CUsbWatchDog( DWORD dwTimeout ) {
    m_dwTimeout = dwTimeout;
    m_hFuncStartEvent  = CreateEvent(NULL, TRUE, FALSE, NULL);
    m_hFuncStopEvent   = CreateEvent(NULL, TRUE, FALSE, NULL);
    m_hThreadStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    wsprintf(m_wszMessage, L"undefined" );
    m_hThread = CreateThread(NULL, 0, ThreadFunc, this, 0, NULL);
}

CUsbWatchDog::~CUsbWatchDog() {
    SetEvent( m_hThreadStopEvent );
    // wait for thread termination
    DEBUGMSG(ZONE_USB_WATCHDOG, (TEXT("HcUsb: WATCHDOG - WaitForThreadTermination\r\n")));
    WaitForSingleObject( m_hThread, INFINITE );
    CloseHandle( m_hThread );
    CloseHandle( m_hThreadStopEvent );
    CloseHandle( m_hFuncStartEvent );
    CloseHandle( m_hFuncStopEvent );
}

void CUsbWatchDog::start( WCHAR *wszMessage ) {
    wsprintf(m_wszMessage, L"%s", wszMessage );
    m_callingThreadID = GetCurrentThreadId();
    NKDbgPrintfW( TEXT("%06d HcUsb: CUsbWatchDog::start(%s) wd=%p\r\n"), GetTickCount(), m_wszMessage, this );
    SetEvent( m_hFuncStartEvent );
}

void CUsbWatchDog::stop( void ) {
    NKDbgPrintfW( TEXT("%06d HcUsb: CUsbWatchDog::stop(%s) wd=%p\r\n"), GetTickCount(), m_wszMessage, this );
    SetEvent( m_hFuncStopEvent );
}

DWORD WINAPI CUsbWatchDog::ThreadFunc(LPVOID lpParameter) {
    CUsbWatchDog *pBC = (CUsbWatchDog *)lpParameter;
    HANDLE hWaitStart[] = { pBC->m_hFuncStartEvent, pBC->m_hThreadStopEvent };
    HANDLE hWaitStop[]  = { pBC->m_hFuncStopEvent,  pBC->m_hThreadStopEvent };

    //DEBUGMSG(ZONE_ERROR, (TEXT("HcUsb: WATCHDOG - %s: start thread\r\n"), MSG_TEXT));
    // increase prio for thread
    CeSetThreadPriority(GetCurrentThread(), 100);

    while ( TRUE ) {
        switch ( WaitForMultipleObjects( 2, hWaitStart, FALSE, INFINITE ) ) {
        case WAIT_OBJECT_0:
            // continue with waiting for func-stop
            break;
        case WAIT_OBJECT_0 +1:
            DEBUGMSG(ZONE_USB_WATCHDOG, (TEXT("HcUsb: WATCHDOG - %s: WaitForStart deinit wd=%p\r\n"), pBC->m_wszMessage, pBC));
            return 0;
        default:
            DEBUGMSG(ZONE_ERROR, (TEXT("HcUsb: WATCHDOG - %s: WaitForStart error wd=%p\r\n"), pBC->m_wszMessage, pBC));
            return -1;
        }
        ResetEvent( pBC->m_hFuncStartEvent );
        switch ( WaitForMultipleObjects( 2, hWaitStop,  FALSE, pBC->m_dwTimeout ) ) {
        case WAIT_OBJECT_0:
            // continue with waiting for func-start
            wsprintf(pBC->m_wszMessage, L"unused" );
            break;
        case WAIT_OBJECT_0 +1:
            DEBUGMSG(ZONE_USB_WATCHDOG, (TEXT("HcUsb: WATCHDOG - %s: WaitForStop deinit wd=%p\r\n"), pBC->m_wszMessage, pBC));
            return 0;
        case WAIT_TIMEOUT:
            NKDbgPrintfW(TEXT("%06d HcUsb: WATCHDOG - %s: WaitForStop timed out (ThreadID=0x%X) wd=%p\r\n"), GetTickCount(), pBC->m_wszMessage, pBC->m_callingThreadID, pBC);
            RaiseException( 0xC0000210L /* STATUS_TRANSACTION_TIMED_OUT */, EXCEPTION_NONCONTINUABLE, 0, NULL );
            break;
        default:
            DEBUGMSG(ZONE_ERROR, (TEXT("HcUsb: WATCHDOG - %s: WaitForStop error wd=%p\r\n"), pBC->m_wszMessage, pBC));
            return -1;
        }
        ResetEvent( pBC->m_hFuncStopEvent );
    }
}
