Milan Stephan
Fotografie & IT

Zurück zur SPiC Übersicht

stoppuhr.c

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>


static volatile uint8_t sigint_event;
static volatile uint8_t sigalarm_event;
static volatile uint16_t milliseconds;

static void sigint_handler(int signum) {
	sigint_event = 1;
}

static void sigalarm_handler(int signum) {
	milliseconds++;
	if (milliseconds == 1000) {
		milliseconds = 0;
		sigalarm_event = 1;
	}
}

static void set_timer(uint32_t microseconds) {

	struct itimerval tv = {

		// Regelmäßig
		.it_interval = {
			.tv_sec = 0,
			.tv_usec = microseconds
		},

		// Oneshot, Zeit bis zum nächsten Timer
		.it_value = {
			.tv_sec = 0,
			.tv_usec = microseconds
		}
	};

	setitimer(ITIMER_REAL, &tv, NULL);
}

int main(void) {

	sigset_t sync;
	sigemptyset(&sync);
	sigaddset(&sync, SIGINT);
	sigaddset(&sync, SIGALRM);

	sigset_t oldmask;




	struct sigaction sa = {
		.sa_handler = &sigint_handler,
		.sa_flags = SA_RESTART,
	};
	sigemptyset(&sa.sa_mask);
	sigaction(SIGINT, &sa, NULL);

	// sa kann für SIGALRM wiederverwendet werden,
	// nachdem die Behandlung für SIGINT gesetzt wurde.
	sa.sa_handler = &sigalarm_handler;
	sigaction(SIGALRM, &sa, NULL);




	// Weil sonst undefiniert!
	sigprocmask(SIG_UNBLOCK, &sync, NULL);

	printf("SIGINT (Ctrl+C) für Start/Stop\n");

	uint8_t running = 0;
	int seconds = 0;

	while(1) {

		// Signale bei Zugriffen auf die Events blockieren
		sigprocmask(SIG_BLOCK, &sync, &oldmask);
		while (!sigint_event && !sigalarm_event) {
			sigsuspend(&oldmask);
		}
		sigprocmask(SIG_SETMASK, &oldmask, NULL);

		if (sigint_event) {
			sigint_event = 0;

			if (running == 0) {
				set_timer(1000); // 1ms = 1000us
				running = 1;
				printf("Timer läuft!\n");
			} else {
				set_timer(0);
				printf("Vergangene Zeit: %d sec, %d ms\n", seconds, milliseconds);

				// Timer zurücksetzen für einen neuen Durchlauf
				running = 0;
				seconds = 0;
				milliseconds = 0;

				// Alternativ: Stoppuhr mit break beenden
				// break;
			}
		}

		if (sigalarm_event) {
			sigalarm_event = 0;
			seconds++;
			printf("%d sec\n", seconds);
		}

	}

	return EXIT_SUCCESS;
}