//
// markIV: software to download CCD data from a MarkIV ISA card and parse
//         two files containing FITS style header information, with the intent
//         of creating two FITS files containing appropriate information
// Copyright (C) 2001  Robert S. Creager
//
// E-mail: robert@carolinecreager.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//

// For linux, we need the inb macro defined from sys/io.h
#ifdef LINUX
#include <sys/io.h>
#else
#include <windows.h>
#include <winbase.h>
#endif
//
// $Name: Downfits-1_1 $
//
// $Log: tom.cpp,v $
// Revision 1.1  2002/05/27 19:32:09  robert
// Add resetting of memory address lines
//
// Revision 1.0  2002/01/06 18:12:19  robc
// First CVS entry
//                                                                         

#include <fitsio.h>
#include <longnam.h>
#include "tom.h"

void
outportb( unsigned short port,
          unsigned short value )
{
// On Linux systems, we have a macro which does the outport stuff
#ifdef LINUX
   return outb( value, port );
// This should be a Windows system
#else
   asm mov dx, port
   asm mov ax, value
   asm out dx, ax
#endif
}

unsigned char
inportb( unsigned short port )
{
// On Linux systems, we have a macro which does the inport stuff
#ifdef LINUX
   return inb( port );
// This should be a Windows system
#else
   asm mov dx, port
   asm in ax, dx
   return _AX;
#endif
}

int
main( int argc,
      char *argv[] )
{
   fitsfile *fptr[MAX_CCD];
   long naxis[2];
   unsigned short **data;
   int status = 0;
   long x, y, offset;
   int num_ccds, ccd_count;
   char plate_id[MAX_CCD];
   SPString band;

   // If no input file has been specified
   if ( ( argc != 5 ) || !( strcmp( argv[3], argv[4] ) ) )
      {
         cerr << "Usage: " << argv[0]
            << " <naxis1> <naxis2> <plate_1 file name> <plate_2 file name>" <<
            endl << "Where: " << endl <<
            "\tnaxis1 = the number columns in the image" << endl <<
            "\tnaxis2 = the number rows in the image" << endl <<
            "\tplate_1 file name = The file name to go with the data in plate_1"
            << endl <<
            "\tplate_2 file name = The file name to go with the data in plate_2"
            << endl;
         return ( 0 );
      }

   // Now use 'hard coded' plate file names
   plate_id[0] = '1';
   plate_id[1] = '2';

#ifdef LINUX
   // Grant port permissions - need suid root privy
   if ( ioperm( 0x300, 2, 1 ) )
      {
         printf
            ( "Cannot get read privledges for port 0x300 - is suid root set?\n" );
         perror( "ioperm" );
         exit( 1 );
      }
#endif

   // Initialize stuff
   num_ccds = 2;
   naxis[0] = atoi( argv[1] );
   naxis[1] = atoi( argv[2] );
   data = new unsigned short *[num_ccds];

   // For each cdd, remove the associated file name, create the fits
   // file, create the image in each fits file, and allocate the memory
   // needed to store an entire image
   for ( ccd_count = 0; ccd_count < num_ccds; ++ccd_count )
      {
         status = 0;
         remove( argv[ccd_count + 3] );

         fits_create_file( &fptr[ccd_count], argv[ccd_count + 3], &status );
         fits_report_error( stdout, status );

         fits_create_img( fptr[ccd_count], SHORT_IMG, 2, naxis, &status );
         fits_report_error( stderr, status );

// Seem to have a daylight savings problem, so don't write the date...
//      fits_write_date( fptr[ ccd_count ], &status );
//      fits_report_error( stdout, status );

         data[ccd_count] = new unsigned short[naxis[0] * naxis[1]];
      }

   // Reset the memory board address register, should fix the problem where
   // data is shifted
   outportb( 0x300, 0x80 );
   outportb( 0x300, 0x05 );
   outportb( 0x300, 0x00 );

   // This resets the ISA card's address so we'll be reading from
   // the beginning, not from where we were last reading
   outportb( 0x300, 0x1 );

   // Now we go and read all the data for each CCD
   for ( y = 0; y < naxis[1]; ++y )
      {
         offset = y * naxis[0];
         for ( x = offset; x < ( offset + naxis[0] ); ++x )
            {
               for ( ccd_count = 0; ccd_count < num_ccds; ++ccd_count )
                  {
                     data[ccd_count][x]
                        = ( ( unsigned short ) ( inportb( 0x301 ) ) << 8 );
                     data[ccd_count][x]
                        |= ( unsigned short ) ( inportb( 0x301 ) );
                  }
            }
      }

   // Here we'll write out each image, and de-allocate the
   // memory used for the CCD read
   for ( ccd_count = 0; ccd_count < num_ccds; ++ccd_count )
      {
         status = 0;
         fits_write_img( fptr[ccd_count], TSHORT, 1,
                         naxis[0] * naxis[1], data[ccd_count], &status );
         delete[]data[ccd_count];
      }

   delete[]data;

   // Try to parse the input fits file information
   parse_main( fptr, plate_id, num_ccds );

   // Close out the final fits files
   for ( ccd_count = 0; ccd_count < num_ccds; ++ccd_count )
      {
         status = 0;
         fits_close_file( fptr[ccd_count], &status );
         fits_report_error( stderr, status );
      }

   // Remove port access permissions
#ifdef LINUX
   if ( ioperm( 0x300, 2, 0 ) )
      {
         printf
            ( "Cannot release read privledges for port 0x300 - is suid root set?\n" );
         perror( "ioperm" );
         exit( 1 );
      }
#endif
   exit( 0 );
}
