/* Soft decision Viterbi Decoder Test Driver                        */
/* Copyright (c) 1999, Spectrum Applications, Derwood, MD, USA      */
/* All rights reserved                                              */
/* Version 2.0 Last Modified 1999.02.20                             */

#include <alloc.h>
#include <conio.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "vdsim.h"
 
extern void gen01dat(long data_len, int *out_array);
extern void cnv_encd(int g[2][K], long data_len, int *in_array, int *out_array);
extern void addnoise(float es_ovr_n0, long data_len, int *in_array, float *out_array);
extern void sdvd(int g[2][K], float es_ovr_n0, long channel_length,
            float *channel_output_vector, int *decoder_output_matrix);
 
void testsdvd(void) {
 
    long iter, t, msg_length, channel_length; /* loop variables, length of I/O files */

    int *onezer;
    int *encoded;                    /* original, encoded, & decoded data arrays */
    int *sdvdout;

    int start;

    float *splusn;                   /* noisy data array */

    int i_rxdata, m;                 /* int rx data , m = K - 1*/
    float es_ovr_n0, number_errors_encoded, number_errors_unencoded,
            e_threshold, ue_threshold, e_ber, ue_ber; /* various statistics */

    #if K == 3        /* polynomials for K = 3 */
    int g[2][K] = {{1, 1, 1},     /* 7 */
                   {1, 0, 1}};    /* 5 */
    #endif

    #if K == 5        /* polynomials for K = 5 */
    int g[2][K] = {{1, 1,  1, 0, 1},  /* 35 */
                   {1, 0,  0, 1, 1}}; /* 23 */
    #endif
 
    #if K == 7        /* polynomials for K = 7 */
    int g[2][K] = {{1,  1, 1, 1,  0, 0, 1},  /* 171 */
                   {1,  0, 1, 1,  0, 1, 1}}; /* 133 */
    #endif

    #if K == 9        /* polynomials for K = 9 */
    int g[2][K] = {{1, 1, 1,  1, 0, 1,  0, 1, 1}, /* 753 */
                   {1, 0, 1,  1, 1, 0,  0, 0, 1}}; /* 561 */
    #endif
 
    clrscr();

    printf("\nK = %d", K);

    #if K == 3
    printf("\ng1 = %d%d%d", g[0][0], g[0][1], g[0][2] );
    printf("\ng2 = %d%d%d\n", g[1][0], g[1][1], g[1][2] );
    #endif

    #if K == 5
    printf("\ng1 = %d%d %d%d%d", g[0][0], g[0][1], g[0][2], g[0][3], g[0][4] );
    printf("\ng2 = %d%d %d%d%d\n", g[1][0], g[1][1], g[1][2], g[1][3], g[1][4] );
    #endif

    #if K == 7
    printf("\ng1 = %d %d%d%d %d%d%d", g[0][0], g[0][1], g[0][2], g[0][3], g[0][4],
                     g[0][5], g[0][6] );
    printf("\ng2 = %d %d%d%d %d%d%d\n", g[1][0], g[1][1], g[1][2], g[1][3], g[1][4],
                     g[1][5], g[1][6] );
    #endif

    #if K == 9
    printf("\ng1 = %d%d%d %d%d%d %d%d%d", g[0][0], g[0][1], g[0][2], g[0][3], g[0][4],
                     g[0][5], g[0][6], g[0][7], g[0][8] );
    printf("\ng2 = %d%d%d %d%d%d %d%d%d\n", g[1][0], g[1][1], g[1][2], g[1][3], g[1][4],
                     g[1][5], g[1][6], g[1][7], g[1][8] );
    #endif

    m = K - 1;
    msg_length = MSG_LEN;
    channel_length = ( msg_length + m ) * 2;

    onezer = malloc( msg_length * sizeof( int ) );
    if (onezer == NULL) {
        printf("\n testsdvd.c:  error allocating onezer array, aborting!");
        exit(1);
    }

    encoded = malloc( channel_length * sizeof(int) );
    if (encoded == NULL) {
        printf("\n testsdvd.c:  error allocating encoded array, aborting!");
        exit(1);
    }

    splusn = malloc( channel_length * sizeof(float) );
    if (splusn == NULL) {
        printf("\n testsdvd.c:  error allocating splusn array, aborting!");
        exit(1);
    }

    sdvdout = malloc( msg_length * sizeof( int ) );
    if (sdvdout == NULL) {
        printf("\n testsdvd.c:  error allocating sdvdout array, aborting!");
        exit(1);
    }


    for (es_ovr_n0 = LOESN0; es_ovr_n0 <= HIESN0; es_ovr_n0 += ESN0STEP) {

        start = time(NULL);
        
        number_errors_encoded = 0.0;
        e_ber = 0.0;
        iter = 0;

        #ifdef DOENC
        if (es_ovr_n0 <= 9)
            e_threshold = 100; /* +/- 20% */
        else
            e_threshold = 20; /* +/- 100 % */
 
        while (number_errors_encoded < e_threshold) {
            iter += 1;
 
            /*printf("Generating one-zero data\n");*/
            gen01dat(msg_length, onezer);
 
            /*printf("Convolutionally encoding the data\n");*/
            cnv_encd(g, msg_length, onezer, encoded);
 
            /*printf("Adding noise to the encoded data\n");*/
            addnoise(es_ovr_n0, channel_length, encoded, splusn);
 
 
            /*printf("Decoding the BSC data\n");*/
            sdvd(g, es_ovr_n0, channel_length, splusn, sdvdout);

            for (t = 0; t < msg_length; t++) {
                if ( *(onezer + t) != *(sdvdout + t) ) {
                   /*printf("\n error occurred at location %ld", t);*/
                       number_errors_encoded += 1;
                } /* end if */
            } /* end t for-loop */
 
           if (kbhit()) exit(0);
            /*printf("\nDone!");*/

        }

        e_ber = number_errors_encoded / (msg_length * iter);

        printf("\nThe elapsed time was %d seconds for %d iterations",
                   time(NULL) - start, iter);
        #endif
 
        number_errors_unencoded = 0.0;
        ue_ber = 0.0;
        iter = 0;

        #ifdef DONOENC
        if (es_ovr_n0 <= 12)
            ue_threshold = 100;
        else
            ue_threshold = 20;
 
 
        while (number_errors_unencoded < ue_threshold) {
            iter += 1;
 
            /*printf("Generating one-zero data\n");*/
            gen01dat(msg_length, onezer);
 
            /*printf("Adding noise to the unencoded data\n");*/
            addnoise(es_ovr_n0, msg_length, onezer, splusn);
 
            for (t = 0; t < msg_length; t++) {

                if ( *(splusn + t) < 0.0 )
                    i_rxdata = 1;
                else
                    i_rxdata = 0;
 
                if ( *(onezer + t) != i_rxdata )
                    number_errors_unencoded += 1;
            }
 
            if (kbhit()) exit(0);
            /*printf("\nDone!");*/

        }

        ue_ber = number_errors_unencoded / (msg_length * iter);
        #endif

        printf("\nAt %1.1fdB Es/No, ", es_ovr_n0);

        #ifdef DOENC
        printf("the e_ber was %1.1e ", e_ber);
        #ifdef DONOENC
        printf("and ");
        #endif
        #endif

        #ifdef DONOENC
        printf("the ue_ber was %1.1e", ue_ber);
        #endif


    }

    free(onezer);
    free(encoded);
    free(splusn);
    free(sdvdout);

    while ( !kbhit() ) {
    }

    exit(0);
}