;+
; Project     : SOHO - CDS     
;                   
; Name        : FAST_EMON
;               
; Purpose     : Gather engineering data statistics quickly.
;               
; Explanation : Reads engineering A/B packets from the science telemetry
;               files and gathers data on selected parameters.
;
;               Notes:    No time information is returned, just the data.
;               The parameters supplied (pname) are split into
;               eng A and eng B before processing, and are returned
;               separately.
;               This routine runs approx. 50 times faster than emon
;               
; Use         : IDL> fast_emon, a_data, b_data, a_names, b_names, fname, $
;               pname [,array=array] [,a_datpos] [,b_datpos]
;
; Inputs      : FNAME - file name (array) of telemetry files to be searched.
;               PNAME - parameter name (array) to be monitored.  Can contain
;                   any mixture of EngA and EngB parameters.
;               
; Opt. Inputs : none
;
; Outputs     : a_data  - array containing values of Eng A parameters chosen
;               b_data  - array containing values of Eng B parameters chosen
;               a_names - array giving the Eng A parameter names (reordered)
;               b_names - array giving the Eng B parameter names (reordered)
;               
; Opt. Outputs: a_datpos - original position of the EngA parameters in the data
;               b_datpos - ditto for EngB
;             
; Keywords    : ARRAY - size of storage arrays to overide the default 30000
;
; Calls       :
;
; Common      :
;               
; Restrictions: 
;               
; Side effects: 
;               
; Category    : Telemetry
;               
; Prev. Hist. : From emon, version 4, C D Pike, RAL, 29-Sep-94
;
; Written     : Eddie Breeveld (erb@mssl.ucl.ac.uk), 11 Nov 1996
;               
; Modified    : v3: Eddie Breeveld, 14 Jan 1997, allowed larger array size 
;                   (c.f. Emon version 6)
;               v4: Eddie Breeveld,  2 Sep 1997, added a/b_datpos outputs
;               v4.1 : Eddie Breeveld, 25 May 1998, fixed v5.2 hex constant
;                   feature
;
; Version     : 4.1
;-            

pro fast_emon, a_arr, b_arr, a_n_arr, b_n_arr, fname, pname, array=array, $
        a_datpos, b_datpos
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;  Step 1, setup the inputs needed
;
;
    if not keyword_set(array) then array_size = 30000L else array_size = array
;
;  replace characters
;
    wanted_parms = strupcase(pname)    
    n_parms = n_elements(wanted_parms)
;
    for i=0, n_parms-1 do begin
        wanted_parms(i) = repstr(wanted_parms(i),'_POS_','+')
        wanted_parms(i) = repstr(wanted_parms(i),'_NEG_','-')
    endfor
;
;  set up the mask etc details
;
    get_mask_etc, mask_etc
;
;  convert mask details for each parameter
;
    offset = intarr(n_parms)
    mask   = lonarr(n_parms)
    type   = intarr(n_parms)
;
    for i=0, n_parms-1 do begin            
        name = wanted_parms(i)
        n = where(mask_etc(0,*) eq name)
        if n(0) ge 0 then begin
            n = n(0)
;
;  first get the offsets
;
            offset(i) = fix(mask_etc(3,n))
;
;  Now get the mask
;
            temp = strmid(mask_etc(5,n),2,4)
            hex2dec,temp,mask(i),/quiet
            if (mask(i) eq 0) then mask(i) = 'FFFF'XL
;
;  Finally the type - 1 for byte, 2 for word, and 4 for longword
;
            case mask_etc(2,n) of
            'B':    type(i) = 1
            'W':    type(i) = 2
            'L':    type(i) = 4
            endcase
        endif
    endfor
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;  Step 2
;  Split into eng A and eng B data
;
    use_a = 1
    a_wanted = 0
    temp = [where(strmid(wanted_parms(*), 0, 1) eq 'A')]
    if temp(0) ne -1 then begin
        a_wanted = wanted_parms(temp) 
        a_offset = offset(temp)
        a_mask   = mask(temp)
        a_type   = type(temp)
        a_n_arr  = pname(temp)        ; return unadulterated param names 
;
    endif else use_a = 0
;
    use_b = 1
    b_wanted = 0
    temp = [where(strmid(wanted_parms(*), 0, 1) eq 'B')]
    if temp(0) ne -1 then begin
        b_wanted = wanted_parms(temp) 
        b_offset = offset(temp)
        b_mask   = mask(temp)
        b_type   = type(temp)
        b_n_arr  = pname(temp)        ; return unadulterated param names 
;
    endif else use_b = 0
;
;  Build up arrays to hold the result
;
    num_a = n_elements(a_wanted)
    num_b = n_elements(b_wanted)
;
    a_parm_data    = lonarr(num_a,array_size)
    b_parm_data    = lonarr(num_b,array_size)
    a_nparm_data   = 0L
    b_nparm_data   = 0L
    file_name      = fname
    a_datpos       = lonarr(array_size)
    b_datpos       = lonarr(array_size)
;
;  arrays for raw packet data and intermediate data
;
    packet = bytarr(306)
    a_data = lonarr(num_a)
    b_data = lonarr(num_b)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;  Step 3, loop over the files and extract the data
;
;
    counter = 0L
;
    for file_seq_no = 0, n_elements(file_name)-1 do begin
;
        print, 'Extracting data from ', file_name(file_seq_no), '...'
        openr, eng_lun, file_name(file_seq_no), /get_lun
;
        while not eof(eng_lun) do begin
;
;  read the file looking for eng packets
;
            readu, eng_lun, packet
            counter = counter + 1L
            if counter/10000.0 eq float(counter/10000) then $
                        print, 'Packet no.', counter
;
;  Eng A packets
;
            case 1 of
            (packet(18) eq '0A'x) and (use_a):  begin
                for i=0, num_a-1 do begin            
                    case a_type(i) of
                    1:  a_data(i) = packet(a_offset(i)) and a_mask(i)
                    2:  begin
                            temp = byteswap((fix(packet,a_offset(i),1))(0))
                            a_data(i) = long(temp) and a_mask(i)
                        end
                    4:  a_data(i) = (long(packet,a_offset(i),1))(0)
                    endcase
                endfor
;
                a_datpos(a_nparm_data) = counter
                a_parm_data(*,a_nparm_data) = a_data
                a_nparm_data = a_nparm_data + 1
            end
;
;  Eng B packets
;
            (packet(18) eq '0B'x) and (use_b): begin
                for i=0, num_b-1 do begin            
                    case b_type(i) of
                    1:  b_data(i) = packet(b_offset(i)) and b_mask(i)
                    2:  begin
                            temp = byteswap((fix(packet,b_offset(i),1))(0))
                            b_data(i) = long(temp) and b_mask(i)
                    end
                    4:  b_data(i) = (long(packet,b_offset(i),1))(0)
                    endcase
                endfor
;
                b_datpos(b_nparm_data) = counter
                b_parm_data(*,b_nparm_data) = b_data
                b_nparm_data = b_nparm_data + 1
            end
            else:
            endcase
;
        endwhile    ; loop to end of file
;
        free_lun, eng_lun
    endfor        ; loop over files
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;  Stage 4,
;  output Eng A and Eng B data
;
    if (use_a) then begin
        a_arr = a_parm_data(*,0:a_nparm_data-1)
        a_datpos = a_datpos(  0:a_nparm_data-1)
    endif
    if (use_b) then begin
        b_arr = b_parm_data(*,0:b_nparm_data-1)
        b_datpos = b_datpos(  0:b_nparm_data-1)
    endif
;
    return
end
