/*============================================================================
#  AuvTimeSync -   Send current time of this system to client for
#                  synchronization. The packet sent is a string representation
#                  of the current system time (e.g. "1049896563.230740")
#
#  Client notes  - The client should bind a UDP socket to the given port and
#                  read incoming time using recv or recvfrom. Use the first
#                  packet to form a baseline difference between the to system
#                  clocks. Then continuously track the drift between the two
#                  system clocks by comparing the baseline difference to the
#                  subsequent time differences:
#                          begin
#                             recv(WinXpTime)
#                             base = WinXpTime - mytime
#                             do (forever)
#                                recv(WinXpTime)
#                                diff  = WinXpTime - mytime
#                                drift = base - diff
#                             end
#                          end
#
#  Usage: ats.exe [-h host.ip] [-p port] [-r rate_in_Hz]
#  To Make: gcc -o ats.exe ats.cc
#  To Run on PLC: ats.exe -h 134.89.32.35 -p 9009 -r 10
#
#============================================================================*/
#include <Windows.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/fcntl.h> // IO Control of socket.
#include <sys/time.h>
#include <errno.h>

#define DEFAULT_MVC_HOST "mvc-dmo"
#define DEFAULT_MVC_PORT 9009
#define DEFAULT_RATE 20         // Hz

#define WAIT_PORT 9727

void usage();
int setupCommSocket(const char* host, int port);

struct sockaddr_in  servaddr;
int main(int argc, char* const* argv)
{
  char *host = DEFAULT_MVC_HOST;
  int   port = DEFAULT_MVC_PORT;
  float rate = DEFAULT_RATE;

  // Resolve options
  //
  int c;
  while ( (c = getopt(argc, argv, "h:p:r:")) != EOF)
  {
    switch(c) {
      case 'h':
        host = strdup(optarg);
        break;
        
      case 'p':
        port = atoi(optarg);
        break;
        
      case 'r':
        rate = atof(optarg);
        if (rate <= 0.)
        {
          printf("ats: The rate must be >= 1.0\n");
          usage();
          return -1;
        }
        break;
        
      default:
        usage();
        return -1;
    }
  }

  // Open a channel to the MVC
  //
  int sockfd = 0;
  if ((sockfd = setupCommSocket(host, port)) < 0) return -1;
  
  unsigned int interval = ((1./rate)*1.e+06);   // microseconds
  printf("\r   Connected. Sending time data @ %fHz...\n", rate);
  while(1)
  {
    // Sleep for the specified interval using the timing socket
    //
    usleep(interval);
    
    // Get the current system time
    //
    FILETIME ft, epoch_ft;
    SYSTEMTIME epoch_st = {1970,1, 0, 1, 0, 0, 0, 0};
    ULARGE_INTEGER a, b;
    GetSystemTimeAsFileTime(&ft);
    SystemTimeToFileTime(&epoch_st, &epoch_ft);
    memcpy(&a, &ft, sizeof(ULARGE_INTEGER));
    memcpy(&b, &epoch_ft, sizeof(ULARGE_INTEGER));
    ULARGE_INTEGER c;
    c.QuadPart = a.QuadPart - b.QuadPart;
    
    double packet = c.QuadPart/(double)(1.e7);
    // Send it out the socket
    //
    int nb;
    if ((nb = sendto(sockfd, (char*)&packet, sizeof(double), 0,
        (struct sockaddr*)&servaddr, sizeof(servaddr))) <= 0)
    {
      printf("Errno = %d\n", errno);
    }
    
  }
  
  return 0;
}

int setupCommSocket(const char* host, int port)
{
  printf("\r   Connecting to host: %s   port: %d...\n", host, port);

  // Get a socket resource
  //
  int  sockfd = -1;
  if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  {
    printf("ats: Failed to initialize socket: errno = %d", errno);
    return -1;
  }

  // Attempt to setup a UDP socket to the port on the MVC
  //
  bzero((char*) &servaddr, sizeof(servaddr));
  servaddr.sin_family      = AF_INET;
  inet_aton(host, &servaddr.sin_addr);
  servaddr.sin_port        = htons((short)port);

  if (0 == servaddr.sin_addr.s_addr)
  {
    printf("ats: Failed to resolve host address");
    return -1;
  }

  return sockfd;
}

void usage()
{
  printf("ats: AuvTimeSync utility\n");
  printf("Usage:\n");
  printf("  ats [-h host.ip.str.ing] [-p portnumber_int] [-r frequency_float]\n");
}

