	PRO MAKECDSFITS, FILENAME, RASTER, DATAWIN, PATH=PATH
;+
; Project     :	SOHO - CDS
;
; Name        :	MAKECDSFITS
;
; Purpose     :	Write CDS telemetry data to a FITS file.
;
; Explanation :	Writes a CDS raster as read from the telemetry by READ_RASTER
;		to a FITS file.
;
; Use         :	MAKECDSFITS, FILENAME, RASTER, DATAWIN
;
; Inputs      :	FILENAME = Name of the file to receive the data.  The default
;			   extension is ".fits".
;		RASTER	 = Structure variable from READ_RASTER, containing all
;			   the metadata extracted from the science telemetry
;			   stream pertaining to the raster.
;		DATAWIN  = Array from READ_RASTER, containing all the data
;			   windows.
;
; Opt. Inputs :	None.
;
; Outputs     :	None.
;
; Opt. Outputs:	None.
;
; Keywords    :	PATH	 = Directory to place the output file.  If not passed,
;			   the the file is placed in the user's current
;			   directory.
;
; Calls       :	FXHMAKE, FXADDPAR, DEC2BIN, FXBHMAKE, TRIM, CDSADDCOL, UNSIGN,
;		CDS_POINT, CDS_WAVE, CDS_TTYPE, CDSAUXEXTR, CDSWINEXTR,
;		FIND_IN_PLAN, GETCDSTIMES, GUESS_STEP, MAKECDSHEADER,
;		SENSOR_DECODE, MAKECDSQLI
;
; Common      :	FITSGEN contains the arrays WAVELENGTHS, POINTINGS, TIMES.
;
; Restrictions:	None.
;
; Side effects:	None.
;
; Category    :	Data_handling, Telemetry, I/O, FITS, CDS.
;
; Prev. Hist. :	None.
;
; Written     :	William Thompson, GSFC, 14 October 1994
;
; Modified    :	Version 1, William Thompson, GSFC, 3 July 1995
;		Version 2, William Thompson, GSFC, 2 August 1995
;			Added binning factors
;		Version 3, William Thompson, GSFC, 3 August 1995
;			Changed way FIND_IN_PLAN is called.
;		Version 4, William Thompson, GSFC, 22 August 1995
;			Added call to INS_CATALOG
;		Version 5, William Thompson, GSFC, 16 October 1995
;			Added columns for GIS parameters.
;		Version 6, William Thompson, GSFC, 15 November 1995
;			Moved call to CDS_POINT to after call to GUESS_STEP.
;		Version 7, William Thompson, GSFC, 6 March 1996
;			Fixed bug for GIS data introduced in version 4 of
;			CDSWINEXTR.
;		Version 8, William Thompson, GSFC, 12 March 1996
;			Call FIND_IN_PLAN before CDS_WAVE, so that GSET_ID is
;			placed into the RASTER structure first.
;		Version 9, William Thompson, GSFC, 13 March 1996
;			Correct bug when only one window.
;
; Version     :	Version 9, 13 March 1996
;-
;
	ON_ERROR, 2
@fitsgen.cmn
;
;  Check the number of parameters.
;
	IF N_PARAMS() NE 3 THEN MESSAGE,	$
		'Syntax:  MAKECDSFITS, FILENAME, RASTER, DATAWIN'
;
;  Get the times associated with the observation.
;
	GETCDSTIMES, RASTER, TIMES
;
;  Find the current raster in the science plan.
;
	FIND_IN_PLAN, RASTER, PLAN, RASTER_DEF
;
;  Get the wavelength information associated with the observation.
;
	CDS_WAVE, RASTER, TIMES, WAVELENGTHS
;
;  Get the mechanism step sizes.  Normally, these will be retrieved from the
;  SCI_DETAILS database.  However, GUESS_STEP is called to check the telemetry
;  against the plan, and to serve as a fallback in case a match to the science
;  plan cannot be found.
;
	GUESS_STEP, RASTER, MIRRORSTEP, SLITSTEP
	IF RASTER_DEF.RAS_ID GT 0 THEN BEGIN
		IF (RASTER_DEF.XSTEP NE MIRRORSTEP) OR			$
			(RASTER_DEF.YSTEP NE SLITSTEP) THEN CDS_MESSAGE, $
			'Raster step size of ' + TRIM(RASTER_DEF.XSTEP) + $
			'x' + TRIM(RASTER_DEF.YSTEP) +			$
			' does not agree with guess of ' +		$
			TRIM(MIRRORSTEP) + 'x' + TRIM(SLITSTEP),	$
			/CONTINUE, /ATTENTION
		MIRRORSTEP = RASTER_DEF.XSTEP
		SLITSTEP   = RASTER_DEF.YSTEP
	ENDIF
;
;  Apply the correction term to make the values precise.
;
	RASTER.MIRRORSTEP = MIRRORSTEP * 1.016
	RASTER.SLITSTEP	  = SLITSTEP   * 1.016
;
;  Get the pointing information associated with the observation.
;
	CDS_POINT, RASTER, TIMES, POINTINGS
;
;  Make a basic FITS primary header, with no primary array, and signaling that
;  there will be an extension to the file.  Add the creation date to the FITS
;  header.
;
	HEADER1 = MAKECDSHEADER(FILENAME,RASTER,PLAN,RASTER_DEF)
;
;  Insert the information about the observation into the online catalog.
;
	IF !PRIV NE 0 THEN INS_CATALOG, HEADER1
;
;  Use the primary header to create a binary table extension header.  The
;  number of rows is equal to one.
;
	HEADER2 = HEADER1
	FXBHMAKE, HEADER2, 1, 'DATA', 'CDS data'
;
;  Extract the names to be used for the data window columns.
;
	CDS_TTYPE, RASTER, TTYPE
;
;  Create columns for each of the data windows.  Store the column numbers in
;  the array DATAWIN_COL.  At the same time, extract the information about the
;  dimensions of the auxilliary data from the exposure headers.
;
	N_WINDOWS = RASTER.HEADER.NWINDOWS
	DATAWIN_COL = INTARR(N_WINDOWS)
	DETECTOR = RASTER.INSTRUMENT
;
	FOR I = 0,N_WINDOWS-1 DO BEGIN
		WINDOW = RASTER.HEADER.DATA_WIN(I)
		CDSWINEXTR, RASTER, DATAWIN, I, TDESC, DATA,	$
			TDESC2, DIM2, ORDER2, /NOREARRANGE
		IF DETECTOR EQ 'NIS' THEN BEGIN
			TUNIT = 'ADC'
			TDETX = WINDOW.STARTX
			TDETY = WINDOW.STARTY
		END ELSE BEGIN
			TUNIT = 'Counts'
			TDETX = WINDOW.START
			TDETY = -1
		ENDELSE
		CDSADDCOL, COL, HEADER2, DATA, TTYPE(I), 'Data window',	$
			TUNIT, TDESC, -1, TDETX=TDETX, TDETY=TDETY, INDEX=I
		DATAWIN_COL(I) = COL
;
;  Add in the keywords for the binning factors.
;
		IF RASTER.INSTRUMENT EQ 'NIS' THEN BEGIN
			IF RASTER.SP_STATUS.VDS_ORIENT EQ 1 THEN BEGIN
				BINX = (RASTER.BIN2)(I)
				BINY = (RASTER.BIN1)(I)
			END ELSE BEGIN
				BINX = (RASTER.BIN1)(I)
				BINY = (RASTER.BIN2)(I)
			ENDELSE
			FXADDPAR, HEADER2, 'TBINX'+TRIM(I+1), BINX,	$
				'Detector binning across columns'
			FXADDPAR, HEADER2, 'TBINY'+TRIM(I+1), BINY,	$
				'Detector binning across rows'
		END ELSE BEGIN
			FXADDPAR, HEADER2, 'TBINX'+TRIM(I+1),		$
				(RASTER.BIN1)(I), 'Detector binning'
		ENDELSE
	ENDFOR
;
;  Create columns for the data from the exposure headers.
;
	DATA = CDSAUXEXTR(RASTER,TIMES.DEL_TIME,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, DEL_TIME, HEADER2, DATA, 'DEL_TIME',		$
		'Delta times in seconds from start of observation', 'second', $
		TDESC2, TNULL
;
	DATA = CDSAUXEXTR(RASTER,POINTINGS.INS_X,DIM2,ORDER2,TNULL,	$
		/NOREARRANGE)
	CDSADDCOL, INS_X, HEADER2, DATA, 'INS_X',	$
		'Preliminary ins. pointing in Solar X', 'arcsec', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,POINTINGS.INS_Y,DIM2,ORDER2,TNULL,	$
		/NOREARRANGE)
	CDSADDCOL, INS_Y, HEADER2, DATA, 'INS_Y',	$
		'Preliminary ins. pointing in Solar Y', 'arcsec', TDESC2, TNULL
;
	OPS_DECODE, RASTER.OPSLPOSITION, OPSLBITS, OPSLPOSITION, /MAP
	DATA = CDSAUXEXTR(RASTER,OPSLBITS,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, OPSL_BITS, HEADER2, DATA, 'OPSLBITS',	$
		'OPS L status bits', 'code', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,OPSLPOSITION,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, OPS_L, HEADER2, DATA, 'OPS_L',		$
		'OPS L Coordinate', 'raw', TDESC2, TNULL
;
	OPS_DECODE, RASTER.OPSRPOSITION, OPSRBITS, OPSRPOSITION, /MAP
	DATA = CDSAUXEXTR(RASTER,OPSRBITS,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, OPSR_BITS, HEADER2, DATA, 'OPSRBITS',	$
		'OPS R status bits', 'code', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,OPSRPOSITION,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, OPS_R, HEADER2, DATA, 'OPS_R',		$
		'OPS R Coordinate', 'raw', TDESC2, TNULL
;
	SLITPOS_DECODE, RASTER.SLITPOSITION, SLITBITS, SLITPOSITION, /MAP
	DATA = CDSAUXEXTR(RASTER,SLITBITS,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, SLIT_BITS, HEADER2, DATA, 'SLITBITS',	$
		'Slit position status bits', 'code', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,SLITPOSITION,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, SLIT_POS, HEADER2, DATA, 'SLIT_POS',		$
		'Slit position', 'raw', TDESC2, TNULL
;
	DATA = CDSAUXEXTR(RASTER,RASTER.MIRRORPOSITION,DIM2,ORDER2,TNULL, $
		/NOREARRANGE)
	CDSADDCOL, MIR_POS, HEADER2, DATA, 'MIR_POS',		$
		'Mirror position', 'raw', TDESC2, TNULL
;
	SENSOR_DECODE, RASTER.SUNSENSORPITCH, PITCHBITS, PITCHMAGNITUDE, /MAP
	DATA = CDSAUXEXTR(RASTER,PITCHBITS,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, PITCH_BITS, HEADER2, DATA, 'PTCHBITS',	$
		'Sun sensor pitch status bits', 'code', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,PITCHMAGNITUDE,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, PITCH, HEADER2, DATA, 'PITCH',		$
		'Sun sensor pitch', 'raw', TDESC2, TNULL
;
	SENSOR_DECODE, RASTER.SUNSENSORYAW, YAWBITS, YAWMAGNITUDE, /MAP
	DATA = CDSAUXEXTR(RASTER,YAWBITS,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, YAW_BITS, HEADER2, DATA, 'YAW_BITS',		$
		'Sun sensor yaw status bits', 'code', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,YAWMAGNITUDE,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, YAW, HEADER2, DATA, 'YAW',			$
		'Sun sensor yaw', 'raw', TDESC2, TNULL
;
	DATA = CDSAUXEXTR(RASTER,UNSIGN(RASTER.EV_LEVEL),DIM2,ORDER2,TNULL, $
		/NOREARRANGE)
	CDSADDCOL, EV_LEVEL, HEADER2, DATA, 'EV_LEVEL',		$
		'Event level', 'code', TDESC2, TNULL
;
	DATA = CDSAUXEXTR(RASTER,RASTER.SOLAR_X,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, SOLAR_X,  HEADER2, DATA, 'ONBOARDX',		$
		'Onboard calc. Solar west (X) pointing', 'arcsec', TDESC2, $
		TNULL
	DATA = CDSAUXEXTR(RASTER,RASTER.SOLAR_Y,DIM2,ORDER2,TNULL,/NOREARRANGE)
	CDSADDCOL, SOLAR_Y,  HEADER2, DATA, 'ONBOARDY',		$
		'Onboard calc. Solarnorth (Y) pointing', 'arcsec', TDESC2, $
		TNULL
;
;  Add the columns for the information derived from the event status parameter.
;
	EV_STATUS = RASTER.EV_STATUS
	DATA = CDSAUXEXTR(RASTER,EV_STATUS.EV_RECOG,DIM2,ORDER2,TNULL,	$
		/NOREARRANGE)
	CDSADDCOL, EV_RECOG, HEADER2, DATA, 'EV_RECOG', /LOGICAL,	$
		'Event recognition enabled', 'logical', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,EV_STATUS.EV_DETEC,DIM2,ORDER2,TNULL,	$
		/NOREARRANGE)
	CDSADDCOL, EV_DETEC, HEADER2, DATA, 'EV_DETEC', /LOGICAL,	$
		'Event detected', 'logical', TDESC2, TNULL
	DATA = CDSAUXEXTR(RASTER,EV_STATUS.EV_VALID,DIM2,ORDER2,TNULL,	$
		/NOREARRANGE)
	CDSADDCOL, EV_VALID, HEADER2, DATA, 'EV_VALID', /LOGICAL,	$
		'Event solar coordinates valid', 'logical', TDESC2, TNULL
;
;  Add the columns for the GIS engineering parameters.
;
	IF DETECTOR EQ 'GIS' THEN BEGIN
		DIM3 = [4,DIM2]
		ORDER3 = [1,ORDER2+1*ORDER2/ABS(ORDER2)]
		IF STRMID(TDESC2,0,1) NE '(' THEN TDESC3 = TDESC2 ELSE	$
			TDESC3 = STRMID(TDESC2,1,STRLEN(TDESC2)-2)
		TDESC3 = '(DETECTOR,' + TDESC3 + ')'
		ENGB_EXPOSURE, ENGB
		DATA = CDSAUXEXTR(RASTER,ENGB.BKGRCD,DIM3,ORDER3,TNULL, $
			/NOREARRANGE)
		CDSADDCOL, BKGRCD, HEADER2, DATA, 'BKGRCD',	$
			'Detector raw event count', 'counts/sec', TDESC3, TNULL
		DATA = CDSAUXEXTR(RASTER,ENGB.BKGPCD,DIM3,ORDER3,TNULL,	$
			/NOREARRANGE)
		CDSADDCOL, BKGPCD, HEADER2, DATA, 'BKGPCD',	$
			'Detector processed event count', 'counts/sec', $
			TDESC3, TNULL
		DATA = CDSAUXEXTR(RASTER,ENGB.BKGULCD,DIM3,ORDER3,TNULL, $
			/NOREARRANGE)
		CDSADDCOL, BKGULCD, HEADER2, DATA, 'BKGULCD',	$
			'Detector upper level discriminator count',	$
			'counts/sec', TDESC3, TNULL
	ENDIF
;
;  Form the name of the output file.
;
	FILE = FORM_FILENAME(FILENAME, '.fits')
	IF N_ELEMENTS(PATH) EQ 0 THEN PATH = ''
	IF PATH NE '' THEN FILE = CONCAT_DIR(PATH,FILE)
;
;  Create the file, write out the primary and binary table headers, and open
;  the binary table for write.
;
	FXWRITE, FILE, HEADER1
	FXBCREATE, UNIT, FILE, HEADER2
;
;  Write out the data windows.
;
	FOR I = 0,N_ELEMENTS(DATAWIN_COL)-1 DO BEGIN
		CDSWINEXTR, RASTER, DATAWIN, I, TDESC, DATA
		FXBWRITE, UNIT, DATA, DATAWIN_COL(I), 1, NANVALUE=-1
;
;  If appropriate, write out a quick-look image file for this window.
;
		HEADERI = HEADER1
		MAKECDSQLI, HEADERI, DATA, I, TTYPE(I), TDESC
	ENDFOR
;
;  Write out the auxilliary information.
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,RASTER.SOLAR_X,DIM2,ORDER2),	$
		SOLAR_X,  1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,RASTER.SOLAR_Y,DIM2,ORDER2),	$
		SOLAR_Y,  1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,RASTER.MIRRORPOSITION,DIM2,ORDER2), $
		MIR_POS,  1
	FXBWRITE, UNIT,		$
		CDSAUXEXTR(RASTER,UNSIGN(RASTER.EV_LEVEL),DIM2,ORDER2),	$
		EV_LEVEL, 1
;
;  Write out the parameters that are in MCU telemetry format.
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,OPSLBITS,DIM2,ORDER2), OPSL_BITS, 1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,OPSLPOSITION,DIM2,ORDER2), OPS_L, 1
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,OPSRBITS,DIM2,ORDER2), OPSR_BITS,1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,OPSRPOSITION,DIM2,ORDER2), OPS_R, 1
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,SLITBITS,DIM2,ORDER2), SLIT_BITS, 1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,SLITPOSITION,DIM2,ORDER2), SLIT_POS,1
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,PITCHBITS,DIM2,ORDER2), PITCH_BITS, 1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,PITCHMAGNITUDE,DIM2,ORDER2), PITCH, 1
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,YAWBITS,DIM2,ORDER2), YAW_BITS, 1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,YAWMAGNITUDE,DIM2,ORDER2), YAW, 1
;
;  Write out the delta time.
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,TIMES.DEL_TIME,DIM2,ORDER2,TNULL), $
		DEL_TIME, 1, NANVALUE=TNULL
;
;  Write out the pointings.
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,POINTINGS.INS_X,DIM2,ORDER2,TNULL), $
		INS_X, 1, NANVALUE=TNULL
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,POINTINGS.INS_Y,DIM2,ORDER2,TNULL), $
		INS_Y, 1, NANVALUE=TNULL
;
;  Write out the information derived from the event status parameter.
;
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,EV_STATUS.EV_RECOG,DIM2,ORDER2), $
		EV_RECOG, 1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,EV_STATUS.EV_DETEC,DIM2,ORDER2), $
		EV_DETEC, 1
	FXBWRITE, UNIT, CDSAUXEXTR(RASTER,EV_STATUS.EV_VALID,DIM2,ORDER2), $
		EV_VALID, 1
;
;  Write out the columns for the GIS engineering parameters.
;
	IF DETECTOR EQ 'GIS' THEN BEGIN
		FXBWRITE, UNIT, CDSAUXEXTR(RASTER,ENGB.BKGRCD,DIM3,ORDER3), $
			BKGRCD, 1
		FXBWRITE, UNIT, CDSAUXEXTR(RASTER,ENGB.BKGPCD,DIM3,ORDER3), $
			BKGPCD, 1
		FXBWRITE, UNIT, CDSAUXEXTR(RASTER,ENGB.BKGULCD,DIM3,ORDER3), $
			BKGULCD, 1
	ENDIF
;
;  Close the file, and return.
;
	FXBFINISH, UNIT
;
	RETURN
	END
