def __init__(self): self.telegraph = None if MultiClamp.INSTANCE is not None: raise Exception( "Already created MultiClamp driver object; use MultiClamp.INSTANCE" ) self.handle = None self.lock = threading.RLock() self.channels = {} self.chanDesc = {} self.connect() self.telegraph = MultiClampTelegraph(self.chanDesc, self.telegraphMessage) MultiClamp.INSTANCE = self atexit.register(self.quit)
def __init__(self): self.telegraph = None if MultiClamp.INSTANCE is not None: raise Exception("Already created MultiClamp driver object; use MultiClamp.INSTANCE") self.handle = None self.lock = threading.RLock() #self.lock = Mutex(Mutex.Recursive) #self.devStates = [] ## Stores basic state of devices reported by telegraph self.channels = {} self.chanDesc = {} self.connect() self.telegraph = MultiClampTelegraph(self.chanDesc, self.telegraphMessage) MultiClamp.INSTANCE = self
class MultiClamp: """Class used to interface with remote multiclamp server. Only one instance of this class should be created. Example usage: mc = MultiClamp.instance() devs = mc.listDevices() chan0 = mc.getChannel(devs[0]) chan0.setMode('IC') signal, gain, units = chan0.getSignalInfo() """ INSTANCE = None def __init__(self): self.telegraph = None if MultiClamp.INSTANCE is not None: raise Exception( "Already created MultiClamp driver object; use MultiClamp.INSTANCE" ) self.handle = None self.lock = threading.RLock() self.channels = {} self.chanDesc = {} self.connect() self.telegraph = MultiClampTelegraph(self.chanDesc, self.telegraphMessage) MultiClamp.INSTANCE = self atexit.register(self.quit) def quit(self): ## do other things to shut down driver? self.disconnect() if self.telegraph is not None: self.telegraph.quit() MultiClamp.INSTANCE = None @staticmethod def instance(): return MultiClamp.INSTANCE def getChannel(self, channel, callback=None): """Return a MultiClampChannel object for the specified device/channel. The channel argument should be the same as a single item from listDevices(). The callback will be called when certain (but not any) changes are made to the multiclamp state.""" if channel not in self.channels: raise Exception( "No channel with description '%s'. Options are %s" % (str(channel), str(self.listChannels()))) ch = self.channels[channel] if callback is not None: ch.setCallback(callback) return ch def listChannels(self): """Return a list of strings used to identify all devices/channels. These strings should be used to identify the same channel across invocations.""" return self.channels.keys() def connect(self): """(re)create connection to commander.""" #print "connect to commander.." with self.lock: if self.handle is not None: #print " disconnect first" self.disconnect() (self.handle, err) = axlib.CreateObject() if self.handle == 0: self.handle = None self.raiseError("Error while initializing Axon library:", err) self.findDevices() #print " now connected:", self.chanDesc def disconnect(self): """Destroy connection to commander""" with self.lock: if self.handle is not None and axlib is not None: axlib.DestroyObject(self.handle) self.handle = None def findDevices(self): while True: ch = self.findMultiClamp() if ch is None: break else: ## Make sure the order of keys is well defined; string must be identical every time. ch1 = ch.copy() ch1['model'] = MODELS[ch1['model']] if ch1['model'] == 'MC700A': strDesc = ",".join( "%s:%s" % (k, ch1[k]) for k in ['model', 'com', 'dev', 'chan']) elif ch1['model'] == 'MC700B': strDesc = ",".join("%s:%s" % (k, ch1[k]) for k in ['model', 'sn', 'chan']) if strDesc not in self.channels: self.channels[strDesc] = MultiClampChannel(self, ch) self.chanDesc[strDesc] = ch def findMultiClamp(self): if len(self.channels) == 0: fn = 'FindFirstMultiClamp' else: fn = 'FindNextMultiClamp' try: serial = create_string_buffer('\0' * 16) ret = self.call(fn, pszSerialNum=serial, uBufSize=16) except: if sys.exc_info( )[1][0] == 6000: ## We have reached the end of the device list return None raise desc = { 'sn': ret['pszSerialNum'], 'model': ret['puModel'], 'com': ret['puCOMPortID'], 'dev': ret['puDeviceID'], 'chan': ret['puChannelID'] } return desc def call( self, fName, *args, **kargs ): ## call is only used for functions that return a bool error status and have a pnError argument passed by reference. with self.lock: ret = axlib('functions', fName)(self.handle, *args, **kargs) if ret() == 0: funcStr = "%s(%s)" % (fName, ', '.join( map(str, args) + ["%s=%s" % (k, str(kargs[k])) for k in kargs])) self.raiseError( "Error while running function %s\n Error:" % funcStr, ret['pnError']) return ret def raiseError(self, msg, err): raise Exception(err, msg + " " + self.errString(err)) def errString(self, err): try: return axlib.BuildErrorText(self.handle, err, create_string_buffer('\0' * 256), 256)['sTxtBuf'] except: sys.excepthook(*sys.exc_info()) return "<could not generate error message>" def telegraphMessage(self, msg, chID=None, state=None): if msg == 'update': self.channels[chID].updateState(state) elif msg == 'reconnect': self.connect()
class MultiClamp: """Class used to interface with remote multiclamp server. Only one instance of this class should be created. Example usage: mc = MultiClamp.instance() devs = mc.listDevices() chan0 = mc.getChannel(devs[0]) chan0.setMode('IC') signal, gain, units = chan0.getSignalInfo() """ INSTANCE = None def __init__(self): self.telegraph = None if MultiClamp.INSTANCE is not None: raise Exception("Already created MultiClamp driver object; use MultiClamp.INSTANCE") self.handle = None self.lock = threading.RLock() #self.lock = Mutex(Mutex.Recursive) #self.devStates = [] ## Stores basic state of devices reported by telegraph self.channels = {} self.chanDesc = {} self.connect() self.telegraph = MultiClampTelegraph(self.chanDesc, self.telegraphMessage) MultiClamp.INSTANCE = self def __del__(self): self.quit() def quit(self): ## do other things to shut down driver? self.disconnect() if self.telegraph is not None: self.telegraph.quit() MultiClamp.INSTANCE = None @staticmethod def instance(): return MultiClamp.INSTANCE def getChannel(self, channel, callback=None): """Return a MultiClampChannel object for the specified device/channel. The channel argument should be the same as a single item from listDevices(). The callback will be called when certain (but not any) changes are made to the multiclamp state.""" if channel not in self.channels: raise Exception("No channel with description '%s'. Options are %s" % (str(channel), str(self.listChannels()))) ch = self.channels[channel] if callback is not None: ch.setCallback(callback) return ch def listChannels(self): """Return a list of strings used to identify all devices/channels. These strings should be used to identify the same channel across invocations.""" return self.channels.keys() def connect(self): """(re)create connection to commander.""" #print "connect to commander.." with self.lock: if self.handle is not None: #print " disconnect first" self.disconnect() (self.handle, err) = axlib.CreateObject() if self.handle == 0: self.handle = None self.raiseError("Error while initializing Axon library:", err) self.findDevices() #print " now connected:", self.chanDesc def disconnect(self): """Destroy connection to commander""" with self.lock: if self.handle is not None and axlib is not None: axlib.DestroyObject(self.handle) self.handle = None def findDevices(self): while True: ch = self.findMultiClamp() if ch is None: break else: ## Make sure the order of keys is well defined; string must be identical every time. ch1 = ch.copy() ch1['model'] = MODELS[ch1['model']] if ch1['model'] == 'MC700A': strDesc = ",".join("%s:%s" % (k, ch1[k]) for k in ['model', 'com', 'dev', 'chan']) elif ch1['model'] == 'MC700B': strDesc = ",".join("%s:%s" % (k, ch1[k]) for k in ['model', 'sn', 'chan']) if strDesc not in self.channels: self.channels[strDesc] = MultiClampChannel(self, ch) self.chanDesc[strDesc] = ch def findMultiClamp(self): if len(self.channels) == 0: fn = 'FindFirstMultiClamp' else: fn = 'FindNextMultiClamp' try: serial = create_string_buffer('\0'*16) ret = self.call(fn, pszSerialNum=serial, uBufSize=16) except: if sys.exc_info()[1][0] == 6000: ## We have reached the end of the device list return None raise desc = {'sn': ret['pszSerialNum'], 'model': ret['puModel'], 'com': ret['puCOMPortID'], 'dev': ret['puDeviceID'], 'chan': ret['puChannelID']} #if MODELS.has_key(desc['model']): #desc['model'] = MODELS[desc['model']] #else: #desc['model'] = 'UNKNOWN' return desc def call(self, fName, *args, **kargs): ## call is only used for functions that return a bool error status and have a pnError argument passed by reference. with self.lock: ret = axlib('functions', fName)(self.handle, *args, **kargs) if ret() == 0: funcStr = "%s(%s)" % (fName, ', '.join(map(str, args) + ["%s=%s" % (k, str(kargs[k])) for k in kargs])) self.raiseError("Error while running function %s\n Error:" % funcStr, ret['pnError']) return ret def raiseError(self, msg, err): raise Exception(err, msg + " " + self.errString(err)) def errString(self, err): try: return axlib.BuildErrorText(self.handle, err, create_string_buffer('\0'*256), 256)['sTxtBuf'] except: sys.excepthook(*sys.exc_info()) return "<could not generate error message>" def telegraphMessage(self, msg, chID=None, state=None): if msg == 'update': self.channels[chID].updateState(state) elif msg == 'reconnect': self.connect()