	FUNCTION READ_PACKET, TEL_MODE, UNIT, PACKET
;+
; Project     : SOHO - CDS
;
; Name        : READ_PACKET()
;
; Purpose     : Read a telemetry packet
;
; Explanation : Reads a complete telemetry packet from either the realtime
;		telemetry feed, or from a playback file.
;
; Use         : Result = READ_PACKET( TEL_MODE, UNIT, PACKET )
;
; Inputs      : TEL_MODE = Input mode.  The following modes have been defined.
;
;				0:	Replay stored telemetry
;				1:	Realtime telemetry
;				2:	Quicklook tape recorder dumps
;				3:	Realtime telemetry archived by ECS
;				4:	Final distribution
;
;		UNIT	 = Logical unit number of input stream.
;
; Opt. Inputs : None.
;
; Outputs     : PACKET	= Structure variable containing the packet.  The
;			  structure type will depend on the type of the packet.
;
;		The return value for the function can be one of the following:
;
;			 1	Packet successfully read.
;			 0	End-of-file encountered.
;			-1	Error during read.
;
; Opt. Outputs: None.
;
; Keywords    : None.
;
; Calls       : IEEE_TO_HOST, ENGB_STORE
;
; Common      : FITSGEN from the include file "fitsgen.cmn"
;
; Restrictions: TM_DEFINE_STRUC must have already been called to define the
;		telemetry structures.
;
; Side effects: None.
;
; Category    : Data Handling, Telemetry
;
; Prev. Hist. : Influenced by SCI_ANA.PRO by Arnulf from Spacetec.
;
; Written     : William Thompson, GSFC, 19 March 1993.
;
; Modified    : Version 1, William Thompson, GSFC, 6 April 1993.
;		Version 2, William Thompson, GSFC, 30 August 1994
;			Changed ...DEF to ...DFN to avoid conflicts with other
;			software such as STM.PRO
;		Version 3, William Thompson, GSFC, 31 August 1994
;			Modified to write packet ID to FITSGEN widget.
;		Version 4, William Thompson, GSFC, 30 January 1995
;			Changed to read from realtime telemetry files as they
;			are written, instead of reading from realtime pipe.
;		Version 5, William Thompson, GSFC, 3 February 1995
;			Modified to support both realtime and
;			quicklook/final-distribution formats.
;		Version 6, William Thompson, GSFC, 6 February 1995
;			Modified to support final distribution format.
;		Version 7, William Thompson, GSFC, 9 February 1995
;			Modified to display the internal packet counter, rather
;			than the counter embedded within the packet header.
;		Version 8, William Thompson, GSFC, 10 March 1995
;			Modified to only display every 10th packet.
;		Version 9, William Thompson, GSFC, 28 March 1995
;			Make sure that I_PACK and NUM_PACK are always long.
;		Version 10, William Thompson, GSFC, 7 June 1995
;			Modified to call TM_ENOUGH.
;		Version 11, William Thompson, GSFC, 12 June 1995
;			Increased timeout to 30 seconds
;		Version 12, William Thompson, GSFC, 29 June 1995
;			Added optional output parameter CHECKSUM to TM_ENOUGH
;			call.
;		Version 13, William Thompson, GSFC, 25 August 1995
;			Added call to ENGB_STORE
;		Version 14, William Thompson, GSFC, 10 November 1995
;			Removed inefficiency in use of TM_ENOUGH
;		Version 15, William Thompson, GSFC, 26 January 1996
;			Check CHECKSUM for ENGB packets.
;		Version 16, William Thompson, GSFC, 26 February 1996
;			Increased timeout to 5 minutes.
;		Version 17, William Thompson, GSFC, 19 February 1996
;			Don't wait so long when switching over to a new
;			telemetry file.
;		Version 18, William Thompson, GSFC, 23 April 1996
;			If an end of realtime telemetry has already been
;			detected, then don't put in any waits.
;		Version 19, William Thompson, GSFC, 11 May 1996
;			Put in short wait to ease CPU usage.
;		Version 20, William Thompson, GSFC, 24 May 1996
;			Wait up to 10 minutes during loss of telemetry.
;		Version 21, William Thompson, GSFC, 20 May 1997
;			Read realtime data until CHECKSUM is not zero.
;		Version 22, William Thompson, GSFC, 4 June 1997
;			Change to read until MAX_BYTE is not zero.
;		Version 23, William Thompson, GSFC, 10 June 1997
;			If MAX_BYTE is zero, try closing and reopening the file
;			before giving up on the packet.
;
; Version     :	Version 23, 10 June 1997
;-
;
	IF !DEBUG EQ 0 THEN ON_ERROR, 2 ELSE ON_ERROR, 0
	ON_IOERROR, ERROR
;
;  Include the common block to support the FITSGEN routine.
;
@fitsgen.cmn
;
;  Check the number of parameters.
;
	IF N_PARAMS() NE 3 THEN MESSAGE,	$
		'Syntax:  Result = READ_PACKET( TEL_MODE, UNIT, PACKET )'
;
;  Make sure that I_PACK and NUM_PACK are defined.
;
	IF N_ELEMENTS(I_PACK) EQ 0 THEN I_PACK = 0L
	IF N_ELEMENTS(NUM_PACK) EQ 0 THEN NUM_PACK = 0L
;
;  If the TEL_MODE is 1 (realtime), then check to see if there are enough bytes
;  left in the file to read.  Keep checking until there are, or until 600
;  seconds have gone by.  The TM_ENOUGH routine also calculates a CHECKSUM
;  value, and a MAX_BYTE value.  Keep reading until MAX_BYTE is not zero.
;
	IF TEL_MODE EQ 1 THEN BEGIN
		WAITED = 0
		MAX_WAIT = 600
		FILE_STATUS = FSTAT(UNIT)
		IF FILE_STATUS.NAME EQ '' THEN RETURN,0
		BREAK_FILE, FILE_STATUS.NAME, DISK, DIR, NAME, EXT
;
		TEST = TM_ENOUGH(UNIT, 306, CHECKSUM, MAX_BYTE)
		WHILE ((NOT TEST) OR (MAX_BYTE EQ 0)) AND	$
			(WAITED LT MAX_WAIT) DO BEGIN
		    WAIT, 0.5
		    WAITED = WAITED + 0.5
;
;  If we've already waited more than 45 seconds, and the next FITS file is
;  available, then return 0 to signal the end of the current file.
;
		    IF WAITED GE 45 THEN BEGIN
			FILENAME = GT_RT_FILE()
			IF FILENAME NE NAME+EXT THEN BEGIN
				FILENAME = CONCAT_DIR('$CDS_TM_DATA', FILENAME)
				IF FILE_EXIST(FILENAME) THEN RETURN,0
			ENDIF
		    ENDIF
;
;  If there are enough bytes, but they appear to be all zero, then don't wait
;  so long.
;
		    IF TEST AND (MAX_BYTE EQ 0) THEN WAITED = WAITED +	$
			    MAX_WAIT / 4
		    TEST = TM_ENOUGH(UNIT, 306, CHECKSUM, MAX_BYTE)
		ENDWHILE
;
;  If it was an empty packet that caused the delay, then try closing and
;  reopening the file.  If that still doesn't work, then signal an error.
;
		IF TEST AND (MAX_BYTE EQ 0) THEN BEGIN
		    FILE_STATUS = FSTAT(UNIT)
		    POINT_LUN, -UNIT, CUR_POS
		    CLOSE, UNIT
		    OPENR, UNIT, FILE_STATUS.NAME
		    POINT_LUN, UNIT, CUR_POS
		    TEST = TM_ENOUGH(UNIT, 306, CHECKSUM, MAX_BYTE)
		    IF MAX_BYTE EQ 0 THEN CDS_MESSAGE, /CONTINUE, /ADD_TIME, $
			    'Empty packet #' + TRIM(I_PACK+1) + ' detected'
		ENDIF
;
;  If no packet is available, then perhaps we're onto a new file.  Return 0 to
;  signal the end of the current file.
;
		IF WAITED GE MAX_WAIT THEN	$
			IF NOT TM_ENOUGH(UNIT, 306, CHECKSUM) THEN RETURN, 0
;
;  Otherwise, in playback mode, return 0 if the end-of-file is encountered.
;  Use TM_ENOUGH in addition to the EOF function so that a checksum can be
;  calculated.
;
	END ELSE IF EOF(UNIT) THEN RETURN, 0 ELSE BEGIN
		IF (TEL_MODE EQ 0) OR (TEL_MODE EQ 1) THEN NEEDED = 306 ELSE $
			NEEDED = 300
		IF NOT TM_ENOUGH(UNIT, NEEDED, CHECKSUM) THEN RETURN, 0
	ENDELSE
;
;  If reading in stored telemetry in either the ECS format or in the final
;  distribution format, then return 0 to signal an end-of-file if one has
;  already read in all the packets.
;
	IF (TEL_MODE GE 2) AND (I_PACK GE NUM_PACK) THEN RETURN, 0
;
;  If in realtime or playback mode, then read in an initial header not present
;  in other modes.  This information is discarded.
;
	IF (TEL_MODE EQ 0) OR (TEL_MODE EQ 1) THEN BEGIN
		DUMMY = {RTPKTHDRDFN}
		READU, UNIT, DUMMY
	ENDIF
;
;  Read the packet header, and convert the byte ordering to that of the host
;  machine.
;
READ_PKT:
	HEADER = {PACKETHDRDFN}
	READU, UNIT, HEADER
	IEEE_TO_HOST, HEADER
;
;  Depending on the packet type, read the rest of the packet.
;
	CASE HEADER.ID OF
	    '01'X:  BEGIN & REST={GISRASTERDFN} & PACKET={GISRASTERPKT} & END
	    '02'X:  BEGIN & REST={VDSRASTERDFN} & PACKET={VDSRASTERPKT} & END
	    '11'X:  BEGIN & REST={EXPHEADERDFN} & PACKET={EXPHEADERPKT} & END
	    '12'X:  BEGIN & REST={EXPHEADERDFN} & PACKET={EXPHEADERPKT} & END
	    '21'X:  BEGIN & REST={SCIPACKETDFN} & PACKET={SCIPACKETPKT} & END
	    '22'X:  BEGIN & REST={SCIPACKETDFN} & PACKET={SCIPACKETPKT} & END
	     ELSE:  BEGIN & REST={ANYPACKETDFN} & PACKET={ANYPACKETPKT} & END
	ENDCASE
;
;  Read the rest of the packet
;
	READU, UNIT, REST
	IEEE_TO_HOST, REST
;
;  Combine the two parts into the structure to be returned.
;
	PACKET.HDR = HEADER
	PACKET.PKT = REST
;
;  Increment the packet counter.
;
	I_PACK = I_PACK + 1L
;
;  If being called from FITSGEN, then write out the packet counter to the
;  widget.
;
	IF KEYWORD_SET(PACKET_WIDG) AND ((I_PACK MOD 10) EQ 0) THEN	$
		WIDGET_CONTROL, PACKET_WIDG, SET_VALUE = STRING(I_PACK, $
			FORMAT='(I6)')
;
;  If the packet is an Engineering B packet, then store it for future use.  But
;  first check the checksum.  If not correct, then try reading the packet
;  again.
;
	IF PACKET.HDR.ID EQ '0B'X THEN BEGIN
	    IF CHECKSUM NE PACKET.PKT.CHKSUM THEN BEGIN
		IF NOT KEYWORD_SET(ALREADY_RETRIED) THEN BEGIN
		    IF TEL_MODE EQ 1 THEN BEGIN
			POINT_LUN, -TELEM_UNIT, CUR_POS
			POINT_LUN, TELEM_UNIT, CUR_POS-300
			WAIT, 0.1
			I_PACK = I_PACK - 1L
			ALREADY_RETRIED = 1
			GOTO, READ_PKT
		    ENDIF
		ENDIF
		CDS_MESSAGE, /CONTINUE, 'Packet ' + TRIM(I_PACK) +	$
			' does not have the correct checksum', /ADD_TIME
		GOTO, FINISH
	    ENDIF
	    ENGB_STORE, PACKET
	ENDIF
;
;  Return 1 for success.
;
FINISH:
	WAIT, 0.001	;Short wait to ease CPU usage
	RETURN, 1
;
;  I/O error point.
;
ERROR:
	RETURN, -1
	END
