/* ---------------------------------------------------------------------
   (c) ED 1998-2002
   Projet       : CLIB
   Fonction     : Gestionnaire de timer par polling regulier (sans IT)
   Module       : TIM
   Fichier      : TIM.C
   Creation     : 27-05-1998
   Modification : 19-07-2002
   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This source file is not C++ but C. Please use a C compiler.
#endif

/* ---------------------------------------------------------------------
   Journal

   0.0 du 27-05-1998 Creation
   1.0 du 27-05-1998 Version operationelle
   1.1 du 14-10-1998 Portage CLIB
   1.2 du 16-01-2001 Mise aux normes pour utilisation professionelle
   1.3 du 13-07-2002 LCLint (nettoyage)
   1.4 du 19-07-2002 suppression sys_*()

   --------------------------------------------------------------------- */
#include <stdlib.h>
#include <string.h>

#include "ed/inc/tim.h"
#include "ed/inc/sys.h"

#include "ed/inc/sysalloc.h"

#define TIM_DBG 0
#if TIM_DBG
#include "dprintf.h"
#endif

/* ---------------------------------------------------------------------
   Donnees publiques
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Constantes privees
   --------------------------------------------------------------------- */
#define MODULE "TIM"
#define VER "1.4"
#define ID "TIM Module \"C\" (c) ED 1998-2002"

/* ---------------------------------------------------------------------
   Structures privees
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Donnees privees
   --------------------------------------------------------------------- */

/* =====================================================================
   Fonctions privees
   ===================================================================== */

/* ---------------------------------------------------------------------
   start()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
static void start (sTIM * pPrivate, ulong duree)
{
   STACK_CHK ();
   ASSERT (pPrivate != NULL);
   if (duree)
   {
      /* Pour la division qui suit... */
      if (pPrivate->tic != 0)
      {
         /* Memoriser pour restart */
         pPrivate->cpt0 = (ulong) (duree / pPrivate->tic);
         /* Charger le compteur en nombre de tics */
         pPrivate->cpt = pPrivate->cpt0;
         pPrivate->DataCb.info = TIM_START;
#if TIM_DBG
         dprintf (MODULE, "start(%lu ms) '%s'"
                  ,(ulong) duree
                  ,pPrivate->DataCb.szTag);
#endif
      }
      else
      {
         pPrivate->DataCb.info = TIM_STOP;
      }
   }
   else
   {
      pPrivate->DataCb.info = TIM_STOP;
   }

   pPrivate->DataCb.duree = (ulong) (pPrivate->cpt * pPrivate->tic);  /* en ms */

   if (pPrivate->pfAction)
   {
      /* LCLint */
      (*pPrivate->pfAction) (&pPrivate->DataCb);
   }
}

/* ---------------------------------------------------------------------
   restart()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
static void restart (sTIM * pPrivate)
{
   STACK_CHK ();
   ASSERT (pPrivate != NULL);
   if (pPrivate->cpt0)
   {
      if (pPrivate->cpt)
      {
         /* Relance d'un timer non echu */
         pPrivate->DataCb.info = TIM_RESTART;
      }
      else
      {
         /* Relance d'un timer echu */
         pPrivate->DataCb.info = TIM_START;
      }
      /* Recharger le compteur en nombre de tics */
      pPrivate->cpt = pPrivate->cpt0;
   }
   else
   {
      /* Le timer n'a pas demarre (compteur nul!) */
      pPrivate->DataCb.info = TIM_STOP;
   }

   pPrivate->DataCb.duree = (ulong) (pPrivate->cpt * pPrivate->tic);  /* en ms */
#if TIM_DBG
   dprintf (MODULE, "restart() %lu ms '%s'"
            ,(ulong) pPrivate->DataCb.duree
            ,pPrivate->DataCb.szTag
      );
#endif

   if (pPrivate->pfAction)
   {
      /* LCLint */
      (*pPrivate->pfAction) (&pPrivate->DataCb);
   }
}

/* ---------------------------------------------------------------------
   stop()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
static void stop (sTIM * pPrivate)
{
   STACK_CHK ();
   ASSERT (pPrivate != NULL);
   pPrivate->cpt = 0;           /* Vider le compteur */

#if TIM_DBG
   dprintf (MODULE, "stop() '%s'", pPrivate->DataCb.szTag);
#endif
   pPrivate->DataCb.info = TIM_STOP;

   if (pPrivate->pfAction)
   {
      /* LCLint */
      (*pPrivate->pfAction) (&pPrivate->DataCb);
   }
}

/* ---------------------------------------------------------------------
   poll()
   ---------------------------------------------------------------------
   Role :
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
static ulong poll (sTIM * pPrivate)
{
   STACK_CHK ();
   ASSERT (pPrivate != NULL);

   if (pPrivate->cpt)
   {
      pPrivate->cpt--;
      if (!pPrivate->cpt)
      {
         if (pPrivate->pfAction)
         {
            pPrivate->DataCb.info = TIM_TIMEOUT;
            /* LCLint */
            (*pPrivate->pfAction) (&pPrivate->DataCb);
         }
      }
   }
   return pPrivate->cpt;
}

/* =====================================================================
   Fonctions publiques
   ===================================================================== */

/* ---------------------------------------------------------------------
   TIM_sver()
   ---------------------------------------------------------------------
   Role : Retourne une chaine "Version"
   ---------------------------------------------------------------------
   E :
   S : Pointeur de chaine ASCIIZ
   --------------------------------------------------------------------- */
const char *TIM_sver (void)
{
   STACK_CHK ();
   return VER;
}

/* ---------------------------------------------------------------------
   TIM_sid()
   ---------------------------------------------------------------------
   Role : Retourne une chaine "Identification"
   ---------------------------------------------------------------------
   E :
   S : Pointeur de chaine ASCIIZ
   --------------------------------------------------------------------- */
const char *TIM_sid (void)
{
   STACK_CHK ();
   return ID;
}

/* ---------------------------------------------------------------------
   TIM_init()
   ---------------------------------------------------------------------
   Role : Creation/Initialisation
   ---------------------------------------------------------------------
   E : Pointeur de donnees. Si NULL, allocation statique par l'utilisateur
   E : Duree d'un tic en ms
   E : fonction de sortie
   E : contexte utilisateur
   E : identificateur
   S : Pointeur de donnees
   --------------------------------------------------------------------- */
sTIM *TIM_init (sTIM * pTim
                ,ulong tic
                ,fTIM_ACTION * pfAction
                ,void *pUser
                ,char const *szTag)
{
   STACK_CHK ();
   /* TIC nul interdit !!! */
   if (tic != 0)
   {
      uint dyn;

      if (pTim == NULL)
      {
         pTim = malloc (sizeof *pTim);
         dyn = 1;
      }
      else
      {
         dyn = 0;
      }

      if (pTim)
      {
         SYS_CLR (pTim, sTIM);

         pTim->dyn = dyn;

         pTim->tic = tic;
         /* Peut etre NULL (pas d'action) */
         pTim->pfAction = pfAction;

         if (pTim->pfAction)
         {
            pTim->DataCb.szTag = szTag;
            /* Contexte utilisateur */
            pTim->DataCb.pUser = pUser;
         }
      }
   }
   return pTim;
}

/* ---------------------------------------------------------------------
   TIM_end()
   ---------------------------------------------------------------------
   Role : Suppression
   ---------------------------------------------------------------------
   E : Pointeur de donnees
   S :
   --------------------------------------------------------------------- */
void TIM_end (sTIM * pTim)
{
   STACK_CHK ();
   if (pTim != NULL)
   {
      if (pTim->dyn)
      {
         free (pTim);
      }
   }
}

/* ---------------------------------------------------------------------
   TIM_poll()
   ---------------------------------------------------------------------
   Polling regulier d'un timer au rythme declare dans l'init
   (parametre tic)
   ---------------------------------------------------------------------
   E : Pointeur de donnees
   S :
   --------------------------------------------------------------------- */
ulong TIM_poll (sTIM * pTim)
{
   ulong cpt = (ulong) - 1;
   STACK_CHK ();

   if (pTim != NULL)
   {
      cpt = poll (pTim);
   }
   /* pour debug... */
   return cpt;
}

/* ---------------------------------------------------------------------
   TIM_start()
   ---------------------------------------------------------------------
   Demarrage d'un timer pour la duree specifiee
   ---------------------------------------------------------------------
   E : Pointeur de donnees
   E : Duree en ms (0-0xFFFF)
   NOTA : 0 est equivallent a TIM_stop()
   S :
   --------------------------------------------------------------------- */
void TIM_start (sTIM * pTim, ulong duree)
{
   STACK_CHK ();
   if (pTim != NULL)
   {
      start (pTim, duree);
   }
}

/* ---------------------------------------------------------------------
   TIM_restart()
   ---------------------------------------------------------------------
   Redemarrage d'un timer pour la duree specifiee par TIM_start()
   NOTA par defaut, la valeur est 0, donc equivallente a un TIM_stop()
   ---------------------------------------------------------------------
   E : Pointeur de donnees
   S :
   --------------------------------------------------------------------- */
void TIM_restart (sTIM * pTim)
{
   STACK_CHK ();
   if (pTim != NULL)
   {
      restart (pTim);
   }
}

/* ---------------------------------------------------------------------
   TIM_stop()
   ---------------------------------------------------------------------
   Arret d'un timer. Si celui-ci etait deja arrete, pas d'erreur
   ---------------------------------------------------------------------
   E : Pointeur de donnees
   S :
   --------------------------------------------------------------------- */
void TIM_stop (sTIM * pTim)
{
   STACK_CHK ();
   if (pTim != NULL)
   {
      stop (pTim);
   }
}

/* File generated by 'NEW.EXE' Ver 1.10 (c) ED 1998 */
