/* test-phaseout.c
created lun. juin  5 04:41:28 CEST 2017 by Yann Guidon (whygee@f-cpu.org)
version mar. juin  6 05:55:18 CEST 2017 : merged phase-out and bitstream
version mar. juil. 4 07:03:03 CEST 2017 bitstream.c stripped down to test-phaseout.c

Test of the bitstream insertion and extraction routines
   with phase-out encoding, 64-bits version

gcc -Wall -O2 -o bs test-phaseout.c && ./bs
*/

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

#define DEBUG
#define VERBOSE
#define TEST_SEQ
#define TEST_RAND

#define BUFFER_LENGTH (1<<16)

#define CHUNKSIZE 20
uint16_t limits[CHUNKSIZE+3],
         values[CHUNKSIZE+3];

void my_error(char *m) {
  fflush(NULL);
  puts(m);
  exit(EXIT_FAILURE);
}


#include "lfsr4.c"  // found at http://ygdes.com/sources/lm98/lfsr4.c
#include "phaseout.c"


////////////////////////////////////////////////////////////

int main(int argc, char *argv[]) {

#ifdef TEST1
  memset(Buffer32, 170, sizeof(Buffer32));

  init_encode();
  send_phaseout( 3, 65535);
  send_phaseout( 6,  2047);
  send_phaseout(40,    48);
  send_phaseout(90,    90);
  flush_bitstream();

  init_decode();
  receive_phaseout(65535);
  receive_phaseout( 2047);
  receive_phaseout(   48);
  receive_phaseout(   90);

  puts("\n");

#endif

#ifdef TEST_SEQ
  int t;
  unsigned int i, j, k, l, v,
    errors=0,
    max=600;

  //////////////////////////////

  init_encode();
  for (j=0; j<=max; j++) {
//    printf("\n\nLim=%d", j);
    for (i=0; i<=j; i++) {
      send_phaseout(i, j);
    }
  }
  flush_bitstream();
  printf("\n\n  Buffer length: %ld\n\n",
     Stream_length*sizeof(*Buffer32));

  //////////////////////////////

  Stream_max = Stream_length;
  init_decode();

  for (j=0; j<=max; j++) {
//    printf("\nLim=%d", j);
    for (i=0; i<=j; i++) {
      k=receive_phaseout(j);
      if (k != i){
        errors++;
        printf("\n expected %d, received %d  ", i, k);
      }
    }
  }

#ifdef TEST_RAND

  //////////////////////////////
  // Random test
  puts("\n\nRandom test:");

  for (j=0; j<10000000; j++) {
//    printf("\nEncoding #%d: ", j);

    init_encode();
    for (i=0; i<CHUNKSIZE; i++) {

      // generate the limit
      k = lfsr4(); // from 1 to 16 bits
      l = 0;
      t = k;
      while (t>0){
        l = (l<<4) | lfsr4();
        t-=4;
      }
      t=1<<k;
      l = t | (l & (t-1));
      limits[i]=l;

      // generate the value
      v=0;
      t = k;
      while (t>-5){
        v = (v<<4) | lfsr4();
        t-=4;
      }
      v = v % (l+1);
      values[i]=v;

//      printf ("\n - %2d: %d,%d  ", k, v, l);
      send_phaseout(v, l);
    }
    flush_bitstream();

//    puts("\nDecoding: ");

    Stream_max = Stream_length;
    init_decode();
    for (i=0; i<CHUNKSIZE; i++) {
      l=values[i];
      k=receive_phaseout(limits[i]);
      if (k != l){
        errors++;
        printf("\n expected %d, received %d  ", l, k);
      }
    }
  }

#endif

  //////////////////////////////

  if (errors) {
    printf("\n\n%d errors\n\n", errors);
    return EXIT_FAILURE;
  }
  else {
    puts("\n\nOK!\n\n");
    return EXIT_SUCCESS;
  }
#endif

}
