;+
; NAME: eis_make_status_fits.pro
;
; PURPOSE: To convert solar-B ccsds status packet archives into
;          level-0 fits format.
;          Converts ICU/PSU, CAM, MHC and Eis specific parameters of
;          HK1 status packets.
;      
; CATEGORY: Engineering
;
; CALLING SEQUENCE: eis_make_status_fits, 'status_archive' [,output=output]
;
; INPUTS: Filename string of the status archive
;
; KEYWORD PARAMETERS: Set output (string) to an existing directory
; where the fits output will be written. Default to '/tmp'.
;
; OUTPUTS: One fits file per status APID in either /tmp or the
; directory specified by output.
;
; CALLS: Various SSW fits routines.
;
; COMMON BLOCKS:None.
;
; PROCEDURE:
;
; RESTRICTIONS: Uses SolarSoft
;               To do: history keywords and updating
;
; MODIFICATION HISTORY:
;	17/09/06 mcrw   v2.0
;                       New version based on version 1.1
;                       Does not split ccsds header up
;
; Needs altering so that the mhc mechanisms first/last position can be
; put in
;-


; Utility functions to extract bytes and bits.
; offset is the byte offset into the packet from location 0
; Extracts a byte from the array at offset location. Last 2 parameters
; unused but provided to make a standard calling sequence.
function eis_extractByte, dataArray, offset, startBit, numBits
    return, dataArray[offset, *]
end

; Extracts a 2-byte word
function eis_extractWord, dataArray, offset, startBit, numBits
    return, ishft(fix(dataArray[offset, *]), 8) or fix(dataArray[offset + 1, *])
end

; Extracts a 4-byte word
function eis_extractDoubleWord, dataArray, offset, startBit, numBits
    return, long(ishft(long(dataArray[offset,     *]), 24) or $
            ishft(long(dataArray[offset + 1, *]), 16) or $
            ishft(long(dataArray[offset + 2, *]),  8) or $
                  long(dataArray[offset + 3, *]))
end

; Extracts the top 4 bits from a byte
function eis_extractMsNibble, dataArray, offset, startBit, numBits
    return, byte(ishft(dataArray[offset, *], -4))
end

; Extracts the bottom 4 bits from a byte
function eis_extractLsNibble, dataArray, offset, startBit, numBits
    return, byte(dataArray[offset, *] and 15)
end

; Extracts n-bits from anywhere in a byte. No error checking.
; Bit order is: bit 0 (2^7) .. bit 7 (2^0), unfortunately
function eis_extractBitsFromByte, dataArray, offset, startBit, numBits
    foo = dataArray[offset, *]
    range = (startBit + numBits) - 1
    shift = 0 - (7 - range) ; negative for right shift
    mask = (2 ^ numBits) - 1
    return, byte(ishft(foo, shift) and mask)
end

; Extract n-bits from a 16 bit word. Starting offset is first byte
; of word
function eis_extractBitsFromWord, dataArray, offset, startBit, numBits
    word_array = eis_extractWord(dataArray, offset, startBit, numBits)
    range = (startBit + numBits) - 1
    shift = 0 - (15 - range) ; negative for right shift
    mask = (2 ^ numBits) - 1
    return, fix(ishft(word_array, shift) and mask)
end

function eis_extract24Bits, dataArray, offset, startBit, numBits
    long_array = eis_extractDoubleWord(dataArray, offset, startBit, numBits)
    return, long(ishft(long_array, -8) and '00FFFFFF'X)
end

; Main procedure
pro eis_get_ccsds_packets, file, hk1, hk2, aocs, s1, s2, s3

    openr, lu, file, /get_lun

    ; Extract gnd receive time from filename
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    grt = '20060811113116' ; Dummy for testing

    ; Initalize packet counters
    packetCount   = 0L
    sts1Count     = 0L
    sts2Count     = 0L
    sts3Count     = 0L
    hk1Count      = 0L
    hk2Count      = 0L
    hk440Count    = 0L

    ; Initialize start times
    sts1StartTime   = 0L
    sts2StartTime   = 0L
    sts3StartTime   = 0L
    hk1StartTime    = 0L
    hk2StartTime    = 0L
    hk440StartTime  = 0L

    ; Initialize flags that control appending data onto the byte arrays
    sts1Flag   = 0
    sts2Flag   = 0
    sts3Flag   = 0
    hk1Flag    = 0
    hk2Flag    = 0
    hk440Flag  = 0

    ; Allocate room for 10,000 packets of each APID type (a tad excessive perhaps)
    sts1Data   = bytarr(110L * 10000, /nozero)
    sts2Data   = bytarr(160L * 10000, /nozero)
    sts3Data   = bytarr(160L * 10000, /nozero)
    hk1Data    = bytarr(436L * 10000, /nozero)
    hk2Data    = bytarr(436L * 10000, /nozero)
    hk440Data  = bytarr(436L * 10000, /nozero)

    ; Ccsds packet stuff
    ccsdsHeader = bytarr(10)	; Split so we can get ccsds seq count (not in hk1)

;    ccsdsSequenceCount = 0L
;    spacecraftTime     = 0L

    ; Array for the packet data of each apid
    sts1Packet  = bytarr(100)
    sts2Packet  = bytarr(150)
    sts3Packet  = bytarr(150)
    hk1Packet   = bytarr(426)

    on_ioerror, FINISH
    
    ; Read in the data...
    while not eof(lu) do begin

        ; Get the Ccsds headers
        readu, lu, ccsdsHeader
;        readu, lu, spacecraftTime

;        temp = ccsdsHeader[2:3]
;        ccsdsSequenceCount = ishft(fix(temp[0]), 8) + temp[1]
;        ccsdsSequenceCount = ccsdsSequenceCount and '3FFF'X

;        byteorder, spacecraftTime, /htonl

        ; Calculate APID and user data length (used to create buffers on the fly)
        apid = ishft((ulong(ccsdsHeader[0]) and 7), 8) or ulong(ccsdsHeader[1])

        ; Process each type of packet according to its APID
        case apid of

	    '420'X : begin	;;; hk1 (only in ISAS generated archives)
                readu, lu, hk1Packet
                if hk1Flag eq 0 then begin
                    hk1Flag = 1
                    hk1Data = [ccsdsHeader, hk1Packet]
                endif else begin
                    hk1Data = [hk1Data, [ccsdsHeader, hk1Packet]]
                endelse
                hk1Count = hk1Count + 1
                packetCount = packetCount + 1
            end
	    '428'X : begin	;;; (only in ISAS generated archives)
                readu, lu, hk1Packet
                if hk2Flag eq 0 then begin
                    hk2Flag = 1
                    hk2Data = [ccsdsHeader, hk1Packet]
                endif else begin
                    hk2Data = [hk2Data, [ccsdsHeader, hk1Packet]]
                endelse
                hk2Count = hk2Count + 1
                packetCount = packetCount + 1
            end
	    '440'X : begin	;;; (only in ISAS generated archives)
                readu, lu, hk1Packet
                if hk440Flag eq 0 then begin
                    hk440Flag = 1
                    hk440Data = [ccsdsHeader, hk1Packet]
                endif else begin
                    hk440Data = [hk440Data, [ccsdsHeader, hk1Packet]]
                endelse
                hk440Count = hk440Count + 1
                packetCount = packetCount + 1
            end
            '5C4'X : begin	;;; Status 1
                readu, lu, sts1Packet
                if sts1Flag eq 0 then begin
                    sts1Flag = 1
                    sts1Data = [ccsdsHeader, sts1Packet]
                endif else begin
                    sts1Data = [sts1Data, [ccsdsHeader, sts1Packet]]
                endelse
                sts1Count = sts1Count + 1
                packetCount = packetCount + 1
            end
            '5C6'X : begin	;;; Status 2
                readu, lu, sts2Packet
                if sts2Flag eq 0 then begin
                    sts2Flag = 1
                    sts2Data = [ccsdsHeader, sts2Packet]
                endif else begin
                    sts2Data = [sts2Data, [ccsdsHeader, sts2Packet]]
                endelse
                sts2Count = sts2Count + 1
                packetCount = packetCount + 1
            end
            '5C8'X : begin	;;; Status 3
                readu, lu, sts3Packet
                if sts3Flag eq 0 then begin
                    sts3Flag = 1
                    sts3Data = [ccsdsHeader, sts3Packet]
                endif else begin
                    sts3Data = [sts3Data, [ccsdsHeader, sts3Packet]]
                endelse
                sts3Count = sts3Count + 1
                packetCount = packetCount + 1
            end
	    '0'X  : begin	;;; loss of hk detected by egse (only in MSSL generated archives)
                len  = ishft(ulong(ccsdsHeader[4]), 8) or ulong(ccsdsHeader[5]) - 3
                buffer = bytarr(len)
                readu, lu, buffer
            end
	    'F0'X  : begin	;;; start of archive (only in MSSL generated archives)
                len  = ishft(ulong(ccsdsHeader[4]), 8) or ulong(ccsdsHeader[5]) - 3
                buffer = bytarr(len)
                readu, lu, buffer
            end
	    '7FF'X  : begin	;;; start of hk (only in MSSL generated archives)
                len  = ishft(ulong(ccsdsHeader[4]), 8) or ulong(ccsdsHeader[5]) - 3
                buffer = bytarr(len)
                readu, lu, buffer
            end
            '1CC'X : begin	;;; Telecommand (only in MSSL generated archives)
                len  = ishft(ulong(ccsdsHeader[4]), 8) or ulong(ccsdsHeader[5]) - 3
                buffer = bytarr(len)
                readu, lu, buffer
            end
            else : begin
                print, 'Unknown APID ', apid ; Bit of an error if this happens...
            end
        endcase
    endwhile

FINISH:

    ; All data read in - debug print
    print, 'Packet Count : ', packetCount
    print, 'HK 1 packets : ', hk1Count
    print, 'HK 2 packets : ', hk2Count
    print, 'HK 440 packets : ', hk440Count
    print, 'Status 1 packets : ', sts1Count
    print, 'Status 2 packets : ', sts2Count
    print, 'Status 3 packets : ', sts3Count

;help,hk1Data
;help,sts1Data
;help,sts2Data
;help,sts3Data

    ; Close the input file
    close, lu
    free_lun, lu

    ; No point continuing if there are no packets
    if packetCount eq 0 then return

    ; Re-arrange the data into columns, if there is any data that is...
    if sts1Count gt 0 then begin
        sts1Data = reform(temporary(sts1Data), 110, sts1Count, /overwrite)
    endif
    if sts2Count gt 0 then begin
        sts2Data = reform(temporary(sts2Data), 160, sts2Count, /overwrite)
    endif
    if sts3Count gt 0 then begin
        sts3Data = reform(temporary(sts3Data), 160, sts3Count, /overwrite)
    endif

    ; In case we are dealing with a MSSL archive which does not have hk1
    if hk1count gt 0 then begin
        hk1Data  = reform(temporary(hk1Data), 436, hk1Count, /overwrite)
    endif

    if hk2count gt 0 then begin
        hk2Data  = reform(temporary(hk2Data), 436, hk2Count, /overwrite)
    endif

    if hk440count gt 0 then begin
        hk440Data  = reform(temporary(hk440Data), 436, hk440Count, /overwrite)
    endif

    hk1 = hk1Data
    hk2 = hk2Data
    aocs = hk440Data
    s1 = sts1Data
    s2 = sts2Data
    s3 = sts3Data

end
