;+ ; NAME: ; smei_frm_cvhdr ; PURPOSE: ; Convert frame headers between various formats ; CATEGORY: ; camera/idl/frm ; CALLING SEQUENCE: FUNCTION smei_frm_cvhdr, $ from_hdr = from_hdr , $ from_byte = from_byte , $ from_fits = from_fits , $ to_ascii = to_ascii , $ to_fits = to_fits , $ to_byte = to_byte , $ to_hdr = to_hdr , $ swap_bytes = swap_bytes, $ tlm_file = tlm_file , $ l1a_file = l1a_file , $ l1a_pntr = l1a_pntr , $ length = length , $ allow_bad = allow_bad ; OPTIONAL INPUT PARAMETERS: ; from_hdr=from_hdr array[1]; type: smei_frm_hdr structure ; frame header ; ; from_byte=from_byte array[256] or array[512]; type: byte ; binary header from L1A file (256 bytes) or ; trailer from .nic file (512 bytes). ; A trailer from .nic file should have the ; starting byte('buf') removed already. ; ; from_fits=from_fits array[n]; type: string ; fits header extracted from SMEI frame fits file ; ; /to_hdr return header as a smei_frm_hdr structure ; /to_byte return header as a 256 or 512 byte array ; /to_fits return header as a fits header string array ; if the fits header is not from a SMEI camera frame ; then the integer -1 is returned. ; /to_ascii return a single string with an ascii representation ; of selected information from the header (used primarily ; for display in widgets). ; /swap_bytes if set, then bytes are swapped in the byte header ; (used if from_byte=from_byte or /to_byte is used. ; OUTPUTS: ; rtn_hdr header in format selected with /to_* keywords ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, IsType, GetFileSpec, smei_property ; strposn, TimeGet, TimeSet, TimeUnit, TimeOp, cvsmei ; jpl_eph, jpl_body, eclipsed_area, AngleRange, smei_frm_flag ; sgp4_eph, smei_filename ; EXTERNAL ; smei_frm_hdr__define ; PROCEDURE: ; Only a selection of the data in the header are put in the string, ; separated by the newline character (10B). ; ; The binary frame header in the Hanscom L1A*.buf files binary header ; has 256 bytes. These are in Unix format (big-endian), i.e. byte swapping ; is necessary on i386 machines (which are little-endian). ; ; The .nic files contain a 512 byte trailer. ; The first 3 bytes in the .nic files are used to store the ASCII string 'buf' ; (to distinguish them from other .nic files, e.g. the TMO data). ; The next 256 bytes in the .nic trailer (bytes 3-258) are a copy ; of the frame header found in the Hanscom L1A*.buf files, except for byte ; swapping when necessary (i.e. they are little-endian). ; The remaining 253 bytes are partially filled with UCSD extensions: ; ; 259 + ; byte 0- 59 (60) name of original telemetry file ; byte 60-119 (60) name of original L1A file ; byte 120-123 ( 4) file pointer into L1A file ; ; byte 184-187 ( 4) # pixels contributing to pedestal ; byte 188-191 ( 4) # pixels contributing to dark current ; byte 192-196 ( 4) # pixels in negative measles ; byte 196-199 ( 4) # pixels in positive measles ; byte 200-203 ( 4) # pixels in big measles ; byte 204-207 ( 4) # pixels in cosmic rays ; byte 208-211 ( 4) # pixels in big cosmic rays ; byte 212-215 ( 4) residual intensity in squares ; byte 216-219 ( 4) residual intensity in center group ; byte 220-223 ( 4) standard deviation of pedestal ; byte 224-227 ( 4) standard deviation of dark current ; byte 228-231 ( 4) flags ; ; MODIFICATION HISTORY: ; OCT-2003, Paul Hick (UCSD/CASS) ; Extracted from smei_buf_splitframe ; JUN-2004, Paul Hick (UCSD/CASS) ; Added room for name of another pattern file name. ; Rearranged to put everything at proper boundaries. ; MAR-2005, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Added code to fill hdr.sun,hdr.moon,hdr.venus,hdr.ra,hdr.dec ; and hdr.angle, hdr.eclipse and hdr.shadow using JPL ephemeris ; and Coriolis orbital elements run through sgd4. ; Note that for the first real-time downloads of the ; SMEI data the orbital elements will probably be out of date, so ; especially hdr.moon and hdr.eclipse should be treated with suspicion ; until this has been rerun with valid orbital elements. ;- InitVar, to_hdr , /key InitVar, to_ascii , /key InitVar, to_fits , /key InitVar, to_byte , /key InitVar, swap_bytes , /key InitVar, length , 256 InitVar, allow_bad , /key IF IsType( from_byte, /defined ) THEN BEGIN hdr = {smei_frm_hdr} ii = from_byte[0:3] IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian hdr.frame_nr = long(ii,0) hdr.camera = from_byte[4] hdr.roi_map = from_byte[5] hdr.mode = from_byte[6] hdr.tagmode = from_byte[7] ii = from_byte[8:9] IF swap_bytes THEN byteorder, ii, /sswap, /swap_if_little_endian hdr.bitpix = fix(ii,0) hdr.full_frame = from_byte[10] ; Added in V1.1. Was unused in V1.0 hdr.shutter = from_byte[11] ii = from_byte[12:23] IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian ii = long(ii,0,3) hdr.naxes = ii[0:1] hdr.n_data = ii[2] ;================================================================== ; KLUDGE ; ; For unpadded data (hdr.full_frame = 0) we expect a data area of 1,4,16 ; times 7947 pixels (7947, 31788 or 127152). These we now how to pad to ; a 2D frame using the roi.fits mask. On one occasion a data area of ; 324608 = 1268 x 256 was found, but still with full_frame, nx and ; ny all set to zero. Try to detect these here on the assumption ; that these data are already padded with 64, 128 or 256 pixels in the ; y-dimension depending on the mode. IF hdr.full_frame EQ 0 AND $ (where(hdr.n_data EQ [1,4,16]*7947L))[0] EQ -1 THEN BEGIN ny = 256/2^hdr.mode nx = hdr.n_data/ny IF nx*ny EQ hdr.n_data THEN BEGIN hdr.full_frame = 1 hdr.naxes = [nx,ny] ENDIF ENDIF ELSE BEGIN IF hdr.full_frame EQ 1 AND hdr.naxes[0]*hdr.naxes[1] NE hdr.n_data THEN message, 'zero dimension' ENDELSE ;================================================================== ii = from_byte[24:47] IF swap_bytes THEN byteorder, ii, /xdrtod, /swap_if_little_endian ii = double(ii,0,3) start_ut = ii[0] stop_ut = ii[1] julian_date = ii[2] hdr.exposure = round(stop_ut-start_ut) ii = from_byte[48:55] IF swap_bytes THEN byteorder, ii, /sswap, /swap_if_little_endian ii = fix(ii,0,4) year = ii[0] day = ii[1] hour = ii[2] minute = ii[3] ii = from_byte[56:71] IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian ii = float(ii,0,4) hdr.time = TimeSet(year=year,doy=day,hour=hour,minute=minute,sec=ii[0]) IF TimeOp(/subtract,hdr.time,TimeSet(yr=2000,doy=1,hr=12),TimeUnit(/second)) $ NE round(start_ut) THEN message, 'inconsistent start_ut in '+smei_property(hdr,/name) IF TimeGet(hdr.time,/jd) NE julian_date THEN $ message, 'inconsistent julian date in '+smei_property(hdr,/name) IF hdr.exposure NE 4 THEN BEGIN tmp = 'exposure time is'+strcompress(hdr.exposure)+' seconds' message, /info, tmp spawn, 'echo "'+smei_filename(hdr.time,camera=hdr.camera,mode=hdr.mode)+ $ ' '+tmp+'" | mail pphick@ucsd.edu -sexposure"' ENDIF hdr.ra = ii[1] hdr.dec = ii[2] hdr.angle = ii[3] ii = from_byte[72:135] IF swap_bytes THEN byteorder, ii, /xdrtod, /swap_if_little_endian ii = double(ii,0,8) hdr.quat = ii[0:3] hdr.rquat = ii[4:7] ii = from_byte[136:159] IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian ii = float(ii,0,6) hdr.sun = ii[0:2] hdr.moon = ii[3:5] hdr.venus = replicate(0d0,3) hdr.dark_offset = from_byte[160] hdr.flatfield = from_byte[161] ; Large-scale flatfield hdr.cosmic_rays = from_byte[162] hdr.calibration = from_byte[163] ii = from_byte[164:171] IF swap_bytes THEN byteorder, ii, /xdrtod, /swap_if_little_endian hdr.bad_data = double(ii,0) ii = from_byte[182:185] IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian hdr.obs_frame = long(ii,0) hdr.flat_enabled = from_byte[186] ; Small-scale (onboard) flatfield hdr.led_enabled = from_byte[187] hdr.bos_alert = from_byte[188] hdr.bos_change = from_byte[189] hdr.fixed_bits = from_byte[190] hdr.corrupt_pix = from_byte[191] hdr.cr_hits = from_byte[192] ii = from_byte[194:201] IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian ii = float(ii,0,2) hdr.attitude_dt = ii[0] hdr.ccd_temp = ii[1] IF n_elements(from_byte) GT 256 THEN BEGIN ; If from_byte gt 256 then it probably is a modified byte header with ; UCSD extensions already added to the Hanscom structure hdr.tlm_file = GetFileSpec(string( from_byte[256 :256+ 59] ),part='name') hdr.l1a_file = GetFileSpec(string( from_byte[256+60:256+119] ),part='name') ii = from_byte[256+120:256+123] IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian hdr.l1a_pntr = long(ii,0) ENDIF ELSE BEGIN ; Add extensions to UCSD structure here, if supplied by keyword. IF IsType(tlm_file, /defined) THEN hdr.tlm_file = GetFileSpec(tlm_file,part='name') IF IsType(l1a_file, /defined) THEN hdr.l1a_file = GetFileSpec(l1a_file,part='name') IF IsType(l1a_pntr, /defined) THEN hdr.l1a_pntr = l1a_pntr ENDELSE rr = [[0,0,1],[1,0,0]] ; Unit vectors along z and x axis in camera frame rr = cvsmei( $ camera = smei_property(hdr,/camera) , $ quaternion = smei_property(hdr,/quaternion), $ from_camera = rr , $ /to_equatorial , $ /rectangular , $ /silent) ; PA with equatorial north hdr.angle = atan(rr[1,0]*rr[0,1]-rr[0,0]*rr[1,1],rr[2,1])*(180d0/!dpi) rr = cv_coord(from_rect=rr[*,0], /to_sphere, /degrees) hdr.ra = AngleRange(rr[0],/degrees) ; RA optical axis in range [0,360] hdr.dec = rr[1] ; Dec optical axis rr = [jpl_body(/sun),jpl_body(/moon),jpl_body(/venus),jpl_body(/earth)] ut = smei_property(hdr,/time) loc = sgp4_eph(ut, /location) ; Coriolis location loc = loc#replicate(1,n_elements(rr)) ; Get geocentric positions of Sun, Moon, Venus and Earth (note that ; earth will be [0,0,0]). rr = jpl_eph(ut, rr, center=jpl_body(/earth), /location) rr -= loc ; Change to topocentric coordinates tmp = cvsmei( $ camera = smei_property(hdr,/camera ), $ quaternion = smei_property(hdr,/quaternion), $ from_equatorial = rr, $ /rectangular , $ /to_camera , $ /force_unit , $ /silent) hdr.sun = tmp[*,0] hdr.moon = tmp[*,1] hdr.venus = tmp[*,2] tmp = cv_coord(from_rect=rr, /to_sphere) hdr.eclipse = eclipsed_area(tmp[*,0],tmp[*,1] ,/silent) NE 0 ; Eclipse by Moon? hdr.shadow = eclipsed_area(tmp[*,0],tmp[*,3],/earth,/silent) NE 0 ; Eclipse by Earth? hdr.version = 1.00d0 ENDIF ELSE IF IsType(from_hdr, /defined) THEN BEGIN hdr = from_hdr ENDIF ELSE IF IsType(from_fits, /defined) THEN BEGIN hdr = {smei_frm_hdr} names = tag_names(hdr) ; Process the FLAGS keyword. tmp = fxpar(from_fits, 'FLAGS', count=count) IF count EQ 0 THEN BEGIN message, /info, 'not a SMEI camera Fits header, missing keyword FLAGS' IF NOT allow_bad THEN RETURN, -1 ENDIF hdr = smei_frm_flag(hdr, flag=tmp, names=flag_names) start = 0 FOR i=0,n_elements(names)-1 DO BEGIN ; Skip keywords that are part of the default FITS header ; (nx -> NAXIS1, ny -> NAXIS2, BITPIX -> BITPIX) CASE names[i] OF 'BITPIX': hdr.(i) = fxpar(from_fits, 'BITPIX', start=0, precheck=0, postcheck=1, count=count) 'NAXES' : hdr.(i) = fxpar(from_fits, 'NAXIS*', count=count) 'TIME' : BEGIN tmp = fxpar(from_fits, 'TIME', count=count) IF count NE 0 THEN hdr.(i) = TimeSet(tmp,format='YYYY_DOY_hhmmss') END 'VERSION': BEGIN hdr.(i) = fxpar(from_fits, 'VERSION', count=count) IF count EQ 0 THEN hdr.(i) = 1.00d0 count = 1 END 'DARK_AVERAGE': BEGIN ; DARK_AVE is not present in most frames (yet; Jul-2008) hdr.(i) = fxpar(from_fits, strmid(names[i],0,8), start=start, precheck=-1, postcheck=1, count=count) IF count EQ 0 THEN $ hdr.(i) = fxpar(from_fits, 'BAD_DATA', start=start, precheck=-1, postcheck=1, count=count) END 'SDARK003': BEGIN ; SDARK003 only present for cam 3 for 2006 and later hdr.(i) = fxpar(from_fits, strmid(names[i],0,8), start=start, precheck=-1, postcheck=1, count=count) IF count EQ 0 THEN $ hdr.(i) = fxpar(from_fits, 'BAD_DATA', start=start, precheck=-1, postcheck=1, count=count) END 'SDARK010': BEGIN ; SDARK010 only present for cam 3 for 2006 and later hdr.(i) = fxpar(from_fits, strmid(names[i],0,8), start=start, precheck=-1, postcheck=1, count=count) IF count EQ 0 THEN $ hdr.(i) = fxpar(from_fits, 'BAD_DATA', start=start, precheck=-1, postcheck=1, count=count) END ELSE: BEGIN IF (where(names[i] EQ flag_names))[0] EQ -1 THEN BEGIN nh = n_elements(hdr.(i)) CASE nh EQ 1 OF 0: hdr.(i) = fxpar(from_fits, strmid(names[i],0,7)+'*', count=count) 1: hdr.(i) = fxpar(from_fits, strmid(names[i],0,8), start=start, precheck=-1, postcheck=1, count=count) ENDCASE ENDIF ELSE $ count = 1 END ENDCASE IF count EQ 0 THEN BEGIN message, /info, 'not a SMEI camera Fits header, missing keyword '+names[i] IF NOT allow_bad THEN RETURN, -1 ENDIF ENDFOR ENDIF ; We now have a smei_frm_hdr structure CASE 1 OF to_hdr : rtn_hdr = hdr to_byte : BEGIN rtn_hdr = bytarr(length) ii = hdr.frame_nr IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian rtn_hdr[0:3] = byte(ii,0,4) rtn_hdr[4] = hdr.camera rtn_hdr[5] = hdr.roi_map rtn_hdr[6] = hdr.mode rtn_hdr[7] = hdr.tagmode ii = hdr.bitpix IF swap_bytes THEN byteorder, ii, /sswap, /swap_if_little_endian rtn_hdr[8:9] = byte(ii,0,2) rtn_hdr[10] = hdr.full_frame ; Added in V1.1. Was unused in V1.0 rtn_hdr[11] = hdr.shutter ii = [hdr.naxes,hdr.n_data] IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian rtn_hdr[12:23] = byte(ii,0,12) start_ut = TimeOp(/subtract,hdr.time,TimeSet(yr=2000,doy=1,hr=12),TimeUnit(/second)) stop_ut = start_ut+hdr.exposure start_ut = double(start_ut) stop_ut = double(stop_ut ) julian_date = TimeGet(hdr.time,/jd) ii = [start_ut,stop_ut,julian_date] IF swap_bytes THEN byteorder, ii, /xdrtod, /swap_if_little_endian rtn_hdr[24:47] = byte(ii,0,24) year = TimeGet(hdr.time, TimeUnit(/year)) day = TimeGet(hdr.time, TimeUnit(/day )) hour = TimeGet(hdr.time, TimeUnit(/hour)) minute = TimeGet(hdr.time, TimeUnit(/minute)) ii = fix([year,day,hour,minute]) IF swap_bytes THEN byteorder, ii, /sswap, /swap_if_little_endian rtn_hdr[48:55] = byte(ii,0,8) second = TimeGet(hdr.time, TimeUnit(/sec)) ii = float([second,hdr.ra,hdr.dec,hdr.angle]) IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian rtn_hdr[56:71] = byte(ii,0,16) ii = [hdr.quat,hdr.rquat] IF swap_bytes THEN byteorder, ii, /xdrtod, /swap_if_little_endian rtn_hdr[72:135] = byte(ii,0,64) ii = float([hdr.sun,hdr.moon]) IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian rtn_hdr[136:159] = byte(ii,0,24) rtn_hdr[160] = hdr.dark_offset rtn_hdr[161] = hdr.flatfield rtn_hdr[162] = hdr.cosmic_rays rtn_hdr[163] = hdr.calibration ii = hdr.bad_data ; blank_double IF swap_bytes THEN byteorder, ii, /xdrtod, /swap_if_little_endian rtn_hdr[164:171] = byte(ii,0,8) ii = -999.0 ; blank_float IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian rtn_hdr[172:175] = byte(ii,0,4) ii = -65535L ; blank_long IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian rtn_hdr[176:179] = byte(ii,0,4) ii = -1 ; blank_short IF swap_bytes THEN byteorder, ii, /sswap, /swap_if_little_endian rtn_hdr[180:181] = byte(ii,0,2) ii = hdr.obs_frame IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian rtn_hdr[182:185] = byte(ii,0,4) rtn_hdr[186] = hdr.flat_enabled rtn_hdr[187] = hdr.led_enabled rtn_hdr[188] = hdr.bos_alert rtn_hdr[189] = hdr.bos_change rtn_hdr[190] = hdr.fixed_bits rtn_hdr[191] = hdr.corrupt_pix rtn_hdr[192] = hdr.cr_hits rtn_hdr[193] = 0 ii = float([hdr.attitude_dt, hdr.ccd_temp]) IF swap_bytes THEN byteorder, ii, /xdrtof, /swap_if_little_endian rtn_hdr[194:201] = byte(ii,0,8) ; UCSD addition to Hanscom structure IF length GT 256 THEN BEGIN ; Length should be 512 rtn_hdr[256 :255 +strlen(hdr.tlm_file)] = byte(hdr.tlm_file) rtn_hdr[256+60:255+60+strlen(hdr.l1a_file)] = byte(hdr.l1a_file) ii = hdr.l1a_pntr IF swap_bytes THEN byteorder, ii, /lswap, /swap_if_little_endian rtn_hdr[256+120:256+123] = byte(ii,0,4) ENDIF END to_fits: BEGIN ; Make a basic fits header based on the data mkhdr, rtn_hdr, IsType(/unsigned_short), [hdr.naxes] names = tag_names(hdr) comments = ' '+smei_frm_comments(hdr) fxaddpar, rtn_hdr, 'FLAGS', smei_frm_flag(hdr,names=flag_names), ' bitwise flags' FOR i=0, n_elements(names)-1 do begin ; Skip keywords that are part of the default FITS header ; (NAXES[0] -> NAXIS1, NAXES[1] -> NAXIS2, BITPIX -> BITPIX) CASE names[i] OF 'BITPIX' : ; Ignore (already inserted by mkhdr) 'NAXES' : ; Ignore (already inserted by mkhdr) 'TIME' : fxaddpar, rtn_hdr, 'TIME', TimeGet(format='YYYY_DOY_hhmmss', hdr.(i),/scalar), comments[i] 'TLM_FILE' : fxaddpar, rtn_hdr, names[i], GetFileSpec(hdr.(i),part='name'), comments[i] 'L1A_FILE' : fxaddpar, rtn_hdr, names[i], GetFileSpec(hdr.(i),part='name'), comments[i] 'CAL_PATTERN': fxaddpar, rtn_hdr, names[i], GetFileSpec(hdr.(i),part='name'), comments[i] 'ORB_PATTERN': fxaddpar, rtn_hdr, names[i], GetFileSpec(hdr.(i),part='name'), comments[i] 'VERSION' : fxaddpar, rtn_hdr, names[i], hdr.(i), comments[i], format='(F5.2)' ELSE : BEGIN IF (where(names[i] EQ flag_names))[0] EQ -1 THEN BEGIN nh = n_elements(hdr.(i)) CASE nh EQ 1 OF 0: FOR j=0,nh-1 DO fxaddpar, rtn_hdr, names[i]+strcompress(j+1,/rem), (hdr.(i))[j], format='(E15.7)', comments[i] 1: BEGIN CASE IsType(hdr.(i)) EQ IsType(/double) OF 0: fxaddpar, rtn_hdr, names[i], hdr.(i), comments[i] 1: fxaddpar, rtn_hdr, names[i], hdr.(i), comments[i], format='(E15.7)' ENDCASE END ENDCASE ENDIF END ENDCASE ENDFOR END to_ascii: BEGIN nl = string(10B) ; 12B rtn_hdr = string( format='(A,I8,A,A,12(A,I4),4A, A, 16A)', $ 'frame : ' , hdr.frame_nr , $ nl+'time : ' , TimeGet(smei_property(hdr,/time), /ymd, upto=TimeUnit(/sec),/scalar) , $ nl+'exposure : ' , smei_property(hdr,/exposure), $ nl+'camera : ' , smei_property(hdr,/camera) , $ nl+'roi_map : ' , smei_property(hdr,/roi_map) , $ nl+'bos alert : ' , smei_property(hdr,/bos_alert),$ nl+'mode : ' , smei_property(hdr,/mode) , $ nl+'bit/pix : ' , hdr.bitpix , $ nl+'just bad : ' , hdr.just_bad , $ nl+'shutter : ' , smei_property(hdr,/shutter), $ nl+'dark off : ' , hdr.dark_offset , $ nl+'SS flatfld: ' , smei_property(hdr,/onboard_ff_enabled), $ nl+'LS flatfld: ' , hdr.flatfield , $ nl+'cosmic ray: ' , hdr.cosmic_rays , $ nl+'size : ' , strjoin(strcompress(hdr.naxes,/rem),'x'), $ nl+'CCD temp : ' , string(smei_property(hdr,/ccd_temp), format='(F7.2)'), $ nl+'---' , $ nl+'saturated : ' , string(hdr.n_saturated, format='(I8)'), $ nl+'base : ' , strjoin(strcompress([smei_property(hdr,/base_done),smei_property(hdr,/base_ok)],/rem),'/'), $ nl+'pedestal : ' , string(smei_property(hdr,/pedestal ),' (',smei_property(hdr,/n_pedestal) ,')',format='(F7.2,A,I3,A)'), $ nl+'dark curr : ' , string(smei_property(hdr,/dark_median ),' (',smei_property(hdr,/n_dark_current),')',format='(F7.2,A,I3,A)'), $ nl+'dark ave : ' , string(smei_property(hdr,/dark_average),' (',smei_property(hdr,/n_dark_current),')',format='(F7.2,A,I3,A)'), $ nl+'tlm file : ' , smei_property(hdr,/tlm_file) , $ nl+'l1a file : ' , smei_property(hdr,/l1a_file) , $ nl+'version : ' , string(smei_property(hdr,/version),format='(F4.2)') ) END ENDCASE RETURN, rtn_hdr & END