;+ ; NAME: ; BITSTRACT ; ; AUTHOR: ; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770 ; craigm@lheamail.gsfc.nasa.gov ; UPDATED VERSIONs can be found on my WEB PAGE: ; http://cow.physics.wisc.edu/~craigm/idl/idl.html ; ; PURPOSE: ; Extract fields from bit-packed data ; ; MAJOR TOPICS: ; Database ; ; CALLING SEQUENCE: ; BITSTRACT, BYTES, FORMAT, ITEM, DATA, STATUS=status ; ; DESCRIPTION: ; ; The procedure BITSTRACT is useful to extract data from a ; bit-packed byte array. Here "bit-packed" means data packed into ; structures that are not aligned with standard word boundaries. ; Thus, a series of shifts and masks must be used to extract the ; desired quantities. ; ; The input array is expected to be an NxM array, where N is the ; number of bytes per record, and M is the number of records. The ; records themselves must be at least byte-aligned. [ However the ; fields within the records do not. ] ; ; The use passes a FORMAT, which describes the structure of the ; bit-packed data. Here is the definition of the structure: ; ; hformat = { $ ; ITEM: 0L, $ ;; Item number ; START: 0L, $ ;; Bit position, starting at 0 ; STOP: 0L, $ ;; Input length in bits ; SIGNLENGTH: 0L,$ ;; Length of sign field in bits ; OUTLENGTH: 0L, $ ;; Convert to output length in bits (MSB lost) ; TYPE: '', $ ;; Data type to convert to ; NAME: '' $ ;; Name of field ; } ; ; A sign length of -1 indicates two's complement number. Outlength ; is essentially ignored, but it is checked against the length of ; the output data type to warn against a too-small type. ; ; There is one format structure for each field in the record. ; The TYPE tag must be an IDL data type generation function. ; ; The bit addressing addresses the bytes in ascending order, most ; significant bit first, as follows: ; ; BYTE 0 BYTE 1 ... ; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ... ; ; Address: ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... ; ; ; PARAMETERS: ; ; BB - byte array, NxM where N is the number of bytes per record, ; and M is the number of records. ; ; FORMAT - bit-packed record format, as described above. All ; desired records must be listed here. ; ; ITEM - the desired item number (i.e., field number). ; ; DATA - upon output, the data is returned in this value, as a ; M-array. The type of the output data depends on the TYPE ; field of the format structure. ; ; ; KEYWORD PARAMETERS: ; ; STATUS - upon return, a value of 0 indicates failure. A value of ; 1 indicates success. ; ; RESTRICTIONS: ; ; A bit swapping operation of IEEE_TO_HOST is performed on the ; integer data. Users must have the IDL Astronomy library installed ; to get this function. ; ; ; MODIFICATION HISTORY: ; Written and documented, CM, Jan-Feb 2002 ; ; $Id: bitstract.pro,v 1.1 2002/02/06 21:37:49 craigm Exp $ ; ;- ; Copyright (C) 2002, Craig Markwardt ; This software is provided as is without any warranty whatsoever. ; Permission to use, copy, modify, and distribute modified or ; unmodified copies is granted, provided this copyright and disclaimer ; are included unchanged. ;- pro bitstract, bb, format, item, data, status=status, offset=offset0 status = 0 if n_elements(offset0) NE 0 then offset = round(offset0(0)) $ else offset = 0L ;; Locate column information from the format wh = where(format.item EQ item, ct) if ct EQ 0 then return nrec = n_elements(bb)/n_elements(bb(*,0)) - offset ;; Copy the format data into local variables form = format(wh(0)) bmin = form.start ;; Start bit bmax = form.stop ;; Stop bit bsize = bmax-bmin+1 ;; Number of bits mmin = bmin/8 ;; Start byte mmax = bmax/8 ;; Stop byte omin = bmin-mmin*8 ;; Bit offset into start byte omax = bmax-mmax*8 ;; Bit offset into stop byte msize = mmax-mmin+1 ;; Number of bytes to examine ;; Extract the bytes of interest into an 8 byte x NREC array. The ;; bytes will be placed at an offset of PAD, so that the "last" byte ;; appears in the rightmost position. pad = 8-msize ;; # of pad bytes bful = bytarr(8,nrec) bful(pad:*,*) = bb(mmin:mmax,offset:*) ;; Formulate a bit mask that strips out the upper bits of the start ;; byte bful(pad,*) = bful(pad,*) AND byte(2L^(8-omin) - 1) ;; Convert the byte data into an IDL "unsigned long 64-bit" ;; quantity, so they are easily shiftable in one operation isub = ulong64(temporary(bful), 0, nrec) ieee_to_host, isub ;; Shift the data so that the "last" bit is the 0th bit isub = ishft(temporary(isub),-(8-omax-1)) ;; Typecast the data data = call_function(form.type, temporary(isub)) ;; Sneaky way to get number of bytes in the data type, by putting ;; one into a structure nbits = n_tags({dummy:call_function(form.type,0)},/length)*8 if nbits NE form.outlength then $ message, 'WARNING: number of requested bits does not match '+ $ 'requested data type', /info ;; Determine if output is signed outsigned = (call_function(form.type,0)-1) LT 0 ;; Normally we don't do anything about the sign length, but if this ;; is a two's complement number then, then it's possible that it ;; needs to be sign extended. if outsigned AND form.signlength EQ -1 AND nbits GT bsize then begin wh = where(data GE 2L^(bsize-1), ct) if ct GT 0 then $ data(wh) = data(wh) - 2L^bsize endif status = 1 return end