def abf_read_header(fname, saveHeader=True):
<EOL>header={} <EOL>sections={} <EOL>strings=[] <EOL>protocol = {} <EOL>tags=[] <EOL>adcs=[] <EOL>dacs=[] <EOL>digitalOutputs=[] <EOL>config={} <EOL>f=open(fname,'<STR_LIT:rb>')<EOL>config["<STR_LIT>"]=os.path.abspath(fname) <EOL>config["<STR_LIT>"]=os.path.basename(fname)[:-<NUM_LIT:4>] <EOL>for key, byte_location, fmt in headerDescriptionV2:<EOL><INDENT>header[key]=fread(f,byte_location,fmt)<EOL><DEDENT>header['<STR_LIT>']=header['<STR_LIT>'].decode()<EOL>for sectionNumber, sectionName in enumerate(sectionNames):<EOL><INDENT>uBlockIndex, uBytes, llNumEntries = fread(f,<NUM_LIT>+sectionNumber*<NUM_LIT:16>,"<STR_LIT>")<EOL>sections[sectionName] = [uBlockIndex,uBytes,llNumEntries]<EOL><DEDENT>config["<STR_LIT>"]=header['<STR_LIT>']/<NUM_LIT:1000>/<NUM_LIT:1000><EOL>byte_location = sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE<EOL>string_size = sections['<STR_LIT>'][<NUM_LIT:1>]<EOL>strings_data = fread(f,byte_location,structFormat=None,nBytes=string_size)<EOL>for key in [b'<STR_LIT>', b'<STR_LIT>', b'<STR_LIT>', b'<STR_LIT>', b'<STR_LIT>']:<EOL><INDENT>if key in strings_data:<EOL><INDENT>for line in strings_data.split(key)[<NUM_LIT:1>].split(b'<STR_LIT:\x00>')[<NUM_LIT:1>:-<NUM_LIT:1>]:<EOL><INDENT>strings.append(line.decode())<EOL><DEDENT>config["<STR_LIT>"]=strings[<NUM_LIT:0>]<EOL>config["<STR_LIT>"]=strings[<NUM_LIT:1>]<EOL>config["<STR_LIT>"]=strings[<NUM_LIT:2>::<NUM_LIT:2>]<EOL>config["<STR_LIT>"]=strings[<NUM_LIT:3>::<NUM_LIT:2>]<EOL>break<EOL><DEDENT><DEDENT>for ADCsection in range(sections['<STR_LIT>'][<NUM_LIT:2>]):<EOL><INDENT>thisADC={}<EOL>byte_location=sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE+sections['<STR_LIT>'][<NUM_LIT:1>]*ADCsection<EOL>for key, fmt in ADCInfoDescription:<EOL><INDENT>thisADC[key]=fread(f,byte_location,fmt)<EOL>byte_location+=struct.calcsize(fmt)<EOL><DEDENT>adcs.append(thisADC)<EOL><DEDENT>byte_location=sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE<EOL>for key, fmt in protocolInfoDescription:<EOL><INDENT>protocol[key]=fread(f,byte_location,fmt)<EOL>byte_location+=struct.calcsize(fmt)<EOL><DEDENT>protocol.pop('<STR_LIT>', None) <EOL>byte_location=sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE<EOL>for i in range(sections['<STR_LIT>'][<NUM_LIT:2>]):<EOL><INDENT>thisTag=[]<EOL>for key, fmt in TagInfoDescription:<EOL><INDENT>val=fread(f,byte_location,fmt)<EOL>if type(val) is bytes:<EOL><INDENT>val=val.decode().strip()<EOL><DEDENT>thisTag.append(val)<EOL>byte_location+=struct.calcsize(fmt)<EOL><DEDENT>tags.append(thisTag)<EOL><DEDENT>for dacNumber in range(sections['<STR_LIT>'][<NUM_LIT:2>]):<EOL><INDENT>thisDAC={}<EOL>byte_location=sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE+sections['<STR_LIT>'][<NUM_LIT:1>]*dacNumber                              <EOL>for key, fmt in DACInfoDescription:<EOL><INDENT>thisDAC[key]=fread(f,byte_location,fmt)<EOL>byte_location+=struct.calcsize(fmt)<EOL><DEDENT>thisDAC.pop('<STR_LIT>', None) <EOL>if thisDAC['<STR_LIT>']==<NUM_LIT:0>: continue <EOL>dacs.append(thisDAC)<EOL><DEDENT>epochs=[]<EOL>for epochNumber in range(sections['<STR_LIT>'][<NUM_LIT:2>]):<EOL><INDENT>thisEpoch={}<EOL>byte_location=sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE+sections['<STR_LIT>'][<NUM_LIT:1>]*epochNumber<EOL>for key, fmt in EpochInfoPerDACDescription:<EOL><INDENT>thisEpoch[key]=fread(f,byte_location,fmt)<EOL>byte_location+=struct.calcsize(fmt)<EOL><DEDENT>thisEpoch.pop('<STR_LIT>', None) <EOL>epochs.append(thisEpoch)<EOL><DEDENT>byte_location=sections['<STR_LIT>'][<NUM_LIT:0>]*BLOCKSIZE<EOL>for epochNumber in range(sections['<STR_LIT>'][<NUM_LIT:0>]):<EOL><INDENT>if epochNumber>=len(epochs):<EOL><INDENT>break <EOL><DEDENT>thisEpoch=epochs[epochNumber]<EOL>for key, fmt in EpochSectionDescription:<EOL><INDENT>val=fread(f,byte_location,fmt)<EOL>if key=='<STR_LIT>':<EOL><INDENT>val=format(val, '<STR_LIT:b>').rjust(<NUM_LIT:8>,'<STR_LIT:0>') <EOL><DEDENT>thisEpoch[key]=val<EOL>byte_location+=struct.calcsize(fmt)<EOL><DEDENT>thisEpoch.pop('<STR_LIT>', None) <EOL>epochs[epochNumber]=thisEpoch<EOL><DEDENT>f.close()<EOL>config["<STR_LIT>"]=float("<STR_LIT>".join([str(x) for x in header['<STR_LIT>']]))/<NUM_LIT:100> <EOL>config['<STR_LIT>']=config['<STR_LIT>'][:len(adcs)] <EOL>config['<STR_LIT>']=config['<STR_LIT>'][:len(adcs)] <EOL>config['<STR_LIT>']=[x[:<NUM_LIT:2>] for x in tags]<EOL>config['<STR_LIT>']=sections['<STR_LIT>'][<NUM_LIT:2>]<EOL>YY = int(header['<STR_LIT>'] / <NUM_LIT>)<EOL>MM = int((header['<STR_LIT>'] - YY * <NUM_LIT>) / <NUM_LIT:100>)<EOL>DD = int(header['<STR_LIT>'] - YY * <NUM_LIT> - MM * <NUM_LIT:100>)<EOL>hh = int(header['<STR_LIT>'] / <NUM_LIT> / <NUM_LIT>)<EOL>mm = int((header['<STR_LIT>'] / <NUM_LIT> - hh * <NUM_LIT>) / <NUM_LIT>)<EOL>ss = header['<STR_LIT>'] / <NUM_LIT> - hh * <NUM_LIT> - mm * <NUM_LIT><EOL>ms = int((ss%<NUM_LIT:1>)*<NUM_LIT>)<EOL>ss = int(ss)<EOL>config['<STR_LIT>'] = datetime.datetime(YY, MM, DD, hh, mm, ss, ms)<EOL>
Practice pulling data straight out of an ABF's binary header. Support only ABF2 (ClampEx an ClampFit 10).
Use only native python libraries. Strive for simplicity and readability (to promote language portability).
This was made by Scott Harden after a line-by-line analysis of axonrawio.py from the neo io library.
Unlike NeoIO's format, I'm going to try to prevent nested dictionaries to keep things simple.