TS-4710 Watchdog

From Technologic Systems Manuals

By default there is a /dev/watchdog with the tshwctl daemon running at the highest possible priority to feed the watchdog. This is a pipe that is created in userspace, so for many applications this may provide enough functionality for the watchdog by verifying that userspace is still executing applications. If you would like to have the watchdog functionality more tightly integrated with your application you can specify various feed options.

At the lower level there are 3 valid watchdog feed values that are written to the watchdog register in the #Syscon:

Value Result
0 feed watchdog for another .338s
1 feed watchdog for another 2.706s
2 feed watchdog for another 10.824s
3 disable watchdog

The watchdog is armed by default for 10s for the operating system to take over, after which the startup scripts autofeed the watchdog with:

echo a2 > /dev/watchdog

The /dev/watchdog fifo accepts 3 types of commands:

Value Function
f<3 digits> One time feed for a specified amount of time which uses the 3 digit number / 10. For example, "f456" would feed for 45.6 seconds.
"0", "1", "2", "3" One time feed with the value in the above table.
a<num 0-3> This value autofeeds with the value in the above table.

Most applications should use the f<3 digits> option to more tightly integrate this to their application. For example:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

void do_some_work(int data) {
	/* The contract for sleep(int n) is that it will sleep for at least n
	 * seconds, but not less.  If other kernel threads or processes require
	 * more time sleep can take longer, but when your process has a high
	 * priority this is usually measured in millseconds */
	sleep(5);
}

int read_some_io() {
	/* If this function (or do_some_work) misbehave and stall thee watchdog 
         * will not be fed in the main loop and cause a reboot.  You can test 
         * this by uncommenting the next line to force an infinite loop */
	// while (1) {}
	return 42;
}

int main(int argc, char **argv)
{
	int wdfd;
	/* In languages other than C/C++ this is still essentially the same, but
	 * make sure you are opening the watchdog file synchronously so the writes
	 * happen immediately.  Many languages will buffer writes together to make 
	 * them more efficient, but the watchdog needs the writes to be timed 
	 * precisely */
	wdfd = open("/dev/watchdog", O_SYNC|O_RDWR);

	while (1) {
		int data;
		/* This loop is expected to take about 5-6 seconds, but to allow some
		 * headroom for other applications, I will feed the watchdog for 10s. */
		write(wdfd, "f100", 4);

		data = read_some_io();
		do_some_work(data);
	}
}