--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygpibtoolkit/gpib_utils.py Mon Feb 25 18:38:27 2008 +0100 @@ -0,0 +1,128 @@ +# +""" +Several untity functions for GPIB data conversions +""" +import struct +import re +import numpy + +######################################## +# internal binary types decoders + +def decode_float(s): + """ + Decode a Float from the HP binary representation. + """ + if len(s) == 4: + i1, i2, e = struct.unpack('>hbb', s) + i2 = i2 * 2**(-23) + return (i1/32768. + i2)*2**e + else: + i1, i2, i3, i4, e = struct.unpack('>hhhbb', s) + if i2 < 0: + i2 = (i2+32768.)*2**(-15) + else: + i2 = i2*2**(-15) + if i3 < 0: + i3 = (i3+32768.)*2**(-30) + else: + i3 = i3*2**(-15) + i4 = i4 * 2**(-38) + return (i1+i2+i3+i4)*2**(e-15) + +def decode_string(s): + """ + Decode a string from the HP binay representation. + """ + nb = ord(s[0]) + s = s[1:nb+2] + r = "" + # XXX why do we need to do this? It's not described in the manual... + for c in s: + r += chr(ord(c) & 0x7F) + return r + +### +# Datavlock useful functions +def format_datablock_header(header, head_struct, columns=80): + """ + Pretty print a data block (trace, state or coord) + """ + bool_re = re.compile(r'((?P<before>.*) )?(?P<flag>\w+/\w+)( (?P<after>.*))?') + + todisp = [] + for row in head_struct: + key = row[0] + typ = row[1] + if typ is None: + continue + val = header.get(key, "N/A") + if isinstance(val, basestring): + val = repr(val) + elif typ is bool and isinstance(val, typ): + m = bool_re.match(key) + if m: + d = m.groupdict() + key = "" + if d['before']: + key += d['before'] + if d['after']: + key += d['after'] + key = key.capitalize() + val = d['flag'].split('/')[not val] + else: + val = str(val) + else: + val = str(val) + todisp.append((key+":", val)) + maxk = max([len(k) for k, v in todisp]) + maxv = max([len(v) for k, v in todisp]) + fmt = "%%-%ds %%-%ds"%(maxk, maxv) + w = maxk+maxv+4 + ncols = columns/w + if ncols: + nrows = len(todisp)/ncols + else: + nrows = len(todisp) + res = "" + for i in range(nrows): + res += "| ".join([fmt%todisp[j*nrows+i] for j in range(ncols)]) + "\n" + return res + +def decode_datablock_header(data, header_struct, idx=0): + d = data + if d[idx:].startswith('#'): + # we have a preliminary header here... + typ = d[idx:idx+2] + assert typ == "#A" + idx += 2 + totlen = struct.unpack('>h', d[idx:idx+2])[0] + idx += 2 + tt=0 + header = {} + for i, (nam, dtype, fmt, nbytes) in enumerate(header_struct): + if dtype is None: + idx += nbytes + continue + elif dtype == str: + val = decode_string(d[idx:]) + else: + if fmt: + v = struct.unpack('>'+fmt, d[idx: idx+nbytes])[0] + if isinstance(dtype, dict): + val = dtype.get(int(v), "N/A") + else: + val = dtype(v) + else: + val = dtype(d[idx: idx+nbytes]) + header[nam] = val + idx += nbytes + return header, idx + +def read_datablock_trace(data, idx, nelts): + assert len(data[idx:]) >= (nelts*4), "data[idx:] is too small (%s for %s)"%(len(data[idx:]), (nelts*4)) + resu = [] + for i in range(nelts): + resu.append(decode_float(data[idx: idx+4])) + idx += 4 + return numpy.array(resu, dtype=float)