#!/bin/bash

########################################################################

### Dump raw REX Output Frame from packet, stored in PDU of FITS file
### - byte-interleaved 5088-byte stream of bytes

### Reads label to get data offsets in FITS
### Read FITS data to make table

### Usage:  newrex_dump_rof.bash __rawdata/rex_003031500?_0x7b3_eng_*.lbl


########################################################################
### Extract ordinal-1 of 2880-byte FITS record from PDS label file
### e.g. extract the "13" from a line like this:
###
### ^EXTENSION_IQVALS_TABLE = ("REX_0030315000_0X7B3_ENG_1.FIT", 13)              
function getifitrec() {
   line=( `head -1 | tr '\" (),\r' ' '` )
   echo "${line[3]}-1"
}


########################################################################
### Usage:  headfit file.fit 12880 10000
### - output 10000 bytes, starting at an offset of 2880 bytes past the
###   1st byte (ordinal byte 2881), from file file.fit start

function headfit() {
  fit="$1"
  headbytes="$2"
  bytes="$3"
  head -${headbytes}c $fit \
  | tail -c -$bytes
}

### Main function
while [ $# -gt 0 ] ; do

  ### Get and consume first command-line argument
  lbl="$1" ; shift

  ### Ensure end in .lbl
  [ "${lbl%.lbl}" == "$lbl" ] && ( echo "### Skipping $lbl" 1>&2 || true ) && continue

  ### Build FITS pathname from PDS label path name
  fit="${lbl%lbl}fit"

  ### Get 2880-byte FITS record offsets to PDU data
  let imgoffset=`grep '^ *[\^]IMAGE *= *(' "$lbl" | getifitrec`

  ### Calculate byte offsets
  let imgbyteoffset=2880*$imgoffset

  ### Determine IMAGE data lengths and other parameters
  ### - imgbytes:  ROF:  5088 bytes
  let imgbytes=5088

  ### Calculate total number of bytes from start of file to end of
  ### each BINTABLE

  let imgheadbytes=$imgbyteoffset+$imgbytes

  ### Set up local variables for assigning a description to each byte in stream
  ### - ID: Identifier byte
  ### - Status:  status byte, 3 bits of which identify FPGA source stream
  ### - R[n][hi:lo]:  hi to lo bits of 40-bit Radiometry; n is ordinal, 1-10
  ### - T[n][hi:lo]:  hi to lo bits of 24-bit Time Tag; n is ordinal, 1-10
  ### - I[n][MSB], I[n][LSB] Q[n][MSB], Q[n][LSB]:
  ###     MSBytes and LSBytes of 16-bit IQ Values; n is ordinal of value, 1-1250
  ###     MSBytes and LSBytes of IQ Values
  ### - Spare:  spares; last six bytes of strem

  iqpfx=( I    I   Q    Q )
  iqsfx=( MSB  LSB MSB  LSB )

  rtpfx=( R     R     R     R     R     T     T     T )
  rtsfx=( 39:32 31:24 23:16 15:08 07:00 23:16 15:08 07:00  )

  iqlen=${#iqsfx[*]}
  rtlen=${#rtpfx[*]}

  ### Maintain count of IQ and RT (Radiometry or Time Tag) bytes encountered
  let nextIQ0=0
  let nextRT0=0

  ### Maintain count of bytes (rows of data) encountered
  nextrow0=0

  ### Pipe 5088 raw bytes from FITS file
  ### - to od to convert to ASCII unsigned 1-byte integers one per line, then
  ### - to while-read loop to add a description to each line, then
  ### - to GAWK for formatting
  headfit $fit $imgheadbytes $imgbytes \
  | od -v -w1 -t u1 \
  | while read pfx u1 xxx ; do
    ### while-read loop parses and print out data from od command above
    ### - pfx is the octal offset from od
    ### - u1 is the bytes
    ### - row0 is the offset from the first byte

      ### If no second item, do nothing
      [ "$u1" ] || continue

      ### print out -t u1 (unsigned 1-byte decimals) from
      echo -n "$u1 "

      let row0=$nextrow0
      let ++nextrow0

      ### Deal with first six and last six bytes:  ID, Status, first IQ pair, spares
      case $row0 in
      0) echo "ID" ; continue ;;
      1) echo "I[1][MSB]" ; continue ;;
      2) echo "I[1][LSB]" ; continue ;;
      3) echo "$u1" | gawk '{printf "Status [0x%02x => ", $1}'
         ### Parse bits 6:4 of u1 value to identify FPGS source stream
         let status=($u1/16)\&7
         case $status in
         0) echo "ADC output from NH receiver]" ;;
         1) echo "Impulse]" ;;
         2) echo "Low-f square wave]" ;;
         3) echo "Mid-f square wave]" ;;
         4) echo "PRN +/-1]" ;;
         5) echo "PRN full scale]" ;;
         6) echo "High-f square wave]" ;;
         7) echo "All zeroes]" ;;
         *) echo "Unknown]" ;;
         esac
         continue
         ;;
      4) echo "Q[1][MSB]" ; continue ;;
      5) echo "Q[1][LSB]" ; let nextIQ0=4 ; continue ;;
      508[2-7]) echo "Spare" ; continue ;;
      ### This is not one of the first or last six bytes; drop through
      *) true ;;
      esac

      ### After the sixth byte, the interleaving repeats on 508-byte periods
      let rowm6=($row0-6)%508

      ### If this is within the first 21 bytes, then this row's byte may
      ### be RT (Radiometry or Time Tag)
      if [ $rowm6 -lt 21 ] ; then
        ### if rowm6 is a multiple of 3, it is RT
        let rowm6mod3=$rowm6%3
        if [ $rowm6mod3 -eq 0 ] ; then
          ### step through 8-element RT prefix array rtpfx=(R R R R R T T T T)
          ### and suffix array=(39:32  31:24, ...) i.e. bit boundaries
          ### - rtidx is index within rtpfx and rtsfx
          ### - rtord is the ordinal of this RT value (not byte) within
          ###   the entire 5088-byte stream
          let rtidx=$nextRT0%8
          let rtord=($nextRT0/8)+1
          ### output Radiometry or Time Tag description e.g. R[5][23:15]
          echo "${rtpfx[$rtidx]}[$rtord][${rtsfx[$rtidx]}]"
          ### Increment count of RT bytes encountered so far
          let ++nextRT0
          continue
        fi
      fi

      ### To here this is an I or Q value; step through 4-element prefix and
      ### suffix arrays
      let iqidx=$nextIQ0%4
      let iqord=($nextIQ0/4)+1
      ### output IQ description e.g. Q[1234][LSB]
      echo "${iqpfx[$iqidx]}[$iqord][${iqsfx[$iqidx]}]"
      ### Increment count of IQ bytes encountered so far
      let ++nextIQ0

    ### Pipe while-read loop to gawk to format first two columns and append
    ### description for each row
    done \
  | gawk '{s="";for(i=2;i<=NF;++i){ s=s " " $i}printf "%5d%5d %s\n", FNR, $1, s }'

done

exit 0