;+
; Project     : SOHO - CDS     
;                   
; Name        : CHK_TMFILE
;               
; Purpose     : Checks CDS tm file for misplaced APIDs and bad chksums.
;               
; Explanation : Reads a specified CDS telemetry file(s) packet by packet
;               and reports if any packets contain multiple or misplaced
;               APIDs.  Four APIDs are searched for viz. '88a3'x, '88a5'x,
;               '88a6'x and '8863'x.  The cases reported are:
;               1) Packet contains all zeros
;               2) Packet does not contain a recognised APID
;               3) Packet contains more than one recognised APID
;               4) Packet contains only one APID but not at the normal location
;               5) Bad packet check sum
;               
; Use         : IDL> chk_tmfile, files [, various keywords]
;    
; Inputs      : files - A valid CDS telemetry file name or array of names.  
;                       Directory $CDS_TM_DATA is assumed unless specified.
;               
; Opt. Inputs : None
;               
; Outputs     : None
;               
; Opt. Outputs: None
;               
; Keywords    :  PACKS    - specify the packet at which to start the search
;                PACKE    - specify the packet at which to end the search
;                NONORMAL - after the first error is found, normal packets are 
;                           also reported.  Use this keyword to switch off this
;                           reporting of normal packets.
;                HARD     - produce hardcopy of report
;                QUIET    - suppress output to screen
;                KEEP     - keep output file (defaults to tlm_check.lis in HOME
;                           directory unless keyword OUTFILE is used.
;                OUTFILE  - specify the output file in which to keep the report.
;                MAXNORM  - specifies maximum number of consecutive normal
;                           packets to report after an error is detected.
;                           Default is 10.
;                MORE     - if present, screen output has the Unix 'more'
;                           paging option set.
;                NOTIME   - suppress listing of time for each packet
;
; Calls       :
;
; Common      : None
;               
; Restrictions: None
;               
; Side effects: None
;               
; Category    : Telemetry
;               
; Prev. Hist. : None
;
; Written     : C D Pike, RAL, 17-Jun-95
;               
; Modified    : Added chksum test.  CDP, 13-Dec-95
;               Cater for IDL5.2 hex bug.  CDP, 1-6-99
;
; Version     : Version 3, 1-Jun-99
;-            
pro chk_tmfile, infile, packs=packs, packe=packe, nonormal=nonormal,$
                hard=hard, keep=keep, outfile=outfile, quiet=quiet,$
                maxnorm=maxnorm, more=more, notime=notime


;
;  check has the file parameter
;
if n_params() eq 0 then begin
   print,'Use: chk_tmfile, tmfile_name [, keywords]'
   return
endif


;
;  to terminal?
;
if keyword_set(quiet) then to_screen = 0 else to_screen = 1
if to_screen then begin
   if keyword_set(more) then begin
      openw, screen, filepath(/terminal), /get_lun ,/more
   endif else begin
      openw, screen, filepath(/terminal), /get_lun
   endelse
endif

;
;  create filename (in home directory) for hardcopy or use user-supplied
;
vms=(!version.os eq 'VMS')
if not keyword_set(outfile) then begin
   hfile = 'tlm_check.lis'
   if vms then home='sys$login' else home=getenv('HOME')
   hfile=concat_dir(home,hfile)
endif else begin
   hfile = outfile
endelse

;
;  attempt to open output file
;
openw,lun,hfile,/get_lun,error=err
if err ne 0 then begin
   print,'Error opening output file ',hfile
   return
endif


;
;  was maxnorm set?
;
if not keyword_set(maxnorm) then maxnorm = 10

;
;  loop in case the input filename was an array
;
for file_num = 0,n_elements(infile)-1 do begin

;
;  set flag to indicate if anything bad seen
;
   bad = 0
   norm_cnt = 0



;
;  check each file exists
;
   badfile = 0
   if file_exist(infile(file_num)) then begin
      usefile = infile(file_num)
   endif else begin
      break_file, infile(file_num),disk,dir,file,ext
      if dir ne '' then begin
         badfile = 1
      endif else begin
         usefile = concat_dir('$CDS_TM_DATA',infile(file_num))
         if not file_exist(usefile) then badfile = 1
      endelse
   endelse

;
;  is this file OK?
;
   if badfile then begin   
      if to_screen then begin
         printf,screen,'**************''
         printf,screen,'File '+infile(file_num)+' does not exist.'
         printf,screen,'**************''
      endif
      printf,lun,'**************''
      printf,lun,'File '+infile(file_num)+' does not exist.'
      printf,lun,'**************''
   endif else begin

;
;  try to open telemetry file
;
      openr,tmlun,usefile,/get_lun,error=err
      if err ne 0 then begin
         if to_screen then begin
            printf,screen,'**************''
            printf,screen,'Error opening tm file '+usefile
            printf,screen,'**************''
         endif
         printf,lun,'**************''
         printf,lun,'Error opening tm file '+usefile
         printf,lun,'**************''
      endif else begin

;
;  print header
;
         if to_screen then begin
            printf,screen,'**********************'
            printf,screen,'Reading telemetry file '+usefile
            printf,screen,'**********************'
         endif
         printf,lun,'**********************'
         printf,lun,'Reading telemetry file '+usefile
         printf,lun,'**********************'

;
;  all OK so begin reading file
;
         b = bytarr(306)
         pack_cnt = 0

;
;  jump to first packet requested
;
         if keyword_set(packs) then point_lun,tmlun,packs*306L else packs = 0
         pack_cnt = pack_cnt + packs
 
;
;  set last packet wanted
;
         if keyword_set(packe) then last = packe else last = 100000L

         while (pack_cnt le last) and not eof(tmlun) do begin

            readu,tmlun,b

;
;  set time output format
;
            if not keyword_set(notime) then begin
               ptime = '                       '
            endif else begin
               ptime = ''
            endelse


;
;  for ease , convert to int16, but need to carry case where possible loss
;  (or addition) of bytes has lost/added a non-even number of bytes
;
            p  = unsign(byteswap(fix(b,0,153)))
            ps = unsign(byteswap(fix(shift(b,-1),0,153)))
            pc = strcompress(string('#',pack_cnt,form='(a,i5)'),/rem)
            pc = strpad(pc,6,/after)

;
;  immediately test the checksum
;
            chksum_ok = check_sum(b,6,151) eq (byteswap(fix(b,304,1)))(0)
            if not chksum_ok then begin
               if not keyword_set(notime) then begin
                  ptime = anytim2cal(tai2utc(obt2tai(b(12:17))))
                  ptime = ptime + ' --> '
               endif 
               if to_screen then begin
                  printf,screen,ptime+'Packet '+pc+' ......bad CHKSUM'
               endif
               printf,lun,ptime+'Packet '+pc+' ......bad CHKSUM'
            endif
;
;  look for the possible APIDs
;
            nlow = where(p eq '88a3'xl)
            nmed = where(p eq '88a5'xl)
            nhi  = where(p eq '88a6'xl)
            nhk  = where(p eq '8863'xl)
;
;  and in the case of odd number of bytes shift
;
            nlows = where(ps eq '88a3'xl)
            nmeds = where(ps eq '88a5'xl)
            nhis  = where(ps eq '88a6'xl)
            nhks  = where(ps eq '8863'xl)
            all_apids = [nlow,nmed,nhi,nhk,nlows,nmeds,nhis,nhks]

;
;  test for the possible error states.....
;  first was the packet empty?
;
            if total(p) eq 0L then begin
               bad = 1
               norm_cnt = 0
               if to_screen then begin
                  printf,screen,ptime+'Packet '+pc+' ......Empty'
               endif
               printf,lun,ptime+'Packet '+pc+' ......Empty'
            endif

;
;  no APIDs seen?
;
            if (total(all_apids) eq -8) and (total(p) gt 0) then begin
               bad = 1
               norm_cnt = 0
               if to_screen then begin
                  printf,screen,ptime+'Packet '+pc+' ...........No APIDs'
               endif
               printf,lun,ptime+'Packet '+pc+' ...........No APIDs'
            endif

;
;  was more than one APID seen? Disallow case of where have 2 APIDs but
;  they are in different 'halves' of all_apids because they are mutually
;  incompatible
;
            n = where(all_apids ge 0)
            n1 = where(all_apids(0:3) ge 0)
            n2 = where(all_apids(4:7) ge 0)
            one_each = 0
            if n_elements(n1) eq 1 and n_elements(n2) eq 1 then begin
               if max(all_apids(0:3)) ge 0 and $
                  max(all_apids(4:7)) ge 0 then one_each = 1
            endif
            if (n_elements(n) gt 1) and not one_each then begin
               offset = min(all_apids(n))
               if n(0) gt 3 then offset = offset + 0.5
               time_byte = fix(((offset-3.0)*2.)+12)
               if not keyword_set(notime) then begin
                  ptime = anytim2cal(tai2utc(obt2tai(b(time_byte:time_byte+5))))
                  ptime = ptime + ' --> '
               endif 
               bad = 1
               norm_cnt = 0
               if b(18) eq '05'xl then begin
                  if to_screen then begin
                     printf,screen,ptime+'Packet '+pc+$
                       ' ...................Possible Multiple APIDs (mem dump)'
                  endif
                  printf,lun,ptime+'Packet '+pc+$
                       ' ...................Possible Multiple APIDs (mem dump)'
               endif else begin
                  if to_screen then begin
                     printf,screen,ptime+'Packet '+pc+$
                                          ' ...................Multiple APIDs'
                  endif
                  printf,lun,ptime+'Packet '+pc+$
                                          ' ...................Multiple APIDs'
               endelse
            endif


;
;  only one APID but in wrong position or normal packet
;
            if (n_elements(n) eq 1) and (n(0) ge 0)  then begin
               good = where(all_apids ge 0)
               offset = all_apids(good(0))
               if good(0) gt 3 then offset = offset + 0.5
               time_byte = fix(((offset-3.0)*2.)+12)
               if not keyword_set(notime) then begin
                  ptime = anytim2cal(tai2utc(obt2tai(b(time_byte:time_byte+5))))
                  ptime = ptime + ' --> '
               endif 
               if offset ne 3 then begin
                  bad = 1
                  norm_cnt = 0
                  offc = strtrim(string(fix((offset-3.0)*2.),' bytes.'),2)
                  if to_screen then begin
                     printf,screen,ptime+'Packet '+pc+$
                        ' .........................APID offset by '+offc
                  endif
                  printf,lun,ptime+'Packet '+pc+$
                        ' .........................APID offset by '+offc
               endif else begin
                  norm_cnt = norm_cnt + 1
                  if bad and not keyword_set(nonormal) and $
                                               norm_cnt le maxnorm then begin
                     if to_screen then begin
                        printf,screen,ptime+'Packet '+pc+' Normal',form='(a,i5,a)'
                     endif
                     printf,lun,ptime+'Packet '+pc+' Normal',form='(a,i5,a)'
                  endif
               endelse
            endif
            pack_cnt = pack_cnt + 1
         endwhile
         free_lun,tmlun
      endelse
   endelse
endfor

;
;  release units
;
free_lun,lun
if to_screen then free_lun,screen


;
;  print hard copy
;
if keyword_set(hardcopy) then begin
   if vms then com = 'print '+hfile else com = 'lpr '+hfile
   spawn,com
   bell
   print,'Hard copy sent to printer'
endif
if (not keyword_set(keep)) and (not keyword_set(outfile)) then begin
   status = delete_file(hfile,/noconfirm)
endif


end
