diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index fac0e4dbc4..db59f76973 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -15,7 +15,7 @@ /// @anchor VersioningConstants /// @{ -Constant DAQ_CONFIG_WAVE_VERSION = 2 +Constant DAQ_CONFIG_WAVE_VERSION = 3 /// Used to upgrade the GuiStateWave as well as the DA Ephys panel Constant DA_EPHYS_PANEL_VERSION = 64 @@ -85,6 +85,12 @@ StrConstant ITC_DEVICE_REGEXP = "^ITC.*" StrConstant DEVICE_TYPES_ITC = "ITC16;ITC18;ITC1600;ITC00;ITC16USB;ITC18USB" StrConstant DEVICE_NUMBERS = "0;1;2;3;4;5;6;7;8;9;10" +StrConstant DEVICE_NAME_NICE_SUTTER = "Sutter Instrument Integrated Patch Amplifier" +StrConstant DEVICE_SUTTER_NAME_START_CLEAN = "IPA_E_" +Constant SUTTER_AI_PER_AMP = 4 +Constant SUTTER_AO_PER_AMP = 2 +Constant SUTTER_DIO_PER_AMP = 8 + StrConstant BASE_WINDOW_NAME = "DA_Ephys" StrConstant DATABROWSER_WINDOW_NAME = "DataBrowser" StrConstant SWEEPBROWSER_WINDOW_NAME = "SweepBrowser" @@ -172,6 +178,7 @@ Constant MAXIMUM_WAVE_SIZE = 16384 // 2^14 /// Convenience definition to nicify expressions like DimSize(wv, ROWS) /// easier to read than DimSize(wv, 0). /// @{ +Constant DATADIMENSION = -1 Constant ROWS = 0 Constant COLS = 1 Constant LAYERS = 2 @@ -776,13 +783,14 @@ Constant HARDWARE_PREVENT_ERROR_MESSAGE = 0x04 /// @} /// List of different DAC hardware types -StrConstant HARDWARE_DAC_TYPES = "ITC;NI" +StrConstant HARDWARE_DAC_TYPES = "ITC;NI;SUTTER;" /// @name Indizes into HARDWARE_DAC_TYPES /// @anchor HardwareDACTypeConstants /// @{ Constant HARDWARE_ITC_DAC = 0 Constant HARDWARE_NI_DAC = 1 +Constant HARDWARE_SUTTER_DAC = 2 Constant HARDWARE_UNSUPPORTED_DAC = 1000 /// @} @@ -806,6 +814,8 @@ Constant HARDWARE_NI_DAC_MIN_SAMPINT = 0.002 ///< NI 6343 and other devices, so #endif Constant HARDWARE_ITC_MIN_SAMPINT = 0.005 ///< ITC DACs Constant HARDWARE_NI_6001_MIN_SAMPINT = 0.2 ///< NI 6001 USB +Constant HARDWARE_SU_MIN_SAMPINT_DAC = 0.1 /// Sutter output -> 10 kHz +Constant HARDWARE_SU_MIN_SAMPINT_ADC = 0.02 /// Sutter input -> 50 kHz /// @} Constant WAVEBUILDER_MIN_SAMPINT = 0.005 ///< [ms] @@ -1013,6 +1023,22 @@ Constant NI_ADC_MIN = -10 Constant NI_ADC_MAX = 10 /// @} +/// @name Ranges for Sutter DAQ analog output in volts +/// +/// @anchor SUDAQ_WaveRanges +/// @{ +Constant SU_HS_IN_V_MIN = -1 // V +Constant SU_HS_IN_V_MAX = 1 // V +Constant SU_HS_IN_I_MIN = -20E-9 // A +Constant SU_HS_IN_I_MAX = 20E-9 // A +Constant SU_DAC_MIN = -10 // V +Constant SU_DAC_MAX = 10 // V +Constant SU_ADC_MIN = -10 // V +Constant SU_ADC_MAX = 10 // V +Constant SU_HS_OUT_MIN = -1 // V +Constant SU_HS_OUT_MAX = 1 // V +/// @} + /// Maximum length of a valid object name in bytes in Igor Pro >= 8 Constant MAX_OBJECT_NAME_LENGTH_IN_BYTES = 255 @@ -2197,3 +2223,6 @@ Constant PSX_HORIZ_OFFSET_PEAK = 1 Constant PSX_DECONV_FILTER_DEF_LOW = 0.002 Constant PSX_DECONV_FILTER_DEF_HIGH = 0.004 Constant PSX_DECONV_FILTER_DEF_ORDER = 101 + +// @todo test with low pulse number, e.g. 100 and non-integer ratio of DAC/ADC sampling rate +Constant SUTTER_MAX_MAX_TP_PULSES = 10000 diff --git a/Packages/MIES/MIES_DAC-Hardware.ipf b/Packages/MIES/MIES_DAC-Hardware.ipf index 5da5351ef8..7dc4e58a6c 100644 --- a/Packages/MIES/MIES_DAC-Hardware.ipf +++ b/Packages/MIES/MIES_DAC-Hardware.ipf @@ -24,6 +24,10 @@ #define NIDAQMX_XOP_PRESENT #endif +#if exists("SutterDAQScanWave") +#define SUTTER_XOP_PRESENT +#endif + /// @name Error codes for the ITC XOP2 /// @anchor ITCXOP2Errors /// @{ @@ -90,6 +94,8 @@ static Constant HW_ITC_RUNNING_STATE = 0x10 static Constant HW_ITC_MAX_TIMEOUT = 10 static Constant HW_ITC_DSP_TIMEOUT = 0x80303001 +static Constant SUTTER_CHANNELOFFSET_TTL = 3 + /// @name Wrapper functions redirecting to the correct internal implementations depending on #HARDWARE_DAC_TYPES /// @{ @@ -117,6 +123,8 @@ Function HW_PrepareAcq(hardwareType, deviceID, mode, [data, dataFunc, config, co case HARDWARE_NI_DAC: return HW_NI_PrepareAcq(deviceID, mode, flags=flags) break + case HARDWARE_SUTTER_DAC: + return HW_SU_PrepareAcq(deviceID, mode, flags=flags) endswitch return 0 End @@ -138,10 +146,10 @@ Function HW_SelectDevice(hardwareType, deviceID, [flags]) case HARDWARE_ITC_DAC: return HW_ITC_SelectDevice(deviceID, flags=flags) break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: // nothing to do return 0 - break endswitch End @@ -165,6 +173,10 @@ Function HW_OpenDevice(deviceToOpen, hardwareType, [flags]) deviceID = WhichListItem(deviceToOpen, HW_NI_ListDevices()) HW_NI_OpenDevice(deviceToOpen, flags = flags) break + case HARDWARE_SUTTER_DAC: + HW_SU_OpenDevice(flags=flags) + deviceID = 0 + break case HARDWARE_ITC_DAC: ParseDeviceString(deviceToOpen, deviceType, deviceNumber) deviceTypeIndex = WhichListItem(deviceType, DEVICE_TYPES_ITC) @@ -200,6 +212,9 @@ Function HW_CloseDevice(hardwareType, deviceID, [flags]) case HARDWARE_NI_DAC: HW_NI_CloseDevice(deviceID, flags=flags) break + case HARDWARE_SUTTER_DAC: + HW_SU_CloseDevice(deviceID, flags=flags) + break endswitch End @@ -226,6 +241,8 @@ Function HW_WriteDAC(hardwareType, deviceID, channel, value, [flags]) HW_NI_AssertOnInvalid(realDeviceOrPressure) HW_NI_WriteAnalogSingleAndSlow(realDeviceOrPressure, channel, value, flags=flags) break + case HARDWARE_SUTTER_DAC: + ASSERT(0, "Not yet implemented") endswitch End @@ -253,6 +270,8 @@ Function HW_ReadADC(hardwareType, deviceID, channel, [flags]) HW_NI_AssertOnInvalid(realDeviceOrPressure) return HW_NI_ReadAnalogSingleAndSlow(realDeviceOrPressure, channel, flags=flags) break + case HARDWARE_SUTTER_DAC: + ASSERT(0, "Not yet implemented") endswitch End @@ -293,6 +312,8 @@ Function HW_ReadDigital(hardwareType, deviceID, channel, [line, flags]) return HW_NI_ReadDigital(realDeviceOrPressure, DIOPort=channel, DIOline=line, flags=flags) endif break + case HARDWARE_SUTTER_DAC: + ASSERT(0, "Not yet implemented") endswitch End @@ -332,6 +353,8 @@ Function HW_WriteDigital(hardwareType, deviceID, channel, value, [line, flags]) HW_NI_WriteDigital(realDeviceOrPressure, value, DIOPort=channel, DIOline=line, flags=flags) endif break + case HARDWARE_SUTTER_DAC: + ASSERT(0, "Not yet implemented") endswitch End @@ -349,7 +372,8 @@ Function HW_EnableYoking(hardwareType, deviceID, [flags]) case HARDWARE_ITC_DAC: HW_ITC_EnableYoking(deviceID, flags=flags) break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: ASSERT(0, "Not implemented") break endswitch @@ -369,7 +393,8 @@ Function HW_DisableYoking(hardwareType, deviceID, [flags]) case HARDWARE_ITC_DAC: HW_ITC_DisableYoking(deviceID, flags=flags) break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: ASSERT(0, "Not implemented") break endswitch @@ -395,6 +420,9 @@ Function HW_StopAcq(hardwareType, deviceID, [prepareForDAQ, zeroDAC, flags]) case HARDWARE_NI_DAC: HW_NI_StopAcq(deviceID, zeroDAC = zeroDAC, flags=flags) break + case HARDWARE_SUTTER_DAC: + HW_SU_StopAcq(deviceID, zeroDAC = zeroDAC, flags=flags) + break endswitch End @@ -408,18 +436,19 @@ End Function HW_IsRunning(hardwareType, deviceID, [flags]) variable hardwareType, deviceID, flags - string realDeviceOrPressure + string realDeviceOrPressure, device HW_AssertOnInvalid(hardwareType, deviceID) switch(hardwareType) case HARDWARE_ITC_DAC: return HW_ITC_IsRunning(deviceID, flags=flags) - break case HARDWARE_NI_DAC: realDeviceOrPressure = HW_GetDeviceName(hardwareType, deviceID, flags = flags) HW_NI_AssertOnInvalid(realDeviceOrPressure) return HW_NI_IsRunning(realDeviceOrPressure) - break + case HARDWARE_SUTTER_DAC: + device = HW_GetMainDeviceName(HARDWARE_SUTTER_DAC, deviceID, flags = flags) + return HW_SU_IsRunning(device) endswitch End @@ -445,6 +474,9 @@ Function/WAVE HW_GetDeviceInfo(hardwareType, deviceID, [flags]) HW_NI_AssertOnInvalid(realDeviceOrPressure) return HW_NI_GetDeviceInfo(realDeviceOrPressure, flags=flags) break + case HARDWARE_SUTTER_DAC: + return HW_SU_GetDeviceInfo(flags = flags) + break endswitch End @@ -478,6 +510,9 @@ Function/WAVE HW_GetDeviceInfoUnregistered(variable hardwareType, string device, WAVE/Z devInfo = HW_NI_GetDeviceInfo(device, flags = flags) // nothing to do for NI break + case HARDWARE_SUTTER_DAC: + WAVE/Z devInfo = HW_SU_GetDeviceInfo(flags = flags) + break default: ASSERT(0, "Unsupported hardware") endswitch @@ -512,6 +547,12 @@ Function HW_WriteDeviceInfo(variable hardwareType, string device, WAVE deviceInf endif #endif +#ifndef SUTTER_XOP_PRESENT + if(hardwareType == HARDWARE_SUTTER_DAC) + return NaN + endif +#endif + deviceID = ROVar(GetDAQDeviceID(device)) if(HW_IsValidDeviceID(deviceID) && !HW_SelectDevice(hardwareType, deviceID, flags = HARDWARE_PREVENT_ERROR_MESSAGE)) @@ -540,6 +581,13 @@ Function HW_WriteDeviceInfo(variable hardwareType, string device, WAVE deviceInf deviceInfo[%TTL] = str2num(devInfoHWText[%DIOPortWidth]) deviceInfo[%Rack] = NaN break + case HARDWARE_SUTTER_DAC: + WAVE/T devInfoHWText = devInfoHW + deviceInfo[%AD] = str2num(devInfoHWText[%AI]) + str2num(devInfoHWText[%SUMHEADSTAGES]) + deviceInfo[%DA] = str2num(devInfoHWText[%AO]) + str2num(devInfoHWText[%SUMHEADSTAGES]) + deviceInfo[%TTL] = str2num(devInfoHWText[%DIOPortWidth]) + deviceInfo[%Rack] = NaN + break endswitch End @@ -566,6 +614,11 @@ Function HW_StartAcq(hardwareType, deviceID, [triggerMode, flags, repeat]) case HARDWARE_NI_DAC: HW_NI_StartAcq(deviceID, triggerMode, flags=flags, repeat=repeat) break + case HARDWARE_SUTTER_DAC: + HW_SU_StartAcq(deviceID, flags=flags) + break + default: + ASSERT(0, "Unknown hardware type") endswitch End @@ -588,6 +641,11 @@ Function HW_ResetDevice(hardwareType, deviceID, [flags]) HW_NI_AssertOnInvalid(realDeviceOrPressure) HW_NI_ResetDevice(realDeviceOrPressure, flags=flags) break + case HARDWARE_SUTTER_DAC: + HW_SU_ResetDevice(flags=flags) + break + default: + ASSERT(0, "Unknown hardware type") endswitch End @@ -609,7 +667,7 @@ static Function HW_IsValidHardwareType(hardwareType) variable hardwareType #ifndef EVIL_KITTEN_EATING_MODE - return hardwareType == HARDWARE_NI_DAC || hardwareType == HARDWARE_ITC_DAC + return hardwareType == HARDWARE_NI_DAC || hardwareType == HARDWARE_ITC_DAC || hardwareType == HARDWARE_SUTTER_DAC #else return 1 #endif @@ -737,6 +795,19 @@ Function/S HW_GetDeviceName(hardwareType, deviceID, [flags]) return mainDevice End + +Function HW_GetEffectiveADCWaveLength(string device, variable dataAcqOrTP) + + if(GetHardwareType(device) == HARDWARE_ITC_DAC) + return ROVar(GetStopCollectionPoint(device)) + endif + + WAVE/WAVE dataWave = GetDAQDataWave(device, dataAcqOrTP) + WAVE config = GetDAQConfigWave(device) + + return DimSize(dataWave[GetFirstADCChannelIndex(config)], ROWS) +End + /// @} /// @name ITC @@ -803,6 +874,8 @@ Function/S HW_ITC_ListDevices() #ifndef EVIL_KITTEN_EATING_MODE #if defined(TESTS_WITH_NI_HARDWARE) return "" +#elif defined(TESTS_WITH_SUTTER_HARDWARE) + return "" #elif defined(TESTS_WITH_ITC18USB_HARDWARE) return HW_ITC_BuildDeviceString("ITC18USB", "0") #elif defined(TESTS_WITH_ITC1600_HARDWARE) @@ -2672,6 +2745,8 @@ Function/S HW_NI_ListDevices([flags]) return "" #elif defined(TESTS_WITH_ITC1600_HARDWARE) return "" +#elif defined(TESTS_WITH_SUTTER_HARDWARE) + return "" #endif #endif @@ -3157,4 +3232,413 @@ End #endif // NIDAQMX_XOP_PRESENT +#ifdef SUTTER_XOP_PRESENT + +/// @brief Return a the serial string of the SUTTER master device if present +/// +/// @param flags [optional, default none] One or multiple flags from @ref HardwareInteractionFlags +Function/S HW_SU_ListDevices([variable flags]) + + DEBUGPRINTSTACKINFO() + +#ifndef EVIL_KITTEN_EATING_MODE +#if defined(TESTS_WITH_ITC18USB_HARDWARE) + return "" +#elif defined(TESTS_WITH_ITC1600_HARDWARE) + return "" +#elif defined(TESTS_WITH_NI_HARDWARE) + return "" +#endif +#endif + + HW_SU_ResetDevice(flags=flags) + WAVE/T deviceInfo = GetSUDeviceInfo() + + return deviceInfo[%MASTERDEVICE] +End + +Function HW_SU_CloseDevice(variable deviceID, [variable flags]) + + string device + + DEBUGPRINTSTACKINFO() + + device = HW_GetMainDeviceName(HARDWARE_SUTTER_DAC, deviceID, flags = flags) + if(HW_SU_IsRunning(device)) + HW_SU_StopAcq(deviceID, flags=flags) + endif + + SutterDAQUSBClose() + WAVE/T deviceInfo = GetSUDeviceInfo() + deviceInfo = "" +End + +static Function HW_SU_IsRunning(string device) + + return ROVar(GetSU_IsAcquisitionRunning(device)) +End + +/// @brief Reset device +/// +/// @param flags [optional, default none] One or multiple flags from @ref HardwareInteractionFlags +static Function HW_SU_ResetDevice([variable flags]) + + variable numIPAs, i, numHeadstages, numDevices + string serial + string deviceList = "" + string numHSList = "" + + DEBUGPRINTSTACKINFO() + + WAVE/T deviceInfo = GetSUDeviceInfo() + deviceInfo = "" + + numIPAs = SutterDAQusbreset() + deviceInfo[%NUMBEROFDACS] = num2istr(numIPAs) + for(i = 0; i < numIPAs; i += 1) + serial = CleanupName(SutterDAQSN(i), 0) + ASSERT(strlen(serial) > 6, "Error parsing IPA serial: " + serial) + deviceList = AddListItem(serial, deviceList, ";", Inf) + strswitch(serial[6]) + case "1": + numHeadstages += 1 + numHSList = AddListItem("1", numHSList, ";", Inf) + break + case "2": + numHeadstages += 2 + numHSList = AddListItem("2", numHSList, ";", Inf) + break + default: + ASSERT(0, "Error parsing IPA serial: " + serial) + endswitch + endfor + numDevices = ItemsInList(deviceList) + // @TODO Check for SU MultiDevices if Master is subdev 0 + deviceInfo[%MASTERDEVICE] = StringFromList(0, deviceList) + deviceInfo[%LISTOFDEVICES] = deviceList + deviceInfo[%LISTOFHEADSTAGES] = numHSList + deviceInfo[%SUMHEADSTAGES] = num2istr(numHeadstages) + deviceInfo[%AI] = num2istr(SUTTER_AI_PER_AMP * numDevices) + deviceInfo[%AO] = num2istr(SUTTER_AO_PER_AMP * numDevices) + deviceInfo[%DIOPortWidth] = num2istr(SUTTER_DIO_PER_AMP) + + SutterDAQReset() +End + +/// @brief Opens a Sutter device, executes reset + +/// @param flags [optional, default none] One or multiple flags from @ref HardwareInteractionFlags +Function HW_SU_OpenDevice([variable flags]) + + DEBUGPRINTSTACKINFO() + + HW_SU_ResetDevice(flags=flags) +End + +/// @see HW_GetDeviceInfo +Function/WAVE HW_SU_GetDeviceInfo([variable flags]) + + DEBUGPRINTSTACKINFO() + + return GetSUDeviceInfo() +End + +/// @brief Stop scanning and waveform generation +/// +/// @param[in] zeroDAC [optional, defaults to false] set all DA channels to zero +/// @param[in] flags [optional, default none] One or multiple flags from @ref HardwareInteractionFlags +/// +/// @see HW_StopAcq +Function HW_SU_StopAcq(variable deviceID, [variable zeroDAC, variable flags]) + + string device + + SutterDAQReset() + + if(zeroDAC) + DEBUGPRINTSTACKINFO() +// @TODO zero the DAC maybe through RHP ? +// HW_SU_ZeroDAC(flags=flags) + endif + + device = HW_GetMainDeviceName(HARDWARE_SUTTER_DAC, deviceID, flags = flags) + NVAR acq = $GetSU_IsAcquisitionRunning(device) + acq = 0 +End + +/// @brief Prepare for data acquisition +/// +/// @param mode one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE +/// @param data ITC data wave +/// @param dataFunc [optional, defaults to GetDAQDataWave()] override wave getter for the ITC data wave +/// @param config ITC config wave +/// @param configFunc [optional, defaults to GetDAQConfigWave()] override wave getter for the ITC config wave +/// @param offset [optional, defaults to zero] offset into the data wave in points +/// @param flags [optional, default none] One or multiple flags from @ref HardwareInteractionFlags +Function HW_SU_PrepareAcq(variable deviceId, variable mode, [WAVE/Z data, FUNCREF HW_WAVE_GETTER_PROTOTYPE dataFunc, WAVE/Z config, FUNCREF HW_WAVE_GETTER_PROTOTYPE configFunc, variable flags, variable offset]) + + string device, encodeInfo + variable channels, i, haveTTL, unassocADCIndex, unassocDACIndex + variable headStage, channelNumber, amp0Type + variable outIndex, inIndex, outChannel, inChannel + + DEBUGPRINTSTACKINFO() + + device = HW_GetMainDeviceName(HARDWARE_SUTTER_DAC, deviceID, flags = flags) + if(ParamIsDefault(data)) + if(ParamIsDefault(dataFunc)) + WAVE/WAVE SUDataWave = GetDAQDataWave(device, mode) + else + WAVE/WAVE SUDataWave = dataFunc(device) + endif + endif + + if(ParamIsDefault(config)) + if(ParamIsDefault(configFunc)) + WAVE config = GetDAQConfigWave(device) + else + WAVE config = configFunc(device) + endif + endif + + if(!ParamIsDefault(offset)) + ASSERT(0, "Offset is not supported") + endif + + WAVE gain = SWS_GetChannelGains(device, timing = GAIN_BEFORE_DAQ) + WAVE hwGainTable = GetSUDeviceInputGains(device) + + WAVE/T output = GetSUDeviceOutput(device) + WAVE/T input = GetSUDeviceInput(device) + + channels = DimSize(config, ROWS) + for(i = 0;i < channels; i += 1) + WAVE SUChannel = SUDataWave[i] + + ASSERT(!IsFreeWave(SUChannel), "Can not work with free waves") + + channelNumber = config[i][%ChannelNumber] + headstage = config[i][%HEADSTAGE] + switch(config[i][%ChannelType]) + case XOP_CHANNEL_TYPE_ADC: + EnsureLargeEnoughWave(input, indexShouldExist=inIndex) + EnsureLargeEnoughWave(hwGainTable, indexShouldExist=inIndex) + hwGainTable[inIndex][%GAINFACTOR] = gain[i] + hwGainTable[inIndex][%OFFSET] = 0 + input[inIndex][%INPUTWAVE] = GetWavesDataFolder(SUChannel, 2) + if(IsNaN(headStage)) + // unassoc ADC + [inChannel, encodeInfo] = HW_SU_GetEncodeFromUnassocADC(unassocADCIndex) + unassocADCIndex += 1 + else + [inChannel, encodeInfo] = HW_SU_GetEncodeFromHS(headstage) + inChannel *= 2 + if(config[i][%CLAMPMODE] == I_CLAMP_MODE) + inChannel += 1 + endif + endif + input[inIndex][%CHANNEL] = num2istr(inChannel) + input[inIndex][%ENCODEINFO] = encodeInfo + inIndex += 1 + break + case XOP_CHANNEL_TYPE_DAC: + EnsureLargeEnoughWave(output, indexShouldExist=outIndex) + output[outIndex][%OUTPUTWAVE] = GetWavesDataFolder(SUChannel, 2) + if(IsNaN(headStage)) + // unassoc DAC + [outChannel, encodeInfo] = HW_SU_GetEncodeFromUnassocDAC(unassocDACIndex) + unassocDACIndex += 1 + else + [outChannel, encodeInfo] = HW_SU_GetEncodeFromHS(headstage) + endif + output[outIndex][%CHANNEL] = num2istr(outChannel) + output[outIndex][%ENCODEINFO] = encodeInfo + outIndex += 1 + break + case XOP_CHANNEL_TYPE_TTL: + if(!haveTTL) + haveTTL = 1 + WAVE ttlComposite = GetSUCompositeTTLWave(device) + FastOp ttlComposite = 0 + Redimension/N=(DimSize(SUChannel, ROWS)) ttlComposite + endif + MultiThread ttlComposite[] += SUChannel[p] * (1 << channelNumber) + break + endswitch + endfor + + if(haveTTL) + WAVE/T deviceInfo = HW_SU_GetDeviceInfo() + amp0Type = str2num(StringFromList(0, deviceInfo[%LISTOFHEADSTAGES])) + sprintf encodeInfo, "00%02d-1", amp0Type + + EnsureLargeEnoughWave(output, indexShouldExist=outIndex) + output[outIndex][%OUTPUTWAVE] = GetWavesDataFolder(ttlComposite, 2) + output[outIndex][%CHANNEL] = num2istr(amp0Type - 1 + SUTTER_CHANNELOFFSET_TTL) + output[outIndex][%ENCODEINFO] = encodeInfo + outIndex += 1 + endif + Redimension/N=(outIndex, -1) output + Redimension/N=(inIndex, -1) input + Redimension/N=(inIndex, -1) hwGainTable +End + +static Function [variable channel, string encode] HW_SU_GetEncodeFromHS(variable headstage) + + variable i, index, subHS, numAmps, ampType + variable amp = NaN + + WAVE/T deviceInfo = HW_SU_GetDeviceInfo() + WAVE hsNums = ListToNumericWave(deviceInfo[%LISTOFHEADSTAGES], ";") + + for(hsInAmp : hsNums) + i += hsInAmp + if(i > headstage) + amp = index + ampType = hsInAmp + subHS = index ? headstage - sum(hsNums, 0, index - 1) : headstage + break + endif + index += 1 + endfor + + ASSERT(!IsNaN(amp), "Headstage " + num2istr(headstage) + " beyond available headstages on connected IPAs") + sprintf encode, "%02d%02d%02d", amp, ampType, subHS + + return [subHS, encode] +End + +static Function [variable hwChannel, string encode] HW_SU_GetEncodeFromUnassocADC(variable channelNumber) + + variable amp, ampType, hwChannelOffset + + WAVE/T deviceInfo = HW_SU_GetDeviceInfo() + WAVE hsNums = ListToNumericWave(deviceInfo[%LISTOFHEADSTAGES], ";") + amp = trunc(channelNumber / SUTTER_AI_PER_AMP) + ampType = hsNums[amp] + // Each headstage adds two channel in the front + hwChannelOffset = 2 * ampType + hwChannel = channelNumber - amp * SUTTER_AI_PER_AMP + hwChannelOffset + + ASSERT(amp < DimSize(hsNums, ROWS), "Analog In " + num2istr(channelNumber) + " beyond available Analog Ins on connected IPAs") + sprintf encode, "%02d%02d%02d", amp, ampType, -1 + + return [hwChannel, encode] +End + +static Function [variable hwChannel, string encode] HW_SU_GetEncodeFromUnassocDAC(variable channelNumber) + + variable amp, ampType + + WAVE/T deviceInfo = HW_SU_GetDeviceInfo() + WAVE hsNums = ListToNumericWave(deviceInfo[%LISTOFHEADSTAGES], ";") + amp = trunc(channelNumber / SUTTER_AO_PER_AMP) + ampType = hsNums[amp] + hwChannel = channelNumber - amp * SUTTER_AO_PER_AMP + ampType + + ASSERT(amp < DimSize(hsNums, ROWS), "Analog Out " + num2istr(channelNumber) + " beyond available Analog Outs on connected IPAs") + sprintf encode, "%02d%02d%02d", amp, ampType, -1 + + return [hwChannel, encode] +End + +Function HW_SU_StartAcq(variable deviceId, [variable flags]) + + string device, cmdError, cmdDone + + DEBUGPRINTSTACKINFO() + + device = HW_GetMainDeviceName(HARDWARE_SUTTER_DAC, deviceID, flags = flags) + WAVE/T output = GetSUDeviceOutput(device) + WAVE/T input = GetSUDeviceInput(device) + WAVE hwGainTable = GetSUDeviceInputGains(device) + sprintf cmdDone, "HW_SU_AcqDone(\"%s\")", device + sprintf cmdError, "HW_SU_AcqError(\"%s\")", device + + NVAR err = $GetSU_AcquisitionError(device) + NVAR acq = $GetSU_IsAcquisitionRunning(device) + err = 0 + acq = 1 + SutterDAQUSBReset() + SutterDAQWriteWave/MULT=1/T=1/R=0/RHP=0 output + SutterDAQScanWave/MULT=1/T=1/C=0/B=1/G=hwGainTable/E=cmdError/H=cmdDone input + SutterDAQClock(0, 0, 1) +End + +Function HW_SU_AcqDone(string device) + + NVAR acq = $GetSU_IsAcquisitionRunning(device) + acq = 0 +End + +Function HW_SU_AcqError(string device) + + NVAR err = $GetSU_AcquisitionError(device) + NVAR acq = $GetSU_IsAcquisitionRunning(device) + err = 1 + acq = 0 +End + +Function HW_SU_GetADCSamplePosition() + + variable pos + + SutterDAQReadAvailable(pos) + + return pos +End + +#else + +Function HW_SU_OpenDevice([variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +Function/S HW_SU_ListDevices([variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +Function HW_SU_CloseDevice(variable deviceId, [variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +static Function HW_SU_ResetDevice([variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +Function/WAVE HW_SU_GetDeviceInfo([variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +static Function HW_SU_IsRunning(string device) + + DoAbortNow("SUTTER XOP is not available") +End + +Function HW_SU_StopAcq(variable deviceId, [variable zeroDAC, variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +Function HW_SU_PrepareAcq(variable deviceId, variable mode, [WAVE/Z data, FUNCREF HW_WAVE_GETTER_PROTOTYPE dataFunc, WAVE/Z config, FUNCREF HW_WAVE_GETTER_PROTOTYPE configFunc, variable flags, variable offset]) + + DoAbortNow("SUTTER XOP is not available") +End + +Function HW_SU_StartAcq(variable deviceId, [variable flags]) + + DoAbortNow("SUTTER XOP is not available") +End + +Function HW_SU_GetADCSamplePosition() + + DoAbortNow("SUTTER XOP is not available") +End +#endif // SUTTER_XOP_PRESENT + /// @} diff --git a/Packages/MIES/MIES_DAEphys.ipf b/Packages/MIES/MIES_DAEphys.ipf index ae48f59207..916b749425 100644 --- a/Packages/MIES/MIES_DAEphys.ipf +++ b/Packages/MIES/MIES_DAEphys.ipf @@ -114,6 +114,29 @@ Function/S DAP_GetITCDeviceList() return globalITCDevList End +/// @brief Returns a list of SU devices for DAC, #NONE if there are none +Function/S DAP_GetSUDeviceList() + + string devList + + SVAR globalSUDevList = $GetSUDeviceList() + devList = globalSUDevList + + if(!isEmpty(devList)) + return devList + endif + + devList = HW_SU_ListDevices() + + if(!IsEmpty(devList)) + globalSUDevList = devList + else + globalSUDevList = NONE + endif + + return globalSUDevList +End + /// @brief Returns a list of available ITC and NI devices /// /// @return list of DAC devices @@ -134,6 +157,12 @@ Function/S DAP_GetDACDeviceList() list = AddListItem(devices, list, ";", inf) endif + devices = DAP_GetSUDeviceList() + + if(CmpStr(devices, NONE)) + list = AddListItem(devices, list, ";", inf) + endif + if(!cmpstr(list, NONE)) DAP_SuggestIssueForAdditionalNIHardware() endif @@ -1899,6 +1928,59 @@ static Function DAP_HasAscendingSweepOrdering(string device) return 0 End +static Function DAP_CheckSampleInterval(string device, variable mode) + + variable sampIntADC, sampIntDAC, sampIntTTL, validSampInt + variable hardwareType + + sampIntDAC = DAP_GetSampInt(device, mode, XOP_CHANNEL_TYPE_DAC, valid=validSampInt) + if(!validSampInt) + printf "%s: The selected sampling interval is not possible with your DAC hardware.\r", device + ControlWindowToFront() + return 1 + endif + + sampIntADC = DAP_GetSampInt(device, mode, XOP_CHANNEL_TYPE_ADC, valid=validSampInt) + if(!validSampInt) + printf "%s: The selected sampling interval is not possible with your ADC hardware.\r", device + ControlWindowToFront() + return 1 + endif + + sampIntTTL = DAP_GetSampInt(device, mode, XOP_CHANNEL_TYPE_TTL, valid=validSampInt) + if(!validSampInt) + printf "%s: The selected sampling interval is not possible with your TTL hardware.\r", device + ControlWindowToFront() + return 1 + endif + + hardwareType = GetHardwareType(device) + if(hardwareType == HARDWARE_SUTTER_DAC) + WAVE allowedIntervals = GetSutterDACTTLSampleInterval() + FindValue/Z/V=(sampIntDAC) allowedIntervals + if(V_value == -1) + printf "%s: The selected sampling interval is not available for DAC on sutter hardware.\r", device + ControlWindowToFront() + return 1 + endif + FindValue/Z/V=(sampIntTTL) allowedIntervals + if(V_value == -1) + printf "%s: The selected sampling interval is not available for TTL on sutter hardware.\r", device + ControlWindowToFront() + return 1 + endif + WAVE allowedIntervals = GetSutterADCSampleInterval() + FindValue/Z/V=(sampIntADC) allowedIntervals + if(V_value == -1) + printf "%s: The selected sampling interval is not available for ADC on sutter hardware.\r", device + ControlWindowToFront() + return 1 + endif + endif + + return 0 +End + /// @brief Check if all settings are valid to send a test pulse or acquire data /// /// For invalid settings an informative message is printed into the history area. @@ -1916,7 +1998,7 @@ Function DAP_CheckSettings(device, mode) variable numDACs, numADCs, numHS, numEntries, i, clampMode, headstage variable ampSerial, ampChannelID, minValue, maxValue, hardwareType, hwChannel - variable lastStartSeconds, lastITI, nextStart, leftTime, sweepNo, validSampInt + variable lastStartSeconds, lastITI, nextStart, leftTime, sweepNo variable DACchannel, ret string ctrl, endWave, ttlWave, dacWave, refDacWave, reqParams string list, lastStart, msg @@ -1980,10 +2062,7 @@ Function DAP_CheckSettings(device, mode) return 1 endif - DAP_GetSampInt(device, mode, XOP_CHANNEL_TYPE_DAC, valid=validSampInt) - if(!validSampInt) - printf "%s: The selected sampling interval is not possible with your hardware.\r", device - ControlWindowToFront() + if(DAP_CheckSampleInterval(device, mode)) return 1 endif @@ -4100,6 +4179,7 @@ Function/S DAP_CreateDAEphysPanel() // fetch device lists DAP_GetNIDeviceList() DAP_GetITCDeviceList() + DAP_GetSUDeviceList() Execute "DA_Ephys()" panel = GetCurrentWindow() @@ -4759,6 +4839,7 @@ static Function DAP_UpdateListOfLockedDevices() string ITCPanelList = WinList("ITC*", ";", "WIN:64") string allPanelList = WinList("*", ";", "WIN:64") string NIDevList = DAP_GetNIDeviceList() + string SUPanelList = WinList(DEVICE_SUTTER_NAME_START_CLEAN + "*", ";", "WIN:64") numDevs = ItemsInList(NIDevList) for(i = 0;i < numDevs; i += 1) @@ -4769,7 +4850,7 @@ static Function DAP_UpdateListOfLockedDevices() endfor SVAR panelList = $GetLockedDevices() - panelList = ITCPanelList + NIPanelList + panelList = ITCPanelList + NIPanelList + SUPanelList End static Function DAP_UpdateChanAmpAssignStorWv(device) @@ -5195,6 +5276,7 @@ Function ButtonProc_Hardware_rescan(ba) : ButtonControl DAP_GetNIDeviceList() DAP_GetITCDeviceList() + DAP_GetSUDeviceList() break endswitch diff --git a/Packages/MIES/MIES_DataAcquisition_Multi.ipf b/Packages/MIES/MIES_DataAcquisition_Multi.ipf index 181cbb6667..687c9f85c3 100644 --- a/Packages/MIES/MIES_DataAcquisition_Multi.ipf +++ b/Packages/MIES/MIES_DataAcquisition_Multi.ipf @@ -36,6 +36,17 @@ Function DQM_FIFOMonitor(s) WAVE TPSettingsCalc = GetTPSettingsCalculated(device) switch(hardwareType) + case HARDWARE_SUTTER_DAC: + if(ROVar(GetSU_AcquisitionError(device))) + LOG_AddEntry(PACKAGE_MIES, "hardware error", stacktrace = 1) + DQ_StopOngoingDAQ(device, DQ_STOP_REASON_HW_ERROR, startTPAfterDAQ = 0) + endif + + fifoLatest = HW_SU_GetADCSamplePosition() +// fifoLatest = GetSUFifoPos(device) + + isFinished = HW_GetEffectiveADCWaveLength(device, DATA_ACQUISITION_MODE) == fifoLatest + break case HARDWARE_NI_DAC: AssertOnAndClearRTError() diff --git a/Packages/MIES/MIES_DataBrowser.ipf b/Packages/MIES/MIES_DataBrowser.ipf index 33268e2688..ef0d345ed0 100644 --- a/Packages/MIES/MIES_DataBrowser.ipf +++ b/Packages/MIES/MIES_DataBrowser.ipf @@ -651,56 +651,11 @@ End /// @returns 1 on error, 0 on success Function DB_SplitSweepsIfReq(string win, variable sweepNo) - string device, mainPanel - variable sweepModTime, numWaves, requireNewSplit, i - variable numBackupWaves - if(!BSP_HasBoundDevice(win)) return NaN endif - device = BSP_GetDevice(win) - - DFREF deviceDFR = GetDeviceDataPath(device) - DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) - - WAVE/Z sweepWave = GetSweepWave(device, sweepNo) - if(!WaveExists(sweepWave)) - return 1 - endif - - WAVE configWave = GetConfigWave(sweepWave) - - sweepModTime = max(ModDate(sweepWave), ModDate(configWave)) - numWaves = CountObjectsDFR(singleSweepDFR, COUNTOBJECTS_WAVES) - requireNewSplit = (numWaves == 0) - - for(i = 0; i < numWaves; i += 1) - WAVE/SDFR=singleSweepDFR wv = $GetIndexedObjNameDFR(singleSweepDFR, COUNTOBJECTS_WAVES, i) - if(sweepModTime > ModDate(wv)) - // original sweep was modified, regenerate single sweep waves - KillOrMoveToTrash(dfr=singleSweepDFR) - DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) - requireNewSplit = 1 - break - endif - if(GrepString(NameOfWave(wv), "\\Q" + WAVE_BACKUP_SUFFIX + "\\E$")) - numBackupWaves += 1 - endif - endfor - - if(!requireNewSplit && (numBackupWaves * 2 == numWaves)) - return 0 - endif - - KillOrMoveToTrash(dfr = singleSweepDFR) - DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) - - WAVE numericalValues = DB_GetLBNWave(win, LBN_NUMERICAL_VALUES) - - SplitSweepIntoComponents(numericalValues, sweepNo, sweepWave, configWave, TTL_RESCALE_ON, targetDFR=singleSweepDFR) - - return 0 + return SplitSweepsIfReq(BSP_GetDevice(win), sweepNo) End /// @brief Find a Databrowser which is locked to the given DAEphys panel diff --git a/Packages/MIES/MIES_DataConfigurator.ipf b/Packages/MIES/MIES_DataConfigurator.ipf index 62056be166..0cf499f6ad 100644 --- a/Packages/MIES/MIES_DataConfigurator.ipf +++ b/Packages/MIES/MIES_DataConfigurator.ipf @@ -185,7 +185,8 @@ static Function DC_ChannelCalcForDAQConfigWave(device, dataAcqOrTP) endif return numDACs + numADCs + numTTLsRackZero + numTTLsRackOne break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: if(dataAcqOrTP == DATA_ACQUISITION_MODE) numDACs = DC_NoOfChannelsSelected(device, CHANNEL_TYPE_DAC) numADCs = DC_NoOfChannelsSelected(device, CHANNEL_TYPE_ADC) @@ -264,6 +265,9 @@ static Function DC_LongestOutputWave(device, dataAcqOrTP, channelType) singlePulseLength = DimSize(wv, ROWS) numPulses = max(10, ceil((2^(MINIMUM_ITCDATAWAVE_EXPONENT + 1) * 0.90) / singlePulseLength)) maxNumRows = max(maxNumRows, numPulses * singlePulseLength) + elseif(dataAcqOrTP == TEST_PULSE_MODE && GetHardwareType(device) == HARDWARE_SUTTER_DAC) + singlePulseLength = DimSize(wv, ROWS) + maxNumRows = SUTTER_MAX_MAX_TP_PULSES * singlePulseLength else maxNumRows = max(maxNumRows, DimSize(wv, ROWS)) endif @@ -283,7 +287,9 @@ End /// /// @param device panel title /// @param dataAcqOrTP acquisition mode, one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE -static Function DC_CalculateDAQDataWaveLength(string device, variable dataAcqOrTP) +/// @param channelType channel type, one of @sa XopChannelConstants +static Function DC_CalculateDAQDataWaveLength(string device, variable dataAcqOrTP, variable channelType) + variable rateFactor variable hardwareType = GetHardwareType(device) NVAR stopCollectionPoint = $GetStopCollectionPoint(device) @@ -302,6 +308,14 @@ static Function DC_CalculateDAQDataWaveLength(string device, variable dataAcqOrT case HARDWARE_NI_DAC: return stopCollectionPoint break + case HARDWARE_SUTTER_DAC: + if(channelType == XOP_CHANNEL_TYPE_ADC) + rateFactor = DAP_GetSampInt(device, dataAcqOrTP, XOP_CHANNEL_TYPE_DAC) / DAP_GetSampInt(device, dataAcqOrTP, XOP_CHANNEL_TYPE_ADC) + return trunc(stopCollectionPoint * rateFactor) + else + return stopCollectionPoint + endif + break endswitch return NaN end @@ -326,64 +340,118 @@ End /// /// Config all refers to configuring all the channels at once /// -/// @param device panel title -/// @param hardwareType hardware type -/// @param numActiveChannels number of active channels as returned by DC_ChannelCalcForDAQConfigWave() -/// @param samplingInterval sampling interval as returned by DAP_GetSampInt() -/// @param dataAcqOrTP one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE -static Function [WAVE/Z DAQDataWave, WAVE/WAVE NIDataWave] DC_MakeAndGetDAQDataWave(string device, variable hardwareType, variable numActiveChannels, variable samplingInterval, variable dataAcqOrTP) +/// @param device panel title +/// @param s DataConfigurationResult structure +/// @param dataAcqOrTP one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE +static Function [WAVE/Z DAQDataWave, WAVE/WAVE NIDataWave] DC_MakeAndGetDAQDataWave(string device, STRUCT DataConfigurationResult &s, variable dataAcqOrTP) variable numRows, i - numRows = DC_CalculateDAQDataWaveLength(device, dataAcqOrTP) - switch(hardwareType) + switch(s.hardwareType) case HARDWARE_ITC_DAC: + numRows = DC_CalculateDAQDataWaveLength(device, dataAcqOrTP, XOP_CHANNEL_TYPE_DAC) WAVE ITCDataWave = GetDAQDataWave(device, dataAcqOrTP) - Redimension/N=(numRows, numActiveChannels) ITCDataWave + Redimension/N=(numRows, s.numActiveChannels) ITCDataWave FastOp ITCDataWave = 0 - SetScale/P x, 0, samplingInterval * MICRO_TO_MILLI, "ms", ITCDataWave + SetScale/P x, 0, s.samplingInterval * MICRO_TO_MILLI, "ms", ITCDataWave return [ITCDataWave, $""] break - case HARDWARE_NI_DAC: - WAVE/WAVE NIDataWave = GetDAQDataWave(device, dataAcqOrTP) - Redimension/N=(numActiveChannels) NIDataWave - - SetScale/P x, 0, samplingInterval * MICRO_TO_MILLI, "ms", NIDataWave + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: + WAVE/WAVE NISUDataWave = GetDAQDataWave(device, dataAcqOrTP) + Redimension/N=(s.numActiveChannels) NISUDataWave + + if(s.hardwareType == HARDWARE_NI_DAC) + // @TODO original commit 54ad670, can not be used for SU as waves can have different scaling + SetScale/P x, 0, s.samplingInterval * MICRO_TO_MILLI, "ms", NISUDataWave + endif - Make/FREE/N=(numActiveChannels) type = SWS_GetRawDataFPType(device) + Make/FREE/N=(s.numActiveChannels) type = SWS_GetRawDataFPType(device) WAVE config = GetDAQConfigWave(device) type = config[p][%ChannelType] == XOP_CHANNEL_TYPE_TTL ? IGOR_TYPE_UNSIGNED | IGOR_TYPE_8BIT_INT : type[p] - NIDataWave = DC_MakeNIChannelWave(device, numRows, samplingInterval, p, type[p], dataAcqOrTP) + if(s.hardwareType == HARDWARE_NI_DAC) + NISUDataWave = DC_MakeNIChannelWave(device, dataAcqOrTP, config[p][%ChannelType], config[p][%SamplingInterval], p, type[p]) + elseif(s.hardwareType == HARDWARE_SUTTER_DAC) + NISUDataWave = DC_MakeSUTTERChannelWave(device, dataAcqOrTP, config[p][%ChannelType], config[p][%SamplingInterval], p, type[p]) + endif + NISUDataWave = DC_SetDataScaleNISUChannelWave(NISUDataWave[p], config[p][%ChannelType]) + + return [$"", NISUDataWave] + break + endswitch +End + +/// @brief set a data scale for channel waves, this is not required for operation but allows to keep track of the scales +/// The waves for the hardware that output data and read back data are typically in V because any other unit, like pA in current clamp mode on DAC channels +/// is converted by the gain from pA to voltage and then by the hardware amplifier converted back from V to pA. +static Function/WAVE DC_SetDataScaleNISUChannelWave(WAVE channel, variable type) - return [$"", NIDataWave] + switch(type) + case XOP_CHANNEL_TYPE_DAC: + SetScale d, 0, 0, "V", channel break + case XOP_CHANNEL_TYPE_ADC: + SetScale d, 0, 0, "V", channel + break + case XOP_CHANNEL_TYPE_TTL: + break + default: + ASSERT(0, "Unknown channel type") endswitch + + return channel End /// @brief Creates a single NIChannel wave /// /// Config all refers to configuring all the channels at once /// -/// @param device panel title -/// @param numRows size of the 1D channel wave +/// @param device panel title +/// @param dataAcqOrTP one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE +/// @param channelType channel type, one of @sa XopChannelConstants /// @param samplingInterval minimum sample intervall in microseconds /// @param index number of NI channel -/// @param type numeric data type of NI channel +/// @param dataType numeric data type of NI channel +/// +/// @return Wave Reference to NI Channel wave +static Function/WAVE DC_MakeNIChannelWave(string device, variable dataAcqOrTP, variable channelType, variable samplingInterval, variable index, variable dataType) + + variable numRows = DC_CalculateDAQDataWaveLength(device, dataAcqOrTP, channelType) + + WAVE channel = GetNIDAQChannelWave(device, index, dataAcqOrTP) + Redimension/N=(numRows)/Y=(dataType) channel + // @todo test + FastOp channel = (NaN) + SetScale/P x, 0, samplingInterval * MICRO_TO_MILLI, "ms", channel + + return channel +End + +/// @brief Creates a single SUTTER Channel wave +/// +/// Config all refers to configuring all the channels at once +/// +/// @param device panel title /// @param dataAcqOrTP one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE +/// @param channelType channel type, one of @sa XopChannelConstants +/// @param samplingInterval minimum sample intervall in microseconds +/// @param index number of NI channel +/// @param dataType numeric data type of NI channel /// /// @return Wave Reference to NI Channel wave -static Function/WAVE DC_MakeNIChannelWave(device, numRows, samplingInterval, index, type, dataAcqOrTP) - variable numRows, samplingInterval, index, type, dataAcqOrTP - string device +static Function/WAVE DC_MakeSUTTERChannelWave(string device, variable dataAcqOrTP, variable channelType, variable samplingInterval, variable index, variable dataType) - WAVE NIChannel = GetNIDAQChannelWave(device, index, dataAcqOrTP) - Redimension/N=(numRows)/Y=(type) NIChannel - FastOp NIChannel= 0 - SetScale/P x, 0, samplingInterval * MICRO_TO_MILLI, "ms", NIChannel + variable numRows = DC_CalculateDAQDataWaveLength(device, dataAcqOrTP, channelType) - return NIChannel + WAVE channel = GetNIDAQChannelWave(device, index, dataAcqOrTP) + Redimension/N=(numRows)/Y=(dataType) channel +// uncomment when using GetSUFifoPos in DQM_FIFOMonitor +// FastOp channel = (NaN) + SetScale/P x, 0, samplingInterval * MICRO_TO_ONE, "s", channel + + return channel End /// @brief Initializes the waves used for displaying DAQ/TP results in the @@ -392,16 +460,14 @@ End /// @param device panel title /// @param dataAcqOrTP one of #DATA_ACQUISITION_MODE or #TEST_PULSE_MODE static Function DC_MakeHelperWaves(string device, variable dataAcqOrTP) - variable numRows, sampleInterval, col, hardwareType, decimatedNumRows, numPixels, dataPointsPerPixel + variable numRows, col, hardwareType, decimatedNumRows, numPixels, dataPointsPerPixel variable decMethod, decFactor, tpLength, numADCs, numDACs, numTTLs, decimatedSampleInterval variable tpOrPowerSpectrumLength, powerSpectrum + variable sampleIntervalADC, pointsAcq WAVE config = GetDAQConfigWave(device) WAVE OscilloscopeData = GetOscilloscopeWave(device) WAVE TPOscilloscopeData = GetTPOscilloscopeWave(device) - WAVE scaledDataWave = GetScaledDataWave(device) - WAVE ITCDataWave = GetDAQDataWave(device, dataAcqOrTP) - WAVE/WAVE NIDataWave = GetDAQDataWave(device, dataAcqOrTP) WAVE TPSettingsCalc = GetTPSettingsCalculated(device) hardwareType = GetHardwareType(device) @@ -415,16 +481,29 @@ static Function DC_MakeHelperWaves(string device, variable dataAcqOrTP) switch(hardwareType) case HARDWARE_ITC_DAC: - sampleInterval = DimDelta(ITCDataWave, ROWS) + WAVE ITCDataWave = GetDAQDataWave(device, dataAcqOrTP) + sampleIntervalADC = DimDelta(ITCDataWave, ROWS) break case HARDWARE_NI_DAC: - sampleInterval = DimDelta(NIDataWave[0], ROWS) + WAVE/WAVE NIDataWave = GetDAQDataWave(device, dataAcqOrTP) + sampleIntervalADC = DimDelta(NIDataWave[numDACs], ROWS) + break + case HARDWARE_SUTTER_DAC: + WAVE/WAVE SUDataWave = GetDAQDataWave(device, dataAcqOrTP) + sampleIntervalADC = DimDelta(SUDataWave[numDACs], ROWS) * ONE_TO_MILLI break endswitch + tpLength = TPSettingsCalc[%totalLengthPointsTP_ADC] + powerSpectrum = DAG_GetNumericalValue(device, "check_settings_show_power") + if(powerSpectrum) + // see DisplayHelpTopic `FFT` for the explanation of the calculation + tpOrPowerSpectrumLength = floor(TP_GetPowerSpectrumLength(tpLength) / 2) + 1 + else + tpOrPowerSpectrumLength = tpLength + endif + if(dataAcqOrTP == TEST_PULSE_MODE) - tpLength = TPSettingsCalc[%totalLengthPointsTP] - powerSpectrum = DAG_GetNumericalValue(device, "check_settings_show_power") numRows = tpLength @@ -432,29 +511,28 @@ static Function DC_MakeHelperWaves(string device, variable dataAcqOrTP) decFactor = NaN decimatedNumRows = numRows - decimatedSampleInterval = sampleInterval - - if(powerSpectrum) - // see DisplayHelpTopic `FFT` for the explanation of the calculation - tpOrPowerSpectrumLength = floor(TP_GetPowerSpectrumLength(tpLength) / 2) + 1 - else - tpOrPowerSpectrumLength = tpLength - endif + decimatedSampleInterval = sampleIntervalADC elseif(dataAcqOrTP == DATA_ACQUISITION_MODE) - tpLength = NaN + + WAVE tpOsciForPowerSpectrum = GetScaledTPTempWave(device) + Redimension/N=(tpLength, numADCs) tpOsciForPowerSpectrum switch(hardwareType) case HARDWARE_ITC_DAC: numRows = DimSize(ITCDataWave, ROWS) + pointsAcq = ROVar(GetStopCollectionPoint(device)) break case HARDWARE_NI_DAC: - numRows = DimSize(NIDataWave[0], ROWS) + numRows = DimSize(NIDataWave[numDACs], ROWS) + pointsAcq = numRows + break + case HARDWARE_SUTTER_DAC: + numRows = DimSize(SUDataWave[numDACs], ROWS) + pointsAcq = numRows break endswitch - NVAR stopCollectionPoint = $GetStopCollectionPoint(device) - decMethod = DAG_GetNumericalValue(device, "Popup_Settings_DecMethod") decFactor = DEFAULT_DECIMATION_FACTOR @@ -462,7 +540,7 @@ static Function DC_MakeHelperWaves(string device, variable dataAcqOrTP) case DECIMATION_NONE: decFactor = 1 decimatedNumRows = numRows - decimatedSampleInterval = sampleInterval + decimatedSampleInterval = sampleIntervalADC break default: STRUCT RectD s @@ -471,17 +549,17 @@ static Function DC_MakeHelperWaves(string device, variable dataAcqOrTP) // use twice as many pixels as we need // but round to a power of two numPixels = s.right - s.left - dataPointsPerPixel = trunc((stopCollectionPoint / (numPixels * 2))) + dataPointsPerPixel = trunc((pointsAcq / (numPixels * 2))) if(dataPointsPerPixel > 2) decFactor = 2^FindPreviousPower(dataPointsPerPixel, 2) decimatedNumRows = GetDecimatedWaveSize(numRows, decFactor, decMethod) - decimatedSampleInterval = sampleInterval * decFactor + decimatedSampleInterval = sampleIntervalADC * decFactor else // turn off decimation for very short stimsets decMethod = DECIMATION_NONE decFactor = 1 decimatedNumRows = numRows - decimatedSampleInterval = sampleInterval + decimatedSampleInterval = sampleIntervalADC endif break endswitch @@ -492,14 +570,74 @@ static Function DC_MakeHelperWaves(string device, variable dataAcqOrTP) SetNumberInWaveNote(OscilloscopeData, "DecimationMethod", decMethod) SetNumberInWaveNote(OscilloscopeData, "DecimationFactor", decFactor) - DC_InitDataHoldingWave(TPOscilloscopeData, tpOrPowerSpectrumLength, sampleInterval, numDACs, numADCs, numTTLs, isFourierTransform=(powerSpectrum && dataAcqOrTP == TEST_PULSE_MODE)) - DC_InitDataHoldingWave(OscilloscopeData, decimatedNumRows, decimatedSampleInterval, numDACs, numADCs, numTTLs) + DC_InitOscilloscopeDataWave(TPOscilloscopeData, tpOrPowerSpectrumLength, sampleIntervalADC, numDACs, numADCs, numTTLs, isFourierTransform=powerSpectrum) + DC_InitOscilloscopeDataWave(OscilloscopeData, decimatedNumRows, decimatedSampleInterval, numDACs, numADCs, numTTLs) + + DC_InitScaledDataWave(device, dataAcqOrTP) +End + +/// @brief Initialize scaledDataWave, as NI and SUTTER output already properly scaled data, we can prefill output channels. +/// So in in the more time critical SCOPE_xx_UpdateOscilloscope we can optimize by only copying the ADC data over (ADC data from SUTTER and NI is already properly scaled by hardware) +static Function DC_InitScaledDataWave(string device, variable dataAcqOrTP) + + variable i, numChannels, dataType, tpLength, size, sampleIntervalADC, hardwareType + + WAVE TPSettingsCalc = GetTPSettingsCalculated(device) + WAVE/WAVE scaledDataWave = GetScaledDataWave(device) + WAVE config = GetDAQConfigWave(device) + WAVE/T units = AFH_GetChannelUnits(config) + dataType = SWS_GetRawDataFPType(device) + hardwareType = GetHardwareType(device) + + if(hardwareType == HARDWARE_ITC_DAC) + size = dataAcqOrTP == DATA_ACQUISITION_MODE ? ROVar(GetStopCollectionPoint(device)) : TPSettingsCalc[%totalLengthPointsTP_ADC] + WAVE ITCDataWave = GetDAQDataWave(device, dataAcqOrTP) + sampleIntervalADC = DimDelta(ITCDataWave, ROWS) + numChannels = DimSize(config, ROWS) + Redimension/N=(numChannels) scaledDataWave + for(i = 0; i < numChannels; i += 1) + Make/FREE/Y=(dataType)/N=(size) wv + // in SCOPE_ITC_UpdateOscilloscope all channels are copied over to scaledDataWave + FastOp wv = (NaN) + SetScale/P x, 0, sampleIntervalADC, "ms", wv + if(i < DimSize(units, ROWS)) + SetScale d, 0, 0, units[i] + endif + scaledDataWave[i] = wv + endfor + + return NaN + endif + + WAVE gains = SWS_GetChannelGains(device, timing = GAIN_BEFORE_DAQ) + WAVE/WAVE dataWave = GetDAQDataWave(device, dataAcqOrTP) + numChannels = DimSize(dataWave, ROWS) + Redimension/N=(numChannels) scaledDataWave + for(i = 0; i < numChannels; i += 1) + WAVE channel = dataWave[i] + size = dataAcqOrTP == DATA_ACQUISITION_MODE ? DimSize(channel, ROWS) : TPSettingsCalc[%totalLengthPointsTP_ADC] + Make/FREE/Y=(dataType)/N=(size) wv + if(config[i][%ChannelType] == XOP_CHANNEL_TYPE_ADC) + FastOp wv = (NaN) + else + Multithread wv[] = channel[p] / gains[i] + endif + + if(hardwareType == HARDWARE_NI_DAC) + SetScale/P x, 0, DimDelta(channel, ROWS), "ms", wv + elseif(hardwareType == HARDWARE_SUTTER_DAC) + SetScale/P x, 0, DimDelta(channel, ROWS) * ONE_TO_MILLI, "ms", wv + endif + if(i < DimSize(units, ROWS)) + SetScale d, 0, 0, units[i], wv + endif - DC_InitDataHoldingWave(scaledDataWave, dataAcqOrTP == DATA_ACQUISITION_MODE ? stopCollectionPoint : tpLength, sampleInterval, numDACs, numADCs, numTTLs, type = SWS_GetRawDataFPType(device)) + scaledDataWave[i] = wv + endfor End -/// @brief Initialize data holding waves to NaN -static Function DC_InitDataHoldingWave(wv, numRows, sampleInterval, numDACs, numADCs, numTTLs, [type, isFourierTransform]) +/// @brief Initialize OscilloscopeData waves to NaN +static Function DC_InitOscilloscopeDataWave(wv, numRows, sampleInterval, numDACs, numADCs, numTTLs, [type, isFourierTransform]) WAVE wv variable numRows, sampleInterval, numDACs, numADCs, numTTLs, type, isFourierTransform string msg @@ -626,6 +764,8 @@ static Function DC_PlaceDataInDAQConfigWave(device, dataAcqOrTP) WAVE statusDAFiltered = DC_GetFilteredChannelState(device, dataAcqOrTP, CHANNEL_TYPE_DAC) WAVE/T allSetNames = DAG_GetChannelTextual(device, CHANNEL_TYPE_DAC, CHANNEL_CONTROL_WAVE) ctrl = GetSpecialControlLabel(CHANNEL_TYPE_DAC, CHANNEL_CONTROL_UNIT) + DAQConfigWave[][%HEADSTAGE] = NaN + DAQConfigWave[][%CLAMPMODE] = NaN numEntries = DimSize(statusDAFiltered, ROWS) for(i = 0; i < numEntries; i += 1) @@ -638,6 +778,12 @@ static Function DC_PlaceDataInDAQConfigWave(device, dataAcqOrTP) DAQConfigWave[j][%ChannelNumber] = i unitList = AddListItem(DAG_GetTextualValue(device, ctrl, index = i), unitList, ",", Inf) DAQConfigWave[j][%DAQChannelType] = !CmpStr(allSetNames[i], STIMSET_TP_WHILE_DAQ, 1) || dataAcqOrTP == TEST_PULSE_MODE ? DAQ_CHANNEL_TYPE_TP : DAQ_CHANNEL_TYPE_DAQ + headstage = AFH_GetHeadstageFromDAC(device, i) + DAQConfigWave[j][%HEADSTAGE] = headstage + if(IsFinite(headstage)) + DAQConfigWave[j][%CLAMPMODE] = DAG_GetHeadstageMode(device, headstage) + endif + j += 1 endfor @@ -662,6 +808,8 @@ static Function DC_PlaceDataInDAQConfigWave(device, dataAcqOrTP) if(IsFinite(headstage)) // use the same channel type as the DAC DAQConfigWave[j][%DAQChannelType] = DC_GetChannelTypefromHS(device, headstage) + DAQConfigWave[j][%HEADSTAGE] = headstage + DAQConfigWave[j][%CLAMPMODE] = DAG_GetHeadstageMode(device, headstage) else // unassociated ADCs are always of DAQ type DAQConfigWave[j][%DAQChannelType] = DAQ_CHANNEL_TYPE_DAQ @@ -696,7 +844,8 @@ static Function DC_PlaceDataInDAQConfigWave(device, dataAcqOrTP) DAQConfigWave[j][%DAQChannelType] = DAQ_CHANNEL_TYPE_DAQ endif break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: WAVE statusTTL = DAG_GetChannelState(device, CHANNEL_TYPE_TTL) numEntries = DimSize(statusTTL, ROWS) for(i = 0; i < numEntries; i += 1) @@ -834,7 +983,8 @@ static Function DC_MakeTTLWave(string device, STRUCT DataConfigurationResult &s) endif switch(s.hardwareType) - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: DC_NI_MakeTTLWave(device, s) break case HARDWARE_ITC_DAC: @@ -861,7 +1011,8 @@ static Function DC_WriteTTLIntoDAQDataWave(string device, STRUCT DataConfigurati WAVE config = GetDAQConfigWave(device) switch(s.hardwareType) - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: WAVE/WAVE NIDataWave = GetDAQDataWave(device, s.dataAcqOrTP) WAVE/WAVE TTLWaveNI = GetTTLWave(device) @@ -1092,7 +1243,8 @@ static Function DC_FillSetEventFlag(string device, STRUCT DataConfigurationResul End static Function DC_FillDAQDataWaveForTP(string device, STRUCT DataConfigurationResult &s) - variable cutOff, i, tpAmp + + variable cutOff, i, tpAmp, channelSize, minLimit, maxLimit string key // varies per DAC: @@ -1113,7 +1265,7 @@ static Function DC_FillDAQDataWaveForTP(string device, STRUCT DataConfigurationR cacheParams.hardwareType = s.hardwareType cacheParams.numDACs = s.numDACEntries cacheParams.numActiveChannels = s.numActiveChannels - cacheParams.numberOfRows = DC_CalculateDAQDataWaveLength(device, TEST_PULSE_MODE) + cacheParams.numberOfRows = DC_CalculateDAQDataWaveLength(device, TEST_PULSE_MODE, XOP_CHANNEL_TYPE_DAC) cacheParams.samplingInterval = s.samplingInterval WAVE cacheParams.gains = s.gains Duplicate/FREE/RMD=[][FindDimLabel(s.DACAmp, COLS, "TPAMP")] s.DACAmp, DACAmpTP @@ -1135,7 +1287,8 @@ static Function DC_FillDAQDataWaveForTP(string device, STRUCT DataConfigurationR WAVE/W ITCDataWave = DAQDataWave Multithread ITCDataWave[][s.numDACEntries, s.numDACEntries + s.numADCEntries - 1] = 0 break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: WAVE/WAVE NIDataWave = DAQDataWave for(i = 0; i < s.numADCEntries; i += 1) WAVE NIChannel = NIDataWave[s.numDACEntries + i] @@ -1153,8 +1306,8 @@ static Function DC_FillDAQDataWaveForTP(string device, STRUCT DataConfigurationR MoveWaveWithOverwrite(DAQDataWave, result, recursive = 1) endif else - [WAVE ITCDataWave, WAVE/WAVE NIDataWave] = DC_MakeAndGetDAQDataWave(device, s.hardwareType, s.numActiveChannels, \ - s.samplingInterval, TEST_PULSE_MODE) + [WAVE ITCDataWave, WAVE/WAVE NISUDataWave] = DC_MakeAndGetDAQDataWave(device, s, TEST_PULSE_MODE) + WAVE config = GetDAQConfigWave(device) switch(s.hardwareType) case HARDWARE_ITC_DAC: @@ -1181,7 +1334,7 @@ static Function DC_FillDAQDataWaveForTP(string device, STRUCT DataConfigurationR break case HARDWARE_NI_DAC: for(i = 0;i < s.numDACEntries; i += 1) - WAVE NIChannel = NIDataWave[i] + WAVE NIChannel = NISUDataWave[i] tpAmp = s.DACAmp[i][%TPAMP] * s.gains[i] Multithread NIChannel[0, s.testPulseLength - 1] = \ limit( \ @@ -1190,8 +1343,26 @@ static Function DC_FillDAQDataWaveForTP(string device, STRUCT DataConfigurationR NI_DAC_MAX); AbortOnRTE endfor - SetStringInWaveNote(NIDataWave, TP_PROPERTIES_HASH, key, recursive = 1) - CA_StoreEntryIntoCache(key, NIDataWave) + SetStringInWaveNote(NISUDataWave, TP_PROPERTIES_HASH, key, recursive = 1) + CA_StoreEntryIntoCache(key, NISUDataWave) + break + case HARDWARE_SUTTER_DAC: + for(i = 0;i < s.numDACEntries; i += 1) + WAVE SUChannel = NISUDataWave[i] + ASSERT(!mod(DimSize(SUChannel, ROWS), s.testPulseLength), "Sutter TP channel length is not integer multiple of test pulse length") + tpAmp = s.DACAmp[i][%TPAMP] * s.gains[i] + if(IsNaN(config[i][%HEADSTAGE])) + minLimit = SU_DAC_MIN + maxLimit = SU_DAC_MAX + else + minLimit = SU_HS_OUT_MIN + maxLimit = SU_HS_OUT_MAX + endif + Multithread SUChannel[] = limit(tpAmp * s.testPulse[mod(p, s.testPulseLength)], minLimit, maxLimit); AbortOnRTE + endfor + + SetStringInWaveNote(NISUDataWave, TP_PROPERTIES_HASH, key, recursive = 1) + CA_StoreEntryIntoCache(key, NISUDataWave) break endswitch endif @@ -1199,12 +1370,11 @@ End static Function DC_FillDAQDataWaveForDAQ(string device, STRUCT DataConfigurationResult &s) variable i, tpAmp, cutOff, channel, headstage, DAScale, singleSetLength, stimsetCol, startOffset - variable lastValidRow, isUnAssociated + variable lastValidRow, isUnAssociated, maxLimit, minLimit WAVE config = GetDAQConfigWave(device) - [WAVE ITCDataWave, WAVE/WAVE NIDataWave] = DC_MakeAndGetDAQDataWave(device, s.hardwareType, s.numActiveChannels, \ - s.samplingInterval, DATA_ACQUISITION_MODE) + [WAVE ITCDataWave, WAVE/WAVE NIDataWave] = DC_MakeAndGetDAQDataWave(device, s, DATA_ACQUISITION_MODE) for(i = 0; i < s.numDACEntries; i += 1) if(config[i][%DAQChannelType] == DAQ_CHANNEL_TYPE_TP) @@ -1223,7 +1393,8 @@ static Function DC_FillDAQDataWaveForDAQ(string device, STRUCT DataConfiguration ITCDataWave[DimSize(ITCDataWave, ROWS) - cutOff, *][i] = 0 endif break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: WAVE NIChannel = NIDataWave[i] Multithread NIChannel[] = \ limit( \ @@ -1262,7 +1433,8 @@ static Function DC_FillDAQDataWaveForDAQ(string device, STRUCT DataConfiguration limit(tpAmp * s.testPulse[p], SIGNED_INT_16BIT_MIN, SIGNED_INT_16BIT_MAX); AbortOnRTE endif break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: // for an index step of 1 in NIChannel, singleStimSet steps decimationFactor // for an index step of 1 in singleStimset, NIChannel steps 1 / decimationFactor // for decimationFactor < 1 and indexing NIChannel to DimSize(NIChannel, ROWS) - 1 (as implemented here), @@ -1273,17 +1445,28 @@ static Function DC_FillDAQDataWaveForDAQ(string device, STRUCT DataConfiguration // for ITC decimationFactor is always >= 1 since the stimSets are generated for the ITC max. sample rate WAVE NIChannel = NIDataWave[i] lastValidRow = DimSize(singleStimSet, ROWS) - 1 + if(s.hardwareType == HARDWARE_NI_DAC) + minLimit = NI_DAC_MIN + maxLimit = NI_DAC_MAX + elseif(isUnAssociated) + minLimit = SU_DAC_MIN + maxLimit = SU_DAC_MAX + else + minLimit = SU_HS_OUT_MIN + maxLimit = SU_HS_OUT_MAX + endif + MultiThread NIChannel[startOffset, startOffset + singleSetLength - 1] = \ limit( \ DAScale * singleStimSet[limit(s.decimationFactor * (p - startOffset), 0, lastValidRow)][stimsetCol], \ - NI_DAC_MIN, \ - NI_DAC_MAX); AbortOnRTE + minLimit, \ + maxLimit); AbortOnRTE if(s.globalTPInsert && !isUnAssociated) // space in ITCDataWave for the testpulse is allocated via an automatic increase // of the onset delay MultiThread NIChannel[0, s.testPulseLength - 1] = \ - limit(tpAmp * s.testPulse[p], NI_DAC_MIN, NI_DAC_MAX); AbortOnRTE + limit(tpAmp * s.testPulse[p], minLimit, maxLimit); AbortOnRTE endif break endswitch @@ -1435,10 +1618,13 @@ static Function [STRUCT DataConfigurationResult s] DC_GetConfiguration(string de s.DACAmp[i][%TPAMP] = 0 endif elseif(config[i][%DAQChannelType] == DAQ_CHANNEL_TYPE_TP) - // do nothing + if(s.powerSpectrum) + s.DACAmp[i][%TPAMP] = 0 + endif endif elseif(dataAcqOrTP == TEST_PULSE_MODE) if(s.powerSpectrum) + // intended use of powerspectrum is for noise checking s.DACAmp[i][%TPAMP] = 0 endif else @@ -1585,6 +1771,11 @@ static Function DC_DocumentHardwareProperties(device, hardwareType) sprintf str, "%#0X", str2num(devInfoText[%DeviceSerialNumber]) DC_DocumentChannelProperty(device, "Digitizer Serial Numbers", INDEP_HEADSTAGE, NaN, NaN, str=str) break + case HARDWARE_SUTTER_DAC: + WAVE/T devInfoText = devInfo + DC_DocumentChannelProperty(device, "Digitizer Hardware Name", INDEP_HEADSTAGE, NaN, NaN, str=DEVICE_NAME_NICE_SUTTER) + DC_DocumentChannelProperty(device, "Digitizer Serial Numbers", INDEP_HEADSTAGE, NaN, NaN, str=devInfoText[%LISTOFDEVICES]) + break default: ASSERT(0, "Unknown hardware") endswitch @@ -1689,6 +1880,9 @@ static Function [variable result, variable row, variable column] DC_CheckIfDataW return [0, NaN, NaN] endfor break + case HARDWARE_SUTTER_DAC: + // @TODO Determine what to check here + break endswitch End diff --git a/Packages/MIES/MIES_Epochs.ipf b/Packages/MIES/MIES_Epochs.ipf index ad73d5b170..364c780b09 100644 --- a/Packages/MIES/MIES_Epochs.ipf +++ b/Packages/MIES/MIES_Epochs.ipf @@ -743,24 +743,14 @@ End /// @brief Write the epoch info into the sweep settings wave /// /// @param device device -/// @param sweepWave sweep wave -/// @param configWave config wave -Function EP_WriteEpochInfoIntoSweepSettings(string device, WAVE sweepWave, WAVE configWave) +/// @param sweepNo sweep Number +Function EP_WriteEpochInfoIntoSweepSettings(string device, variable sweepNo) variable i, numDACEntries, channel, headstage, acquiredTime, plannedTime string entry - plannedTime = IndexToScale(sweepWave, DimSize(sweepWave, ROWS) - 1, ROWS) * MILLI_TO_ONE + [plannedTime, acQuiredTime] = GetActualAcquisitionTimes(device, sweepNo) - // all channels are acquired simultaneously we can just check if the last - // channel has NaN in the last element - if(IsNaN(sweepWave[inf][inf])) - FindValue/FNAN sweepWave - ASSERT(V_row >= 0, "Unexpected result") - - acquiredTime = IndexToScale(sweepWave, max(V_row - 1, 0), ROWS) * MILLI_TO_ONE - else - acquiredTime = plannedTime - endif + [WAVE sweepWave, WAVE configWave] = GetSweepAndConfigWaveFromDevice(device, sweepNo) EP_AdaptEpochInfo(device, configWave, acquiredTime, plannedTime) diff --git a/Packages/MIES/MIES_GlobalStringAndVariableAccess.ipf b/Packages/MIES/MIES_GlobalStringAndVariableAccess.ipf index bd66801c25..b60815b4ac 100644 --- a/Packages/MIES/MIES_GlobalStringAndVariableAccess.ipf +++ b/Packages/MIES/MIES_GlobalStringAndVariableAccess.ipf @@ -298,7 +298,13 @@ Function/S GetUserComment(device) return GetSVARAsString(GetDevicePath(device), "userComment") End -/// @brief Return the stop collection point, this is a *length*. +/// @brief Return the stop collection point, this is a *length* in points. +/// The StopCollectionPoint is the effective length of the DAC data. +/// While for NI and SUTTER hardware this equals the length of the DAC output wave, +/// for ITC the DAC output wave is longer (next power of 2). +/// +/// Also for SUTTER hardware the ADC input wave length is different from the DAC output wave. +/// StopCollectionPoint CAN NOT be used to determine the length of the ADC input wave. /// /// @sa GetFifoPosition() Function/S GetStopCollectionPoint(device) @@ -352,6 +358,17 @@ Function/S GetTestpulseRunMode(device) return GetNVARAsString(GetDeviceTestPulse(device), "runMode", initialValue=TEST_PULSE_NOT_RUNNING) End +/// @brief Returns SU device list +/// +/// Internal use only, prefer DAP_GetSUDeviceList() instead. +/// +/// The initial value `""` is different from #NONE which denotes no matches. +Function/S GetSUDeviceList() + + // note: this global gets killed in IH_KillTemporaries + return GetSVARAsString(GetDAQDevicesFolder(), "SUDeviceList", initialValue="") +End + /// @brief Returns NI device list /// /// Internal use only, prefer DAP_GetNIDeviceList() instead. @@ -416,6 +433,18 @@ Function/S GetNI_DACTaskID(device) return GetNVARAsString(GetDevicePath(device), "NI_DAC_taskID", initialValue=NaN) End +/// @brief Returns if the Sutter hardware is acquiring +Function/S GetSU_IsAcquisitionRunning(string device) + + return GetNVARAsString(GetDevicePath(device), "SU_AcquisitionRunning", initialValue=0) +End + +/// @brief Returns if the Sutter hardware had an acquisition error +Function/S GetSU_AcquisitionError(string device) + + return GetNVARAsString(GetDevicePath(device), "SU_AcquisitionError", initialValue=0) +End + /// @brief Returns the TTL task ID set by DAQmx_DIO_Config in HW_NI_PrepareAcq Function/S GetNI_TTLTaskID(device) string device diff --git a/Packages/MIES/MIES_MiesUtilities.ipf b/Packages/MIES/MIES_MiesUtilities.ipf index 7eef16df53..65efe7f021 100644 --- a/Packages/MIES/MIES_MiesUtilities.ipf +++ b/Packages/MIES/MIES_MiesUtilities.ipf @@ -2281,21 +2281,32 @@ threadsafe Function GetHardwareType(device) if(WhichListItem(deviceType, DEVICE_TYPES_ITC) != -1) return HARDWARE_ITC_DAC elseif(IsEmpty(deviceNumber)) - return HARDWARE_NI_DAC + if(IsDeviceNameFromSutter(deviceType)) + return HARDWARE_SUTTER_DAC + else + return HARDWARE_NI_DAC + endif endif return HARDWARE_UNSUPPORTED_DAC End +threadsafe static Function IsDeviceNameFromSutter(string device) + + return strsearch(device, DEVICE_SUTTER_NAME_START_CLEAN, 0) == 0 && strlen(device) >= 7 +End + /// @brief Parse a device string: /// for ITC devices of the form X_DEV_Y, where X is from @ref DEVICE_TYPES_ITC /// and Y from @ref DEVICE_NUMBERS. /// for NI devices of the form X, where X is from DAP_GetNIDeviceList() +/// for Sutter devices of the form IPA_E_Xxxxxx, where X must be present /// /// Returns the result in deviceType and deviceNumber. /// Currently the parsing is successfull if /// for ITC devices X and Y are non-empty. /// for NI devices X is non-empty. +/// for Sutter devices if the name starts with IPA_E_ and is at least 7 characters long /// deviceNumber is empty for NI devices as it does not apply /// @param[in] device input device string X_DEV_Y /// @param[out] deviceType returns the device type X @@ -2311,17 +2322,23 @@ threadsafe Function ParseDeviceString(device, deviceType, deviceNumber) return 0 endif + if(IsDeviceNameFromSutter(device)) + deviceType = device + deviceNumber = "" + return 1 + endif + if(strsearch(device, "_Dev_", 0, 2) == -1) // NI device deviceType = device deviceNumber = "" return !isEmpty(deviceType) && cmpstr(deviceType, "DA") - else - // ITC device notation with X_Dev_Y - deviceType = StringFromList(0,device,"_") - deviceNumber = StringFromList(2,device,"_") - return !isEmpty(deviceType) && !isEmpty(deviceNumber) && cmpstr(deviceType, "DA") endif + + // ITC device notation with X_Dev_Y + deviceType = StringFromList(0,device,"_") + deviceNumber = StringFromList(2,device,"_") + return !isEmpty(deviceType) && !isEmpty(deviceNumber) && cmpstr(deviceType, "DA") End /// @brief Layout the DataBrowser/SweepBrowser graph @@ -2743,7 +2760,7 @@ Function CreateTiledChannelGraph(string graph, WAVE config, variable sweepNo, WA print "Turning off tgs.splitTTLBits as some labnotebook entries could not be found" ControlWindowToFront() tgs.splitTTLBits = 0 - elseif(hardwareType == HARDWARE_NI_DAC) + elseif(hardwareType == HARDWARE_NI_DAC || hardwareType == HARDWARE_SUTTER_DAC) // NI hardware does use one channel per bit so we don't need that here tgs.splitTTLBits = 0 endif @@ -3728,19 +3745,21 @@ threadsafe Function/Wave ExtractOneDimDataFromSweep(config, sweep, index) ASSERT_TS(IsValidSweepAndConfig(sweep, config, configVersion = 0), "Sweep and config are not compatible") + WAVE/T units = AFH_GetChannelUnits(config) if(IsWaveRefWave(sweep)) ASSERT_TS(index < DimSize(sweep, ROWS), "The index is out of range") WAVE/WAVE sweepRef = sweep Duplicate/FREE sweepRef[index], data + if(index < DimSize(units, ROWS)) + ASSERT_TS(!CmpStr(WaveUnits(data, DATADIMENSION), units[index]), "wave units for data in config wave are different from wave units in channel wave (" + WaveUnits(data, -1) + " and " + units[index]) + endif else ASSERT_TS(index < DimSize(sweep, COLS), "The index is out of range") MatrixOP/FREE data = col(sweep, index) - endif - - SetScale/P x, DimOffset(sweep, ROWS), DimDelta(sweep, ROWS), WaveUnits(sweep, ROWS), data - WAVE/T units = AFH_GetChannelUnits(config) - if(index < DimSize(units, ROWS)) - SetScale d, 0, 0, units[index], data + SetScale/P x, DimOffset(sweep, ROWS), DimDelta(sweep, ROWS), WaveUnits(sweep, ROWS), data + if(index < DimSize(units, ROWS)) + SetScale d, 0, 0, units[index], data + endif endif Note data, note(sweep) @@ -4819,9 +4838,9 @@ threadsafe static Function/WAVE GetActiveChannelsTTL(WAVE numericalValues, WAVE index = GetIndexForHeadstageIndepData(numericalValues) hwDACType = GetUsedHWDACFromLNB(numericalValues, sweep) - ASSERT_TS(hwDACType == HARDWARE_ITC_DAC || hwDACType == HARDWARE_NI_DAC, "Unsupported hardware dac type") + ASSERT_TS(hwDACType == HARDWARE_ITC_DAC || hwDACType == HARDWARE_NI_DAC || hwDACType == HARDWARE_SUTTER_DAC, "Unsupported hardware dac type") - if(hwDACType == HARDWARE_NI_DAC) + if(hwDACType == HARDWARE_NI_DAC || hwDACType == HARDWARE_SUTTER_DAC) // present since 2f56481a (DC_MakeNITTLWave: Document TTL settings and rework it completely, 2018-09-06) WAVE/T/Z ttlChannels = GetLastSetting(textualValues, sweep, "TTL channels", DATA_ACQUISITION_MODE) if(!WaveExists(ttlChannels)) @@ -5576,7 +5595,7 @@ Function/WAVE ReplaceWaveWithBackup(WAVE wv, [variable nonExistingBackupIsFatal, return $"" endif - Duplicate/O backup, wv + DuplicateWaveAndKeepTargetRef(backup, wv) if(!keepBackup) KillOrMoveToTrash(wv=backup) @@ -5893,7 +5912,8 @@ Function StartZeroMQSockets([variable forceRestart]) return numTrials End -/// @brief Split an DAQDataWave into one 1D-wave per channel/ttlBit +/// @brief Split an DAQDataWave into one 1D-wave per channel/ttlBit. The old 2D DAQDataWave source format is converted automatically to the +/// current WaveRef format. Thus, the wave reference to sweepWave can get invalid and must be reobtained after splitting. /// /// @param numericalValues numerical labnotebook /// @param sweep sweep number @@ -5901,13 +5921,10 @@ End /// @param configWave DAQConfigWave /// @param targetDFR [optional, defaults to the sweep wave DFR] datafolder where to put the waves, can be a free datafolder /// @param rescale One of @ref TTLRescalingOptions -Function SplitSweepIntoComponents(numericalValues, sweep, sweepWave, configWave, rescale, [targetDFR]) - WAVE numericalValues, sweepWave, configWave - variable sweep, rescale - DFREF targetDFR +Function SplitSweepIntoComponents(WAVE numericalValues, variable sweep, WAVE sweepWave, WAVE configWave, variable rescale, [DFREF targetDFR]) - variable numRows, i, channelNumber, ttlBits - string channelType, str + variable numRows, i, ttlBits, convertSweepWave + string sweepWaveName if(ParamIsDefault(targetDFR)) DFREF targetDFR = GetWavesDataFolderDFR(sweepWave) @@ -5918,29 +5935,58 @@ Function SplitSweepIntoComponents(numericalValues, sweep, sweepWave, configWave, ASSERT(IsValidSweepAndConfig(sweepWave, configWave, configVersion = 0), "Sweep and config waves are not compatible") numRows = DimSize(configWave, ROWS) - for(i = 0; i < numRows; i += 1) - channelType = StringFromList(configWave[i][0], XOP_CHANNEL_NAMES) - ASSERT(!isEmpty(channelType), "empty channel type") - channelNumber = configWave[i][1] - ASSERT(IsFinite(channelNumber), "non-finite channel number") - str = channelType + "_" + num2istr(channelNumber) + convertSweepWave = !IsWaveRefWave(sweepWave) + if(convertSweepWave) + Make/FREE/WAVE/N=(numRows) sweepRef + else + WAVE/WAVE sweepRef = sweepWave + endif - WAVE data = ExtractOneDimDataFromSweep(configWave, sweepWave, i) + Make/FREE/T/N=(numRows) componentNames = GetSweepComponentWaveName(configWave, p) + sweepRef[] = ExtractOneDimDataFromSweep(configWave, sweepWave, i) - if(!cmpstr(channelType, "TTL")) - ttlBits = GetTTLBits(numericalValues, sweep, channelNumber) + for(i = 0; i < numRows; i += 1) + MoveWave sweepRef[i], targetDFR:$componentNames[i] + if(configWave[i][%ChannelType] == XOP_CHANNEL_TYPE_TTL) + ttlBits = GetTTLBits(numericalValues, sweep, configWave[i][%ChannelNumber]) if(IsFinite(ttlBits)) - SplitTTLWaveIntoComponents(data, ttlBits, targetDFR, str + "_", rescale) + SplitTTLWaveIntoComponents(sweepRef[i], ttlBits, targetDFR, componentNames[i] + "_", rescale) endif endif - - MoveWave data, targetDFR:$str endfor - string/G targetDFR:note = note(sweepWave) + DFREF sweepWaveDFR = GetWavesDataFolderDFR(sweepWave) + sweepWaveName = NameOfWave(sweepWave) + if(convertSweepWave) + note/K sweepRef, note(sweepWave) + CopyScales sweepWave, sweepRef + WAVE/Z wv = sweepWaveDFR:$sweepWaveName + if(WaveExists(wv)) + KillOrMoveToTrash(wv = wv) + endif + MoveWave sweepRef, sweepWaveDFR:$sweepWaveName + endif + CreateBackupWavesForAll(targetDFR) + componentNames[] = componentNames[p] + WAVE_BACKUP_SUFFIX + sweepWaveName = sweepWaveName + WAVE_BACKUP_SUFFIX + Duplicate sweepRef, sweepWaveDFR:$sweepWaveName + WAVE/WAVE bakSweepData = sweepWaveDFR:$sweepWaveName + bakSweepData[] = targetDFR:$componentNames[p] +End + +Function/S GetSweepComponentWaveName(WAVE config, variable channelIndex) + + string channelType + variable channelNumber + + channelType = StringFromList(config[channelIndex][%ChannelType], XOP_CHANNEL_NAMES) + ASSERT(!isEmpty(channelType), "empty channel type") + channelNumber = config[channelIndex][%ChannelNumber] + ASSERT(IsFinite(channelNumber), "non-finite channel number") + return channelType + "_" + num2istr(channelNumber) End /// @brief Add user data "panelVersion" to the panel @@ -6274,7 +6320,9 @@ threadsafe Function IsValidConfigWave(config, [version]) waveVersion = GetWaveVersion(config) // we know version NaN, 1 and 2, see GetDAQConfigWave() - if(version == 2 && waveVersion >= 2) + if(version == 3 && waveVersion >= 3) + return DimSize(config, ROWS) > 0 && DimSize(config, COLS) >= 8 + elseif(version == 2 && waveVersion >= 2) return DimSize(config, ROWS) > 0 && DimSize(config, COLS) >= 6 elseif(version == 1 && waveVersion >= 1) return DimSize(config, ROWS) > 0 && DimSize(config, COLS) >= 5 @@ -7177,6 +7225,8 @@ static function UploadPing() JSON_AddWave(jsonId2, jsonPath + "/NI", NIDevices) WAVE/T ITCDevices = ListToTextWave(DAP_GetITCDeviceList(), ";") JSON_AddWave(jsonId2, jsonPath + "/ITC", ITCDevices) + WAVE/T SUDevices = ListToTextWave(DAP_GetSUDeviceList(), ";") + JSON_AddWave(jsonId2, jsonPath + "/SU", SUDevices) payLoad = JSON_Dump(jsonId2, indent=2) JSON_Release(jsonId2) @@ -8500,3 +8550,131 @@ Function ArchiveLogFilesOnceAndKeepMonth() endif endfor End + +Function SplitSweepsIfReq(string device, variable sweepNo) + + [WAVE sweepWave, WAVE configWave] = GetSweepAndConfigWaveFromDevice(device, sweepNo) + + if(!SweepRequiresNewSplitting(device, sweepNo)) + return 0 + endif + + DFREF deviceDFR = GetDeviceDataPath(device) + DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) + KillOrMoveToTrash(dfr = singleSweepDFR) + + DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) + WAVE numericalValues = GetLogbookWaves(LBT_LABNOTEBOOK, LBN_NUMERICAL_VALUES, device = device) + + SplitSweepIntoComponents(numericalValues, sweepNo, sweepWave, configWave, TTL_RESCALE_ON, targetDFR=singleSweepDFR) + + return 0 +End + +Function [WAVE sweepWave, WAVE config] GetSweepAndConfigWaveFromDevice(string device, variable sweepNo) + + WAVE/Z sweepWave = GetSweepWave(device, sweepNo) + ASSERT(WaveExists(sweepWave), "Could not find sweep " + num2istr(sweepNo) + " for device " + device + " .") + WAVE config = GetConfigWave(sweepWave) + + return [sweepWave, config] +End + +static Function SweepRequiresNewSplitting(string device, variable sweepNo) + + variable sweepModTime, numWaves, requireNewSplit, i + variable numBackupWaves + + DFREF deviceDFR = GetDeviceDataPath(device) + DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) + WAVE/Z sweepWave = GetSweepWave(device, sweepNo) + ASSERT(WaveExists(sweepWave), "Could not resolve sweep wave") + WAVE configWave = GetConfigWave(sweepWave) + + sweepModTime = max(ModDate(sweepWave), ModDate(configWave)) + numWaves = CountObjectsDFR(singleSweepDFR, COUNTOBJECTS_WAVES) + requireNewSplit = (numWaves == 0) + + for(i = 0; i < numWaves; i += 1) + WAVE/SDFR=singleSweepDFR wv = $GetIndexedObjNameDFR(singleSweepDFR, COUNTOBJECTS_WAVES, i) + if(sweepModTime > ModDate(wv)) + // @todo: Do we need this check here still or was it ONLY for sweeprollback? + // original sweep was modified, regenerate single sweep waves + KillOrMoveToTrash(dfr=singleSweepDFR) + DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) + requireNewSplit = 1 + break + endif + if(GrepString(NameOfWave(wv), "\\Q" + WAVE_BACKUP_SUFFIX + "\\E$")) + numBackupWaves += 1 + endif + endfor + + if(!requireNewSplit && (numBackupWaves * 2 == numWaves)) + return 0 + endif + + return 1 +End + +Function GetFirstADCChannelIndex(WAVE config) + + variable col + + col = FindDimlabel(config, COLS, "ChannelType") + ASSERT(col >= 0, "Could not find ChannelType column in config wave") + FindValue/RMD=[][col]/V=(XOP_CHANNEL_TYPE_ADC) config + ASSERT(V_value >= 0, "Could not find any XOP_CHANNEL_TYPE_ADC channel") + + return V_row +End + +Function [variable plannedTime, variable acquiredTime] GetActualAcquisitionTimes(string device, variable sweepNo) + + variable firstADCIndex + + DFREF deviceDFR = GetDeviceDataPath(device) + DFREF singleSweepDFR = GetSingleSweepFolder(deviceDFR, sweepNo) + + [WAVE sweepWave, WAVE config] = GetSweepAndConfigWaveFromDevice(device, sweepNo) + + firstADCIndex = GetFirstADCChannelIndex(config) + WAVE channel = GetDAQDataSingleColumnWave(singleSweepDFR, XOP_CHANNEL_TYPE_ADC, config[firstADCIndex][%ChannelNumber]) + + plannedTime = IndexToScale(channel, DimSize(channel, ROWS) - 1, ROWS) * MILLI_TO_ONE + // in case the acquisition was stopped early, there are remaining NaNs at the end + if(!IsNaN(channel[inf])) + return [plannedTime, plannedTime] + endif + + FindValue/FNAN channel + ASSERT(V_row >= 0, "Unexpected result") + acquiredTime = IndexToScale(channel, max(V_row - 1, 0), ROWS) * MILLI_TO_ONE + + return [plannedTime, acquiredTime] +End + +static Function FindSUFifoPos(WAVE entries) + + variable l, r, m + + r = DimSize(entries, ROWS) + for(;l < r;) + m = trunc((l + r) / 2) + if(IsNaN(entries[m])) + r = m + else + l = m + 1 + endif + endfor + + return r +End + +Function GetSUFifoPos(string device) + + WAVE/WAVE SUDataWave = GetDAQDataWave(device, DATA_ACQUISITION_MODE) + WAVE config = GetDAQConfigWave(device) + return FindSUFifoPos(SUDataWave[GetFirstADCChannelIndex(config)]) + +End diff --git a/Packages/MIES/MIES_Oscilloscope.ipf b/Packages/MIES/MIES_Oscilloscope.ipf index efe4ea8710..0beb132fbf 100644 --- a/Packages/MIES/MIES_Oscilloscope.ipf +++ b/Packages/MIES/MIES_Oscilloscope.ipf @@ -190,7 +190,7 @@ static Function [variable showSteadyStateResistance, variable showPeakResistance showPeakResistance = DAG_GetNumericalValue(device, "check_settings_TP_show_peak") showSteadyStateResistance = DAG_GetNumericalValue(device, "check_settings_TP_show_steady") - showPowerSpectrum = dataAcqOrTP == TEST_PULSE_MODE && DAG_GetNumericalValue(device, "check_settings_show_power") + showPowerSpectrum = DAG_GetNumericalValue(device, "check_settings_show_power") End Function SCOPE_CreateGraph(device, dataAcqOrTP) @@ -204,7 +204,7 @@ Function SCOPE_CreateGraph(device, dataAcqOrTP) string steadyStateTrace, peakTrace, adcStr variable YaxisLow, YaxisHigh, YaxisSpacing, Yoffset, resPosPercY variable testPulseLength, cutOff, sampInt, axisMinTop, axisMaxTop - variable headStage, activeHeadStage, showPowerSpectrum, baselineFrac, pulseLength + variable headStage, activeHeadStage, showPowerSpectrum, baselineFrac, pulseLength, pointsAcq STRUCT RGBColor peakColor STRUCT RGBColor steadyColor @@ -382,9 +382,9 @@ Function SCOPE_CreateGraph(device, dataAcqOrTP) endif if(gotDAQChan) Label/W=$graph bottomDAQ "Time DAQ (\\U)" - NVAR stopCollectionPoint = $GetStopCollectionPoint(device) + pointsAcq = HW_GetEffectiveADCWaveLength(device, dataAcqOrTP) sampInt = DAP_GetSampInt(device, DATA_ACQUISITION_MODE, XOP_CHANNEL_TYPE_ADC) * MICRO_TO_MILLI - SetAxis/W=$graph bottomDAQ, 0, stopCollectionPoint * sampInt + SetAxis/W=$graph bottomDAQ, 0, pointsAcq * sampInt ModifyGraph/W=$graph freePos(bottomDAQ)=-35 endif End @@ -444,23 +444,20 @@ Function SCOPE_SetADAxisLabel(device, dataAcqOrTP, activeHeadStage) endfor End -static Function SCOPE_UpdatePowerSpectrum(device) - String device - - variable startOfADColumns, numADCs +static Function SCOPE_UpdatePowerSpectrum(string device, WAVE columns, [WAVE osci]) if(DAG_GetNumericalValue(device, "check_settings_show_power")) - WAVE OscilloscopeData = GetOscilloscopeWave(device) + if(ParamIsDefault(osci)) + WAVE OscilloscopeData = GetOscilloscopeWave(device) + else + WAVE OscilloscopeData = osci + endif WAVE TPOscilloscopeData = GetTPOscilloscopeWave(device) - startOfADColumns = ROVar(GetADChannelToMonitor(device)) - numADCs = DimSize(OscilloscopeData, COLS) - startOfADColumns // FFT knows how to transform units without prefix so transform them temporarly SetScale/P x, DimOffset(OscilloscopeData, ROWS) * MILLI_TO_ONE, DimDelta(OscilloscopeData, ROWS) * MILLI_TO_ONE, "s", OscilloscopeData - Make/FREE/N=(numADCs) junk - - MultiThread junk[] = DoPowerSpectrum(OscilloscopeData, TPOscilloscopeData, (startOfADColumns + p)) + MultiThread columns[] = DoPowerSpectrum(OscilloscopeData, TPOscilloscopeData, columns[p]) SetScale/P x, DimOffset(OscilloscopeData, ROWS) * ONE_TO_MILLI, DimDelta(OscilloscopeData, ROWS) * ONE_TO_MILLI, "ms", OscilloscopeData endif @@ -481,11 +478,10 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi variable dataAcqOrTP, chunk, fifoPos, deviceID STRUCT TPAnalysisInput tpInput - string osciUnits variable i, j variable tpChannels, numADCs, numDACs, tpLengthPoints, tpStart, tpEnd, tpStartPos - variable TPChanIndex, saveTP, sampleInt, clampAmp - variable headstage, fifoLatest + variable TPChanIndex, saveTP, clampAmp + variable headstage, fifoLatest, channelIndex string hsList variable hardwareType = GetHardwareType(device) @@ -508,6 +504,18 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi ASSERT(!ParamIsDefault(deviceID), "optional parameter deviceID missing (required for NI devices in TP mode)") SCOPE_NI_UpdateOscilloscope(device, dataAcqOrTP, deviceID, fifoPos) break + case HARDWARE_SUTTER_DAC: + if(dataAcqOrTP == TEST_PULSE_MODE) + ASSERT(!ParamIsDefault(chunk), "optional parameter chunk is missing with TEST_PULSE_MODE") + ASSERT(ParamIsDefault(fifoPos), "optional parameter fifoPos is not possible with TEST_PULSE_MODE") + elseif(dataAcqOrTP == DATA_ACQUISITION_MODE) + ASSERT(!ParamIsDefault(fifoPos), "optional parameter fifoPos missing") + ASSERT(ParamIsDefault(chunk), "optional parameter chunk is not possible with DATA_ACQUISITION_MODE") + endif + SCOPE_SU_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos) + break + default: + ASSERT(0, "Unsupported hardware type") endswitch WAVE config = GetDAQConfigWave(device) @@ -522,7 +530,7 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi WAVE TPSettings = GetTPSettings(device) WAVE TPSettingsCalc = GetTPSettingsCalculated(device) - tpLengthPoints = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%totalLengthPointsTP] : TPSettingsCalc[%totalLengthPointsDAQ] + tpLengthPoints = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%totalLengthPointsTP_ADC] : TPSettingsCalc[%totalLengthPointsDAQ_ADC] // use a 'virtual' end position for fifoLatest for TP Mode since the input data contains one TP only fifoLatest = (dataAcqOrTP == TEST_PULSE_MODE) ? tpLengthPoints : fifoPos @@ -531,19 +539,16 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi WAVE DACs = GetDACListFromConfig(config) WAVE hsProp = GetHSProperties(device) - WAVE scaledDataWave = GetScaledDataWave(device) - sampleInt = DimDelta(scaledDataWave, ROWS) - osciUnits = WaveUnits(scaledDataWave, ROWS) + WAVE/WAVE scaledDataWave = GetScaledDataWave(device) numDACs = DimSize(DACs, ROWS) numADCs = DimSize(ADCs, ROWS) // note: currently this works for multiplier = 1 only, see DC_PlaceDataInDAQDataWave Make/FREE/N=(tpLengthPoints) channelData WAVE tpInput.data = channelData - SetScale/P x, 0, sampleInt, osciUnits, channelData tpInput.device = device - tpInput.duration = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%pulseLengthPointsTP] : TPSettingsCalc[%pulseLengthPointsDAQ] + tpInput.duration = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%pulseLengthPointsTP_ADC] : TPSettingsCalc[%pulseLengthPointsDAQ_ADC] tpInput.baselineFrac = TPSettingsCalc[%baselineFrac] tpInput.tpLengthPoints = tpLengthPoints tpInput.readTimeStamp = ticks * TICKS_TO_SECONDS @@ -565,8 +570,12 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi tpStartPos = i * tpLengthPoints if(saveTP) - Duplicate/FREE/R=[tpStartPos, tpStartPos + tpLengthPoints - 1][numDACs, numDACs + tpChannels - 1] scaledDataWave, StoreTPWave - SetScale/P x, 0, sampleInt, osciUnits, StoreTPWave + Make/FREE/D/N=(tpLengthPoints, tpChannels) StoreTPWave + for(j = 0; j < tpChannels; j += 1) + WAVE scaledChannel = scaledDataWave[numDACs + j] + Multithread StoreTPWave[][j] = scaledChannel[tpStartPos + p] + endfor + CopyScales/P scaledChannel, StoreTPWave TPChanIndex = 0 hsList = "" endif @@ -574,7 +583,9 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi for(j = 0; j < numADCs; j += 1) if(ADCmode[j] == DAQ_CHANNEL_TYPE_TP) - MultiThread channelData[] = scaledDataWave[tpStartPos + p][numDACs + j] + WAVE scaledChannel = scaledDataWave[numDACs + j] + MultiThread channelData[] = scaledChannel[tpStartPos + p] + CopyScales/P scaledChannel, channelData headstage = AFH_GetHeadstageFromADC(device, ADCs[j]) if(hsProp[headstage][%ClampMode] == I_CLAMP_MODE) @@ -610,12 +621,35 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi endfor - if(dataAcqOrTP == DATA_ACQUISITION_MODE) - WAVE TPOscilloscopeData = GetTPOscilloscopeWave(device) - Duplicate/O/R=[tpStartPos, tpStartPos + tpLengthPoints - 1][] scaledDataWave TPOscilloscopeData - SetScale/P x, 0, sampleInt, osciUnits, TPOscilloscopeData + if(dataAcqOrTP == DATA_ACQUISITION_MODE && tpEnd > tpStart) + tpStartPos = (tpEnd - 1) * tpLengthPoints + if(DAG_GetNumericalValue(device, "check_settings_show_power")) + WAVE tpOsciForPowerSpectrum = GetScaledTPTempWave(device) + Make/FREE/D/N=(numADCs) tpColumns + j = 0 + for(i = 0; i < numADCs; i += 1) + if(ADCmode[i] == DAQ_CHANNEL_TYPE_TP) + channelIndex = numDACs + i + WAVE scaledChannel = scaledDataWave[channelIndex] + MultiThread tpOsciForPowerSpectrum[][channelIndex] = scaledChannel[tpStartPos + p] + tpColumns[j] = channelIndex + j += 1 + endif + CopyScales/P scaledChannel, tpOsciForPowerSpectrum + endfor + Redimension/N=(j) tpColumns + SCOPE_UpdatePowerSpectrum(device, tpColumns, osci=tpOsciForPowerSpectrum) + else + WAVE TPOscilloscopeData = GetTPOscilloscopeWave(device) + for(i = 0; i < numADCs; i += 1) + if(ADCmode[i] == DAQ_CHANNEL_TYPE_TP) + channelIndex = numDACs + i + WAVE scaledChannel = scaledDataWave[channelIndex] + MultiThread TPOscilloscopeData[][channelIndex] = scaledChannel[tpStartPos + p] + endif + endfor + endif endif - endif // Sync fifo position @@ -624,43 +658,115 @@ Function SCOPE_UpdateOscilloscopeData(device, dataAcqOrTP, [chunk, fifoPos, devi ASYNC_ThreadReadOut() End +static Function SCOPE_SU_UpdateOscilloscope(string device, variable dataAcqOrTP, variable chunk, variable fifoPos) + + variable i, decMethod, decFactor, gain, numCols, lastRow + variable startOfADColumns, endOfADColumns, first, last, length + string msg + + WAVE/WAVE scaledDataWave = GetScaledDataWave(device) + WAVE OscilloscopeData = GetOscilloscopeWave(device) + WAVE/WAVE SUDataWave = GetDAQDataWave(device, dataAcqOrTP) + WAVE config = GetDAQConfigWave(device) + WAVE ADCs = GetADCListFromConfig(config) + WAVE DACs = GetDACListFromConfig(config) + startOfADColumns = DimSize(DACs, ROWS) + endOfADColumns = startOfADColumns + DimSize(ADCs, ROWS) + + if(dataAcqOrTP == TEST_PULSE_MODE) + WAVE TPSettingsCalc = GetTPSettingsCalculated(device) + length = TPSettingsCalc[%totalLengthPointsTP_ADC] + first = chunk * length + last = first + length - 1 + + ASSERT(first >= 0 && first < last, "Invalid wave subrange") + // update a full pulse + for(i = startOfADColumns; i < endOfADColumns; i += 1) + WAVE SUChannel = SUDataWave[i] + WAVE scaledChannel = scaledDataWave[i] + ASSERT(last < DimSize(SUChannel, ROWS), "Invalid wave subrange") + + Multithread OscilloscopeData[][i] = SUChannel[first + p] + Multithread scaledChannel[] = SUChannel[first + p] + endfor + Make/FREE/N=(DimSize(ADCs, ROWS)) tpColumns + tpColumns[] = startOfADColumns + p + SCOPE_UpdatePowerSpectrum(device, tpColumns) + elseif(dataAcqOrTP == DATA_ACQUISITION_MODE) + NVAR fifoPosGlobal = $GetFifoPosition(device) + + for(i = startOfADColumns; i < endOfADColumns; i += 1) + WAVE SUChannel = SUDataWave[i] + WAVE scaledChannel = scaledDataWave[i] + + AssertOnAndClearRTError() + try + Multithread scaledChannel[fifoPosGlobal, fifoPos - 1] = SUChannel[p]; AbortOnRTE + catch + sprintf msg, "Writing scaledDataWave failed, please save the experiment and file a bug report: scaledDataWave rows %g\r", DimSize(scaledDataWave, ROWS) + ASSERT(0, msg) + endtry + endfor + + decMethod = GetNumberFromWaveNote(OscilloscopeData, "DecimationMethod") + decFactor = GetNumberFromWaveNote(OscilloscopeData, "DecimationFactor") + + for(i = startOfADColumns; i < endOfADColumns; i += 1) + WAVE SUChannel = SUDataWave[i] + + switch(decMethod) + case DECIMATION_NONE: + Multithread OscilloscopeData[fifoPosGlobal, fifoPos - 1][i] = SUChannel[p] + break + default: + DecimateWithMethod(SUChannel, OscilloscopeData, decFactor, decMethod, firstRowInp = fifoPosGlobal, lastRowInp = fifoPos - 1, firstColInp = 0, lastColInp = 0, firstColOut = i, lastColOut = i) + break + endswitch + endfor + endif +End + static Function SCOPE_NI_UpdateOscilloscope(device, dataAcqOrTP, deviceiD, fifoPos) string device variable dataAcqOrTP, deviceID, fifoPos - variable i, channel, decMethod, decFactor, gain, numCols - string fifoName, msg + variable i, channel, decMethod, decFactor, gain, numCols, numFifoChannels + string fifoName, msg, fifoInfo - WAVE scaledDataWave = GetScaledDataWave(device) + WAVE/WAVE scaledDataWave = GetScaledDataWave(device) WAVE OscilloscopeData = GetOscilloscopeWave(device) WAVE/WAVE NIDataWave = GetDAQDataWave(device, dataAcqOrTP) fifoName = GetNIFIFOName(deviceID) FIFOStatus/Q $fifoName ASSERT(V_Flag != 0, "FIFO does not exist!") + numFifoChannels = V_FIFOnchans + fifoInfo = S_info if(dataAcqOrTP == TEST_PULSE_MODE) // update a full pulse - for(i = 0; i < V_FIFOnchans; i += 1) - channel = NumberByKey("NAME" + num2str(i), S_Info) + Make/FREE/N=(numFifoChannels) tpColumns + for(i = 0; i < numFifoChannels; i += 1) + channel = NumberByKey("NAME" + num2istr(i), fifoInfo) WAVE NIChannel = NIDataWave[channel] - multithread OscilloscopeData[][channel] = NIChannel[p] - Multithread scaledDataWave[][] = OscilloscopeData + WAVE scaledChannel = scaledDataWave[channel] + Multithread OscilloscopeData[][channel] = NIChannel[p] + Multithread scaledChannel[] = NIChannel[p] + tpColumns[i] = channel endfor - SCOPE_UpdatePowerSpectrum(device) + SCOPE_UpdatePowerSpectrum(device, tpColumns) elseif(dataAcqOrTP == DATA_ACQUISITION_MODE) // it is in this moment the previous fifo position, so the new data goes from here to fifoPos-1 NVAR fifoPosGlobal = $GetFifoPosition(device) - WAVE allGain = SWS_GetChannelGains(device, timing = GAIN_AFTER_DAQ) numCols = DimSize(scaledDataWave, COLS) - for(i = 0; i < numCols; i += 1) - WAVE NIChannel = NIDataWave[i] - - gain = allGain[i] + for(i = 0; i < numFifoChannels; i += 1) + channel = NumberByKey("NAME" + num2istr(i), fifoInfo) + WAVE NIChannel = NIDataWave[channel] + WAVE scaledChannel = scaledDataWave[channel] AssertOnAndClearRTError() try - Multithread scaledDataWave[fifoPosGlobal, fifoPos - 1][i] = NIChannel[p] / gain; AbortOnRTE + Multithread scaledChannel[fifoPosGlobal, fifoPos - 1] = NIChannel[p]; AbortOnRTE catch sprintf msg, "Writing scaledDataWave failed, please save the experiment and file a bug report: fifoPosGlobal %g, fifoPos %g, scaledDataWave rows %g, stopCollectionPoint %g\r", fifoPosGlobal, fifoPos, DimSize(scaledDataWave, ROWS), ROVAR(GetStopCollectionPoint(device)) ASSERT(0, msg) @@ -670,8 +776,8 @@ static Function SCOPE_NI_UpdateOscilloscope(device, dataAcqOrTP, deviceiD, fifoP decMethod = GetNumberFromWaveNote(OscilloscopeData, "DecimationMethod") decFactor = GetNumberFromWaveNote(OscilloscopeData, "DecimationFactor") - for(i = 0; i < V_FIFOnchans; i += 1) - channel = NumberByKey("NAME" + num2str(i), S_Info) + for(i = 0; i < numFifoChannels; i += 1) + channel = NumberByKey("NAME" + num2str(i), fifoInfo) WAVE NIChannel = NIDataWave[channel] switch(decMethod) @@ -692,21 +798,21 @@ static Function SCOPE_ITC_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos WAVE OscilloscopeData = GetOscilloscopeWave(device) variable length, first, last - variable startOfADColumns, numEntries, decMethod, decFactor + variable startOfADColumns, endOfADColumns, decMethod, decFactor, i, numChannels string msg - WAVE scaledDataWave = GetScaledDataWave(device) + WAVE/WAVE scaledDataWave = GetScaledDataWave(device) WAVE DAQDataWave = GetDAQDataWave(device, dataAcqOrTP) WAVE DAQConfigWave = GetDAQConfigWave(device) WAVE ADCs = GetADCListFromConfig(DAQConfigWave) WAVE DACs = GetDACListFromConfig(DAQConfigWave) startOfADColumns = DimSize(DACs, ROWS) - numEntries = DimSize(ADCs, ROWS) + endOfADColumns = startOfADColumns + DimSize(ADCs, ROWS) WAVE allGain = SWS_GETChannelGains(device, timing = GAIN_AFTER_DAQ) if(dataAcqOrTP == TEST_PULSE_MODE) WAVE TPSettingsCalc = GetTPSettingsCalculated(device) - length = TPSettingsCalc[%totalLengthPointsTP] + length = TPSettingsCalc[%totalLengthPointsTP_ADC] first = chunk * length last = first + length - 1 ASSERT(first >= 0 && last < DimSize(DAQDataWave, ROWS) && first < last, "Invalid wave subrange") @@ -724,10 +830,15 @@ static Function SCOPE_ITC_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos endif #endif - Multithread OscilloscopeData[][startOfADColumns, startOfADColumns + numEntries - 1] = DAQDataWave[first + p][q] / allGain[q] - Multithread scaledDataWave[][] = OscilloscopeData + Multithread OscilloscopeData[][startOfADColumns, endOfADColumns - 1] = DAQDataWave[first + p][q] / allGain[q] + for(i = startOfADColumns; i < endOfADColumns; i += 1) + WAVE scaledChannel = scaledDataWave[i] + Multithread scaledChannel[] = OscilloscopeData[p][i] + endfor - SCOPE_UpdatePowerSpectrum(device) + Make/FREE/N=(DimSize(ADCs, ROWS)) tpColumns + tpColumns[] = startOfADColumns + p + SCOPE_UpdatePowerSpectrum(device, tpColumns) elseif(dataAcqOrTP == DATA_ACQUISITION_MODE) @@ -741,11 +852,15 @@ static Function SCOPE_ITC_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos return NaN endif + numChannels = DimSize(scaledDataWave, ROWS) AssertOnAndClearRTError() try - Multithread scaledDataWave[fifoPosGlobal, fifoPos - 1][] = DAQDataWave[p][q] / allGain[q]; AbortOnRTE + for(i = 0; i < numChannels; i += 1) + WAVE scaledChannel = scaledDataWave[i] + Multithread scaledChannel[fifoPosGlobal, fifoPos - 1] = DAQDataWave[p][i] / allGain[i]; AbortOnRTE + endfor catch - sprintf msg, "Writing scaledDataWave failed, please save the experiment and file a bug report: fifoPosGlobal %g, fifoPos %g, scaledDataWave rows %g, stopCollectionPoint %g\r", fifoPosGlobal, fifoPos, DimSize(scaledDataWave, ROWS), ROVAR(GetStopCollectionPoint(device)) + sprintf msg, "Writing scaledDataWave failed, please save the experiment and file a bug report: fifoPosGlobal %g, fifoPos %g, Channel Index %d, scaledChannelWave rows %g, stopCollectionPoint %g\r", fifoPosGlobal, fifoPos, i, DimSize(scaledChannel, ROWS), ROVAR(GetStopCollectionPoint(device)) ASSERT(0, msg) endtry @@ -754,12 +869,12 @@ static Function SCOPE_ITC_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos switch(decMethod) case DECIMATION_NONE: - Multithread OscilloscopeData[fifoPosGlobal, fifoPos - 1][startOfADColumns, startOfADColumns + numEntries - 1] = DAQDataWave[p][q] / allGain[q] + Multithread OscilloscopeData[fifoPosGlobal, fifoPos - 1][startOfADColumns, endOfADColumns - 1] = DAQDataWave[p][q] / allGain[q] break default: - Duplicate/FREE/RMD=[startOfADColumns, startOfADColumns + numEntries - 1] allGain, gain + Duplicate/FREE/RMD=[startOfADColumns, endOfADColumns - 1] allGain, gain gain[] = 1 / gain[p] - DecimateWithMethod(DAQDataWave, OscilloscopeData, decFactor, decMethod, firstRowInp = fifoPosGlobal, lastRowInp = fifoPos - 1, firstColInp = startOfADColumns, lastColInp = startOfADColumns + numEntries - 1, factor = gain) + DecimateWithMethod(DAQDataWave, OscilloscopeData, decFactor, decMethod, firstRowInp = fifoPosGlobal, lastRowInp = fifoPos - 1, firstColInp = startOfADColumns, lastColInp = endOfADColumns - 1, factor = gain) endswitch else ASSERT(0, "Invalid dataAcqOrTP value") diff --git a/Packages/MIES/MIES_PressureControl.ipf b/Packages/MIES/MIES_PressureControl.ipf index ed7ed1214a..b12193fcbd 100644 --- a/Packages/MIES/MIES_PressureControl.ipf +++ b/Packages/MIES/MIES_PressureControl.ipf @@ -2343,7 +2343,7 @@ Function ButtonProc_Hrdwr_P_UpdtDAClist(ba) : ButtonControl switch(ba.eventCode) case 2: // mouse up string filteredList = "" - string DeviceList = NONE + ";" + DAP_GetITCDeviceList() + HW_NI_ListDevices() + string DeviceList = NONE + ";" + DAP_GetITCDeviceList() + HW_NI_ListDevices() + HW_SU_ListDevices() string lockedList = GetListOfLockedDevices() string dev variable nrDevs = ItemsInList(DeviceList) diff --git a/Packages/MIES/MIES_SamplingInterval.ipf b/Packages/MIES/MIES_SamplingInterval.ipf index e76f1c4121..2bf74ac5bb 100644 --- a/Packages/MIES/MIES_SamplingInterval.ipf +++ b/Packages/MIES/MIES_SamplingInterval.ipf @@ -509,6 +509,7 @@ End Function SI_CalculateMinSampInterval(string device, variable dataAcqOrTP, variable channelType) variable hardwareType = GetHardwareType(device) + switch(hardwareType) case HARDWARE_ITC_DAC: return SI_ITC_CalculateMinSampInterval(device, dataAcqOrTP) @@ -516,6 +517,9 @@ Function SI_CalculateMinSampInterval(string device, variable dataAcqOrTP, variab case HARDWARE_NI_DAC: return SI_NI_CalculateMinSampInterval(device) break + case HARDWARE_SUTTER_DAC: + return channelType == XOP_CHANNEL_TYPE_ADC ? HARDWARE_SU_MIN_SAMPINT_ADC * MILLI_TO_MICRO : HARDWARE_SU_MIN_SAMPINT_DAC * MILLI_TO_MICRO + break endswitch End diff --git a/Packages/MIES/MIES_SweepSaving.ipf b/Packages/MIES/MIES_SweepSaving.ipf index 156c56d57e..8cbf49b994 100644 --- a/Packages/MIES/MIES_SweepSaving.ipf +++ b/Packages/MIES/MIES_SweepSaving.ipf @@ -47,10 +47,9 @@ Function SWS_SaveAcquiredData(device, [forcedStop]) Duplicate hardwareConfigWave, dfr:$configName MoveWave scaledDataWave, dfr:$sweepName - WAVE sweepWave = GetSweepWave(device, sweepNo) - WAVE configWave = GetConfigWave(sweepWave) + SplitSweepsIfReq(device, sweepNo) - EP_WriteEpochInfoIntoSweepSettings(device, sweepWave, configWave) + EP_WriteEpochInfoIntoSweepSettings(device, sweepNo) // Add labnotebook entries for the acquired sweep ED_createWaveNoteTags(device, sweepNo) @@ -58,6 +57,7 @@ Function SWS_SaveAcquiredData(device, [forcedStop]) EP_CopyLBNEpochsToEpochsWave(device, sweepNo) if(DAG_GetNumericalValue(device, "Check_Settings_NwbExport")) + [WAVE sweepWave, WAVE configWave] = GetSweepAndConfigWaveFromDevice(device, sweepNo) NWB_AppendSweepDuringDAQ(device, sweepWave, configWave, sweepNo, str2num(DAG_GetTextualValue(device, "Popup_Settings_NwbVersion"))) endif @@ -71,7 +71,7 @@ Function SWS_SaveAcquiredData(device, [forcedStop]) AFM_CallAnalysisFunctions(device, POST_SET_EVENT) endif - EP_WriteEpochInfoIntoSweepSettings(device, sweepWave, configWave) + EP_WriteEpochInfoIntoSweepSettings(device, sweepNo) SWS_SweepSettingsEpochInfoToLBN(device, sweepNo) End @@ -127,10 +127,23 @@ End /// NI DA None /// NI AD Scaled directly on acquisition. /// NI TTL One channel per TTL bit. +/// SU DA None +/// SU AD Scaled directly on acquisition. +/// SU TTL One channel per TTL bit. /// ========== ========= =============================================== /// /// \endrst /// +/// With GAIN_BEFORE_DAQ the function returns the gain factor for all channels. +/// With GAIN_AFTER_DAC the gain factor for ADC channels is returned as 1. +/// Gain handling for NI: +/// In dataconfigurator setup DAC_values = data(before_DAQ) * gain_factor(DAC_channel) @sa DC_FillDAQDataWaveForDAQ +/// at acquisition time done by hardware ADC_values = data(acquired_by_ADC) * gain_factor(ADC_channel) @sa HW_NI_PrepareAcq +/// at acquisition time on readout: +/// oscilloscopeValues = DAC_values +/// scaledValues = DAC_values / gain_factor(DAC_channel) +/// ADC_values are NOT changed, thus a gain factor of 1 is used when calculcation indexes over all DAC, ADC, TTL channels. @sa SCOPE_NI_UpdateOscilloscope +/// /// @param device device /// @param timing One of @ref GainTimeParameter /// @@ -160,7 +173,8 @@ Function/WAVE SWS_GetChannelGains(device, [timing]) hardwareType = GetHardwareType(device) switch(hardwareType) - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: // in mV^-1, w'(V) = w * g if(numDACs > 0) gain[0, numDACs - 1] = 1 / DA_EphysGuiState[DACs[p]][%$GetSpecialControlLabel(CHANNEL_TYPE_DAC, CHANNEL_CONTROL_GAIN)] diff --git a/Packages/MIES/MIES_TestPulse.ipf b/Packages/MIES/MIES_TestPulse.ipf index f6f7b8910f..8667519d3d 100644 --- a/Packages/MIES/MIES_TestPulse.ipf +++ b/Packages/MIES/MIES_TestPulse.ipf @@ -1534,25 +1534,40 @@ Function TP_SendToAnalysis(string device, STRUCT TPAnalysisInput &tpInput) End Function TP_UpdateTPSettingsCalculated(string device) - WAVE TPSettings = GetTPSettings(device) + variable interTPDAC, interDAQDAC, interTPADC, interDAQADC, factorTP, factorDAQ + + WAVE TPSettings = GetTPSettings(device) WAVE calculated = GetTPSettingsCalculated(device) calculated = NaN + interTPDAC = DAP_GetSampInt(device, TEST_PULSE_MODE, XOP_CHANNEL_TYPE_DAC) * MICRO_TO_MILLI + interDAQDAC = DAP_GetSampInt(device, DATA_ACQUISITION_MODE, XOP_CHANNEL_TYPE_DAC) * MICRO_TO_MILLI + interTPADC = DAP_GetSampInt(device, TEST_PULSE_MODE, XOP_CHANNEL_TYPE_ADC) * MICRO_TO_MILLI + interDAQADC = DAP_GetSampInt(device, DATA_ACQUISITION_MODE, XOP_CHANNEL_TYPE_ADC) * MICRO_TO_MILLI + factorTP = interTPDAC / interTPADC + factorDAQ = interDAQDAC / interDAQADC + // update the calculated values calculated[%baselineFrac] = TPSettings[%baselinePerc][INDEP_HEADSTAGE] * PERCENT_TO_ONE calculated[%pulseLengthMS] = TPSettings[%durationMS][INDEP_HEADSTAGE] // here for completeness - calculated[%pulseLengthPointsTP] = trunc(TPSettings[%durationMS][INDEP_HEADSTAGE] / (DAP_GetSampInt(device, TEST_PULSE_MODE, XOP_CHANNEL_TYPE_DAC) * MICRO_TO_MILLI)) - calculated[%pulseLengthPointsDAQ] = trunc(TPSettings[%durationMS][INDEP_HEADSTAGE] / (DAP_GetSampInt(device, DATA_ACQUISITION_MODE, XOP_CHANNEL_TYPE_DAC) * MICRO_TO_MILLI)) + calculated[%pulseLengthPointsTP] = trunc(TPSettings[%durationMS][INDEP_HEADSTAGE] / interTPDAC) + calculated[%pulseLengthPointsDAQ] = trunc(TPSettings[%durationMS][INDEP_HEADSTAGE] / interDAQDAC) + calculated[%pulseLengthPointsTP_ADC] = trunc(calculated[%pulseLengthPointsTP] * factorTP) + calculated[%pulseLengthPointsDAQ_ADC] = trunc(calculated[%pulseLengthPointsDAQ] * factorDAQ) calculated[%totalLengthMS] = TP_CalculateTestPulseLength(calculated[%pulseLengthMS], calculated[%baselineFrac]) calculated[%totalLengthPointsTP] = trunc(TP_CalculateTestPulseLength(calculated[%pulseLengthPointsTP], calculated[%baselineFrac])) calculated[%totalLengthPointsDAQ] = trunc(TP_CalculateTestPulseLength(calculated[%pulseLengthPointsDAQ], calculated[%baselineFrac])) + calculated[%totalLengthPointsTP_ADC] = trunc(calculated[%totalLengthPointsTP] * factorTP) + calculated[%totalLengthPointsDAQ_ADC] = trunc(calculated[%totalLengthPointsDAQ] * factorDAQ) calculated[%pulseStartMS] = calculated[%baselineFrac] * calculated[%totalLengthMS] calculated[%pulseStartPointsTP] = trunc(calculated[%baselineFrac] * calculated[%totalLengthPointsTP]) calculated[%pulseStartPointsDAQ] = trunc(calculated[%baselineFrac] * calculated[%totalLengthPointsDAQ]) + calculated[%pulseStartPointsTP_ADC] = trunc(calculated[%pulseStartPointsTP] * factorTP) + calculated[%pulseStartPointsDAQ_ADC] = trunc(calculated[%pulseStartPointsDAQ] * factorDAQ) End /// @brief Convert from row names of GetTPSettings()/GetTPSettingsCalculated() to GetTPSettingsLBN() column names. diff --git a/Packages/MIES/MIES_TestPulse_Multi.ipf b/Packages/MIES/MIES_TestPulse_Multi.ipf index d052620880..63f8de63ab 100644 --- a/Packages/MIES/MIES_TestPulse_Multi.ipf +++ b/Packages/MIES/MIES_TestPulse_Multi.ipf @@ -95,6 +95,9 @@ static Function TPM_BkrdTPMD(device) NVAR tpCounter = $GetNITestPulseCounter(device) tpCounter = 0 break + case HARDWARE_SUTTER_DAC: + HW_StartAcq(HARDWARE_SUTTER_DAC, deviceID, flags=HARDWARE_ABORT_ON_ERROR) + break endswitch if(!IsBackgroundTaskRunning(TASKNAME_TPMD)) CtrlNamedBackground $TASKNAME_TPMD, start @@ -109,7 +112,7 @@ Function TPM_BkrdTPFuncMD(s) variable i, j, deviceID, fifoPos, hardwareType, checkAgain, updateInt, endOfPulse variable fifoLatest, lastTP, now - variable channelNr, tpLengthPoints, err + variable channelNr, tpLengthPoints, err, doRestart string device, fifoChannelName, fifoName, errMsg variable debTime @@ -138,6 +141,29 @@ Function TPM_BkrdTPFuncMD(s) WAVE TPSettingsCalc = GetTPsettingsCalculated(device) switch(hardwareType) + case HARDWARE_SUTTER_DAC: + if(ROVar(GetSU_AcquisitionError(device))) + LOG_AddEntry(PACKAGE_MIES, "hardware error", stacktrace = 1) + DQ_StopOngoingDAQ(device, DQ_STOP_REASON_HW_ERROR, startTPAfterDAQ = 0) + endif + + fifoLatest = HW_SU_GetADCSamplePosition() + doRestart = HW_GetEffectiveADCWaveLength(device, TEST_PULSE_MODE) == fifoLatest + + lastTP = trunc(fifoLatest / TPSettingsCalc[%totalLengthPointsTP_ADC]) - 1 + if(lastTP >= 0 && lastTP != ActiveDeviceList[i][%ActiveChunk]) + SCOPE_UpdateOscilloscopeData(device, TEST_PULSE_MODE, chunk=lastTP) + ActiveDeviceList[i][%ActiveChunk] = lastTP + endif + + if(doRestart) + HW_SU_StopAcq(deviceId) + ActiveDeviceList[i][%ActiveChunk] = NaN + HW_SU_PrepareAcq(deviceId, TEST_PULSE_MODE) + HW_SU_StartAcq(deviceId) + endif + + break case HARDWARE_NI_DAC: // Pull data until end of FIFO, after BGTask finishes Graph shows only last update do diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index e4d0d5896f..d24784fc6f 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -222,6 +222,12 @@ threadsafe static Function WaveVersionIsAtLeast(wv, existingVersion) return !isNaN(waveVersion) && waveVersion >= existingVersion End +/// @brief Returns 1 if the wave has a valid version information attached, 0 otherwise +threadsafe static Function IsWaveVersioned(WAVE wv) + + return IsValidWaveVersion(GetWaveVersion(wv)) +End + /// @brief Check if the given wave's version is smaller than the given version, if version is not set true is returned threadsafe static Function WaveVersionIsSmaller(wv, existingVersion) WAVE/Z wv @@ -661,6 +667,9 @@ threadsafe Function/S GetDevicePathAsString(device) case HARDWARE_ITC_DAC: return GetDeviceTypePathAsString(deviceType) + ":Device" + deviceNumber break + case HARDWARE_SUTTER_DAC: + return GetDeviceTypePathAsString(deviceType) + break default: ASSERT_TS(0, "Invalid hardware type") endswitch @@ -744,7 +753,7 @@ End /// ITC hardware: /// - 2D signed 16bit integer wave, the colums are for the channel /// -/// NI hardware: +/// NI/SU hardware: /// - Wave reference wave, one referencing each channel /// /// Rows: @@ -789,6 +798,7 @@ Function/Wave GetDAQDataWave(string device, variable mode) Make/W/N=(1, NUM_DA_TTL_CHANNELS) dfr:$name/Wave=wv break case HARDWARE_NI_DAC: + case HARDWARE_SUTTER_DAC: // intended drop through Make/WAVE/N=(NUM_DA_TTL_CHANNELS) dfr:$name/Wave=wv_ni WAVE wv = wv_ni break @@ -799,18 +809,44 @@ Function/Wave GetDAQDataWave(string device, variable mode) return wv End -/// @brief Get the single NI channel waves +Function/WAVE GetSUCompositeTTLWave(string device) + + string name = "SU_OutputTTLComposite" + + DFREF dfr = GetDevicePath(device) + + WAVE/D/Z/SDFR=dfr wv = $name + + if(WaveExists(wv)) + return wv + endif + + Make/D/N=(0) dfr:$name/WAVE=wv + + return wv +End + +/// @brief Get the single NI/Sutter channel waves /// /// Special use function, normal callers should use GetDAQDataWave() /// instead. -Function/WAVE GetNIDAQChannelWave(device, channel, mode) - string device - variable channel - variable mode +Function/WAVE GetNIDAQChannelWave(string device, variable channel, variable mode) - string name + string name, prefix + variable hardwareType = GetHardwareType(device) + + switch (hardwareType) + case HARDWARE_NI_DAC: + prefix = "NI" + break + case HARDWARE_SUTTER_DAC: + prefix = "SU" + break + default: + ASSERT(0, "unsupported device type") + endswitch - name = "NI_Channel" + num2str(channel) + name = prefix + "_Channel" + num2str(channel) switch(mode) case DATA_ACQUISITION_MODE: @@ -940,6 +976,8 @@ End /// - sampling interval in microseconds (1e-6) /// - decimation mode (always zero) /// - data offset +/// - headstage number +/// - clamp mode /// /// The wave note holds a list of channel units. The order /// is the same as the rows. TTL channels don't have units. Querying the @@ -964,12 +1002,17 @@ End /// /// Version 2 changes: /// - DAQChannelType column added +/// +/// Version 3 changes: +/// - Change wave to double precision +/// - Headstage column added +/// - ClampMode column added Function/Wave GetDAQConfigWave(device) string device DFREF dfr = GetDevicePath(device) - WAVE/I/Z/SDFR=dfr wv = DAQConfigWave + WAVE/D/Z/SDFR=dfr wv = DAQConfigWave // On version upgrade also adapt function IsValidConfigWave if(ExistsWithCorrectLayoutVersion(wv, DAQ_CONFIG_WAVE_VERSION)) @@ -989,8 +1032,16 @@ Function/Wave GetDAQConfigWave(device) wv[][5] = DAQ_CHANNEL_TYPE_DAQ Note/K wv endif + if(WaveVersionIsSmaller(wv, 3)) + // this version adds the DAQChannelType column + // In previous version of TPduringDAQ only DAQ type channels existed + Redimension/D/N=(-1, 8) wv + wv[][6] = NaN + wv[][7] = NaN + Note/K wv + endif else - Make/I/N=(2, 6) dfr:DAQConfigWave/Wave=wv + Make/D/N=(2, 8) dfr:DAQConfigWave/WAVE=wv endif SetDimLabel COLS, 0, ChannelType, wv @@ -999,6 +1050,8 @@ Function/Wave GetDAQConfigWave(device) SetDimLabel COLS, 3, DecimationMode, wv SetDimLabel COLS, 4, Offset, wv SetDimLabel COLS, 5, DAQChannelType, wv + SetDimLabel COLS, 6, HEADSTAGE, wv + SetDimLabel COLS, 7, CLAMPMODE, wv SetWaveVersion(wv, DAQ_CONFIG_WAVE_VERSION) AddEntryIntoWaveNoteAsList(wv, CHANNEL_UNIT_KEY, str = "") @@ -1077,7 +1130,8 @@ Function/Wave GetTTLWave(device) return wv break - case HARDWARE_NI_DAC: + case HARDWARE_NI_DAC: // intended drop through + case HARDWARE_SUTTER_DAC: WAVE/WAVE/Z/SDFR=dfr wv_ni = TTLWave if(WaveExists(wv_ni)) @@ -1089,6 +1143,8 @@ Function/Wave GetTTLWave(device) return wv_ni break + default: + ASSERT(0, "Unsupported hardware type") endswitch End @@ -1159,6 +1215,9 @@ Function/S GetDevSpecLabNBFolderAsString(device) case HARDWARE_NI_DAC: return GetLabNotebookFolderAsString() + ":" + deviceType break + case HARDWARE_SUTTER_DAC: + return GetLabNotebookFolderAsString() + ":" + deviceType + break case HARDWARE_ITC_DAC: return GetLabNotebookFolderAsString() + ":" + deviceType + ":Device" + deviceNumber break @@ -2890,6 +2949,21 @@ End /// @brief Return a wave which holds undecimated and scaled data /// +/// ScaledDataWave is initialized in @sa DC_InitScaledDataWave +/// Each channel contains scaled data that takes the gain from the headstage into account. +/// In the channel wave the voltage output to the DAC and read from the ADC is translated back +/// to the headstages input/output signal (e.g. mV / pA). The x-time interval is milliseconds. +/// +/// For ITC on initialization the channels are filled with NaN and the headstages data unit is set. +/// In @sa SCOPE_ITC_UpdateOscilloscope all channels are copied from the DAQDataWave to the scaledDataWave +/// and properly scaled. +/// For NI and Sutter on initialization the non-ADC channels are copied from the DAQDataWave to the scaledDataWave +/// and properly scaled. The ADC channels are scaled by a gain factor that is applied in hardware (or the device XOP). +/// Thus, in @sa SCOPE_NI_UpdateOscilloscope and @sa SCOPE_SU_UpdateOscilloscope the ADC channel data is simply +/// copied from the DAQDataWave to the scaledDataWave. +/// +/// Unversioned Wave: +/// /// Rows: /// - StopCollectionPoint /// @@ -2898,19 +2972,31 @@ End /// /// Type: /// - FP32 or FP64, as returned by SWS_GetRawDataFPType() -Function/Wave GetScaledDataWave(device) - string device +/// +/// Version 1: +/// WAVEREF wave, initially with size 0 +/// sized in @sa DC_MakeHelperWaves to number of hardware channels as in config wave +Function/WAVE GetScaledDataWave(string device) - dfref dfr = GetDevicePath(device) + variable version = 1 + + DFREF dfr = GetDevicePath(device) WAVE/Z/SDFR=dfr wv = ScaledData - if(WaveExists(wv)) + if(ExistsWithCorrectLayoutVersion(wv, version)) return wv + elseif(WaveExists(wv)) + if(!IsWaveVersioned(wv)) + KillOrMoveToTrash(wv=wv) + Make/WAVE/N=0 dfr:ScaledData/WAVE=wv1 + endif + else + Make/WAVE/N=0 dfr:ScaledData/WAVE=wv1 endif - Make/Y=(SWS_GetRawDataFPType(device))/N=(1, NUM_DA_TTL_CHANNELS) dfr:ScaledData/Wave=wv + SetWaveVersion(wv1, version) - return wv + return wv1 End /// @brief Return a wave for displaying scaled data in the oscilloscope window @@ -2931,6 +3017,23 @@ Function/Wave GetOscilloscopeWave(device) return wv End +/// @brief Return a wave for temporary storing scaled data for PowerSpectrum input +Function/WAVE GetScaledTPTempWave(string device) + + string name = "ScaledTPTempWave" + + DFREF dfr = GetDevicePath(device) + WAVE/Z/D/SDFR=dfr wv = $name + + if(WaveExists(wv)) + return wv + endif + + Make/D/N=(1, NUM_DA_TTL_CHANNELS) dfr:$name/WAVE=wv + + return wv +End + /// @brief Return a wave for displaying scaled TP data in the oscilloscope window /// for the "TP during DAQ" channels or for TP power spectrum during Test Pulse /// @@ -5776,14 +5879,14 @@ End Function/WAVE GetDeviceMapping() DFREF dfr = GetDAQDevicesFolder() - variable versionOfNewWave = 2 + variable versionOfNewWave = 3 WAVE/Z/T/SDFR=dfr wv = deviceMapping if(ExistsWithCorrectLayoutVersion(wv, versionOfNewWave)) return wv elseif(WaveExists(wv)) - Redimension/N=(HARDWARE_MAX_DEVICES, -1, 2) wv + Redimension/N=(HARDWARE_MAX_DEVICES, -1, 3) wv else Make/T/N=(HARDWARE_MAX_DEVICES, ItemsInList(HARDWARE_DAC_TYPES), 2) dfr:deviceMapping/Wave=wv endif @@ -5792,6 +5895,7 @@ Function/WAVE GetDeviceMapping() SetDimLabel COLS, 0, ITC_DEVICE, wv SetDimLabel COLS, 1, NI_DEVICE , wv + SetDimLabel COLS, 2, SUTTER_DEVICE , wv SetDimLabel LAYERS, 0, MainDevice , wv SetDimLabel LAYERS, 1, PressureDevice, wv @@ -7555,7 +7659,7 @@ End /// The entries in this wave are only valid during DAQ/TP and are updated via DC_UpdateGlobals(). Function/WAVE GetTPSettingsCalculated(string device) - variable versionOfNewWave = 2 + variable versionOfNewWave = 3 DFREF dfr = GetDeviceTestPulse(device) @@ -7564,13 +7668,34 @@ Function/WAVE GetTPSettingsCalculated(string device) if(ExistsWithCorrectLayoutVersion(wv, versionOfNewWave)) return wv elseif(WaveExists(wv)) - Redimension/N=(10) wv + if(!IsWaveVersioned(wv)) + Redimension/N=(7) wv + SetDimensionLabels(wv, "baselineFrac;pulseLengthMS;pulseLengthPointsTP;pulseLengthPointsDAQ;totalLengthMS;totalLengthPointsTP;totalLengthPointsDAQ;", ROWS) + SetWaveVersion(wv, 1) + endif + if(WaveVersionIsAtLeast(wv, 1)) + Redimension/N=(10) wv + SetDimensionLabels(wv, "baselineFrac;pulseLengthMS;pulseLengthPointsTP;pulseLengthPointsDAQ;totalLengthMS;totalLengthPointsTP;totalLengthPointsDAQ;pulseStartMS;pulseStartPointsTP;pulseStartPointsDAQ;", ROWS) + SetWaveVersion(wv, 2) + endif + if(WaveVersionIsAtLeast(wv, 2)) + Redimension/N=(16) wv + SetDimensionLabels(wv, "baselineFrac;pulseLengthMS;pulseLengthPointsTP;pulseLengthPointsDAQ;totalLengthMS;totalLengthPointsTP;totalLengthPointsDAQ;pulseStartMS;pulseStartPointsTP;pulseStartPointsDAQ;pulseLengthPointsTP_ADC;pulseLengthPointsDAQ_ADC;totalLengthPointsTP_ADC;totalLengthPointsDAQ_ADC;pulseStartPointsTP_ADC;pulseStartPointsDAQ_ADC;", ROWS) + wv[%pulseLengthPointsTP_ADC] = wv[%pulseLengthPointsTP] + wv[%pulseLengthPointsDAQ_ADC] = wv[%pulseLengthPointsDAQ] + wv[%totalLengthPointsTP_ADC] = wv[%totalLengthPointsTP] + wv[%totalLengthPointsDAQ_ADC] = wv[%totalLengthPointsDAQ] + wv[%pulseStartPointsTP_ADC] = wv[%pulseStartPointsTP] + wv[%pulseStartPointsDAQ_ADC] = wv[%pulseStartPointsDAQ] + endif else - Make/N=(10)/D dfr:settingsCalculated/WAVE=wv + Make/N=(16)/D dfr:settingsCalculated/WAVE=wv wv = NaN endif - SetDimensionLabels(wv, "baselineFrac;pulseLengthMS;pulseLengthPointsTP;pulseLengthPointsDAQ;totalLengthMS;totalLengthPointsTP;totalLengthPointsDAQ;pulseStartMS;pulseStartPointsTP;pulseStartPointsDAQ", ROWS) + SetDimensionLabels(wv, "baselineFrac;pulseLengthMS;pulseLengthPointsTP;pulseLengthPointsDAQ;totalLengthMS;totalLengthPointsTP;totalLengthPointsDAQ;pulseStartMS;pulseStartPointsTP;pulseStartPointsDAQ;pulseLengthPointsTP_ADC;pulseLengthPointsDAQ_ADC;totalLengthPointsTP_ADC;totalLengthPointsDAQ_ADC;pulseStartPointsTP_ADC;pulseStartPointsDAQ_ADC;", ROWS) + + SetWaveVersion(wv, versionOfNewWave) return wv End @@ -8118,3 +8243,131 @@ Function/WAVE GetLogFileNames() return files End + +/// @brief Return wave with Sutter device info +/// Rows: +/// NUMBEROFDACS: number of IPA devices +/// MASTERDEVICE: Serial of master device +/// LISTOFDEVICES: Serials of SubDevices +/// LISTOFHEADSTAGES: Number of Headstages per Device +/// SUMHEADSTAGES: Sum of Headstages +/// AI: Number of analog ins +/// AO: Number of analog outs +/// DIOPortWidth: Number of digital outs +Function/WAVE GetSUDeviceInfo() + + variable version = 1 + string name = "SUDeviceInfo" + + DFREF dfr = GetDeviceInfoPath() + + WAVE/Z/SDFR=dfr/T wv = $name + + if(ExistsWithCorrectLayoutVersion(wv, version)) + return wv + elseif(WaveExists(wv)) + // upgrade here + else + Make/T/N=8 dfr:$name/WAVE=wv + endif + + SetDimensionLabels(wv, "NUMBEROFDACS;MASTERDEVICE;LISTOFDEVICES;LISTOFHEADSTAGES;SUMHEADSTAGES;AI;AO;DIOPortWidth;", ROWS) + + return wv +End + +/// @brief Return wave with Sutter input list wave +/// Cols: +/// INPUTWAVE +/// CHANNEL +/// ENCODEINFO +Function/WAVE GetSUDeviceInput(string device) + + variable version = 1 + string name = "SUDeviceInput" + + DFREF dfr = GetDevicePath(device) + + WAVE/Z/SDFR=dfr/T wv = $name + + if(ExistsWithCorrectLayoutVersion(wv, version)) + return wv + elseif(WaveExists(wv)) + // upgrade here + else + Make/T/N=(0, 3) dfr:$name/WAVE=wv + endif + + SetDimensionLabels(wv, "INPUTWAVE;CHANNEL;ENCODEINFO;", COLS) + + return wv +End + +/// @brief Return wave with Sutter output list wave +/// Cols: +/// OUTPUTWAVE +/// CHANNEL +/// ENCODEINFO +Function/WAVE GetSUDeviceOutput(string device) + + variable version = 1 + string name = "SUDeviceOutput" + + DFREF dfr = GetDevicePath(device) + + WAVE/Z/SDFR=dfr/T wv = $name + + if(ExistsWithCorrectLayoutVersion(wv, version)) + return wv + elseif(WaveExists(wv)) + // upgrade here + else + Make/T/N=(0, 3) dfr:$name/WAVE=wv + endif + + SetDimensionLabels(wv, "OUTPUTWAVE;CHANNEL;ENCODEINFO;", COLS) + + return wv +End + +/// @brief Return wave with Sutter gains for input +/// Cols: +/// GAINFACTOR +/// OFFSET +Function/WAVE GetSUDeviceInputGains(string device) + + variable version = 1 + string name = "SUDeviceInputGains" + + DFREF dfr = GetDevicePath(device) + + WAVE/Z/SDFR=dfr/D wv = $name + + if(ExistsWithCorrectLayoutVersion(wv, version)) + return wv + elseif(WaveExists(wv)) + // upgrade here + else + Make/D/N=(0, 2) dfr:$name/WAVE=wv + endif + + SetDimensionLabels(wv, "GAINFACTOR;OFFSET;", COLS) + + return wv +End + +Function/WAVE GetSutterDACTTLSampleInterval() + + Make/FREE/D rates = {1 / 100, 1 / 200, 1 / 400, 1 / 800, 1 / 1000, 1 / 2000, 1 / 4000, 1 / 5000, 1 / 8000, 1 / 10000} // NOLINT + rates *= ONE_TO_MICRO + + return rates +End + +Function/WAVE GetSutterADCSampleInterval() + + Make/FREE/D rates = {1 / 100, 1 / 200, 1 / 400, 1 / 800, 1 / 1000, 1 / 2000, 1 / 4000, 1 / 5000, 1 / 8000, 1 / 10000, 1 / 20000, 1 / 25000, 1 / 40000, 1 / 50000} // NOLINT + rates *= ONE_TO_MICRO + + return rates +End diff --git a/Packages/Sutter/AcquisitionExample.ipf b/Packages/Sutter/AcquisitionExample.ipf deleted file mode 100644 index 743a746627..0000000000 --- a/Packages/Sutter/AcquisitionExample.ipf +++ /dev/null @@ -1,89 +0,0 @@ -#pragma TextEncoding = "UTF-8" -#pragma rtGlobals=3 // Use modern global access method and strict wave access -#pragma DefaultTab={3,20,4} // Set default tab width in Igor Pro 9 and later - -Function SetupandStart() -// I. Make input waves - //create both current and voltage waves - Make/d/o/n=(1000) root:input_i, root:input_v //200ms @ 5kHz - Wave input_i = root:input_i - Wave input_v = root:input_v - input_i = nan - input_v = nan - Setscale /p x, 0, 0.0002, "s", input_i, input_v - Setscale d -20e-9,20e-9, "A", input_i - Setscale d -1,1, "V", input_v - -// II. Make inputwavelist - Make /O/T /n=(2,2) root:InputWaveList - Wave /T InputWaveList = root:InputWaveList - InputWaveList[0][0] = "root:input_i" - InputWaveList[1][0] = "root:input_v" - InputWaveList[0][1] = "0" - InputWaveList[1][1] = "1" - -// III. Set key variables - Variable /G root:SweepNumber=0 - Variable ISI = 2 - -// IV. Display Waves – a simple graph to display input waves - Display /W=(50,50,450,400) input_i - AppendToGraph/L=leftv input_v - ModifyGraph lblPos(left)=50,lblPos(leftv)=50 - ModifyGraph freePos(leftv)=0 - ModifyGraph axisEnab(left)={0.55,1} - ModifyGraph axisEnab(leftv)={0,0.45} - -// V. Make output stimulus - Make /d/o/n=200 root:stim_v - Wave stim_v = root:stim_v - Setscale /p x, 0, 0.001, "s", stim_v - //Give it a -10 mV step - stim_v = 0 - stim_v[50,150] = -0.010 - -// VI. Make outputwavelist - Make /O/T/N=(1,2) root:OutputWaveList - Wave /T OutputWaveList = root:OutputWaveList - OutputWaveList[0][0] = "root:stim_v" - OutputWaveList[0][1] = "0" - -// VII. Start acquisition - // First send stimulus, which will be repeated each time, so only need to send once. - SutterDAQWriteWave /T=1 /R=1 /RHP=1 OutputWaveList - // Next request triggered acquisition - SutterDAQScanWave /T=1 /B=1 /H="ContinueExample()" root:InputWaveList - // Finally, trigger acquisition using ISI listed above. - SutterDAQClock(1,ISI,1) -End - -Function ContinueExample() -// This function is automatically called when the input waves have been filled. -// We will increment our sweep counter, copy to a data wave, and rearm acquisition. - - NVar SweepNumber = root:SweepNumber - if (SweepNumber == 0) - //for simple example we'll overwrite data - Make /o/n=(1000,10) mydata_i, mydata_v - Setscale /p x, 0, 0.0002, "s", mydata_i, mydata_v - endif - Wave input_i = root:input_i - Wave input_v = root:input_v - mydata_i[][SweepNumber] = input_i[p] - mydata_v[][SweepNumber] = input_v[p] - - //Increment SweepNumber - SweepNumber += 1 - - //We could do real-time analysis on the data here... - - //Check if we should end - If (SweepNumber == 10) - //Reset the amplifiers acquisition (stops onboard clock) - SutterDAQReset() - Return 0 - else - //Otherwise rearm acquisition - SutterDAQScanWave /T=1 /B=1 /H="ContinueExample()" root:InputWaveList - endif -End diff --git a/Packages/Sutter/SP_IPA_ControlPanel (stand alone).ipf b/Packages/Sutter/SP_IPA_ControlPanel (stand alone).ipf deleted file mode 100644 index d14218ccad..0000000000 --- a/Packages/Sutter/SP_IPA_ControlPanel (stand alone).ipf +++ /dev/null @@ -1,3331 +0,0 @@ -// Copyright Sutter Instrument Corp. 2015 - 2023 - -// ---------------- Pragmas ---------------- - -#pragma IgorVersion = 8.00 // Require Igor version 8.0 or later for compatbility -#pragma rtGlobals=3 // Use modern global access method and strict wave access. -#pragma ModuleName = IPA // This can become an independent module -//#pragma IndependentModule = IPA -Static StrConstant ksModuleName = "IPA" // For reference in procedure calls - -Strconstant AmpPath = "root:SutterIPA" // Created on control panel startup -Static Constant TRUE = 1 -Static Constant FALSE = 0 - -Static Constant IPA_StructVersion = 102 - -// Contants for different systems: IPA, dIPA, dendrite -Static Constant kIPASingle = 1 -Static Constant kIPADouble = 2 -Static Constant kSutterInterface = 3 - -Static Constant kMaxAmplifiers = 4 // Max number of headstage (XOP can handle 2 dIPAs) - -Static Constant kCC_deltaCap = 1.4 // CC circuit has 1.4 pF more headstage capacitance. -Static Constant kStabilityControl = 1 // Reduce cap neut to avoid ringing (pF) - - -//-------------------Structure to store amplifier values ------------------------ - -STRUCTURE IPAControlValues - uchar version - char serial[13] // serial number - uchar vc // VC - CC - uchar filter // Output Filter - uchar gainvc // VC Gain - uchar gaincc // CC Gain - uchar seal // Seal Test on - int16 offset // Offset value - uchar offsetlock // Offset lock - float LJP // Liquid Junction Potential - float hpot // Holding potential - uchar hpoton // Holding potential checked - float hcurr // Holding current - uchar hcurron // Holding current checked - float fastmag // Electrode Compensation mag - float fastphase // Electrode Compensation phase - uchar compon // Cell Compensation on - float rscomp // Cell Compensation Rs - float cmcomp // Cell Compensation Cm - uchar corron // Rs Correction on - uchar rscorr // Correction % - uchar lag // Correction lag - uchar rspred // Prediction % - uchar capneuton // Cap Neut on - float bridge // Bridge balance - uchar bridgeon // Bridge balance on - uchar trackon // Tracking on - float track // Tracking potential - uchar dout // Digital Output (1-8) - float AOut0 // Aux out 1 - float AOut1 // Aux out 2 - float AOut2 // Aux out 3 - float AOUT3 // Aux out 4 - char DACOffset // For Trimming DAC... this is only necessary in rare cases. -EndStructure - -//----------------Read IPA Structure --------------------------------- - -Function IPA_ReadStructure(variable HS_Number) - DFREF dfr=$AmpPath - Wave /T structurewave = dfr:structurewave - - STRUCT IPAControlvalues ipa - StructGet /S ipa, structurewave[HS_Number] - - // All elements of the control panel can be accessed here, Structure elements are - // listed above (e.g. ipa.capneuton). HS_Number is 0 based. For single IPA, use 0. - -End - -//----------------Meta Data Write------------------------------------- - -Function IPA_Meta(string strsetting, string strvalue, variable headstage_number, variable NEWorLAST) - -// IPA_Meta is called anytime an amplifier setting is changed. Add additional code here as needed -// Note: strsetting is not equivelent to IPA_SetValue keywords. Contact Sutter for a list - - -End - -//----------------Sutter IPA Menu------------------------------------ - -Menu "Sutter IPA" , dynamic - "Amplifier Control Panel", /Q, IPA#RestoreIPAPanel() - - "-" - "Reset Control Panel", /Q, IPA#ResetControls() - "Reset USB", /Q, IPA#ResetUSB() - "Reset Acquisition", /Q, SutterDAQReset() - "-" - "Open Zap Panel", /Q, IPA#ZapPanel() - End - - -//--------------------------------------------Package Preferences---------------------------------------------- - -static Constant PanelPrefsVersion = 100 -static StrConstant PanelPackageName = "SutterPatch" -static StrConstant PanelPreferencesFileName = "SP_IPAControl.bin" -static Constant PanelPrefsRecordID = 0 - -Structure SutterDAQPanelPrefs - uint32 version // Preferences structure version number. - double panelCoords[4] // left, top, right, bottom for edit panel - char seal[2] // Deprecated -- for seal test - char DACoffset - double ZapPanelCoords[4] - double ZapDuration - double ZapVoltage -EndStructure - -// Sets prefs structure to default values. -static Function DefaultPackagePrefsStruct(prefs) - STRUCT SutterDAQPanelPrefs &prefs - prefs.version = PanelPrefsVersion - prefs.version = PanelPrefsVersion - prefs.panelCoords[0] = 825 // Left - prefs.panelCoords[1] = 50 // Top - prefs.panelCoords[2] = 1000 // Right - prefs.panelCoords[3] = 440 // Bottom - prefs.seal[0] = 1 - prefs.seal[1] = 10 - prefs.ZapPanelCoords[0] = 80 // Left - prefs.ZapPanelCoords[1] = 120 // Top - prefs.ZapPanelCoords[2] = 350 // Right - prefs.ZapPanelCoords[3] = 240 // Bottom - prefs.ZapDuration = 0.5 - prefs.ZapVoltage = 1 -End - -static Function InitPackagePrefsStruct(prefs) - STRUCT SutterDAQPanelPrefs &prefs - DefaultPackagePrefsStruct(prefs) // Panel does not exist. Set prefs struct to default. - - if (IPA_PanelExists()) - SyncPackagePrefsStruct(prefs) // Panel does exists. Sync prefs struct to match panel state. - endif -End - -static Function UpdatePrefs() - STRUCT SutterDAQPanelPrefs prefs - LoadPackagePrefs(prefs) - SyncPackagePrefsStruct(prefs) - SavePackagePrefs(prefs) -End - - -static Function SyncPackagePrefsStruct(prefs) - STRUCT SutterDAQPanelPrefs &prefs - DFREF dfr=$AmpPath - // Panel does exist. Set prefs to match panel settings... this may be display dependent. - prefs.version = PanelPrefsVersion - if (IPA_PanelExists()) - GetWindow SP_SutterAmp0 wsize - prefs.panelCoords[0] = V_left * ScreenResolution/panelresolution("SP_SutterAmp0") - prefs.panelCoords[1] = V_top * ScreenResolution/panelresolution("SP_SutterAmp0") - prefs.panelCoords[2] = V_right * ScreenResolution/panelresolution("SP_SutterAmp0") - prefs.panelCoords[3] = V_bottom * ScreenResolution/panelresolution("SP_SutterAmp0") - endif - if (wintype("IPA_Zap")) - GetWindow IPA_Zap wsize - prefs.ZapPanelCoords[0] = V_left *ScreenResolution/panelresolution("IPA_Zap") - prefs.ZapPanelCoords[1] = V_top *ScreenResolution/panelresolution("IPA_Zap") - prefs.ZapPanelCoords[2] = V_right*ScreenResolution/panelresolution("IPA_Zap") - prefs.ZapPanelCoords[3] = V_bottom*ScreenResolution/panelresolution("IPA_Zap") - ControlInfo /w=IPA_Zap zapvar1 - prefs.ZapVoltage = V_Value - ControlInfo /w=IPA_Zap zapvar0 - prefs.ZapDuration = V_Value - endif - return TRUE -End - -static Function LoadPackagePrefs(prefs) - STRUCT SutterDAQPanelPrefs &prefs - // Clear structure entries - InitPackagePrefsStruct(prefs) - - // This loads preferences from disk if they exist on disk. - LoadPackagePreferences /MIS=1 PanelPackageName, PanelPreferencesFileName, PanelPrefsRecordID, prefs - - // If error or prefs not found or not valid, initialize them. - if (V_flag!=0 || V_bytesRead==0 || prefs.version!=PanelPrefsVersion) - InitPackagePrefsStruct(prefs) // Set based on panel if it exists or set to default values. - SavePackagePrefs(prefs) // Create initial prefs record. - endif -End - -static Function SavePackagePrefs(prefs) - STRUCT SutterDAQPanelPrefs &prefs - SavePackagePreferences /FLSH=1 PanelPackageName, PanelPreferencesFileName, PanelPrefsRecordID, prefs -End - -Static Function PrintPackagePrefs() - STRUCT SutterDAQPanelPrefs prefs - LoadPackagePrefs(prefs) - print prefs.version - print prefs.panelCoords[0], prefs.panelCoords[1], prefs.panelCoords[2], prefs.panelCoords[3] - print prefs.seal[0], prefs.seal[1] -End - - -//----------------------------------------------Control Panel Initialize / USB Connect ------------------------------------------------- - -Function RestoreIPAPanel() - DoWindow /F /HIDE=0 /Z SP_SutterAmp0 - if (V_flag) - MoveWindow /W=SP_SutterAmp0 1,1,1,1 - else - Initialize_IPA() - Connect_IPA() - endif -End - -static Function Initialize_IPA() // Called on startup, creates IPA data folder and required variables - NewDataFolder /O $(AmpPath) - DFREF dfr=$AmpPath - variable /G $(AmpPath + ":SD_Seal") = 0 - variable /G $(AmpPath + ":SD_USB") = 0 - variable /G $(AmpPath + ":SD_DIO") = 0 - variable /G $(AmpPath + ":SD_sweeptime")=0 - Make /O/n=(8,2) $(AmpPath + ":SD_Meter") = 0 - NewPath /C/O/Q SutterPatch_Prefs SpecialDirPath("Packages",0,0,0) + "SutterPatch:" -End - -static Function Connect_IPA() - variable num_amps = SutterDAQusbreset() - variable step - variable num_hdstg=0 - for (step=0; step kMaxAmplifiers) - num_amps = 1 - endif - CreateStructure(num_amps) - if (WinType("SP_SutterAmp0")) - KillWindow SP_SutterAmp0 - endif - SutterAmpPanel(num_amps) - SetWindow SP_SutterAmp0 userdata(VCon)="1" - SetWindow SP_SutterAmp0 userdata(hide)="0" - SetWindow SP_SutterAmp0 userdata(multi)="0" - SetWindow SP_SutterAmp0 userdata(Amp)="0" - SetWindow SP_SutterAmp0 userdata(HS)="0" - IPA_LoadStructure(0) -End - -static Function IPA_PanelExists() - if( WinType("SP_SutterAmp0") != 0 ) - return TRUE - else - return FALSE - endif -End - -Function IPA_ShowPanel() - if( IPA_PanelExists() ) - DoWindow /F /HIDE=0 SP_SutterAmp0 - else - BuildPanel( IPA_GetValue(0,"NumHS") ) - EndIf - return TRUE -End - -Static Function SutterAmpPanel(variable num_amp) : Panel - DFREF dfr=$AmpPath - STRUCT SutterDAQPanelPrefs prefs - LoadPackagePrefs(prefs) - - Variable left = prefs.panelCoords[0] - Variable top = prefs.panelCoords[1] - Variable subWidth = 250 - Variable right = prefs.panelCoords[0]+subWidth - Variable bottom = prefs.panelCoords[1]+525 - - NewPanel /W=(left,top,right,bottom) /K=3 /N=SP_SutterAmp0 as "IPA Control" - - // Setup color waves - make /FREE/N=3 ColorBACK = {53000,53000,53000} - make /FREE/N=3 ColorOFF = {0,0,0} - make /FREE/N=3 ColorGBLight = {58000,58000,58000} - make /FREE/N=3 ColorON = {63000,20000,0} - - ModifyPanel /W=SP_SutterAmp0 fixedSize=TRUE, noEdit=0 - // Tabs for multiple amplifiers - if (num_amp > 1) - TabControl SDtab win=SP_SutterAmp0,pos={10,5},size={subWidth-20,145},focusRing=0, proc=$(ksModuleName + "#TabProc_SD"),fsize=12,LabelBack=(ColorGBLight[0],ColorGBLight[1],ColorGBLight[2]) - variable step - for (step = 0; stepstr2num(sva.userdata)) - SetVariable SDSetVar12 win=SP_SutterAmp0, value=_NUM:(sva.dval+.09) - sva.userdata = num2str(sva.dval+.09) - else - SetVariable SDSetVar12 win=SP_SutterAmp0, value=_NUM:(sva.dval-.09) - sva.userdata = num2str(sva.dval-.09) - endif - ControlUpdate /W=SP_SutterAmp0 SDSetVar12 - else - sva.userdata = num2str(sva.dval) - endif - - setval=round(dval*655.32) - if (!VCon) - controlinfo /W=SP_SutterAmp0 check4 - setval*= V_Value - ModifyCapMag(setval) - endif - if (HS) - SutterDAQwrite(Amp,23,2,(setval&0xff00)/256,setval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,2,2,(setval&0xff00)/256,setval&0x00ff) // These will need to be calculated - endif - SaveStructure("fastmag",dval,-1) - break - case "SDsetvar13": // Fast phase //GH Edit shift to TAU) - if (sva.eventmod &2) //This is to allow 10x delta using shift key - SetVariable SDSetVar13 win=SP_SutterAmp0, limits={0.1,4.5,.1} - else - SetVariable SDSetVar13 win=SP_SutterAmp0, limits={0.1,4.5,0.01} - endif - setval = round((dval-0.1)*1023/4.4) -// setval=min(1023,round(dval*10.24)) - if (HS) - SutterDAQwrite(Amp,23,1,(setval&0xff00)/256,setval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,2,1,(setval&0xff00)/256,setval&0x00ff) // These will need to be calculated - endif - SaveStructure("fastphase",dval,-1) - break - case "SDsetvar16": //Rs corr % - SaveStructure("rscorr",dval,-1) - SetCorrection(0) - break - case "SDsetvar18": // Rs Correction lag - setval=max(102,round(dval*5.12)) - setval=min(1023,round(dval*5.12)) //Settings from 20 to 200 (us) - if (HS) - SutterDAQwrite(Amp,23,10,(setval&0xff00)/256,setval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,2,10,(setval&0xff00)/256,setval&0x00ff) - endif - SaveStructure("lag",dval,-1) - break - case "SDsetvar19": // Tracking potential - DFREF dfr=$AmpPath - controlinfo /w=SP_SutterAmp0 check3 - if (v_value) - setval = 32.767*dval - if (HS) - SutterDAQwrite(Amp,25,1,(setval&0xff00)/256,setval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,19,1,(setval&0xff00)/256,setval&0x00ff) - endif - endif - SaveStructure("track",dval,-1) - break - endswitch - break - case 8: - //This is called when the exiting the control (click on new control) - strswitch(sva.ctrlName) - case "SDsetvar11": - IPA_Meta("Input_BridgeBalance_R",num2str(sva.dval*1e6),Amp,1) - break - case "SDsetvar12": - IPA_Meta("Input_Pipette_Fast_Mag",num2str(sva.dval*1e-12),Amp,1) - break - case "SDsetvar13": - IPA_Meta("Input_Pipette_Fast_Tau",num2str(sva.dval),Amp,1) - break - case "SDsetvar16": - IPA_Meta("Input_SeriesR_Corr_Value",num2str(sva.dval),Amp,1) - break - case "SDsetvar18": - IPA_Meta("Input_SeriesR_Corr_Lag",num2str(sva.dval*1e-6),Amp,1) - break - case "SDsetvar19": - IPA_Meta("Input_Slow_Track_Value",num2str(sva.dval*1e-3),Amp,1) - break - endswitch - break - endswitch - - return 0 -End - - -static Function SetCompensation(variable probe_count) // This sets the Rs Cm compensation along with Rs Prediction % (all are related) - DFREF dfr=$AmpPath - variable VC, Amp, HS, StructureRow - variable tau_set, Pred, cp_set, alpha, rs_val, cp_val,CompOn, CorrOn - Wave /Z/T structurewave = dfr:structurewave - STRUCT IPAControlvalues ipa - if (probe_count == 0) - DoWindow SP_SutterAmp0 - if (V_flag) - ControlInfo /W=SP_SutterAmp0 SDtab - StructureRow = V_value - endif - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - else - StructureRow = probe_count -1 - Amp = IPA_GetValue(probe_count, "AmplIndex") - HS = IPA_GetValue(probe_count, "HSIndex") - endif - StructGet /S ipa, structurewave[StructureRow] - CompOn = ipa.compon*!ipa.vc - CorrOn = ipa.corron - alpha = CorrOn* ipa.rspred/100 - cp_val = ipa.cmcomp - rs_val = ipa.rscomp - //NOT TAKING INTO ACCOUNT ENDPOINT RESISTANCE: - //tau_set = ( (rs_val * cp_val) / .068)/20000)*2^10 -// tau_set = CompOn * round((1-alpha)*rs_val*cp_val*.752942) //.0939794) //.752942) -// Pred =CompOn*CorrOn*floor(163.84*alpha/(1-alpha)) //Rev G: scaling is now alpha/(1-alpha) -// cp_set = CompOn*floor(cp_val*163.84) // 327.68 for 5 pf ci. for 10 pf multiply by 163.84 Rev F has x2 gain(which allows up to 100pF), so 163.84 - -// New version... prediction does not require that Cell Compensation is enabled. - - tau_set = round((1-alpha)*rs_val*cp_val*.752942) //.0939794) //.752942) - Pred = !ipa.vc * CorrOn*floor(163.84*alpha/(1-alpha)) //Rev G: scaling is now alpha/(1-alpha) - cp_set = CompOn*floor(cp_val*163.84) // 327.68 for 5 pf ci. for 10 pf multiply by 163.84 Rev F has x2 gain(which allows up to 100pF), so 163.84 - - if (HS) - SutterDAQwrite(Amp,23,6,(tau_set&0xff00)/256,tau_set&0x00ff) - SutterDAQwrite(Amp,23,7,(cp_set&0xff00)/256,cp_set&0x00ff) - SutterDAQwrite(Amp,23,9,(Pred&0xff00)/256,Pred&0x00ff) - else - SutterDAQwrite(Amp,2,6,(tau_set&0xff00)/256,tau_set&0x00ff) - SutterDAQwrite(Amp,2,7,(cp_set&0xff00)/256,cp_set&0x00ff) - SutterDAQwrite(Amp,2,9,(Pred&0xff00)/256,Pred&0x00ff) - endif -End - -static Function SetCorrection(variable probe_count) - DFREF dfr=$AmpPath - variable VC, Amp, HS, StructureRow - variable CorrOn, rs_val, cm_val, setval - Wave /Z/T structurewave = dfr:structurewave - STRUCT IPAControlvalues ipa - if (probe_count == 0) - DoWindow SP_SutterAmp0 - if (V_flag) - ControlInfo /W=SP_SutterAmp0 SDtab - StructureRow = V_value - endif - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - else - StructureRow = probe_count -1 - Amp = IPA_GetValue(probe_count, "AmplIndex") - HS = IPA_GetValue(probe_count, "HSIndex") - endif - StructGet /S ipa, structurewave[StructureRow] - setval= 0 - if (!ipa.vc) //ipa.vc = 2 for cc, 0 for vc - setval=round(ipa.corrOn*ipa.rscorr*ipa.rscomp*1.6383) //product of Rs corr% AND Rs - endif - if (HS) - SutterDAQwrite(Amp,23,8,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(Amp,2,8,(setval&0xff00)/256,setval&0x00ff) - endif -End - -static Function SetVarProc_SD4(sva) : SetVariableControl // Procedure for setting Rs, Wc and Rs Pred - STRUCT WMSetVariableAction &sva - sva.blockreentry = 1 - switch( sva.eventCode ) - case 1: - case 2: - case 3: - strswitch(sva.ctrlName) - case "SDsetvar4": - SaveStructure("rscomp",sva.dval,-1) - break - case "SDsetvar5": - SaveStructure("cmcomp",sva.dval,-1) - break - case "SDsetvar17": - SaveStructure("rspred",sva.dval,-1) - break - endswitch - SetCompensation(0) - SetCorrection(0) - break - case 8: - strswitch(sva.ctrlName) - case "SDsetvar4": - IPA_Meta("Input_SeriesR_Value",num2str(sva.dval*1e6),0,1) - break - case "SDsetvar5": - IPA_Meta("Input_Memb_Cap",num2str(sva.dval*1e-12),0,1) - break - case "SDsetvar17": - IPA_Meta("Input_SeriesR_Pred_Value",num2str(sva.dval),0,1) - break - endswitch - break - endswitch - return 0 -end - -static Function SetVarProc_SD5(sva) : SetVariableControl // Procedure for setting offset - STRUCT WMSetVariableAction &sva - sva.blockreentry = 1 - switch( sva.eventCode ) - case 1: - case 2: - case 3: - DFREF dfr=$AmpPath - variable SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - - if (sva.eventmod &2) //This is to allow 10x delta using shift key - SetVariable SDSetVar0 win=SP_SutterAmp0, limits={-250,250,0.152588} - else - SetVariable SDSetVar0 win=SP_SutterAmp0, limits={-250,250,0.0152588} - endif - - Variable dval = sva.dval - - dval = round(dval*2^16/1000) //extra divide by two for dipa is performed in firmware - if (abs(sva.dval)<.008) - SetVariable SDSetVar0 win=SP_SutterAmp0, value=_NUM:0 - endif - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - variable HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - if (HS) - SutterDAQwrite(Amp,17,4,(dval&0xff00)/256,dval&0x00ff) //Check to see if 2nd bit has to be 1? - else - SutterDAQwrite(Amp,17,1,(dval&0xff00)/256,dval&0x00ff) //2nd bit has to be 1 for IPA? - endif - SaveStructure("offset",dval,-1) - break - case 8: - IPA_Meta("Input_Offset",num2str(sva.dval*1e-3),0,1) - break - endswitch - - return 0 -End - -static Function SetVarProc_SD6(sva) : SetVariableControl //to input holding potential/current - STRUCT WMSetVariableAction &sva - - switch( sva.eventCode ) - case 1: - case 8: - case 3: - sva.blockreentry = 1 - - if (sva.eventmod &2) //This is to allow 10x delta using shift key - if (cmpstr(sva.ctrlName, "SDsetvar3")==0) - SetVariable $sva.ctrlName win=SP_SutterAmp0, limits={-1000,1000,10} - else - SetVariable $sva.ctrlName win=SP_SutterAmp0, limits={-20000,20000,10} - endif - else - if (cmpstr(sva.ctrlName, "SDsetvar3")==0) - SetVariable $sva.ctrlName win=SP_SutterAmp0, limits={-1000,1000,1} - else - SetVariable $sva.ctrlName win=SP_SutterAmp0, limits={-20000,20000,1} - endif - endif - - variable SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - variable HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - - ControlInfo /W=SP_SutterAmp0 SDtab0 - variable VCTab=V_value - variable setvalue - variable holding - variable update = FALSE - - if (VCTab == 0) //VC TAB - if (SD_VCon) //Only set if in VC - controlinfo /W=SP_SutterAmp0 check5 - if (v_value == TRUE) - setvalue = 32.767 * sva.dval - holding = sva.dval*1e-3 //mV - update = 1 - endif - endif - SaveStructure("hpot",sva.dval,-1) - elseif (VCTab == 1) //CC Tab - if (!SD_VCon) //Only set if in CC - controlinfo /W=SP_SutterAmp0 check6 - if (v_value == TRUE) - setvalue =round(1.63835 * sva.dval) //was 1.6384, but reduced to avoid rollover to negative - holding = sva.dval*1e-12 //pA - update = 1 - endif - endif - SaveStructure("hcurr",sva.dval,-1) - endif - - if (update) - SutterDAQwrite(Amp,16,HS,(setvalue&0xff00)/256,setvalue&0x00ff) - IPA_Meta("Cmd_Holding_Value_"+num2istr(HS+1),num2str(holding),0,1) - endif - break - endswitch - - return 0 -End - -static Function ButtonProc_SD0(ba) : ButtonControl // Sets VC vs CC mode - STRUCT WMButtonAction &ba - if ( ba.eventCode == 2 ) - ba.blockreentry = TRUE - DFREF dfr=$AmpPath - - variable SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - variable SD_hide = str2num(GetUserData("SP_SutterAmp0","","hide")) - - // Setup color waves - make /FREE/N=3 ColorOFF = {0,0,0} - make /FREE/N=3 ColorON = {63000,20000,0} - - Button SDbutton0 fColor=(colorOFF[0],colorOFF[1],colorOFF[2]), win=SP_SutterAmp0 - Button SDbutton2 fColor=(colorOFF[0],colorOFF[1],colorOFF[2]), win=SP_SutterAmp0 - Button $ba.ctrlName fColor=(colorON[0],colorON[1],colorON[2]), win=SP_SutterAmp0 //Turns clicked button gray. - if (!cmpstr(ba.ctrlName,"SDbutton0")) //VC on - SD_VCon = 1 - SetWindow SP_SutterAmp0 userdata(VCon) = "1" - if(!SD_hide) - tabcontrol sdtab0 value=0, win=SP_SutterAmp0 - Settab(0) - endif - SaveStructure("vc",0,-1) - IPA_Meta("Input_Recording_Mode","1",0,1) - else // CC - SD_VCon = 0 - SetWindow SP_SutterAmp0 userdata(VCon) = "0" - if(!SD_hide) - tabcontrol sdtab0 value=1, win=SP_SutterAmp0 - SetTab(1) - endif - SaveStructure("vc",2,-1) - IPA_Meta("Input_Recording_Mode","2",0,1) - endif - SetIPA() - endif - - return 0 -End - -static Function SetIPA() //This uses controls -- works for setting active tab only - DFREF dfr=$AmpPath - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - variable HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - variable SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - variable setval =0 - variable AcquisitionOn = 0 - NVar /Z AcqInProgress = root:SutterPatch:'AppControl​':Variables:Acq_InProgress - if (NVar_Exists(AcqInProgress)) - AcquisitionOn = AcqInProgress - endif - //1. Seal test off - SutterDAQWrite(amp,18,0,10,10) //Currently same for both amplifiers. - SaveStructure("seal",0,0) - //2. Set Offset - controlinfo /w=SP_SutterAmp0 SDsetvar0 - setval = round(v_value*2^16/1000) - if (HS) - SutterDAQwrite(Amp,17,4,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(Amp,17,1,(setval&0xff00)/256,setval&0x00ff) - endif - //3. Turn on/off compensation - - //SDsetvar11: Bridge set in CC - controlinfo /W=SP_SutterAmp0 SDsetvar11 - setval = round(v_value*81.92) - controlinfo /W=SP_SutterAmp0 check7 - setval *= (v_value * !SD_VCon) //only in CC, only if checked - if (HS) - SutterDAQwrite(amp,23,5,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(amp,2,5,(setval&0xff00)/256,setval&0x00ff) - endif - - //SDsetvar12: Fast Mag -- have different value for CC? - controlinfo /w=SP_SutterAmp0 SDsetvar12 - setval=round(v_value*655.32) - if (SD_VCon==0) //CC (or going into CC) - controlinfo /W=SP_SutterAmp0 check4 - setval *= v_value - ModifyCapMag(setval) - if (HS) - SutterDAQwrite(amp,23,2,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(amp,2,2,(setval&0xff00)/256,setval&0x00ff) - endif - endif - - //SDsetvar13: Fast Tau can stay on no matter what - controlinfo /w=SP_SutterAmp0 SDsetvar13 - setval = round((v_value-0.1)*1023/4.4) - // setval=min(1023,round(v_value*10.24)) - if (HS) - SutterDAQwrite(amp,23,1,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(Amp,2,1,(setval&0xff00)/256,setval&0x00ff) - endif - //SDsetvar16: Rs corr% turns off in IC - // setval is the product of Rs corr% AND Rs - //SDsetvar4,SDsetvar5,SDsetvar17: Whole cell compensation turns off in IC - //Rs can stay on, Pred value is OK, but need to switch off (SwCtrl2) Cm is off in IC - SetCompensation(0) - controlinfo /w=SP_SutterAmp0 SDsetvar18 - setval=min(1023,round(v_value*5.12)) //Settings from 20 to 200 (us) - setval=max(102,round(v_value*5.12)) - if (HS) - SutterDAQwrite(Amp,23,10,(setval&0xff00)/256,setval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,2,10,(setval&0xff00)/256,setval&0x00ff) - endif - SetCorrection(0) - //Short delay to insure injection capacitor is discharged prior to changing to CC - IPA_usdelay(2000) - // We may only want this delay if we are going VC->CC - - // Set Gain to 1 (for firmware versions <4)... This can cause glitch if acquisition is on, so - // we will only change gain if not... - if (!AcqInProgress) - if (HS) - SutterDAQwrite(amp,23,12,0,0) - else - SutterDAQwrite(amp,12,0,0,0) - endif - SutterDAQRead(amp,0) //This may not be required... need to test on all firmware versions. - endif - - //4. Switch to VC / IC - if (HS) - SutterDAQwrite(amp,23,20,3,SD_VCon) //SmartSwitch and I=0 are byte 4 - else - SutterDAQwrite(amp,20,1,1,SD_VCon) //SmartSwitch on. - - endif - - //5. Turn on holding i/v (if checked) - variable SD_HPot - if (SD_VCon) - Controlinfo /w=SP_SutterAmp0 SDsetvar3 - SD_Hpot = v_value - Controlinfo /w=SP_SutterAmp0 check5 - SD_Hpot *= v_value - SutterDAQwrite(amp,16,HS,((32.767*sd_hpot)&0xff00)/256,(32.767*sd_hpot)&0x00ff) - else - ControlInfo /w=SP_SutterAmp0 check3 //Slow hold checked? - if (v_value) - //Enter code for slow hold here: - - else - Controlinfo /w=SP_SutterAmp0 SDsetvar10 - SD_HPot = 1.63835*v_value - Controlinfo /w=SP_SutterAmp0 check6 - SD_HPot *= v_value - SutterDAQwrite(amp,16,HS,((SD_HPot)&0xff00)/256,(SD_HPot)&0x00ff) - endif - endif - if (SD_VCon) - controlinfo /w=SP_SutterAmp0 SDsetvar12 - setval=round(v_value*655.32) - if (HS) - SutterDAQwrite(amp,23,2,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(amp,2,2,(setval&0xff00)/256,setval&0x00ff) - endif - endif - //6. Change to correct gain - if(SD_VCon) - Controlinfo /w=SP_SutterAmp0 SDpop0 - else - Controlinfo /w=SP_SutterAmp0 SDpop2 - endif - if (HS) - SutterDAQwrite(amp,23,12,0,v_value-1) - else - SutterDAQwrite(amp,12,0,0,v_value-1) - endif - - //7. Set correct filter - Controlinfo /w=SP_SutterAmp0 SDpop1 - if (HS) - SutterDAQwrite(amp,23,11,0,6-v_value) - else - SutterDAQwrite(amp,11,0,0,6-v_value) - endif - return 0 -End - - -static Function SetIPA_fromStructure(variable StructureRow) -// THIS IS CALLED ON STARTUP AND EACH TIME WE SWITCH HS - DFREF dfr=$AmpPath - Wave /T structurewave = dfr:structurewave - STRUCT IPAControlvalues ipa - variable Amp=0 - variable HS = 0 - variable setval - string amplist = note(structurewave) - if (numtype(str2num(stringfromlist(StructureRow,amplist)[0]))==0) - Amp = str2num(stringfromlist(StructureRow,amplist)[0]) - HS = str2num(stringfromlist(StructureRow,amplist)[1]) - endif - StructGet /S ipa, structurewave[StructureRow] - //Different SutterDAQ command for first and second headstage on a dIPA - //Channel 1 of dIPA is controlled exactly the same as IPA. So if HS=0; no need to test for amptype. - variable Cmd = 2 - if (HS) - Cmd = 23 - endif - variable AcquisitionOn = 0 - NVar /Z AcqInProgress = root:SutterPatch:'AppControl​':Variables:Acq_InProgress - if (NVar_Exists(AcqInProgress)) - AcquisitionOn = AcqInProgress - endif -//1. Seal test off - //Currently this is HS indepedent... need to update on dIPA firmware. - SutterDAQWrite(Amp,18,0,10,10) //Currently same for both HS - SaveStructure("seal",0,0) -//2. Set Offset - setval = ipa.offset - if (HS) - SutterDAQwrite(Amp,17,4,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(Amp,17,1,(setval&0xff00)/256,setval&0x00ff) - endif - -//3. Turn on/off compensation - - //SDsetvar11: Bridge set only in CC - if (ipa.vc==2) //CC - setval = round(ipa.bridge*81.92)*ipa.bridgeon //2^14/200 max range = 200 MOhm - SutterDAQwrite(Amp,Cmd,5,(setval&0xff00)/256,setval&0x00ff) - endif - - //SDsetvar12: Fast Mag -- may allow a different value for CC? - setval=round(ipa.fastmag*655.32) - if (ipa.vc==2) - ModifyCapMag(setval) - if (ipa.capneuton == 0) - setval=0 - endif - endif - SutterDAQwrite(Amp,Cmd,2,(setval&0xff00)/256,setval&0x00ff) - - //SDsetvar13: Fast Tau can stay on no matter what - //setval=min(1023,round(ipa.fastphase*10.24)) - setval = round((ipa.fastphase-0.1)*1023/4.4) - SutterDAQwrite(Amp,Cmd,1,(setval&0xff00)/256,setval&0x00ff) - - - //SDsetvar18: Rs Lag - setval=min(1023,round(ipa.lag*5.12)) //Settings from 20 to 200 (us) - setval=max(51,round(ipa.lag*5.12)) - if (HS) - SutterDAQwrite(Amp,23,10,(setval&0xff00)/256,setval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,2,10,(setval&0xff00)/256,setval&0x00ff) - endif - - //SDsetvar16: Rs corr% turns off in IC - // setval is the product of Rs corr% AND Rs - //SDsetvar4,SDsetvar5,SDsetvar17: Whole cell compensation turns off in IC - //Rs can stay on, Pred value is OK, but need to switch off (SwCtrl2) Cm is off in IC - -//THIS NEEDS TO BE HS SPECIFIC AND KNOW SWITCH BETWEEN VC AND CC! - SetCompensation(0) - SetCorrection(0) - IPA_usdelay(2000) -//Short delay to insure injection capacitor is discharged prior to changing to CC -// We may only want this delay if we are going VC->CC - -// Set Gain to 1 (for firmware versions <4)... This can cause glitch if acquisition is on, so -// we will only change gain if not... - if (!AcqInProgress) - if (HS) - SutterDAQwrite(amp,23,12,0,0) - else - SutterDAQwrite(amp,12,0,0,0) - endif - SutterDAQread(amp,0) - endif - -//4. Switch to VC / IC - if (HS) - SutterDAQwrite(amp,23,20,3,!ipa.vc) //SmartSwitch on - else - SutterDAQwrite(amp,20,1,1,!ipa.vc) //SmartSwitch on. - endif -//5. Turn on holding i/v (if checked) - if (ipa.vc == 0) //VC - setval = 32.767*ipa.hpot*ipa.hpoton - SutterDAQwrite(amp,16,HS,(setval&0xff00)/256,setval&0x00ff) - else - if (ipa.trackon) - //Enter code for slow hold here: - else - setval = 1.63835*ipa.hcurr*ipa.hcurron - SutterDAQwrite(amp,16,HS,(setval&0xff00)/256,setval&0x00ff) - endif - endif -//6. Change to correct gain - if(ipa.vc==0) //VC - setval = ipa.gainvc - else - setval = ipa.gaincc - endif - if (HS) - SutterDAQwrite(amp,23,12,0,setval) - else - SutterDAQwrite(amp,12,0,0,setval) - endif -//7. Set correct filter - setval = 5-ipa.filter - if (HS) - SutterDAQwrite(amp,23,11,0,setval) - else - SutterDAQwrite(amp,11,0,0,setval) - endif -End - - -static Function ModifyCapMag (variable &Value) - Value += (kCC_deltaCap - kStabilityControl)*655.32 - if (Value<0) - Value = 0 - elseif (Value>16383) - Value = 16383 - endif - return TRUE -end - - -static Function ButtonProc_SD3(ba) : ButtonControl // This is Auto compensation buttons - STRUCT WMButtonAction &ba - if( ba.eventCode == 2) - ba.blockreentry = TRUE - - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - variable HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - variable sample - if (stringmatch(ba.ctrlName,"SDbutton6")) //Whole Cell - variable capreturn, rsreturn - Checkbox check1 win=SP_SutterAmp0, value=1 - SutterDAQwrite(Amp,13,HS,0,1) - ipa_tickdelay(30) - if (HS) - capreturn = round(SutterDAQread(Amp,19)/16.384)/10 - if (capreturn==0) - rsreturn = 0 - else - rsreturn = round(SutterDAQread(Amp,18)*13.2812/capreturn)/10 //10x difference due to change in rc circuit - endif - else - capreturn = round(SutterDAQread(Amp,12)/16.384)/10 - if (capreturn==0) - rsreturn = 0 - else - rsreturn = round(SutterDAQread(Amp,11)*13.2812/capreturn)/10 //10x difference due to change in rc circuit - endif - endif - - SetVariable /Z SDsetvar5 win=SP_SutterAmp0, value=_NUM:capreturn - SetVariable /Z SDsetvar4 win=SP_SutterAmp0, value=_NUM:rsreturn - SetVariable /Z SDsetvar11 win=SP_SutterAmp0, value=_NUM:rsreturn - SaveStructure("cmcomp",capreturn,-1) - SaveStructure("rscomp",rsreturn,-1) - SaveStructure("bridge",rsreturn,-1) - SaveStructure("compon",1,HS) - IPA_Meta("Input_SeriesR_Value",num2str(rsreturn*1e6),amp,1) - IPA_Meta("Input_Memb_Cap",num2str(capreturn*1e-12),amp,0) - elseif (stringmatch(ba.ctrlName,"SDbutton7")) //Fast Cap --only other possibility, but test anyway - variable magreturn, taureturn - SutterDAQwrite(Amp,13,HS,0,0) - magreturn = round(SutterDAQread(Amp,9+HS*7)/6.5532)/100 //16 and 17 for HS2 - taureturn = round(SutterDAQread(Amp,10+HS*7)*4.4/10.23)/100+0.1 // /10 - SetVariable /Z SDsetvar12 win=SP_SutterAmp0, value=_NUM:magreturn, userdata=num2str(magreturn) - SetVariable /Z SDsetvar13 win=SP_SutterAmp0, value=_NUM:taureturn - SaveStructure("fastmag",magreturn,-1) - SaveStructure("fastphase",taureturn,-1) //Need to Fix for multiAMPs. - IPA_Meta("Input_Pipette_Fast_Mag",num2str(magreturn*1e-12),amp,1) - IPA_Meta("Input_Pipette_Fast_Tau",num2str(taureturn),amp,0) - endif - endif - - return 0 -End - -static Function ButtonProc_SD4(ba) : ButtonControl // This is the offset null control - STRUCT WMButtonAction &ba - if( ba.eventCode == 2 ) - ba.blockreentry = TRUE - ZeroIPAOffset() - endif - return 0 -End - - -static Function SD_CheckProc(cba) : CheckBoxControl // This is compensation, correction and offset checkbox - STRUCT WMCheckboxAction &cba - - if( cba.eventCode == 2 ) - cba.blockreentry = 1 - - variable SD_HPot, SD_VCon, Amp, HS - - strswitch(cba.ctrlName) - case "check0": //offset lock - if (cba.checked) - SetVariable SDsetvar0 disable=2, win=SP_SutterAmp0 - SetVariable SDsetvar1 disable=2, win=SP_SutterAmp0 - Button SDButton4 disable=2, win=SP_SutterAmp0 - else - SetVariable SDsetvar0 disable=0, win=SP_SutterAmp0 - SetVariable SDsetvar1 disable=0, win=SP_SutterAmp0 - Button SDButton4 disable=0, win=SP_SutterAmp0 - endif - SaveStructure("offsetlock",cba.checked,-1) - IPA_Meta("Input_Offset_Locked",num2str(cba.checked),0,1) - break - case "check1": // Rs Compensation enabled - SaveStructure("compon",cba.checked,-1) - SetCompensation(0) - IPA_Meta("Input_Whole_Cell",num2str(cba.checked),0,1) - break - case "check2": //Prediction/Correction enabled - SaveStructure("corron",cba.checked,-1) - SetCompensation(0) - SetCorrection(0) - IPA_Meta("Input_SeriesR_Corr",num2str(cba.checked),0,1) - break - case "check3": //Slow holding potential enabled - SaveStructure("trackon",cba.checked,-1) - IPA_Meta("Input_Slow_Track",num2str(cba.checked),0,1) - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - if (cba.checked) //Tracking turned ON - SetVariable SDsetvar10 win=SP_SutterAmp0, disable=2 - CheckBox check6 win=SP_SutterAmp0, disable=2 - SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - if (!SD_VCON) - Controlinfo /w=SP_SutterAmp0 SDsetvar19 // Slow Hold value - SD_HPot =32.767 * v_value - SutterDAQwrite(Amp,19+6*HS,1,((SD_HPot)&0xff00)/256,(SD_HPot)&0x00ff) //19 for HS0, 25 for HS1 - endif - else //Tracking turned OFF - SetVariable SDsetvar10 win=SP_SutterAmp0, disable=0 - CheckBox check6 win=SP_SutterAmp0, disable=0 - SutterDAQwrite(Amp,19+6*HS,0,0,0) - endif - break - case "check4": //Current Clamp electrode compensation enabled. - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - if (!SD_VCon) //only set if in CC - controlinfo /w=SP_SutterAmp0 SDsetvar12 - variable setval=cba.checked*round((v_value+kCC_deltaCap-kStabilityControl)*655.32) - if (setval<0) - setval=0 - endif - if (HS) - SutterDAQwrite(amp,23,2,(setval&0xff00)/256,setval&0x00ff) - else - SutterDAQwrite(amp,2,2,(setval&0xff00)/256,setval&0x00ff) - endif - endif - SaveStructure("capneuton",cba.checked,-1) - break - case "check5": //Holding potential set - SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - ControlInfo /W=SP_SutterAmp0 SDtab0 - if (v_value == 0 && SD_VCon) //Only set if in VC - controlinfo /W=SP_SutterAmp0 SDsetvar3 - SD_Hpot = 32.767*v_value*cba.checked - SutterDAQwrite(Amp,16,HS,(sd_hpot&0xff00)/256,sd_hpot&0x00ff) - endif - SaveStructure("hpoton",cba.checked,-1) - break - case "check6": //Holding current set - SD_VCon = str2num(GetUserData("SP_SutterAmp0","","VCon")) - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - ControlInfo /W=SP_SutterAmp0 SDtab0 - - if (v_value == 1 &&!SD_VCon) //Only set if in CC - Controlinfo /w=SP_SutterAmp0 SDsetvar10 - sd_hpot =1.63835* v_value*cba.checked - SutterDAQwrite(Amp,16,HS,(sd_hpot&0xff00)/256,sd_hpot&0x00ff) - endif - SaveStructure("hcurron",cba.checked,-1) - break - case "check7": // Bridge Balance on - Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - SaveStructure("bridgeon",cba.checked,-1) - controlinfo /W=SP_SutterAmp0 SDsetvar11 - variable bridgeval = cba.checked*round(V_value*81.92) // *2^14/200 max range = 200 MOhm - if (HS) - SutterDAQwrite(Amp,23,5,(bridgeval&0xff00)/256,bridgeval&0x00ff) //14bit unsigned? - else - SutterDAQwrite(Amp,2,5,(bridgeval&0xff00)/256,bridgeval&0x00ff) //14bit unsigned - endif - break - endswitch - endif - - return 0 -End - -Function Slider_DIO(sa) : SliderControl - STRUCT WMSliderAction &sa - switch( sa.eventCode ) - case -1: // control being killed - break - default: - if( sa.eventCode & 1 ) // value set - Variable curval = sa.curval - Variable channelnumber = str2num(replacestring("slider",sa.ctrlName,"")) - // Write DIO to Amplifier - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - SutterDAQwrite(Amp,22,0,channelnumber,sa.curval) - DFREF dfr=$AmpPath - NVar SD_DIO = dfr:SD_DIO - if (sa.curval) - SD_DIO = SD_DIO | 2^(channelnumber) - else - SD_DIO = SD_DIO & ~2^(channelnumber) - endif - SaveStructure("dout",SD_DIO,-1) - endif - endswitch - return 0 -End - -Function ButtonProc_AuxOut(ba) : ButtonControl - STRUCT WMButtonAction &ba - - switch( ba.eventCode ) - case 2: // mouse up - Controlinfo /W=SP_SutterAmp0 popup0 - variable Channel=str2num(s_Value)+1 //ch1 writes to DAC2, ch2 writes to DAC30 - Controlinfo /W=SP_SutterAmp0 SDsetvar20 - variable value = v_value*3276.7 - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - SutterDAQwrite(Amp,17,channel, (value&0xff00)/256,value&0x00ff) - SaveStructure("AOut"+num2str(channel-2),v_value,-1) - break - case -1: // control being killed - break - endswitch - return 0 -End - -Function ButtonProc_Auxread(ba) : ButtonControl - STRUCT WMButtonAction &ba - - switch( ba.eventCode ) - case 2: // mouse up - // click code here - Controlinfo /W=SP_SutterAmp0 popup1 - variable Channel - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - if (IPA_GetValue(Amp,"amptype")==1) - Channel=str2num(s_Value)+2 //channel one arrives on read(3) - ValDisplay valdisp0 value=_NUM:(SutterDAQread(Amp,Channel)) - else - Channel= str2num(Stringfromlist(str2num(s_Value)-1,"5;6;23;24")) //channel one arrives on read(5), 3 and 4 arrive on read(23 and 24) - ValDisplay valdisp0 value=_NUM:(SutterDAQread(Amp,Channel)) - endif - break - case -1: // control being killed - break - endswitch - - return 0 -End - - -//------------------IPA Delay Functions------------------------------- - -Function IPA_tickdelay(timeval) //for inaccurate short delays (1 tick ~ 17ms) - variable timeval - variable t0 = ticks - - do - while(ticks-t0= dimsize(structurewave,0)) - print "Amplifier #"+num2str(amplifier_num)+" not connected" - return 0 - endif - StructGet /S ipa, structurewave[amplifier_num] - print ipa -End - -//-------------Zero any residual offset on IPA Headstage DAC ---------------------------------- - -static Function IPA_ZeroOffset(variable amplifier,variable channel,variable value) - if (value > 256) - value = 255 - elseif (value < -256) - value = -255 - else - value = trunc(value) - endif - SutterDAQwrite(amplifier,21,channel, (value&0xff00)/256,value&0x00ff) -End - -static Function IPA_SetDACOffset() - DFREF dfr=$AmpPath - Wave /T structurewave = dfr:structurewave - STRUCT IPAControlvalues ipa - variable amplifier_num - for (amplifier_num = 0; amplifier_num20e-9) - value = 20e-9*sign(value) - endif - value =round(value*1e12) - if (probe_index == active_tab) - SetVariable SDsetvar10 win=SP_SutterAmp0, value=_NUM:(value) - CheckBox check6 win=SP_SutterAmp0, value=1 - endif - SaveStructure("hcurr",value,probe_index) - SaveStructure("hcurron",1,probe_index) - if (IPA_GetValue(probe_count,"CCMode")) - SutterDAQwrite(ampl_index,16,HS_index,((1.6384* value)&0xff00)/256,(1.6384* value)&0x00ff) - IPA_Meta("Cmd_Holding_Value"+num2str(probe_count),num2str(value*1e-12),ampl_index,1) - endif - return TRUE - break - case "VHold": - if (abs(value)>1) - value = sign(value) - endif - value =round(value*1000) - if (probe_index == active_tab) - SetVariable SDsetvar3 win=SP_SutterAmp0, value=_NUM:(value) - CheckBox check5 win=SP_SutterAmp0, value=1 - endif - SaveStructure("hpot",value,probe_index) - SaveStructure("hpoton",1,probe_index) - if (IPA_GetValue(probe_count,"VCMode")) - SutterDAQwrite(ampl_index,16,HS_index,((32.767*value)&0xff00)/256,(32.767*value)&0x00ff) - IPA_Meta("Cmd_Holding_Value"+num2str(probe_count),num2str(value*1e-3),ampl_index,1) - endif - return TRUE - break - case "Filter": - case "IFilter": - case "VFilter": - setval = whichlistitem(num2str(value),"500;1000;2000;5000;10000;20000") - if (setval == -1) - if (value<550) - setval = 0 - elseif (value<1100) - setval = 1 - elseif (value<2200) - setval = 2 - elseif (value<5500) - setval = 3 - elseif (value<11000) - setval = 4 - else - setval = 5 - endif - endif - if (HS_index) - SutterDAQwrite(ampl_index,23,11,0,5-setval) - else - SutterDAQwrite(ampl_index,11,0,0,5-setval) - endif - - if (probe_index == active_tab) - PopupMenu /Z SDPop1 win=SP_SutterAmp0, mode=(setval+1) - endif - SaveStructure("filter",setval,probe_index) - IPA_Meta("Input_Filter_Freq",StringFromList(setval,"500 Hz; 1 kHZ; 2 kHz; 5 kHz; 10 kHz; 20 kHz"),ampl_index,1) - return TRUE - break - case "VGain": - setval = whichlistitem(num2str(value),"10;20;50;100;200;500") - if (setval == -1 ) - if (value<18) - setval=0 - elseif (value<45) - setval=1 - elseif (value<90) - setval=2 - elseif (value<180) - setval=3 - elseif (value<450) - setval=4 - else - setval=5 - endif - endif - if (IPA_GetValue(probe_count,"CCMode")) //current clamp - if (HS_index) - SutterDAQwrite(ampl_index,23,12,0,setval) // 0 for VC; 1 for CC, dval is code for gain - else - SutterDAQwrite(ampl_index,12,0,0,setval) // 0 for VC; 1 for CC, dval is code for gain - endif - endif - if (probe_index==active_tab) - PopupMenu /Z SDPop2 win=SP_SutterAmp0, mode=(setval+1) - endif - SaveStructure("gaincc",setval,probe_index) - IPA_Meta("Input_Gain_CC",StringFromList(setval,"10;20;50;100;200;500"),ampl_index,1) - return TRUE - break - case "IGain": - setval = whichlistitem(num2str(value),"0.5;1;2.5;5;10;25") - if (setval == -1 ) - if (value<.9e9) - setval=0 - elseif (value<2.25e9) - setval=1 - elseif (value<4.5e9) - setval=2 - elseif (value<9e9) - setval=3 - elseif (value<22.5e9) - setval=4 - else - setval=5 - endif - endif - if (IPA_GetValue(probe_count,"VCMode")) //VC - if (HS_index) - SutterDAQwrite(ampl_index,23,12,0,setval) // 0 for VC; 1 for CC, dval is code for gain - else - SutterDAQwrite(ampl_index,12,0,0,setval) - endif - endif - if (probe_index == active_tab) - PopupMenu /Z SDPop0 win=SP_SutterAmp0, mode=(setval+1) - endif - SaveStructure("gainvc",setval,probe_index) - IPA_Meta("Input_Gain_VC",StringFromList(setval,"0.5;1;2.5;5;10;25"),ampl_index,1) - return TRUE - break - case "Offset": //value sent in volts - if (abs(value)>=0.25) - value = 0.25*sign(value) - endif - if (probe_index == active_tab) - SetVariable SDSetVar0 win=SP_SutterAmp0, value=_Num:value*1000 - endif - Value = round(2^16*value) //convert to 16bit value - SutterDAQwrite(ampl_index,17,1+3*HS_Index,(value&0xff00)/256,value&0x00ff) //1 for HS#0, 4 for HS#1 - SaveStructure("offset",value,probe_index) //in bits - IPA_Meta("Input_Offset",num2str(value/2^16),ampl_index,1) //in V - return TRUE - break - case "OffsetLock": - if (probe_index == active_tab) - if (value == 1) - CheckBox check0 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar0 disable=2, win=SP_SutterAmp0 - Button SDButton4 disable=2, win=SP_SutterAmp0 - elseif (value == 0) - CheckBox check0 win=SP_SutterAmp0, value=0 - SetVariable SDsetvar0 disable=0, win=SP_SutterAmp0 - Button SDButton4 disable=0, win=SP_SutterAmp0 - endif - endif - SaveStructure("offsetlock",value,probe_index) - IPA_Meta("Input_Offset_Locked",num2str(value),ampl_index,1) - break - case "ECompMag": - if (value<0) - value = 0 - elseif (value>25e-12) - value = 25e-12 - endif - value *= 1e12 - if (IPA_GetValue(probe_count,"CCMode")) //in CC - value += kCC_deltaCap - kStabilityControl - endif - if (probe_index == active_tab) - SetVariable SDsetvar12 win=SP_SutterAmp0, value=_NUM:(value), userdata=num2str(value) - endif - setval = round(value*655.32) - if (setval<0) - setval=0 - endif - SutterDAQwrite(ampl_index,2+21*HS_index,2,(setval&0xff00)/256,setval&0x00ff) //2 for HS#0, 23 for HS#1 - SaveStructure("fastmag",value,probe_index) - IPA_Meta("Input_Pipette_Fast_Mag",num2str(value*1e-12),ampl_index,1) - return TRUE - break - case "ECompTau": // was "ECompPhase" - if (value<1e-7) - value = 1e-7 - elseif (value>4.5e-6) - value = 4.5e-6 - endif - value *=1e6 - if (probe_index == active_tab) - SetVariable SDsetvar13 win=SP_SutterAmp0, value=_NUM:(value) - endif - setval = round((value-0.1)*1023/4.4) - SutterDAQwrite(ampl_index,2+21*HS_index,1,(setval&0xff00)/256,setval&0x00ff) - SaveStructure("fastphase",value,probe_index) - IPA_Meta("Input_Pipette_Fast_Tau",num2str(value),ampl_index,1) - return TRUE - break - case "RsComp": - if (value<0) - value = 0 - elseif (value>100e6) - value = 100e6 - endif - value *= 1e-6 - if (probe_index == active_tab) - CheckBox check1 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar4 win=SP_SutterAmp0, value=_NUM:(value) - endif - SaveStructure("rscomp",value,probe_index) - SaveStructure("compon",1,probe_index) - SetCompensation(probe_count) - SetCorrection(probe_count) - IPA_Meta("Input_SeriesR_Value",num2str(value*1e6),ampl_index,1) - return TRUE - break - case "CmComp": - if (value<0) - value = 0 - elseif(value>100e-12) - value = 100e-12 - endif - value *=1e12 - if (probe_index == active_tab) - CheckBox check1 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar5 win=SP_SutterAmp0, value=_NUM:(value) - endif - SaveStructure("cmcomp",value,probe_index) - SaveStructure("compon",1,probe_index) - SetCompensation(probe_count) - SetCorrection(probe_count) - IPA_Meta("Input_Memb_Cap",num2str(value*1e-12),ampl_index,1) - return TRUE - break - case "RsPred": - if (value<0) - value = 0 - elseif (value>1) - value = 1 - endif - value *=100 - if (probe_index == active_tab) - CheckBox check1 win=SP_SutterAmp0, value=1 - CheckBox check2 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar17 win=SP_SutterAmp0, disable=0, value=_NUM:(value) - endif - SaveStructure("rspred",value,probe_index) - SaveStructure("corron",1,probe_index) - SaveStructure("compon",1,probe_index) - SetCompensation(probe_count) - SetCorrection(probe_count) - IPA_Meta("Input_SeriesR_Pred_Value",num2str(value),ampl_index,1) - return TRUE - break - case "RsCorr": - if (value<0) - value = 0 - elseif (value>1) - value = 1 - endif - value *=100 - if (probe_index == active_tab) - CheckBox check2 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar16 win=SP_SutterAmp0, value=_NUM:(value) - endif - SaveStructure("rscorr",value,probe_index) - SaveStructure("corron",1,probe_index) - SetCorrection(probe_count) - IPA_Meta("Input_SeriesR_Corr_Value",num2str(value),ampl_index,1) - return TRUE - break - case "RsLag": - if (value<20e-6) - value = 20e-6 - elseif (value>200e-6) - value = 200e-6 - endif - value *= 1e6 - if (probe_index == active_tab) - SetVariable SDsetvar18 win=SP_SutterAmp0, value=_NUM:(value) - endif - setval = min(1023,round(value*5.12)) - SutterDAQwrite(ampl_index,2+21*HS_index,10,(setval&0xff00)/256,setval&0x00ff) - SaveStructure("lag",value,probe_index) - IPA_Meta("Input_SeriesR_Corr_Lag",num2str(value*1e-6),ampl_index,1) - return TRUE - break - case "Bridge": - if (value<0) - value = 0 - elseif (value>200e6) - value = 200e6 - endif - value *=1e-6 - if (probe_index == active_tab) - CheckBox check7 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar11 win=SP_SutterAmp0, value=_NUM:(value) - endif - setval = round(value*81.92) - SutterDAQwrite(ampl_index,2+21*HS_index,5,(setval&0xff00)/256,setval&0x00ff) - SaveStructure("bridge",value,probe_index) - SaveStructure("bridgeon",1,probe_index) - IPA_Meta("Input_BridgeBalance_R",num2str(value*1e6),ampl_index,1) - return TRUE - break - case "BridgeOn": - if (probe_index == active_tab) - CheckBox check7 win=SP_SutterAmp0, value=value - endif - setval = value*round(ipa.bridge*81.92) - SutterDAQwrite(ampl_index,2+21*HS_index,5,(setval&0xff00)/256,setval&0x00ff) - SaveStructure("bridgeon",!!value,probe_index) - return TRUE - break - case "AutoEComp": //not amplifier specific - ba.eventCode = 2 - ba.ctrlName="SDbutton7" - ButtonProc_SD3(ba) - return TRUE - break - case "AutoCellComp": //not amplifier specific - ba.eventCode = 2 - ba.ctrlName="SDbutton6" - ButtonProc_SD3(ba) - return TRUE - break - case "RsCompOn": // Rs Compensation enabled - if (probe_index == active_tab) - CheckBox check1, value=value, win=SP_SutterAmp0 - endif - SaveStructure("compon",!!value,probe_index) - SetCompensation(probe_count) - IPA_Meta("Input_Whole_Cell",num2str(!!value),ampl_index,1) - break - case "RsCorrOn": //Prediction/Correction enabled - if (probe_index == active_tab) - CheckBox check2, value=value, win=SP_SutterAmp0 - endif - SaveStructure("corron",!!value,probe_index) - SetCompensation(probe_count) - SetCorrection(probe_count) - IPA_Meta("Input_SeriesR_Corr",num2str(!!value),0,1) - break - case "DynHold": - if (abs(value)>1) - value = sign(value) - endif - value*=1000 - if (probe_index == active_tab) - CheckBox check3 win=SP_SutterAmp0, value=1 - SetVariable SDsetvar19 win=SP_SutterAmp0, value=_NUM:(value) - endif - setval = round(value*32.767) - SutterDAQwrite(ampl_index,19+6*HS_index,1,(setval&0xff00)/256,setval&0x00ff) - SaveStructure("track",value,probe_index) - IPA_Meta("Input_Slow_Track_Value",num2str(value*1e-3),ampl_index,1) - return TRUE - break - case "DynHoldOn": //Slow holding potential enabled - SaveStructure("trackon",!!value,-1) - IPA_Meta("Input_Slow_Track",num2str(!!value),0,1) - Controlinfo /W=SP_SutterAmp0 SDtab0 - if (value) //Tracking turned ON - CheckBox check3, value=1, win=SP_SutterAmp0 - if (V_value == 1) - SetVariable SDsetvar10 win=SP_SutterAmp0, disable=2 - CheckBox check6 win=SP_SutterAmp0, disable=2 - endif - if (ipa.vc==2) //CC - Controlinfo /w=SP_SutterAmp0 SDsetvar19 // Slow Hold value - setval =32.767 * v_value - SutterDAQwrite(ampl_index,19+6*HS_index,1,((setval)&0xff00)/256,(setval)&0x00ff) - endif - else //Tracking turned OFF - CheckBox check3, value=0, win=SP_SutterAmp0 - if (V_value == 1) - SetVariable SDsetvar10 win=SP_SutterAmp0, disable=0 - CheckBox check6 win=SP_SutterAmp0, disable=0 - endif - if (ipa.vc==2) - SutterDAQwrite(ampl_index,19,0,0,0) - endif - endif - break - case "ECompOn": //Current Clamp electrode compensation enabled. - CheckBox check4, value=value, win=SP_SutterAmp0 - if (ipa.vc==2) //only set if in CC - setval=value*round((ipa.fastmag+kCC_deltaCap-kStabilityControl)*655.32) - SutterDAQwrite(ampl_index ,2,2,(setval&0xff00)/256,setval&0x00ff) - endif - SaveStructure("capneuton",!!value,-1) - break - case "VHoldOn": //Holding potential set - CheckBox check5, value=!!value, win=SP_SutterAmp0 - if (ipa.vc==0) //only set if in VC - setval = 32.767*ipa.hpot*value - SutterDAQwrite(ampl_index,16,0,(setval&0xff00)/256,setval&0x00ff) - SaveStructure("hpoton",!!value,-1) - endif - break - case "IHoldOn": //Holding current set - CheckBox check6, value = !!value, win=SP_SutterAmp0 - if (ipa.vc==2) //Only set if in CC - setval = 1.63835*ipa.hcurr*value - SutterDAQwrite(ampl_index,16,0,(setval&0xff00)/256,setval&0x00ff) - endif - SaveStructure("hcurron",!!value,-1) - break - case "DigOutWord": //not amplifier specific - variable step - NVar /Z SD_DIO=dfr:SD_DIO - SD_DIO = value - for (step=0; step<8; step+=1) - if (value & 2^step) - SutterDAQwrite(0,22,0,step,1) - Slider $("slider"+num2str(step)) win=SP_SutterAmp0, value=1 - else - SutterDAQwrite(0,22,0,step,0) - Slider $("slider"+num2str(step)) win=SP_SutterAmp0, value=0 - endif - endfor - SaveStructure("dout",value,-1) - IPA_Meta("Cmd_Digital_Out_Pattern",num2str(value),0,1) - return TRUE - break - case "AuxOut1": - if (abs(value)>10) - value = 10*sign(value) - endif - setval =value* 3276.7 - SutterDAQwrite(ampl_index,17,2, (setval&0xff00)/256,setval&0x00ff) - controlinfo /w=SP_SutterAmp0 popup0 - if (v_value==1) - SetVariable SDsetvar20 win=SP_SutterAmp0, value=_NUM:value - endif - SaveStructure("AOut0",value,-1) - IPA_Meta("Cmd_Aux_Holding_Value_1",num2str(value),0,1) - Return TRUE - case "AuxOut2": - if (abs(value)>10) - value = 10*sign(value) - endif - setval =value* 3276.7 - SutterDAQwrite(ampl_index ,17,3, (setval&0xff00)/256,setval&0x00ff) - controlinfo /w=SP_SutterAmp0 popup0 - if (v_value==2) - SetVariable SDsetvar20 win=SP_SutterAmp0, value=_NUM:value - endif - SaveStructure("AOut1",value,-1) - IPA_Meta("Cmd_Aux_Holding_Value_2",num2str(value),0,1) - Return TRUE - case "Reconnect": - ResetUSB() - return TRUE - case "AutoOffset": - if (IPA_GetValue(probe_count,"OffsetLock")) - return FALSE - endif - ZeroIPAOffset() - return TRUE - case "SealTest": - if (value==0) - SutterDAQWrite(0,18,0,10,10) - else - SutterDAQwrite(0,18,1,10,value) - endif - SaveStructure("seal",value,0) - Return TRUE - -// case "AutoBridge": -// if (IPA_AutoBridge() != TRUE) -// return FALSE -// endif -// return TRUE - DEFAULT: - return FALSE //Not a proper keyword - endswitch - - else - // Error handling here - return FALSE - endif -End - - -Function ButtonProcUSBreset(STRUCT WMButtonAction &ba) : ButtonControl - if (ba.eventCode == 2) - ba.blockreentry = 1 - ResetUSB() - endif - return 0 -End - - -Function ResetControls() - DFREF dfr=$AmpPath - Wave /T /Z structurewave = dfr:structurewave - if (WaveExists(structurewave)==0) - CreateStructure(1) - endif - //Reset Structure Wave - ResetStructureWave(structurewave) - IPA_SetValue(0,"SelectHS",1) - //Reset Amplifier to match - ResetAmplifier(dimsize(structurewave,0)) - -End - -static Function ZeroIPAOffset() //This is the automatic offset button - // Determine active probe - ControlInfo /W=SP_SutterAmp0 SDtab - variable ProbeCount=V_value - variable Amp = str2num(GetUserData("SP_SutterAmp0","","Amp")) - variable HS = str2num(GetUserData("SP_SutterAmp0","","HS")) - variable readvalue - variable myoffset = (IPA_GetValue(0,"Offset")*2^16) - variable myLJP = (IPA_GetValue(0,"LJP")*2^16) - variable offsetMV - variable readchannel - if (HS==0) - readchannel=1 - else - readchannel=21 //Second headstage on dIPA - endif - if (IPA_GetValue(0,"VCMode")) - variable offsetstep = 1024 //Start at 16 mV step - variable direction =1 - variable count = 0 - readvalue = sutterdaqread(Amp,readchannel) - direction = (readvalue > 0) //1 is positive, 0 is negative - if (abs(readvalue*IPA_GetValue(0,"Igain")) > 9.9) - //Print "Out of Range" - offsetstep = 2048 //32 mV - endif - for (count=0; count<50; count+=1) - if (abs(readvalue)<2e-12 || offsetstep < 1) - break - endif - if (readvalue>0) - if (!direction) - offsetstep /=2 - endif - myoffset-=offsetstep - direction = 1 - else - if (direction) - offsetstep /=2 - endif - myoffset += offsetstep - direction = 0 - endif - if (abs(myoffset)>16384) - myoffset = 16384*sign(myoffset) //limit to +/- 250 mV - break - endif - if (HS==1) //Second HS on dIPA - SutterDAQwrite(Amp,17,4,(myoffset&0xff00)/256,myoffset&0x00ff) - else - SutterDAQwrite(Amp,17,1,(myoffset&0xff00)/256,myoffset&0x00ff) - endif - IPA_tickdelay(3) //Wait before taking next reading (~50ms) - readvalue = sutterdaqread(Amp,readchannel) - endfor - myoffset += myljp - if (HS==1) //Second HS on dIPA - SutterDAQwrite(Amp,17,4,(myoffset&0xff00)/256,myoffset&0x00ff) - else - SutterDAQwrite(Amp,17,1,(myoffset&0xff00)/256,myoffset&0x00ff) - endif - else - // Otherwise CC, just read voltage and subtract - readvalue = sutterdaqread(Amp,readchannel) - myoffset += readvalue*2^16 - if (abs(myoffset)>16384) - myoffset = 16384*sign(myoffset) - endif - myoffset += myljp - if (HS==1) //Second HS on dIPA - SutterDAQwrite(Amp,17,4,(myoffset&0xff00)/256,myoffset&0x00ff) - else - SutterDAQwrite(Amp,17,1,(myoffset&0xff00)/256,myoffset&0x00ff) - endif - endif - offsetMV =myoffset*1000/2^16 //convert offset to volts - SetVariable SDSetVar0 win=SP_SutterAmp0, value=_Num:offsetmV - SaveStructure("offset",myoffset,ProbeCount) //structure saves in bits - IPA_Meta("Input_Offset",num2str(1000*offsetmv),ProbeCount,0) - return 0 -end - -//--------------- ZAP, BUZZ and SEALTEST --------------------------- - -Function IPA_Buzz(variable Duration) //duration in ms, must be in CC - if (IPA_GetValue(0,"CCmode")) - DFREF dfr=$AmpPath - Wave /Z/T structurewave = dfr:structurewave - STRUCT IPAControlvalues ipa - StructGet /S ipa, structurewave[0] - SutterDAQwrite(0,2,1,3,0) - SutterDAQwrite(0,2,2,40,0) - variable step, stepsign - stepsign=1 - for (step=0; step<(1*duration); step+=1) - if (stepsign==1) - SutterDAQwrite(0,16,0,192,0) - stepsign= -1 - else - SutterDAQwrite(0,16,0,64,0) - stepsign=1 - endif - IPA_usdelay(1000) - endfor - variable setval - setval=round((ipa.fastmag+kCC_deltaCap-kStabilityControl)*655.32)*ipa.capneuton - SutterDAQwrite(0,2,2,(setval&0xff00)/256,setval&0x00ff) - setval=round((ipa.fastphase-0.1)*1023/4.4) - SutterDAQwrite(0,2,1,(setval&0xff00)/256,setval&0x00ff) - setval = 1.63835*ipa.hcurr*ipa.hcurron - SutterDAQwrite(0,16,0,(setval&0xff00)/256,setval&0x00ff) - endif -end - -Function ZapPanel() - if (wintype("IPA_Zap")) - DoWindow /F IPA_Zap - else - STRUCT SutterDAQPanelPrefs prefs - LoadPackagePrefs(prefs) - NewPanel /W=(prefs.ZapPanelCoords[0],prefs.ZapPanelCoords[1],prefs.ZapPanelCoords[2],prefs.ZapPanelCoords[3]) /k=1 /n=IPA_Zap as "IPA Zap" - ModifyPanel /W=IPA_Zap fixedSize=1, noEdit=1 - Button Zap_btn, focusring=0,pos={40,63},size={50,24},fsize=12, proc=Trig_Zap,title="Zap",help={"Single square wave"} - SetVariable zapvar0, focusring=0, pos={108,65}, size={65,20},fsize=12,value= _NUM:prefs.ZapDuration,format="%.1f ms",limits={0.1,2,0.1}, help={"Set zap duration"} - SetVariable zapvar1, focusring=0, pos={180,65}, size={55,20},fsize=12,value= _NUM:prefs.ZapVoltage,format="%.1f V",limits={0.1,1,0.1}, help={"Set zap amplitude"} - DoWindow SP_SutterAmp0 - if (V_flag) - variable NumHS = ipa_getvalue(0,"numHS") - variable Headstage = ipa_getvalue(0,"ActiveHS") - else - NumHS = 1 - endif - switch (NumHS) - case 2: - PopupMenu popupZap focusRing=0,pos={45,20},size={140,20},title="Headstage " - PopupMenu popupZap fSize=12,mode=2,popvalue=num2str(Headstage),value= #"\"1;2\"" - break - case 3: - PopupMenu popupZap focusRing=0,pos={45,20},size={140,20},title="Headstage " - PopupMenu popupZap fSize=12,mode=2,popvalue=num2str(Headstage),value= #"\"1;2;3\"" - break - case 4: - PopupMenu popupZap focusRing=0,pos={45,20},size={140,20},title="Headstage " - PopupMenu popupZap fSize=12,mode=2,popvalue=num2str(Headstage),value= #"\"1;2;3;4\"" - break - default: - TitleBox titleZap pos={45,22}, title="Headstage 1",frame=0, focusRing=0, fSize=12 - break - endswitch - SetWindow kwTopWin,hook(myhook)=IPA#SutterZapHook - endif -End - -Function SutterZapHook(s) - STRUCT WMWinHookStruct &s - variable hookResult=0 - strswitch(s.eventname) - case "activate": // Activate - break - case "kill": //Kill - IPA#UpdatePrefs() - break - case "moved": - break - case "mousedown": - break - endswitch - return hookResult // 0 if nothing done, else 1 -End - -Function Trig_Zap(ba) : ButtonControl - STRUCT WMButtonAction &ba - ba.blockreentry = 1 - switch( ba.eventCode ) - case 2: // mouse up - if (!datafolderexists("root:SutterIPA")) - NewDataFolder root:SutterIPA - endif - Make /o/n=3 root:SutterIPA:ZapWave = 0 - Wave ZapWave = root:SutterIPA:ZapWave - ControlInfo /w=IPA_Zap zapvar1 - ZapWave[0] = V_Value - ControlInfo /w=IPA_Zap zapvar0 - Setscale /p x, 0, (V_Value/1000), "s", ZapWave - ControlInfo /w=IPA_Zap popupZap - if (V_flag == 0) - V_Value = 1 - endif - Make /o/n=(1,2) /T root:SutterIPA:ZapList - Wave /T ZapList = root:SutterIPA:ZapList - ZapList[0][0] = "root:SutterIPA:ZapWave" - ZapList[0][1] = num2str(V_Value-1) - SutterDAQWriteWave /T=0 /R=0 /RHP=0 root:SutterIPA:ZapList - break - case -1: // control being killed - break - endswitch - return 0 -End - -Function Set_Zap(sva) : SetVariableControl - STRUCT WMSetVariableAction &sva - - switch( sva.eventCode ) - case 1: // mouse up - case 2: // Enter key - case 3: // Live update - Variable dval = sva.dval - String sval = sva.sval - Wave ZapWave = ZapWave - if (cmpstr(sva.ctrlName,"zapvar0")==0) - SetScale/P x 0,(sva.dval*.001),"s", ZapWave - else - ZapWave[0] = sva.dval*.99 - endif - break - case -1: // control being killed - break - endswitch - return 0 -End - -