/*****************************************************************************
 * Copyright (C) Gemalto M2M GmbH
 *****************************************************************************
 * Project: IMC-RIL-Driver
 *****************************************************************************
 * Author : Wireless Modules RD SW A2
 *****************************************************************************
 * $Workfile: Y:/z_ms-d/src/working/Quinn/RilDrv/monitor.cpp $
 * $Revision: /main/ms-d/5 $
 *     $Date: 2012-10-08 16:18:31 $
 *   $Author: pmackent $
 *****************************************************************************
 * Target:
 *  Microsoft Windows Mobile 5.0
 *****************************************************************************
 * Description:
 *  Gemalto IMC RIL
 *****************************************************************************
 *
 * $Log: Y:/z_ms-d/src/working/Quinn/RilDrv/monitor.cpp$ 
 * 
 * /main/ms-d/5   2012-10-08 16:18:31   pmackent 
 * Comply to Klocwork checks.
 *
 * /main/ms-d/4   2011-09-26 13:34:42   ctna0256
 * Comply with CE6 warning level 4
 *
 * /main/ms-d/3   2008-08-22 10:24:27   ctna0256
 * Set Cinterion copyright text
 *
 * /main/ms-d/2   2008-08-21 09:34:45   ctna0256
 * Prepared for new disclaimer handling
 *
 * /main/ms-d/1   2006-10-25 16:53:55   wm36264
 * First transformation from classic RIL
 *
*/

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Gemalto M2M GmbH
// Copyright (C) 2006-2008 Siemens AG
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//
// Version: 1.0
// Date:    dummy
//
//////////////////////////////////////////////////////////////////////////////

/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation
--*/

#include "precomp.h"

static void Reboot(void)
{
    // Flush the flash database volumes
    (void)CeFlushDBVol(NULL);

    // Flush the registry to flash.
    (void)RegFlushKey(HKEY_CURRENT_USER);

    (void)KernelIoControl(IOCTL_HAL_REBOOT, NULL, NULL, NULL, 0, NULL);

    return;
}


//
// Thread responsible for monitoring RIL
//
static DWORD WINAPI MonitorThreadProc(LPVOID lpParameter)
{
#ifdef UNDER_CE
    DWORD dwWait;
    CMonitor* pMonitor = (CMonitor*)lpParameter;
    int nEventCnt = 2;

    // Let the main thead know that the thread has started up
    if (pMonitor->GetCheckPoint() != NULL)
        pMonitor->GetCheckPoint()->Reached();

    HANDLE rghEvents[] = { g_hCriticalErrorEvent, pMonitor->GetCancelEvent() };

    // Switch the thread into higher priority (to guarantee that CPM doesn't reboot the device just because this
    //    thread didn't get scheduled)
    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
        goto Error;
    }

    for (;;) {
        dwWait = WaitForMultipleObjects(nEventCnt, rghEvents, FALSE, INFINITE);
        if (WAIT_OBJECT_0 == dwWait) {
                // For platforms that do not use CPM, just reboot thank you
                Reboot();
        } else if (WAIT_OBJECT_0 + 1 == dwWait) {
            // RIL is exiting -- terminate this thread
            goto Error;
        }
    }

Error:
#endif // UNDER_CE

    return 0;
}


//
// Ctor
//
CMonitor::CMonitor()
: m_hCancelEvent(NULL),
  m_hCriticalErrorEvent(NULL),
  m_pCheckPoint(NULL),
  m_hMonitorThread(NULL)
{
}


//
// Dtor
//
CMonitor::~CMonitor()
{
    // Destroy the monitor thread
    if (m_hMonitorThread)
    {
        // Wait for the monitor thread to terminate
        DWORD dwRes = WaitForSingleObject(m_hMonitorThread, 10000);
        if (WAIT_OBJECT_0 != dwRes)
        {
            // If the thread did not terminate, then maybe
            // the timeout is too short. Alert someone.
            ASSERT(0);

            // We could try to force the thread to terminate,
            // but it's probably not worth the risk. The monitor
            // thread does two things: notify CPM, and quit.
            // If the thread is stuck in CPM, then let's not
            // exacerbate the problem by killing a thread that
            // is executing CPM code.
        }

        // Close thread object
        (void)CloseHandle(m_hMonitorThread);
        m_hMonitorThread = NULL;
    }

    if (m_pCheckPoint != NULL) delete m_pCheckPoint;
    m_pCheckPoint = NULL;
}


//
// Initialisation
//
BOOL CMonitor::Init(const HANDLE hCancelEvent)
{
    BOOL fRet = FALSE;

#ifdef UNDER_CE
    m_hCancelEvent = hCancelEvent;

    // Create the thread checkpoint
    m_pCheckPoint = new CCheckPoint;
    if (!m_pCheckPoint || !m_pCheckPoint->Init(1)) {
        goto Error;
    }

    // Launch the monitor thread
    m_hMonitorThread = CreateThread(NULL, 0, MonitorThreadProc, (LPVOID)this, 0, NULL);
    if (!m_hMonitorThread) {
        goto Error;
    }

    // Wait until the thread starts up
    if (!m_pCheckPoint->Wait(30000)) {
        goto Error;
    }
    fRet = TRUE;

Error:
    delete m_pCheckPoint;
    m_pCheckPoint = NULL;

    if (!fRet) {
        if (m_hMonitorThread) {
            (void)CloseHandle(m_hMonitorThread);
            m_hMonitorThread = NULL;
        }
    }
#endif // UNDER_CE

    return fRet;
}

