Commit 4a8e6283 authored by Matthieu Cattin's avatar Matthieu Cattin

struct: Remove modules moved to common pts project.

- PAGE (Python Adc and GEnerator control library)
- Pyro (Python Remote Object library)
- cp210x EEPROM and GPIO interface
- VIC (Vectored Interrupt Controller)
- find_usb_tty (get tty from VID, DID)
parent a84ec97c
from Utilities import *
from Item import *
"""This class manages a generic waveform generator."""
class ADC(Item):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
def clockFrequency():
doc = "Clock frequency used by the ADC"
def fget(self): return 0
def fset(self, value): return
return locals()
@Property
def clockFrequencies():
doc = "Clock frequencies"
def fget(self): return tuple()
def fset(self, value): return
return locals()
@Property
def nrBits():
doc = "Number of bits of the device."
def fget(self): return 0
return locals()
def readEvent(self, samples):
'''Read an event of size 'samples' from the ADC. Uses self.segment
and self.channel to select the missing parameters.'''
return []
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
from Generator import *
from SineWaveform import SineWaveform
from TTWaveform import TTWaveform
from serial import Serial
from struct import pack
from time import sleep
from numpy import ndarray
import Pyro4
import Pyro4.util
"""This class manages the Agilent 33250A waveform generator, offering different ways
to control its output."""
class Agilent33250A(Generator):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
_parameters = {'device':['Serial device', 'Serial device used to communicate with the generator', "/dev/ttyUSB1", 'file'],
'bauds':['Bauds', 'Speed of the communication', 9600, int],
'to':['Timeout', 'Timeout during read operations', 2, int],
'ict':['Inter character space', 'Pause time between each character sent', 1, int]}
# These are the functions the generator supports.
functionList = ('SIN', 'SQU', 'RAMP', 'PULS', 'NOIS', 'DC', 'USER')
def __init__(self, *args, **kwargs):
"""The initializer doesn't connect to the device."""
Generator.__init__(self, *args, **kwargs)
self.connected = False
self.adaptDict = {SineWaveform: self.adaptSine,
list: self.adaptData,
tuple: self.adaptData,
ndarray: self.adaptData,
str: self.adaptSavedFunction}
def connect(self):
""" Connect to the device"""
self.comm = Serial(port = self.device, baudrate = self.bauds, timeout = self.to, interCharTimeout=self.ict)
#print 'Waiting for 2 bytes from the device:'
self.comm.read(2)
self.connected = True
def close(self):
"""Close the connection to the device"""
if self.connected:
return
self.comm.close()
self.connected = False
# utilities
def adaptSavedFunction(self, wave, *args, **kwargs):
"""Play an already uploaded function."""
self.function = ('USER', wave)
return ""
def adaptSine(self, wave, *args, **kwargs):
"""Adapt a SineWaveform to a generator command"""
return "APPL:SIN %f HZ, %f VPP, %f V" % (wave.frequency, wave.amplitude, wave.dc)
def adaptData(self, data, *args, **kwargs):
"""Upload data to the volatile memory of the device and select it"""
self.dataUpload(data, *args, **kwargs)
self.function = ('USER')
self.function = ('USER', 'VOLATILE')
return ''
def play(self, wave, *args, **kwargs):
'''Play a wave'''
cmd = self.adapt(wave, *args, **kwargs)
self.command(cmd)
def command(self, what):
'''Send a (list of) command(s) to the device: a command is a string, and
this function appends automatically a new line.'''
if len(what) == 0:
return
if type(what) is str:
what = (what, )
if not self.connected:
self.connect()
return sum(map(lambda x: self.comm.write("%s\n" % x), what))
# output
@Property
def output():
doc = "Output status of the generator"
def fget(self):
self.command("OUTP?")
output = self.comm.read(2)[0]
return output == "1"
def fset(self, status):
if type(status) is not bool:
return
self.command("OUTP %d" % (1 if status else 0))
return locals()
# sync output
@Property
def sync():
doc = "Sync output status of the generator"
def fget(self):
self.command("OUTP:SYNC?")
output = self.comm.read(2)[0]
return output == "1"
def fset(self, status):
if type(status) is not bool:
return
self.command("OUTP:SYNC %d" % (1 if status else 0))
return locals()
@Property
def function():
doc = "Function used by the generator"
def fget(self):
self.command("FUNC?")
output = self.comm.readline()[:-1] # avoid \n
if output == 'USER':
self.command('FUNC:USER?')
u = self.comm.readline()[:-1] # avoid \n
return (output, u)
return (output, )
def fset(self, f):
if type(f) in (tuple, list):
if len(f) == 2:
f, n = f
else:
return
if type(f) != str:
return
f = f.upper()
if ' ' in f:
f, n = f.split(' ')
else:
n = ''
if f not in self.functionList:
return
self.command("FUNC %s %s" % (f, n))
return locals()
@Property
def frequency():
doc = "Frequency used by the generator"
def fget(self):
self.command("FREQ?")
output = eval(self.comm.readline()[:-1]) # avoid \n
return output
def fset(self, value):
f = ' '.join(parse(value, 'HZ'))
self.command("FREQ %s" % f)
return locals()
@Property
def voltage():
doc = "Output amplitude"
def fget(self):
self.command("VOLT?")
V = eval(self.comm.readline()[:-1]) # avoid \n
self.command("VOLT? MIN")
m = eval(self.comm.readline()[:-1])
self.command("VOLT? MAX")
M = eval(self.comm.readline()[:-1])
return V, m, M
def fset(self, v):
if type(v) is str:
v = v.upper()
if v[:3] in ['MIN', 'MAX']:
self.command('VOLT %s' % v[:3])
return
f = ' '.join(parse(v, 'V'))
self.command("VOLT %s" % f)
return locals()
@Property
def voltageOffset():
doc = "Offset of the output signal"
def fget(self):
self.command("VOLT:OFFS?")
V = eval(self.comm.readline()[:-1]) # avoid \n
self.command("VOLT:OFFS? MIN")
m = eval(self.comm.readline()[:-1])
self.command("VOLT:OFFS? MAX")
M = eval(self.comm.readline()[:-1])
return V, m, M
def fset(self, v):
if type(v) is str:
v = v.upper()
if v[:3] in ['MIN', 'MAX']:
self.command('VOLT:OFFS %s' % v[:3])
return
f = ' '.join(parse(v, 'V'))
self.command("VOLT:OFFS %s" % f)
return locals()
# skipping volt:high volt:low
@Property
def voltageRangeAuto():
doc = "Voltage autoranging for all function. Setter supports also ONCE"
def fget(self):
self.command("VOLT:RANG:AUTO?")
output = self.comm.read(2)[0]
return output == "1"
def fset(self, status):
if type(status) is not bool:
if status != 'ONCE':
return
else:
if status: status = 'ON'
else: status = 'OFF'
self.command("VOLT:RANG:AUTO %s" % status)
return locals()
# skipping volt:high or volt:low
@Property
def squareDutyCycle():
doc = "Duty cycle of a square wave"
def fget(self):
self.command("FUNC:SQU:DCYC?")
V = eval(self.comm.readline()[:-1])
self.command("FUNC:SQU:DCYC? MIN")
m = eval(self.comm.readline()[:-1])
self.command("FUNC:SQU:DCYC? MAX")
M = eval(self.comm.readline()[:-1])
return V, m, M
def fset(self, v):
if type(v) is str:
v = v.upper()
if v[:3] in ['MIN', 'MAX']:
self.command('FUNC:SQU:DCYC %s' % v[:3])
return
self.command("FUNC:SQU:DCYC %f" % v)
return locals()
# data
def dataUpload(self, data, ttw = 0.002):
"""Upload a sequence of integers to the volatile memory of the generator.
TTW is the time to wait between each character of the sequence, which
is transferred in ASCII"""
command = 'DATA:DAC VOLATILE, %s\n' % ', '.join(str(i) for i in data)
self.comm.write(command)
def dataStore(self, destination):
"""Save VOLATILE waveform into 'destination'"""
if type(destination) is not str: return
self.command("DATA:COPY %s" % destination)
@Property
def dataCatalog():
doc = "List of all available arbitrary waveforms"
def fget(self):
self.command('DATA:CAT?')
return tuple(self.comm.readline()[:-1].replace('"', '').split(','))
return locals()
@Property
def dataNVCatalog():
doc = "List of the user defined waveforms store in non-volatile memory"
def fget(self):
self.command('DATA:NVOL:CAT?')
return tuple(self.comm.readline()[:-1].replace('"', '').split(','))
return locals()
@Property
def dataFree():
doc = "Free arbitrary waveform slots in non-volatile memory"
def fget(self):
self.command('DATA:NVOL:FREE?')
return int(self.comm.readline()[:-1])
return locals()
def dataDel(self, what):
"""Delete the waveform 'what'. If 'what' is all, then delete everything."""
if type(what) is not str: return
if what.upper() == 'ALL':
self.command('DATA:DEL:ALL')
else:
self.command('DATA:DEL %s' % what)
def sweep(self, interval, waves, callback = None):
'''Commodity function: play all the waves in 'waves' with a pause of
'interval' seconds between each. If present, calls 'callback' passing
the wave as a first parameter.'''
for w in waves:
self.play(w)
sleep(interval)
if callback is not None:
callback(w)
# specify the name of the module
name = 'Agilent 33250A'
# the interesting class
target = Agilent33250A
import sys
import commands
def launch():
g = target()
g.device = sys.argv[1]
g.connect()
hn = commands.getoutput('hostname')
daemon=Pyro4.Daemon(host = hn)
myUri = daemon.register(g)
ns=Pyro4.locateNS()
ns.register("Agilent33250A", myUri)
daemon.requestLoop()
if __name__ == '__main__':
launch()
from Utilities import *
from Item import *
"""This class manages a generic waveform generator."""
class Generator(Item):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
# this dictionary is used to map data types into function which can
# translate such type of data into something the generator can understand.
adaptDict = {}
def adaptKeys(self):
"""Returns all data types supported."""
return self.adaptDict.keys()
def adapt(self, wave, *args, **kwargs):
"""Adapt a wave to the generator"""
return self.adaptDict[type(wave)](wave, *args, **kwargs)
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
"""This class just represent an API item. An item is configurable and has two
methods, get and set, which actually wrap getattribute and setattr."""
class Item(object):
# these are the default values of the parameters used
#
# the key of the dictionary is the actual name of the parameter in the class
# the item is a list:
# 1. Name of the parameter
# 2. Description
# 3. Default value
# 4. Type (it's just an object, really)
_parameters = {}
def __init__(self, *args, **kwargs):
"""Create the object and loads alll the parameters from kwargs.
Look at _parameters for more information."""
self.parameters = dict(self._parameters)
for i in kwargs:
if i in self.parameters.keys():
self.parameters[i][2] = kwargs[i]
for i in self.parameters.keys():
self.__setattr__(i, self.parameters[i][2])
import sys
import Pyro4
import Item
from Utilities import *
from numpy import *
"""This class represents a remote object, using Pyro4 framework.
All it needs is a URI."""
class RemoteObject(Item.Item, Pyro4.Proxy):
_parameters = {'uri': ['URI', 'Name of the service', '', str]}
def __init__(self, *args, **kwargs):
Item.Item.__init__(self, *args, **kwargs)
Pyro4.Proxy.__init__(self, uri = Pyro4.locateNS().lookup(self.uri))
name = 'Remote Object'
target = RemoteObject
import Waveform
from Utilities import *
from numpy import *
import Pyro4
import Pyro4.util
import sys
class SineWaveform(Waveform.Waveform):
def get(self, what):
return self.__getattribute__(what)
def set(self, what, how):
self.__setattr__(what, how)
_parameters = {'frequency':['Frequency', 'Frequency of the sinewave, in HZ', 1000, float],
'amplitude':['Amplitude', 'Amplitude of the sinewave, in Vpp', 1, float],
'dc':['DC Compoment', 'DC component of the sinewave, in Vpp', 0, float]}
def __init__(self, *args, **kwargs):
Waveform.Waveform.__init__(self, *args, **kwargs)
def generate(self, sampleRate, samples, nbits, fsr):
f = self.frequency
A = self.amplitude
C = self.dc
t = arange(samples, dtype=float)/sampleRate
s = A*sin(2*pi*f*t) +C
lsb = fsr/(2**nbits)
return (s/lsb).astype(int)
def scale(self, factor):
"""Multiply the frequency by factor."""
self.frequency *= factor
return self
name = 'Sine Waveform'
target = SineWaveform
import commands
def launch():
g = target()
hn = commands.getoutput('hostname')
daemon=Pyro4.Daemon(host = hn)
myUri = daemon.register(g)
ns=Pyro4.locateNS()
ns.register("Sine", myUri)
daemon.requestLoop()
if __name__ == '__main__':
launch()
#
from ctypes import *
from ADC import *
import Pyro4
import Pyro4.util
lib = CDLL("./libsis33.L865.so")
SIS33_ROUND_NEAREST, SIS33_ROUND_DOWN, SIS33_ROUND_UP = range(3)
SIS33_TRIGGER_START, SIS33_TRIGGER_STOP = range(2)
SIS33_CLKSRC_INTERNAL, SIS33_CLKSRC_EXTERNAL = range(2)
class Sis33Acq(Structure):
def get(self, what):
return self.__getattribute__(what)
def set(self, what, how):
self.__setattr__(what, how)
_fields_ = [("data",POINTER(c_uint16)),
("nr_samples" , c_uint32),
("prevticks", c_uint64),
("size", c_uint32)]
@classmethod
def zalloc(cls, events, ev_length):
pointer = POINTER(cls)
lib.sis33_acqs_zalloc.restype = pointer
acqs = lib.sis33_acqs_zalloc(events, ev_length)
# insert error control
return acqs
@staticmethod
def free(item, n_acqs):
lib.sis33_acqs_free(item, n_acqs)
class Timeval(Structure):
_fields_ = [("tv_sec", c_uint32),
("tv_usec", c_uint32)]
@classmethod
def create(cls, s, u):
t = cls()
t.tv_sec = s;
t.tv_usec = u;
return t
class Sis33Exception(Exception):
@classmethod
def spawn(cls, desc):
return cls(strerror(errno()), desc)
def Property(func):
return property(**func())
def logLevel(l):
return lib.sis33_loglevel(l)
def errno():
return lib.sis33_errno()
def strerror(i):
return lib.sis33_strerror(i)
def perror(s):
lib.sis33_perror(s)
"""This class should manage a generic waveform generator"""
class Sis33Device(ADC):
_ptr = 0
_parameters = {'index':['Device Index', 'Index of the ADC', 2, int],
'channel':['Channel', 'Channel to use for DAQ', 7, int],
'segment':['Segment', 'Memory segment used for data storage', 0, int]}
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
def __init__(self, *args, **kwargs):
ADC.__init__(self, *args, **kwargs)
self.pointer = lib.sis33_open(self.index)
def __del__(self):
"""Destroy the object, if needed. Closes the device before dying."""
if self._ptr != 0:
self.close()
def close(self):
"""Close the device."""
lib.sis33_close(self.pointer)
self._ptr = 0 # bypass pointer
@Property
def pointer():
doc = "Device descriptor"
def fget(self):
if (self._ptr == 0): raise Sis33Exception('Null pointer')
return self._ptr
def fset(self, value):
if (value == 0): raise Sis33Exception('Null pointer')
self._ptr = value
return locals()
@Property
def clockSource():
doc = "Clock source of the device"
def fget(self):
i = c_int()
if lib.sis33_get_clock_source(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Clock Source')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_clock_source(self.pointer, value):
raise Sis33Exception.spawn('Set Clock Source (%d)' % value)
return locals()
@Property
def clockFrequency():
doc = "Clock frequency used"
def fget(self):
i = c_int()
if lib.sis33_get_clock_frequency(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Clock Frequency')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_clock_frequency(self.pointer, value):
raise Sis33Exception.spawn('Set Clock Frequency (%d)' % value)
return locals()
@Property
def clockFrequencies():
doc = "Clock frequencies"
def fget(self):
i = lib.sis33_get_nr_clock_frequencies(self.pointer)
if i == 0:
raise Sis33Exception('Clock Frequencies number is 0')
output = (c_uint*i)()
if lib.sis33_get_available_clock_frequencies(self.pointer, output, c_long(i)):
raise Sis33Exception.spawn('Get Clock Frequencies')
return tuple(output)
return locals()
def roundClockFrequency(self, clkfreq, roundType):
"""Round a clock frequency to a valid value. """
return lib.sis33_round_clock_frequency(self.pointer, clkfreq, roundType)
@Property
def eventLengths():
doc = "Get the available event lengths. "
def fget(self):
i = lib.sis33_get_nr_event_lengths(self.pointer)
if i == 0:
raise Sis33Exception('Event Length number is 0')
output = (c_uint*i)()
if lib.sis33_get_available_event_lengths(self.pointer, output, c_long(i)):
raise Sis33Exception.spawn('Get Event Lengths')
return tuple(output)
return locals()
def roundEventLength(self, evLen, roundType):
"""Round an event length to a valid value. """
return lib.sis33_round_event_length(self.pointer, evLen, roundType)
def trigger(self, trigger):
if lib.sis33_trigger(self.pointer, trigger):
raise Sis33Exception.spawn('Trigger (%d)' % trigger)
@Property
def enableExternalTrigger():
doc = "Enable/Disable status of the external trigger"
def fget(self):
i = c_int()
if lib.sis33_get_enable_external_trigger(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Enble External Trigger')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_enable_external_trigger(self.pointer, value):
raise Sis33Exception.spawn('Set Enable External Trigger (%d)' % value)
return locals()
@Property
def startAuto():
doc = "Autostart mode"
def fget(self):
i = c_int()
if lib.sis33_get_start_auto(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Start Auto')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_start_auto(self.pointer, value):
raise Sis33Exception.spawn('Set Start Auto (%d)' % value)
return locals()
@Property
def startDelay():
doc = "Start delay"
def fget(self):
i = c_int()
if lib.sis33_get_start_delay(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Start Delay')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_start_delay(self.pointer, value):
raise Sis33Exception.spawn('Set Start Delay (%d)' % value)
return locals()
@Property
def stopAuto():
doc = "Autostop mode"
def fget(self):
i = c_int()
if lib.sis33_get_stop_auto(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Stop Auto')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_stop_auto(self.pointer, value):
raise Sis33Exception.spawn('Set Stop Auto (%d)' % value)
return locals()
@Property
def stopDelay():
doc = "Stop delay"
def fget(self):
i = c_int()
if lib.sis33_get_stop_delay(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Stop Delay')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_stop_delay(self.pointer, value):
raise Sis33Exception.spawn('Set Stop Delay (%d)' % value)
return locals()
@Property
def nrChannels():
doc = "Number of channels on the device."
def fget(self):
return lib.sis33_get_nr_channels(self.pointer)
return locals()
def channelSetOffset(self, channel, offset):
i = lib.sis33_channel_set_offset(self.pointer, channel, offset)
if i != 0:
raise Sis33Exception.spawn('Channel Set Offset (%d)' % channel)
def channelGetOffset(self, channel):
r = c_int()
i = lib.sis33_channel_get_offset(self.pointer, channel, byref(r))
if i != 0:
raise Sis33Exception.spawn('Channel Get Offset (%d)' % channel)
return r
def channelSetOffsetAll(self, offset):
i = lib.sis33_channel_set_offset_all(self.pointer, offset)
if i != 0:
raise Sis33Exception.spawn('Channel Set Offset All')
@Property
def nrSegments():
doc = "Number of segments on the device."
def fget(self):
i = c_int()
if lib.sis33_get_nr_segments(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Nr Segments')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_nr_segments(self.pointer, value):
raise Sis33Exception.spawn('Set Nr Segments (%d)' % value)
return locals()
@Property
def maxNrSegments():
doc = "Maximum number of segments"
def fget(self):
i = c_int()
if lib.sis33_get_max_nr_segments(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Maximum Nr Segments')
return i.value
return locals()
@Property
def minNrSegments():
doc = "Minimum number of segments"
def fget(self):
i = c_int()
if lib.sis33_get_min_nr_segments(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Minimum Nr Segments')
return i.value
return locals()
@Property
def maxNrEvents():
doc = "Maximum number of events"
def fget(self):
i = c_int()
if lib.sis33_get_max_nr_events(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Maximum Nr Events')
return i.value
return locals()
@Property
def nrBits():
doc = "Number of bits of the device."
def fget(self):
return lib.sis33_get_nr_bits(self.pointer)
return locals()
@Property
def eventTimestampingIsSupported():
doc = "Device implements event hardware timestamping."
def fget(self):
return lib.sis33_event_timestamping_is_supported(self.pointer)
return locals()
@Property
def maxEventTimestampingClockTicks():
doc = "Maximum number of clock ticks of the event timestamping unit. "
def fget(self):
i = c_int()
if lib.sis33_get_max_event_timestamping_clock_ticks(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Maximum Event Timestamping Clock Ticks')
return i.value
return locals()
@Property
def maxEventTimestampingDivider():
doc = "Maximum event timestamping divider available on a device. "
def fget(self):
i = c_int()
if lib.sis33_get_max_event_timestamping_divider(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Maximum Event Timestamping Divider')
return i.value
return locals()
@Property
def eventTimestampingDivider():
doc = "Current event timestamping divider on a device."
def fget(self):
i = c_int()
if lib.sis33_get_event_timestamping_divider(self.pointer, byref(i)):
raise Sis33Exception.spawn('Get Event Timestamping Divider')
return i.value
def fset(self, value):
value = c_long(value)
if lib.sis33_set_event_timestamping_divider(self.pointer, value):
raise Sis33Exception.spawn('Set Event Timestamping Divider (%d)' % value)
return locals()
def acq(self, segment, nr_events, ev_length):
'Acquires an event, storing it into segment.'
ev_length = self.roundEventLength(ev_length, SIS33_ROUND_NEAREST)
if lib.sis33_acq(self.pointer, segment, nr_events, ev_length):
raise Sis33Exception.spawn('Acq')
def acqWait(self, segment, nr_events, ev_length):
'Acquires an event, storing it into segment; blocking.'
ev_length = self.roundEventLength(ev_length, SIS33_ROUND_NEAREST)
if lib.sis33_acq_wait(self.pointer, segment, nr_events, ev_length):
raise Sis33Exception.spawn('Acq Wait')
def acqTimeout(self, segment, nr_events, ev_length, timeout):
'Acquires an event, storing it into segment; blocking with timeout.'
ev_length = self.roundEventLength(ev_length, SIS33_ROUND_NEAREST)
if lib.sis33_acq_timeout(self.pointer, segment, nr_events, ev_length, timeout):
raise Sis33Exception.spawn('Acq Timeout')
def acqCancel(self):
'Cancel an acquisition'
if lib.sis33_acq_cancel(self.pointer):
raise Sis33Exception.spawn('Acq Cancel')
def fetch(self, segment, channel, acqs, n_acqs, endtime):
'Fetch an event from a channel, stored in a segment.'
if lib.sis33_fetch(self.pointer, segment, channel, acqs, n_acqs, endtime) < 0:
raise Sis33Exception.spawn('Fetch')
def fetchWait(self, segment, channel, acqs, n_acqs, endtime):
'Fetch an event from a channel, stored in a segment; blocking.'
if lib.sis33_fetch_wait(self.pointer, segment, channel, acqs, n_acqs, endtime) < 0:
raise Sis33Exception.spawn('Fetch Wait')
def fetchTimeout(self, segment, channel, acqs, n_acqs, endtime, timeout):
'Fetch an event from a channel, stored in a segment; blocking with timeout.'
if lib.sis33_fetch_timeout(self.pointer, segment, channel, acqs, n_acqs, endtime, timeout) < 0:
raise Sis33Exception.spawn('Fetch Timeout')
def readEvent(self, samples):
'''Read an event of size 'samples' from the ADC. Uses self.segment
and self.channel to select the missing parameters.'''
ev_length = self.roundEventLength(samples, SIS33_ROUND_UP)
self.acqWait(self.segment, 1, ev_length)
a = Sis33Acq.zalloc(1, ev_length)
t = Timeval()
self.fetchWait(self.segment, self.channel, byref(a[0]), 1, byref(t))
# memory leak!
return [a[0].data[i] for i in xrange(samples)]
name = 'Sis 33xx ADC'
target = Sis33Device
import sys
import commands
def launch():
g = target(int(sys.argv[1]))
hn = commands.getoutput('hostname')
daemon=Pyro4.Daemon(host = hn)
myUri = daemon.register(g)
ns=Pyro4.locateNS()
ns.register("Sis33_%s" % sys.argv[1], myUri)
daemon.requestLoop()
if __name__ == '__main__':
launch()
import Waveform
from Utilities import *
from numpy import *
import Pyro4
import Pyro4.util
import sys
import commands
class TTWaveform(Waveform.Waveform):
def get(self, what):
return self.__getattribute__(what)
def set(self, what, how):
self.__setattr__(what, how)
_parameters = {'frequency':['Frequency (1)', 'Frequency of the first sinewave, in HZ', float(5e6), float],
'ratio':['Ratio', 'Ratio between the frequency of the second sinewave and the one', 6./5., float],
'amplitude':['Amplitude', 'Amplitude of each sinewave, in Vpp', 1., float],
'dc':['DC Compoment', 'DC component of the whole waveform, in Vpp', 0., float]}
def __init__(self, *args, **kwargs):
Waveform.Waveform.__init__(self, *args, **kwargs)
def generate(self, sampleRate, samples, nbits, fsr):
f1, f2 = self.frequency, self.frequency * self.ratio
A = self.amplitude
C = self.dc
t = arange(samples, dtype=float)/sampleRate
s = A*sin(2*pi*f1*t) +A*sin(2*pi*f2*t) +C
lsb = fsr/(2**nbits)
return (s/lsb).astype(int)
def scale(self, factor):
"""Multiply the frequency by factor"""
self.frequency *= factor
return self
name = 'Two Tones Waveform'
target = TTWaveform
def launch():
g = target()
hn = commands.getoutput('hostname')
daemon = Pyro4.Daemon(host = hn)
myUri = daemon.register(g)
ns=Pyro4.locateNS()
ns.register("TTSine", myUri)
daemon.requestLoop()
if __name__ == '__main__':
launch()
def Property(func):
return property(**func())
decodeDict = {'KHZ': 3, 'MHZ': 6, 'HZ':0, 'UHZ': -6, 'NHZ': 9,
'MV': -3, 'NV': -6, 'KV': 3, 'V':0,
'MVPP': -3, 'NVPP': -6, 'KVPP': 3, 'VPP':0}
def decode(values):
return float(values[0])* (10.**float(decodeDict[values[1].upper()]))
def parse(value, s):
if type(value) is str:
value = value.split(" ")
value[0] = float(value[0])
value = tuple(value)
if type(value) is tuple and len(value) == 1:
value = value[0]
if type(value) is not tuple:
value = (value, s)
return tuple(str(i) for i in value)
def prettyParameter(x, vx):
print 'Parameter %s is called %s.' % (x, vx[0])
print 'Description:', vx[1]
print 'Default value, in %s, is %s' % (repr(vx[3]), repr(vx[2]))
from numpy import array
from Item import *
"""This class represent a generic waveform."""
class Waveform(Item):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
"""A waveform must provide this method.
Create a numeric array which represents the wave."""
def generate(self, nbits, frequency, samples, fsr):
return array([])
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
def getType(self):
return type(self)
__author__="Federico"
__date__ ="$Aug 17, 2011 4:43:08 PM$"
# PAGE: Python ADC and GEnerators API
hasSis33 = False
import SineWaveform, TTWaveform
import Agilent33250A
import RemoteObject
try:
import Sis33
hasSis33 = True
except:
#print 'Error while loading Sis33 module, skipping it'
pass
waveforms = (RemoteObject, SineWaveform, TTWaveform)
generators = (Agilent33250A, RemoteObject)
if hasSis33:
adcs = (RemoteObject, Sis33)
else:
adcs = (RemoteObject, )
# -*- coding: utf-8 -*-
__author__ = "Johannes Hölzl <johannes.hoelzl@gmx.de>"
__license__ = "GNU LGPL"
# -*- coding: utf-8 -*-
# Copyright (c) 2007 Johannes Hölzl <johannes.hoelzl@gmx.de>
#
# This library is covered by the GNU LGPL, read LICENSE for details.
"""Provides access to the EEPROM of Silabs CP210x devices
The following classes are available:
class Cp210xProgrammer:
Provides direct access to the CP2101, can be used to write single data
directly or via an EEPROM image.
class EEPROM:
Can be used to read or write a hex file containing the EEPROM content
of an CP2101. Provides also access to the single fields in the EEPROM.
"""
import ctypes
import usb
__all__ = ['Cp210xProgrammer', 'Cp210xError']
CP2101_UART = 0x00
CP2101_CONFIG = 0xFF
CP2101_UART_ENABLE = 0x0001
CP2101_UART_DISABLE = 0x0000
REG_VENDOR_ID = 0x3701
REG_PRODUCT_ID = 0x3702
REG_PRODUCT_STRING = 0x3703
REG_SERIAL_NUMBER = 0x3704
REG_CFG_ATTRIBUTES = 0x3705
REG_MAX_POWER = 0x3706
REG_VERSION = 0x3707
REG_UNKNOWN = 0x3708
REG_EEPROM = 0x3709
REG_LOCK_VALUE = 0x370A
REG_PART_NUMBER = 0x370B
SIZE_EEPROM = 0x0400
SIZE_PRODUCT_STRING = 0x007D
SIZE_SERIAL_NUMBER = 0x003F
SIZE_BAUDRATES = 32
SIZE_BAUDRATE_CFG = 10
SIZE_BAUDRATE_TABLE = SIZE_BAUDRATES * SIZE_BAUDRATE_CFG
SIZE_VENDOR_STRING = 24
LCK_LOCKED = 0x00
LCK_UNLOCKED = 0xFF
VID_SILABS = 0x10C4
PID_CP210x = 0xEA60
VALUES = [
('product_string', 'string'),
('serial_number', 'string'),
('product_id', 'id'),
('vendor_id', 'id'),
('version', 'version'),
('bus_powered', 'boolean'),
('max_power', 'int'),
('locked', 'boolean'),
('part_number', 'int'),
('vendor_string', 'string'),
('baudrate_table', 'list'),
]
def iif(v, a, b):
if v:
return a
else:
return b
def to_div2(p):
value = int(p / 2)
if (value * 2) < p:
value += 1
return value
def to_bcd(i):
assert i >= 0 and i <= 99
return (i // 10) << 4 | (i % 10)
def to_bcd2( (i, j) ):
return to_bcd(i) << 8 | to_bcd(j)
def from_bcd(num):
return num & 0x0F + (num >> 4) * 10
def from_bcd2(data):
return (from_bcd(data >> 8), from_bcd(data & 0xFF))
def from_binary(data, le=True):
value = 0
if le:
data = data[::-1]
for byte in data:
value = value << 8 | ord(byte)
return value
def to_binary(value, size=2, le=True):
data = ''
for i in range(size):
data += chr(value & 0xFF)
value >>= 8
if le:
return data
else:
return data[::-1]
def parse_baudrate_cfg(data):
return (from_binary(data[0:2], le=False),
from_binary(data[2:4], le=False),
from_binary(data[4:5]),
from_binary(data[6:10]))
def build_baudrate_cfg(baudgen, timer0reload, prescaler, baudrate):
return (to_binary(baudgen, le=False) + to_binary(timer0reload, le=False) +
to_binary(prescaler, 1) + '\x00' + to_binary(baudrate, 4))
class Cp210xError(IOError):
pass
class DeviceLocked(Cp210xError):
pass
class Cp210xProgrammer(object):
"""Program an Silabs CP2101, CP2102 or CP2103
This modul provides access to Silabs CP210x devices to set some USB
descriptor fields and some USB descriptor strings.
The following fields can be set:
* Vendor ID
* Product ID
* Product String
* Serial Number
* Device Version
* Bus Powered
* max. Power consumption
Either use libusb to find a device, and provide the device description
to the constructor, or use Cp210xProgrammer.list_device() to list all
devices matching certain pattern.
To progamm the device open() it, set the data, and close() it. To have the
changed fields reread call reset() before closing it.
"""
TIMEOUT = 300 #ms
@classmethod
def list_devices(self, patterns=[{ 'idVendor': VID_SILABS,
'idProduct': PID_CP210x }]):
"""Yields a list of devices matching certain patterns.
param patterns: This must be a list of dictionaries or pairs of string.
Each device in the usb tree is matched against all pattern in the
list.
When an item is a dictionary all fields of the descriptors
are compared against the corresponding values in the dictionary. If
each value is equal, the device is yielded.
When an item is a pair of strings. The first string must be the
dirname of the bus and the second string the filename of the device.
For example:
>> list(Cp210xProgrammer.list_device([{ 'idVendor': VID_SILABS,
'idProduct': PID_CP210x }]))
[device(...)]
"""
usb.find_busses()
usb.find_devices()
bus = usb.get_busses()
while bus:
dev = bus.contents.devices
while dev:
for pattern in patterns:
if isinstance(pattern, dict):
for name, value in pattern.items():
if getattr(dev.contents.descriptor, name) != value:
break
else:
yield self(dev)
break
elif isinstance(pattern, tuple):
if (bus.contents.dirname == pattern[0] and
dev.contents.filename == pattern[1]):
yield self(dev)
break
dev = dev.contents.next
bus = bus.contents.next
def __init__(self, dev_info):
self.dev_info = dev_info
self.handle = None
self._locked = None
def open(self):
"""Opens the device.
Only after an successful call to open() data can be read from and
written to the device.
Claims all resources associated with this device.
"""
self.handle = usb.open(self.dev_info)
if self.handle == 0:
self.handle = None
raise Cp210xError("Can't open device.")
usb.set_configuration(self.handle, 1)
usb.claim_interface(self.handle, 0)
def reset(self):
"""Force the USB stack to reset the device.
Resets the device through an hard reset over the port to which the
device is connected. After that happend the EEPROM content in the device
is reread and the device's descriptors are the one written to it.
"""
assert self.handle is not None
usb.reset(self.handle)
def close(self):
"""Closes the device.
Releases all resources associated with this device.
"""
assert self.handle is not None
usb.release_interface(self.handle, 0)
usb.close(self.handle)
self.handle = None
def __del__(self):
if self.handle is not None:
self.close()
def _set_config(self, value, index=0, data=None, request=CP2101_CONFIG):
assert self.handle is not None
if self.get_locked():
raise DeviceLocked()
if data is not None:
data_length = len(data)
else:
data_length = 0
res = usb.control_msg(self.handle, usb.ENDPOINT_OUT | usb.TYPE_VENDOR,
request, value, index, data, data_length,
self.TIMEOUT)
if res < 0:
raise Cp210xError("Unable to send request %04X result=%d"
% (value, res))
def _set_config_string(self, value, content, max_length):
assert isinstance(content, basestring)
encoded = content.encode('utf-16-le')
assert len(encoded) <= max_length
self._set_config(value, data=chr(len(encoded) + 2) + "\x03" + encoded)
def _get_config(self, value, length, index=0, request=CP2101_CONFIG):
assert self.handle is not None
data = ctypes.create_string_buffer(length)
res = usb.control_msg(self.handle, usb.ENDPOINT_IN | usb.TYPE_VENDOR,
request, value, index, data, length,
self.TIMEOUT)
if res < 0:
raise Cp210xError("Unable to send request, %04X result=%d"
% (value, res))
return data.raw[:res]
def _get_int8_config(self, value, index=0, request=CP2101_CONFIG):
return ord(self._get_config(value, 1, index=index, request=request))
def _get_int16_config(self, value, index=0, request=CP2101_CONFIG):
data = self._get_config(value, 2, index=index, request=request)
return ord(data[0]) << 8 | ord(data[1])
def get_eeprom_content(self):
"""Reads the entire EEPROM content as one big 1024-byte blob.
"""
return self._get_config(REG_EEPROM, SIZE_EEPROM)
def get_baudrate_content(self):
"""Return the baudrate table as binary data.
"""
return self._get_config(REG_EEPROM, SIZE_BAUDRATE_TABLE)
def get_baudrate_table(self):
"""Returns the baudrate table.
A list containing 4-tuples are returnes.
Each tuple containes the following data:
* BaudGen: Value used to generate the real baudrate.
* Time0Reset: Value used to generate the usb timeout.
* Prescaler: Used to generate the real baudrate.
* Baudrate: The baudrate which activates this entry.
"""
data = self.get_baudrate_content()
return [parse_baudrate_cfg(data[pos:pos+SIZE_BAUDRATE_CFG])
for pos in range(0, SIZE_BAUDRATE_TABLE, SIZE_BAUDRATE_CFG)]
def set_baudrate_table(self, baudrates):
"""Writes the baudrate table.
See get_baudrate_table() for the structure of the table.
"""
assert len(baudrates) == SIZE_BAUDRATES
self.set_baudrate_content(data=''.join(build_baudrate_cfg(*cfg)
for cfg in baudrates))
baudrate_table = property(get_baudrate_table, set_baudrate_table)
def get_part_number(self):
""" The part number of the device.
Returns: 1 for an CP2101
2 for an CP2102
3 for an CP2103
"""
return self._get_int8_config(REG_PART_NUMBER)
def get_locked(self):
""" The lock value of the device.
When True is returnes no data can be written to the device.
"""
if self._locked is None:
self._locked = self._get_int8_config(REG_LOCK_VALUE) == LCK_LOCKED
return self._locked
def set_eeprom_content(self, content):
"""Writes an 1024-byte blob to the EEPROM
"""
assert len(content) == SIZE_EEPROM, ("EEPROM data must be %i bytes."
% SIZE_EEPROM)
assert isinstance(content, str), "EEPROM data must be string."
self._set_config(REG_EEPROM, data=content)
def set_product_id(self, pid):
"""Sets the Product ID
"""
assert pid > 0x0000 and pid < 0xFFFF
self._set_config(REG_PRODUCT_ID, pid)
def set_vendor_id(self, vid):
"""Sets the Vendor ID
"""
assert vid > 0x0000 and vid < 0xFFFF
self._set_config(REG_VENDOR_ID, vid)
def set_product_string(self, product_string):
"""Sets the product string.
Be aware that the string will be stored as UTF-16 encoded and should not
exceed SIZE_PRODUCT_STRING
"""
self._set_config_string(REG_PRODUCT_STRING, product_string,
SIZE_PRODUCT_STRING)
def set_serial_number(self, serial_number):
self._set_config_string(REG_SERIAL_NUMBER, serial_number,
SIZE_SERIAL_NUMBER)
def set_max_power(self, max_power):
assert max_power >= 0 and max_power <= 500
self._set_config(REG_MAX_POWER, to_div2(max_power))
def set_bus_powered(self, bus_powered):
if bus_powered:
self._set_config(REG_CFG_ATTRIBUTES, 0xC0)
else:
self._set_config(REG_CFG_ATTRIBUTES, 0x80)
def set_version(self, version):
self._set_config(REG_VERSION, to_bcd2(version))
def set_locked(self, locked):
""" The lock value of the device.
When True is returnes no data can be written to the device.
"""
if locked:
self._set_config(REG_LOCK_VALUE, LCK_LOCKED)
else:
self._set_config(REG_LOCK_VALUE, LCK_UNLOCKED)
def set_values(self, values):
for name, value in values.items():
if name not in ['part_number', 'vendor_string']:
getattr(self, "set_" + name) (value)
# -*- coding: utf-8 -*-
# Copyright (c) 2007 Johannes Hölzl <johannes.hoelzl@gmx.de>
#
# This library is covered by the GNU LGPL, read LICENSE for details.
import cp210x
from cp210x import from_binary, to_binary, iif, VALUES
__all__ = ['EEPROM', 'HexFileError']
POS_BAUDRATE_TABLE = 0x0000
POS_PART_NUMBER = 0x01FF
POS_PRODUCT_STRING = 0x0208
POS_SERIAL_NUMBER = 0x0307
POS_PRODUCT_ID = 0x0390
POS_VENDOR_ID = 0x0392
POS_VERSION = 0x0394
POS_CFG_ATTRIBUTES = 0x03A1
POS_MAX_POWER = 0x03A2
POS_VENDOR_STRING = 0x03C3
POS_LOCK_VALUE = 0x03FF
class HexFileError(StandardError):
pass
def checksum(line):
return sum(ord(c) for c in line) & 0xFF
def _int_value(position, size, read=lambda x:x, write=lambda x:x):
def get(self):
return read(from_binary(self.get(position, size)))
def set(self, value):
self.set(position, to_binary(write(value), size))
return property(get, set)
def _str_value(position, max_size):
def get(self):
size = from_binary(self.get(position, 1))
assert size <= (max_size + 2) and size >= 2
assert self.get(position + 1, 1) == '\x03', "Missing 0x03 at %04X" % (position + 1)
return self.get(position + 2, size - 2).decode('utf-16-le')
def set(self, value):
encoded = value.encode('utf-16-le')
assert len(encoded) <= max_size
self.set(position, chr(len(encoded) + 2) + '\x03' + encoded)
return property(get, set)
class EEPROM(object):
START_ADDRESS = 0x3600
def __init__(self, content=None):
if isinstance(content, str) or content is None:
assert content is None or len(content) == cp210x.SIZE_EEPROM
self.content = content
elif isinstance(content, cp210x.Cp210xProgrammer):
self.content = content.get_eeprom_content()
else:
self.parse_hex_file(content.read())
def write_to_cp210x(self, cp210xDevice):
cp210xDevice.set_eeprom_content(self.content)
def parse_hex_file(self, hex_content):
self.content = ''
address = self.START_ADDRESS
for tag in hex_content.split('\n'):
if not tag.startswith(':'):
raise HexFileError("Line doesn't start with ':'")
try:
content = tag[1:].decode('hex')
except TypeError:
raise HexFileError("Hex data expected")
if len(content) < 5:
raise HexFileError("Line to short")
if checksum(content) != 0:
raise HexFileError("Checksum error")
size = from_binary(content[0])
tag_address = from_binary(content[1:3], le=False)
tag_type = from_binary(content[3:4])
line = content[4:-1]
if tag_type == 0x00:
if tag_address != address:
raise HexFileError("Expected address %04X but found %04X"
% (address, tag_address))
self.content += line
address += len(line)
elif tag_type == 0x01:
if size != 0 or len(line) != 0:
raise HexFileError("Defekt end tag")
break
else:
raise HexFileError("Unknown tag type %02X" % tag_type)
def build_hex_file(self):
for tag_start in range(0, len(self.content), 0x10):
line = self.content[tag_start:tag_start+0x10]
address = self.START_ADDRESS + tag_start
tag = (to_binary(len(line), 1) +
to_binary(address, le=False) +
'\x00' +
line)
cs = checksum(tag)
if cs == 0:
tag += '\x00'
else:
tag += chr(0x100 - cs)
yield ":%s\n" % tag.encode('hex')
yield ":00000001FF\n"
def write_hex_file(self, f):
if isinstance(f, str):
f = file(f, 'wb')
do_close = True
else:
do_close = False
for line in self.build_hex_file():
f.write(line)
if do_close:
f.close()
def read_hex_file(self, f):
if isinstance(f, str):
f = file(f, 'rb')
do_close = True
else:
do_close = False
self.parse_hex_file(f.read())
if do_close:
f.close()
def get(self, pos, length):
return self.content[pos:pos+length]
def set(self, pos, data):
self.content = (self.content[:pos] +
data +
self.content[pos + len(data):])
def _get_baudrate_table(self):
dat = self.get(POS_BAUDRATE_TABLE, cp210x.SIZE_BAUDRATE_TABLE)
return [cp210x.parse_baudrate_cfg(dat[pos:pos+cp210x.SIZE_BAUDRATE_CFG])
for pos in range(0, cp210x.SIZE_BAUDRATE_TABLE,
cp210x.SIZE_BAUDRATE_CFG)]
def _set_baudrate_table(self, baudrates):
assert len(baudrates) == cp210x.SIZE_BAUDRATES
self.set(POS_BAUDRATE_TABLE,
''.join(cp210x.build_baudrate_cfg(*cfg) for cfg in baudrates))
baudrate_table = property(_get_baudrate_table, _set_baudrate_table)
product_string = _str_value(POS_PRODUCT_STRING, cp210x.SIZE_PRODUCT_STRING)
serial_number = _str_value(POS_SERIAL_NUMBER, cp210x.SIZE_SERIAL_NUMBER)
part_number = _int_value(POS_PART_NUMBER, 1)
product_id = _int_value(POS_PRODUCT_ID, 2)
vendor_id = _int_value(POS_VENDOR_ID, 2)
version = _int_value(POS_VERSION, 2,
cp210x.from_bcd2, cp210x.to_bcd2)
bus_powered = _int_value(POS_CFG_ATTRIBUTES, 1,
lambda a: bool(a & 0x40),
lambda a: iif(a, 0xC0, 0x80))
max_power = _int_value(POS_MAX_POWER, 1, lambda p: p*2, cp210x.to_div2)
vendor_string = _str_value(POS_VENDOR_STRING, cp210x.SIZE_VENDOR_STRING)
locked = _int_value(POS_LOCK_VALUE, 1,
lambda l: l == cp210x.LCK_LOCKED,
lambda b: iif(b, cp210x.LCK_LOCKED,
cp210x.LCK_UNLOCKED))
def get_values(self):
return dict((name, getattr(self, name)) for name, type in VALUES)
def set_values(self, values):
for name, value in values.items():
setattr(self, name, value)
# Python interface for "usb.h" version 0.1.4.4.4
#
# Copyright (c) 2005 Robert Hoelzl <robert.hoelzl@gmx.de>
# Copyright (c) 2007 Johannes Hoelzl <johannes.hoelzl@gmx.de>
#
# This library is covered by the GNU LGPL, read LICENSE for details.
from ctypes import *
import sys
class LibUsbNotInstalled(OSError):
pass
try:
if sys.platform == 'darwin':
PATH_MAX = 1024
dll=cdll.LoadLibrary("libusb.dylib")
elif sys.platform == 'linux2':
PATH_MAX = 4096
dll=cdll.LoadLibrary("libusb.so")
else:
raise NotImplementedError("Platform %s not supported by usb.py" % sys.platform)
except OSError:
raise LibUsbNotInstalled()
# helper functions
def func(f, *args, **retval):
f.restype = retval.get('retval', None)
f.argtypes = args
if retval.has_key('rename'): globals()[retval['rename']] = f
else: globals()[f.__name__[4:]] = f
# constants
CLASS_PER_INTERFACE = 0
USB_CLASS_AUDIO = 1
CLASS_COMM = 2
CLASS_HID = 3
CLASS_PRINTER = 7
CLASS_PTP = 6
CLASS_MASS_STORAGE = 8
CLASS_HUB = 9
CLASS_DATA = 10
CLASS_VENDOR_SPEC = 0xff
DT_DEVICE = 0x01
DT_CONFIG = 0x02
DT_STRING = 0x03
DT_INTERFACE = 0x04
DT_ENDPOINT = 0x05
DT_HID = 0x21
DT_REPORT = 0x22
DT_PHYSICAL = 0x23
DT_HUB = 0x29
DT_DEVICE_SIZE = 18
DT_CONFIG_SIZE = 9
DT_INTERFACE_SIZE = 9
DT_ENDPOINT_SIZE = 7
DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
DT_HUB_NONVAR_SIZE = 7
class descriptor_header(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8) ]
class string_descriptor(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8),
("wData", c_uint*1) ]
class hid_descriptor(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8),
("bcdHID", c_uint16),
("bCountryCode", c_uint8),
("bNumDescriptors", c_uint8) ]
MAXENDPOINTS = 32
class endpoint_descriptor(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8),
("bEndpointAddress", c_uint8),
("bmAttributes", c_uint8),
("wMaxPacketSize", c_uint16),
("bInterval", c_uint8),
("bRefresh", c_uint8),
("bSynchAddress", c_uint8),
("extra", POINTER(c_uint8)),
("extralen", c_int) ]
ENDPOINT_ADDRESS_MASK = 0x0f # in bEndpointAddress
ENDPOINT_DIR_MASK = 0x80
ENDPOINT_TYPE_MASK = 0x03 # in bmAttributes
ENDPOINT_TYPE_CONTROL = 0
ENDPOINT_TYPE_ISOCHRONOUS = 1
ENDPOINT_TYPE_BULK = 2
ENDPOINT_TYPE_INTERRUPT = 3
MAXINTERFACES = 32
class interface_descriptor(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8),
("bInterfaceNumber", c_uint8),
("bAlternateSetting", c_uint8),
("bNumEndpoints", c_uint8),
("bInterfaceClass", c_uint8),
("bInterfaceSubClass", c_uint8),
("bInterfaceProtocol", c_uint8),
("iInterface", c_uint8),
("endpoint", POINTER(endpoint_descriptor)),
("extra", POINTER(c_uint8)),
("extralen", c_int) ]
MAXALTSETTING = 128 # Hard limit
class interface(Structure): _fields_ = [
("altsetting", POINTER(interface_descriptor)),
("num_altsetting", c_int) ]
MAXCONFIG = 8
class config_descriptor(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8),
("wTotalLength", c_uint16),
("bNumInterfaces", c_uint8),
("bConfigurationValue", c_uint8),
("iConfiguration", c_uint16),
("bmAttributes", c_uint8),
("MaxPower", c_uint8),
("interface", POINTER(interface)),
("extra", POINTER(c_uint8)), # Extra descriptors
("extralen", c_int) ]
class device_descriptor(Structure): _fields_ = [
("bLength", c_uint8),
("bDescriptorType", c_uint8),
("bcdUSB", c_uint16),
("bDeviceClass", c_uint8),
("bDeviceSubClass", c_uint8),
("bDeviceProtocol", c_uint8),
("bMaxPacketSize0", c_uint8),
("idVendor", c_uint16),
("idProduct", c_uint16),
("bcdDevice", c_uint16),
("iManufacturer", c_uint8),
("iProduct", c_uint8),
("iSerialNumber", c_uint8),
("bNumConfigurations", c_uint8) ]
class ctrl_setup(Structure): _fields_ = [
("bRequestType", c_uint8),
("bRequest", c_uint8),
("wValue", c_uint16),
("wIndex", c_uint16),
("wLength", c_uint16) ]
REQ_GET_STATUS = 0x00
REQ_CLEAR_FEATURE = 0x01
# 0x02 is reserved
REQ_SET_FEATURE = 0x03
# 0x04 is reserved
REQ_SET_ADDRESS = 0x05
REQ_GET_DESCRIPTOR = 0x06
REQ_SET_DESCRIPTOR = 0x07
REQ_GET_CONFIGURATION = 0x08
REQ_SET_CONFIGURATION = 0x09
REQ_GET_INTERFACE = 0x0A
REQ_SET_INTERFACE = 0x0B
REQ_SYNCH_FRAME = 0x0C
TYPE_STANDARD = (0x00 << 5)
TYPE_CLASS = (0x01 << 5)
TYPE_VENDOR = (0x02 << 5)
TYPE_RESERVED = (0x03 << 5)
RECIP_DEVICE = 0x00
RECIP_INTERFACE = 0x01
RECIP_ENDPOINT = 0x02
RECIP_OTHER = 0x03
ENDPOINT_IN = 0x80
ENDPOINT_OUT = 0x00
# Error codes
ERROR_BEGIN = 500000
#if 1
#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0)
#else
#define USB_LE16_TO_CPU(x)
#endif
device_p = POINTER("device")
bus_p = POINTER("bus")
class device(Structure): _fields_ = [
("next", device_p),
("prev", device_p),
("filename", c_char*(PATH_MAX + 1)),
("bus", bus_p),
("descriptor", device_descriptor),
("config", POINTER(config_descriptor)),
("dev", c_void_p), # Darwin support
("devnum", c_char),
("num_children", c_uint8),
("children", POINTER(device_p)) ]
SetPointerType(device_p, device)
class bus(Structure): _fields_ = [
("next", bus_p),
("prev", bus_p),
("dirname", c_char*(PATH_MAX + 1)),
("devices", device_p),
("location", c_uint),
("root_dev", device_p) ]
SetPointerType(bus_p, bus)
dev_handle_p = c_void_p
func(dll.usb_open, device_p, retval=dev_handle_p, rename="_open")
func(dll.usb_close, dev_handle_p, retval=c_int)
func(dll.usb_get_string, dev_handle_p, c_int, c_int, c_char_p, c_int, retval=c_int)
func(dll.usb_get_string_simple, dev_handle_p, c_int, c_char_p, c_int, retval=c_int)
func(dll.usb_get_descriptor_by_endpoint, dev_handle_p, c_int, c_uint8, c_uint8, c_void_p, c_int, retval=c_int)
func(dll.usb_get_descriptor, dev_handle_p, c_uint8, c_uint8, c_void_p, c_int, retval=c_int)
func(dll.usb_bulk_write, dev_handle_p, c_int, c_char_p, c_int, c_int, retval=c_int)
func(dll.usb_bulk_read, dev_handle_p, c_int, c_char_p, c_int, c_int, retval=c_int)
func(dll.usb_interrupt_write, dev_handle_p, c_int, c_char_p, c_int, c_int, retval=c_int)
func(dll.usb_interrupt_read, dev_handle_p, c_int, c_char_p, c_int, c_int, retval=c_int)
func(dll.usb_control_msg, dev_handle_p, c_int, c_int, c_int, c_int, c_char_p, c_int, c_int, retval=c_int)
func(dll.usb_set_configuration, dev_handle_p, c_int, retval=c_int)
func(dll.usb_claim_interface, dev_handle_p, c_int, retval=c_int)
func(dll.usb_release_interface, dev_handle_p, c_int, retval=c_int)
func(dll.usb_set_altinterface, dev_handle_p, c_int, retval=c_int)
func(dll.usb_resetep, dev_handle_p, c_uint16, retval=c_int)
func(dll.usb_clear_halt, dev_handle_p, c_uint16, retval=c_int)
func(dll.usb_reset, dev_handle_p, retval=c_int)
func(dll.usb_strerror, retval=c_char_p)
func(dll.usb_init)
func(dll.usb_set_debug, c_int)
func(dll.usb_find_busses, retval=c_int)
func(dll.usb_find_devices, retval=c_int)
func(dll.usb_device, dev_handle_p, retval=device_p, rename="get_device")
func(dll.usb_get_busses, retval=bus_p)
func(dll.usb_detach_kernel_driver_np, dev_handle_p, c_int, retval=c_int)
# workaround for bug in ctypes 0.9.6 (cannot create functions with c_void_p as retval)
def open(dev):
return cast(_open(dev), dev_handle_p)
# -*- coding: utf-8 -*-
# Copyright (c) 2007 Johannes Hölzl <johannes.hoelzl@gmx.de>
#
# This library is covered by the GNU LGPL, read LICENSE for details.
# For documentation of the baudrate table see:
#
# [AN205] Silicon Labs Application Note 205 Rev. 0.3
# http://www.silabs.com/public/documents/tpub_doc/anote/Microcontrollers/Interface/en/an205.pdf
import re
from ConfigParser import ConfigParser
import cp210x
from cp210x import VALUES, SIZE_BAUDRATES
__all__ = ['read_file', 'write_file', 'update_values', 'PrescalerIsZero',
'ValuesFileError']
class ValuesError(StandardError):
pass
class PrescalerIsZero(ValuesError):
pass
class ValuesFileError(ValuesError):
pass
version_pattern = re.compile(r'^\s*(\d\d?)\.(\d\d?)\s*$')
def read_version(s):
match = version_pattern.match(s)
if match is None:
raise ValueError("Version does not match 'xx.yy'")
return (int(match.group(1)), int(match.group(2)))
def write_version(v):
return "%d.%02d" % v
def read_hex(s):
return int(s.strip(), 16)
def write_hex(num):
return "%04X" % num
def write_bool(b):
if b:
return 'yes'
else:
return 'no'
def read_bool(s):
s = s.strip().lower()
if s not in ['true', 'yes', 'false', 'no']:
raise ValueError("Boolean must be either 'true', 'yes', 'false' or 'no'.")
return s in ['true', 'yes']
def read_baudrate_info(s):
values = s.split(',')
if len(values) != 3:
raise ValueError("Baudrate info must be three comma-separated items")
try:
baudgen = read_hex(values[0])
except ValueError:
raise ValueError("The first baudrate info must be a hex-value")
try:
timer0 = read_hex(values[1])
except ValueError:
raise ValueError("The second baudrate info must be a hex-value")
try:
prescale = int(values[2])
except ValueError:
raise ValueError("The thirdbaudrate info must be a number")
return (baudgen, timer0, prescale)
TYPES = {
'boolean': (read_bool, write_bool),
'int': (int, str),
'id': (read_hex, write_hex),
'string': (str, str),
'version': (read_version, write_version),
}
def read_file(fp):
cp = ConfigParser()
if isinstance(fp, str):
cp.read([fp])
else:
cp.readfp(fp)
values = {}
for name, type in VALUES:
if name is 'baudrate_table':
continue
reader, _ = TYPES[type]
if cp.has_option('usb device', name):
try:
values[name] = reader(cp.get('usb device', name))
except ValueError, err:
raise ValuesFileError("Key '%s': %s" % (name, str(err)))
if cp.has_section('baudrate table'):
baudrate_table = []
for name, value in cp.items('baudrate table'):
try:
baudrate = int(name)
except ValueError:
raise ValuesFileError("Key names in 'baudrate table' must be"
" baudrate numbers.")
try:
baudrate_table.append(read_baudrate_info(value) + (baudrate, ))
except ValueError, err:
raise ValuesFileError("Wrong baudrate info %i: %s"
% (baudrate, str(err)))
baudrate_table.sort(key=(lambda i: i[3]), reverse=True)
values['baudrate_table'] = baudrate_table
return values
def write_file(fp, values):
fp.write("[usb device]\n")
for name, type in VALUES:
if name == 'baudrate_table':
continue
_, writer = TYPES[type]
if name in values:
fp.write("%s = %s\n" % (name, writer(values[name])))
if 'baudrate_table' in values:
fp.write("\n")
fp.write("[baudrate table]\n")
for (baudgen, timegen, prescaler,
baudrate) in sorted(values['baudrate_table'], key=(lambda i: i[3]),
reverse=True):
fp.write("%7d = %04X, %04X, %d # %s\n"
% (baudrate, baudgen, timegen, prescaler,
show_baudrate(baudgen, timegen, prescaler)))
def calc_baudrate(baudgen, timegen, prescaler):
# This formulas are from AN205 page 5.
if prescaler == 0:
raise PrescalerIsZero("Prescaler is 0")
baudrate = (24000000. / prescaler) / (0x10000 - baudgen)
return (baudrate, (0x10000 - timegen) * 2)
def show_baudrate(baudgen, timegen, prescaler):
try:
baudrate, timeout = calc_baudrate(baudgen, timegen, prescaler)
except PrescalerIsZero:
return "Wrong data, Prescaler is 0."
if timeout >= 1000:
timeout = "%1.3f ms" % (float(timeout) / 1000)
else:
timeout = "%d us" % timeout
if baudrate is None:
return ", %s" % (baudrate, timeout)
else:
return "%7.0f Baud, %s" % (baudrate, timeout)
def update_values(v, new, dev):
old_baudrate_table = v.get('baudrate_table')
new_baudrate_table = new.get('baudrate_table')
v.update(new)
# update baudrate table
# it is needed, that the baudrate table has 32 entries when it is written
# to the eeprom or device.
if ((old_baudrate_table is not None or new_baudrate_table is not None) and
(new_baudrate_table is None or
len(new_baudrate_table) < SIZE_BAUDRATES)):
if old_baudrate_table is not None:
if len(old_baudrate_table) < SIZE_BAUDRATES:
baudrate_table = old_baudrate_table
else:
baudrate_table = list(merge_baudrate_table(dev.baudrate_table,
old_baudrate_table))
else:
baudrate_table = dev.baudrate_table
if new_baudrate_table:
baudrate_table = list(merge_baudrate_table(baudrate_table,
new_baudrate_table))
v['baudrate_table'] = baudrate_table
def merge_baudrate_table(old, new):
for (old_info, (start, stop)) in zip(old, REQUEST_BAUDRATE_RANGES):
for baudgen, timer, prescaler, baudrate in new:
if ((start is None or baudrate <= start) and
baudrate >= stop):
yield (baudgen, timer, prescaler, baudrate)
break
else:
yield old_info
REQUEST_BAUDRATE_RANGES = [
# The table data is from AN205 Table 1 on page 1.
# Start End Default Baudrate
(None, 2457601), # Undefined
(2457600, 1474561), # Undefined
(1474560, 1053258), # Undefined
(1053257, 670255), # 921600
( 670254, 567139), # 576000
( 567138, 491521), # 500000
( 491520, 273067), # 460800
( 273066, 254235), # 256000
( 254234, 237833), # 250000
( 237832, 156869), # 230400
( 156868, 129348), # 153600
( 129347, 117029), # 128000
( 117028, 77609), # 115200
( 77608, 64112), # 76800
( 64111, 58054), # 64000
( 58053, 56281), # 57600
( 56280, 51559), # 56000
( 51558, 38602), # 51200
( 38601, 28913), # 38400
( 28912, 19251), # 28800
( 19250, 16063), # 19200
( 16062, 14429), # 16000
( 14428, 9613), # 14400
( 9612, 7208), # 9600
( 7207, 4804), # 7200
( 4803, 4001), # 4800
( 4000, 2401), # 4000
( 2400, 1801), # 2400
( 1800, 1201), # 1800
( 1200, 601), # 1200
( 600, 301), # 600
( 300, 57), # 300
]
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
import sys
import rr
import time
import os
import re
from ctypes import *
from ptsexcept import *
from cp210x import usb, valuefile, cp210x
from cp210x.eeprom import EEPROM
"""
cp210x_eeprom: Access to USB-UART bridge CP2103 EEPROM
Note: The EEPROM is used to store calibration data (reference voltage output for
the three ranges). The data are stores as a string in the "Product String".
Format: "4.09551500 0.40967800 0.04096060"
"""
CALIBR_RANGES = ['10V', '1V', '100mV']
class CP210xEepromOperationError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return ("CP210x EEPROM: %s" %(self.msg))
class CCP210x_Eeprom:
def __init__(self, vid, pid):
usb.init()
usb_patterns = []
vid = int(vid, 16)
pid = int(pid, 16)
usb_patterns.append(dict(idVendor=vid, idProduct=pid))
self.dev = [item for item in cp210x.Cp210xProgrammer.list_devices(usb_patterns)]
self.dev = self.dev[0]
def get_calibr_data(self):
self.dev.open()
try:
eeprom = EEPROM(self.dev)
except:
raise CP210xEepromOperationError('Cannot open device.')
finally:
self.dev.close()
eeprom_value = eeprom.get_values()
product_string = eeprom_value['product_string']
#print "Product string: \"%s\"" % product_string
calibr_string_list = product_string.split(' ')
if len(calibr_string_list) != 3:
raise CP210xEepromOperationError('Product string has the wrong format.')
calibr_data = {}
for i in range(len(calibr_string_list)):
pattern = r'\b[0-9]\.[0-9]{8}\b'
if re.search(pattern, calibr_string_list[i]):
calibr_data[CALIBR_RANGES[i]] = calibr_string_list[i]
else:
raise CP210xEepromOperationError('Product string has the wrong format.')
return calibr_data
def set_calibr_data(self, data):
self.dev.open()
product_string = data[CALIBR_RANGES[0]] + ' ' + data[CALIBR_RANGES[1]] + ' ' + data[CALIBR_RANGES[2]]
#print "New product string value: \"%s\"" % product_string
try:
self.dev.set_product_string(product_string)
print "Calibration data written to cp210x EEPROM."
finally:
self.dev.close()
#! /usr/bin/env python
# coding: utf8
import fcntl, struct, termios, os
import time
import array
class CCP210x:
def __init__(self, device):
self.fd = open(device, 'wb')
def gpio_set(self, mask):
f = array.array('I', [mask])
f[0] = (f[0] << 8) | 0xFF
fcntl.ioctl(self.fd.fileno(), 0x8001, f, 1)
def gpio_get(self):
f = array.array('I', [0])
fcntl.ioctl(self.fd.fileno(), 0x8000, f, 1)
return f[0]
# Create an object (the 0 is used to generate the name, eg. /dev/ttyUSB0
#gpio = cp210x_gpio(0)
# Infinite test loop
#while 1:
# # Pass the mask of the 4 bits as a hex number
# gpio.gpio_set(0xf)
# # Returns the states of the 4 bits as hex number
# print gpio.gpio_get()
# time.sleep(1)
# gpio.gpio_set(0x0)
# print gpio.gpio_get()
# time.sleep(1)
#! /usr/bin/env python
# coding: utf8
import glob
import os
import re
class CttyUSB:
def __init__(self):
pass
def find_usb_tty(self, vendor_id = None, product_id = None) :
tty_devs = []
for dn in glob.glob('/sys/bus/usb/devices/*') :
try :
vid = int(open(os.path.join(dn, "idVendor" )).read().strip(), 16)
pid = int(open(os.path.join(dn, "idProduct")).read().strip(), 16)
#print "dn:%s vid:%s pid:%s" % (dn,vid,pid)
if ((vendor_id is None) or (vid == vendor_id)) and ((product_id is None) or (pid == product_id)) :
dns = glob.glob(os.path.join(dn, os.path.basename(dn) + "*"))
for sdn in dns :
for fn in glob.glob(os.path.join(sdn, "*")) :
if re.search(r"\/ttyUSB[0-9]+$", fn) :
tty_devs.append("/dev/" + os.path.basename(fn))
pass
pass
pass
pass
except ( ValueError, TypeError, AttributeError, OSError, IOError ) :
pass
pass
return tty_devs
#print find_usb_tty()
#print find_usb_tty(0x10c4,0xea60)
#print find_usb_tty(0x0403,0x6001)
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2012
# Author: Matthieu Cattin (CERN)
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 8/5/2012
# Import standard modules
import sys
import time
import random
import math
# Import specific modules
#import rr
from csr import *
# Import register maps
from vic_regs import *
# Class to access VIC (Vectored Interrupt Controller)
class VicOperationError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return ("VIC: %s" %(self.msg))
class CVic:
# Interrupt vector table start address offset
IVT_ADDR = 0x80
#======================================================================
# Class initialisation
def __init__(self, bus, base_address):
self.bus = bus
self.base_address = base_address
# Objects declaration
self.vic = CCSR(self.bus, self.base_address, VIC_REGS)
def print_regs(self):
self.vic.print_reg_map()
def print_ivt(self):
print "\nInterrupt vector table:"
print "------+-------------------------------------------"
print " vect | address"
print "------+-------------------------------------------"
for i in range(32):
val = self.bus.iread(0, self.base_address + self.IVT_ADDR + (i*4), 4)
print " %02d | 0x%08X" % (i, val)
def enable_module(self):
self.vic.set_field('CTL', 'EN', 1)
def disable_module(self):
self.vic.set_field('CTL', 'EN', 0)
def set_polarity(self, pol):
self.vic.set_field('CTL', 'POL', pol)
def enable_emu_edge(self, length=1000):
self.vic.set_field('CTL', 'EMU_EDGE', 1)
self.vic.set_field('CTL', 'EMU_LEN', length)
def disable_emu_edge(self):
self.vic.set_field('CTL', 'EMU_EDGE', 0)
def enable_int(self, int_number):
self.vic.set_reg('IER', 1 << int_number)
def disbale_int(self, int_number):
self.vic.set_reg('IDR', 1 << int_number)
def get_raw_int_status(self):
return self.vic.get_reg('RISR')
def get_int_enable_mask(self):
return self.vic.get_reg('IMR')
def get_int_vector_addr(self):
return self.vic.get_reg('VAR')
def sw_int(self, int_number):
self.vic.set_reg('SWIR', 1 << int_number)
def int_ack(self):
self.vic.set_reg('EOIR', 0x0)
def get_vector_addr(self, vect):
return self.bus.iread(0, self.base_address + self.IVT_ADDR + (vect*4), 4)
# TODO -> set vector table with custom vector addresses
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2012
# Author: Matthieu Cattin (CERN)
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 8/5/2012
# Vectored interrupt controller registers
VIC_REGS=['VIC registers', {
'CTL':[0x00, 'VIC control', {
'EN':[0, 'Enable VIC', 0x1],
'POL':[1, 'Output polaritity (0=low, 1=high)', 0x1],
'EMU_EDGE':[2, 'Emulate edge sensitive output', 0x1],
'EMU_LEN':[3, 'Emulated edge pulse length timer', 0xFFFF],
'RESERVED':[19, 'Reserved', 0xFFF]}],
'RISR':[0x04, 'Raw interrupt status', {}],
'IER':[0x08, 'Interrupt enable', {}],
'IDR':[0x0C, 'Interrupt disable', {}],
'IMR':[0x10, 'Interrupt enable mask', {}],
'VAR':[0x14, 'Vector address', {}],
'SWIR':[0x18, 'Software interrupt', {}],
'EOIR':[0x1C, 'End of interrupt acknowledge', {}]
}]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment