/***************************************************************************
                          download.c     -  description
                             -------------------

    begin                : Thu Jul  12 MET 2001

    copyright            : (C) 1999-2001 by Thomas Marquardt, Steffen Hildebrandt

    email                : th.marquardt@t-online.de
                           Steffen.Hildebrandt@web.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <math.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <ctype.h>

#include "gesko.h"


#define DATA_BLOCK          0x100
#define HEADER_DATA_BLOCK   0x109
#define FIRMWARE            1792          /* Anzahl der Firmwarebloecke */
#define MAX_MEMORY          2048          /* max. Anzahl der Speicherbloecke */

#define PERCENT_FACTOR      0.055805
#define BAR_LEN             40


/* globale Variablen */
static time_t	start_zeit;
static time_t	stop_zeit;
static time_t	lauf_zeit;

extern int PBXHandle;
extern int timeout;
extern int timer;
extern int fw_dld;
extern int fw_ger_aus_ow;


/*****************************************************************************/
/* Funktion zum Download der Firmware                                        */
/* ----------------------------------------------------------------------    */
/* In:	baudrate : Baudrate, datei : Zeiger auf Bin-File (Firmware)          */
/* ---------------------------------------------------                       */
/* Out:                                                                      */
/* ----------------------------------------------------                      */
/* Autor: Steffen Hildebrandt                                                */
/* letzte Aenderung: Steffen Hildebrandt, 22.01.2003                         */
/*****************************************************************************/
int GTFirmwareDownload ( int baudrate, unsigned char *datei )
{
  char zeichen;
  int i, k;
  short j = 0;
  short percent = 0;
  int block = 1;
  long last_adress = PROG_ADRESS;
  long first_adress = PROG_ADRESS + DATA_BLOCK;
  long adress;
  short erg = NO_ERROR;
  float data_rate;
  unsigned char *puffer = malloc(512);
  unsigned char *puffer2 = malloc(512);
  unsigned char *puffer3 = malloc(512);
  unsigned char *buf = malloc(512);
  char *bar = malloc(128);
  FILE *datei_fd;
 #ifdef LINUX
  int switch_baudrate = FALSE;
 #endif


	/* Frage, ob alte Firmware gesichert werden soll... */
  printf("\nHINWEIS : Soll alte Firmware in File <firmware.old> gesichert werden? (J/n) ");    
  do
  {
    zeichen = toupper(getchar());

    if(zeichen == 'J' || zeichen == CR_TASTE)
		{
			printf("\n");
      GTFirmwareUpload(baudrate, "firmware.old");
			break;
		}
    if(zeichen == 'N')
      break;          
  }
  while(zeichen == 'J' || zeichen == 'N');

//	getchar();		/* muss rein, weil es sonst bei den nachfolgenden Fragen Probleme gibt */

  /* Baudrate ueberpruefen */
  CheckBaudRate(baudrate);

  /* Firmware-Datei oeffnen und zweite 256 Byte in Puffer lesen
   * der erste Block (0x100) wird noch nicht gelesen - erst zum Schluß !!! */
  datei_fd = fopen(datei, "r");
  if(datei_fd == NULL)
  {
    printf("\nFEHLER : Keine Datei <%s> vorhanden! -> ABBRUCH!\n", datei);
    exit (0);
  }

  /* neue Firmewareversion untersuchen */
  fseek(datei_fd, 0x10, SEEK_SET);
  fread(puffer2, 0x17, 1, datei_fd);

  /* wenn Firmware-Datei nicht i.O. ist, dann Ende der Veranstaltung */
  if(strncmp(puffer2, "GESKO", 0x05) != 0)
  {
    printf("Firmware-Kennung : %s\n", puffer2);
    printf("\nFEHLER : Fehler in Firmwaredatei! -> ABBRUCH!\n");
    exit (0);
  }

  /* alte Firmareversion ermitteln und Vergleiche anstellen... */
  ReadFirmwareVersion(puffer2, buf, TRUE);

  /* Nachfrage, ob Firmware wirklich gedownloaded weden soll */
  printf("\nWARNUNG : Soll Firmware wirklich gedownloaded werden? (J/N) ");    
  do
  {
    zeichen = toupper(getchar());

    if(zeichen == 'J')
      break;
    if(zeichen == 'N')
      return NO_ERROR;          
  }
  while(zeichen == 'J' || zeichen == 'N');

  /* Flashkennung zerstoeren */
  DestroyFlashSignature();

  /* PBX resetten */
  ResetPbx();

 #ifdef LINUX
  switch(baudrate)
  {
    case 9600   : SetBaudRate(9600);
                  switch_baudrate = TRUE;
     break;
    case 19200  : SetBaudRate(19200);
                  switch_baudrate = FALSE;
     break;
    case 38400  : SetBaudRate(38400);
                  switch_baudrate = TRUE;
     break;
    case 57600  : SetBaudRate(57600);
                  switch_baudrate = TRUE;
     break;
    case 115200 : SetBaudRate(115200);
                  switch_baudrate = TRUE;
     break;
    default     :
     break;
  }
 #endif

  /* und zurueck zum Anfang der Datei */
  rewind(datei_fd);

  /* es wird mit dem zweiten Block (+0x100) angefangen */
  fseek(datei_fd, DATA_BLOCK, SEEK_SET);
  adress = first_adress;

	/* Timeout der seriellen Schnittstelle fuer FW-Download einstellen */
  SetComTimeout(FW_DOWNLOAD_TIMEOUT);

  /* Variable fuer FW-Download setzen */
  fw_dld = TRUE;

  printf("Download der neuen Firmware...\n");

  /* aktuelle Start-Zeit ermitteln */
	time(&start_zeit);

  do
  {
		/* Datenblock lesen */		
    fread(puffer, sizeof(char), DATA_BLOCK, datei_fd);

    /* Prozente ausrechnen */
    percent = block * PERCENT_FACTOR;

    /* Fortschrittsbalken bauen */
    k = abs((BAR_LEN * percent) / 100); 
    sprintf(bar, "%s", "[");
    for(i = 0; i < k; i++)
      strncat(bar, "#", 1);
    for(i = 0; i < (BAR_LEN - k); i++)
      strncat(bar, " ", 1);
    strncat(bar, "]", 1);    

    /* aktuelle Datenuebertragungsrate ausrechnen */
	  time(&lauf_zeit);  
	  data_rate = (DATA_BLOCK * block) / (difftime(lauf_zeit, start_zeit));

    /* und Alles anzeigen */
   #ifndef DEBUG
    printf("\rAdresse : 0x%lX  %s  %3d %%  %4.1f cps", adress, bar, percent, data_rate);
   #endif
   #ifdef DEBUG
    printf("Adresse : 0x%lX   Fortschritt : %3d %%   j : %d   block : %d\n", adress, percent, j, block);
   #endif

    fflush(stdout);

    j = MAX_TRYS;
    do
    {
      erg = WriteBlockToPabx(adress, DATA_BLOCK, puffer);
     #ifdef DEBUG
      printf("   erg = %d     j = %d\n", erg, j);
     #endif
    }
    while(erg != NO_ERROR && --j != 0);

    /* falls der Block nicht geschrieben werden konnte -> Abbruch des FW-Downloads */
		if(erg == ERROR)
		{
     #ifdef DEBUG_ERROR
			printf("\nFEHLER : Fehler bei Schreiben des Blocks %d! -> ABBRUCH!\n", block);
     #endif
     #ifndef DEBUG_ERROR
      printf("\n");
     #endif
      printf("\nFEHLER beim Download!\n");
			printf("\nHINWEIS : Vor neuem Firmware-Download die Anlage per Netztstecker resetten!\n\n");
			exit(0);
		} 

		if(j == 0)
    {
      printf("\nFEHLER bei Download!\n");
			printf("\nHINWEIS : Vor neuem Firmware-Download die Anlage per Netztstecker resetten!\n\n");
      exit (0);
    }

    /* und nun den naechsten Block... */
    block++;
   	adress = adress + DATA_BLOCK;
  }
  while(block != FIRMWARE);        /* einen Block weniger! -> s.u. */

  /* und dann noch den ersten Block */
  rewind(datei_fd);

  adress = last_adress;

  fread(puffer, sizeof(char), DATA_BLOCK, datei_fd);

  /* Prozente ausrechnen */
  percent = block * PERCENT_FACTOR;

  /* Fortschrittsbalken bauen */
  k = abs((BAR_LEN * percent) / 100); 
  sprintf(bar, "%s", "[");
  for(i = 0; i < k; i++)
    strncat(bar, "#", 1);
  for(i = 0; i < (BAR_LEN - k); i++)
    strncat(bar, " ", 1);
  strncat(bar, "]", 1);    

  /* und Alles anzeigen */
 #ifndef DEBUG
  printf("\rAdresse : 0x%lX  %s  %3d %%               ", adress, bar, percent);
 #endif
 #ifdef DEBUG
  printf("Adresse : 0x%lX   Fortschritt : %3d %%   j : %d   block : %d\n", adress, percent, j, block);
 #endif

  j = MAX_TRYS;
  do
  {
    erg = WriteBlockToPabx(adress, DATA_BLOCK, puffer);
  }
  while(erg != NO_ERROR && --j != 0);

  /* aktuelle Stop-Zeit ermitteln */
	time(&stop_zeit);

  if(erg == ERROR && j == 0)
  {
    printf("\nFEHLER beim Download!\n");
	  printf("\nHINWEIS : Vor neuem Firmware-Download die Anlage per Netztstecker resetten!\n\n");
    exit (0);
  }

  /* Ende */
  printf("\nDownload OK!\n");

  /* Variable fuer FW-Download zuruecksetzen */
  fw_dld = FALSE;

	SetComTimeout(SERIAL_TIMEOUT);

  /* Anzeige der Datenuebertragungsrate */
	data_rate = 0x80000 / (difftime(stop_zeit, start_zeit));
  printf("Benoetigte Zeit : %4.1f sec / %2.1f min\n", difftime(stop_zeit, start_zeit), (difftime(stop_zeit, start_zeit)/60));
  printf("Datenrate       : %4.1f cps\n", data_rate);

  /* wenn noetig, Baudrate auf 19200 zuruecksetzen */
 #ifdef LINUX
  if(switch_baudrate == TRUE)
    SetBaudRate(19200);
 #endif

  /* PBX nochmal resetten */
  ResetPbx();

	/* Firmwareversion pruefen */
  ReadFirmwareVersion(puffer3, buf, FALSE);

  return NO_ERROR;
}


/*****************************************************************************/
/* Funktion zum Upload der Firmware                                          */
/* ----------------------------------------------------------------------    */
/* In: baudrate : Baudrate, datei : Zeiger auf Datei                         */
/* ---------------------------------------------------                       */
/* Out:                                                                      */
/* ----------------------------------------------------                      */
/* Autor: Steffen Hildebrandt                                                */
/* letzte Aenderung: Steffen Hildebrandt, 10.01.2003                         */
/*****************************************************************************/
int GTFirmwareUpload ( int baudrate, unsigned char * datei )
{
  char zeichen;
  int i, k;
  long start_adr = FW_ADR_BEGIN;
  long end_adr = FW_ADR_END;
  long anz_data;
  long adress;
  int max_block;
  short j = MAX_TRYS;
  int percent = 0;
  int block = 1;
  int ret;
  float data_rate;
  unsigned char *puffer = malloc(512);
  char *bar = malloc(128);
  FILE *datei_fd;
 #ifdef LINUX
  int switch_baudrate = FALSE;
 #endif


  /* Baudrate ueberpruefen */
  CheckBaudRate(baudrate);

  /* Firmware-Datei oeffnen */
  datei_fd = fopen(datei, "w");
  if(datei_fd == NULL)
  {
    printf("FEHLER : Kann Datei <%s> nicht zum Schreiben oeffnen! -> ABBRUCH!\n", datei);
    exit (0);
  }

	printf("Firmware wird in Datei <%s> geschrieben!\n", datei);

  printf("\nStandard-Upload des Speicherbereichs 0x40000 - 0xBFFFF.\n");

  /* Nachfrage, ob anderer Speicherbereich geuploaded werden soll */
  printf("\nSpeicherbereich fuer Upload aendern? (j/N) ");    
  do
  {
    zeichen = toupper(getchar());

		/* falls nichts geaendert werden soll, dann Ende hier... */
		if(zeichen == CR_TASTE)
			break;

    if(zeichen == 'J')
    {
      printf("Bitte Startadresse eingeben (Hex) : 0x");
      i = scanf("%lX", &start_adr);
      printf("Bitte Endadresse eingeben   (Hex) : 0x");
      scanf("%lX", &end_adr);
      break;
    }
    if(zeichen == 'N')
      break;
  }
  while(zeichen == 'J' || zeichen == 'N');

  if(end_adr <= start_adr)
  {
    printf("FEHLER : Endadresse kleiner als Startadresse! -> ABBRUCH!\n");
    exit(0);
  }

  /* wenn noetig ein wenig Korrektur */
  if(start_adr < 0x40000)
    start_adr = 0x40000;
  if(end_adr > 0xBFFFF)
    end_adr = 0xBFFFF;

 #ifdef DEBUG	
  printf("start_adr = 0x%lX ( %ld )\n", start_adr, start_adr);
  printf("end_adr   = 0x%lX ( %ld )\n", end_adr, end_adr);
 #endif

  /* ein wenig Zuweisung für "Fortschritts"-Anzeige */
  anz_data = end_adr - start_adr;
  max_block = anz_data / DATA_BLOCK;
  adress = start_adr;

  /* PBX resetten */
	ResetPbx();

 #ifdef LINUX
  switch(baudrate)
  {
    case 9600   : SetBaudRate(9600);
                  switch_baudrate = TRUE;
     break;
    case 19200  : SetBaudRate(19200);
                  switch_baudrate = FALSE;
     break;
    case 38400  : SetBaudRate(38400);
                  switch_baudrate = TRUE;
     break;
    case 57600  : SetBaudRate(57600);
                  switch_baudrate = TRUE;
     break;
    case 115200 : SetBaudRate(115200);
                  switch_baudrate = TRUE;
     break;
    default     :
     break;
  }
 #endif

  printf("Upload des Speicherbereichs 0x%lX - 0x%lX...\n", start_adr, end_adr);

  /* aktuelle Start-Zeit ermitteln */
	time(&start_zeit);

  do
  {
    /* Prozente ausrechnen */
    percent = (block * 100) / max_block;
    if(percent > 100)
      percent = 100;

   /* Fortschrittsbalken bauen */
    k = abs((BAR_LEN * percent) / 100); 
    sprintf(bar, "%s", "[");
    for(i = 0; i < k; i++)
      strncat(bar, "#", 1);
    for(i = 0; i < (BAR_LEN - k); i++)
      strncat(bar, " ", 1);
    strncat(bar, "]", 1);    

    /* aktuelle Datenuebertragungsrate ausrechnen */
	  time(&lauf_zeit);  
	  data_rate = (DATA_BLOCK * block) / (difftime(lauf_zeit, start_zeit));

    /* und Alles anzeigen */
   #ifndef DEBUG
//    printf("\rAdresse : 0x%lX   %s   %d %%", adress, bar, percent);
    printf("\rAdresse : 0x%lX  %s  %d %%  %4.1f cps", adress, bar, percent, data_rate);
   #endif
   #ifdef DEBUG
    printf("Adresse : 0x%lX   Fortschritt : %3d %%\n", adress, percent);
   #endif

    fflush(stdout);

    j = MAX_TRYS;
    do
    {
      ret = ReadBlockFromPabx(adress, DATA_BLOCK, puffer);
     #ifdef DEBUG 
      printf("ret = %d     j = %d\n", ret, j);
     #endif
    }
    while(ret != NO_ERROR && --j != 0);

    if(j == 0)
    {
			printf("\n");
      SetBaudRate(19200);
      printf("\nFEHLER beim Upload!\n");
      exit (0);
    }

    fwrite(puffer, sizeof(char), DATA_BLOCK, datei_fd);
    fflush(datei_fd);

    block++;
    adress = adress + DATA_BLOCK;
  }
  while(adress <= end_adr);

  /* aktuelle Stop-Zeit ermitteln */
	time(&stop_zeit);

  fflush(datei_fd);
  fclose(datei_fd);

  /* Ende */
  printf("\nUpload OK!\n");

  /* Anzeige der Datenuebertragungsrate */
	data_rate = (end_adr - start_adr) / (difftime(stop_zeit, start_zeit));
  printf("Benoetigte Zeit : %4.1f sec / %2.1f min\n", difftime(stop_zeit, start_zeit), (difftime(stop_zeit, start_zeit)/60));
  printf("Datenrate       : %4.1f cps\n", data_rate);

  /* wenn noetig, Baudrate auf 19200 zuruecksetzen */
 #ifdef LINUX
  if(switch_baudrate == TRUE)
    SetBaudRate(19200);
 #endif

  return NO_ERROR;
}


/*****************************************************************************/
/* Funktion zum Flashkennung zerstoeren                                      */
/* ----------------------------------------------------------------------    */
/* In:                                                                       */
/* ---------------------------------------------------                       */
/* Out:                                                                      */
/* ----------------------------------------------------                      */
/* Autor: Steffen Hildebrandt                                                */
/* letzte Aenderung: Steffen Hildebrandt, 16.12.2002                         */
/*****************************************************************************/
int DestroyFlashSignature ( void )
{
  unsigned char  OutData    [0x200];
  unsigned char  *Antwort = malloc(512);
  short          HdrCtr;


  printf("FLASH-Kennung zerstoeren...\n"); 

  /* --- Header für die Blockuebertragung bauen ---------------------------------------------- */
	HdrCtr = 0;
  HdrCtr = MakeHeader (BLOCK_DESTROY_FLASH, 0, 0, OutData);

  SwitchToBlockmode(HdrCtr);
	SerialOut(OutData, HdrCtr);
	SerialIn(Antwort, (char)10);

 #ifdef DEBUG
  printf ("Response - SerialIn : Len=%3d : %s\n", strlen(Antwort), Antwort);
 #endif

	if(strncmp(Antwort, "OK", 2) != 0)
		return NO_ERROR;
	 else
		return ERROR;
}


/*****************************************************************************/
/* Funktion zum Flashkennung wiederherstellen                                */
/* ----------------------------------------------------------------------    */
/* In:                                                                       */
/* ---------------------------------------------------                       */
/* Out:                                                                      */
/* ----------------------------------------------------                      */
/* Autor: Steffen Hildebrandt                                                */
/* letzte Aenderung: Steffen Hildebrandt, 16.12.2002                         */
/*****************************************************************************/
int RepairFlashSignature ( void )
{
  unsigned char  OutData    [0x200];
  unsigned char  *Antwort = malloc(512);
  short          HdrCtr;


  printf("Flashkennung wiederherstellen...\n");

  /* --- Header für die Blockübertragung bauen ---------------------------------------------- */
	HdrCtr = 0;
  HdrCtr = MakeHeader (BLOCK_REPAIR_FLASH, 0, 0, OutData);

  SwitchToBlockmode(HdrCtr);
	SerialOut(OutData, HdrCtr);
	SerialIn(Antwort, (char)10);

 #ifdef DEBUG
  printf ("Response - SerialIn : Len=%3d : %s\n", strlen(Antwort), Antwort);
 #endif

	if(strncmp(Antwort, "OK", 2) != 0)
		return NO_ERROR;
	 else
		return ERROR;
}



/*****************************************************************************/
/* Funktion zum Resetten der PBX                                             */
/* ----------------------------------------------------------------------    */
/* In:                                                                       */
/* ---------------------------------------------------                       */
/* Out:                                                                      */
/* ----------------------------------------------------                      */
/* Autor: Steffen Hildebrandt                                                */
/* letzte Aenderung: Steffen Hildebrandt, 16.12.2002                         */
/*****************************************************************************/
int ResetPbx ( void )
{
  cmdtype Cmd;
  unsigned char *text = malloc(512);


  printf("Reset PBX...\n");

	SetComTimeout(RESET_TIMEOUT);

  sprintf (Cmd.befehl, "GTW");
	/* und nun dreimal das Ganze fuer den Reset... */
  GTPbxPutAndGet (Cmd, text, 0);
  GTPbxPutAndGet (Cmd, text, 0);
  GTPbxPutAndGet (Cmd, text, 0);

	sleep(5);         /* kleine Pause */

	SetComTimeout(SERIAL_TIMEOUT);

  return NO_ERROR;
}


/*****************************************************************************/
/* Funktion zum Ermitteln der aktuellen Firmwareversion                      */
/* ----------------------------------------------------------------------    */
/* In:                                                                       */
/* ---------------------------------------------------                       */
/* Out:                                                                      */
/* ----------------------------------------------------                      */
/* Autor: Steffen Hildebrandt                                                */
/* letzte Aenderung: Steffen Hildebrandt, 22.01.2003                         */
/*****************************************************************************/
void ReadFirmwareVersion ( unsigned char *puffer, unsigned char *buf, int check_version )
{
	int fw_anlage, fw_file;
  int fw_typ_anlage = NO_TYP;
  int fw_typ_file = NO_TYP;
  char zeichen;
  cmdtype Cmd;
  unsigned char *daten = malloc(512);
  unsigned char *text = malloc(512);


  printf("Lese Firmwareversion...\n");

	fw_anlage = FW_NONE;
	fw_file = FW_NONE;

  Cmd.param_anz = 0;
  sprintf ( Cmd.befehl, "%s", "I209" );
  ConfPbxPutAndGet  ( Cmd, daten, text, 0 );

  sprintf ( Cmd.befehl, "%s", "VERS" );
  ConfPbxPutAndGet  ( Cmd, daten, text, 0 );

  /* Versionsstring fuer Abfrage kopieren */
  strcpy(buf, text);

  /* und nun die Anzeige der Firmwareversion und diverse Fragen zur Sicherheit... */
  if(strncmp(text, "GESKO", 5) == 0)
  {
		/* Anlagenfirmware... */
    printf("Aktuelle Firmwareversion - Anlage : %.50s\n", text);

    if(check_version == TRUE)
    {
      if(strncmp(text, "GESKO F108", 10) == 0)
      {
				fw_anlage = FW_F108;
        fw_typ_anlage = FAMILY;
      }
      if(strncmp(text, "GESKO A108", 10) == 0)
      {
				fw_anlage = FW_A108;
        fw_typ_anlage = FAMILY;
      }
      if(strncmp(text, "GESKO i416", 10) == 0)
      {
				fw_anlage = FW_I416;
        fw_typ_anlage = OFFICE;
      }
      if(strncmp(text, "GESKO A416", 10) == 0)
      {
				fw_anlage = FW_A416;
        fw_typ_anlage = OFFICE;
      }

			/* Firmware des Files... */
 		  printf("Neue Firmwareversion     - File   : %.50s\n", puffer);

      if(strncmp(puffer, "GESKO F108", 10) == 0)
      {
				fw_file = FW_F108;
        fw_typ_file = FAMILY;
      }
      if(strncmp(puffer, "GESKO A108", 10) == 0)
      {
				fw_file = FW_A108;
        fw_typ_file = FAMILY;
      }
      if(strncmp(puffer, "GESKO i416", 10) == 0)
      {
				fw_file = FW_I416;
        fw_typ_file = OFFICE;
      }
      if(strncmp(puffer, "GESKO A416", 10) == 0)
      {
				fw_file = FW_A416;
        fw_typ_file = OFFICE;
      }

			/* Hinweismeldung bei identischer Firmware */
			if(strncmp(puffer, text, 0x17) == 0)
			{
       	printf("\nHINWEIS : Zu ladende Firmware ist identisch mit aktueller Firmware in der Anlage!\n");    
       	printf("Aktuelle Firmware wirklich ueberschreiben? (J/N) ");
       	do
       	{
         	zeichen = toupper(getchar());

         	if(zeichen == 'J')
           break;
         	if(zeichen == 'N')
           exit (0);          
       	}
       	while(zeichen == 'J' || zeichen == 'N');
			}

			/* Vergleich der Firmwaren... */
			if(fw_anlage != fw_file)
			{
				/* Hinweismeldungen bei unterschiedlicher Firmware : Version (family/office) und Variante A/D */
				switch(fw_anlage)
				{
					case FW_F108 : printf("\nAnlage : family-Reihe - deutsche Firmware (F108)!\n");
			 	 	 break;
					case FW_I416 : printf("\nAnlage : office-Reihe - deutsche Firmware (i416)!\n");
			 	 	 break;
					case FW_A108 : printf("\nAnlage : family-Reihe - oesterreichische Firmware (A108)!\n");
			 	   break;
					case FW_A416 : printf("\nAnlage : office-Reihe - oesterreichische Firmware (A416)!\n");
           break;
				}

				switch(fw_file)
				{
					case FW_F108 : printf("File   : family-Reihe - deutsche Firmware (F108)!\n");
			 	 	 break;
					case FW_I416 : printf("File   : office-Reihe - deutsche Firmware (i416)!\n");
			 	 	 break;
					case FW_A108 : printf("File   : family-Reihe - oesterreichische Firmware (A108)!\n");
			 	 	 break;
					case FW_A416 : printf("File   : office-Reihe - oesterreichische Firmware (A416)!\n");
           break;
				}

        if(fw_typ_anlage != fw_typ_file || fw_ger_aus_ow == FALSE)
        {
				  printf("\nFEHLER : Firmware des Files passt nicht zur Firmware der Anlage! -> ABBRUCH!\n");
				  exit(0);
        }
			}

			text = strpbrk(text, "V");
      puffer = strpbrk(puffer, "V");

			/* Hinweismeldung bei aelterer Firmware */
      if(strstr(text, "Flash") != NULL && strncmp(text, puffer, 4) > 0)
      {
        printf("\nWARNUNG : Zu ladende Firmware ist aelter als aktuelle Firmware!\n");    
        printf("Aktuelle Firmware wirklich ueberschreiben? (J/N) ");
        do
        {
          zeichen = toupper(getchar());

          if(zeichen == 'J')
            break;
          if(zeichen == 'N')
            exit (0);          
        }
        while(zeichen == 'J' || zeichen == 'N');
      }
    }
  }
   else
  {
    printf("\nFEHLER : Fehler bei Ermitteln der Firmwareversion!\n");
    exit (0);
  }

  sprintf ( Cmd.befehl, "%s", "ENDE" );
  ConfPbxPutAndGet  ( Cmd, daten, text, 0 );

  return;
}


/****************************************************************************************************************
 ****************************************************************************************************************
 ****************************************************************************************************************/

/*************************************************************************************************/
/*                                                                                               */
/* Funktion : Block mit fester Laenge lesen                                                      */
/*                                                                                               */
/* letzte Aenderung : Steffen Hildebrandt 10.01.2003                                             */
/*                                                                                               */
/*************************************************************************************************/
short ReadBlockFromPabx ( unsigned long Ctr, unsigned long Blocklaenge, unsigned char *PabxData)
{
  unsigned char  OutData    [0x200];
  short          HdrCtr;
  unsigned char  *Antwort = malloc(512);
  int            i;
  word           MyCrc = 0;
  byte           Crc[2];
  word           PabxCrc = 0;
  int erg_out = NO_ERROR;
  int erg_in = NO_ERROR;
 #ifdef DEBUG_DATA
  int k;
 #endif


  /* --- Header für die Blockuebertragung bauen ------------------------------------------------*/
  HdrCtr = 0;
  HdrCtr = MakeHeader (BLOCK_READ_BEFEHL, Ctr, Blocklaenge, OutData);

  /* --- Jetzt werden die Blockdaten uebertragen, in diesem Fall: Befehl+Start+Länge -----------*/
  SwitchToBlockmode(HdrCtr);
  erg_out = SerialOut(OutData, HdrCtr);
  erg_in = SerialInBlock(Antwort, Blocklaenge + 2);

 #ifdef DEBUG_DATA
  k = 0;
  printf("InData : ");
  do
  {
    printf("%.2X", Antwort[k]);
  }
  while(++k != Blocklaenge + 2);
  printf("\n");
 #endif

  /* CRC und Datenblock aus Puffer extrahieren */
  for(i = 0; i < 2; i++)
    Crc[i] = Antwort[i];
  for(i = 2; i < Blocklaenge + 2; i++)
    PabxData[i - 2] = Antwort[i];

  /* CRCs berechnen und ueberpruefen */
  PabxCrc = (word)( (word)(Crc[1] << 8) + Crc[0] );
  MyCrc = CalcCrc ( PabxData, (word)Blocklaenge );

  if (MyCrc != PabxCrc)
  {
	 #ifdef DEBUG_CRC
   	printf("\nFEHLER : CRC-Fehler ! - MyCrc=%4X  PabxCrc=%4X  Len=%lX\n", MyCrc, PabxCrc, Blocklaenge);
	 #endif
    return ERROR;
  }

  if ( erg_out == ERROR || erg_in == ERROR )
    return ERROR;
   else	 		
    return NO_ERROR;
}


/************************************************************************************************
 *
 * Funktion : Speicherblock in die Anlage uebertragen
 *
 * l. Aend. : Steffen Hildebrandt, 10.01.2003
 *
 ************************************************************************************************/
short WriteBlockToPabx (unsigned long Ctr, unsigned short Blocklaenge, unsigned char *PcData)
{
	int						 j;
	int            k = 0;
	int					   erg_out = NO_ERROR;
  int            erg_in = NO_ERROR;
	int 					 ret;
  unsigned char  OutData    [0x200];
	unsigned char  OutData2   [1] = { 0xFF };
  unsigned char  *Antwort = malloc(512);
  short          HdrCtr;
 #ifdef DEBUG_DATA
	int i = 0;
 #endif


  /* --- Header für die Blockuebertragung bauen ---------------------------------------------- */
	HdrCtr = 0;
  HdrCtr = MakeHeader (BLOCK_WRITE_BEFEHL, Ctr, Blocklaenge, OutData);
  memcpy ((unsigned char *)&(OutData[HdrCtr]), PcData, Blocklaenge);
  HdrCtr = MakeHeader (BLOCK_WRITE_BEFEHL, Ctr, Blocklaenge, OutData);

 #ifdef DEBUG_DATA
	printf("OutData : ");
	for(i = 0; i < (Blocklaenge + HdrCtr) - 1; i++)
		printf("%.2X", OutData[i]);
	printf("\n");
 #endif

	/* Schleife zur Erkennung, ob Blockuebertragung bzw. Antwort i.O. ist/war, d.h.
		 der Block wird solange uebertragen, bis alles i.O. ist */
	j = MAX_TRYS;
	do	
	{
  	ret = SwitchToBlockmode(Blocklaenge + HdrCtr);
	  if ( ret == ERROR )
      return ERROR;

	/* ----- SerialOut ----- */

		timeout = FALSE;
		erg_out = SerialOut(OutData, (Blocklaenge + HdrCtr));											/* Block zur Tk-Anlage senden */

		if(erg_out == ERROR || timeout == TRUE)
	  {
		 #ifdef DEBUG_ERROR
			printf("     --> erg_out=%d / timeout=%d -> Fehler!\n", erg_out, timeout);
		 #endif

			SetComTimeout(SERIAL_FAIL_TIMEOUT);

			/* fehlerhaften Block auffuellen... */
			k = 0;
			do
			{
				k++;
			 #ifdef DEBUG_ERROR
				printf("FEHLER : Versuch %d -> fehlerhaften Block auffuellen...\n", k);
			 #endif
			  ret = SerialOut(OutData2, 1);
		    if ( ret == ERROR && timer == TIMER_DOWN )
			  {
		      /* Timeout temporaer auschalten */
		     #ifdef TIMEOUT
			    #undef TIMEOUT
		     #endif
			    ret = SerialOut(OutData2, 1);
		      if ( ret == ERROR || timer == TIMER_DOWN)
				    return ERROR;
			  }
			}
			while(k <= 266);

		 #ifdef DEBUG_ERROR
			printf("     --> Out -> Fehlerhafter Block aufgefuellt!\n");
		 #endif	

		  /* Timeout wieder einschalten */
		 #ifndef TIMEOUT
			#define TIMEOUT
		 #endif

			return ERROR;
		}

	/* ----- SerialIn ----- */

		timeout = FALSE;
	  erg_in = SerialIn(Antwort, (char)10);

		if(erg_in == ERROR || timeout == TRUE)
		{
		 #ifdef DEBUG_ERROR
			printf("     --> erg_in=%d / timeout=%d -> Fehler!\n", erg_in, timeout);
		 #endif

			SetComTimeout(SERIAL_FAIL_TIMEOUT);

			/* fehlerhaften Block auffuellen... */
			k = 0;
			do
			{
				k++;
			 #ifdef DEBUG_ERROR
				printf("FEHLER : Versuch %d -> fehlerhaften Block auffuellen...\n", k);
			 #endif
			  ret = SerialOut(OutData2, 1);
			  if ( ret == ERROR )
				  return ERROR;
	   		ret = SerialIn(Antwort, (char)10);
			  if ( ret == ERROR && timer == TIMER_DOWN )
			  {
		      /* Timeout temporaer auschalten */
		     #ifdef TIMEOUT
			    #undef TIMEOUT
		     #endif
	   		  ret = SerialIn(Antwort, (char)10);
		      if ( ret == ERROR || timer == TIMER_DOWN)
				    return ERROR;
			  }
			}
			while(k <= 266);

		 #ifdef DEBUG_ERROR
			printf("     --> In -> Fehlerhafter Block aufgefuellt!\n");
		 #endif	

		  /* Timeout wieder einschalten */
		 #ifndef TIMEOUT
			#define TIMEOUT
		 #endif

		  return ERROR;
		}
	}
	while(--j != 0 && erg_out != NO_ERROR && erg_in != NO_ERROR);

  return NO_ERROR;
}


/*-FUNKTION-*************************************************************************************
 * Funktionsname   : L 0 _ R H _ C a l c C r c
 *-----------------------------------------------------------------------------------------------
 * Aufgabe         : 16 Bit CRC-Checksumme berechnen
 *
 * Eingabe-Param.  : data: Zeiger auf das erste Byte
 *                   size: Anzahl der Bytes ueber die die Checksumme gebildet werden soll
 * Return-Wert     : Die berechnete CRC-Checksumme
 *
 * Info            :
 ************************************************************************************************/

/* -- CRC-CCITT  Generatorpolynom: X^16 + X^12 + X^5 + 1 --------------------------------------- */

static unsigned short Crc_Tab[] =
{
  0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
  0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
  0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
  0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
  0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
  0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
  0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
  0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
  0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
  0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
  0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
  0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
  0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
  0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
  0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
  0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
  0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
  0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
  0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
  0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
  0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
  0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
  0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
  0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
  0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
  0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
  0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
  0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
  0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
  0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
  0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
  0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
};


/************************************************************************************************
 *
 * Funktion : Checksumme ausrechnen
 *
 ************************************************************************************************/
unsigned short CalcCrc(unsigned char *data, register unsigned short size)
{
  register unsigned short c = 0xFFFF;


  for ( ; size; size-- )
    c = (unsigned short)( Crc_Tab[ ( (unsigned short)c ^ ( *data++ )) & 0xFF ] ^ ( c >> 8 ) );

 #ifdef DEBUG_CRC
	printf("CRC für Blockmode : %.4X\n", c ^ 0xFFFF);
 #endif

  return ( (unsigned short)( c ^ 0xFFFF ) );
}

/************************************************************************************************
 *
 * Funktion : Blockuebertragungsheader wird gebildet
 *
 ************************************************************************************************/
short MakeHeader(short Befehl, unsigned long Startadresse, short Laenge, unsigned char *OutData)
{
  short          i;
  short          Ctr;
  unsigned char  *OrgPtr;
  unsigned short Crc = 0;
  unsigned char  CrcFeld[3];
  short          CrcLaenge;


  OrgPtr = OutData;
	Ctr = 0;
 
  /* --- Es werden zwei Zeichen freigelassen an die spaeter die Checksumme eingefuegt wird --------- */
  OutData += (sizeof (unsigned short));
  Ctr += (sizeof (unsigned short));
  
  /* --- Jetzt kommt das Befehlbyte ---------------------------------------------------------------- */
  *OutData++ = (char)Befehl;
  Ctr++;
  
  /* --- Wenn es ein Lese/Schreibbefehl ist, dann muessen noch Startadresse und Laenge rankommen --- */
  if ( (Befehl == BLOCK_READ_BEFEHL) || (Befehl == BLOCK_WRITE_BEFEHL) )
  {
    /*                     4 Bytes Startadresse */
    for ( i = 0  ; i < 4 ; i++ )
    {
      *OutData++ = (unsigned char)(Startadresse >> ((3-i)*8));
      Ctr++;
    }
    /*                     2 Bytes Laenge */
    for ( i = 0 ; i < 2 ; i++ )
    {
      *OutData++ = (unsigned char)(Laenge >> ((1-i)*8));
      Ctr++;
    }
  }
  
  /* --- Jetzt wird die Checksumme ermittelt ---------------------------------------------------- */
  if ( Befehl == BLOCK_WRITE_BEFEHL )
    CrcLaenge = (Ctr + Laenge);
  else
    CrcLaenge = Ctr;
 
  Crc = CalcCrc ( (OrgPtr + sizeof (unsigned short) ), (CrcLaenge - sizeof (unsigned short)) );
  
  /*                     2 Bytes CRC          */
  for ( i = 0 ; i < 2 ; i++ )
    CrcFeld[i] = (byte)(Crc >> ((1-i)*8));
  
  /* --- Jetzt wird die Checksumme eingefügt ---------------------------------------------------- */
  memcpy ( OrgPtr, &CrcFeld, sizeof (word) );

  return (Ctr);
}


/*************************************************************************************************/
/*                                                                                               */
/* Funktion : Temporaeres Umschalten in den Blockmodus der Konfigurationsschnittstelle           */
/*                                                                                               */
/* l. Aend. : Steffen Hildebrandt, 19.06.2002                                                    */
/*                                                                                               */
/*************************************************************************************************/
int SwitchToBlockmode ( int Blocklaenge )
{
	int i = 1;
  int erg = ERROR;
  unsigned char *text = malloc(512);
  cmdtype Cmd;
  

  /* --- Umschalten in Block-Empfangsmodus --------------------------------------------------*/
  sprintf(Cmd.befehl, "GTX1,%d", Blocklaenge);

	while (i < MAX_TRYS + 1)	
	{
	 #ifdef DEBUG
		printf("SwitchToBlockmode (Zaehler i = %d)\n", i);
	 #endif
  	erg = GTPbxPutAndGet (Cmd, text, 0);
		if (erg == NO_ERROR && strncmp(text, "OK", 2) == 0)
			break;
		i++;
	}

  if (erg == ERROR)
  {
   #ifdef DEBUG_ERROR
    printf("FEHLER : Fehler bei Schalten in Blockmode!\n");
   #endif
	  return ERROR;
  }

 #ifdef DEBUG
  printf("Transfers in Blockmode!\n");
 #endif

  return NO_ERROR;
}


/*************************************************************************************************/
/*                                                                                               */
/* Funktion : Pruefen der Baudrate                                                               */
/*                                                                                               */
/*************************************************************************************************/
void CheckBaudRate(int baudrate)
{
 #ifdef LINUX
/*
  if(baudrate > 19200)
  {
    printf("WARNUNG : Zur Zeit ist nur eine max. Baudrate von 19200 Baud moeglich!\n");
    exit (0);
  }
*/
 #endif

 #ifdef FREEBSD
  if(baudrate != 19200)
  {
    printf("WARNUNG : Bei FreeBSD ist zur Zeit nur eine Baudrate von 19200 Baud moeglich!\n");
    exit (0);
  }
 #endif
 #ifdef SOLARIS
  if(baudrate != 19200)
  {
    printf("WARNUNG : Bei Solaris8/Intel ist zur Zeit ist nur eine Baudrate von 19200 Baud moeglich!\n");
    exit (0);
  }
 #endif

  return;
}

/****************************************************************************************************************
 ****************************************************************************************************************
 ****************************************************************************************************************/

