;+ ; NAME: ; smei_buf_read ; PURPOSE: ; Read Level 1A file in 'buf' format ; CATEGORY: ; camera/idl/buf ; CALLING SEQUENCE: FUNCTION smei_buf_read, l1a_file, pointer, $ get_file_header = get_file_header, $ file_header = file_header , $ frame_headers = frame_headers , $ frame_nr = frame_nr , $ frame_data = frame_data , $ get_next_frame = get_next_frame , $ silent = silent , $ force_close = force_close , $ trunc_time = trunc_time , $ start_pointer = start_pointer ; INPUTS: ; l1a_file scalar; type: string ; fully-qualified file name of SMEI l1a*.buf file. ; To close an open file, set l1a_file = '' ; pointer scalar; type: integer ; file pointer in l1a_file where the requested frame starts. ; This argument is optional, but if known, speeds up ; the process of finding a frame in the L1A file. ; OPTIONAL INPUT PARAMETERS: ; /get_file_header only fill file_header structure ; /get_next_frame get next frame from file ; If this keyword is set then the data file is kept open ; with the file pointer after the current frame. ; frame_nr=frame_nr ; get frame with number 'frame_nr' ; The frame number specified here should be taken ; from the header array returned in a previous call ; (this is a 1-based frame number). ; trunc_time array[1]; type: time structure ; used only when collecting all frame headers (i.e. ; keywords frame_nr_defined and get_next_frame NOT set, ; and argument have_pointer NOT set). The collection of ; frames stops at the indicated time instead of ; continuing until the end-of-file is reached. ; start_pointer scalar; type: integer ; when new l1a_file is opened move to file pointer ; to start_pointer and start processing from there ; instead of from the beginning of the file. ; 'start_pointer' is destroyed to avoid using ; in another l1a_file. ; OUTPUTS: ; status scalar; type: integer ; 0: failure; 1: success ; OPTIONAL OUTPUT PARAMETERS: ; file_header=file_header ; array[1]; type: file header structure ; frame_headers=frame_headers ; array[n]; type: frame header structure array ; an array with with headers for all frames is returned ; array[1]; type: frame header structure ; if 'frame_nr' is specified than the ; header for the matching frame is returned ; frame_data=frame_data ; array[n], array[n,m]; type: unsigned int, long or float ; if 'frame_nr' is set then the matching frame ; data are returned here. ; INCLUDE: @compile_opt.pro ; On error, return to caller @smei_roi_mask.pro ; ROI mask common block ; COMMON BLOCKS: common smei_read_buf_file, iu, open_file, open_hdr, pntr, last_frm, frm_count ; CALLS: ; InitVar, IsType, destroyvar, TimeGet, smei_buf_splitfile ; smei_frm_cvhdr, smei_property, TimeOp, boost, hide_env ; smei_filename, TimeUnit, IsTime, TimeLimits ; PROCEDURE: ; The content of SMEI .buf files is described in Don Mizuno's memo: ; ; The data area is padded to a 2D frame using the mask stored in ; the ASCII file smei_buf_roi.txt. This file contains a 318 x 64 array with values 0,1,2 and 3. ; 0: pixels outside the region of interest ; 1: pixels in the smei fov ; 2: pixels in the covered columns left and right ; 3; pixels in the square open areas outside the smei fov ; MODIFICATION HISTORY: ; MAR-2003, Paul Hick (UCSD/CASS) ; APR-2003, Paul Hick (UCSD/CASS) ; Fixed bug in frame header structure. The naxes values in the raw ; header were not updated when the ROI was applied (so the nic files ; prior to today (Apr 20) have naxes=[0,0] in the trailer). ; MAR-2003, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Entry frame_header.n_satured is filled here using the ; data extracted from the L1A file. ;- InitVar, get_file_header, /key InitVar, get_next_frame , /key InitVar, silent , 0 InitVar, force_close , /key usec = TimeUnit(/sec) have_pointer = IsType(pointer, /defined) frame_nr_defined = IsType(frame_nr, /defined) get_all_frame_headers = 1-(frame_nr_defined OR get_next_frame OR have_pointer) IF force_close THEN BEGIN IF IsType(iu, /defined) THEN BEGIN free_lun, iu IF NOT get_file_header then message, /info, $ hide_env(open_file)+' ('+strcompress(frm_count,/rem)+' frames)' destroyvar, iu, open_file, open_hdr, pntr, last_frm, frm_count ENDIF RETURN, 1 ENDIF IF IsType(iu, /defined) THEN BEGIN ; There is an open file close_file = get_file_header OR get_all_frame_headers OR l1a_file NE open_file IF NOT close_file THEN $ IF frame_nr_defined THEN $ close_file = frame_nr LE last_frm IF close_file THEN BEGIN free_lun, iu IF NOT get_file_header THEN message, /info, $ hide_env(open_file)+' ('+strcompress(frm_count,/rem)+' frames)' destroyvar, iu, open_file, open_hdr, pntr, last_frm, frm_count ENDIF ENDIF nhdr = 256L bhdr = bytarr(nhdr, /nozero) IF IsType(iu, /undefined) THEN BEGIN openr, /get_lun, iu, l1a_file, error=error IF error NE 0 THEN BEGIN destroyvar, iu message, /info, !error_state.msg RETURN, 0 ENDIF point_lun, -iu, pntr ; Initialize file pointer (to zero) readu, iu, bhdr pntr += nhdr open_file = l1a_file open_hdr = smei_buf_splitfile(bhdr) IF NOT IsType(open_hdr, /structure) THEN BEGIN message, /info, hide_env(open_file)+', funny file name in header?, '+open_hdr free_lun, iu destroyvar, iu, open_file, open_hdr, pntr, last_frm, frm_count message, 'aborting' ENDIF last_frm = 0L frm_count = 0L file_header = open_hdr IF IsType(start_pointer,/defined) THEN BEGIN pntr = start_pointer destroyvar, start_pointer point_lun, iu, pntr ENDIF ENDIF CASE get_file_header OF 0: BEGIN destroyvar, frame_headers IF get_next_frame THEN $ IF NOT frame_nr_defined THEN $ frame_nr = last_frm+1 IF have_pointer THEN BEGIN IF pointer NE pntr THEN BEGIN pntr = pointer point_lun, iu, pntr ; Set pointer ENDIF ENDIF ; Set up I/O error henadler status = 0 on_ioerror, no_more_frames readu, iu, bhdr pntr += nhdr ; Update file pointer next_frame: frame_header = smei_frm_cvhdr(from_byte=bhdr, /to_hdr, /swap, $ tlm_file=open_hdr.tlm_file, l1a_file=open_file, l1a_pntr=pntr-nhdr) IF have_pointer THEN $ IF NOT frame_nr_defined THEN $ frame_nr = frame_header.frame_nr IF silent LE -1 THEN message, /info, smei_property(frame_header,/name) ; Length of data area in bytes len_data = frame_header.n_data*abs(frame_header.bitpix)/8 IF get_all_frame_headers THEN BEGIN ; Skip past data area by moving file pointer pntr += len_data point_lun, iu, pntr ; Set file pointer ; Collect all the frame headers. IF frm_count EQ 0 THEN BEGIN ; IF open_hdr.total_frames LE 0 THEN $ ; message, 'Invalid # frames reported in file header:'+ $ ; strcompress(open_hdr.total_frames) frame_headers = replicate(frame_header, open_hdr.total_frames) time_headers = replicate(!TheTime , open_hdr.total_frames) ENDIF ;ELSE IF frm_count GT open_hdr.total_frames-1 THEN BEGIN ; message, 'Frame index out of range:'+ $ ; strcompress(frm_count+1)+'/'+ $ ; strcompress(open_hdr.total_frames,/rem) ;ENDIF frame_time = smei_property(frame_header,/time) IF IsTime(trunc_time) THEN BEGIN IF TimeOp(/subtract,frame_time,trunc_time,TimeUnit(/sec)) GT 0 THEN BEGIN frame_headers = frame_headers[0:frm_count-1] time_headers = time_headers [0:frm_count-1] !error_state.msg = 'truncated headers at '+TimeGet(trunc_time,/_ydoy,upto=usec) goto, no_more_frames ENDIF ENDIF frame_headers[frm_count] = frame_header time_headers [frm_count] = frame_time frm_count += 1 readu, iu, bhdr pntr += nhdr ; Update file pointer GOTO, next_frame ENDIF IF frame_nr NE frame_header.frame_nr THEN BEGIN ; Skip past data area by moving file pointer pntr += len_data point_lun, iu, pntr ; Set file pointer readu, iu, bhdr pntr += nhdr GOTO, next_frame ENDIF IF arg_present(frame_data) THEN BEGIN ; Read data of type indicated by frame_header.bitpix bitpix = frame_header.bitpix CASE bitpix OF 16: data_area = uintarr( frame_header.n_data, /nozero ) 32: data_area = long ( frame_header.n_data, /nozero ) -32: data_area = float ( frame_header.n_data, /nozero ) ENDCASE readu, iu, data_area pntr += len_data ; Update file pointer byteorder, data_area, sswap=bitpix EQ 16, $ lswap=bitpix EQ 32, xdrtof=bitpix EQ -32, /swap_if_little_endian mode = where( data_area GE ([65535,49147])[frame_header.flat_enabled], n_saturated ) frame_header.n_saturated = n_saturated mode = frame_header.mode frame_dim = *roi_siz[mode] CASE frame_header.full_frame OF 0: BEGIN frame_data = make_array( type=IsType(data_area), dim=frame_dim ) frame_data[ *roi_frm[mode] ] = data_area frame_header.full_frame = 1 frame_header.naxes = frame_dim frame_header.n_data = frame_dim[0]*frame_dim[1] END 1: BEGIN frame_data = reform(data_area, frame_header.naxes) IF frame_header.naxes[0] LT frame_dim[0] THEN BEGIN plus = frame_dim[0]-frame_header.naxes[0] boost, frame_data, /lead, plus=plus frame_header.naxes[0] = frame_dim[0] frame_header.n_data = frame_dim[0]*frame_header.naxes[1] message, /info, smei_filename(smei_property(frame_header,/time), $ camera=frame_header.camera,mode=mode,type='')+' boosted by'+strcompress(plus) ENDIF END ENDCASE ENDIF ELSE BEGIN ; Skip past data area by moving file pointer pntr += len_data point_lun, iu, pntr ; Set file pointer ENDELSE frm_count += 1 frame_headers = frame_header time_headers = smei_property(frame_header, /time) last_frm = frame_nr status = 1 no_more_frames: on_ioerror, null ; Print error message (other than EOF) eof_reached = status EQ 0 IF eof_reached THEN BEGIN eof_reached = strpos(!error_state.msg,'End of file') NE -1 IF NOT eof_reached then message, /info, !error_state.msg ENDIF ; Always close file if status=0. Return status=1 ; only when reading all frame headers (error was EOF). ; status=1: happens when succesfully locating a single frame. Keep the ; file open only if /get_next_frame was set, and the current frame was ; located. close_file = status EQ 0 OR NOT get_next_frame status = status OR get_all_frame_headers ; We assume that all frames in a file fall inside the time range indicated ; in the L1A file name. If this is not true we may run into trouble. IF get_all_frame_headers AND frm_count GT 0 THEN BEGIN nut = where(TimeOp(/subtract,time_headers, open_hdr.ut_start,usec) LT 0 OR $ TimeOp(/subtract,time_headers, open_hdr.ut_stop ,usec) GT 0) IF nut[0] NE -1 THEN BEGIN message, /info, hide_env(open_file)+' '+strjoin(TimeGet([open_hdr.ut_start,open_hdr.ut_stop],/ydoy,upto=usec),' - ') message, /info, strcompress(n_elements(nut),/rem)+' frames outside file time range' message, /info, 'frame range '+strjoin(TimeGet(TimeLimits(time_headers, /bounds),/ydoy,upto=usec),' - ') ENDIF ENDIF END 1: BEGIN close_file = 1 status = 1 END ENDCASE IF close_file THEN BEGIN free_lun, iu IF silent LE 0 THEN BEGIN IF l1a_file NE open_file THEN message, 'oops 13' CASE 1 OF get_file_header : message, /info, hide_env(open_file)+' ('+strcompress(open_hdr.total_frames, /rem)+' frames claimed)' get_all_frame_headers: message, /info, hide_env(open_file)+' ('+strcompress(frm_count, /rem)+'/'+strcompress(open_hdr.total_frames,/rem)+' hdrs)' get_next_frame : if eof_reached then message, /info, hide_env(open_file)+' ('+strcompress(frm_count,/rem)+'/'+strcompress(open_hdr.total_frames,/rem)+' frames)' ELSE : message, /info, hide_env(open_file)+' (frame@'+TimeGet(time_headers,/ydoy,upto=usec)+')' ENDCASE ENDIF destroyvar, iu, open_file, open_hdr, pntr, last_frm, frm_count ENDIF RETURN, status & END