/*
*****************************************************************************
*
*      COPYRIGHT (C) 2000 ERICSSON RADIO SYSTEMS AB
*
*      The copyright to the program(s) herein is the property of
*      Ericsson Radio Systems AB, Sweden.
*
*      The program(s) may be used and/or copied only for the ETSI/3GPP
*      AMR-WB qualification/selection/characterization tests.
*
*****************************************************************************
*
*      File             : wcdma_eid.c
*      Purpose          : error insertion device for Application E
*
*****************************************************************************
*/


/*
*****************************************************************************
*                         VERSION ID
*****************************************************************************
*/

const char wcdma_eid_id[] = "$Id: wcdma_eid.c,v 1.2 2000/03/16 12:19:55 erasbru PA3 $";


/*
*****************************************************************************
*                         INCLUDE FILES
*****************************************************************************
*/

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


/*
*****************************************************************************
*                         FUNCTIONS
*****************************************************************************
*/

/*
 * Sets value to x if option '-optname=x' is present
 * Returns 0 on success
 * Returns -1 when failed sscanf
 * Returns 1 when option not defined
 */
int intOptArg(char *optname, int *value, int argc, char **argv)
{
    int i;  
    int n;
    char *s;

    if ((s = (char *) malloc(strlen(optname) + 2 + 1)) == 0) {
        fprintf(stderr, "intOptArg: Cannot malloc buffer, aborting!\n");
        exit(1);
    }
  

    /* Build "-optname=" string */
    s[0] = '-';
    strcpy(s + 1, optname);
    strcat(s, "=");

    for(i = 1; i < argc; i++) {
        if (strncmp(s, argv[i], strlen(optname) + 2) == 0) {
            if (sscanf(argv[i] + strlen(optname) + 2, "%d", &n) != 1) {
                return -1;
            }
            else {
                *value = n;
                return 0;
            }
        }
    }
    return 1;
}

/*
 * Returns the n:th argument not begining with '-'
 * Returns NULL if failed
 */
char* fileNameArg(int fileNo, int argc, char **argv)
{
    int n = 0;
    int i;
 
    for(i = 1; i < argc; i++) {
        if (argv[i][0] != '-') {
            n++;
            if (n == fileNo) {
                return argv[i];
            }
        }
    }
    return NULL;
}


/*
*****************************************************************************
*                         MAIN FUNCTION
*****************************************************************************
*/

int main (int argc, char *argv[])
{
    /*-----------------------------------------------------------------------*
     * declarations of variables                                             *
     *-----------------------------------------------------------------------*/
    
    int noAbits;                   /* number of speech coder bits per frame */  
    int maxnoBbits;                /* maximum number of bits in the least sigificant class */
    int choffs;                    /* offset (in frames) for channel profiles */
    
    char *fileName_FER;            /* file name for FER profile */
    char *fileName_RBER;           /* file name for RBER profile */
    char *fileName_in;             /* file name for input bitstream */
    char *fileName_out;            /* file name for output bitstream */
    
    FILE *fp_FER;                  /* file pointer to FER profile */
    FILE *fp_RBER;                 /* file pointer to RBER profile */
    FILE *fp_in;                   /* file pointer to input bitstream */
    FILE *fp_out;                  /* file pointer to output bitstream */

    short *sync;                   /* pointer to synchronisation header */
    short *frame;                  /* pointer to bitstream data for one frame */
    
    int newframe;                  /* enable to read new frame from input bitstream */
    int offscount;                 /* counter to set offset for channel profiles */
    int bfi;                       /* BFI flag */
    int bitcount;                  /* counter of bits in one frame */
    
    char biterr;                   /* indicator of residual bit error for a single bit */
    
    long framecount;               /* current frame number */

    
	if ((argc == 7) || (argc == 8)) {
        /*-----------------------------------------------------------------------*
         * get command line parameters                                           *
         *-----------------------------------------------------------------------*/
        
        if (intOptArg("classA", &noAbits, argc, argv)) {
            fprintf(stderr, "missing option classA\n");
            return -1;
        }
        if (intOptArg("maxclassB", &maxnoBbits, argc, argv)) {
            fprintf(stderr, "missing option maxclassB\n");
            return -1;
        }
        if (intOptArg("offset", &choffs, argc, argv)) {
            choffs = 0;
        }
        fileName_FER = fileNameArg(1, argc, argv);
        fileName_RBER = fileNameArg(2, argc, argv);
        fileName_in = fileNameArg(3, argc, argv);
        fileName_out = fileNameArg(4, argc, argv);

        
        /*-----------------------------------------------------------------------*
         * open input and output files                                           *
         *-----------------------------------------------------------------------*/
        
        if ((fp_FER = fopen(fileName_FER, "r")) == NULL) {
            fprintf(stderr, "error opening FER profile %s\n", fileName_FER);
            return -1;
        }
        if ((fp_RBER = fopen(fileName_RBER, "r")) == NULL) {
            fprintf(stderr, "error opening RBER profile %s\n", fileName_RBER);
            return -1;
        }
        if ((fp_in = fopen(fileName_in, "r")) == NULL) {
            fprintf(stderr, "error opening input bitstream %s\n", fileName_in);
            return -1;
        }
        if ((fp_out = fopen(fileName_out, "w")) == NULL) {
            fprintf(stderr, "error opening output bitstream %s\n", fileName_out);
            return -1;
        }

        
        sync = malloc(2*sizeof(short));
        newframe = 1;
        framecount = 0;
        


        /*-----------------------------------------------------------------------*
         * set offset for channel profiles                                       *
         *-----------------------------------------------------------------------*/
        
        if (choffs != 0) {            
            for (offscount = 0; offscount < choffs; offscount++) {
                if (EOF == fscanf(fp_FER, "%d", &bfi)) {
                    fprintf(stderr, "read after end of file in channel profiles\n");
                    exit(-1);
                }
            }
            fseek(fp_RBER, choffs*(maxnoBbits*sizeof(char)), SEEK_SET);
        }

        
        /*-----------------------------------------------------------------------*
         * error insertion according to automatically rewinded channel profiles  *
         *-----------------------------------------------------------------------*/
                    
        while (newframe) {
	   fread(sync, sizeof(short), 2, fp_in);
	   
	   if (!feof(fp_in)) {
	      frame = malloc(sync[1]*sizeof(short));
	      fread(frame, sizeof(short), sync[1], fp_in);
	      framecount++;
	      
	      if (EOF == fscanf(fp_FER,"%d",&bfi)) {
		 rewind(fp_FER);
		 fscanf(fp_FER,"%d",&bfi);
		 
		 rewind(fp_RBER);
	      }
	      if (bfi) {
		 sync[0] = 0x6B20;
		 for (bitcount = 0; bitcount < noAbits; bitcount++) {
		    frame[bitcount] = 0x0000;   
		 }
	      }
	      for (bitcount = noAbits; bitcount < sync[1]; bitcount++) {
		 fread(&biterr, sizeof(biterr), 1, fp_RBER);
		 if (biterr) {
		    frame[bitcount] = (-frame[bitcount])&0x00FF;
		 }
	      }
	      fwrite(sync, sizeof(short), 2, fp_out);
	      fwrite(frame, sizeof(short), sync[1], fp_out);
	      
	      fseek(fp_RBER, (framecount+choffs)*(maxnoBbits*sizeof(char)), SEEK_SET);
	      
	      free(frame);   
	   }
	   else {
	      fclose(fp_FER);
	      fclose(fp_RBER);
	      fclose(fp_in);
	      fclose(fp_out);
	      newframe = 0;
	   }
	}
	free(sync);
	
	}
	else {
        
	  /*-----------------------------------------------------------------------*
	   * usage printout                                                        *
	   *-----------------------------------------------------------------------*/
	  
	  printf("*****************************************************************************\n");
	  printf("*                                                                           *\n");
	  printf("*      COPYRIGHT (C) 2000 ERICSSON RADIO SYSTEMS AB                         *\n");
	  printf("*                                                                           *\n");
	  printf("*      The copyright to the program(s) herein is the property of            *\n");
	  printf("*      Ericsson Radio Systems AB, Sweden.                                   *\n");
	  printf("*                                                                           *\n");
	  printf("*      The program(s) may be used and/or copied only for the ETSI/3GPP      *\n");
	  printf("*      AMR-WB qualification/selection/characterization tests.               *\n");
	  printf("*                                                                           *\n");
	  printf("*****************************************************************************\n\n");
	  printf("usage:\n\nwcdma_eid -classA=<noAbits> -maxclassB=<maxnoBbits> [-offset=<choffs>] FERfilename RBERfilename inputbitstream outputbitstream\n\n");
	  printf("  noAbits:         number of class A bits\n");
	  printf("  maxnoBbits:      maximum number of class B bits (in channel file!)\n");
	  printf("  choffs:          offset in frames into channel file (default 0)\n");
	  printf("  FERfilename:     text file for the FER profile\n");
	  printf("  RBERfilename:    binary file for the residual BER profile\n");
	  printf("  inputbitstream:  binary file of encoded bits ordered with decreased error sensitivity (G.192 format)\n");
	  printf("  outputbitstream: corresponding binary file containing residual biterrors for decoding (G.192 format)\n\n");
	  
	}
	return 0;
}
