LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-07-2014, 07:55 PM   #1
metaschima
Senior Member
 
Registered: Dec 2013
Distribution: Slackware
Posts: 1,982

Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
timer / stopwatch program in C and ncurses


I wrote a timer program in C, but it's not too accurate. Any ideas on how to make it more accurate, like to 10 ms or 100 ms or so. It doesn't need to be too accurate, but the current one is only accurate to the nearest second or so and pausing may introduce more error.

Code:
#include <stdio.h>
#include <time.h>
#include <unistd.h>

#include <ncurses.h>

int main (int argc, char *argv[])
{
	int ch;
	unsigned int countdown;
	time_t start;
	time_t now;

	if (1 == argc)
	{
		start = time (NULL);
	}
	else if (2 == argc)
	{
		sscanf (argv[1], "%u", &countdown);
		start = time (NULL) + (countdown * 60);
	}
	else
	{
		printf ("Usage: %s <minute_countdown>\n", argv[0]);
		return 1;
	}

	initscr();
	cbreak();
	noecho();
	nodelay (stdscr, TRUE);

	int paused = 0;
	time_t prev = 0;
	for (;;)
	{
		if (0 == paused)
		{
			now = time (NULL) - start;
			if (now != prev)
			{
				mvprintw (1, 2, "%+04d:%+03d", now / 60 , now % 60);
				refresh();
				prev = now;
			}
		}
		else
		{
			start = time (NULL) - now;
		}

		if (ERR != (ch = getch()))
		{
			if (27 == ch)
			{
				break;
			}
			else
			{
				if (0 == paused)
				{
					attron (A_STANDOUT);
					paused = 1;
				}
				else
				{
					attroff (A_STANDOUT);
					paused = 0;
				}
				mvprintw (1, 2, "%+04d:%+03d", now / 60 , now % 60);
				refresh();
			}
		}
		usleep(100000);
	}

	endwin();
	return 0;
}
It works well, and I'll keep using it, but I'm sure there's another way. I still need to be able to pause it and resume it, as that's the most important feature, and countdown.

Oh, and it should stay mostly portable, but I only run Linux.

I was thinking of using usleep to pause for certain time, but I feel that the commands in-between will gradually add time to it and make it inaccurate, so before doing that I'm asking for other methods.

Thanks
 
Old 04-07-2014, 10:28 PM   #2
gengisdave
Member
 
Registered: Dec 2013
Location: Turin, Italy
Distribution: slackware
Posts: 328

Rep: Reputation: 74
use gettimeofday, it uses a struct to store sec/msec
 
1 members found this post helpful.
Old 04-08-2014, 03:37 PM   #3
metaschima
Senior Member
 
Registered: Dec 2013
Distribution: Slackware
Posts: 1,982

Original Poster
Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
I decided to use clock_gettime as it is recommended over gettimeofday, but it still doesn't work quite right, I'll have to think this over a bit. Maybe the math is wrong.

Code:
#include <stdio.h>
#include <time.h>
#include <unistd.h>

#include <ncurses.h>

int main (int argc, char *argv[])
{
	int ch;
	unsigned int countdown;
	struct timespec start;
	struct timespec now;

	clock_gettime(CLOCK_MONOTONIC, &start);
	if (2 == argc)
	{
		sscanf (argv[1], "%u", &countdown);
		start.tv_sec += countdown * 60;
	}
	else if (1 != argc)
	{
		printf ("Usage: %s <minute_countdown>\n", argv[0]);
		return 1;
	}

	initscr();
	cbreak();
	noecho();
	nodelay (stdscr, TRUE);

	int paused = 0;
	struct timespec prev = start;
	for (;;)
	{
		if (0 == paused)
		{
			clock_gettime(CLOCK_MONOTONIC, &now);
			now.tv_sec -= start.tv_sec;
			now.tv_nsec -= start.tv_nsec;
			if (now.tv_sec != prev.tv_sec && now.tv_nsec != prev.tv_nsec)
			{
				mvprintw (1, 2, "%+04d:%+03d:%+03d", now.tv_sec / 60 , now.tv_sec, now.tv_nsec/1000000);
				refresh();
				prev = now;
			}
		}
		else
		{
			clock_gettime(CLOCK_MONOTONIC, &start);
			start.tv_sec -= now.tv_sec;
			start.tv_nsec -= now.tv_nsec;
		}

		if (ERR != (ch = getch()))
		{
			if (27 == ch)
			{
				break;
			}
			else
			{
				if (0 == paused)
				{
					attron (A_STANDOUT);
					paused = 1;
				}
				else
				{
					attroff (A_STANDOUT);
					paused = 0;
				}
				mvprintw (1, 2, "%+04d:%+03d:%+03d", now.tv_sec / 60 , now.tv_sec, now.tv_nsec/1000000);
				refresh();
			}
		}
		usleep(100000);
	}

	endwin();
	return 0;
}
 
Old 04-08-2014, 08:14 PM   #4
metaschima
Senior Member
 
Registered: Dec 2013
Distribution: Slackware
Posts: 1,982

Original Poster
Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
Alright, I think I got it, here's the final version.

Code:
#include <stdio.h>
#include <time.h>

#include <ncurses.h>

inline void subtract_time (struct timespec * __restrict later, struct timespec * __restrict former)
{
	clock_gettime(CLOCK_MONOTONIC, later);
	later->tv_sec -= former->tv_sec;
	if (later->tv_nsec < former->tv_nsec)
	{
		later->tv_sec--;
		later->tv_nsec = 1000000000 + later->tv_nsec - former->tv_nsec;
	}
	else
	{
		later->tv_nsec -= former->tv_nsec;
	}
}

int main (int argc, char *argv[])
{
	int ch;
	unsigned int countdown;
	struct timespec start;
	struct timespec now;

	clock_gettime(CLOCK_MONOTONIC, &start);
	if (2 == argc)
	{
		sscanf (argv[1], "%u", &countdown);
		start.tv_sec += countdown * 60;
	}
	else if (1 != argc)
	{
		printf ("Usage: %s <minute_countdown>\n", argv[0]);
		return 1;
	}

	initscr();
	cbreak();
	noecho();
	nodelay (stdscr, TRUE);

	struct timespec delay;
	delay.tv_sec = 0;
	delay.tv_nsec = 1000000;

	int paused = 0;
	struct timespec prev = start;
	for (;;)
	{
		if (0 == paused)
		{
			subtract_time (&now, &start);
			if (now.tv_sec != prev.tv_sec)
			{
				mvprintw (1, 2, "%+04d:%+03d", now.tv_sec / 60 , now.tv_sec % 60);
				refresh();
				prev = now;
			}
		}
		else
		{
			subtract_time (&start, &now);
		}

		if (ERR != (ch = getch()))
		{
			if (27 == ch)
			{
				break;
			}
			else
			{
				if (0 == paused)
				{
					attron (A_STANDOUT);
					paused = 1;
				}
				else
				{
					attroff (A_STANDOUT);
					paused = 0;
				}
				mvprintw (1, 2, "%+04d:%+03d", now.tv_sec / 60 , now.tv_sec % 60);
				refresh();
			}
		}
		clock_nanosleep (CLOCK_MONOTONIC, 0, &delay, NULL);
	}

	endwin();
	return 0;
}
It works well, so I will mark this solved. If someone sees an error, tell me.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Timer program mutetikasikali Linux - Software 4 07-24-2013 06:58 PM
[SOLVED] Ncurses bug or ncurses program error. errigour Programming 2 01-24-2013 08:36 AM
[SOLVED] Stopwatch program for Linux. stf92 Linux - Software 13 06-06-2011 04:45 AM
Looking for timer+stopwatch+small reminder GUI app hottdogg Linux - Software 4 12-26-2010 03:01 AM
ncurses program gayatri Linux - Software 0 05-03-2004 09:07 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:14 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration