/*  Apogee Control Library

Copyright (C) 2001-2006 Dave Mills  (rfactory@theriver.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/
// CameraIO.cpp: implementation of the CCameraIO class.
//
//////////////////////////////////////////////////////////////////////

#include <assert.h>
#include <sys/io.h>                                                           
#include <sys/time.h>                                                           
#include <sys/resource.h>                                                           
#include <sys/ioctl.h>
#include <string.h>                                                           
#include <sched.h>                                                           
#include <unistd.h>                                                           
#include <fcntl.h>                                                           
#include <stdio.h>
#define HANDLE int
#define FALSE 0
#define DWORD long
#define _ASSERT assert
#define REALTIME_PRIORITY_CLASS 1  
#define GetCurrentProcess getpid
#define LOBYTE(x) ((x) & 0xff)
#define HIBYTE(x) ((x >> 8) & 0xff)

#define MIRQ1	0x21
#define MIRQ2	0xA1

#include "time.h"
//#include "tcl.h"
//#include "ccd.h"
#include "CameraIO_Linux.h"
#include "ApogeeLinux.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

void CCameraIO::InitDefaults()
{
	////////////////////////////////////////////////////////////
	// Camera Settings
		
		m_HighPriority = true;
		m_PPRepeat = 1;	
		m_DataBits = 16;	
		m_FastShutter = false;
		m_MaxBinX = 8;
		m_MaxBinY = 63;
		m_MaxExposure = 10485.75;
		m_MinExposure = 0.01;
		m_GuiderRelays = false;
		m_Timeout = 2.0;

	////////////////////////////////////////////////////////////
	// Cooler Settings

		m_TempControl = true;
		m_TempCalibration = 160;
		m_TempScale = 2.1;	
		
	////////////////////////////////////////////////////////////
	// Exposure Settings

		m_BinX = 1;
		m_BinY = 1;		
		m_StartX = 0;
		m_StartY = 0;	
		m_NumX = 1;
		m_NumY = 1;		
	
	////////////////////////////////////////////////////////////
	// Geometry Settings
	
		m_Columns = 0;
		m_Rows = 0;	
		m_SkipC = 0;
		m_SkipR = 0;		
		m_HFlush = 1;
		m_VFlush = 1;	
		m_BIC = 4;
		m_BIR = 4;			
		m_ImgColumns = 0;
		m_ImgRows = 0;

	////////////////////////////////////////////////////////////
	// CCD Settings
		
		memset( m_Sensor, 0, 256 );
		m_Color = false;
		m_Noise = 0.0;				
		m_Gain = 0.0;				
		m_PixelXSize = 0.0;		
		m_PixelYSize = 0.0;		

	////////////////////////////////////////////////////////////
	// Internal variables

                fileHandle = 0;
		m_RegisterOffset = 0;
		m_Interface = Camera_Interface_PCI;	
		m_SensorType = Camera_SensorType_CCD;
}


 
bool CCameraIO::InitDriver(unsigned short camnum) 
{ 
    char deviceName[64];

        sprintf(deviceName,"%s%d",APOGEE_PCI_DEVICE,camnum);
        fileHandle = ::open(deviceName,O_RDONLY);
        if (fileHandle == -1) return false;
	return true; 
} 
 
long CCameraIO::Write( unsigned short reg, unsigned short val ) 
{ 
        int status;
        unsigned short RegNumber;
        struct apIOparam request;

        switch ( reg )
        {
        case Reg_Command:
                RegNumber = RegPCI_Command;
                break;
        case Reg_Timer:
                RegNumber = RegPCI_Timer;
                break;
        case Reg_VBinning:
                RegNumber = RegPCI_VBinning;
                break;
        case Reg_AICCounter:
                RegNumber = RegPCI_AICCounter;
                break;
        case Reg_TempSetPoint:
                RegNumber = RegPCI_TempSetPoint;
                break;
        case Reg_PixelCounter:
                RegNumber = RegPCI_PixelCounter;
                break;
        case Reg_LineCounter:
                RegNumber = RegPCI_LineCounter;
                break;
        case Reg_BICCounter:
                RegNumber = RegPCI_BICCounter;
                break;
        default:
                _ASSERT ( false );
                return 0;
        }
        request.reg = RegNumber;
        request.param1=(int)val;
        status=ioctl(fileHandle,APPCI_WRITE_USHORT,(unsigned long)&request);
        return 0;
} 
 
long CCameraIO::Read( unsigned short reg, unsigned short& val ) 
{ 
        int retval, status;
        struct apIOparam request;
        unsigned short RegNumber;

	switch ( reg ) 
	{ 
        case Reg_Command:
                RegNumber = RegPCI_CommandRead;
                break;
        case Reg_Timer:
                RegNumber = RegPCI_TimerRead;
                break;
        case Reg_VBinning:
                RegNumber = RegPCI_VBinningRead;
                break;
        case Reg_AICCounter:
                RegNumber = RegPCI_AICCounterRead;
                break;
        case Reg_TempSetPoint:
                RegNumber = RegPCI_TempSetPointRead;
                break;
        case Reg_PixelCounter:
                RegNumber = RegPCI_PixelCounterRead;
                break;
        case Reg_LineCounter:
                RegNumber = RegPCI_LineCounterRead;
                break;
        case Reg_BICCounter:
                RegNumber = RegPCI_BICCounterRead;
                break;
        case Reg_ImageData:
                RegNumber = RegPCI_ImageData;
                break;
        case Reg_TempData:
                RegNumber = RegPCI_TempData;
                break;
        case Reg_Status:
                RegNumber = RegPCI_Status;
                break;
        case Reg_CommandReadback:
                RegNumber = RegPCI_CommandReadback;
                break;
	default: 
		assert( 1 );	// application program bug 
		val = 0; 
		return 0; 
	} 

        request.reg = RegNumber;
        request.param1=(unsigned long)&retval;
        status=ioctl(fileHandle,APPCI_READ_USHORT,(unsigned long)&request);
        val = (unsigned short)retval;
	return 0; 
} 
 
// Returns 0 if successful, 1 if Line_Done poll timed out.
long CCameraIO::ReadLine( long SkipPixels, long Pixels,unsigned short* pLineBuffer )
{ 
    int j;
    int retval, status;
    struct apIOparam request;

	if ( !m_TDI ) 
	{ 
		///////////////////////////////////// 
		// Clock out the line 
		m_RegShadow[ Reg_Command ] |= RegBit_StartNextLine;		// set bit to 1 
		Write( Reg_Command, m_RegShadow[ Reg_Command ] ); 
		 
		m_RegShadow[ Reg_Command ] &= ~RegBit_StartNextLine;	// set bit to 0 
		Write( Reg_Command, m_RegShadow[ Reg_Command ] ); 
		///////////////////////////////////// 
	} 
 
        request.reg = RegPCI_ImageData;
        request.param1=(unsigned long)&retval;

	for (j = 0; j < SkipPixels; j++) 
	{ 
             status=ioctl(fileHandle,APPCI_READ_USHORT,(unsigned long)&request);
	} 
	for (j = 0; j < Pixels; j++) 
	{ 
             status=ioctl(fileHandle,APPCI_READ_USHORT,(unsigned long)&request);
	     *pLineBuffer++ = (unsigned short)retval; 
	} 
	///////////////////////////////////// 
	// Assert done reading line 
	m_RegShadow[ Reg_Command ] |= RegBit_DoneReading;	// set bit to 1 
	Write( Reg_Command, m_RegShadow[ Reg_Command ] ); 
	 
	m_RegShadow[ Reg_Command ] &= ~RegBit_DoneReading;	// set bit to 0 
	Write( Reg_Command, m_RegShadow[ Reg_Command ] ); 
	///////////////////////////////////// 
 
	if ( !m_TDI ) 
	{ 
		///////////////////////////////////// 
		// Wait until camera is done 
		clock_t StopTime = clock() + CLOCKS_PER_SEC;	// wait at most one second 
		while ( true ) 
		{ 
			unsigned short val = 0; 
			Read( Reg_Status, val ); 
			if ( ( val & RegBit_LineDone ) != 0 ) break;// Line done 
			 
			if ( clock() > StopTime ) return 1;		// Timed out 
		} 
	} 
 
	return 0; 
} 
 

 
long CCameraIO::ReadImage( unsigned short* pImageBuffer )
{
        m_RegShadow[ Reg_Command ] |= RegBit_FIFOCache;         // set bit to 1
        Write( Reg_Command, m_RegShadow[ Reg_Command ] );

        long XEnd = long( m_ExposureNumX );
        long SkipC = long( m_ExposureSkipC );
        for (long i = 0; i < m_ExposureSkipR; i++)
        {
                if( InternalReadLine( false, SkipC, XEnd, NULL ) ) return 1;
        }

        long YEnd = long( m_ExposureNumY );
        unsigned short* pLineBuffer = pImageBuffer;
        for (long i = 0; i < YEnd; i++)
        {
                if ( InternalReadLine( true, SkipC, XEnd, pLineBuffer ) ) return 1;
                pLineBuffer += XEnd;
        }

        m_RegShadow[ Reg_Command ] &= !RegBit_FIFOCache;        // set bit to 0
        Write( Reg_Command, m_RegShadow[ Reg_Command ] );

        return 0;
}



// Returns 0 if successful, 1 if Line_Done poll timed out.
long CCameraIO::InternalReadLine( bool KeepData, long SkipC, long XEnd, unsigned short* pLineBuffer )
{
      struct apIOparam request;
      int retval, status;

        /////////////////////////////////////
        // Clock out the line
        m_RegShadow[ Reg_Command ] |= RegBit_StartNextLine;             // set bit to 1
        Write( Reg_Command, m_RegShadow[ Reg_Command ] );

        m_RegShadow[ Reg_Command ] &= !RegBit_StartNextLine;    // set bit to 0
        Write( Reg_Command, m_RegShadow[ Reg_Command ] );
        /////////////////////////////////////

        request.reg = RegPCI_ImageData;
        request.param1=(unsigned long)&retval;

        for (long j = 0; j < SkipC; j++)
             status=ioctl(fileHandle,APPCI_READ_USHORT,(unsigned long)&request);

        if ( KeepData )
        {
                for (long j = 0; j < XEnd; j++) {
                  status=ioctl(fileHandle,APPCI_READ_USHORT,(unsigned long)&request);
                  *pLineBuffer++ = (unsigned short)retval;
                }
        }
        else
        {
                for (long j = 0; j < XEnd; j++)
                  status=ioctl(fileHandle,APPCI_READ_USHORT,(unsigned long)&request);
        }

        /////////////////////////////////////
        // Assert done reading line
        m_RegShadow[ Reg_Command ] |= RegBit_DoneReading;       // set bit to 1
        Write( Reg_Command, m_RegShadow[ Reg_Command ] );

        m_RegShadow[ Reg_Command ] &= !RegBit_DoneReading;      // set bit to 0
        Write( Reg_Command, m_RegShadow[ Reg_Command ] );
        /////////////////////////////////////

        /////////////////////////////////////
        // Wait until camera is done clocking
        clock_t StopTime = clock() + CLOCKS_PER_SEC;    // wait at most one second
        while ( true )
        {
                unsigned short val = 0;
                Read( Reg_Status, val );
                if ( ( val & RegBit_LineDone ) != 0 ) break;// Line done

                clock_t CurrentTime = clock();
                if ( CurrentTime > StopTime ) return 1;         // Timed out
        }

        return 0;
}







