/* procedure to compare rReceive methods with read and recv
   parameters include read 1 character at a time and as many as can be read at once

   rReceiveA:  original version of rReceive, use read, up to 1 byte at a time
   rReceiveB:  use read, read as many bytes as available until all obtained
   rReceiveC:  use recv, blocking, 1 byte at a time
   rReceiveD:  use recv, blocking, all bytes requested at once

   for accurate timings, mutex semaphores not used in this program
*/

#include <MyroC.h>
#include "../MyroC-utilities.h"
#include <unistd.h>      // for read
#include <sys/socket.h>  // for recv
#include <errno.h>       // for errno
#include <stdio.h>       // for printf
#include <time.h>
#include <stdlib.h>      // for time

int socket_num;

/* variables to count number of loop iterations in each receive version */
int iterA;
int iterB;
int iterC;
int iterD;

/**
 * Receives data via bluetooth
 * @param message       a pointer to allocated space, where the data will be stored
 * @param numberOfEchoBytes  number of bytes to be received from the Scribbler 
 * @pew                 space pointed to by message >= numberOfEchoBytes
 */
void rReceiveA (unsigned char * message, int numberOfBytes)
{ int total_read;
  iterA = 0;
  for (total_read=0; total_read<numberOfBytes; )
    {
      if (read (socket_num, message+total_read, 1) > 0)
        {
          // printf("received '%u'\n", message[total_read]&255);
          total_read++;
        }
      iterA++;
    }  
}

void rReceiveB (unsigned char * message, int numberOfBytes)
{ int total_read = 0;
  iterB = 0;
  while (total_read < numberOfBytes)
    {
      total_read += read (socket_num, message+total_read, numberOfBytes-total_read);
      iterB++;
    }
}

void rReceiveC (unsigned char * message, int numberOfBytes)
{
  int total_read;
  iterC = 0;
  for (total_read=0; total_read<numberOfBytes; )
    {
      printf ("total_read:  %d\t", total_read);
      int i;
      /* MSG_WAITALL:  wait for full request or error */
      if ((i = recv (socket_num, message+total_read, 1, MSG_WAITALL)) > 0)
        {
           printf("received '%u'\n", message[total_read]&255);
          total_read++;
        }
      iterA++;
      printf ("recv return:  %d \n", i);
      if (errno == EAGAIN)
	printf ("EAGAIN error\n");
      if (errno == EBADF)
	printf ("EBADF error\n");
      if (errno == ECONNRESET)
	printf ("ECONNRESET error\n");
      if (errno == EFAULT)
	printf ("EFAULT error\n");
      if (errno == EINTR)
	printf ("EINTR error\n");
      if (errno == EINVAL)
	printf ("EINVAL error\n");
      if (errno == ENOBUFS)
	printf ("ENOBUFS error\n");
      if (errno == ENOTCONN)
	printf ("ENOTCONN error\n");
      if (errno == ENOTSOCK)
	printf ("ENOTSOCK error\n");
      if (errno == EOPNOTSUPP)
	printf ("EOPNOTSUPP error\n");
      if (errno == ETIMEDOUT)
	printf ("ETIMEDOUT error\n");
    }  
  iterC = 0;
}

void rReceiveD (unsigned char * message, int numberOfBytes)
{ int total_read = 0;
  iterD = 0;
  while (total_read < numberOfBytes)
    {
      /* MSG_WAITALL:  wait for full request or error */
      total_read += recv (socket_num, message+total_read, 
			  numberOfBytes-total_read, MSG_WAITALL);
      iterD++;
    }
}

/* test and compare all rReceive options
   @parm message:  the command to be issued
   @parm numberOfBytes:  number of response bytes expected
   @printResult:  0 - do not print returned data; 1 - print returned data
*/
void testMethods (char * message, int COMMAND_ECHO, int DATA_ECHO,
		  int numberOfBytes, int printResult)
{
  unsigned char * newNameA = malloc (sizeof(char) * numberOfBytes);
  unsigned char * newNameB = malloc (sizeof(char) * numberOfBytes);
  unsigned char * newNameC = malloc (sizeof(char) * numberOfBytes);
  unsigned char * newNameD = malloc (sizeof(char) * numberOfBytes);

  clock_t start_time, end_time;
  double elapsed_time;

  rSend (message, 9, COMMAND_ECHO, DATA_ECHO, "Command");
  start_time = clock ();
  rReceiveA (newNameA, numberOfBytes);
  end_time = clock ();
  printf ("%3d", iterA);
  elapsed_time = (end_time - start_time) / (double) CLOCKS_PER_SEC;
  printf ("  %7.5lf  ", elapsed_time);

  rSend (message, 9, COMMAND_ECHO, DATA_ECHO, "Command");
  start_time = clock ();
  rReceiveB (newNameB, numberOfBytes);
  end_time = clock ();
  printf ("%3d", iterB);
  elapsed_time = (end_time - start_time) / (double) CLOCKS_PER_SEC;
  printf ("  %7.5lf ", elapsed_time);

  rSend (message, 9, COMMAND_ECHO, DATA_ECHO, "Command");
  start_time = clock ();
  rReceiveC (newNameC, numberOfBytes);
  end_time = clock ();
  printf ("%3d", iterC);
  elapsed_time = (end_time - start_time) / (double) CLOCKS_PER_SEC;
  printf (" %7.5lf\n", elapsed_time);

  rSend (message, 9, COMMAND_ECHO, DATA_ECHO, "Command");
  start_time = clock ();
  rReceiveD (newNameD, numberOfBytes);
  end_time = clock ();
  printf ("%3d", iterD);
  elapsed_time = (end_time - start_time) / (double) CLOCKS_PER_SEC;
  printf (" %7.5lf\n", elapsed_time);

  int diffB = 0;
  int diffC = 0;
  int diffD = 0;

  int i;
  for (i = 0; i < numberOfBytes; i++)
    {
      if (newNameA[i] != newNameB[i])
	diffB++;
      if (newNameA[i] != newNameC[i])
	diffC++;
      if (newNameA[i] != newNameD[i])
	diffD++;
    }

  char sep = '\0';
  if (diffB > 0)
    {
      printf ("%c B", sep);
      sep = ',';
    }
  if (diffC > 0)
    {
      printf ("%c C", sep);
      sep = ',';
    }
  if (diffD > 0)
    {
      printf ("%c D", sep);
      sep = ',';
    }
  printf ("\n");

  free (newNameA);
  free (newNameB);
  free (newNameC);
  free (newNameD);
}

int main ()
{

  printf ("program to test time and effort for different rReceive versions\n");
  socket_num = rConnect ("/dev/tty.IPRE6-365877-DevB");

  char message[9];

  /* print heading of results */
  printf ("           rReceiveA     rReceiveB     rReceiveC     rReceiveD    Different\n");
  printf ("Command   iter.  time   iter.  time   iter.  time   iter.  time   from RecA\n");
  
  /* rGetName (bytes 0-7) */
  //Message 78 recieves 9 bytes of echo, and 8 bytes of message.
  message[0]= 78; // get first 8 bytes of the robot's 16-byte name
  message[1]= 0;  // not used
  message[2]= 0;  // not used
  message[3]= 0;  // not used
  message[4]= 0;  // not used
  message[5]= 0;  // not used
  message[6]= 0;  // not used
  message[7]= 0;  // not used
  message[8]= 0;  // not used

  printf ("getName1: "); 
  testMethods (message, ECHO_COMMAND_ON, ECHO_SENSOR_OFF, 8, 1);

  /* rGetName (bytes 8-15) */
  message[0]= 64; // get last 8 bytes of the robot's 16-byte name
  message[1]= 0;  // not used
  message[2]= 0;  // not used
  message[3]= 0;  // not used
  message[4]= 0;  // not used
  message[5]= 0;  // not used
  message[6]= 0;  // not used
  message[7]= 0;  // not used
  message[8]= 0;  // not used
    
  printf ("getName2: "); 
  testMethods (message, ECHO_COMMAND_ON, ECHO_SENSOR_OFF, 8, 1);

  return 0;
}
