//NAME:
//  send_wave_array_over_udp.c
//
//PURPOSE:
//  This program is intended to send a waveform (256 unsigned shorts) to the 
//  GetCentroid algorithm running on a MicroZed FPGA.
//
//  The bitstream on the MicroZed uses a lwIP server (running on a Zynq-7010 SoC/FGPA).
//  It uses UDP for Ethernet communication. It will create a fictitious waveform on 
//  its own.
//
//COMPILING:
//  gcc -o send_wave_array_over_udp.o send_wave_array_over_udp.c 
//
//CALLING SEQUENCE:
//    ./send_index_array_over_udp.o
//
// Standard includes
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>

// New includes relevant to this application
// types.h contains definitions of a number of data types used in system calls
#include <sys/types.h>
// socket.h includes a number of definitions of structures needed for sockets
#include <sys/socket.h>
// in.h contains constants and structures needed for internet domain addresses
#include <netinet/in.h>
// netdb.h contains more network related functions and structures, hostent, in particular
#include <netdb.h>

// Define defaults for IP address and port number on MicroZed
#define PORT_NUMBER 7
#define IP_ADDRESS "192.168.1.10"

// Definitions for our fixed point numbers
#define BW              32     // Total number of bits in fixed point data type
#define IW              24     // Number of bits left of decimal point in fixed point data type
#define BITDIV          256.0  // Divisor to shift fixed point to int and back to float

// Other defines
#define WAVE_SIZE      256     // The number of elements in the pulse (and index array)

// A simple error function that uses the perror call to print an error on stderr 
void error(const char *msg)
{
    perror(msg);
    exit(1);
}

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

  // Declare variables
  int sockfd;               //file descriptors - array subscripts into file descriptor table
  int portno;               //stores the port number on which the server accepts connections
  int n;                    //return value for the read() and write() calls
  char* servername;         //a pointer to the IP address string or server name
  int success=0;            //return value for functions
 
  // Define the structures that contain internet addresses (defined in netinet/in.h)
  struct sockaddr_in serv_addr;

  // Define the hostent structure that defines a host computer on the Internet 
  struct hostent *server;

  // Make sure that the proper syntax is used to call the function
  if (argc < 1){
    fprintf(stderr,"usage %s\n", argv[0]);
    fprintf(stderr, "  or\n");
    fprintf(stderr, "%s [hostip] [port]\n\r", argv[0]);
    exit(0);
  }

  // We are hard coding the IP and Port. See the #define statement above
  server = gethostbyname(IP_ADDRESS);
  portno = PORT_NUMBER;

  // Open the socket - First argument is the address domain (internet domain - AF_INET or unix 
  // domain - AF_UNIX), Second argument is type of socket (stream - SOCK_STREAM or datagram - 
  // SOCK_DGRAM), Third argument is protocol - 0 allows OS to choose protocol (TCP for stream 
  // and UDP for datagram)
  // Returns an entry into file descriptor table
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sockfd < 0) error("ERROR opening socket\n\r");

  // Zero out the character array
  bzero((char *) &serv_addr, sizeof(serv_addr));

  // Assign the proper variables to the serv_addr sockaddr_in structure
  serv_addr.sin_family = AF_INET;          //Code for the address family - internet
  serv_addr.sin_port = htons(portno);      //Assign port number after going host byte->network byte order
  // And copy the server name into the socket structure address
  bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);

  // Connect the socket to the ip address and port that was assigned
  if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) error("ERROR connecting\n\r");

  // Create an array to hold the results of the GetCentroid algorithm
  char   CentroidCharArr[4];
  char*  BuffPtr   = NULL;
  int*   IndexPtr  = NULL;
  int*   FP_Ptr    = NULL;
  float  Centroid  = 0;
  int    i         = 0;
  int    j         = 0;

  // Create the pulse
  unsigned short wave_array[WAVE_SIZE];
  for (i=0; i<WAVE_SIZE; ++i){
    wave_array[i] = i;
  }

  // Send the pulse to the GetCentroid algorithm over UDP
  n = write(sockfd, &wave_array[0], sizeof(unsigned short)*WAVE_SIZE);
  if (n < 0) error("ERROR writing to socket\n\r");
  printf("Sent %d bytes of waveform data to the GetCentroid algorithm...\n", n);

  //Now read back the centroid back over UDP as four bytes in a char array
  n = read(sockfd, &CentroidCharArr[0], 4);
  if (n < 0) error("ERROR reading from socket\n\r");

  // Convert the centroid from a fixed point number to a float
  FP_Ptr   = (int*)(&CentroidCharArr[0]);
  Centroid = ((float)(*FP_Ptr))/BITDIV;

  // Print out the centroid
  printf("Calculated centroid: %14.8f\n", Centroid);

  // Close the socket
  close(sockfd);

  //Return nothing
  return 0;
  
}
