# This library is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 3.0 of the License, or (at your option) any later version. # # The library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # (c) Sam Burden, UC Berkeley, 2012 # # based on viconreader (c) Shai Revzen, U Penn, 2010 import struct import socket import sys import time DEFAULT_HOST = "localhost" DEFAULT_PORT = 43949 # enforce network byte order pack = lambda fmt,*vals : struct.pack( '!'+fmt, *vals) unpack = lambda fmt,str : struct.unpack( '!'+fmt, str) class OptiReader(object): """ OptiReader instances provide access to the real-time data stream made available by opti.exe Instances of OptiReader can send QUERY, START and STOP messages and parse responses into lists of attributes and blocks of doubles (encoded as strings). OptiReader is used from the commandline to log tracking data to a file. Typical use is: >>> R = OptiReader() >>> # get list of names from QUERY Response >>> names = R.connect() >>> # R.stream() is a generator returning packet payload each .next() >>> for pkt,_ in zip(R.stream(),xrange(100)): >>> dat = R.unpack("%dd" % (len(pkt) / R.DATLEN),pkt) >>> print >>> for nm,val in zip(name,dat): >>> print nm,val >>> R.stop() """ QUERY = 1 INFO = 2 START = 3 STOP = 4 DATA = 5 # number of bytes per unit of data DATLEN = 4 # number of bytes per command CMDLEN = 4 if struct.calcsize('L') == CMDLEN: CMD = 'L' elif struct.calcsize('I') == CMDLEN: CMD = 'I' else: raise OSError,'Cannot find %d byte unsigned int for your OS' % CMDLEN def __init__(self): self.sock = None self.push = '' def _get( self, fmt ): "Read data from socket based on format string, and parse it accordingly" N = struct.calcsize(fmt) # Start reading from push-back buffer buf = self.push[:min(len(self.push),N)] self.push = self.push[:len(buf)] while len(buf), --host Specify opti.exe hostname where hostname is an IP address, FQDN or alias -p , --port Specify opti.exe port to connect to -a, --aliases List the builtin host aliases --help, --usage Print this message """ % sys.argv[0]) sys.exit(5) # Filename user requested print "Connecting to %s:%d" % (host,port) R = OptiReader() names = R.connect(host=host, port=port) # Write descriptor dcr = open(fn+".dcr", "w") dcr.write("\n".join(names)+"\n") dcr.close() # Write data L = 0 N = 0 dat = [] try: # for catching ctrl-c termination print "Recording to %s.dcr, %s.raw" % (fn,fn) for pkt in R.stream(): if not L: # First packet sets the length we'll expect L = len(pkt) elif L != len(pkt): print "\nUnexpected packet of length %d instead of %d" % (len(pkt),L) continue #P dat.write(pkt) dat.append(pkt) N += 1 if (N%50)==0: print "\r%5d" % N, # --- except KeyboardInterrupt, ex: #P dat.close() print "Writing data -- WAIT !!!" f = open(fn+".dat", "w") f.write("".join(dat)) f.close() R.stop() R.close() print "\ndone."