;+
; Project     :	SOHO - CDS
;
; Name        :	WR_TTC_FILE
;
; Purpose     :	Writes out the command preparation TTC file.
;
; Explanation :	Writes out the TTC file in the format expected by 
;               the Perl script files. The TTC file contains a time tagged list
;               of the studies forming the science plan to be loaded into the
;               deferred command store.
;
; Use         : <wr_ttc_file, sciplan, series_list, startofperiod, state>
;
; Inputs      : sciplan         = structure array containing information on the science
;                                 plan extracted from the sci_details planning database.
;               series_list     = structure array giving information on series tables;
;               startofperiod   = string containing UTC start time of science plan.
;               initial_state   = structure describing the initial state of the CDS
;
; Opt. Inputs : None.
;
; Outputs     : Writes TTC data to file.
;
; Opt. Outputs:	None.
;
; Keywords    : EMERGENCY : if present indicates that last study is the emergency study..
;
; Calls       :	get_utc, tai2utc, shorthex, get_ops_delay, get_slitn_delay, get_ops_pos, concat_dir, safe_slit.
;                
; Common      :	None.
;
; Restrictions:	None.
;
; Side effects:	None.
;
; Category    :	Command preparation.
;
; Prev. Hist. :	None.
;
; Written     :	Version 0.00, Martin Carter, RAL, 14/10/94
;
; Modified    :	Version 0.01, Martin Carter, RAL, 28/11/94
;                             Added proforma.
;               Version 0.2,  Martin Carter, RAL, 6/2/95
;                             Changed startofperiod input to string.
;               Version 0.3,  MKC, RAL, 21/3/95
;                             Incorporated n_repeat_s. Removed non time-tagged studies.
;               Version 0.4,  MKC, RAL, 18/4/95
;                             Removed series.repn tag.
;                             Inputted sciplan details list.
;                             Incorporated deferred pointing.
;                             Included state structure in input list.
;               Version 0.5,  MKC, RAL, 24/4/95
;                             Took start time to nearest second.
;               Version 0.6,  MKC, 17/5/95
;                             Added more study info.
;                             Modified series state structure.
;               Version 0.7,  MKC, 24/5/95
;                             Removed non time tagged studies from store.
;               Version 0.8,  MKC, 6/6/95
;                             Corrected bug in pointings loop.
;                             Added CB5ABORT to each time tagged study.
;               Version 0.9,  CDP, 17/6/95
;                             Replaced calls to NINT by ROUND to avoid ssw conflict
;               Version 1.0,  MKC, 11/8/95
;                             Added emergency study note.
;               Version 1.1,  MKC,14/8/95
;                             Modified get_ops_delay argument list.
;               Version 1.2,  MKC, 11/10/95
;                             Modified so that printout for non time tagged studies
;                             better reflects the true state of things
;               Version 1.3,  MKC, 23/10/95
;                             Renamed environment variables and used concat_dir.
;               Version 1.4,  MKC, 7/11/95
;                             Modified sequential study printout.
;                             Modified sequential study calculation and mechanism for repeats.
;                             Added emergency keyword.
;               Version 1.5,  MKC, 21/11/95
;                             Added more printout.
;               Version 1.6,  MKC, 8/12/95
;                             Added engineering study info.
;                             Added initial state description.
;               Version 1.7,  MKC, 13/12/95
;                             Added gset lut parameter set up.
;               Version 1.8,  MKC, 14/12/95
;                             Added reverse study processing.
;               Version 1.9,  MKC, 3/1/96
;                             Modified so that OPS commands go through macro.    
;               Version 2.0,  MKC, 15/1/96
;                             Modified s0 that only outputs OPS and slitn command if necessary.
;               Version 2.1,  MKC, 11/3/96
;                             Dealt with unknown initial state.       
;               Version 2.2,  MKC, 15/3/96
;                             Fixed bug when gsetid=-1 which caused GIS LUT to be loaded when unnecessary.
;               Version 2.3,  MKC, 7/5/96
;                             Park GIS volatges at the start of each study.
;               Version 2.4,  MKC, 8/7/96
;                             Added count of no. of deferred command store entries used and 
;                             error message if on-board deferred command store size exceeded.
;               Version 2.5,  MKC, 7/10/96
;                             Combined study repeats and repeat pointings into single set of series tables.
;               Version 2.6,  MKC, 18/10/96
;                             Ensure slit number command sent for every time tagged study.
;                             Safe slit after every slit command.    
;               Version 2.7,  MKC, 27/1/97
;                             Changed CB5ABORT delay from 5 secs to 10 secs
;               Version 2.8,  MKC, 21/4/97
;                             Prevent SW from writing out slitn=0 command explicitly.
;                             Use slitn=0 to signal no MCU commands for special study.
;                             Changed printout to reflect above.       
;                             
; Version     :	Version 2.8, 21/4/97
;-
;**********************************************************


PRO wr_ttc_file, details_list, series_list, startofperiod, initial_state, EMERGENCY=emergency

  ; Output TTC file 
  ; overwrite any existing file 

  sw_version = '2.6'

  ; initialize no. of deferred commands used so far

  commands = 0

  ; get current state

  state = initial_state

  ; get file name

  filename = concat_dir ( '$CDS_CP_TTCFILES_W', startofperiod + '.TTC' )

  PRINT, 'WRITING FILE : ', filename
  PRINT, ''

  ; open wide file 

  OPENW, unit, filename, /GET_LUN, WIDTH=200

  ; file header info

  get_utc, utc, /ECS

  PRINTF, unit, '# DEFERRED TABLE FILE
  PRINTF, unit, '# Created ', utc
  PRINTF, unit, '# Version ', sw_version
  PRINTF, unit

  IF state.mode EQ 'X' THEN BEGIN
    PRINTF, unit, '# Current state of CDS unknown'
    PRINTF, unit
  ENDIF ELSE BEGIN
    PRINTF, unit, '# Initial solar x position       = ' + STRTRIM ( state.solarx, 1 ) + '"'
    PRINTF, unit, '# Initial solar y position       = ' + STRTRIM ( state.solary, 1 ) + '"'
    PRINTF, unit, '# Initial slit number            = ' + STRTRIM ( state.slitn,  1 ) 
    PRINTF, unit, '# Initial gset id                = ' + STRTRIM ( state.gsetid, 1 ) 
    PRINTF, unit
  ENDELSE

  PRINTF, unit, '# Objective'
  PRINTF, unit, '# Time                           Command'
  PRINTF, unit

  ; loop through series list in reverse order

  series_index = N_ELEMENTS(series_list) - 1

  ndetails = N_ELEMENTS ( details_list ) 

  FOR stdyno = 0, ndetails-1 DO BEGIN

    ; note emergency study

    IF KEYWORD_SET ( emergency ) AND  stdyno EQ ndetails-1 THEN BEGIN
      PRINTF, unit, '# EMERGENCY STUDY'
      PRINTF, unit
    ENDIF

    ; abbreviate series list items for study

    nsubs  = series_list(series_index).nsubs

    series = series_list(series_index-nsubs+1:series_index) 

    ; decrement series_index

    series_index = series_index - nsubs

    ; set up start time of study to nearest second

    timenow = DOUBLE ( ROUND ( series(0).time ) )

    ; check if study time tagged and if science or engineering
    ; istate and fstate are the initial and final states of the study
    ; NB istate will correspond to the requested start position of the study

    IF series(0).id NE 0 THEN BEGIN

      IF NOT series(0).tt THEN PRINTF, unit, '# SCIENCE STUDY NOT TIME TAGGED' ELSE $
                               PRINTF, unit, '# TIME TAGGED SCIENCE STUDY

    ENDIF ELSE BEGIN

      IF NOT series(0).tt THEN PRINTF, unit, '# ENGINEERING STUDY NOT TIME TAGGED' ELSE $
                               PRINTF, unit, '# TIME TAGGED ENGINEERING STUDY

    ENDELSE

    ; output study info

    PRINTF, unit, '# TIME     = ' + tai2utc ( timenow, /ECS)
    PRINTF, unit, '# SCI OBJ  = ' + details_list(stdyno).sci_obj
    PRINTF, unit, '# SCI SPEC = ' + details_list(stdyno).sci_spec
    PRINTF, unit, '# No. of study repeats    = ' + STRTRIM(details_list(stdyno).n_repeat_s,1)
    PRINTF, unit, '# No. of pointing repeats = ' + STRTRIM(details_list(stdyno).n_pointings,1)
    IF series(0).istate.slitn EQ 0 THEN BEGIN
      IF state.mode EQ 'X' THEN BEGIN
        PRINTF, unit
        PRINTF, unit, '# Initial state of study unknown'
        PRINTF, unit
        PRINTF, unit
      ENDIF ELSE BEGIN
        PRINTF, unit, '# solar x position        = ' + STRTRIM ( state.solarx, 1 ) + '"'
        PRINTF, unit, '# solar y position        = ' + STRTRIM ( state.solary, 1 ) + '"'
        PRINTF, unit, '# slit number             = ' + STRTRIM ( state.slitn,  1 ) 
        PRINTF, unit, '# gset id                 = ' + STRTRIM ( state.gsetid, 1 ) 
      ENDELSE
    ENDIF ELSE BEGIN
      PRINTF, unit, '# solar x position        = ' + STRTRIM ( series(0).istate.solarx, 1 ) + '"'
      PRINTF, unit, '# solar y position        = ' + STRTRIM ( series(0).istate.solary, 1 ) + '"'
      PRINTF, unit, '# slit number             = ' + STRTRIM ( series(0).istate.slitn,  1 ) 
      PRINTF, unit, '# gset id                 = ' + STRTRIM ( series(0).istate.gsetid, 1 ) 
    ENDELSE
    PRINTF, unit, '# CDHS series indices     = ', STRTRIM ( series.cdhsx, 1) + ' '
    PRINTF, unit, '# CDHS series IDs         = ', STRTRIM ( series.cdhsid, 1) + ' '
    PRINTF, unit

    IF series(0).tt THEN BEGIN

      ; study time tagged

      ; check if GSET ID needs setting up

      IF series(0).istate.gsetid GT 0 AND state.gsetid NE series(0).istate.gsetid THEN $
         do_gset_ttc, unit, series(0).istate.gsetid, timenow, commands 

      ; get ops positions at start of study

      get_ops_pos, state.solarx, state.solary, current_opsl, current_opsr

      ; get study initial ops positions

      get_ops_pos, series(0).istate.solarx, series(0).istate.solary, new_opsl, new_opsr

      ; test whether state is unknown
      ; if unknown assume maximum time to get to next position

      IF state.mode NE 'X' THEN BEGIN

        ; work out delays to nearest second

        opsl_delay  = ROUND ( get_ops_delay ( current_opsl, new_opsl, 0 ) /1000.0 ) + 1 

        opsr_delay  = ROUND ( get_ops_delay ( current_opsr, new_opsr, 1 ) /1000.0 ) + 1

        slitn_delay = ROUND ( get_slitn_delay ( state.slitn, series(0).istate.slitn ) /1000.0 ) + 1

      ENDIF ELSE BEGIN
 
        ; get ops and slit number home position delays in seconds

        ss = cp_get_entry ( 'CBMOPSLP', [0] )

        opsl_delay = ss(0).delay

        ss = cp_get_entry ( 'CBMOPSRP', [0] )

        opsr_delay = ss(0).delay

        ss = cp_get_entry ( 'CBMSLITN', [0] )

        slitn_delay = ss(0).delay
            
      ENDELSE

      ; output abort command

      PRINTF, unit, '#  tell macro to abort any running sequence'
      PRINTF, unit

      PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CB5ABORT"'
      PRINTF, unit

      timenow  = timenow + 10.0 ; 10 seconds delay for abort to work

      commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

      ; explicitly park GIS detectors in case someone has left them on

      ; get parking high voltage for detectors

      ss = cp_get_entry ( 'CBGHV1V', [0] )

      cbghv1v = ss(0).active
  
      ss = cp_get_entry ( 'CBGHV2V', [0] )

      cbghv2v = ss(0).active
  
      ss = cp_get_entry ( 'CBGHV3V', [0] )

      cbghv3v = ss(0).active
  
      ss = cp_get_entry ( 'CBGHV4V', [0] )

      cbghv4v = ss(0).active

      ; set GIS detectors to parking voltage

      PRINTF, unit, '#  Park GIS detectors'
      PRINTF, unit

      PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CBGHV1V ' + shorthex(cbghv1v) + '"'
      PRINTF, unit

      timenow = timenow + 1.0 ; 1 seconds delay

      commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

      PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CBGHV2V ' + shorthex(cbghv2v) + '"'
      PRINTF, unit

      timenow = timenow + 1.0 ; 1 seconds delay

      commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

      PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CBGHV3V ' + shorthex(cbghv3v) + '"'
      PRINTF, unit

      timenow = timenow + 1.0 ; 1 seconds delay

      commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

      PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CBGHV4V ' + shorthex(cbghv4v) + '"'
      PRINTF, unit

      timenow = timenow + 1.0 ; 1 seconds delay
       
      commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

      ; test whether to output mechanism commands

      IF series(0).istate.slitn NE 0 THEN BEGIN

        ; test whether to output OPS commands

        IF state.mode EQ 'X' OR state.solarx NE series(0).istate.solarx OR state.solary NE series(0).istate.solary THEN BEGIN
             
          ; output mechanism movement commands

          PRINTF, unit, '#  tell macro to tell mcu to move OPS left : ' + STRTRIM ( new_opsl, 1 )
          PRINTF, unit

          PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   CB5SIC "CBMOPSLP ', shorthex ( new_opsl ), '"'
          PRINTF, unit

          timenow = timenow + opsl_delay

          commands = commands + 5  ;  increment no. of INT16 words used in deferred command store by entry

          PRINTF, unit, '#  tell macro to tell mcu to move OPS right : ' + STRTRIM ( new_opsr, 1 )
          PRINTF, unit

          PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   CB5SIC "CBMOPSRP ', shorthex ( new_opsr ), '"'
          PRINTF, unit
                      
          timenow = timenow + opsr_delay

          commands = commands + 5  ;  increment no. of INT16 words used in deferred command store by entry

        ENDIF

        ; output slit number command whether changed or not

        ; IF state.mode EQ 'X' OR state.slitn NE series(0).istate.slitn THEN BEGIN ; -- old test 18/10/96

        PRINTF, unit, '#  tell mcu to move slit number : ' + STRTRIM ( series(0).istate.slitn, 1 )
        PRINTF, unit

        PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CBMSLITN ', shorthex ( series(0).istate.slitn ), '"'
        PRINTF, unit
                      
        timenow = timenow + slitn_delay

        commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

        ; ensure slit motor turned off

        safe_slit, /TTC, unit, timenow, commands

      ENDIF ELSE BEGIN

        ; slitn=0 

        PRINTF, unit, '#  No following science studies'
        PRINTF, unit

      ENDELSE

      ; output run series command

      PRINTF, unit, '#  run series command : CDHS ID = ' + shorthex ( series(0).cdhsid ) + $
                    ', CHDS index = ' + STRTRIM ( series(0).cdhsx, 1) 
      PRINTF, unit
 
      PRINTF, unit, '"', tai2utc ( timenow, /ECS),'"   "CB5RUNS ', shorthex ( series(0).cdhsid ), '"'
      PRINTF, unit

      PRINTF, unit

      commands = commands + 4  ;  increment no. of INT16 words used in deferred command store by entry

   ENDIF

   ; update state

   state = series(0).fstate

   ; update current gset ID
   ; Nb do not update if ! gsetid>0 for this study because gsetid will be unchanged

   IF series(0).istate.gsetid GT 0 then state.gsetid = series(0).istate.gsetid

  ENDFOR ; end of details list loop

  ; close file and free logical unit 

  FREE_LUN, unit

  ; check if deferred command store size exceeded

  PRINT, 'No. of deferred command entries used = ', STRTRIM(commands,1), ' out of 1024'

  PRINT, ''

  IF commands GT 1024 THEN $
    MESSAGE, 'ERROR, PLAN EXCEEDED DEFERRED COMMAND STORE SIZE'

END
