|
#include "watchdog.h"
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <linux/watchdog.h>
|
|
|
|
using namespace MityDSP;
|
|
|
|
/**
|
|
* Constructor for the watchdog abstraction
|
|
*
|
|
* \param apDevice filename of device (defaults to /dev/watchdog)
|
|
*/
|
|
tcWatchdog::tcWatchdog(const char* apDevice)
|
|
: mnMask(0)
|
|
, mnSet(0)
|
|
, mnFd(-1)
|
|
{
|
|
sem_init(&mhSem, 0, 1);
|
|
mpFileName = new char[strlen(apDevice)+1];
|
|
strcpy(mpFileName, apDevice);
|
|
}
|
|
|
|
/**
|
|
* Destructor. Shuts down running watchdog. cleans up resources.
|
|
*/
|
|
tcWatchdog::~tcWatchdog(void)
|
|
{
|
|
const char *no_reboot = "V\n";
|
|
if (mnFd >= 0)
|
|
{
|
|
printf("shutting down watchdog\n");
|
|
write(mnFd,no_reboot,strlen(no_reboot));
|
|
close(mnFd);
|
|
}
|
|
delete [] mpFileName;
|
|
sem_destroy(&mhSem);
|
|
}
|
|
|
|
/**
|
|
* Enable the watchdog. This should typically be
|
|
* called after at least 1 checkpoint has been registered
|
|
* and the application is ready for the watchdog operation
|
|
* to begin.
|
|
*
|
|
* \param TimeoutSecs number of seconds before watchdog timeout
|
|
* \return non-zero on error.
|
|
*/
|
|
int tcWatchdog::StartWatchDog(int TimeoutSecs)
|
|
{
|
|
mnFd = open(mpFileName, O_RDWR);
|
|
if (mnFd < 0)
|
|
{
|
|
perror("open watchdog:");
|
|
return mnFd;
|
|
}
|
|
// NOTE: L138 watchdog driver doesn't support WDIOC_SETTIMEOUT.
|
|
// Timeout defaults to 60 seconds
|
|
ioctl(mnFd,WDIOC_SETTIMEOUT,&TimeoutSecs);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Register a checkpoint. The tcWatchdog class supports multiple
|
|
* checkpoints (or threads, etc.) that must Checkin() prior to the
|
|
* watchdog being tagged. This routine generates a handle for a
|
|
* newly registered checkpoint.
|
|
*
|
|
* \return handle to use for Checkin() or -1 on failure.
|
|
*/
|
|
int tcWatchdog::RegisterCheckpoint(void)
|
|
{
|
|
int i, mask;
|
|
int rv = -1;
|
|
sem_wait(&mhSem);
|
|
/* find next available slot in mask */
|
|
for (i = 0, mask=1; i < 31; i++, mask<<=1)
|
|
{
|
|
if (!(mask & mnMask))
|
|
{
|
|
mnMask |= mask;
|
|
rv = mask;
|
|
break;
|
|
}
|
|
}
|
|
sem_post(&mhSem);
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* Remove a registered checkpoint from the monitor list.
|
|
* \param handle the checkpoint previously from RegisterCheckpoint
|
|
* \return non-zero on error.
|
|
*/
|
|
int tcWatchdog::UnRegisterCheckpoint(int handle)
|
|
{
|
|
int rv = -1;
|
|
sem_wait(&mhSem);
|
|
if (handle & mnMask)
|
|
{
|
|
mnMask &= ~handle;
|
|
rv = 0;
|
|
}
|
|
sem_post(&mhSem);
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* Check in for the watchdog update. When all registered
|
|
* methods have checked in, the watchdog timer will be
|
|
* tagged/reset.
|
|
*
|
|
* \param Checkpoint checkpoint handle from RegisterCheckpoint
|
|
*
|
|
* \return non-zero on error.
|
|
*/
|
|
int tcWatchdog::Checkin(int Checkpoint)
|
|
{
|
|
if (mnFd < 0)
|
|
return -1;
|
|
|
|
sem_wait(&mhSem);
|
|
mnSet |= Checkpoint;
|
|
if (mnSet == mnMask)
|
|
{
|
|
/* tag watchdog */
|
|
mnSet = 0;
|
|
ioctl(mnFd, WDIOC_KEEPALIVE, 0);
|
|
}
|
|
sem_post(&mhSem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef WATCHDOG_MAIN
|
|
int main()
|
|
{
|
|
tcWatchdog watch;
|
|
int watchHandle;
|
|
|
|
printf("Starting watchdog! Timeout interval 60s.\n");
|
|
watch.StartWatchDog(60000);
|
|
watchHandle = watch.RegisterCheckpoint();
|
|
|
|
while (1 == 1)
|
|
{
|
|
printf(".");
|
|
fflush(stdout);
|
|
|
|
// Tickle watchdog
|
|
watch.Checkin(watchHandle);
|
|
// Sleep 1 second
|
|
sleep(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|