diff --git a/Packages/MIES/MIES_AmplifierInteraction.ipf b/Packages/MIES/MIES_AmplifierInteraction.ipf index f805f5e3ff..2800e37fa8 100644 --- a/Packages/MIES/MIES_AmplifierInteraction.ipf +++ b/Packages/MIES/MIES_AmplifierInteraction.ipf @@ -445,6 +445,7 @@ static Function AI_UpdateAmpModel(string device, variable headStage, [string ctr AI_UpdateAmpModel(device, i, ctrl = "setvar_DataAcq_RsCorr", value = AmpStorageWave[%$rowLabel][0][i], selectAmp = 0) break case MCC_NO_AUTOBIAS_V_FUNC: // fallthrough + ASSERT(value > -100 && value < 100, "Out of range") case MCC_NO_AUTOBIAS_VRANGE_FUNC: // fallthrough case MCC_NO_AUTOBIAS_IBIASMAX_FUNC: // fallthrough case MCC_NO_AUTOBIAS_ENABLE_FUNC: @@ -1215,7 +1216,7 @@ Function AI_IsControlFromClampMode(string ctrl, variable clampMode) End /// @brief Convert amplifier controls to row labels for `AmpStorageWave` -static Function/S AI_AmpStorageControlToRowLabel(string ctrl) +Function/S AI_AmpStorageControlToRowLabel(string ctrl) strswitch(ctrl) // V-Clamp controls diff --git a/Packages/MIES/MIES_DAEphys.ipf b/Packages/MIES/MIES_DAEphys.ipf index 45dc03cf2d..30d18aace4 100644 --- a/Packages/MIES/MIES_DAEphys.ipf +++ b/Packages/MIES/MIES_DAEphys.ipf @@ -3255,15 +3255,7 @@ Function DAP_CheckProc_ClampMode(STRUCT WMCheckboxAction &cba) : CheckBoxControl device = cba.win control = cba.ctrlName DAP_GetInfoFromControl(device, control, mode, headStage) - - NVAR dataAcqRunMode = $GetDataAcqRunMode(device) - if(dataAcqRunMode == DAQ_NOT_RUNNING) - DAP_ChangeHeadStageMode(device, mode, headstage, DO_MCC_MIES_SYNCING) - else - WAVE GuiState = GetDA_EphysGuiStateNum(device) - GuiState[headstage][%HSmode_delayed] = mode - DAP_SetAmpModeControls(device, headstage, mode, delayed = 1) - endif + DAP_SetClampMode(device, headstage, mode) catch ClearRTError() SetCheckBoxState(device, control, !cba.checked) @@ -5799,3 +5791,20 @@ Function DAP_GetDAScaleMax(string device, variable headstage, string stimsetName return result End + +/// @brief Sets a new clamp mode +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] mode clamp mode @ref AmplifierClampModes +Function DAP_SetClampMode(string device, variable headstage, variable mode) + + NVAR dataAcqRunMode = $GetDataAcqRunMode(device) + if(dataAcqRunMode == DAQ_NOT_RUNNING) + DAP_ChangeHeadStageMode(device, mode, headstage, DO_MCC_MIES_SYNCING) + else + WAVE GuiState = GetDA_EphysGuiStateNum(device) + GuiState[headstage][%HSmode_delayed] = mode + DAP_SetAmpModeControls(device, headstage, mode, delayed = 1) + endif +End diff --git a/Packages/MIES/MIES_ForeignFunctionInterface.ipf b/Packages/MIES/MIES_ForeignFunctionInterface.ipf index dcd3346585..40bfd51d9e 100644 --- a/Packages/MIES/MIES_ForeignFunctionInterface.ipf +++ b/Packages/MIES/MIES_ForeignFunctionInterface.ipf @@ -9,6 +9,14 @@ /// @file MIES_ForeignFunctionInterface.ipf /// @brief __FFI__ ACQ4/ZeroMQ accessible functions +/// @name Auto Clamp Ctrls enum for FFI_TriggerAutoClampControl +/// @anchor FFI_AutoClampCtrls +///@{ +static Constant AUTO_PIPETTE = 1 +static Constant AUTO_CAPACITANCE = 2 +static Constant AUTO_BRIDGEBALANCE = 3 +///@} + /// @brief Function to return Peak Resistance, Steady State Resistance to ACQ4 (Neurophysiology Acquisition and Analysis System. /// See http://acq4.org/ for more details) /// @@ -323,3 +331,257 @@ Function FFI_TestPulseMDSingleResult(string device, variable action) return ret End + +/// @brief Returns the clamp state of a headstage of a locked device +/// +/// - if the requested head stage is not active then a null wave is returned +/// The clamp state wave is DP numeric wave: +/// +/// For VC +/// +/// \rst +/// +------------------------+-----------------------+---------+ +/// | Dimension Label | Value description | Units | +/// +========================+=======================+=========+ +/// | HoldingPotential | | mV | +/// +------------------------+-----------------------+---------+ +/// | RSCompChaining | | On/Off | +/// +------------------------+-----------------------+---------+ +/// | HoldingPotentialEnable | | On/Off | +/// +------------------------+-----------------------+---------+ +/// | WholeCellCap | 1 : On 0 : Off | pF | +/// +------------------------+-----------------------+---------+ +/// | WholeCellRes | | MΩ | +/// +------------------------+-----------------------+---------+ +/// | WholeCellEnable | 1 : On 0 : Off | On/Off | +/// +------------------------+-----------------------+---------+ +/// | Correction | | % | +/// +------------------------+-----------------------+---------+ +/// | Prediction | | % | +/// +------------------------+-----------------------+---------+ +/// | RsCompEnable | | On/Off | +/// +------------------------+-----------------------+---------+ +/// | PipetteOffsetVC | 1 : On 0 : Off | mV | +/// +------------------------+-----------------------+---------+ +/// | WholeCellCap | | a.u. | +/// +------------------------+-----------------------+---------+ +/// | ClampMode | 0 : VC | | +/// +------------------------+-----------------------+---------+ +/// \endrst +/// +/// +/// For IC +/// +/// \rst +/// +----------------------+-----------------------+---------+ +/// | Dimension Label | Value description | Units | +/// +======================+=======================+=========+ +/// | BiasCurrent | | pA | +/// +----------------------+-----------------------+---------+ +/// | BiasCurrentEnable | | On/Off | +/// +----------------------+-----------------------+---------+ +/// | BridgeBalance | | MΩ | +/// +----------------------+-----------------------+---------+ +/// | BridgeBalanceEnable | 1 : On 0 : Off | On/Off | +/// +----------------------+-----------------------+---------+ +/// | CapNeut | | pF | +/// +----------------------+-----------------------+---------+ +/// | CapNeutEnable | 1 : On 0 : Off | On/Off | +/// +----------------------+-----------------------+---------+ +/// | AutoBiasVcom | | mV | +/// +----------------------+-----------------------+---------+ +/// | AutoBiasVcomVariance | | mV | +/// +----------------------+-----------------------+---------+ +/// | AutoBiasIbiasmax | | pA | +/// +----------------------+-----------------------+---------+ +/// | AutoBiasEnable | 1 : On 0 : Off | On/Off | +/// +----------------------+-----------------------+---------+ +/// | PipetteOffsetIC | | mV | +/// +----------------------+-----------------------+---------+ +/// | ClampMode | 1 : IC | | +/// +----------------------+-----------------------+---------+ +/// \endrst +/// +/// +/// For I=0 +/// +/// \rst +/// +----------------------+-----------------------+---------+ +/// | Dimension Label | Value description | Units | +/// +======================+=======================+=========+ +/// | ClampMode | 2 : I=0 | | +/// +----------------------+-----------------------+---------+ +/// \endrst +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @returns wave with clamp state +Function/WAVE FFI_GetClampState(string device, variable headstage) + + variable clampMode, numFuncs, i, j + string lbl + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + if(!DAG_GetHeadstageState(device, headstage)) + return $"" + endif + + WAVE AmpStorageWave = GetAmplifierParamStorageWave(device) + + clampMode = DAG_GetHeadstageMode(device, headstage) + if(clampMode == I_EQUAL_ZERO_MODE) + Make/FREE/D clampState = {I_EQUAL_ZERO_MODE} + SetDimLabel ROWS, j, ClampMode, clampState + return clampState + endif + + WAVE aiFuncs = AI_GetFunctionConstantForClampMode(clampMode) + numFuncs = DimSize(aiFuncs, ROWS) + Make/FREE/T/N=(numFuncs) ctrlNames, ampLabels + + ctrlNames[] = AI_MapFunctionConstantToControl(aiFuncs[p], clampMode) + ampLabels[] = AI_AmpStorageControlToRowLabel(ctrlNames[p]) + + Make/FREE/D/N=(numFuncs + 1) clampState + for(i = 0; i < numFuncs; i += 1) + if(IsEmpty(ampLabels[i])) + continue + endif + clampState[j] = AmpStorageWave[%$ampLabels[i]][0][headStage] + lbl = AI_MapFunctionConstantToName(aiFuncs[i], clampMode) + SetDimLabel ROWS, j, $lbl, clampState + j += 1 + endfor + clampState[j] = clampMode + SetDimLabel ROWS, j, ClampMode, clampState + Redimension/N=(j + 1) clampState + + return clampState +End + +/// @brief Triggers an auto clamp control +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] autoCtrl auto control number @ref FFI_AutoClampCtrls +Function FFI_TriggerAutoClampControl(string device, variable headstage, variable autoCtrl) + + variable clampMode + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + + clampMode = DAG_GetHeadstageMode(device, headstage) + + if(autoCtrl == AUTO_PIPETTE) + AI_WriteToAmplifier(device, headstage, clampMode, MCC_AUTOPIPETTEOFFSET_FUNC, 1, GUIWrite = 1) + elseif(autoCtrl == AUTO_CAPACITANCE) + AI_WriteToAmplifier(device, headstage, V_CLAMP_MODE, MCC_AUTOWHOLECELLCOMP_FUNC, 1, GUIWrite = 1) + elseif(autoCtrl == AUTO_BRIDGEBALANCE) + AI_WriteToAmplifier(device, headstage, I_CLAMP_MODE, MCC_AUTOBRIDGEBALANCE_FUNC, 1, GUIWrite = 1) + else + FATAL_ERROR("Unknown auto clamp control") + endif +End + +/// @brief Sets clamp mode +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] clampMode clamp mode @ref AmplifierClampModes +Function FFI_SetClampMode(string device, variable headstage, variable clampMode) + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + ASSERT(AI_IsValidClampMode(clampMode), "Invalid clamp mode: " + num2istr(clampMode)) + + DAP_SetClampMode(device, headstage, clampMode) +End + +/// @brief Sets Holding Potential +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] potential holding potential in mV when current clamp mode of headstage is VC, bias current in pA when current clamp mode of headstage is IC +Function FFI_SetHoldingPotential(string device, variable headstage, variable potential) + + variable clampMode + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + + clampMode = DAG_GetHeadstageMode(device, headstage) + ASSERT(clampMode == V_CLAMP_MODE, "Attempt to set holding potential but current clamp mode is not VC !") + ASSERT(!IsNaN(potential), "potential argument is NaN") + + FFI_SetHolding(device, headstage, clampMode, potential) +End + +/// @brief Sets Bias Current +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] biasCurrent bias current in pA +Function FFI_SetBiasCurrent(string device, variable headstage, variable biasCurrent) + + variable clampMode + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + + clampMode = DAG_GetHeadstageMode(device, headstage) + ASSERT(clampMode == I_CLAMP_MODE, "Attempt to set holding potential but current clamp mode is not IC !") + ASSERT(!IsNaN(biasCurrent), "bias current argument is NaN") + + FFI_SetHolding(device, headstage, clampMode, biasCurrent) +End + +static Function FFI_SetHolding(string device, variable headstage, variable clampMode, variable value) + + AI_WriteToAmplifier(device, headstage, clampMode, MCC_HOLDING_FUNC, value, GUIWrite = 1) +End + +static Function FFI_CheckValidDeviceAndHeadstage(string device, variable headstage) + + ASSERT(!DAP_DeviceIsUnlocked(device), "Target device is not locked:" + device) + ASSERT(IsValidHeadstage(headstage), "Invalid headStage index: " + num2str(headstage)) +End + +/// @brief Sets Auto Bias +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] potential Vm in mV in the range -99 mV to 99 mV +/// @param[in] enable when set to 1 then auto bias gets enabled, 0 disabled +Function FFI_SetAutoBias(string device, variable headstage, variable potential, variable enable) + + variable clampMode + + enable = !!enable + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + + clampMode = DAG_GetHeadstageMode(device, headstage) + ASSERT(clampMode == I_CLAMP_MODE, "Attempt to set auto bias but current clamp mode is not IC !") + + AI_WriteToAmplifier(device, headstage, clampMode, MCC_NO_AUTOBIAS_V_FUNC, potential, GUIWrite = 1) + AI_WriteToAmplifier(device, headstage, clampMode, MCC_NO_AUTOBIAS_ENABLE_FUNC, enable, GUIWrite = 1) +End + +/// @brief Enables/Disables a headstage +/// +/// The headstage state can not be changed while a data acquisition is running +/// +/// @param[in] device Device title, e.g. "Dev1" +/// @param[in] headstage headstage number +/// @param[in] enable when set to 1 the headstage gets enabled, 0 disabled +/// @returns 0 when successful +Function FFI_SetHeadstageActive(string device, variable headstage, variable enable) + + string ctrlName + + enable = !!enable + + FFI_CheckValidDeviceAndHeadstage(device, headstage) + + ctrlName = GetPanelControl(headstage, CHANNEL_TYPE_HEADSTAGE, CHANNEL_CONTROL_CHECK) + PGC_SetAndActivateControl(device, ctrlName, val = enable) + + return 0 +End