/**
 * \file qwatchdog.cpp
 *
 * \brief Keep tickling the watchdog so we don't reboot
 *
 *     o  0
 *     | /       Copyright (c) 2005-2012
 *    (CL)---o   Critical Link, LLC
 *      \
 *       O
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

#if defined (WIN32)
#elif defined (__GNUC__)
#include <linux/types.h>
#include <linux/watchdog.h>
#elif defined (_TMS320C6X)
#endif

#include "qwatchdog.h"

#if defined(__GNUC__) // linux

/**
 * @brief Constructor
 * @param anBarkMs Bark Rate (How often to Ping the System Watchdog)
 * @param apParent QT Parent Object
 */
tcQWatchDog::tcQWatchDog(int anBarkMs, QObject* apParent)
    : QObject(apParent)
    , mnBarkMs(anBarkMs)
    , mnFd(-1)
    , mnTimerId(-1)
{
    mnBarkMs = mnBarkMs ?: 10000; // do not allow 0 interval

    if(!getenv("DISABLE_WATCHDOG"))
    {
        struct watchdog_info ident;

        mnFd = ::open("/dev/watchdog", O_WRONLY);
        if(0 < mnFd) // should actually end up >> 0
        {
            int interval = mnBarkMs*2/1000;
            int status = 0;
            memset(&ident, '\0', sizeof(ident));
            status = ioctl(mnFd, WDIOC_GETSUPPORT, &ident);
            if(0 != status)
            {
                qWarning("Unable to get watchdog info!:%s\n",strerror(errno));
            }
            else
            {
                qDebug("Watchdog:%s - v%08x - opts = 0x%08x\n",
                       ident.identity, ident.firmware_version, ident.options);
            }
            status = ioctl(mnFd, WDIOC_SETTIMEOUT, &interval);
            if(0 != status)
            {
                qWarning("Unable to set watchdog timeout!:%s\n",strerror(errno));
            }
            interval = -1;
            status = ioctl(mnFd, WDIOC_GETTIMEOUT, &interval);
            if((0 == status) && (interval*1000) < (mnBarkMs*2))
                mnBarkMs = interval * 500; // set WD timeout to 1/2 interval

            qDebug("Watchdog timeout set to %dms [%dms requested]\n", mnBarkMs, anBarkMs);

            if(0 == status)
                mnTimerId = startTimer(mnBarkMs);
        }
        else
        {
            qWarning("Unable to open /dev/watchdog!:%s\n",strerror(errno));
        }
    }
    else
    {
        qWarning("Watchdod disabled.. DISABLE_WATCHDOG env var set\n");
    }
}

/**
 * @brief Destructor
 */
tcQWatchDog::~tcQWatchDog()
{
    if(-1 != mnTimerId)
        killTimer(mnTimerId);
    if(-1 != mnFd)
        ::close(mnFd);
}

/**
 * @brief Sends Ping to System Watchdog
 */
void tcQWatchDog::timerEvent(QTimerEvent *)
{
    //bark
    int dummy = 1;

    ioctl(mnFd, WDIOC_KEEPALIVE, &dummy);

}
#else

// no watchdog on windows
/**
 * \brief Constructor
 *
 * \param anBarkMs Bark Rate (How often to Ping the System Watchdog)
 * \param apParent Pointer to parent QT Object
 */
tcQWatchDog::tcQWatchDog(int anBarkMs, QObject* apParent)
    : QObject(apParent)
    , mnBarkMs(anBarkMs)
    , mnFd(-1)
{
    qWarning("No watchdog support on this platform\n");
}

/**
 * \brief Destructor
 */
tcQWatchDog::~tcQWatchDog()
{
}

/**
 * \brief Timer Event does nothing for Windows
 */
void tcQWatchDog::timerEvent(QTimerEvent *)
{
}
#endif // __GNUC__

#ifdef WATCHDOG_UT
#include <iostream>
#include <QStringList>
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>

class CMyApp : public QCoreApplication
{
public:
    CMyApp(int ms, int argc, char** argv);
protected:
    void timerEvent(QTimerEvent*);
};

CMyApp::CMyApp(int ms , int argc, char** argv)
    : QCoreApplication (argc, argv)
{
    printf("My App here... printing a \'.\' every %d sec\n",ms/10000);
    startTimer(ms);
}
void CMyApp::timerEvent(QTimerEvent*)
{
    printf(".");
    fflush(stdout);
}

int main(int argc, char** argv)
{
    CMyApp a(10000, argc, argv);

    qDebug() << "Building watchdog...";
    tcQWatchDog woof;
    qDebug() << "Entering main loop... reboot comin!";
    return a.exec();

}
#endif // WATCHDOG_UT
