
/*
 *
 */
//#include <forms.h>// for devel machine
//#include <flimage.h> // for devel machine
#include "/usr/include/forms.h" // for SPUPUNIC
#include "/usr/local/xforms-1.2.4/image/flimage.h"// for SPUPUNIC
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <pthread.h>

#include "SxSDK.h"
#include "gui.c"

#define HEIGHT 291
#define WIDTH 752

long LUT_high = 65536;
long LUT_low = 0;
long lookup[65536] ;
long image_raw[HEIGHT*2][WIDTH] ;
long G_slide_val_up = 65536;
long G_slide_val_bot = 0 ;
double cgamma = 1.0 ;
long bright = 1 ;
long backgrd = 1 ;

pthread_t thread1,thread2 ; // eposure thread
int ext_prog=0 ; // flag to exit program
int ext_continous =0; // flag to exit continous exposures
int pan_x, pan_y, zm = 0 ;
int safe_to_exit = 1;

int new_image_ready=0;
int maxpix=0,minpix=65500.; // 

int binning = 2 ;

struct detector_struct { // structure of arguments for instance of the detector class
  float exptime;
  int rowBin;
  int colBin;
  void *handle;
  int width;
  int height;
  //  unsigned short pixelsA[WIDTH * HEIGHT];
  //  unsigned short pixelsB[WIDTH * HEIGHT];
};
struct detector_struct detector_args;






//  writes camera image to ra arrar and array for displaying   1X1 binning
void
write_pgm1X1(unsigned short *pxA,
	  unsigned short *pxB,
	  unsigned width,
	  unsigned height)
{
  FILE *output_fp;
  long image_raw_bright_backgrd ;
//  int i, j;
  
  maxpix=0; // get rid of maxpix at some stage ... left over from testing  
  minpix=65500;
  output_fp = fopen("test.pgm", "w");
  
  //  printf("P2\n%d %d\n65535", width, height*2);
  fprintf(output_fp,"P2\n%d %d\n65535", width, height*2);
  
  unsigned h;
  for (h = 0; h < height; h++) {
    unsigned w;
    for (w = 0; w < width; w++) {
      //      printf("%c%d", (w) ? ' ' : '\n', pxA[width * h + w]);
      fprintf(output_fp,"%c%d", (w) ? ' ' : '\n', pxA[width * h + w]);
      if  (pxA[width * h + w] > 65000) pxA[width * h + w] = 65000 ;
      image_raw[h*2][w] = pxA[width * h + w] ; // keep a global copy of raw image as displayed image undergoes lookup scling
      image_raw_bright_backgrd = image_raw[h*2][w] - backgrd; // subtract the background 
      if (  image_raw_bright_backgrd < 0 )       image_raw_bright_backgrd = 0;
      image_raw_bright_backgrd = image_raw_bright_backgrd * bright ; //and  mult by bright ... also done in lookup_update
      if (  image_raw_bright_backgrd > 65000 )       image_raw_bright_backgrd = 65000;
      fd_mainform->image->gray[h*2][w] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects
//      fd_mainform->image->gray[h*2][w] = lookup[image_raw[h*2][w]]; // copy raw image onto display image with lookup effects

      if (pxA[width * h + w] > maxpix) maxpix = pxA[width * h + w] ;
      if (pxA[width * h + w] < minpix) minpix = pxA[width * h + w] ;
    }
    for (w = 0; w < width; w++) {
      //      printf("%c%d", (w) ? ' ' : '\n', pxB[width * h + w]);
      fprintf(output_fp,"%c%d", (w) ? ' ' : '\n', pxB[width * h + w]);
      if  (pxB[width * h + w] > 65000) pxB[width * h + w] = 65000 ;
      image_raw[(h*2)+1][w] = pxB[width * h + w] ;  // keep a global copy of raw image as displayed image undergoes lookup scling
      image_raw_bright_backgrd = image_raw[(h*2)+1][w] - backgrd; // subtract the background .. mult by bright ... also done in lookup_update
      if (  image_raw_bright_backgrd < 0 )       image_raw_bright_backgrd = 0;
      image_raw_bright_backgrd = image_raw_bright_backgrd * bright ; //and  mult by bright ... also done in lookup_update
      if (  image_raw_bright_backgrd > 65000 )       image_raw_bright_backgrd = 65000;
      fd_mainform->image->gray[(h*2)+1][w] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects
//      fd_mainform->image->gray[(h*2)+1][w] = lookup[image_raw[(h*2)+1][w]]; // copy raw image onto display image with lookup effects

      if (pxB[width * h + w] > maxpix) maxpix = pxB[width * h + w] ;
      if (pxB[width * h + w] < minpix) minpix = pxB[width * h + w] ;

    }
  }

  
  //  printf("\n");
  fprintf(output_fp,"\n");
  fclose(output_fp);

  return;  
}

//  writes camera image to ra arrar and array for displaying  2X2 binning
void
write_pgm2X2(unsigned short *pxA,
	  unsigned short *pxB,
	  unsigned width,
	  unsigned height)
{
  FILE *output_fp;
  long image_raw_bright_backgrd ;
//  int i, j;
  
  maxpix=0; // get rid of maxpix at some stage ... left over from testing  
  minpix=65500;
  output_fp = fopen("test.pgm", "w");
  int xstep_bin=0;
  int ystep_bin=0;
  //  printf("P2\n%d %d\n65535", width, height*2);
  //  fprintf(output_fp,"P2\n%d %d\n65535", width, height*2);
  
  unsigned h;
  for (h = 0; h < (height); h++) {
    unsigned w;
    xstep_bin=0;
    for (w = 0; w < (width); w++) {
      //      printf("%c%d", (w) ? ' ' : '\n', pxA[width * h + w]);
      fprintf(output_fp,"%c%d", (w) ? ' ' : '\n', pxA[width * h + w]);
      if  (pxA[width * h + w] > 65000) pxA[width * h + w] = 65000 ;

      image_raw[h+ystep_bin][w+xstep_bin] = pxA[width * h + w] ; // keep a global copy of raw image as displayed image undergoes lookup scling  --------RAW IMAGE ARRAY-----------
      image_raw[h+ystep_bin+1][w+xstep_bin] = pxA[width * h + w] ; // keep a global copy of raw image as displayed image undergoes lookup scling  --------RAW IMAGE ARRAY-----------
      image_raw[h+ystep_bin][w+xstep_bin+1] = pxA[width * h + w] ; // keep a global copy of raw image as displayed image undergoes lookup scling  --------RAW IMAGE ARRAY-----------
      image_raw[h+ystep_bin+1][w+xstep_bin+1] = pxA[width * h + w] ; // keep a global copy of raw image as displayed image undergoes lookup scling  --------RAW IMAGE ARRAY-----------

      image_raw_bright_backgrd = image_raw[h+ystep_bin][w+xstep_bin] - backgrd; // subtract the background 
      if (  image_raw_bright_backgrd < 0 )       image_raw_bright_backgrd = 0;

      image_raw_bright_backgrd = image_raw_bright_backgrd * bright ; //and  mult by bright ... also done in lookup_update
      if (  image_raw_bright_backgrd > 65000 )       image_raw_bright_backgrd = 65000;

      //      fd_mainform->image->gray[h*1][w] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects -----DISPLAY IMAGE ARRAY---------
      fd_mainform->image->gray[h+ystep_bin][w+xstep_bin] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects -----DISPLAY IMAGE ARRAY---------
      fd_mainform->image->gray[h+ystep_bin+1][w+xstep_bin] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects -----DISPLAY IMAGE ARRAY---------
      fd_mainform->image->gray[h+ystep_bin][w+xstep_bin+1] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects -----DISPLAY IMAGE ARRAY---------
      fd_mainform->image->gray[h+ystep_bin+1][w+xstep_bin+1] = lookup[image_raw_bright_backgrd]; // copy raw image onto display image with lookup effects -----DISPLAY IMAGE ARRAY---------


      if (pxA[width * h + w] > maxpix) maxpix = pxA[width * h + w] ;
      if (pxA[width * h + w] < minpix) minpix = pxA[width * h + w] ;

      xstep_bin = xstep_bin +1;
    }
    ystep_bin = ystep_bin +1;
  }

  
  //  printf("\n");
  fprintf(output_fp,"\n");
  fclose(output_fp);

//  printf("end of write pgm\n") ;  

  return;  
}





//========================================
// function called as a thread2 by expose_cb     .... for 2X2 binning
//===========================================
 void *do_exposure2X2(void *arguments ) {
   struct detector_struct *args = (struct detector_struct *)arguments;
   unsigned short pixelsA[(WIDTH/2) * HEIGHT], pixelsB[WIDTH * HEIGHT];;

//    printf("start of do_exposure\n") ;   
   do { // this thread2 will loop ininfitely until ext_continous is set to 1
     
     safe_to_exit = 0 ; // not safe to exit software until current exposure has read out
     sxExposePixels( (void **)args->handle,3, 0, 0, 0, (int)args->width/1, (int)args->height, 2, 1, (float)args->exptime); // non-blocking, 
//     usleep((float)args->exptime * 1000); // above exposure is non-blocking so need to put in a usleep for this thread2 ... removed 15 Oct 2019
     
     sxReadPixels( (void **)args->handle, pixelsA, (int)args->width/1 * (int)args->height);
     
     write_pgm2X2(pixelsA , pixelsB, WIDTH/2, HEIGHT);
     new_image_ready=1; // this will activate the plot image in main
     //        printf("end of do_exposure\n") ; 
     usleep(300000); // to avoid a race condition in main
     safe_to_exit = 1 ; // now safe to exit software as current exposure has read out
   } while (!ext_continous ) ;
   //    printf("end of do_exposure thread2\n") ; 
   pthread_exit((void*) arguments); 
   
   return(0);
 }


//=====================================
// function called as a thread by expose_cb     .... for 1X1 binning
//=====================================
 void *do_exposure1X1(void *arguments ) {
   
   struct detector_struct *args = (struct detector_struct *)arguments;
   unsigned short pixelsA[WIDTH * HEIGHT], pixelsB[WIDTH * HEIGHT];;
   
   //    printf("start of do_exposure\n") ;   
   do { // this thread will loop ininfitely until ext_continous is set to 1
     
     safe_to_exit = 0 ; // not safe to exit software until current exposure has read out
     sxExposePixels( (void **)args->handle,CCD_EXP_FLAGS_FIELD_ODD, 0, 0, 0, (int)args->width, (int)args->height, 1, 1, (float)args->exptime); // non-blocking, 
//     usleep((float)args->exptime * 1000); // above exposure is non-blocking so need to put in a usleep for this thread... removed 15 Oct 2019
     
     sxReadPixels( (void **)args->handle, pixelsA, (int)args->width * (int)args->height);
     
     sxExposePixels( (void **)args->handle, CCD_EXP_FLAGS_NOCLEAR_FRAME | CCD_EXP_FLAGS_FIELD_EVEN, 0, 0, 0, (int)args->width, (int)args->height, 1, 1, 0); // non-blocking, 
     sxReadPixels( (void **)args->handle, pixelsB, (int)args->width * (int)args->height);
     
     unsigned h; // rescale pixelsA to compensate for extended exposure time of EVEN rows
     for (h = 0; h < HEIGHT; h++) {
       unsigned w;
       for (w = 0; w < WIDTH; w++) {
	 pixelsA[WIDTH * h + w] = lrint(pixelsA[WIDTH * h + w]*(1.+(100./(float)args->exptime) ) );
	 //	pixelsA[WIDTH * h + w] =0.0;
       }
     }
     
     write_pgm1X1(pixelsA , pixelsB, WIDTH, HEIGHT); //2X2
     new_image_ready=1; // this will activate the plot image in main
     //        printf("end of do_exposure\n") ; 
     usleep(300000);// to avoid a race condition in main
     safe_to_exit = 1 ; // now safe to exit software as current exposure has read out
   } while (!ext_continous ) ;
   //    printf("end of do_exposure thread\n") ; 
   pthread_exit((void*) arguments); 
   
   return(0);
 }
 
//=======================
//expose button callback
// =========================
 void expose_cb(FL_OBJECT *ob, long arg)
 {
   
   if (safe_to_exit){ // wil only start and exposure if continous thread has finsihsed
     if(detector_args.exptime < 1000) { // cant seem to put this xforms timed in the do_exposure thread ... it crashes the program
       fl_set_timer(fd_mainform->timer, (double) (detector_args.exptime/1000.)) ; /* start GUI timer, countdown fractions of seconds        */
     } else {
       //       fl_set_timer(fd_mainform->timer,(double)(expose_time/1000.)) ; /* start GUI timer, countdown seconds        */
       fl_set_timer(fd_mainform->timer, (double) (detector_args.exptime/1000.)) ; /* start GUI timer, countdown seconds        */
     }
     //  printf("expose_cb \n") ;   
     ext_continous = 1 ; //global variable
     
     
     if (binning == 1) {
       pthread_create( &thread1, NULL, do_exposure1X1, (void *) &detector_args); // 1x1 binning
     }
     
     if (binning == 2) {
       pthread_create( &thread2, NULL, do_exposure2X2, (void *) &detector_args); // 2x2 binning
     }
   }
   return;
 }

//==========================
//bin1X1 button callback
//=============================
 void bin1X1_cb(FL_OBJECT *ob, long arg)
 {
   binning = 1;
   ext_continous = 1 ; //global variable .... stop any ongoing continous exposure ... new binning comes into effect on next exposure
   return;
 }
 
//=========================
//bin2X2 button callback
//==========================
void bin2X2_cb(FL_OBJECT *ob, long arg)
 {
   binning = 2;
   ext_continous = 1 ; //global variable .... stop any ongoing continous exposure ... new binning comes into effect on next exposure
   return;
 }
 
//================================
//continous expose button callback
//===============================
void cont_expose_cb(FL_OBJECT *ob, long arg)
{

  if (safe_to_exit){ // wil only start and exposure if continous thread has finsihsed
    
    if(detector_args.exptime < 1000) {
      fl_set_timer(fd_mainform->timer, (double) (detector_args.exptime/1000.)) ; /* start GUI timer, countdown fractions of seconds        */
    } else {
      //       fl_set_timer(fd_mainform->timer,(double)(expose_time/1000.)) ; /* start GUI timer, countdown seconds        */
      fl_set_timer(fd_mainform->timer, (double) (detector_args.exptime/1000.)) ; /* start GUI timer, countdown seconds        */
    }
    
    ext_continous = 0 ; //global variable
    
    
    if (binning == 1) {
      pthread_create( &thread1, NULL, do_exposure1X1, (void *) &detector_args); // 2x2 binning
    }
    
    if (binning == 2) {
      pthread_create( &thread2, NULL, do_exposure2X2, (void *) &detector_args);
    }
  } 
  return;
}

//=========================================
//stop continous expose button callback
//=========================================
void stop_cont_expose_cb(FL_OBJECT *ob, long arg)
{

  ext_continous = 1 ; //global variable

  return;
}

//=========================================
//abort expose button callback .. readout immediatlty and stop xposure and continous ... need to also kill thread(not yet done) esle it will continue and readout upon end of exposure
//=========================================
void abort_expose_cb(FL_OBJECT *ob, long arg)
{


  //  unsigned short pixelsA[(WIDTH/2) * HEIGHT], pixelsB[WIDTH * HEIGHT];;
  //  ext_continous = 1 ; //global variable to stop continous exposures in do_exposure

  // do 0 secs exposure and readout in order to abort any ongoing exposure
  //  sxExposePixels(detector_args.handle,3 , 0, 0, 0, WIDTH/1, HEIGHT, 1, 1, 0); // non-blocking, 
  //  sxReadPixels(detector_args.handle, pixelsA, (WIDTH/1) * HEIGHT/1);
  //  write_pgm2X2(pixelsA , pixelsB, WIDTH/2, HEIGHT);

  // this is still bugy

  return;


}


/************************
exit button callback
******************/
void ext_prog_cb(FL_OBJECT *ob, long arg) // need to issue abort exposure and possibly kill thread commands in order to make clean exit and not leave camera in a crashed state
{

  //  unsigned short pixelsA[WIDTH * HEIGHT], pixelsB[WIDTH * HEIGHT];;

  // do 0 secs exposure and readout in order to abort any ongoing exposure ... need to send this as a thread probably, i think
  //  sxExposePixels(detector_args.handle, CCD_EXP_FLAGS_NOCLEAR_FRAME | CCD_EXP_FLAGS_FIELD_ODD, 0, 0, 0, WIDTH/1, HEIGHT, 1, 1, 0); // non-blocking, 
  //  sxReadPixels(detector_args.handle, pixelsA, (WIDTH/1) * HEIGHT/1);
  //  sxExposePixels(detector_args.handle, CCD_EXP_FLAGS_NOCLEAR_FRAME | CCD_EXP_FLAGS_FIELD_EVEN, 0, 0, 0, WIDTH/1, HEIGHT, 1, 1, 0); // non-blocking, 
  //  sxReadPixels(detector_args.handle, pixelsB, (WIDTH/1) * HEIGHT/1);
  //  write_pgm(pixelsA , pixelsB, WIDTH, HEIGHT);

  ext_continous = 1 ; //global variable to stop continous exposures in do_exposure
  ext_prog = 1 ; //global variable to exit program in main
  return;
}


/************************
called by slider callbacks to apply new lookup values
******************/

void lookup_update(void)
{

  long i, d, j;
  long image_raw_bright_backgrd ;
//  printf("LUT_high = %ld\n", LUT_high) ;

  // lut_low is always =0
  // lut_high is always = 65536
  
  d = G_slide_val_up - (LUT_low + G_slide_val_bot)  ;
  //  max =  (LUT_high - LUT_low) ; 
  if(d > 0) {
    for ( i=0 ; i < 65536; i++ ) {
      if ( i < (LUT_low + G_slide_val_bot) ) 
	lookup[i] = 0 ;
      else if ( i > G_slide_val_up) {
	lookup[i] = 65536 ;
      } else {
	//	lookup[i] = (i - LUT_low) ;
	lookup[i] = (long) (((double)(i-G_slide_val_bot)/ (double)(G_slide_val_up-G_slide_val_bot)) * (double)LUT_high)  ; // have to do fractional calc first because i*LUT_high is too big a number
	lookup[i] =  LUT_high * pow(lookup[i],cgamma) / pow(LUT_high,cgamma) ;
	//	printf("lookup= %ld %ld %ld  \n",i, lookup[i], G_slide_val_up) ;  
      } 
    }
  }
  
  
  
  if(d < 0) { // !!! NOT FIXED THIS YET ... .WHEN sliders are swapped min, max to reverse/invert colour table
    for ( i=0 ; i < 65536; i++ ) {
      if ( i <= (G_slide_val_up)) 
	lookup[i] = 65536 ;
      else if ( i > G_slide_val_bot)
	lookup[i] = 0 ;
      else {
	lookup[i] = (long) (((double)(i-G_slide_val_up)/ (double)(G_slide_val_up-G_slide_val_bot)) * (double)LUT_high)  ; // have to do fractional calc first because i*LUT_high is too big a number
      }
      /*                  lookup[i] = (255*(ln_low - i))/abs(d) ; */
    }
  }



  /* Set LUT gray image */  
  for ( j=0; j < fd_mainform->lut->h; j++) {
    for ( i=0; i < IMAGE_W; i++) {
      fd_mainform->lut->gray[j][i] = lookup[(long) (65536*( (double)i/(double)IMAGE_W ) )] ;
    }
  }

  
  fd_mainform->lut->modified = 1 ;
//  flimage_display(fd_mainform->lut, FL_ObjWin(fd_mainform->clut)) ;
  
  
  /* Apply LUT to camera gray image */  
  for ( j=0; j < fd_mainform->image->h; j++) {
    for ( i=0; i < fd_mainform->image->w; i++) {
// backgrd subtracted and bright here and in write_pgm

        image_raw_bright_backgrd = image_raw[j][i] - backgrd; // subtract the background 
        if (  image_raw_bright_backgrd < 0 )       image_raw_bright_backgrd = 0;
        image_raw_bright_backgrd = image_raw_bright_backgrd * bright ; //and  mult by bright ... also done in lookup_update
        if (  image_raw_bright_backgrd > 65000 )       image_raw_bright_backgrd = 65000;
        fd_mainform->image->gray[j][i] = lookup[image_raw_bright_backgrd] ; 


      //  fd_mainform->image->gray[j][i] = lookup[image_raw[j][i]] ; 
      //      printf("lookup = %ld %ld %ld %ld\n",j,i,lookup[fd_mainform->image->gray[j][i]], lookup[image_raw[j][i]]);

    }
  }
  
  fd_mainform->image->modified = 1 ;
  flimage_display(fd_mainform->image, FL_ObjWin(fd_mainform->image_canvas)) ; 

  return;  
}


/************************
LUT upper slide  callback ... change the lookup table AND the grey scale bar image
******************/

void SliderUP_cb(FL_OBJECT *obj, long dud)
{

  G_slide_val_up = (long)fl_get_slider_value(obj) ;
  lookup_update();
//  printf("slider up LUT_high = %ld\n", LUT_high) ;
  return;  
}

/************************
LUT lowere slide  callback ... change the lookup table AND the grey scale bar image
******************/

void SliderBOT_cb(FL_OBJECT *obj, long dud)
{

  G_slide_val_bot = (long)fl_get_slider_value(obj) ;
  lookup_update();
  //  printf("LUT_high = %ld\n", LUT_high) ;
  return;  
}


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                                   Slider

                  Slider gamma value selection for current LUT.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

void Slidergam_cb(FL_OBJECT *obj, long d)
{
  int k; //,knew ;i,j,
  //  unsigned char look[256] ;

/* Get the value */
  k = fl_get_slider_value(obj) ;


  if (k>=50) {  
    cgamma=(k-50.)/2. ;
    cgamma=cgamma+1.;
  }
  if ( k < 50) {
    cgamma=(50.-k)/50. ;
    cgamma=1.-cgamma;
  }  

  printf("slidergam= %i %f \n",k, cgamma);  
  /* Scroll the LUT indices */
  //      linear(fd_mainform);
  lookup_update();
  return;  
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                                   Slider

                  Slider brighness value applied to image
Note that gamma and bot up sliders are applied tolookup table and not image
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

void Sliderbright_cb(FL_OBJECT *obj, long d)
{

/* Get the value */
  bright = fl_get_slider_value(obj)/5 ; // goes from 1-100.. defined in gui.c

  printf("sliderbright= %li \n", bright);  
  lookup_update(); 
// brighness value is applied when image read out and in lookup_update to the image_raw
  return;  
}






/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                  SET_EXPTIME_CB
	     Read exposure time input field and set AAG camera 
             exposure time to user input value
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

void set_exptime_cb( FL_OBJECT *obj, long arg )
{
  //  char tmp[80];
  double t ;

   sscanf(fl_get_input(fd_mainform->set_exptime_inp),"%lf", &t ) ;          /* read input field for exposure time */
   detector_args.exptime = 1000.0*t;
   //   exptime = 1000.0*t ;                                       /*  for t < 1, showsec uses exptime variable        */
//   printf("Exposures time is now! %f", detector_args.exptime );

   return;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                  SET_BACKGRD_CB
	     Read exposure time input field 
            and set global background value to be subtracted from image
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

void set_backgrd_cb( FL_OBJECT *obj, long arg )
{

  long t ;

   sscanf(fl_get_input(fd_mainform->set_backgrd_inp),"%li", &t ) ;          /* read input field for exposure time */
   backgrd = t ;
   printf("backgrd is now! %li", backgrd );
   lookup_update(); 
// backgrd value is applied when image read out and in lookup_update to the image_raw

   return;
}


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                                 CANVAS_XYZ

             Called when the mouse pointer is in the image area.  
               Picks out (X,Y) coordinates and image intensity.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

int 
canvas_xyz(FL_OBJECT *obj, Window win, int w, int h, XEvent *ev, void *d)
{
    FD_mainform *ui = d;
    char buf[128];
    int xp, yp, zp;// xpos, ypos  ;
    unsigned key ;


/* Get pointer position */
    fl_get_win_mouse(FL_ObjWin(obj), &xp, &yp, &key ) ;


    //    xpos = xp;
    //    ypos = yp;

    //    printf("canvas_xyz0 %s %s  \n", xpos, ypos); 

    //    xp = (xp - bx)/ax ;
    //    yp = (yp - by)/ay ;
    //    zp = 0 ;
    //    printf("canvas_xyz 1 \n"); 
    if ( (xp > 0)&&(xp < IMAGE_W) ) { //  sometimes xp or yp can be out of range and cause program to crash... i think
        if ( (yp > 0)&&(yp < IMAGE_H) ) {
            zp = image_raw[yp][xp] ;
            sprintf(buf,"%d %d %d", xp/2, yp/2, zp ) ;
	    fl_set_object_label(ui->xyz_text, buf) ; 
	      //	    }
        }
    }

    return 0;
}


//***********************************

//Scale gamma and brightness according to mouse positon on canvas

//*********************************

static int post(FL_OBJECT *ob, int ev, 
		FL_Coord mx, FL_Coord my, int key, void *xev)
{

    int k;
    //    FD_mainform *ui = d;
    //    char buf[128];
    //    int xp, yp, zp;// xpos, ypos  ;
    //    unsigned key ;

    //    if(ev == FL_PUSH || ev == FL_MOUSE){
    if(ev == FL_PUSH || ev == FL_MOUSE){
      //      sprintf(buf,"%d %d ", mx, my ) ;
      ob->wantkey = FL_KEY_ALL; // this does nothing??
        ob->input = 1; // this does nothing??
      bright = my/ 30 ;
      if (bright > 100) bright = 100;
      if (bright < 1) bright = 1;

      //      k = (mx - 50)/75;
      k = mx/10;
      

      if (k < 1) k =1;
      if (k > 180) k =180;

      if (k>=50) {  
	cgamma=(k-50.)/2. ;
	cgamma=cgamma+1.;
      }
      if ( k < 50) {
	cgamma=(50.-k)/50. ;
	cgamma=1.-cgamma;
      }  
      //      sprintf(buf,"%d %d ", mx,my ) ;
      //      fl_set_object_label(ui->xyz_text, buf) ; 
      //      printf("bright, k(gam)= %li %i \n",bright, k);        
      lookup_update();

/* Get pointer position */
//    fl_get_win_mouse(FL_ObjWin(ob), &xp, &yp, &key ) ;

    //    if ( (xp > 0)&&(xp < IMAGE_W) ) { //  sometimes xp or yp can be out of range and cause program to crash... i think
    //        if ( (yp > 0)&&(yp < IMAGE_H) ) {
    //            zp = image_raw[yp][xp] ;
    //            sprintf(buf,"%d %d %d", xp/2, yp/2, zp ) ;
    //	    fl_set_object_label(ui->xyz_text, buf) ; 
    //        }
    //    }


      
      //  fl_set_object_label(ob->xyz_text, buf) ; 
    }
    return 0 ;
}
/*************************************************************************************/



int main(int argc, char *argv[])
{
  void *handle[20];
  int i, j;
  long k ;
  //  unsigned short pixelsA[(WIDTH/1) * HEIGHT/1], pixelsB[(WIDTH/1) * HEIGHT/1];;

  
  
  

  
  fl_set_border_width(-3) ;                                             /* initialize XFORMS */
  fl_initialize(&argc, argv, 0, 0, 0);
  fd_mainform = create_form_mainform();
  fl_freeze_form(fd_mainform->mainform) ;
  fl_show_form(fd_mainform->mainform,FL_PLACE_GEOMETRY,FL_FULLBORDER,	"Potter's linux lodestar GUI"); 
  fl_unfreeze_form(fd_mainform->mainform);                       
  

  fd_mainform->image = flimage_alloc() ; // setup memory and image array for image
  fd_mainform->image->type =   FL_IMAGE_GRAY16;
  //  fd_mainform->image->type =   FL_IMAGE_CI;
  fd_mainform->image-> gray_maxval =   65536;
  fd_mainform->image->w = IMAGE_W ;
  fd_mainform->image->h = IMAGE_H ;
  fd_mainform->image->wx = 0 ;
  fd_mainform->image->wy = 0 ;
  fd_mainform->image->app_background = 0 ;
  //  fd_mainform->image->double_buffer = 1 ;
  flimage_getmem(fd_mainform->image) ;


  fd_mainform->lut = flimage_alloc() ; // setup memory and image array for lookup ytable
  fd_mainform->lut->type = FL_IMAGE_GRAY16 ;
  //  fd_mainform->image->type =   FL_IMAGE_CI;
  fd_mainform->lut-> gray_maxval =   65536;
  fd_mainform->lut->w = IMAGE_W ;
  fd_mainform->lut->h = LUT_H ;
  fd_mainform->lut->wx = 0 ;
  fd_mainform->lut->wy = 0 ;
  fd_mainform->lut->app_background = 0 ;
  flimage_getmem(fd_mainform->lut) ;
/* Set LUT gray image */  
  for ( j=0; j < fd_mainform->lut->h; j++) {
    for ( i=0; i < fd_mainform->lut->w; i++) {
      k = 65536*i/IMAGE_W ;
       fd_mainform->lut->gray[j][i] = k ; 
    }
  }
/* Set LUT gray lookup table ... linear to start with */  
  for ( k=0; k < 65536; k++) {
    lookup[k] = k;
    //    printf("lookup= %ld %ld   \n",k, lookup[k]) ;  
  }
  fd_mainform->lut->modified = 1 ;
//  flimage_display(fd_mainform->lut, FL_ObjWin(fd_mainform->clut)) ;

  /* initial image for display */  
  for ( j=0; j < fd_mainform->image->h; j++) {
    for ( i=0; i < fd_mainform->image->w; i++) {
      //        image_raw[j][i]= i+ j ;
        image_raw[j][i]= 0 ;
        fd_mainform->image->gray[j][i] = i+j+1234 ;
    }
  }
  fd_mainform->image->modified = 1 ;
  flimage_display(fd_mainform->image, FL_ObjWin(fd_mainform->image_canvas)) ; 


    
// deactivated this as I think it intermitantly crashes software    
//  fl_add_canvas_handler(fd_mainform->image_canvas, MotionNotify,canvas_xyz,fd_mainform); // to print out xyz of mouse in image area
//  fl_add_canvas_handler(fd_mainform->image_canvas, ButtonPress,canvas_xyz,fd_mainform); // to print out xyz of mouse in image area

  fl_set_object_posthandler(fd_mainform->image_canvas, post); // to scale brightness and gamma from mouse pointer position

  printf("Disconnect then re-connect guide camera usb port if stuck here \n"); 
  int count = sxOpen((void **)&handle); // open connection to camera through USB
  if (0 >= count) {
    printf("init USB lodestar handle, camera not found \n");   
    errx(EXIT_FAILURE, "camera not found");
  }
  
  
  detector_args.exptime = 2000.0;
  detector_args.rowBin = 1; // havent used this
  detector_args.colBin = 1;// havent used this
  detector_args.handle = handle[0];
  detector_args.width = WIDTH;
  detector_args.height = HEIGHT;  
  
  

  //  pthread_join(thread1,NULL); // pauses until thread1 has fininshed
  

  while (!ext_prog || !safe_to_exit ) {

    
    fl_check_forms() ;


    if (new_image_ready){ // display the just read out image
//        printf("In new image%d\n", maxpix) ; // get rid of maxpix at some stage ... left over from testing  
        fd_mainform->image->modified = 1 ;
        flimage_display(fd_mainform->image, FL_ObjWin(fd_mainform->image_canvas)) ; 
        new_image_ready=0;
//        printf("Leave new image\n") ;  
        if (!ext_continous ) {  // can't put this xforms "set timer" going in the expose thread because it crahses the program
            if(detector_args.exptime < 1000) {
                fl_set_timer(fd_mainform->timer, (double) (detector_args.exptime/1000.)) ; /* start GUI timer, countdown fractions of seconds        */
            } else {
                //       fl_set_timer(fd_mainform->timer,(double)(expose_time/1000.)) ; /* start GUI timer, countdown seconds        */
                fl_set_timer(fd_mainform->timer, (double) (detector_args.exptime/1000.)) ; /* start GUI timer, countdown seconds        */
            }
            
        }
        
    }
//    usleep(300000);
//    printf("in main ext_prog loop here \n"); 
  }
  
  sxClose(handle[0]);
  
  printf("Exiting\n") ;  
  
  
  if (EOF == fclose(stdout)) {
    err(EXIT_FAILURE, "writing output");
  }  
  
  
  exit(EXIT_SUCCESS);
}

