/* ---------------------------------------------------------------------
   (c) ED 2002
   Project      : G.704 simulator
   Function     : Multiframe manager
   Module       : MF
   File         : MF.C
   Created      : 24-12-2002
   Modified     : 24-12-2002
   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This source file is not C++ but rather C. Please use a C-compiler
#endif

/* ---------------------------------------------------------------------
   Log

   0.0 24-12-2002 Creation

   Extraits significatifs de UIT-T G.732

   <...>
   5.2 Perte et reprise du verrouillage de multitrame en cas de signalisation
   voie par voie

   Le verrouillage de multitrame doit etre considere comme perdu quand
   deux signaux de verrouillage de multitrame consecutifs sont recus avec
   erreur.
   Le verrouillage de multitrame doit etre considere comme repris des la
   detection du premier signal de verrouillage de multitrame juste.

   Remarque . Outre la procedure decrite ci-dessus, on peut appliquer la
   procedure suivante pour eviter un verrouillage de multitrame
   errone:

   * le verrouillage de multitrame doit aussi etre considere comme perdu
   lorsque tous les bits dans l'intervalle de temps de voie 16 sont a
   l'etat 0 pendant une duree correspondant a une ou deux multitrames;

   * le verrouillage de multitrame ne sera considere comme repris qu'a la
   suite de la detection d'au moins un bit a l'etat 1 dans l'intervalle
   de temps de voie 16 qui precede le premier signal de verrouillage de
   multitrame detecte.

   5.3 Défaillances et dispositions correspondantes en cas de signalisation
   voie par voie

   5.3.1 Défaillances
   L'équipement de multiplexage de signalisation doit détecter les
   défaillances suivantes:

   <...>
   5.3.1.3 Perte du verrouillage de multitrame.

   5.3.1.4 Réception de l'indication d'alarme de l'équipement multiplex de
   signalisation distant (voir le § 5.3.2.3).
   <...>

   5.3.2 Dispositions correspondantes

   A la suite de la détection d'une défaillance, des mesures adéquates
   doivent être prises comme spécifié dans le tableau 2/G.732.
   Les dispositions correspondantes sont reprises ci-après.

   <...>

   5.3.2.3 Emission d'une indication d'alarme vers l'équipement de
   multiplexage de signalisation distant, obtenue en faisant passer de
   l'état 0 à l'état 1 le bit 6 de l'intervalle de temps de voie 16
   de la trame 0 de la multitrame (voir le tableau 7/G.704);
   ce changement doit avoir lieu dès que possible.

   --------------------------------------------------------------------- */

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

/* public data ========================================================= */
/* macros ============================================================== */

#define REPOS 0xDD
#define DERANGEMENT 0xFF

/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private data ======================================================== */
/* private functions =================================================== */
/* internal public data ================================================ */
/* internal public functions =========================================== */
/* entry points ======================================================== */

/* ---------------------------------------------------------------------
   mf_init()
   ---------------------------------------------------------------------
   Initialisation de l'objet MF
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
void mf_init (mf_s * const this)
{
   if (this)
   {
      this->sts = MF_STS_CHASE;
      this->rmai = 0;
      this->write = 0;
      this->read = 0;
      this->count_zero = 0;
      this->count_err = 0;
      this->was_zero = 0;

      {
         size_t i;
         for (i = 0; i < NELEM (this->sig); i++)
         {
            this->sig[i] = REPOS;
         }
      }
   }
}

/* ---------------------------------------------------------------------
   mf_in()
   ---------------------------------------------------------------------
   Traitement d'un octet IT16
   - acquisition/perte VMT selon G.732
   - enregistrement des donnees dans un buffer tournant de 16 trames
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
void mf_in (mf_s * const this, uchar const data)
{
   if (this)
   {
      switch (this->sts)
      {
      case MF_STS_CHASE:

         if ((data & 0xF0) == 0 && !this->was_zero)
         {
            this->frame = 0;
            this->sts = MF_STS_LOCKED;
         }

         this->was_zero = data == 0x00;

         break;

      case MF_STS_LOCKED:

         this->was_zero = data == 0x00;

         if (this->was_zero)
         {
            if (this->count_zero < 16)
            {
               this->count_zero++;
            }
            else
            {
               this->sts = MF_STS_CHASE;
               break;           /* quitter sauvagement la branche */
            }
         }
         else
         {
            this->count_zero = 0;
         }

         /* verification du mot de verrouillage de MT
          * Accepte 1 erreur max. A la deuxieme, resynchro.
          */
         this->frame++;
         if (this->frame == 16)
         {
            this->frame = 0;
            if ((data & 0xF0) == 0)
            {
               this->count_err = 0;
               /* enregistrement de la position du FSW */
               this->imfsw = this->write;
            }
            else
            {
               this->count_err++;
               if (this->count_err == 2)
               {
                  this->sts = MF_STS_CHASE;
                  /* quitter sauvagement la branche et se remettre en chasse */
                  break;
               }
            }
         }

         /* enregistrer les donnees recues dans le buffer */
         this->sig[this->write] = data;

         /* mise a jour de l'index d'ecriture */
         this->write++;
         if (this->write == NELEM (this->sig))
         {
            this->write = 0;
         }
         break;

      default:
         ASSERT (0);
      }
   }
}

/* ---------------------------------------------------------------------
   mf_out()
   ---------------------------------------------------------------------
   Lecture synchrone des donnees (ou FF en derangement)
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
uchar mf_out (mf_s * const this, int const out_sync)
{
   uchar data = DERANGEMENT;

   if (this)
   {
      if (this->sts == MF_STS_LOCKED)
      {
         if (out_sync)
         {
            this->read = this->imfsw;
         }

         data = this->sig[this->read];

         /* mise a jour de l'index de lecture */
         this->read++;
         if (this->read == NELEM (this->sig))
         {
            this->read = 0;
         }
      }
   }
   return data;
}

/* ---------------------------------------------------------------------
   mf_mfai()
   ---------------------------------------------------------------------
   Retourne l'etat PVMT (MFAI)
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int mf_mfai (mf_s const *const this)
{
   int mfai = -1;
   if (this)
   {
      mfai = this->sts != MF_STS_LOCKED;
   }
   return mfai;
}

/* ---------------------------------------------------------------------
   mf_rmai()
   ---------------------------------------------------------------------
   Retourne l'etat IADM (RMAI)
   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int mf_rmai (mf_s const *const this)
{
   int rmai = -1;
   if (this)
   {
      rmai = this->rmai;
   }
   return rmai;
}
