﻿C$ Program     TCP2SCET -- Convert ESOC TCP File to SCLKvSCET

      PROGRAM  TCP2SCET

      IMPLICIT NONE

C$ Abstract
C
C     This program convert ESOC Time Correlation Packet (TCP) file to 
C     JPL SCLKvSCET (SCET) format. The program takes a few arguments
C     from the command lines and number of additional parameters from 
C     a setup file. Run the program with -u/-usage argument to see 
C     usage, with -h/help argument to see help and with -template
C     argument to generate setup file template.
C
C     Although not required, it's strongly suggested that the input TCP
C     should contain all TCPs from the beginning of the mission. 
C
C$ Disclaimer
C
C     THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE
C     CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S.
C     GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE
C     ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE
C     PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS"
C     TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY
C     WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A
C     PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC
C     SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
C     SOFTWARE AND RELATED MATERIALS, HOWEVER USED.
C
C     IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA
C     BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT
C     LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND,
C     INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS,
C     REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE
C     REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY.
C
C     RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF
C     THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY
C     CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE
C     ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE.
C
C$ Required_Reading
C
C     TCP2SCET User's Guide.
C
C$ Keywords
C
C     TBD.
C
C$ Declarations
C
C     N/A.
C
C$ Brief_I/O
C
C     N/A.
C
C$ Detailed_Input
C
C     N/A.
C
C$ Detailed_Output
C
C     N/A.
C
C$ Parameters
C
C     Since we need to use SPICE's private binary translation routines,
C     'zzddhman.inc' must be pulled in. Most other parameters (except
C     the one in the Parameters section below) are in 'tcp2scet.inc'.
C
      INCLUDE               'zzddhman.inc'
      INCLUDE               'tcp2scet.inc'

C
C     TCP binary format. Assume BIG-IEEE (UNIX) binary. Use token from
C     zzddhman.inc to identify it.
C
      INTEGER               TCPFMT
      PARAMETER           ( TCPFMT = BIGI3E )

C
C$ Exceptions
C
C     TBD.
C
C$ Files
C
C     This program reads an input binary file containing ESOC Time
C     Correlation Packets (TCP) and created output text file
C     conforming JPL's SCLKvSCET format.
C
C     ESOC Time Correlation Packet (TCP) structure can be described by
C     the following two IDL structure definitions (courtesy of Joe
C     Zender, ESTEC):
C
C        DDS_DH = { dds_dh,    $ ;; dds data header definition
C             time_s:   0UL,   $ ;; 4 bytes: time stamp, sec since 1970
C             time_ms:  0UL,   $ ;; 4 bytes: time stamp, ms since 1970
C             p_length: 0UL,   $ ;; 4 bytes: length of packets in octets
C             gs_id:    0US,   $ ;; 2 bytes: ground station id
C             vc_id:    0US,   $ ;; 2 bytes: vc id
C             sle:      0B,    $ ;; 1 bytes: sle service
C             time_quality: 0B $ ;; 1 bytes: time quality flag
C                 } 
C
C        TCP   = { tcp,        $ ;; 
C             m:  1.0D,        $ ;; 8 bytes: gradient
C             c:  1.0D,        $ ;; 8 bytes: offset
C             d:  1.0D,        $ ;; 8 bytes: deviation
C             t:  bytarr(6)    $ ;; 6 bytes: generation time
C                 }
C
C     with DDS_DH structure defining 18-byte DDS header and TCP
C     structure defining 30-byte TCP data.
C     
C     The combined TCP structure can be presented by the following
C     diagram:
C
C                000000000111111111122222222223333333333444444444
C        byte:   123456789012345678901234567890123456789012345678
C                |   |   |   | | |||       |       |       |   | |
C        field:   sec  ms           gradnt  offset  devtn   sec ms
C        type:    INT  INT          DP      DP      DP      INT 
C
C     Note that both DP and INTs are is UNIX (BIG IEEE) format.
C
C     JPL SCLKvSCET file looks like this:
C
C     -------------------------------------------------------------
C
C     CCSD3ZS00001$$sclk$$NJPL3KS0L015$$scet$$
C     MISSION_NAME          = ...;
C     SPACECRAFT_NAME       = ...;
C     DATA_SET_ID           = SCLK_SCET;
C     FILE_NAME             = ...;
C     PRODUCT_CREATION_TIME = YYYY-MM-DDTHR:MN:SC;
C     PRODUCT_VERSION_ID    = ...;
C     PRODUCER_ID           = ...;
C     APPLICABLE_START_TIME = YYYY-MM-DDTHR:MN:SC;
C     APPLICABLE_STOP_TIME  = YYYY-MM-DDTHR:MN:SC;
C     MISSION_ID            = ...;
C     SPACECRAFT_ID         = ...;
C     CCSD3RE00000$$scet$$NJPL3IS00613$$data$$
C     *____SCLK0________ ________SCET0________ _DUT__ __SCLKRATE__
C                sclk(1)               scet(1) dut(1)      rate(1)  
C                sclk(2)               scet(2) dut(2)      rate(2)  
C                 ...                   ...     ...         ...
C                sclk(n)               scet(n) dut(n)      rate(n)  
C     CCSD3RE00000$$data$$CCSD3RE00000$$sclk$$
C
C     -------------------------------------------------------------
C
C     where the lines that start with "CCSD3" are required and must be
C     exactly as they are shown above; all fields in the header should
C     set to the right values (no quotes are needed for strings and N/A
C     are allowed where applicable); and the data fields the table are:
C
C        sclk(i)   on-board clock value
C
C        scet(i)   UTC that corresponds to it
C
C        dut(i)    delta between ET and UTC
C
C        rate(i)   rate using which SCLK should be interpolated from
C                  this record's time till the next record; this rate 
C                  is the number of UTC seconds in one SCLK second.
C
C$ Particulars
C
C     In order to perform the conversion the program does the following:
C
C        -  processes command-line and setup file inputs
C
C        -  open TCP file and buffers all data from it
C
C        -  sorts buffered data to be in DDH time order
C
C        -  removes duplicate packets (with the same DDH time)
C
C        -  removes TCPs with DDH time earlier that start time specified
C           in the setup file
C
C        -  removes TCPs with DDH time matching one of the times marked
C           as "bad" in the setup file
C
C        -  checks for discontinuities between TCPs by comparing SCLKs
C           computed using current and previous TCPs; if any
C           discontinuity is larger than specified threshold, the
C           program stops
C
C        -  if requested (by setting more to STEP) inserts an extra TCP
C           between each pair of TCPs to "close" the discontinuity
C         
C        -  outputs final TCP data in SCLKvSCET format.
C
C$ Examples
C
C     See User's Guide.
C
C$ Restrictions
C
C     See User's Guide.
C
C$ Literature_References
C
C     None.
C
C$ Author_and_Institution
C
C     B.V.Semenov      (JPL)
C
C$ Version
C
C-    TCP2SCET Version 1.3.1, 03-JUN-2020 (BVS)
C
C        Increased the maximum number of TCPs the program can deal
C        with (MAXTCP in tcp2scet.inc) to 10,000.
C
C-    TCP2SCET Version 1.3.0, 28-OCT-2011 (BVS)
C
C        Moved PARCML to support. Updated its calling sequence.
C        Disabled the error check for negative IOSTAT.
C
C-    TCP2SCET Version 1.2.0, 04-JAN-2006 (BVS)
C
C        Changed the discontinuity check algorithm in TCPCHK and 
C        algorithm computing gradient of additional step records to
C        properly handle records spanning over leapseconds.
C
C-    TCP2SCET Version 1.1.0, 13-OCT-2003 (BVS)
C 
C        Updated to recognize the binary file architecture of the 
C        platform on which the program is running to make sure that
C        it works not only PCs but also on Suns, HPs, etc.
C
C-    TCP2SCET Version 1.0.0, 16-SEP-2003 (BVS)
C 
C        Stolen from CHRONOS. Then global-replaced and further tweaked
C        to be TCP2SCET-specific.
C
C-&

C
C     Local variables.
C 
      CHARACTER*(WRDSIZ)    CLKEYS ( MAXKEY )
      LOGICAL               CLFLAG ( MAXKEY )
      CHARACTER*(LLNSIZ)    CLVALS ( MAXKEY )
      CHARACTER*(WRDSIZ)    CURKEY

      CHARACTER*(LLNSIZ)    HLINE
      CHARACTER*(LLNSIZ)    UNPRSD
      CHARACTER*(LLNSIZ)    LINE
      CHARACTER*(LINSIZ)    HSLINE

      CHARACTER*(FILSIZ)    SETFIL
      CHARACTER*(FILSIZ)    TCPFIL
      CHARACTER*(FILSIZ)    SCTFIL
      CHARACTER*(FILSIZ)    LSKFIL

      DOUBLE PRECISION      S1970
     
      CHARACTER*(LLNSIZ)    ERROR
      CHARACTER*(WRDSIZ)    MODE
      
      INTEGER               TCPUN
      INTEGER               IOSTAT

      DOUBLE PRECISION      DDHTIM ( MAXTCP )
      INTEGER               DDHS   ( MAXTCP )
      INTEGER               DDHMS  ( MAXTCP )
      DOUBLE PRECISION      TCPO   ( MAXTCP )
      DOUBLE PRECISION      TCPG   ( MAXTCP )
      INTEGER               TCPTS  ( MAXTCP )
      CHARACTER*(WRDSIZ)    UTC    ( MAXTCP )
      CHARACTER*(WRDSIZ)    BADUTC ( MAXTCP )
      CHARACTER*(WRDSIZ)    OBTSTR ( MAXTCP )
      DOUBLE PRECISION      ET     ( MAXTCP )
      DOUBLE PRECISION      DUT    ( MAXTCP )
      INTEGER               IORDER ( MAXTCP )
      CHARACTER*(SLNSIZ)    SCETLN ( MAXTCP + 15 )
      CHARACTER*(WRDSIZ)    BEGUTC
      CHARACTER*(WRDSIZ)    HSTR
      INTEGER               RECIDX
      INTEGER               NREC
      INTEGER               BADCNT
      CHARACTER*(TCPRSZ)    TCPREC
      INTEGER               I
      INTEGER               J
      INTEGER               K
      DOUBLE PRECISION      OBTDP
      DOUBLE PRECISION      BEGET
      LOGICAL               DBUGON
      DOUBLE PRECISION      HDP
      INTEGER               NSCET
      INTEGER               SCTUN

      DOUBLE PRECISION      UTCSCP
      DOUBLE PRECISION      TDTSCP
      DOUBLE PRECISION      DELTAP
      DOUBLE PRECISION      UTCSCC
      DOUBLE PRECISION      TDTSCC
      DOUBLE PRECISION      DELTAC
      DOUBLE PRECISION      LEAPSC

      CHARACTER*(18)        FLSCLK
      CHARACTER*(21)        FLUTC
      CHARACTER*(6)         FLDUT
      CHARACTER*(14)        FLRATE
      
      CHARACTER*(WRDSIZ)    HWORD
      CHARACTER*(WRDSIZ)    HWORD1
      CHARACTER*(WRDSIZ)    TSTAMP
      DOUBLE PRECISION      TVEC ( 6 )

      CHARACTER*(SLNSIZ)    MISNAM
      CHARACTER*(SLNSIZ)    SCNAM
      CHARACTER*(SLNSIZ)    PRONAM
      INTEGER               MISID
      INTEGER               SCID
      
      INTEGER               N
      
      CHARACTER*(8)         PLATFM

      DOUBLE PRECISION      MAXDSC
      DOUBLE PRECISION      FIXINT
      LOGICAL               FIXFLG


      LOGICAL               OK
      LOGICAL               FOUND

C
C     SPICELIB functions
C
      INTEGER               RTRIM
      INTEGER               LSTLTD
      INTEGER               ISRCHC
      LOGICAL               EQSTR
      LOGICAL               EXISTS
      DOUBLE PRECISION      UNITIM

C
C     The top portion of the program deals with getting and checking 
C     inputs from the command line and setup file. It's quite long 
C     and boring. To get to the real stuff, start search and skip to
C     the words "We are done with inputs."
C

C
C     Standard SPICE error handling.
C
      CALL CHKIN  ( 'TCP2SCET' )

C
C     Get the command line. Save it "as is" for future debug output.
C
      CALL GETCML ( LINE )
      HLINE = LINE
 
C
C     Setup command line keys array and parse the command line.
C
      CLKEYS(1)  = SETKEY
      CLKEYS(2)  = MODKEY
      CLKEYS(3)  = TCPKEY
      CLKEYS(4)  = SCTKEY
      CLKEYS(5)  = SILKEY
      CLKEYS(6)  = VRBKEY
      CLKEYS(7)  = HLPKEY
      CLKEYS(8)  = HKEY
      CLKEYS(9)  = USGKEY
      CLKEYS(10) = UKEY
      CLKEYS(11) = TMLKEY
      CALL PARCML( HLINE, MAXKEY, CLKEYS, CLFLAG, CLVALS, FOUND, 
     .             UNPRSD )

C
C     Are there any keys on the command line? Is one of the usage keys
C     present? Display USAGE and STOP if yes.
C
      IF ( .NOT. FOUND .OR.
     .     CLFLAG( ISRCHC( USGKEY, MAXKEY, CLKEYS ) ) .OR.
     .     CLFLAG( ISRCHC( UKEY,   MAXKEY, CLKEYS ) )       ) THEN
 
         CALL DSPLAY( 'USAGE', 'STOP' )
 
      END IF
 
C
C     Are there any help keys? Display HELP and STOP if yes.
C
      IF ( CLFLAG( ISRCHC( HLPKEY, MAXKEY, CLKEYS ) ) .OR.
     .     CLFLAG( ISRCHC( HKEY,   MAXKEY, CLKEYS ) )     ) THEN
 
         CALL DSPLAY( 'HELP', 'STOP' )
 
      END IF
 
C
C     What about template key? Display TEMPLATE and STOP if it's
C     present.
C
      IF ( CLFLAG( ISRCHC( TMLKEY, MAXKEY, CLKEYS ) ) ) THEN
 
         CALL DSPLAY( 'TEMPLATE', 'STOP' )
 
      END IF
 
C
C     If silent operation was not requested, turn on the speaker
C     and print version.
C
      IF ( .NOT.  CLFLAG( ISRCHC( SILKEY, MAXKEY, CLKEYS ) ) ) THEN

         CALL SPEKON
         CALL DSPLAY( 'VERSION', 'PROCEED' )
 
      END IF

C
C     If verbose operation was requested, set debug print flag and 
C     turn the speaker on (note that this overrides previously 
C     processed silent request.)
C
      IF ( CLFLAG( ISRCHC( VRBKEY, MAXKEY, CLKEYS ) ) ) THEN
         DBUGON = .TRUE.
      ELSE
         DBUGON = .FALSE.
      END IF

C
C     Well, nobody wants information about the program, they just want
C     to run it. So, check what other stuff we got on the command line.
C     But first, let set all values to blanks.
C
      SETFIL = ' '
      MODE   = ' '
      TCPFIL = ' '
      SCTFIL = ' '
 
      DO I = 1, MAXKEY
 
         IF ( CLFLAG( I ) ) THEN
 
            CURKEY = CLKEYS(I)
 
            IF      ( CURKEY .EQ. SETKEY ) THEN
C
C              It's a setup file name. Save it.
C
               SETFIL = CLVALS( I )(:RTRIM(CLVALS( I )))
 
            ELSE IF ( CURKEY .EQ. MODKEY ) THEN
C
C              It's mode in which we will run. Save and uppercase it.
C
               MODE   = CLVALS( I )(:RTRIM(CLVALS( I )))
               CALL UCASE( MODE, MODE )
 
            ELSE IF ( CURKEY .EQ. TCPKEY ) THEN
C
C              It's TCP file name. Save it.
C
               TCPFIL = CLVALS( I )(:RTRIM(CLVALS( I )))
 
            ELSE IF ( CURKEY .EQ. SCTKEY  ) THEN
C
C              It's SCET file name. Save it.
C
               SCTFIL = CLVALS( I )(:RTRIM(CLVALS( I )))
 
            END IF
 
         END IF
 
      END DO

C
C     Check what we have got on the command line.
C

C
C     Setup file is first. If setup file name was not provided on the
C     command line or if it was blank, we will complain. Otherwise we
C     will try to load it with furnsh.
C
      IF ( SETFIL .EQ. ' ' ) THEN
         CALL SETMSG ( 'Setup file name was''t provided '       //
     .                 'on the command line using # '           //
     .                 'switch or it was set to blank.'         )
         CALL ERRCH  ( '#', SETKEY                              )
         CALL SIGERR ( 'SPICE(NOSETUPFILENAME)'                 )
      ELSE
         CALL FURNSH( SETFIL )
      END IF

C
C     Mode is second. Check that it is one of expected values.
C
      IF      ( EQSTR( MODE, STPMOD ) ) THEN
         FIXFLG = .TRUE.
      ELSE IF ( EQSTR( MODE, STRMOD ) ) THEN
         FIXFLG = .FALSE.
      ELSE IF ( MODE .EQ. ' ' ) THEN
         CALL SETMSG ( 'Mode was not provided on the command '  //
     .                 'line using # switch.'                   )
         CALL ERRCH  ( '#', MODKEY                              )
         CALL SIGERR ( 'SPICE(NOMODESPEC)'                      )
      ELSE
         CALL SETMSG ( 'Mode provided on the command line '     //
     .                 'using # was not one of the expected '   //
     .                 'values -- # or #.'         )
         CALL ERRCH  ( '#', MODKEY                              )
         CALL ERRCH  ( '#', STPMOD                              )
         CALL ERRCH  ( '#', STRMOD                              )
         CALL SIGERR ( 'SPICE(BADMODESPEC)'                     )
      END IF

C
C     Input TCP file is third. The name should be non-blank; the
C     file should exist.
C
      IF      ( TCPFIL .EQ. ' ' ) THEN
         CALL SETMSG ( 'TCP file name was''t provided '         //
     .                 'on the command line using # '           //
     .                 'switch or it was set to blank.'         )
         CALL ERRCH  ( '#', TCPKEY                              )
         CALL SIGERR ( 'SPICE(NOTCPFILENAME)'                   )
      ELSE IF ( .NOT. EXISTS( TCPFIL ) ) THEN
         CALL SETMSG ( 'TCP file ''#'' provided '               //
     .                 'on the command line using # '           //
     .                 'switch does not exist.'                 )
         CALL ERRCH  ( '#', TCPFIL                              )
         CALL ERRCH  ( '#', TCPKEY                              )
         CALL SIGERR ( 'SPICE(TCPDOESNOTEXIST)'                 )
      END IF

C
C     Output SCET file is the last. It should be non-blank and 
C     not exist.
C
      IF      ( SCTFIL .EQ. ' ' ) THEN
         CALL SETMSG ( 'SCET file name was''t provided '        //
     .                 'on the command line using # '           //
     .                 'switch or it was set to blank.'         )
         CALL ERRCH  ( '#', SCTKEY                              )
         CALL SIGERR ( 'SPICE(NOSCETFILENAME)'                  )
      ELSE IF ( EXISTS( SCTFIL ) ) THEN
         CALL SETMSG ( 'SCET file ''#'' provided '              //
     .                 'on the command line using # '           //
     .                 'switch already exists.'                 )
         CALL ERRCH  ( '#', SCTFIL                              )
         CALL ERRCH  ( '#', SCTKEY                              )
         CALL SIGERR ( 'SPICE(EXISTINGSCETFILE)'                )
      END IF

C
C     We are done with command-line parameters. It's time to check
C     setup file stuff.
C
C     Get LSK file name. If it was provides and the file exists,
C     "furnsh" it. Otherwise, complain.
C
      CALL GCPOOL ( LSKKWD, 1, 1, N, LSKFIL, FOUND )
      IF ( FOUND ) THEN
         IF ( EXISTS( LSKFIL ) ) THEN
            CALL FURNSH( LSKFIL )
         ELSE
            CALL SETMSG ( 'LSK file ''#'' provided in '         //
     .                    'the setup file using ''#'' keyword'  //
     .                    'doesn''t exist.'                     )
            CALL ERRCH  ( '#', LSKFIL                           )
            CALL ERRCH  ( '#', LSKKWD                           )
            CALL SIGERR ( 'SPICE(LSKDOESNOTEXIST)'              )
         END IF
      ELSE
         CALL SETMSG ( 'LSK file name wasn''t provided in '    //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', LSKKWD                              )
         CALL SIGERR ( 'SPICE(NOLSKFILENAME)'                   )
      END IF

C
C     Get clock start time.
C
      CALL GCPOOL ( SCLKWD, 1, 1, N, BEGUTC, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Clock start time wasn''t provided in '  //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', SCLKWD                              )
         CALL SIGERR ( 'SPICE(NOCLOCKSTARTTIME)'                )
      END IF

C
C     Get bad TCP times.
C
      CALL GCPOOL ( BADKWD, 1, MAXTCP, BADCNT, BADUTC, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Bad TCP times weren''t provided in '    //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', BADKWD                              )
         CALL SIGERR ( 'SPICE(NOBADTCPTIMES)'                   )
      END IF

C
C     If the number of returned values is equal to MAXTCP, check if we
C     have more values to get. It can be done by calling GCPOOL for
C     (MAXTCP+1)th value. If another value is there we have a buffer
C     overflow and have to stop.
C
      IF ( BADCNT .EQ. MAXTCP ) THEN
            
         CALL GCPOOL ( BADKWD, MAXTCP+1, 1, N, HWORD, FOUND )
         IF ( FOUND ) THEN
            CALL SETMSG ( 'The number of bad TCP times '        //
     .                    'provided in the setup file '         //
     .                    'using ''#'' keyword is greater '     //
     .                    'than can be buffered (max=#).'       )
            CALL ERRCH  ( '#', BADKWD                           )
            CALL ERRINT ( '#', MAXTCP                           )
            CALL SIGERR ( 'SPICE(BADTCPOVERFLOW)'               )
         END IF

      END IF

C
C     Get discontinuity threshold.
C
      CALL GDPOOL ( DISKWD, 1, 1, N, MAXDSC, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'TCP discontinuity threshold wasn''t  '  //
     .                 'provided in the setup file using '      //
     .                 '''#'' keyword.'                         )
         CALL ERRCH  ( '#', DISKWD                              )
         CALL SIGERR ( 'SPICE(NODISCNTTHRESHOLD)'               )
      END IF

C
C     If we run in STEP mode, get phony interval duration.
C
      IF ( FIXFLG ) THEN

         CALL GDPOOL ( INTKWD, 1, 1, N, FIXINT, FOUND )
         IF ( .NOT. FOUND ) THEN
            CALL SETMSG ( 'Auxiliary interval size wasn''t  '   //
     .                    'provided in the setup file using '   //
     .                    '''#'' keyword.'                      )
            CALL ERRCH  ( '#', INTKWD                           )
            CALL SIGERR ( 'SPICE(NOINTERVALSIZE)'               )
         END IF

      ELSE

C
C        Set to some default harmless value.
C
         FIXINT = 1.D0         

      END IF

C
C     Get mission name, s/c name, producer ID, mission ID, and s/c ID.
C
      CALL GCPOOL ( MNMKWD, 1, 1, N, MISNAM, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Mission name wasn''t provided in '      //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', MNMKWD                              )
         CALL SIGERR ( 'SPICE(NOMISSIONNAME)'                   )
      END IF

      CALL GCPOOL ( SNMKWD, 1, 1, N, SCNAM, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Spacecraft name wasn''t provided in '   //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', SNMKWD                              )
         CALL SIGERR ( 'SPICE(NOSPACERAFTNAME)'                 )
      END IF

      CALL GCPOOL ( PIDKWD, 1, 1, N, PRONAM, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Producer ID wasn''t provided in '       //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', PIDKWD                              )
         CALL SIGERR ( 'SPICE(NOPRODUCERID)'                    )
      END IF

      CALL GIPOOL ( MIDKWD, 1, 1, N, MISID, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Mission ID wasn''t provided in '       //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', MIDKWD                              )
         CALL SIGERR ( 'SPICE(NOMISSIONID)'                     )
      END IF

      CALL GIPOOL ( SIDKWD, 1, 1, N, SCID, FOUND )
      IF ( .NOT. FOUND ) THEN
         CALL SETMSG ( 'Spacecraft ID wasn''t provided in '     //
     .                 'the setup file using ''#'' keyword.'    )
         CALL ERRCH  ( '#', SIDKWD                              )
         CALL SIGERR ( 'SPICE(NOSPACECRAFTID)'                  )
      END IF

C
C     If debug flag is ON, print all inputs.
C
      IF ( DBUGON ) THEN

         CALL SPEAK( 'Original command-line:' )
         CALL SPEAK( ' ' )
         CALL SPEAK( '   ' // LINE )
         CALL SPEAK( ' ' )

         CALL SPEAK( 'Buffered command-line and setup file ' //
     .                'parameters: ' )
         CALL SPEAK( ' ' )

         HSLINE = '   SETFIL = ''#'''
         CALL REPMC ( HSLINE, '#', SETFIL(:RTRIM(SETFIL)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   MODE = ''#'''
         CALL REPMC ( HSLINE, '#', MODE(:RTRIM(MODE)), HSLINE )
         CALL SPEAK( HSLINE )

         IF ( FIXFLG ) THEN
            HSLINE = '   FIXFLG = .TRUE.'
         ELSE
            HSLINE = '   FIXFLG = .FALSE.'
         END IF
         CALL SPEAK( HSLINE )

         HSLINE = '   TCPFIL = ''#'''
         CALL REPMC ( HSLINE, '#', TCPFIL(:RTRIM(TCPFIL)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   SCTFIL = ''#'''
         CALL REPMC ( HSLINE, '#', SCTFIL(:RTRIM(SCTFIL)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   LSKFIL = ''#'''
         CALL REPMC ( HSLINE, '#', LSKFIL(:RTRIM(LSKFIL)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   BEGUTC = ''#'''
         CALL REPMC ( HSLINE, '#', BEGUTC(:RTRIM(BEGUTC)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   BADCNT = #'
         CALL REPMI ( HSLINE, '#', BADCNT, HSLINE )
         CALL SPEAK( HSLINE )

         DO I = 1, BADCNT
            HSLINE = '   BADUTC(#) = ''#'''
            CALL REPMI ( HSLINE, '#', I, HSLINE)
            CALL REPMC ( HSLINE, '#', 
     .                   BADUTC(I)(:RTRIM(BADUTC(I))), HSLINE)
            CALL SPEAK( HSLINE )
         END DO

         HSLINE = '   MAXDSC = #, seconds'
         CALL REPMF ( HSLINE, '#', MAXDSC, 12, 'F', HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   FIXINT = #, seconds'
         CALL REPMF ( HSLINE, '#', FIXINT, 12, 'F', HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   MISNAM = ''#'''
         CALL REPMC ( HSLINE, '#', MISNAM(:RTRIM(MISNAM)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   MISID = #'
         CALL REPMI ( HSLINE, '#', MISID, HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   SCNAM = ''#'''
         CALL REPMC ( HSLINE, '#', SCNAM(:RTRIM(SCNAM)), HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   SCID = #'
         CALL REPMI ( HSLINE, '#', SCID, HSLINE )
         CALL SPEAK( HSLINE )

         HSLINE = '   PROID = ''#'''
         CALL REPMC ( HSLINE, '#', PRONAM(:RTRIM(PRONAM)), HSLINE )
         CALL SPEAK( HSLINE )

         CALL SPEAK( ' ' )
 
      END IF

C
C     We are done with inputs. At this point we have obtained and 
C     buffered/set:
C
C        MODE     mode is which we are running (STEP or STRETCH)
C
C        FIXFLG   logical flag set to .TRUE. if mode if STEP, to
C                 .FALSE. otherwise
C
C        TCPFIL   name of input TCP file
C
C        SCTFIL   name of output SCLKvSCET file
C
C        BEGUTC   UTC of the clock start; all TCP records before this
C                 time will be ignored
C
C        BADUTC   UTC times of bad TCP packets; TCP packets that match
C                 these times will be ignored)
C
C        BADCNT   the number of bad TCP times
C
C        MAXDSC   maximum discontinuity between neighbor TCP packet that
C                 we can tolerate, in seconds; any discontinuity larger
C                 than this will cause the program to stop
C
C        FIXINT   duration of the "extra" interval that will be
C                 inserted each TCP if we are running in STEP mode, in
C                 seconds
C
C        MISNAM   mission name; not used for anything except is put
C                 into SCLKvSCET header
C
C        MISID    mission id; not used for anything except is put into
C                 SCLKvSCET header
C
C        SCNAM    spacecraft name; not used for anything except is put
C                 into SCLKvSCET header
C
C        SCID     spacecraft id; not used for anything except is put
C                 into SCLKvSCET header
C
C        PROID    producer id; not used for anything except is put into
C                 SCLKvSCET header
C
C     We have also loaded LSK file.
C
C

C
C     Compute and buffer the number of "formal" seconds between
C     1970-01-01 00:00:00 ("base" for the VAX time used in DDS header)
C     and J2000. (Ignore the ERROR as we know that input time string
C     has correct format :).
C
      CALL TPARSE( '1970-01-01 00:00:00', S1970, ERROR )
     
C
C     Find out what is the binary architecture of the platform we are
C     running on. If it's not Unix (BIG-IEEE) or PC (LTL-IEEE) we
C     cannot process the input TCP file.
C
      CALL ZZPLATFM ( 'FILE_FORMAT', PLATFM  )
      IF ( PLATFM .NE. 'BIG-IEEE' .AND. PLATFM .NE. 'LTL-IEEE' ) THEN
         CALL SETMSG ( 'The program is running on the platform '//
     .                 'with ''#'' binary file architecture '   //
     .                 'while it can only be run on the '       //
     .                 '''BIG-IEEE'' or ''LTL-IEEE'' platforms.' )
         CALL ERRCH  ( '#', PLATFM                               )
         CALL SIGERR ( 'SPICE(INCOMPATIBLEPLATFORM)'             )
      END IF

C
C     Get logical unit and open input TCP file.
C
      CALL GETLUN ( TCPUN )

      OPEN ( UNIT   = TCPUN,
     .       FILE   = TCPFIL,
     .       ACCESS = 'DIRECT',
     .       RECL   = TCPRSZ,
     .       IOSTAT = IOSTAT )
      
C
C     Check IOSTAT and bail out if error.
C
      IF ( IOSTAT .NE. 0 ) THEN
 
         CALL SETMSG ( 'Error opening binary TCP file ''#''.'    //
     .                 ' IOSTAT = #.'                            )
         CALL ERRCH  ( '#', TCPFIL                               )
         CALL ERRINT ( '#', IOSTAT                               )
         CALL SIGERR ( 'SPICE(FILEOPENFAILED)'                   )
 
      END IF

C
C     The combined TCP structure can be presented by the following
C     diagram:
C
C                000000000111111111122222222223333333333444444444
C        byte:   123456789012345678901234567890123456789012345678
C                |   |   |   | | |||       |       |       |   | |
C        field:   sec  ms           gradnt  offset  devtn   sec ms
C        type:    INT  INT          DP      DP      DP      INT 
C
C     If we are on a PC (LTL-IEEE), read TCP records into a character
C     string, one-by-one, till the end of the file. Otherwise, read
C     them directly into the TCP data buffers' elements.
C
      RECIDX = 1
      IF ( PLATFM .EQ. 'LTL-IEEE' ) THEN
         READ ( UNIT=TCPUN, REC=RECIDX, IOSTAT=IOSTAT ) TCPREC
      ELSE
         READ ( UNIT=TCPUN, REC=RECIDX, IOSTAT=IOSTAT ) 
     .       DDHS(RECIDX),
     .       DDHMS(RECIDX), TCPREC(1:10),
     .       TCPG(RECIDX), 
     .       TCPO(RECIDX),  TCPREC(1:8),
     .       TCPTS(RECIDX), TCPREC(1:2)
      END IF

      DO WHILE ( IOSTAT .EQ. 0 ) 

C
C        If our platform is PC (LTL-IEEE) we must use SPICE binary
C        translation routines to convert characters from the record
C        into numbers. 
C
         IF ( PLATFM .EQ. 'LTL-IEEE' ) THEN
            CALL ZZXLATEI ( TCPFMT, TCPREC(1:4),   1, DDHS(RECIDX)  )
            CALL ZZXLATEI ( TCPFMT, TCPREC(5:8),   1, DDHMS(RECIDX) )
            CALL ZZXLATED ( TCPFMT, TCPREC(19:26), 1, TCPG(RECIDX)  )
            CALL ZZXLATED ( TCPFMT, TCPREC(27:34), 1, TCPO(RECIDX)  )
            CALL ZZXLATEI ( TCPFMT, TCPREC(43:46), 1, TCPTS(RECIDX) )
         END IF

C
C        Add DDH header seconds and microseconds to get accurate 
C        time.
C
         DDHTIM(RECIDX) = DDHS(RECIDX) + DDHMS(RECIDX)*1.D-6

C
C        Convert DDS seconds to UTC (SCETvSCET DOY format) and ET.
C
         CALL TIMOUT ( DDHTIM(RECIDX) + S1970, 
     .                 'YYYY-DOYTHR:MN:SC.### ::TDB ::RND', 
     .                 UTC(RECIDX) )
         CALL STR2ET ( UTC(RECIDX), ET(RECIDX) )

C
C        Also set reference OBT string to "not set yet" value.
C
         OBTSTR(RECIDX) = 'not_set_yet'

C
C        Increment record counter.
C
         RECIDX = RECIDX + 1

C
C        Do we have space to buffer the next record?
C
         IF ( RECIDX .GT. MAXTCP ) THEN
            CALL SETMSG ( 'TCP buffer overrun. Can buffer only '   //
     .                    '# records. Increase MAXTCP size.'        )
            CALL ERRINT ( '#', MAXTCP                               )
            CALL SIGERR ( 'SPICE(TCPBUFFEROVERRUN)'                 )
         END IF

C
C        Read the next record.
C
         IF ( PLATFM .EQ. 'LTL-IEEE' ) THEN
            READ ( UNIT=TCPUN, REC=RECIDX, IOSTAT=IOSTAT ) TCPREC
         ELSE
            READ ( UNIT=TCPUN, REC=RECIDX, IOSTAT=IOSTAT ) 
     .         DDHS(RECIDX),
     .         DDHMS(RECIDX), TCPREC(1:10),
     .         TCPG(RECIDX), 
     .         TCPO(RECIDX),  TCPREC(1:8),
     .         TCPTS(RECIDX), TCPREC(1:2)
         END IF

      END DO

C
C     Check IOSTAT to see if it's negative (indicates the end of the 
C     file.) If it's not negative, complain and bail out.
C
C     This is no true for GFORTRAN. This check had to be disabled.
C
C      IF ( IOSTAT .GT. 0 ) THEN
C 
C         CALL SETMSG ( 'Error reading record # of binary '       //
C     .                 'TCP file ''#''. IOSTAT = #.'             )
C         CALL ERRINT ( '#', RECIDX                               )
C         CALL ERRCH  ( '#', TCPFIL                               )
C         CALL ERRINT ( '#', IOSTAT                               )
C         CALL SIGERR ( 'SPICE(FILEOPENFAILED)'                   )
C 
C      END IF
      
      NREC = RECIDX - 1

C
C     Close input file.
C
      CLOSE ( TCPUN )

C
C     Debug-print original buffered data.
C
      CALL TCPPRN( 'TCP data as buffered from the file ''' 
     .             // TCPFIL(:RTRIM(TCPFIL)) // ''':',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )


C
C     Say that we are going to do changes to the file
C
      CALL SPEAK( 'Changes made to the original TCP set:' )
      CALL SPEAK( '-------------------------------------' )

C
C     Data has been loaded successfully. Sort records to be DDH-time
C     ordered.
C
      CALL ORDERD ( DDHTIM, NREC, IORDER )
      
      CALL REORDD ( IORDER, NREC, DDHTIM )
      CALL REORDI ( IORDER, NREC, DDHS   )
      CALL REORDI ( IORDER, NREC, DDHMS  )
      CALL REORDD ( IORDER, NREC, TCPO   )
      CALL REORDD ( IORDER, NREC, TCPG   )
      CALL REORDI ( IORDER, NREC, TCPTS  )
      CALL REORDC ( IORDER, NREC, UTC    )
      CALL REORDD ( IORDER, NREC, ET     )

C
C     Debug-print re-ordered data.
C
      CALL TCPPRN('TCP data after reordering:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )

C
C     Remove duplicate points.
C
      I = 1
      DO WHILE ( I .LT. NREC ) 

C
C        If DDH times are equal we need to drop one of the records and
C        decrement the number of records by one.
C
         IF ( DDHTIM(I) .EQ. DDHTIM(I+1) ) THEN

C
C           First, check is the values in these records are the same or
C           not and let the user know about it loud and clear.
C           
            IF ( TCPO(I) .EQ. TCPO(I+1) .AND. 
     .           TCPG(I) .EQ. TCPG(I+1)      ) THEN
               CALL SPEAK( 
     .            '   Removed duplicate times/identical TCP data @ ' 
     .            // UTC(I) )
            ELSE
               CALL SPEAK( 
     .            '   Removed duplicate times/DIFFERENT TCP data @ ' 
     .            // UTC(I) )
            END IF

C
C           Then, remove the second of the two records from all
C           buffered arrays, one-by-one.
C
            J = NREC
            CALL REMLAD ( 1, I+1, DDHTIM, J )
            J = NREC
            CALL REMLAI ( 1, I+1, DDHS,   J )
            J = NREC
            CALL REMLAI ( 1, I+1, DDHMS,  J )
            J = NREC
            CALL REMLAD ( 1, I+1, TCPO,   J )
            J = NREC
            CALL REMLAD ( 1, I+1, TCPG,   J )
            J = NREC
            CALL REMLAI ( 1, I+1, TCPTS,  J )
            J = NREC
            CALL REMLAC ( 1, I+1, UTC,    J )
            J = NREC
            CALL REMLAD ( 1, I+1, ET,     J )

C
C           And reset the number of records.
C
            NREC = NREC - 1

         ELSE
            I = I + 1
         END IF

      END DO
      CALL SPEAK( ' ' )

C
C     Debug-print data without duplicates. Also, debug-print the first
C     check for discontinuities.
C
      CALL TCPPRN( 'TCP data after removing duplicates:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )

      CALL TCPCHK( 'Check for discontinuities (before cleanup):',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, MAXDSC, OK) 


C
C     Cut-off initial points (prior to epoch specified in the setup.)
C
      CALL STR2ET( BEGUTC, BEGET )
      I = LSTLTD ( BEGET, NREC, ET )

      IF      ( I .EQ. 0 ) THEN
C
C        Nothing to strip off: all TCPs are later than cut off epoch.
C
         LINE = 'No initial packets before # to remove ...'
         CALL REPMC ( LINE, '#', BEGUTC, LINE )
         CALL SPEAK( LINE ) 

      ELSE IF ( I .EQ. NREC ) THEN

C
C        All TCP are before the cut off epoch. Cannot process such
C        input.
C
         CALL SETMSG ( 'All input TCPs have time stamp earlier ' //
     .                 'than cut off time ''#'' specified in '  //
     .                 'the setup.'                              )
         CALL ERRCH  ( '#', BEGUTC                               )
         CALL SIGERR ( 'SPICE(INCONSISTENTCUTOFF)'               )

      ELSE
         
C        
C        We need to chop off so many initial packets.
C
         LINE = '   Removed # initial packets before # ...'
         CALL REPMI ( LINE, '#', I, LINE )
         CALL REPMC ( LINE, '#', BEGUTC, LINE )
         CALL SPEAK( LINE )
         CALL SPEAK( ' ' )

         J = NREC
         CALL REMLAD ( I, 1, DDHTIM, J )
         J = NREC
         CALL REMLAI ( I, 1, DDHS,   J )
         J = NREC
         CALL REMLAI ( I, 1, DDHMS,  J )
         J = NREC
         CALL REMLAD ( I, 1, TCPO,   J )
         J = NREC
         CALL REMLAD ( I, 1, TCPG,   J )
         J = NREC
         CALL REMLAI ( I, 1, TCPTS,  J )
         J = NREC
         CALL REMLAC ( I, 1, UTC,    J )
         J = NREC
         CALL REMLAD ( I, 1, ET,     J )

         NREC = J
         
      END IF

C
C     Debug-print truncated data.
C
      CALL TCPPRN('TCP data after removing initial packets:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )

C
C     Remove data points labeled as bad in the setup file.
C
      DO I = 1, BADCNT

C
C        Check if this UTC is present in the TCP buffer.
C
         K = ISRCHC( BADUTC(I), NREC, UTC )

         IF ( K .NE. 0 ) THEN

C
C           It is. Notify the user that that we are going to remove it.
C
            LINE = '   Removed TCP matching ''bad'' UTC # ...'
            CALL REPMC ( LINE, '#', BADUTC(I), LINE )
            CALL SPEAK( LINE ) 
C
C           Remove this TCP's data from the buffers.
C
            J = NREC
            CALL REMLAD ( 1, K, DDHTIM, J )
            J = NREC
            CALL REMLAI ( 1, K, DDHS,   J )
            J = NREC
            CALL REMLAI ( 1, K, DDHMS,  J )
            J = NREC
            CALL REMLAD ( 1, K, TCPO,   J )
            J = NREC
            CALL REMLAD ( 1, K, TCPG,   J )
            J = NREC
            CALL REMLAI ( 1, K, TCPTS,  J )
            J = NREC
            CALL REMLAC ( 1, K, UTC,    J )
            J = NREC
            CALL REMLAD ( 1, K, ET,     J )

            NREC = J
            
         ELSE
            
C
C           Hmmmm, funny. This may be a mistake in setup. Why would
C           someone put in a UTC that does not appear in the TCP
C           stream? Let the user know about it.
C
            LINE = 'No TCP matching ''bad'' UTC #. ' //
     .             'Is this time correct?'
            CALL REPMC ( LINE, '#', BADUTC(I), LINE )
            CALL SPEAK( LINE ) 
            
         END IF

      END DO

C
C     Debug-print final data.
C
      CALL TCPPRN('TCP data after removing ''bad'' packets:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )

      CALL TCPCHK('Check for discontinuities (after cleanup):',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, MAXDSC, OK) 


C
C     This time we will check the flag that TCPCHK returns. If it was
C     set to .FALSE. we have to report discontinuities and stop the
C     program.
C
      IF ( .NOT. OK ) THEN
         CALL SPEKON
         CALL TCPCHK('Discontinuities in cleaned TCP set:',
     .               .TRUE., NREC, DDHTIM, DDHS, DDHMS, 
     .               TCPG, TCPO, TCPTS, UTC, ET, MAXDSC, OK) 

         CALL SETMSG ( 'One or more discontinuities between adjacent '//
     .                 'correlation packets is greater then the '//
     .                 'permitted threshold of # seconds. '     //
     .                 'These records must be tagged as ''bad''' // 
     .                 'or threshold value should be increased ' //
     .                 'in order for this data to be processed.' )
         CALL ERRDP  ( '#', MAXDSC                               )
         CALL SIGERR ( 'SPICE(BIGDISCONTINUITIES)'               )
      END IF

C
C     Everything seems to OK. Proceed to compute reference OBT -- the
C     OBT value at the DDH time -- and DUT -- delta between UTC and ET
C     -- for each packet. Buffer OBT in SCLK format.
C
      DO RECIDX = 1, NREC

C
C        This is the ESOC's simple time correlation formula.
C
         OBTDP = ( DDHTIM(RECIDX) - TCPO(RECIDX) )/ TCPG(RECIDX)

C
C        We have a "pure DP" OBT but need an OBT with fractional part
C        expressed as the number of ticks.
C
         OBTSTR(RECIDX) = '#.#'

         HDP = INT(OBTDP)
         CALL DPFMT( HDP, 'xxxxxxxxxxxx', HSTR )
         CALL REPMC ( OBTSTR(RECIDX), '#', HSTR, OBTSTR(RECIDX) )

         HDP = ( OBTDP - INT(OBTDP) ) * ( 1.D0 / TICKSZ )
         CALL DPFMT( HDP, '0xxxx', HSTR )
         CALL REPMC ( OBTSTR(RECIDX), '#', HSTR, OBTSTR(RECIDX) )

C
C        Also compute and buffer DUT for each point.
C
         CALL DELTET( ET(RECIDX), 'ET', DUT(RECIDX) )

      END DO

C
C     Debug-print reference OBTs.
C      
      CALL TCPPRN('TCP data, fully cleaned and with reference OBTs:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )

C
C     Are we are running in "fix-it-by-extra-little-packets" mode?
C
      IF ( FIXFLG ) THEN

         CALL SPEAK ( ' ' )

C
C        Ughhhh ... we need to insert a little phony packet between 
C        every two real packets to ensure continuity.
C
         RECIDX = 2
         DO WHILE ( RECIDX .LE. NREC )

C
C           Insert extra element at RECIDX position into all buffers.
C
            J = NREC
            CALL INSLAD ( 0.D0, 1, RECIDX, DDHTIM, J )
            J = NREC
            CALL INSLAI ( 0,    1, RECIDX, DDHS,   J )
            J = NREC
            CALL INSLAI ( 0,    1, RECIDX, DDHMS,  J )
            J = NREC
            CALL INSLAD ( 0.D0, 1, RECIDX, TCPO,   J )
            J = NREC
            CALL INSLAD ( 0.D0, 1, RECIDX, TCPG,   J )
            J = NREC
            CALL INSLAI ( 0,    1, RECIDX, TCPTS,  J )
            J = NREC
            CALL INSLAC ( ' ',  1, RECIDX, UTC,    J )
            J = NREC
            CALL INSLAD ( 0.D0, 1, RECIDX, ET,     J )
            J = NREC
            CALL INSLAC ( ' ',  1, RECIDX, OBTSTR, J )
            J = NREC
            CALL INSLAD ( 0.D0, 1, RECIDX, DUT,    J )
            NREC = NREC + 1

C
C           Set the values of this new element, now sitting at RECIDX.
C           DDHTIM is first.
C
            DDHTIM(RECIDX) = DDHTIM(RECIDX + 1) - FIXINT
            
C
C           Then set UTC, ET and DUT that correspond to it.
C
            CALL TIMOUT ( DDHTIM(RECIDX) + S1970, 
     .                    'YYYY-DOYTHR:MN:SC.### ::TDB ::RND', 
     .                    UTC(RECIDX) )
            CALL STR2ET ( UTC(RECIDX), ET(RECIDX) )
            CALL DELTET ( ET(RECIDX), 'ET', DUT(RECIDX) )

C
C           Determine whether there was a leapsecond between 
C           the new record and the previous one.
C
            UTCSCP = DDHTIM(RECIDX-1) + S1970
            TDTSCP = UNITIM ( ET(RECIDX-1), 'ET', 'TDT' )
            DELTAP = TDTSCP - UTCSCP

            UTCSCC = DDHTIM(RECIDX) + S1970
            TDTSCC = UNITIM ( ET(RECIDX), 'ET', 'TDT' )
            DELTAC = TDTSCC - UTCSCC

            LEAPSC = DELTAC - DELTAP

C
C           Set OBT using DDHTIM of this point BUT offset and gradient
C           of the previous one while accounting for the leapsecond.
C
            OBTDP = ( DDHTIM(RECIDX) - TCPO(RECIDX-1) + LEAPSC )
     .              / TCPG(RECIDX-1)

            OBTSTR(RECIDX) = '#.#'

            HDP = INT(OBTDP)
            CALL DPFMT( HDP, 'xxxxxxxxxxxx', HSTR )
            CALL REPMC ( OBTSTR(RECIDX), '#', HSTR, OBTSTR(RECIDX) )

            HDP = ( OBTDP - INT(OBTDP) ) * ( 1.D0 / TICKSZ )
            CALL DPFMT( HDP, '0xxxx', HSTR )
            CALL REPMC ( OBTSTR(RECIDX), '#', HSTR, OBTSTR(RECIDX) )

C
C           Next determine whether there was a leapsecond between 
C           the new record and the next one.
C
            UTCSCP = DDHTIM(RECIDX) + S1970
            TDTSCP = UNITIM ( ET(RECIDX), 'ET', 'TDT' )
            DELTAP = TDTSCP - UTCSCP

            UTCSCC = DDHTIM(RECIDX+1) + S1970
            TDTSCC = UNITIM ( ET(RECIDX+1), 'ET', 'TDT' )
            DELTAC = TDTSCC - UTCSCC

            LEAPSC = DELTAC - DELTAP

C
C           And finally compute adjusted gradient. It is equal to our 
C           interval length divided by delta between OBT of the next 
C           point and this point.
C
            TCPG(RECIDX) = ( FIXINT + LEAPSC ) / 
     .      ((DDHTIM(RECIDX+1) - TCPO(RECIDX+1))/TCPG(RECIDX+1) - OBTDP)

C
C           We should also compute offset to make sure that we can 
C           do continuity checks.
C
            TCPO(RECIDX) = ( DDHTIM(RECIDX) - OBTDP * TCPG(RECIDX) )

C
C           Report that we added a record
C            
            CALL SPEAK ( '   Added extra (step) TCP @ ' // UTC(RECIDX) )

C
C           We will leave DDHS and DDHMS unset to indicate that
C           this is "phony" data point and reset index forward two
C           records.
C            
            RECIDX = RECIDX + 2

         END DO

      END IF

C
C     Debug-print with phony records.
C
      CALL TCPPRN('TCP data with ''extra'' step records:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, OBTSTR )

      CALL TCPCHK('Final check for discontinuities:',
     .             DBUGON, NREC, DDHTIM, DDHS, DDHMS, 
     .             TCPG, TCPO, TCPTS, UTC, ET, MAXDSC, OK) 

C
C     Fill SCLKvSCET line buffer. Do header first. Get/pack CPU time.
C
      CALL CPUTIM ( TVEC )
      TSTAMP = 'YYYY-MM-DDTHR:MN:SC'
      CALL DPFMT ( TVEC(1), '0YYY',  TSTAMP(1:4)   )
      CALL DPFMT ( TVEC(2), '0M',    TSTAMP(6:7)   )
      CALL DPFMT ( TVEC(3), '0D',    TSTAMP(9:10)  )
      CALL DPFMT ( TVEC(4), '0h',    TSTAMP(12:13) )
      CALL DPFMT ( TVEC(5), '0m',    TSTAMP(15:16) )
      CALL DPFMT ( TVEC(6), '0s',    TSTAMP(18:19) )

      CALL INTSTR( SCID, HWORD )
      CALL INTSTR( MISID, HWORD1 )

      SCETLN(  1 ) = 'CCSD3ZS00001$$sclk$$NJPL3KS0L015$$scet$'
     .//             '$'
      SCETLN(  2 ) = 'MISSION_NAME          = ' 
     .//             MISNAM(:RTRIM(MISNAM)) // ';'
      SCETLN(  3 ) = 'SPACECRAFT_NAME       = ' 
     .//             SCNAM(:RTRIM(SCNAM)) // ';'
      SCETLN(  4 ) = 'DATA_SET_ID           = SCLK_SCET;'
      SCETLN(  5 ) = 'FILE_NAME             = ' // 
     .               SCTFIL(:RTRIM(SCTFIL)) // ';'
      SCETLN(  6 ) = 'PRODUCT_CREATION_TIME = ' //
     .               TSTAMP(:RTRIM(TSTAMP)) // ';'
      SCETLN(  7 ) = 'PRODUCT_VERSION_ID    = N/A;'
      SCETLN(  8 ) = 'PRODUCER_ID           = ' 
     .//             PRONAM(:RTRIM(PRONAM)) // ';'
      SCETLN(  9 ) = 'APPLICABLE_START_TIME = ' // 
     .               UTC(1)(:RTRIM(UTC(1))) // ';'
      SCETLN( 10 ) = 'APPLICABLE_STOP_TIME  = N/A;'
      SCETLN( 11 ) = 'MISSION_ID            = ' // 
     .               HWORD1(:RTRIM(HWORD1)) // ';'
      SCETLN( 12 ) = 'SPACECRAFT_ID         = ' // 
     .               HWORD(:RTRIM(HWORD)) // ';'
      SCETLN( 13 ) = 'CCSD3RE00000$$scet$$NJPL3IS00613$$data$'
     .//             '$'
      SCETLN( 14 ) = '*____SCLK0________ ________SCET0_______'
     .//             '_ _DUT__ __SCLKRATE__'
      NSCET = 14

C
C     Fill in the data lines.
C
      DO RECIDX = 1, NREC

         FLSCLK = OBTSTR(RECIDX)
         CALL RJUST( FLSCLK, FLSCLK )

         FLUTC = UTC(RECIDX)
         CALL RJUST( FLUTC, FLUTC )

         CALL DPFMT( DUT(RECIDX), 'xx.xxx', FLDUT )
         CALL RJUST( FLDUT, FLDUT )

         CALL DPFMT( TCPG(RECIDX), 'x.xxxxxxxxxxxx', FLRATE )
         CALL RJUST( FLRATE, FLRATE )

         SCETLN( NSCET + RECIDX ) = FLSCLK // ' ' //
     .                              FLUTC  // ' ' // 
     .                              FLDUT  // ' ' //
     .                              FLRATE

      END DO

      NSCET = NSCET + NREC + 1
C
C     Don't forget footer.
C
      SCETLN( NSCET ) = 'CCSD3RE00000$$data$$CCSD3RE00000$$sclk$'
     .//                '$'

C
C     Dump SCET to the file and to the screen.
C
C
      CALL TXTOPN ( SCTFIL, SCTUN )

      CALL SPEAK( ' ' )
      CALL SPEAK( 'Output SCLKvSCET file:' )
      CALL SPEAK( '----------------------' )
      CALL SPEAK( ' ' )
      DO I = 1, NSCET
         CALL SPEAK( SCETLN(I) )
         CALL WRITLN( SCETLN(I), SCTUN ) 
      END DO

      CLOSE( SCTUN )
      
C
C     All done.
C
      CALL SPEAK( ' ' )

      CALL CHKOUT( 'TCP2SCET' )

      END

