#!/usr/bin/env python
"""
Code for interfacing with the Multi Clamp Commander application from Axon/Molecular Devices
"""
import ctypes as ct
import os
import time
import json
import datetime
import argparse
from watchdog.events import RegexMatchingEventHandler
from watchdog.observers import Observer
# Original code taken from https://github.com/tgbugs/inferno/core/mcc.py, commit 3d555888 (Update README.md, 2017-08-02)
# Original License: MIT
#
# Code heavily modified by Thomas Braun
API_VERSION_STR = b'1.0.0.9'
V_CLAMP_MODE = 0
I_CLAMP_MODE = 1
# clamp mode defintion
MCC_MODE_DICT = {0: 'VC',
1: 'IC',
2: 'IEZ'}
c_int_p = ct.POINTER(ct.c_int)
c_uint_p = ct.POINTER(ct.c_uint)
c_bool_p = ct.POINTER(ct.c_bool)
c_double_p = ct.POINTER(ct.c_double)
c_string_p = ct.POINTER(ct.c_char)
[docs]class DataGatherer():
"""
Collect data from all available MCC amplifiers
"""
def __init__(self):
pass
[docs] def getData(self, mcc):
"""
Return all MCC settings for all amplifiers as dictionary
"""
settings = {}
for uid in mcc.getUIDs():
mcc.selectUniqueID(uid)
settings[uid] = {}
for name in self._getListOfFunctions(mcc.GetMode()):
func = getattr(mcc, name)
settings[uid][name] = func()
return settings
def _getListOfFunctions(self, clampMode):
"""
Return a list of MultiClampControl getter functions with settings for
the current amplifier and the current clamp mode.
"""
VCfuncs = ["GetHoldingEnable",
"GetHolding",
"GetOscKillerEnable",
"GetRsCompBandwidth",
"GetRsCompCorrection",
"GetRsCompEnable",
"GetRsCompPrediction",
"GetWholeCellCompEnable",
"GetWholeCellCompCap",
"GetWholeCellCompResist",
"GetFastCompCap",
"GetSlowCompCap",
"GetFastCompTau",
"GetSlowCompTau",
"GetSlowCompTauX20Enable",
"GetZapDuration"]
ICfuncs = ["GetBuzzDuration",
"GetHoldingEnable",
"GetHolding",
"GetNeutralizationEnable",
"GetNeutralizationCap",
"GetBridgeBalEnable",
"GetBridgeBalResist",
"GetSlowCurrentInjEnable",
"GetSlowCurrentInjLevel",
"GetSlowCurrentInjSettlingTime"]
funcs = ["GetMode",
"GetModeSwitchEnable",
"GetPipetteOffset",
"GetPrimarySignal",
"GetPrimarySignalGain",
"GetPrimarySignalLPF",
"GetPrimarySignalHPF",
"GetScopeSignalLPF",
"GetSecondarySignal",
"GetSecondarySignalGain",
"GetSecondarySignalLPF",
"GetOutputZeroEnable",
"GetOutputZeroEnable",
"GetLeakSubEnable",
"GetLeakSubResist",
"GetPulseAmplitude",
"GetPulseDuration",
"GetMeterResistEnable",
"GetMeterIrmsEnable"]
if clampMode == V_CLAMP_MODE:
return VCfuncs + funcs
elif clampMode == I_CLAMP_MODE:
return ICfuncs + funcs
else:
raise RuntimeError(f"Unexpected clamp mode {clampMode}")
# utility function for type casting and returning the value of a pointer
[docs]def val(ptr, ptype):
if ptype == ct.c_char_p:
return ct.cast(ptr, ptype).value
return ct.cast(ptr, ptype)[0]
[docs]class MultiClampControl:
"""
Class for interacting with the MultiClamp Commander from Axon/Molecular Devices
Usage:
```
import mcc
m = mcc.MultiClampControl()
UIDs = m.getUIDs() # output all found amplifiers
m.selectUniqueID(next(iter(UIDs))) # select the first one (implicitly done by __init__)
clampMode = m.GetMode() # return the clamp mode
if m._handleError()[0]:
# handle error
pass
```
"""
def __init__(self, dllPath=None):
dllPaths = [("C:/Program Files/Molecular Devices/MultiClamp 700B Commander/"
"3rd Party Support/AxMultiClampMsg/"),
("C:/Program Files (x86)/Molecular Devices/MultiClamp 700B Commander/"
"3rd Party Support/AxMultiClampMsg/")]
if dllPath:
dllPaths.insert(0, dllPath)
for path in dllPaths:
if os.path.isdir(path):
self._getDLL(path)
self._pnError = ct.byref(ct.c_int())
# temporaries from some calls
self._pnPointer = ct.byref(ct.c_int())
self._puPointer = ct.byref(ct.c_uint())
self._pbPointer = ct.byref(ct.c_bool())
self._pdPointer = ct.byref(ct.c_double())
self.CreateObject()
# format for what this holds is: uModel, _pszSerialNum, uCOMPortID, uDeviceID, uChannelID
self.mcDict = {}
while True:
if not len(self.mcDict):
mcc = self.FindFirstMultiClamp()
else:
mcc = self.FindNextMultiClamp()
if not mcc:
break
self.mcDict[self._generateUIDFromMCCTuple(mcc)] = mcc
if not len(self.mcDict):
raise ValueError("Could not find any MCC amplifiers!")
# select the first one
self.selectUniqueID(next(iter(self.mcDict)))
if not self.CheckAPIVersion():
raise IOError(f"The API version {API_VERSION_STR} is not supported")
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.cleanup()
def _clearError(self):
"""
Clear error flag and return the now cleared error.
"""
err = self._pnError
self._pnError = ct.byref(ct.c_int(6000))
return err
def _hasError(self):
return val(self._pnError, c_int_p) != 6000
def _handleError(self):
"""
Return a tuple with the error state (T/F), the error value and the error message
"""
errdict = {6000: 'MCCMSG_ERROR_NOERROR',
6001: 'MCCMSG_ERROR_OUTOFMEMORY',
6002: 'MCCMSG_ERROR_MCCNOTOPEN',
6003: 'MCCMSG_ERROR_INVALIDDLLHANDLE',
6004: 'MCCMSG_ERROR_INVALIDPARAMETER',
6005: 'MCCMSG_ERROR_MSGTIMEOUT',
6006: 'MCCMSG_ERROR_MCCCOMMANDFAIL'}
if self._hasError():
errval = self._clearError()
return True, errval, errdict[errval]
return False, 6000, ""
def _extractValue(self, ptr, ptype):
if self._hasError():
return float('nan')
return val(ptr, ptype)
def _getDLL(self, dllPath):
olddir = os.getcwd()
try:
os.chdir(dllPath)
self.aDLL = ct.windll.AxMultiClampMsg
os.chdir(olddir)
except IOError:
os.chdir(olddir)
raise IOError('Multiclamp DLL not found! Check your install path!')
def _returnUID(self, serial, channel):
""" give demo mccs a unique id channel correspondence"""
if serial == 'Demo': # we know we have at least one demo channel
c1_count = 0
c2_count = 0
# have to deal with the fact that channels increment only AFTER the
# first run through
for uniqueID, tup in self.mcDict.items():
if uniqueID.count('Demo'):
chan = tup[-1]
if chan == 1:
c1_count += 1
elif chan == 2:
c2_count += 1
if channel == 1:
demo_count = c1_count + 1
elif channel == 2:
demo_count = c2_count + 1
return serial + '%s' % demo_count
else:
return serial
def _generateUIDFromMCCTuple(self, mcTuple):
serial = val(mcTuple[1], ct.c_char_p).decode('utf-8')
channel = mcTuple[-1]
serial = serial.strip('(').rstrip(')')
serial = self._returnUID(serial, channel)
mcid = '%s_%s' % (serial, channel)
return mcid
[docs] def getSerial(self):
return self.currentUniqueID.split('_')[0]
[docs] def getChannel(self):
mcTuple = self.mcDict[self.currentUniqueID]
return mcTuple[-1]
[docs] def getUIDs(self):
"""
Return a list of all amplifier UIDs
"""
return self.mcDict.keys()
[docs] def cleanup(self):
self.DestroyObject()
[docs] def selectUniqueID(self, uniqueID):
try:
mcTup = self.mcDict[uniqueID]
except KeyError:
print(self.mcDict.keys())
raise KeyError(f"I dont know where you got the UID {uniqueID} but it wasn't from here! Check your config!")
out = self.SelectMultiClamp(*mcTup)
self.currentUniqueID = uniqueID
return out
"""everything below interfaces with the MCC SDK API through ctypes"""
# DLL functions
[docs] def CreateObject(self):
"""run this first to create self.hMCCmsg"""
self.hMCCmsg = self.aDLL.MCCMSG_CreateObject(self._pnError)
return self.hMCCmsg
[docs] def DestroyObject(self):
"""Do this last if you do it"""
return self.aDLL.MCCMSG_DestroyObject(self.hMCCmsg)
# General funcs
[docs] def SetTimeOut(self, u):
uValue = ct.c_uint(u)
self._clearError()
self.aDLL.MCCMSG_SetTimeOut(self.hMCCmsg, uValue, self._pnError)
return self._handleError()
[docs] def FindFirstMultiClamp(self):
"""
Find the first available amplifier and return its parameter
"""
puModel = ct.byref(ct.c_uint(0))
pszSerialNum = ct.byref(ct.c_char_p(b''))
uBufSize = ct.c_uint(16)
puCOMPortID = ct.byref(ct.c_uint(0))
puDeviceID = ct.byref(ct.c_uint(0))
puChannelID = ct.byref(ct.c_uint(0)) # head stage
self._clearError()
if self.aDLL.MCCMSG_FindFirstMultiClamp(self.hMCCmsg, puModel, pszSerialNum,
uBufSize, puCOMPortID, puDeviceID,
puChannelID, self._pnError):
return (val(puModel, c_uint_p), pszSerialNum,
val(puCOMPortID, c_uint_p),
val(puDeviceID, c_uint_p),
val(puChannelID, c_uint_p))
return None
[docs] def FindNextMultiClamp(self):
"""
Find the next available amplifier and return its parameter
"""
puModel = ct.byref(ct.c_uint(0))
pszSerialNum = ct.byref(ct.c_char_p(b''))
uBufSize = ct.c_uint(16)
puCOMPortID = ct.byref(ct.c_uint(0))
puDeviceID = ct.byref(ct.c_uint(0))
puChannelID = ct.byref(ct.c_uint(0)) # head stage
self._clearError()
if self.aDLL.MCCMSG_FindNextMultiClamp(self.hMCCmsg, puModel, pszSerialNum,
uBufSize, puCOMPortID, puDeviceID,
puChannelID, self._pnError):
return (val(puModel, c_uint_p), pszSerialNum,
val(puCOMPortID, c_uint_p),
val(puDeviceID, c_uint_p),
val(puChannelID, c_uint_p))
return None
[docs] def SelectMultiClamp(self, uModel, _pszSerialNum, uCOMPortID, uDeviceID, uChannelID):
self._clearError()
self.aDLL.MCCMSG_SelectMultiClamp(self.hMCCmsg, uModel, _pszSerialNum,
uCOMPortID, uDeviceID, uChannelID, self._pnError)
return self._handleError()
[docs] def CheckAPIVersion(self):
self._clearError()
queryVersion = ct.c_char_p(API_VERSION_STR)
self.aDLL.MCCMSG_CheckAPIVersion(queryVersion, self._pnError)
return self._handleError()
[docs] def BuildErrorText(self):
self._clearError()
errval = val(self._pnError, c_int_p)
txtBufLen = 256
txtBuf = ct.c_char_p(b' ' * txtBufLen)
self.aDLL.MCCMSG_BuildErrorText(self.hMCCmsg, errval, txtBuf, txtBufLen, self._pnError)
return self._handleError(), val(txtBuf, ct.c_char_p).decode('utf-8')
# MCC mode funcs
[docs] def SetMode(self, u):
self._clearError()
uValue = ct.c_uint(u)
self.aDLL.MCCMSG_SetMode(self.hMCCmsg, uValue, self._pnError)
return self._handleError()
[docs] def GetMode(self):
self._clearError()
self.aDLL.MCCMSG_GetMode(self.hMCCmsg, self._puPointer, self._pnError)
return self._extractValue(self._puPointer, c_uint_p)
[docs] def SetModeSwitchEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetModeSwitchEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetModeSwitchEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetModeSwitchEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
# MCC holding funcs
[docs] def SetHoldingEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetHoldingEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetHoldingEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetHoldingEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetHolding(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetHolding(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetHolding(self):
self._clearError()
self.aDLL.MCCMSG_GetHolding(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC seal test and tuning funcs
[docs] def SetTestSignalEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetTestSignalEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetTestSignalEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetTestSignalEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetTestSignalAmplitude(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetTestSignalAmplitude(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetTestSignalAmplitude(self):
self._clearError()
self.aDLL.MCCMSG_GetTestSignalAmplitude(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetTestSignalFrequency(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetTestSignalFrequency(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetTestSignalFrequency(self):
self._clearError()
self.aDLL.MCCMSG_GetTestSignalFrequency(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC pipette offset funcs
[docs] def AutoPipetteOffset(self):
self._clearError()
self.aDLL.MCCMSG_AutoPipetteOffset(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def SetPipetteOffset(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetPipetteOffset(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetPipetteOffset(self):
self._clearError()
self.aDLL.MCCMSG_GetPipetteOffset(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# IC ONLY MCC inject slow current
[docs] def SetSlowCurrentInjEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetSlowCurrentInjEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetSlowCurrentInjEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetSlowCurrentInjEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetSlowCurrentInjLevel(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetSlowCurrentInjLevel(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetSlowCurrentInjLevel(self):
self._clearError()
self.aDLL.MCCMSG_GetSlowCurrentInjLevel(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetSlowCurrentInjSettlingTime(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetSlowCurrentInjSettlingTime(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetSlowCurrentInjSettlingTime(self):
self._clearError()
self.aDLL.MCCMSG_GetSlowCurrentInjSettlingTime(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# VC ONLY MCC compensation funcs
[docs] def SetFastCompCap(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetFastCompCap(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetFastCompCap(self):
self._clearError()
self.aDLL.MCCMSG_GetFastCompCap(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetSlowCompCap(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetSlowCompCap(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetSlowCompCap(self):
self._clearError()
self.aDLL.MCCMSG_GetSlowCompCap(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetFastCompTau(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetFastCompTau(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetFastCompTau(self):
self._clearError()
self.aDLL.MCCMSG_GetFastCompTau(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetSlowCompTau(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetSlowCompTau(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetSlowCompTau(self):
self._clearError()
self.aDLL.MCCMSG_GetSlowCompTau(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetSlowCompTauX20Enable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetSlowCompTauX20Enable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetSlowCompTauX20Enable(self):
self._clearError()
self.aDLL.MCCMSG_GetSlowCompTauX20Enable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def AutoFastComp(self):
self._clearError()
self.aDLL.MCCMSG_AutoFastComp(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def AutoSlowComp(self):
self._clearError()
self.aDLL.MCCMSG_AutoSlowComp(self.hMCCmsg, self._pnError)
return self._handleError()
# IC ONLY MCC pipette capacitance neutralization funcs
[docs] def SetNeutralizationEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetNeutralizationEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetNeutralizationEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetNeutralizationEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetNeutralizationCap(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetNeutralizationCap(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetNeutralizationCap(self):
self._clearError()
self.aDLL.MCCMSG_GetNeutralizationCap(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# VC ONLY MCC whole cell funcs
[docs] def SetWholeCellCompEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetWholeCellCompEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetWholeCellCompEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetWholeCellCompEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetWholeCellCompCap(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetWholeCellCompCap(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetWholeCellCompCap(self):
self._clearError()
self.aDLL.MCCMSG_GetWholeCellCompCap(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetWholeCellCompResist(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetWholeCellCompResist(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetWholeCellCompResist(self):
self._clearError()
self.aDLL.MCCMSG_GetWholeCellCompResist(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def AutoWholeCellComp(self):
self._clearError()
self.aDLL.MCCMSG_AutoWholeCellComp(self.hMCCmsg, self._pnError)
return self._handleError()
# VC ONLY MCC rs compensation funcs
[docs] def SetRsCompEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetRsCompEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetRsCompEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetRsCompEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetRsCompBandwidth(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetRsCompBandwidth(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetRsCompBandwidth(self):
self._clearError()
self.aDLL.MCCMSG_GetRsCompBandwidth(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetRsCompCorrection(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetRsCompCorrection(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetRsCompCorrection(self):
self._clearError()
self.aDLL.MCCMSG_GetRsCompCorrection(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetRsCompPrediction(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetRsCompPrediction(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetRsCompPrediction(self):
self._clearError()
self.aDLL.MCCMSG_GetRsCompPrediction(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC oscillation killer funcs
[docs] def SetOscKillerEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetOscKillerEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetOscKillerEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetOscKillerEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
# MCC primary (or scaled) signal funcs
[docs] def SetPrimarySignal(self, u):
self._clearError()
uValue = ct.c_uint(u)
self.aDLL.MCCMSG_SetPrimarySignal(self.hMCCmsg, uValue, self._pnError)
return self._handleError()
[docs] def GetPrimarySignal(self):
self._clearError()
self.aDLL.MCCMSG_GetPrimarySignal(self.hMCCmsg, self._puPointer, self._pnError)
return self._extractValue(self._puPointer, c_uint_p)
[docs] def SetPrimarySignalGain(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetPrimarySignalGain(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetPrimarySignalGain(self):
self._clearError()
self.aDLL.MCCMSG_GetPrimarySignalGain(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetPrimarySignalLPF(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetPrimarySignalLPF(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetPrimarySignalLPF(self):
self._clearError()
self.aDLL.MCCMSG_GetPrimarySignalLPF(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetPrimarySignalHPF(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetPrimarySignalHPF(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetPrimarySignalHPF(self):
self._clearError()
self.aDLL.MCCMSG_GetPrimarySignalHPF(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC scope signal funcs
[docs] def SetScopeSignalLPF(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetScopeSignalLPF(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetScopeSignalLPF(self):
self._clearError()
self.aDLL.MCCMSG_GetScopeSignalLPF(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC secondary (or raw) signal funcs
[docs] def SetSecondarySignal(self, u):
self._clearError()
uValue = ct.c_uint(u)
self.aDLL.MCCMSG_SetSecondarySignal(self.hMCCmsg, uValue, self._pnError)
return self._handleError()
[docs] def GetSecondarySignal(self):
self._clearError()
self.aDLL.MCCMSG_GetSecondarySignal(self.hMCCmsg, self._puPointer, self._pnError)
return self._extractValue(self._puPointer, c_uint_p)
[docs] def SetSecondarySignalGain(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetSecondarySignalGain(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetSecondarySignalGain(self):
self._clearError()
self.aDLL.MCCMSG_GetSecondarySignalGain(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetSecondarySignalLPF(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetSecondarySignalLPF(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetSecondarySignalLPF(self):
self._clearError()
self.aDLL.MCCMSG_GetSecondarySignalLPF(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC output zero funcs
[docs] def SetOutputZeroEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetOutputZeroEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetOutputZeroEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetOutputZeroEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetOutputZeroAmplitude(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetOutputZeroAmplitude(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetOutputZeroAmplitude(self):
self._clearError()
self.aDLL.MCCMSG_GetOutputZeroAmplitude(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def AutoOutputZero(self):
self._clearError()
self.aDLL.MCCMSG_AutoOutputZero(self.hMCCmsg, self._pnError)
return self._handleError()
# VC ONLY MCC leak subtraction funcs
[docs] def SetLeakSubEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetLeakSubEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetLeakSubEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetLeakSubEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetLeakSubResist(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetLeakSubResist(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetLeakSubResist(self):
self._clearError()
self.aDLL.MCCMSG_GetLeakSubResist(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def AutoLeakSub(self):
self._clearError()
self.aDLL.MCCMSG_AutoLeakSub(self.hMCCmsg, self._pnError)
return self._handleError()
# IC ONLY MCC bridge balance funcs
[docs] def SetBridgeBalEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetBridgeBalEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetBridgeBalEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetBridgeBalEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetBridgeBalResist(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetBridgeBalResist(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetBridgeBalResist(self):
self._clearError()
self.aDLL.MCCMSG_GetBridgeBalResist(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def AutoBridgeBal(self):
self._clearError()
self.aDLL.MCCMSG_AutoBridgeBal(self.hMCCmsg, self._pnError)
return self._handleError()
# IC ONLY MCC clear funcs
[docs] def ClearPlus(self):
self._clearError()
self.aDLL.MCCMSG_ClearPlus(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def ClearMinus(self):
self._clearError()
self.aDLL.MCCMSG_ClearMinus(self.hMCCmsg, self._pnError)
return self._handleError()
# MCC pulse zap buzz!
[docs] def Pulse(self):
self._clearError()
self.aDLL.MCCMSG_Pulse(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def SetPulseAmplitude(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetPulseAmplitude(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetPulseAmplitude(self):
self._clearError()
self.aDLL.MCCMSG_GetPulseAmplitude(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def SetPulseDuration(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetPulseDuration(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetPulseDuration(self):
self._clearError()
self.aDLL.MCCMSG_GetPulseDuration(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def Zap(self):
self._clearError()
self.aDLL.MCCMSG_Zap(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def SetZapDuration(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetZapDuration(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetZapDuration(self):
self._clearError()
self.aDLL.MCCMSG_GetZapDuration(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
[docs] def Buzz(self):
self._clearError()
self.aDLL.MCCMSG_Buzz(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def SetBuzzDuration(self, d):
self._clearError()
dValue = ct.c_double(d)
self.aDLL.MCCMSG_SetBuzzDuration(self.hMCCmsg, dValue, self._pnError)
return self._handleError()
[docs] def GetBuzzDuration(self):
self._clearError()
self.aDLL.MCCMSG_GetBuzzDuration(self.hMCCmsg, self._pdPointer, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC meter funcs
[docs] def SetMeterResistEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetMeterResistEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetMeterResistEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetMeterResistEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def SetMeterIrmsEnable(self, b):
self._clearError()
bValue = ct.c_bool(b)
self.aDLL.MCCMSG_SetMeterIrmsEnable(self.hMCCmsg, bValue, self._pnError)
return self._handleError()
[docs] def GetMeterIrmsEnable(self):
self._clearError()
self.aDLL.MCCMSG_GetMeterIrmsEnable(self.hMCCmsg, self._pbPointer, self._pnError)
return self._extractValue(self._pbPointer, c_bool_p)
[docs] def GetMeterValue(self, u):
self._clearError()
uValue = ct.c_uint(u)
self.aDLL.MCCMSG_GetMeterValue(self.hMCCmsg, self._pdPointer, uValue, self._pnError)
return self._extractValue(self._pdPointer, c_double_p)
# MCC toolbar funcs
[docs] def Reset(self):
self._clearError()
self.aDLL.MCCMSG_Reset(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def ToggleAlwaysOnTop(self):
self._clearError()
self.aDLL.MCCMSG_ToggleAlwaysOnTop(self.hMCCmsg, self._pnError)
return self._handleError()
[docs] def ToggleResize(self):
self._clearError()
self.aDLL.MCCMSG_ToggleResize(self.hMCCmsg, self._pnError)
return self._handleError()
[docs]def parseSettingsFromFile(settingsFile):
with open(settingsFile) as fh:
d = json.load(fh)
scaleFactors = d.pop("ScaleFactors", None)
uids = d
return uids, scaleFactors
[docs]def writeSettingsToFile(settingsFile, filename):
with MultiClampControl() as mcc:
d = DataGatherer()
data = d.getData(mcc)
data["timestamp"] = datetime.datetime.utcnow().isoformat() + "Z"
uids, scaleFactors = parseSettingsFromFile(settingsFile)
print(f"ADC name <-> Amplifier mapping: {uids}")
print(f"Scale factors: {scaleFactors}")
if uids:
for k, v in uids.items():
if not data.get(v):
raise ValueError(f"Amplifier named {v} does not exist.")
data["uids"] = uids
data["ScaleFactors"] = scaleFactors
with open(filename, mode="w", encoding="utf-8") as fh:
fh.write(json.dumps(data, sort_keys=True, indent=4))
print(f"Output written to {filename}")
[docs]class SettingsFetcher(RegexMatchingEventHandler):
def __init__(self, settingsFile):
super().__init__(regexes=[".*\.abf"], ignore_directories=True, case_sensitive=False)
self.settingsFile = settingsFile
[docs] def on_created(self, event):
print(f"Fetching settings for file {event.src_path}.")
base, _ = os.path.splitext(event.src_path)
try:
writeSettingsToFile(self.settingsFile, base + ".json")
except Exception as e:
print(f"Ignoring exception {e}.")
[docs]def main():
parser = argparse.ArgumentParser()
parser.add_argument("--settingsFile", "--idChannelMappingFromFile", type=str,
help="JSON formatted file with the ADC name <-> Amplifier mapping and optional stimset scale factors.",
required=True)
feature_parser = parser.add_mutually_exclusive_group(required=True)
feature_parser.add_argument("--filename", type=str, help="Name of the generated JSON file", default="mcc-output.json")
feature_parser.add_argument("--watchFolder", type=str,
help="Gather settings each time a new ABF file is created in this folder.")
args = parser.parse_args()
if not os.path.isfile(args.settingsFile):
raise ValueError("The parameter settingsFile requires an existing file in JSON format.")
if not args.watchFolder:
writeSettingsToFile(args.settingsFile, args.filename)
return None
if not os.path.isdir(args.watchFolder):
raise ValueError("The parameter watchFolder requires an existing folder.")
eventHandler = SettingsFetcher(args.settingsFile)
observer = Observer()
observer.schedule(eventHandler, args.watchFolder, recursive=False)
observer.start()
print(f"Starting to watch {args.watchFolder} for ABF files to appear. Press Ctrl + Break to stop.")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
if __name__ == '__main__':
main()
"""
primary signal reference
const UINT MCCMSG_PRI_SIGNAL_VC_MEMBCURRENT = 0; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_VC_MEMBPOTENTIAL = 1; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_VC_PIPPOTENTIAL = 2; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_VC_100XACMEMBPOTENTIAL = 3; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_VC_EXTCMDPOTENTIAL = 4; // 700B only
const UINT MCCMSG_PRI_SIGNAL_VC_AUXILIARY1 = 5; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_VC_AUXILIARY2 = 6; // 700B only
const UINT MCCMSG_PRI_SIGNAL_IC_MEMBPOTENTIAL = 7; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_IC_MEMBCURRENT = 8; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_IC_CMDCURRENT = 9; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_IC_100XACMEMBPOTENTIAL = 10; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_IC_EXTCMDCURRENT = 11; // 700B only
const UINT MCCMSG_PRI_SIGNAL_IC_AUXILIARY1 = 12; // 700B and 700A
const UINT MCCMSG_PRI_SIGNAL_IC_AUXILIARY2 = 13; // 700B only
// Parameters for MCCMSG_GetMeterValue()
const UINT MCCMSG_METER1 = 0; // 700B
const UINT MCCMSG_METER2 = 1; // 700B
const UINT MCCMSG_METER3 = 2; // 700B
const UINT MCCMSG_METER4 = 3; // 700B
"""