/* ---------------------------------------------------------------------
   (c) ED 1998-2002
   Projet       : CLIB
   Fonction     : Decodeur/Encodeur de trame S (format Motorola)
   Module       : S
   Fichier      : S.C
   Creation     : 28-12-1998
   Modification : 13-07-2002
   --------------------------------------------------------------------- */

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

   0.0 du 28-12-1998 Creation
   1.0 du 28-12-1998 Version operationelle
   .                 S1 (code 16 bits)
   .                 S3 (code 32 bits)
   1.1 du 18-04-2000 Ajoute encodeur 24-32 bits
   1.2 du 12-01-2001 Ajout de S_getadr24() et S_decodeS2
   1.3 du 29-02-2002 Mise au point longueur
   1.4 du 13-07-2002 LCLint
   .                 Ajout de S_line_size()
   1.5 du 18-07-2002 Suppression de S_line_size()

   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This source file is not C++ but C. Please use a C compiler.
#endif

#include "ed/inc/s.h"

#include "ed/inc/sysalloc.h"

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>

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

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

#define DBG 0

/* taille de l'adresse */
#define A1 2
#define A2 3
#define A3 4

/* offset de longueur */
#define N1 (1 + A1)
#define N2 (1 + A2)
#define N3 (1 + A3)

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

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

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

/* -----------------------------------------------------------------------
   create()
   -----------------------------------------------------------------------
   initalisation du bloc
   Liberer le bloc apres usage avec S_free()
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   ----------------------------------------------------------------------- */
static s_t *create (eS_TYP typ)
{
   s_t *ps = malloc (sizeof *ps);

   if (ps)
   {
      CLR (ps, s_t);
      ps->typ = typ;
   }
   return ps;
}

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

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

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

/* -----------------------------------------------------------------------
   S_getlen()
   -----------------------------------------------------------------------
   retourne la longueur de la trame
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   S : longueur de la trame (en octets)
   ----------------------------------------------------------------------- */
uchar S_getlen (const char *const sline)
{
   char s[3];

   /* Constituer la chaine */
   s[0] = sline[2];
   s[1] = sline[3];
   s[2] = 0;

   /* Conversion Hexa -> binaire */
   return (uchar) strtoul (s, NULL, 16);
}

/* -----------------------------------------------------------------------
   Procedure S_getadr16
   -----------------------------------------------------------------------
   retourne sline'adresse de la trame
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   S : adresse de la trame (16 bits)
   ----------------------------------------------------------------------- */
ushort S_getadr16 (const char *const sline)
{
   char s[5];

   /* Constituer la chaine */
   s[0] = sline[4];
   s[1] = sline[5];
   s[2] = sline[6];
   s[3] = sline[7];
   s[4] = 0;

   /* Convertir la chaine Hexa -> binaire */
   return (ushort) strtoul (s, NULL, 16);
}

/* -----------------------------------------------------------------------
   Procedure S_getadr24
   -----------------------------------------------------------------------
   retourne sline'adresse de la trame
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   S : adresse de la trame (24 bits)
   ----------------------------------------------------------------------- */
ulong S_getadr24 (const char *const sline)
{
   ulong adr;
   char s[7];

   /* Constituer la chaine */
   s[0] = sline[4];
   s[1] = sline[5];
   s[2] = sline[6];
   s[3] = sline[7];
   s[4] = sline[8];
   s[5] = sline[9];
   s[6] = 0;

   /* Convertir la chaine Hexa -> binaire */
   adr = strtoul (s, NULL, 16);

   return adr;
}

/* -----------------------------------------------------------------------
   Procedure S_getadr32
   -----------------------------------------------------------------------
   retourne sline'adresse de la trame
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   S : adresse de la trame (32 bits)
   ----------------------------------------------------------------------- */
ulong S_getadr32 (const char *const sline)
{
   char s[9];

   /* Constituer la chaine */
   s[0] = sline[4];
   s[1] = sline[5];
   s[2] = sline[6];
   s[3] = sline[7];
   s[4] = sline[8];
   s[5] = sline[9];
   s[6] = sline[10];
   s[7] = sline[11];
   s[8] = 0;

   /* Convertir la chaine Hexa -> binaire */
   return strtoul (s, NULL, 16);
}

/* -----------------------------------------------------------------------
   getdat()
   -----------------------------------------------------------------------
   Lire un octet dans une trameS1 a un index donnee
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : index de lecture
   S : donnee (8 bits)
   ----------------------------------------------------------------------- */
static int getdat (const char *sline, size_t const Ndx)
{
   char s[3];

   /* Constituer la chaine */
   s[0] = sline[Ndx];
   s[1] = sline[Ndx + 1];
   s[2] = 0;

   /* Convertir la chaine Hexa -> binaire */
   return (int) strtoul (s, NULL, 16);
}

/* -----------------------------------------------------------------------
   S_getdatS1()
   -----------------------------------------------------------------------
   Lire un octet dans une trameS1 a un index donnee
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : index de lecture
   S : donnee (8 bits)
   ----------------------------------------------------------------------- */
int S_getdatS1 (const char *const sline, size_t const i)
{
   /* Calculer l'index reel */
   size_t const Ndx = 2 * (i + 1 + 1 + A1);
   int n = getdat (sline, Ndx);

   return n;
}

/* -----------------------------------------------------------------------
   S_getdatS2()
   -----------------------------------------------------------------------
   Lire un octet dans une trame a un index donnee
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : index de lecture
   S : donnee (8 bits)
   ----------------------------------------------------------------------- */
int S_getdatS2 (char const *const sline, size_t const i)
{
   size_t const Ndx = 2 * (i + 1 + 1 + A2);
   int n = getdat (sline, Ndx);

   return n;
}

/* -----------------------------------------------------------------------
   S_getdatS3()
   -----------------------------------------------------------------------
   Lire un octet dans une trame a un index donnee
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : index de lecture
   S : donnee (8 bits)
   ----------------------------------------------------------------------- */
int S_getdatS3 (char const *const sline, size_t const i)
{
   size_t const Ndx = 2 * (i + 1 + 1 + A3);
   int n = getdat (sline, Ndx);

   return n;
}

/* -----------------------------------------------------------------------
   S_loaddatS1()
   -----------------------------------------------------------------------
   Lire une trame de donnees S1
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : tableau d'octets
   E : nombre d'octets
   S : 0
   ----------------------------------------------------------------------- */
int S_loaddatS1 (char const *const sline, uchar * const abuf, size_t const len)
{
   size_t i;

   for (i = 0; i < len; i++)
   {
      int dat = S_getdatS1 (sline, i);
      abuf[i] = (uchar) dat;
   }
   return 0;
}

/* -----------------------------------------------------------------------
   S_loaddatS2()
   -----------------------------------------------------------------------
   Lire une trame de donnees S2
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : tableau d'octets
   E : nombre d'octets
   S : 0
   ----------------------------------------------------------------------- */
int S_loaddatS2 (char const *const sline, uchar * const abuf, size_t const len)
{
   size_t i;

   for (i = 0; i < len; i++)
   {
      int dat = S_getdatS2 (sline, i);
      abuf[i] = (uchar) dat;
   }
   return 0;
}

/* -----------------------------------------------------------------------
   S_loaddatS3()
   -----------------------------------------------------------------------
   Lire une trame de donnees S2
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   E : tableau d'octets
   E : nombre d'octets
   S : 0
   ----------------------------------------------------------------------- */
int S_loaddatS3 (char const *const sline, uchar * const abuf, size_t const len)
{
   size_t i;

   for (i = 0; i < len; i++)
   {
      int dat = S_getdatS3 (sline, i);
      abuf[i] = (uchar) dat;
   }
   return 0;
}

/* -----------------------------------------------------------------------
   S_decodeS1()
   -----------------------------------------------------------------------
   Decodage d'une trame S1 (adresse 16 bits)
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   ----------------------------------------------------------------------- */
s_t *S_decodeS1 (const char *const sline)
{
   s_t *ps = create (S_DATA16);

   if (ps)
   {
      size_t const len = S_getlen (sline) - N1;
      uchar *ao = calloc (1, len);

      if (ao)
      {
         ushort adr = S_getadr16 (sline);
#if DBG
         printf ("adr=$%0*lX ", A1 * 2, (ulong) adr);
         printf ("len=%lu", (ulong) len);
         printf ("\n");
#endif

         S_loaddatS1 (sline, ao, len);
#if DBG
         SYS_dump (ao, len);
#endif
         ps->adr = adr;
         BUF_init (&ps->buf, ao, len, MEM_DYN);
      }
      else
      {
         S_free (ps);
      }
   }
   return ps;
}

/* -----------------------------------------------------------------------
   S_decodeS2()
   -----------------------------------------------------------------------
   Decodage d'une trame S2 (adresse 24 bits)
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   ----------------------------------------------------------------------- */
s_t *S_decodeS2 (const char *const sline)
{
   s_t *ps = create (S_DATA24);

   if (ps)
   {
      /* longueur reelle des donnes  */
      size_t const len = S_getlen (sline) - N2;
      uchar *ao = calloc (1, len);

      if (ao)
      {
         ulong adr = S_getadr24 (sline);

#if DBG
         printf ("adr=$%0*lX ", A2 * 2, (ulong) adr);
         printf ("len=%lu", (ulong) len);
         printf ("\n");
#endif
         S_loaddatS2 (sline, ao, len);

#if DBG
         SYS_dump (ao, len);    /* -> stdout */
#endif

         ps->adr = adr;
         BUF_init (&ps->buf, ao, len, MEM_DYN);

      }
      else
      {
         S_free (ps);
      }
   }
   return ps;
}

/* -----------------------------------------------------------------------
   S_decodeS3()
   -----------------------------------------------------------------------
   Decodage d'une trame S3 (adresse 32 bits)
   Liberer le bloc apres usage avec S_free()
   -----------------------------------------------------------------------
   E : pointeur sur la chaine contenant la trame
   ----------------------------------------------------------------------- */
s_t *S_decodeS3 (const char *const sline)
{
   s_t *ps = create (S_DATA32);

   if (ps)
   {
      size_t len = S_getlen (sline) - N3;
      uchar *ao = calloc (1, len);

      if (ao)
      {
         ulong adr = S_getadr32 (sline);

#if DBG
         printf ("adr=$%0*lX ", A3 * 2, (ulong) adr);
         printf ("len=%lu", (ulong) len);
         printf ("\n");
#endif
         S_loaddatS3 (sline, ao, len);
#if DBG
         SYS_dump (ao, len);    /* -> stdout */
#endif
         ps->adr = adr;
         BUF_init (&ps->buf, ao, len, MEM_DYN);
      }
      else
      {
         S_free (ps);
      }
   }
   return ps;
}

/* ---------------------------------------------------------------------
   S_decode()
   ---------------------------------------------------------------------
   Role : Decoder une ligne s
   ---------------------------------------------------------------------
   E :
   S :
   --------------------------------------------------------------------- */
s_t *S_decode (const char *const sline)
{
   s_t *ps = NULL;
   int cr = 0;

#if DBG
   printf ("%s", sline);
#endif

   switch (sline[0])            /* 1er car */
   {
   case 'S':                   /* Trame S */
      {
         cr = 1;
         switch (sline[1])      /* 2eme car */
         {
         case '0':             /* S0 */
            break;

         case '1':             /* S1  data avec adresse 16-bit */
            ps = S_decodeS1 (sline);
            break;

         case '2':             /* S2 data avec adresse 24-bit */
            ps = S_decodeS2 (sline);
            break;

         case '3':             /* S3 data avec adresse 32-bit */
            ps = S_decodeS3 (sline);
            break;

         case '4':             /* S4 */
            break;

         case '5':             /* S5 count record */
            break;

         default:
            cr = 0;
         }

         break;

   case '/':                   /* On accepte des commentaires... */
         cr = 1;
         break;

   default:                    /* Mais pas les lignes vides !!! */
         cr = 0;
      }

   }

   if (ps)
   {
      ps->cr = cr;
   }
   return ps;
}

/* -----------------------------------------------------------------------
   S_free()
   -----------------------------------------------------------------------
   Liberer le bloc
   -----------------------------------------------------------------------
   E : bloc
   ----------------------------------------------------------------------- */
void S_free (s_t * const ps)
{
   if (ps)
   {
      BUF_end (&ps->buf);
      free (ps);
   }
}

/* ---------------------------------------------------------------------
   S_rec()
   ---------------------------------------------------------------------
   Role : Creer un S-record()
   ---------------------------------------------------------------------
   E : Flux sortant
   E : type
   E : adresse
   E : debut des donnees (tableau d'octets)
   E : longueur des donnees (en octet)
   S :
   --------------------------------------------------------------------- */
void S_rec (FILE * const fp
            ,eS_TYP const type
            ,ulong const adr
            ,uchar * const a
            ,size_t const len
)
{
   if (fp)
   {
      int cs = 0;

      static const char *const aszType[] =
      {
#define ITEM(a,b) #b,
#include "ed/inc/srecord.itm"
#undef ITEM
      };

      cs = 0;

      fprintf (fp, "%s", aszType[type]);

      {
         uint i;

         switch (type)
         {
         case S_HEADER:
#define L (1+2)
            /* longueur */
            {
               size_t const l = strlen ("HDR");

               fprintf (fp, "%02X", (uint) l + L);
               cs += l + L;
            }
            /* adresse 0 sur 16 bits */
            fprintf (fp, "0000");
#undef L
            break;

         case S_DATA16:
         case S_END16:
#define L (1+2)

            /* longueur */
            fprintf (fp, "%02X", (uint) len + L);
            cs += len + L;

#undef L

            /* adresse sur 16 bits */
            i = (uint) (adr >> 8) & 0xFF;  /* Intel : MSB */
            fprintf (fp, "%02X", i);
            cs += i;

            i = (uint) (adr >> 0) & 0xFF;  /* Intel : LSB */
            fprintf (fp, "%02X", i);
            cs += i;

            break;

         case S_DATA24:
         case S_END24:
#define L (1+3)

            /* longueur */
            fprintf (fp, "%02X", (uint) len + L);
            cs += len + L;

#undef L
            /* adresse sur 24 bits */
            i = (uint) (adr >> 16) & 0xFF;  /* MSB */
            fprintf (fp, "%02X", i);
            cs += i;

            i = (uint) (adr >> 8) & 0xFF;
            fprintf (fp, "%02X", i);
            cs += i;

            i = (uint) (adr >> 0) & 0xFF;  /* LSB */
            fprintf (fp, "%02X", i);
            cs += i;

            break;

         case S_DATA32:
         case S_END32:
#define L (1+4)

            /* longueur */
            fprintf (fp, "%02X", (uint) len + L);
            cs += len + L;

#undef L

            /* adresse sur 32 bits */
            i = (uint) (adr >> 24) & 0xFF;  /* MSB */
            fprintf (fp, "%02X", (uint) i);
            cs += i;

            i = (uint) (adr >> 16) & 0xFF;
            fprintf (fp, "%02X", (uint) i);
            cs += i;

            i = (uint) (adr >> 8) & 0xFF;
            fprintf (fp, "%02X", (uint) i);
            cs += i;

            i = (uint) (adr >> 0) & 0xFF;  /* LSB */
            fprintf (fp, "%02X", (uint) i);
            cs += i;

            break;
         default:
            assert (0);

         }
      }

      /* data */
      {
         size_t i;
         for (i = 0; i < len; i++)
         {
            fprintf (fp, "%02X", (uint) a[i]);
            cs += a[i];
         }
      }

      fprintf (fp, "%02X\n", (uint) ((255 - cs) & 0xFF));
   }
}

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