/****************************************************************************************
 * Notice:  When compiling, be sure to use the flags -lX11, -lpthread and of course,    *
 *          be sure the DLP-2232PB-G is plugged into a USB port. I use:                 *
 *                                                                                      *
 *          cc -Wall -lX11 -lpthread -o mavica mavica.c                                 *
 *                                                                                      *
 *          Pin 5 (AN1) of the DLP-2232PB-G is being used for the input.  Remember, its *
 *          input impedance is quite low and a preamp may be necessary.                 *
 *                                                                                      *
 *          Edit main() to try the various capabilities.                                *
 *          The thermometer routines need a pull-up resistor.  See ds18s20 spec sheet.  *
 *                                                                                      *
 *          Study the 16F877A port specs carefully.  Different pins/ports have varied   *
 *          capabilities - Schmidtt trigger, open-collector, TTL                        *
 *                                                                                      *
 *          Written by Craig Van Degrift <craig@yosemitefoothills.com>                  *
 *                     http://yosemitefoothills.com                                     *
 *                                                                                      *
 *          This demo code is only a best effort.  Use at your own risk.                *
 *          Uncomment the function calls in main() to try the different capabilities.   *
 *                                                                                      *
 *          Consider this code a framework which will need considerable modification    *
 *          to meet the needs of a particular measurement task.                         *
 *                                                                                      *
 ****************************************************************************************/

#include <sys/select.h>    // select(), FD_ZERO, FD_SET, FD_CLR, FD_ISSET, struct fd_set
#include <fcntl.h>         // fcntl(), open() and their flags
#include <termios.h>       // termios() and its flags, cfmakeraw(), cfsetispeed(), cfsetospeed(), tcflush(), tcsetattr() 
#include <stdlib.h>        // exit()
#include <unistd.h>        // write(), read(), close(), getpid(), sleep()
#include <signal.h>        // struct sigaction, sigemptyset(), sigaddset() and related flags
#include <string.h>        // strncmp(), bzero()
#include <X11/Xutil.h>     // X windows functions
#include <stdio.h>         // printf(), sprintf(), fprintf(), fopen(), fclose(), fscanf(), rewind(), feof(), FILE
#include <sys/time.h>      // struct itimerval, struct timeval, struct timespec, setitimer(), getitimer() and related flags
#include <time.h>          // nanosleep()
#include <error.h>         // error()
#include <errno.h>         // errno, EINTR
#include <pthread.h>       // POSIX threading: create_thread(), pthread_join(), pthread_mutex_lock(), pthread_mutex_unlock()
                           // PTHREAD_MUTEX_INITIALIZER
#include <math.h>          // pow(), sqrt()


// General Declarations *****************************************************
#define TRUE  1
#define FALSE 0
const int true = TRUE;
const int false = FALSE;

struct itimerval timer;
struct itimerval start_time;
struct itimerval cur_time;

void nap(int microseconds);
void show_file_descriptor_owner_pid(int fd);
void show_file_descriptor_flags(int fd);
double time_test();

void nap(int microseconds){
  struct timespec nap_interval;
  nap_interval.tv_sec=0;
  nap_interval.tv_nsec=microseconds*1000;
  nanosleep(&nap_interval, NULL);
}

// A function to prove that the process id (pid) was set
void show_file_descriptor_owner_pid(int fd){
  int i;
  i = fcntl(fd, F_GETOWN);
  printf("File descriptor owner is %d\n",i);
}

void show_file_descriptor_flags(int fd){
  int i;
  i = fcntl(fd, F_GETFL);
  printf("fcntl result is %04X\n", i);
  if (i & O_ASYNC)
    printf("O_ASYNC is set\n");
  if (i & O_NONBLOCK)
    printf("O_NONBLOCK is set\n");
  if (i & O_RDWR)
    printf("O_RDWR is set\n");
  if (i & O_RDONLY)
    printf("O_RDONLY is set\n");
  if (i & O_WRONLY)
    printf("O_WRONLY is set\n");
  if (i & O_NOCTTY)
    printf("O_NOCTTY is set\n");
  if (i & O_CREAT)
    printf("O_CREAT is set\n");
  if (i & O_EXCL)
    printf("O_EXCL is set\n");
  if (i & O_APPEND)
    printf("O_APPEND is set\n");
  if (i & O_TRUNC)
    printf("O_TRUNC is set\n");
//  if (i & O_DIRECT)                // These are not available to
//    printf("O_DIRECT is set\n");  // application programs, only
//  if (i & O_NOATIME)              // to kernel drivers.
//    printf("O_NOATIME is set\n");
}

double time_test(){
  double duration;
  start_time.it_interval.tv_sec = 1000;
  start_time.it_interval.tv_usec = 0;
  start_time.it_value.tv_sec = 1000;
  start_time.it_value.tv_usec = 0;
  setitimer(ITIMER_REAL, &start_time, NULL);
 
  // function to be timed goes here
  
  getitimer(ITIMER_REAL, &cur_time);
  if (cur_time.it_value.tv_usec < start_time.it_value.tv_usec){
    cur_time.it_value.tv_usec += 1000;
    cur_time.it_value.tv_sec  -= 1;
  }
  duration = (double)(start_time.it_value.tv_sec  - cur_time.it_value.tv_sec )*1000000
           + (double)(start_time.it_value.tv_usec - cur_time.it_value.tv_usec);
  printf("Time test took ");
  if (duration < 1000)
    printf("%0.0f microseconds\n", duration);
  else if (duration < 1000000)
    printf("%0.3f milliseconds\n", duration/1000);
  else
    printf("%0.6f seconds\n", duration/1000000);
  return duration;
}

