C/Timers

From Attie's Wiki
Revision as of 10:20, 1 October 2014 by Attie (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <time.h>
 
/*
	TIME_MAX should equate to 4294966999
	this equals approx 49.71 days
		4294966999 / 1000 / 60 / 60 / 24 = 49.71...
*/
 
 
#define SECONDS_MAX  (((uint32_t)(((uint32_t)-1) / 1000) - 1))
 
/* roughly 49.7 days */
#define TIME_MAX     ((uint32_t)((SECONDS_MAX * 1000) + 999))
 
/* roughly 48.7 days... 24 hours less than TIME_MAX */
#define TIMEOUT_MAX  ((uint32_t)(TIME_MAX - (1000 * 60 * 60 * 24)))
 
/* the difference between TIME_MAX and TIMEOUT_MAX allows a grace period
   of roughly 1 day for the user to check if a timeout has occured - if
   the user doesn't check within this time, then they deserve to have
   problems... :-) */
 
uint32_t get_time(void) {
	struct timespec ts;
	uint32_t ms;
 
	if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
		perror("clock_gettime()");
		exit(1);
	}
 
	ts.tv_sec  %= SECONDS_MAX;        /* wrap the seconds field at SECONDS_MAX */
	ts.tv_nsec /= 1000000;            /* convert ns to ms */
	ts.tv_sec  += ts.tv_nsec / 1000;  /* add any seconds from the nsec field - there shouldn't be any... */
	ts.tv_nsec %= 1000;               /* wrap the nsec field to 1 seconds-worth of milliseconds */
	ts.tv_sec  %= SECONDS_MAX;        /* re-wrap the seconds field at SECONDS_MAX */
 
	ms  = ts.tv_sec * 1000;           /* convert s to ms */
	ms += ts.tv_nsec;                 /* add the ms count */
 
	return ms;
}
 
 
uint32_t timeout_start(uint32_t timeout) {
	/* we need a 64-bit variable for this operation, because a large time + a large timeout could wrap at a funny place (32-bit max, not TIME_MAX) */
	uint64_t ms;
 
	if (timeout > TIMEOUT_MAX) timeout = TIMEOUT_MAX;
 
	ms  = get_time();
	ms += timeout;
	ms %= TIME_MAX;
 
	return (uint32_t)(ms & 0xFFFFFFFF);
}
 
uint32_t timeout_remain(uint32_t timeout) {
	uint64_t to;
	uint32_t ms;
 
	to = timeout;
	ms = get_time();
 
	if (to < ms) {
		/* a large time - a small timeout would cause the operation to wrap to a fumny place (32-bit max, not TIME_MAX), so we need to artificially wrap the calculation using a 64-bit variable */
		to += TIME_MAX;	
	}
	to -= ms;
	to %= TIME_MAX;
	ms = (uint32_t)(to & 0xFFFFFFFF);
 
	return (ms > TIMEOUT_MAX ? 0 : ms);
}
 
uint8_t timeout_check(uint32_t timeout) {
	return !timeout_remain(timeout);
}
 
/* - - - - */
 
int main(int argc, char *argv[]) {
	uint32_t ms;
 
	uint32_t timeout;
 
	printf(    "t_max_sec        : %10u\n", SECONDS_MAX);
	printf(    "time_max         : %10u\n", TIME_MAX);
	printf(    "timeout_max      : %10u\n", TIMEOUT_MAX);
	printf("\n");
 
	timeout = timeout_start(15 * 1000);
	printf(    "timeout          : %10u\n", timeout);
	printf("\n");
 
	for (;; printf("%c[4A", 27)) {
		ms = get_time();
 
		printf("the time (in ms) : %10u (%.5f%%)%c[K\n", ms, (((float)ms / (float)TIME_MAX) * 100), 27);
		printf("timeout over?    : %s%c[K\n", timeout_check(timeout) ? "yes" : "no", 27);
		printf("timeout remain   : %10u%cK\n", timeout_remain(timeout), 27);
 
		{
			int x, y;
			uint32_t d, h, m, s, ss;
			x  = 1; y = 1000; ss = (ms / x) % y;
			x *= y; y = 60;    s = (ms / x) % y;
			x *= y; y = 60;    m = (ms / x) % y;
			x *= y; y = 24;    h = (ms / x) % y;
			x *= y; y = 50;    d = (ms / x) % y;
 
			printf("time since boot  : %ud, %02u:%02u:%02u.%03u%c[K\n",
			       d, h, m, s, ss, 27);
		}
 
		fflush(stdout);
		usleep(1000);
	}
 
	return 0;
}
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox