/*************************************************************************
 * scheduler.c
 *
 * Time Table Scheduler: Zu einer gewünschten relativen Zeit eine Funktion aufrufen
 * und den entsprechenden Tabelleneintrag entfernen
 *
 * 22.10.2010 li
 * 27.05.2011 li maximale Wartezeit: 65535 time_ticks, bei 5,12 msec sind das ca. 330 Sekunden
 * 15.05.2012 li wahlweise long werte
 * 20.07.2012 li Trennung zwischen PID und Uebergabewert.
 * 20.07.2012 li PID nur wenn PROZESS_TRACE definiert
 * 03.08.2012 li Insert_TT_Entry: update wenn zielfunktion vorhanden
 */

#include <stdint.h>
#include "scheduler.h"

#ifdef TT_PROZESS
#include "prozess.h"
#endif

TIME_TABLE timetable[ TT_ENTRIES ];

S_SCHEDULE volatile schedule_s;   // Stuktur der flags / trace 

/*****************************************************************
 * Initialisierung
 */
void Scheduler_Init(void)
{
   unsigned char i;
   TIME_TABLE *tt = timetable;
#ifdef TT_COMPUTE_MAX
   schedule_s.timetable_max = 0; 
   schedule_s.timetable_cnt = 0;  
#endif  
   schedule_s.error = 0;
   
   for ( i=0; i < TT_ENTRIES; i++ )
   {
      tt->fp = NULL ;   // entry frei
      tt++;
   }
}


#ifdef TT_DELETE
/*****************************************************************
 * Timer Tabelle, del funktionsaufrufe
 */
void Delete_TT_Entry( _ptarget fp )
{
   unsigned char i;
   TIME_TABLE *tt = timetable;

   for (i = 0; i < TT_ENTRIES; i++)
   {
      if ( tt->fp == fp )          // funktion equ ?
      {
         tt->fp = NULL;            // Tabelleneintrag frei geben
#ifdef TT_COMPUTE_MAX         
         schedule_s.timetable_cnt--;
#endif         
      }
      tt++;
   }
}
#endif


/*****************************************************************
 * Timer Tabelle, Tabelleneintrag einfuegen
 */
#ifdef SCHED_LONG
#ifdef PROZESS_TRACE
unsigned char Insert_TT_Entry( unsigned long ms, _ptarget fp, unsigned char value, char pid)
#else
unsigned char Insert_TT_Entry( unsigned long ms, _ptarget fp, unsigned char value)
#endif
#else
#ifdef PROZESS_TRACE
unsigned char Insert_TT_Entry( unsigned int ms, _ptarget fp, unsigned char value, char pid)
#else
unsigned char Insert_TT_Entry( unsigned int ms, _ptarget fp, unsigned char value)
#endif
#endif
{
   unsigned char i;
   TIME_TABLE *tt = timetable;

#ifdef TT_UPDATE
   for (i = 0; i < TT_ENTRIES; i++)
   {
      if ( tt->fp == fp )         // funktion equ ?
      {
         tt->c_time = 0;          // start time
         tt->target_time = ms;    // ziel
         tt->value  = value;      // update value 
         return 1;
      } 
      tt++;
   }
   tt = timetable;                // nicht gefunden, restart
#endif   
   
   for ( i=0; i < TT_ENTRIES; i++ )
   {
      if ( tt->fp == NULL  )      // frei ??
      {
#ifdef TT_COMPUTE_MAX      
         schedule_s.timetable_cnt++;
         if ( schedule_s.timetable_max < schedule_s.timetable_cnt )
            schedule_s.timetable_max = schedule_s.timetable_cnt;
#endif
         tt->fp     = fp;
         tt->value  = value;
#ifdef PROZESS_TRACE
         tt->pid    = pid;
#endif
         tt->c_time = 0;          // start time
         tt->target_time = ms;    // ziel
         return 1;
      }
      tt++;
   }
   schedule_s.error++;           // Error count
   return 0;
}



/*****************************************************************
 * Wenn TargetTime erreicht, Funktion ausfuehren und vorher
 * Tabelleneintag freigeben bzw. in die Prozess queue eintragen
 */
void schedule( unsigned char tick )
{
   unsigned char i;
   TIME_TABLE *tt = timetable;
   _ptarget ptarget;

   for (i = 0; i < TT_ENTRIES; i++)
   {
      if ( tt->fp  )                  // eintrag vorhanden
      {
         tt->c_time += tick ;         // relative Zeit ++
         if ( tt->c_time >= tt->target_time )  // Zielzeitpunkt erreicht ?
         {
            ptarget = tt->fp;         // Funktion
            tt->fp  = NULL;           // Tabelleneintrag frei geben
#ifdef TT_COMPUTE_MAX            
            schedule_s.timetable_cnt--;
#endif            
#ifdef TT_PROZESS
#ifdef PROZESS_TRACE
            insert_prozess_sync( (_pziel)ptarget, tt->value, tt->pid );
#else
            insert_prozess_sync( (_pziel)ptarget, tt->value );
#endif
#else
            ptarget( tt->value );     // Funktion aufrufen
#endif
         }
      }
      tt++;
   }
}


