Skip to content

Commit

Permalink
Merge pull request #1667 from AllenInstitute/feature/1667-sutter-support
Browse files Browse the repository at this point in the history
Add support for Sutter DAC
  • Loading branch information
t-b authored Apr 11, 2024
2 parents 0a5b202 + 22dfc0d commit 90f5a1b
Show file tree
Hide file tree
Showing 49 changed files with 1,869 additions and 370 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ jobs:
experiment: Packages/tests/Compilation/CompilationTester.pxp
installer_flags: "-s git"
artifact_name: Compilation-Each-Commit-assets
timeout_minutes: 120
timeout_minutes: 180

Documentation:
name: 👷 Documentation
Expand Down
14 changes: 10 additions & 4 deletions Packages/MIES/MIES_AnalysisFunctionManagement.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Function AFM_CallAnalysisFunctions(device, eventType)
string device
variable eventType

variable i, valid_f1, valid_f2, valid_f3, ret, DAC, sweepsInSet
variable i, valid_f1, valid_f2, valid_f3, ret, DAC, sweepsInSet, hwIsSutter
variable realDataLengthAD, realDataLengthDA, sweepNo, fifoPositionAD, fifoPositionDA, sampleIntDA, sampleIntAD
string func, msg
STRUCT AnalysisFunction_V3 s
Expand Down Expand Up @@ -44,6 +44,8 @@ Function AFM_CallAnalysisFunctions(device, eventType)
fifoPositionDA = HW_GetDAFifoPosition(device, DATA_ACQUISITION_MODE)
endif

hwIsSutter = GetHardwareType(device) == HARDWARE_SUTTER_DAC

for(i = 0; i < NUM_HEADSTAGES; i += 1)

if(!statusHS[i])
Expand Down Expand Up @@ -135,11 +137,15 @@ Function AFM_CallAnalysisFunctions(device, eventType)

if(valid_f1)
WAVE DAQDataWave = GetDAQDataWave(device, DATA_ACQUISITION_MODE)
ChangeWaveLock(DAQDataWave, 1)
if(!hwIsSutter)
ChangeWaveLock(DAQDataWave, 1)
endif
ret = f1(device, eventType, DAQDataWave, i); AbortOnRTE
elseif(valid_f2)
WAVE DAQDataWave = GetDAQDataWave(device, DATA_ACQUISITION_MODE)
ChangeWaveLock(DAQDataWave, 1)
if(!hwIsSutter)
ChangeWaveLock(DAQDataWave, 1)
endif
ret = f2(device, eventType, DAQDataWave, i, realDataLengthAD); AbortOnRTE
elseif(valid_f3)

Expand Down Expand Up @@ -181,7 +187,7 @@ Function AFM_CallAnalysisFunctions(device, eventType)
if(WaveExists(dataWave))
ChangeWaveLock(dataWave, 0)
endif
if(WaveExists(DAQDataWave))
if(WaveExists(DAQDataWave) && !hwIsSutter)
ChangeWaveLock(DAQDataWave, 0)
endif

Expand Down
56 changes: 46 additions & 10 deletions Packages/MIES/MIES_AnalysisFunctions_PatchSeq.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ static Function [variable ret, variable chunk] PSQ_EvaluateBaselineChunks(string

variable numBaselineChunks, i, totalOnsetDelay, fifoInStimsetTime

numBaselineChunks = PSQ_GetNumberOfChunks(device, s.sweepNo, s.headstage, type, s.sampleIntervalAD)
numBaselineChunks = PSQ_GetNumberOfChunks(device, s.sweepNo, s.headstage, type, s.sampleIntervalDA)

if(type == PSQ_CHIRP)
ASSERT(numBaselineChunks >= 3, "Unexpected number of baseline chunks")
Expand Down Expand Up @@ -1139,14 +1139,13 @@ End
/// - 3: leak current baseline QC
Function/WAVE PSQ_CreateOverrideResults(string device, variable headstage, variable type, [string opMode])

variable DAC, numCols, numRows, numLayers, numChunks, sampleIntervalAD, firstADChannelIndex
variable DAC, numCols, numRows, numLayers, numChunks, sampleIntervalDA
string stimset
string layerDimLabels = ""

WAVE config = GetDAQConfigWave(device)

firstADChannelIndex = GetFirstADCChannelIndex(config)
sampleIntervalAD = config[firstADChannelIndex][%SamplingInterval] * MICRO_TO_MILLI
sampleIntervalDA = config[0][%SamplingInterval] * MICRO_TO_MILLI

DAC = AFH_GetDACFromHeadstage(device, headstage)
stimset = AFH_GetStimSetName(device, DAC, CHANNEL_TYPE_DAC)
Expand All @@ -1161,13 +1160,13 @@ Function/WAVE PSQ_CreateOverrideResults(string device, variable headstage, varia
case PSQ_RAMP:
case PSQ_RHEOBASE:
numChunks = 4
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalAD)
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalDA)
numCols = IDX_NumberOfSweepsInSet(stimset)
layerDimLabels = "BaselineQC;SpikePositionAndQC;AsyncQC"
break
case PSQ_DA_SCALE:
numChunks = 4
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalAD)
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalDA)
numCols = IDX_NumberOfSweepsInSet(stimset)
layerDimLabels = "BaselineQC;SpikePosition;NumberOfSpikes;AsyncQC"
break
Expand All @@ -1178,13 +1177,13 @@ Function/WAVE PSQ_CreateOverrideResults(string device, variable headstage, varia
break
case PSQ_CHIRP:
numChunks = 4
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalAD)
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalDA)
numCols = IDX_NumberOfSweepsInSet(stimset)
layerDimLabels = "BaselineQC;MaxInChirp;MinInChirp;SpikeQC;AsyncQC"
break
case PSQ_PIPETTE_BATH:
numChunks = 4
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalAD)
numRows = PSQ_GetNumberOfChunks(device, 0, headstage, type, sampleIntervalDA)
numCols = IDX_NumberOfSweepsInSet(stimset)
layerDimLabels = "BaselineQC;SteadyStateResistance;AsyncQC"
break
Expand Down Expand Up @@ -1673,6 +1672,22 @@ static Function PSQ_GetDefaultSamplingFrequency(string device, variable type)
default:
ASSERT(0, "Unknown analysis function")
endswitch
case HARDWARE_SUTTER_DAC:
switch(type)
case PSQ_CHIRP:
case PSQ_DA_SCALE:
case PSQ_RAMP:
case PSQ_RHEOBASE:
case PSQ_SQUARE_PULSE:
return 50
case PSQ_PIPETTE_BATH:
case PSQ_SEAL_EVALUATION:
case PSQ_TRUE_REST_VM:
case PSQ_ACC_RES_SMOKE:
return 50
default:
ASSERT(0, "Unknown analysis function")
endswitch
default:
ASSERT(0, "Unknown hardware type")
endswitch
Expand All @@ -1687,6 +1702,8 @@ Function PSQ_GetDefaultSamplingFrequencyForSingleHeadstage(string device)
return 50
case HARDWARE_NI_DAC:
return 125
case HARDWARE_SUTTER_DAC:
return 50
default:
ASSERT(0, "Unknown hardware")
endswitch
Expand Down Expand Up @@ -1730,7 +1747,7 @@ End
/// Not every analysis function uses every parameter though.
static Function/S PSQ_GetHelpCommon(variable type, string name)

string freqITC, freqNI
string freqITC, freqNI, freqSU

strswitch(name)
case "AsyncQCChannels":
Expand Down Expand Up @@ -1758,7 +1775,8 @@ static Function/S PSQ_GetHelpCommon(variable type, string name)
case "SamplingFrequency":
freqITC = num2str(PSQ_GetDefaultSamplingFrequency("ITC16", type))
freqNI = num2str(PSQ_GetDefaultSamplingFrequency("Dev1", type))
return "Required sampling frequency for the acquired data [kHz]. Defaults to ITC:" + freqITC + " NI:" + freqNI + "."
freqSU = num2str(PSQ_GetDefaultSamplingFrequency(DEVICE_SUTTER_NAME_START_CLEAN + "1", type))
return "Required sampling frequency for the acquired data [kHz]. Defaults to ITC:" + freqITC + " NI:" + freqNI + " Sutter:" + freqSU + "."
case "SamplingMultiplier":
return "Sampling multiplier, use 1 for no multiplier"
default:
Expand Down Expand Up @@ -3522,6 +3540,24 @@ Function PSQ_Ramp(device, s)

PSQ_Ramp_AddEpoch(device, s.headstage, NIChannel, "Name=DA suppression", "RA_DS", V_FIFOChunks, DimSize(NIChannel, ROWS) - 1)
endif
elseif(hardwareType == HARDWARE_SUTTER_DAC)
// the sutter XOP might prefetch upto 4096 samples

WAVE config = GetDAQConfigWave(device)
WAVE/WAVE SUDataWave = daqDataWave
WAVE/WAVE scaledDataWave = GetScaledDataWave(device)
// As only one AD and DA channel is allowed for this function, at index 0 the setting for first DA channel are expected
WAVE channelDA = SUDataWave[0]
WAVE scaledChannelDA = scaledDataWave[0]
fifoPos = HW_GetDAFifoPosition(device, DATA_ACQUISITION_MODE)
if(fifoPos < DimSize(channelDA, ROWS))
MultiThread channelDA[fifoPos,] = 0
ChangeWaveLock(scaledChannelDA, 0)
MultiThread scaledChannelDA[fifoPos,] = 0
ChangeWaveLock(scaledChannelDA, 1)

PSQ_Ramp_AddEpoch(device, s.headstage, scaledChannelDA, "Name=DA suppression", "RA_DS", fifoPos, DimSize(channelDA, ROWS) - 1)
endif
else
ASSERT(0, "Unknown hardware type")
endif
Expand Down
1 change: 1 addition & 0 deletions Packages/MIES/MIES_AsynchronousData.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Function ASD_CheckAsynAlarmState(string device, variable value, variable minValu
End

/// @brief Read the given asynchronous channel and return the scaled value
/// It is only valid to call for ITC and SUTTER when there is no acquisition running.
Function ASD_ReadChannel(device, channel)
string device
variable channel
Expand Down
39 changes: 28 additions & 11 deletions Packages/MIES/MIES_Configuration.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -583,25 +583,36 @@ Function CONF_PrimeDeviceLists(string device)

variable hardwareType

hardwareType = GetHardwareType(device)
SVAR globalITCDeviceList = $GetITCDeviceList()
SVAR globalNIDeviceList = $GetNIDeviceList()
SVAR globalSUDeviceList = $GetSUDeviceList()

hardwareType = GetHardwareType(device)
switch(hardwareType)
case HARDWARE_ITC_DAC:
SVAR globalDeviceList = $GetITCDeviceList()
SVAR globalOtherDeviceList = $GetNIDeviceList()
if(IsEmpty(globalITCDeviceList))
globalITCDeviceList = device + ";"
globalNIDeviceList = NONE
globalSUDeviceList = NONE
endif
break
case HARDWARE_NI_DAC:
SVAR globalDeviceList = $GetNIDeviceList()
SVAR globalOtherDeviceList = $GetITCDeviceList()
if(IsEmpty(globalNIDeviceList))
globalITCDeviceList = NONE
globalNIDeviceList = device + ";"
globalSUDeviceList = NONE
endif
break
case HARDWARE_SUTTER_DAC:
if(IsEmpty(globalSUDeviceList))
globalITCDeviceList = NONE
globalNIDeviceList = NONE
globalSUDeviceList = device + ";"
endif
break
default:
ASSERT(0, "Unknown hardwareType")
endswitch

if(IsEmpty(globalDeviceList))
globalDeviceList = device + ";"
globalOtherDeviceList = NONE
endif
End

/// @brief Restores the GUI state of a DA_Ephys panel from a configuration file
Expand Down Expand Up @@ -2020,7 +2031,9 @@ static Function CONF_RestoreHeadstageAssociation(device, jsonID, midExp)
if(type == JSON_NULL)
PGC_SetAndActivateControl(device, "popup_Settings_Amplifier", str = NONE)
PGC_SetAndActivateControl(device, "popup_Settings_Pressure_dev", str = NONE)
PGC_SetAndActivateControl(device, "button_Hardware_ClearChanConn")
if(!IsDeviceNameFromSutter(device))
PGC_SetAndActivateControl(device, "button_Hardware_ClearChanConn")
endif
elseif(type == JSON_OBJECT)
jsonPathAmpBlock = jsonBasePath + "/" + EXPCONFIG_JSON_AMPBLOCK + "/"
ampSerial = JSON_GetVariable(jsonID, jsonPathAmpBlock + EXPCONFIG_JSON_AMPSERIAL)
Expand Down Expand Up @@ -2111,6 +2124,10 @@ static Function CONF_SetDAEPhysChannelPopup(string device, string ctrl, variable

variable channelNumber

if(IsDeviceNameFromSutter(device))
return NaN
endif

if(JSON_Exists(jsonId, jsonPath))
channelNumber = JSON_GetVariable(jsonID, jsonPath)
if(IsNaN(channelNumber))
Expand Down
29 changes: 28 additions & 1 deletion Packages/MIES/MIES_Constants.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -777,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
/// @}

Expand All @@ -807,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]
Expand Down Expand Up @@ -1019,6 +1028,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

Expand Down Expand Up @@ -2214,3 +2239,5 @@ StrConstant SWEEP_NOTE_KEY_ORIGCREATIONTIME_UTC = "OriginalCreationTimeInUTC"

StrConstant DF_NAME_FREE = "freeroot"
StrConstant DF_NAME_MIES = "MIES"

Constant SUTTER_MAX_MAX_TP_PULSES = 10000
Loading

0 comments on commit 90f5a1b

Please sign in to comment.