#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

#include <rtdk.h>
#include <native/task.h>
#include <native/timer.h>


static RTIME periode;
static int nb_mesures = 0; // Nombre de mesures entre deux affichages

void fonction_periodique (void * unused)
{
	RTIME precedent = 0; 
	RTIME heure = 0;
	RTIME duree;
	
	int mesure = 0;
	long long int min = -1;
	long long int max = 0;
	long long int max_max = 0;
	double sum = 0.0;
	
	periode = periode * 1000; // en ns
	rt_task_set_periodic(NULL, TM_NOW, periode);
	while(1) {
		rt_task_wait_period(NULL);
		heure = rt_timer_read();
		if (mesure != 0) { 
			duree = heure - precedent;
			duree = duree / 1000; // en microsecondes
			if ((min == -1) || (duree < min))
				min = duree;
			if (duree > max) {
				max = duree;
				if (max_max < max)
					max_max = max;
			}
			sum += duree;
		}
		precedent = heure;
		mesure ++;
		if (mesure >= nb_mesures) {
			rt_fprintf(stdout, "[%ld] Min.= %lld, Moy.= %.1lf, Max.= %lld,  Max.Max.= %lld\n",
				(long int)(heure/1000000000), min, sum / nb_mesures, max, max_max);
			min = -1;
			max = 0;
			sum = 0.0;
			mesure = 0;
			rt_print_flush_buffers();
		}
	}
}



int main (int argc, char * argv[])
{
	int cpu = 0;
	RT_TASK task;
	int err;

	mlockall(MCL_CURRENT|MCL_FUTURE);
	rt_print_auto_init(1);

	if ((argc < 2)
	 || (sscanf(argv[1], "%lld", & periode) != 1)
	 || ((argc == 3) && (sscanf(argv[2], "%d", & cpu) != 1))) {
		fprintf(stderr, "usage: %s periode_us [cpu]\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	if ((periode <= 0) || (periode > 2000000)) {
		fprintf(stderr, "%s: La periode doit etre dans [1, 2000000]\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	if ((cpu < 0) || (cpu >= sysconf(_SC_NPROCESSORS_ONLN))) {
		fprintf(stderr, "%s: Le CPU doit etre dans [0, %ld]\n", argv[0], sysconf(_SC_NPROCESSORS_ONLN) - 1);
		exit(EXIT_FAILURE);
	}

	setvbuf(stdout, NULL, _IONBF, 0);
	
	nb_mesures = 5000000 / periode;
	if (nb_mesures == 0) {
		fprintf(stderr, "periode trop longue\n");
		exit(EXIT_FAILURE);
	}
	
	if ((err = rt_task_spawn(& task, "Fluctuation-RT-TIMER", 0, 99, T_JOINABLE | T_CPU(cpu),
	                         fonction_periodique, NULL)) != 0) {
		fprintf(stderr, "rt_task_spawn: %s\n", strerror(-err));
		exit(EXIT_FAILURE);
	}
	
	rt_task_join(& task);
	return EXIT_SUCCESS;
}


