/* 
 * sht.c - Testprogram for shared memory refclock
 * read/write shared memory segment; see usage
 */
#ifndef SYS_WINNT
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#else
#include <windows.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream.h>
#define sleep(x) Sleep(x*1000)
#endif
#include <assert.h>
struct shmTime {
  int    mode; /* 0 - if valid set
                *       use values, 
                *       clear valid
                * 1 - if valid set 
                *       if count before and after read of values is equal,
                *         use values 
                *       clear valid
                */
  int    count;
  time_t clockTimeStampSec;
  int    clockTimeStampUSec;
  time_t receiveTimeStampSec;
  int    receiveTimeStampUSec;
  int    leap;
  int    precision;
  int    nsamples;
  int    valid;
};
struct shmTime *getShmTime (int unit) {
#ifndef SYS_WINNT
    int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777);
    if (shmid==-1) {
      perror ("shmget");
      exit (1);
    }
    else {
      struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
      if ((int)(long)p==-1) {
        perror ("shmat");
        p=0;
      }
      assert (p!=0);
      return p;
    }
#else
    char buf[10];
    LPSECURITY_ATTRIBUTES psec=0;
    sprintf (buf,"NTP%d",unit);
    SECURITY_DESCRIPTOR sd;
    SECURITY_ATTRIBUTES sa;
    HANDLE shmid;

    assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
    assert (SetSecurityDescriptorDacl(&sd,1,0,0));
    sa.nLength=sizeof (SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor=&sd;
    sa.bInheritHandle=0;
    shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
                                    psec, sizeof (struct shmTime),buf);
    if (!shmid) {
    shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE,
                                    0, sizeof (struct shmTime),buf);
      cout <<"CreateFileMapping with psec!=0 failed"<<endl;
    }

    if (!shmid) {
      char mbuf[1000];
      FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
                     0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
      int x=GetLastError ();
      cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl;
      exit (1);
    }
    else {
      struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, 
                          FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime));
      if (p==0) {
        char mbuf[1000];
        FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM,
                       0, GetLastError (), 0, mbuf, sizeof (mbuf), 0);
        cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl;
        exit (1);
      }
      return p;
    }
    return 0;
#endif
}
void main (int argc, char *argv[]) {
  volatile struct shmTime *p=getShmTime(2);
  if (argc<=1) {
    printf ("usage: %s r[c][l]|w|snnn\n",argv[0]);
    printf ("       r read shared memory\n");
    printf ("        c clear valid-flag\n");
    printf ("        l loop (so, rcl will read and clear in a loop\n");
    printf ("       w write shared memory with current time\n");
    printf ("       snnnn set nsamples to nnn\n");
    printf ("       lnnnn set leap to nnn\n");
    printf ("       pnnnn set precision to -nnn\n");
    exit (0);
  }
  switch (argv[1][0]) {
    case 's': {
      p->nsamples=atoi(&argv[1][1]);
    }
    break;
    case 'l': {
      p->leap=atoi(&argv[1][1]);
    }
    break;
    case 'p': {
      p->precision=-atoi(&argv[1][1]);
    }
    break;
    case 'r': {
      char *ap=&argv[1][1];
      int clear=0;
      int loop=0;
      printf ("reader\n");
      while (*ap) {
        switch (*ap) {
          case 'l' : loop=1; break;
          case 'c' : clear=1; break;
        }
        ap++;
      }
      do {
        printf ("mode=%d, count=%d, clock=%d.%d, rec=%d.%d,\n",
          p->mode,p->count,p->clockTimeStampSec,p->clockTimeStampUSec,
          p->receiveTimeStampSec,p->receiveTimeStampUSec);
        printf ("  leap=%d, precision=%d, nsamples=%d, valid=%d\n",
          p->leap, p->precision, p->nsamples, p->valid);
        if (!p->valid)
          printf ("***\n");
        if (clear) {
          p->valid=0;
          printf ("cleared\n");
        }
        if (loop)
          sleep (1);
      } while (loop);
    }
    break;
    case 'w': {
      printf ("writer\n");
      p->mode=0;
      if (!p->valid) {
        p->clockTimeStampSec=time(0)-20;
        p->clockTimeStampUSec=0;
        p->receiveTimeStampSec=time(0)-1;
        p->receiveTimeStampUSec=0;
        printf ("%d %d\n",p->clockTimeStampSec, p->receiveTimeStampSec);
        p->valid=1;
      }
      else {
        printf ("p->valid still set\n"); // not an error!
      }
    }
    break;
  }
}
