/*
 * POSIX.4 Timers example program
 *
 * Written by J. Vidal
 * Copyright (C) Dec, 2002 OCERA Consortium.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * published by the Free Software Foundation version 2.
 * 
 * This program shows how timers can be used for making periodic tasks.
 * To do this, it arms a periodic timer per task. Every time the timer 
 * expires the task is woken up.
 *
 */

#include <rtl.h>
#include <pthread.h>
#include <time.h>
#include <signal.h>

#define NTASKS 2
#define ONEMILISEC (long long)1000*1000
#define MY_CLOCK CLOCK_REALTIME
#define MY_SIGNAL RTL_SIGUSR1

pthread_t thread[NTASKS];
timer_t timer[NTASKS];
long long start_time=0;


void timer_intr(int sig){
    int param=sig-MY_SIGNAL;
        
    rtl_printf("\n\n Timer handler called for timer:%d\n",timer[param]->id);
    rtl_printf(" Timer period ns:%d\n",(unsigned int)timer[param]->expires.it_interval);
    
    pthread_wakeup_np(pthread_self());
}

void *start_routine(void *arg)
{
  struct sched_param p;
  struct itimerspec new_setting;
  struct sigaction sa;
  int signal=0, err=0, param=(unsigned) arg;
  long period;
  
  p . sched_priority =param;
  pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
  
  if (param!=(NTASKS-1))
      period=(long)1000*ONEMILISEC;
  else
      period=(long)500*ONEMILISEC;
  
  sa.sa_handler=timer_intr;
  
  if ((signal=MY_SIGNAL+param)> RTL_MAX_SIGNAL) signal=RTL_MAX_SIGNAL;

  if ((err=sigaction(signal,&sa,NULL))<0 ){
    rtl_printf("sigaction(MY_SIGNAL,&sa,NULL) FAILING, err:%d.\n",err);
    pthread_exit(NULL);
  }
  
  new_setting.it_interval.tv_sec=0;
  new_setting.it_interval.tv_nsec=period;
  timespec_normalize(&new_setting.it_interval);
  new_setting.it_value.tv_sec=0;
  new_setting.it_value.tv_nsec=start_time+period;
  timespec_normalize(&new_setting.it_value);
  
  err=timer_settime(timer[param],0,&new_setting,NULL);
  rtl_printf("timer_settime(timer[%d],0,&new_setting,&old_setting) returns %d\n",param,err);

  while(1) {
      pthread_suspend_np(pthread_self());
      rtl_printf(" thread %d woken up\n",param);
  }
    
  pthread_exit(NULL);
  return 0;
}

int init_module(void) {
  int i,ret;
  sigevent_t signal; 

  for (i=0;i<NTASKS;i++){    
    signal.sigev_notify=SIGEV_SIGNAL;
    if ((signal.sigev_signo=MY_SIGNAL+i)>=RTL_MAX_SIGNAL) 
      signal.sigev_signo=RTL_MAX_SIGNAL-1;
    ret=timer_create(MY_CLOCK,&signal,&(timer[i]));
    
    if (!ret) rtl_printf("Timer %d created succesfully\n",i);
    else {
      rtl_printf("Error creating timer %d. errno=%d\n",i,errno);
      return -1;
    }
  }  
  
  start_time=100*ONEMILISEC;

  // Threads creation.
  for (i=0;i<NTASKS;i++)
    pthread_create (&(thread[i]), NULL, start_routine,(void *) i); 
  
  return 0;
}

void cleanup_module(void) {
  int i;
  
  for (i=0;i<NTASKS;i++)
    timer_delete(timer[i]);
  
  for (i=0;i<NTASKS;i++)
    pthread_delete_np (thread[i]);
    
}










