diff --git a/Packages/MIES/MIES_DAEphys.ipf b/Packages/MIES/MIES_DAEphys.ipf index 80055d0f35..1334d80fa0 100644 --- a/Packages/MIES/MIES_DAEphys.ipf +++ b/Packages/MIES/MIES_DAEphys.ipf @@ -1521,7 +1521,7 @@ Function DAP_PopMenuChkProc_StimSetList(pa) : PopupMenuControl // is not yet reflected in the user data list = GetUserData(device, ctrl, USER_DATA_MENU_EXP) if(FindListItem(stimSet, list) == -1) - DAP_UpdateDaEphysStimulusSetPopups() + WB_UpdateChangedStimsets() endif endif @@ -4456,7 +4456,7 @@ Function DAP_LockDevice(string win) DAP_UpdateDAQControls(deviceLocked, REASON_STIMSET_CHANGE | REASON_HEADSTAGE_CHANGE) // create the amplifier settings waves GetAmplifierParamStorageWave(deviceLocked) - DAP_UpdateDaEphysStimulusSetPopups(device=deviceLocked) + WB_UpdateChangedStimsets(device=deviceLocked) DAP_UnlockCommentNotebook(deviceLocked) DAP_ToggleAcquisitionButton(deviceLocked, DATA_ACQ_BUTTON_TO_DAQ) SI_CalculateMinSampInterval(deviceLocked, DATA_ACQUISITION_MODE) @@ -5339,6 +5339,7 @@ Function DAP_DeleteStimulusSet(string setName, [string device]) if(ParamIsDefault(device)) WB_KillParameterWaves(setName) WB_KillStimset(setName) + WB_UpdateChangedStimsets() return NaN endif @@ -5351,7 +5352,7 @@ Function DAP_DeleteStimulusSet(string setName, [string device]) WB_KillParameterWaves(setName) WB_KillStimset(setName) - DAP_UpdateDaEphysStimulusSetPopups(device = device) + WB_UpdateChangedStimsets(device = device) End /// @brief Write all TP settings from the data acquisition/settings tab to the settings wave diff --git a/Packages/MIES/MIES_DataBrowser_Macro.ipf b/Packages/MIES/MIES_DataBrowser_Macro.ipf index 4245176470..e3d90730db 100644 --- a/Packages/MIES/MIES_DataBrowser_Macro.ipf +++ b/Packages/MIES/MIES_DataBrowser_Macro.ipf @@ -628,7 +628,7 @@ Window DataBrowser() : Graph SetVariable setvar_pulseAver_startPulse,limits={0,inf,1},value=_NUM:0 CheckBox check_pulseAver_multGraphs,pos={234.00,165.00},size={121.00,15.00},disable=1,proc=PA_CheckProc_Common CheckBox check_pulseAver_multGraphs,title="Use multiple graphs" - CheckBox check_pulseAver_multGraphs,help={"Show the single pulses in multiple graphs or only one graph with mutiple axis."} + CheckBox check_pulseAver_multGraphs,help={"Show the single pulses in multiple graphs or only one graph with multiple axis."} CheckBox check_pulseAver_multGraphs,userdata(tabnum)="4" CheckBox check_pulseAver_multGraphs,userdata(tabcontrol)="Settings" CheckBox check_pulseAver_multGraphs,userdata(ResizeControlsInfo)=A"!!,H%!!#A4!!#@V!!#<(z!!#`-A7TLfzzzzzzzzzzzzzz!!#r+D.OhkBk2=!z" diff --git a/Packages/MIES/MIES_NeuroDataWithoutBorders.ipf b/Packages/MIES/MIES_NeuroDataWithoutBorders.ipf index 46a9666146..7ed7171fa6 100644 --- a/Packages/MIES/MIES_NeuroDataWithoutBorders.ipf +++ b/Packages/MIES/MIES_NeuroDataWithoutBorders.ipf @@ -1634,7 +1634,7 @@ Function NWB_LoadAllStimsets([overwrite, fileName, loadOnlyBuiltins]) HDF5CloseGroup/Z groupID H5_CloseFile(fileID) - DAP_UpdateDaEphysStimulusSetPopups() + WB_UpdateChangedStimsets() LOG_AddEntry(PACKAGE_MIES, "end") diff --git a/Packages/MIES/MIES_Utilities.ipf b/Packages/MIES/MIES_Utilities.ipf index 52b06b5e4f..19e0e1c08b 100644 --- a/Packages/MIES/MIES_Utilities.ipf +++ b/Packages/MIES/MIES_Utilities.ipf @@ -739,7 +739,7 @@ End /// @param upsampleFactor positive non-zero integer by which the wave should /// be upsampled /// @param mode decimation mode, one of @ref DECIMATION_BY_OMISSION, -/// @ref DECIMATION_BY_AVERAGING +/// @ref DECIMATION_BY_AVERAGING /// or @ref DECIMATION_BY_SMOOTHING. /// @param winFunction Windowing function for @ref DECIMATION_BY_SMOOTHING mode, /// must be one of @ref FFT_WINF. @@ -2116,13 +2116,14 @@ threadsafe Function/S RemoveEndingRegExp(str, endingRegExp) string str, endingRegExp string endStr + variable err if(isEmpty(str) || isEmpty(endingRegExp)) return str endif - SplitString/E="(" + endingRegExp + ")$" str, endStr - ASSERT_TS(V_flag == 0 || V_flag == 1, "Unexpected number of matches") + SplitString/E=("(" + endingRegExp + ")$") str, endStr; err = GetRTError(1) + ASSERT_TS((V_flag == 0 || V_flag == 1) && err == 0, "Unexpected number of matches or invalid regex") return RemoveEnding(str, endStr) End @@ -2150,20 +2151,38 @@ End /// /// @return 1 if word was found in str and word was not "". 0 if not. Function SearchWordInString(string str, string word, [string &prefix, string &suffix]) - WAVE/Z/T wv = SearchStringBase(str, "(.*)\\b\\Q" + word + "\\E\\b(.*)") - if(!WaveExists(wv)) - return 0 + + string prefixParam, suffixParam + variable ret + + [ret, prefixParam, suffixParam] = SearchRegexInString(str, "\\b\\Q" + word + "\\E\\b") + + if(!ret) + return ret endif if(!ParamIsDefault(prefix)) - prefix = wv[0] + prefix = prefixParam endif if(!ParamIsDefault(suffix)) - suffix = wv[1] + suffix = suffixParam endif - return 1 + return ret +End + +static Function [variable ret, string prefix, string suffix] SearchRegexInString(string str, string regex) + + ASSERT(IsValidRegexp(regex), "Empty regex") + + WAVE/Z/T wv = SearchStringBase(str, "(.*)" + regex + "(.*)") + + if(!WaveExists(wv)) + return [0, "", ""] + endif + + return [1, wv[0], wv[1]] End /// @brief More advanced version of SplitString @@ -4056,24 +4075,27 @@ Function/S SortAxisList(graph, list) return TextWaveToList(axisListWave, ";") End -/// @brief Replaces all occurences of the string `word`, treated as regexp word, -/// in `str` with `replacement`. Does not ignore case. -Function/S ReplaceWordInString(word, str, replacement) - string word, str, replacement +Function/S ReplaceWordInString(string word, string str, string replacement) - ASSERT(!IsEmpty(word), "Empty regex") - - variable ret - string result, prefix, suffix + ASSERT(!IsEmpty(word), "Empty word") if(!cmpstr(word, replacement, 0)) return str endif + return ReplaceRegexInString("\\b\\Q" + word + "\\E\\b", str, replacement) +End + +/// @brief Replaces all occurences of the regular expression `regex` in `str` with `replacement` +Function/S ReplaceRegexInString(string regex, string str, string replacement) + + variable ret + string result, prefix, suffix + result = str for(;;) - ret = SearchWordInString(result, word, prefix = prefix, suffix = suffix) + [ret, prefix, suffix] = SearchRegexInString(result, regex) if(!ret) break diff --git a/Packages/MIES/MIES_WaveBuilder.ipf b/Packages/MIES/MIES_WaveBuilder.ipf index bbcd508e31..fc5dd8fe79 100644 --- a/Packages/MIES/MIES_WaveBuilder.ipf +++ b/Packages/MIES/MIES_WaveBuilder.ipf @@ -1937,12 +1937,9 @@ static Function/WAVE WB_FillWaveFromFormula(formula, channelType, sweep) STRUCT FormulaProperties fp string shorthandFormula - // update shorthand -> stimset mapping - WB_UpdateEpochCombineList(channelType) + shorthandFormula = WB_FormulaSwitchToShorthand(channelType, formula) - shorthandFormula = WB_FormulaSwitchToShorthand(formula) - - if(WB_ParseCombinerFormula(shorthandFormula, sweep, fp)) + if(WB_ParseCombinerFormula(channelType, shorthandFormula, sweep, fp)) return $"" endif @@ -1972,7 +1969,7 @@ End /// /// The rows are sorted by creationDate of the WP/stimset wave to try to keep /// the shorthands constants even when new stimsets are added. -Function WB_UpdateEpochCombineList(variable channelType) +Function WB_UpdateEpochCombineList(WAVE/T epochCombineList, variable channelType) string list, setPath, setParamPath, entry variable numEntries, i @@ -2006,7 +2003,6 @@ Function WB_UpdateEpochCombineList(variable channelType) Sort creationDates, stimsets - Wave/T epochCombineList = GetWBEpochCombineList() Redimension/N=(numEntries, -1) epochCombineList epochCombineList[][%StimSet] = stimsets[p] @@ -2035,16 +2031,14 @@ End /// @brief Parse the formula from the epoch type `Combine` /// -/// @param[in] formula math formula to execute, all operators which Igor can grok are allowed -/// @param sweep current sweep (aka step) -/// @param[out] fp parsed formula structure, with shorthands replaced by stimsets, -/// empty on parse error, ready to be executed by WB_FillWaveFromFormula() +/// @param[in] channelType One of CHANNEL_TYPE_DA or CHANNEL_TYPE_TTL +/// @param[in] formula math formula to execute, all operators which Igor can grok are allowed +/// @param[in] sweep current sweep (aka step) +/// @param[out] fp parsed formula structure, with shorthands replaced by stimsets, +/// empty on parse error, ready to be executed by WB_FillWaveFromFormula() /// /// @returns 0 on success, 1 on parse errors (currently not many are found) -Function WB_ParseCombinerFormula(formula, sweep, fp) - string formula - variable sweep - struct FormulaProperties &fp +Function WB_ParseCombinerFormula(variable channelType, string formula, variable sweep, STRUCT FormulaProperties &fp) string dependentStimsets variable i, numStimsets @@ -2054,7 +2048,7 @@ Function WB_ParseCombinerFormula(formula, sweep, fp) InitFormulaProperties(fp) InitFormulaProperties(trans) - WB_FormulaSwitchToStimset(formula, trans) + WB_FormulaSwitchToStimset(channelType, formula, trans) // look for shorthand-like strings not referring to existing stimsets if(GrepString(trans.formula, "\\b[A-Z][0-9]*\\b")) @@ -2100,10 +2094,7 @@ Function WB_ParseCombinerFormula(formula, sweep, fp) End /// @brief Replace shorthands with the real stimset names suffixed with `?` -Function WB_FormulaSwitchToStimset(formula, fp) - string formula - struct FormulaProperties &fp - +Function WB_FormulaSwitchToStimset(variable channelType, string formula, STRUCT FormulaProperties &fp) string stimset, shorthand, stimsetSpec, prefix, suffix variable numSets, i, stimsetFound @@ -2113,7 +2104,7 @@ Function WB_FormulaSwitchToStimset(formula, fp) return NaN endif - WAVE/T epochCombineList = GetWBEpochCombineList() + WAVE/T epochCombineList = GetWBEpochCombineList(channeltype) formula = UpperStr(formula) @@ -2122,7 +2113,7 @@ Function WB_FormulaSwitchToStimset(formula, fp) // iterate the stimset list from bottom to top, so that we replace first the shorthands // with numeric prefix and only later on the ones without numSets = DimSize(epochCombineList, ROWS) - for(i = numSets - 1; i >= 0; i -= 1) + for(i = numSets - 1; i >= 0 && numSets > 0; i -= 1) shorthand = epochCombineList[i][%Shorthand] stimset = epochCombineList[i][%stimset] stimsetSpec = LowerStr(stimset) + "?" @@ -2164,24 +2155,24 @@ static Function WB_PrepareFormulaForExecute(fp, sweep) End /// @brief Replace all stimsets suffixed with `?` by their shorthands -Function/S WB_FormulaSwitchToShorthand(formula) - string formula +Function/S WB_FormulaSwitchToShorthand(variable channelType, string formula) variable numSets, i - string stimset, shorthand + string stimset, shorthand, regex if(isEmpty(formula)) return "" endif - WAVE/T epochCombineList = GetWBEpochCombineList() + WAVE/T epochCombineList = GetWBEpochCombineList(channelType) numSets = DimSize(epochCombineList, ROWS) for(i = 0; i < numSets; i += 1) shorthand = epochCombineList[i][%Shorthand] stimset = epochCombineList[i][%stimset] - formula = ReplaceString(stimset + "?", formula, shorthand) + regex = "\\b\\Q" + LowerStr(stimset) + "\\E\\b\?" + formula = ReplaceRegexInString(regex, formula, shorthand) endfor return formula @@ -2680,8 +2671,7 @@ Function/S WB_SaveStimSet(string baseName, variable stimulusType, WAVE SegWvType ASSERT(WaveExists(stimset), "Could not recreate stimset") // propagate the existence of the new set - DAP_UpdateDaEphysStimulusSetPopups() - WB_UpdateEpochCombineList(stimulusType) + WB_UpdateChangedStimsets(stimulusType = stimulusType) return setName End @@ -2816,3 +2806,24 @@ Function WB_MakeStimsetThirdParty(string setName) KillOrMoveToTrash(wv=WPT) KillOrMoveToTrash(wv=SegWvType) End + +/// @brief Propagate added/removed stimsets to DA_Ephys panels and our epoch combine list +Function WB_UpdateChangedStimsets([string device, variable stimulusType]) + + if(ParamIsDefault(device)) + DAP_UpdateDaEphysStimulusSetPopups() + else + DAP_UpdateDaEphysStimulusSetPopups(device = device) + endif + + if(ParamIsDefault(stimulusType)) + WAVE/T epochCombineList = GetWBEpochCombineList(CHANNEL_TYPE_DAC) + WB_UpdateEpochCombineList(epochCombineList, CHANNEL_TYPE_DAC) + + WAVE/T epochCombineList = GetWBEpochCombineList(CHANNEL_TYPE_TTL) + WB_UpdateEpochCombineList(epochCombineList, CHANNEL_TYPE_TTL) + else + WAVE/T epochCombineList = GetWBEpochCombineList(stimulusType) + WB_UpdateEpochCombineList(epochCombineList, stimulusType) + endif +End diff --git a/Packages/MIES/MIES_WaveBuilderPanel.ipf b/Packages/MIES/MIES_WaveBuilderPanel.ipf index d5d3a2d567..d433d7f46d 100644 --- a/Packages/MIES/MIES_WaveBuilderPanel.ipf +++ b/Packages/MIES/MIES_WaveBuilderPanel.ipf @@ -116,8 +116,10 @@ Function/S WBP_CreateWaveBuilderPanel() WBP_ClearFolders() + WB_UpdateChangedStimsets() + Execute "WaveBuilder()" - ListBox listbox_combineEpochMap, listWave=GetWBEpochCombineList() + ListBox listbox_combineEpochMap, listWave=GetWBEpochCombineList(WBP_GetStimulusType()) AddVersionToPanel(panel, WAVEBUILDER_PANEL_VERSION) NVAR JSONid = $GetSettingsJSONid() @@ -403,9 +405,6 @@ static Function WBP_UpdatePanelIfAllowed() SetSetVariable(panel, "SetVar_WaveBuilder_P8", maxDuration) endif break - case EPOCH_TYPE_COMBINE: - WB_UpdateEpochCombineList(WBP_GetStimulusType()) - break default: // nothing to do break @@ -834,6 +833,8 @@ static Function WBP_ChangeWaveType() ASSERT(0, "Unknown stimulus type") endif + ListBox listbox_combineEpochMap, win=$panel, listWave=GetWBEpochCombineList(WBP_GetStimulusType()) + WBP_UpdatePanelIfAllowed() End @@ -1426,7 +1427,7 @@ Function WBP_SetVarCombineEpochFormula(sva) : SetVariableControl struct FormulaProperties fp string win, formula - variable currentEpoch, lastSweep + variable currentEpoch, lastSweep, channelType switch(sva.eventCode) case 1: // mouse up @@ -1436,10 +1437,11 @@ Function WBP_SetVarCombineEpochFormula(sva) : SetVariableControl formula = sva.sval WAVE/T WPT = GetWaveBuilderWaveTextParam() + channelType = WBP_GetStimulusType() lastSweep = GetSetVariable(win, "SetVar_WB_SweepCount_S101") - 1 - if(WB_ParseCombinerFormula(formula, lastSweep, fp)) + if(WB_ParseCombinerFormula(channelType, formula, lastSweep, fp)) break endif @@ -1469,11 +1471,13 @@ static Function/S WBP_TranslateControlContents(control, direction, data) strswitch(control) case "setvar_combine_formula_T6": if(direction == FROM_PANEL_TO_WAVE) + variable channelType = WBP_GetStimulusType() + struct FormulaProperties fp - WB_FormulaSwitchToStimset(data, fp) + WB_FormulaSwitchToStimset(channelType, data, fp) return fp.formula elseif(direction == FROM_WAVE_TO_PANEL) - return WB_FormulaSwitchToShorthand(data) + return WB_FormulaSwitchToShorthand(channelType, data) endif break default: @@ -2151,6 +2155,8 @@ static Function/WAVE WBP_ListControlsPerStimulusType(variable epochType) // additional entries which are not covered by the usual naming scheme if(epochType == EPOCH_TYPE_CUSTOM) Make/FREE/T additional = {"Custom epoch wave name"} + elseif(epochType == EPOCH_TYPE_COMBINE) + Make/FREE/T additional = {"Combine epoch formula version"} else Make/FREE/T/N=(0) additional endif diff --git a/Packages/MIES/MIES_WaveBuilder_Macro.ipf b/Packages/MIES/MIES_WaveBuilder_Macro.ipf index 1cdcc73bb9..14bed964fd 100644 --- a/Packages/MIES/MIES_WaveBuilder_Macro.ipf +++ b/Packages/MIES/MIES_WaveBuilder_Macro.ipf @@ -615,7 +615,7 @@ Window WaveBuilder() : Panel ListBox listbox_combineEpochMap,widths={58,120} SetVariable setvar_combine_formula_T6,pos={598.00,210.00},size={427.00,18.00},disable=1,proc=WBP_SetVarCombineEpochFormula SetVariable setvar_combine_formula_T6,title="Formula" - SetVariable setvar_combine_formula_T6,help={"Mathematical formula for combining stim sets. All math operators from Igor are supported. Examples: +/-*^,sin,cos,tan. All are applied elementwise on the stim set contents. Mutiple sweeps are flattened into one sweep."} + SetVariable setvar_combine_formula_T6,help={"Mathematical formula for combining stim sets. All math operators from Igor are supported. Examples: +/-*^,sin,cos,tan. All are applied elementwise on the stim set contents. Multiple sweeps are flattened into one sweep."} SetVariable setvar_combine_formula_T6,userdata(tabnum)="8" SetVariable setvar_combine_formula_T6,userdata(tabcontrol)="WBP_WaveType" SetVariable setvar_combine_formula_T6,userdata(ResizeControlsInfo)=A"!!,J&J,hr7!!#C:J,hlsz!!#](Aon\"Qzzzzzzzzzzzzzz!!#](Aon\"Qzz" diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index 01a44d2bf2..e4d0d5896f 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -3500,13 +3500,41 @@ Function/DF GetWaveBuilderDataPath() return createDFWithAllParents(GetWaveBuilderDataPathAsString()) End -/// @brief Returns the full path to the data folder, e.g root:MIES:WaveBuilder:Data +/// @brief Returns the full path to the data folder, e.g root:MIES:WaveBuilder:Data /// /// UTF_NOINSTRUMENTATION Function/S GetWaveBuilderDataPathAsString() return GetWaveBuilderPathAsString() + ":Data" End +/// @brief Returns a data folder reference to the data +/// +/// UTF_NOINSTRUMENTATION +Function/DF GetWaveBuilderDataDAPath() + return createDFWithAllParents(GetWaveBuilderDataDAPathAsString()) +End + +/// @brief Returns the full path to the data folder, e.g root:MIES:WaveBuilder:Data:DA +/// +/// UTF_NOINSTRUMENTATION +Function/S GetWaveBuilderDataDAPathAsString() + return GetWaveBuilderDataPathAsString() + ":DA" +End + +/// @brief Returns a data folder reference to the data +/// +/// UTF_NOINSTRUMENTATION +Function/DF GetWaveBuilderDataTTLPath() + return createDFWithAllParents(GetWaveBuilderDataTTLPathAsString()) +End + +/// @brief Returns the full path to the data folder, e.g root:MIES:WaveBuilder:Data:TTL +/// +/// UTF_NOINSTRUMENTATION +Function/S GetWaveBuilderDataTTLPathAsString() + return GetWaveBuilderDataPathAsString() + ":TTL" +End + /// @brief Returns a data folder reference to the stimulus set parameter /// /// UTF_NOINSTRUMENTATION @@ -3514,7 +3542,7 @@ Function/DF GetWBSvdStimSetParamPath() return createDFWithAllParents(GetWBSvdStimSetParamPathAS()) End -/// @brief Returns the full path to the stimulus set parameter folder, e.g. root:MIES:WaveBuilder:SavedStimulusSetParameters +/// @brief Returns the full path to the stimulus set parameter folder, e.g. root:MIES:WaveBuilder:SavedStimulusSetParameters /// /// UTF_NOINSTRUMENTATION Function/S GetWBSvdStimSetParamPathAS() @@ -3528,7 +3556,7 @@ Function/DF GetWBSvdStimSetPath() return createDFWithAllParents(GetWBSvdStimSetPathAsString()) End -/// @brief Returns the full path to the stimulus set, e.g. root:MIES:WaveBuilder:SavedStimulusSets +/// @brief Returns the full path to the stimulus set, e.g. root:MIES:WaveBuilder:SavedStimulusSets /// /// UTF_NOINSTRUMENTATION Function/S GetWBSvdStimSetPathAsString() @@ -3542,7 +3570,7 @@ Function/DF GetWBSvdStimSetParamDAPath() return createDFWithAllParents(GetWBSvdStimSetParamDAPathAS()) End -/// @brief Returns the full path to the stimulus set parameters of `DA` type, e.g. root:MIES:WaveBuilder:SavedStimulusSetParameters:DA +/// @brief Returns the full path to the stimulus set parameters of `DA` type, e.g. root:MIES:WaveBuilder:SavedStimulusSetParameters:DA /// /// UTF_NOINSTRUMENTATION Function/S GetWBSvdStimSetParamDAPathAS() @@ -3556,7 +3584,7 @@ Function/DF GetWBSvdStimSetParamTTLPath() return createDFWithAllParents(GetWBSvdStimSetParamTTLAsString()) End -/// @brief Returns the full path to the stimulus set parameters of `TTL` type, e.g. root:MIES:WaveBuilder:SavedStimulusSetParameters:TTL +/// @brief Returns the full path to the stimulus set parameters of `TTL` type, e.g. root:MIES:WaveBuilder:SavedStimulusSetParameters:TTL /// /// UTF_NOINSTRUMENTATION Function/S GetWBSvdStimSetParamTTLAsString() @@ -3570,7 +3598,7 @@ Function/DF GetWBSvdStimSetDAPath() return createDFWithAllParents(GetWBSvdStimSetDAPathAsString()) End -/// @brief Returns the full path to the stimulus set of `DA` type, e.g. root:MIES:WaveBuilder:SavedStimulusSet:DA +/// @brief Returns the full path to the stimulus set of `DA` type, e.g. root:MIES:WaveBuilder:SavedStimulusSet:DA /// /// UTF_NOINSTRUMENTATION Function/S GetWBSvdStimSetDAPathAsString() @@ -3584,7 +3612,7 @@ Function/DF GetWBSvdStimSetTTLPath() return createDFWithAllParents(GetWBSvdStimSetTTLPathAsString()) End -/// @brief Returns the full path to the stimulus set of `TTL` type, e.g. root:MIES:WaveBuilder:SavedStimulusSet:TTL +/// @brief Returns the full path to the stimulus set of `TTL` type, e.g. root:MIES:WaveBuilder:SavedStimulusSet:TTL /// /// UTF_NOINSTRUMENTATION Function/S GetWBSvdStimSetTTLPathAsString() @@ -4188,20 +4216,37 @@ Function/Wave GetWaveBuilderDispWave() return wv End -Function/WAVE GetWBEpochCombineList() +Function/WAVE GetWBEpochCombineList(variable channelType) + // remove the existing wave which is not channel type aware DFREF dfr = GetWaveBuilderDataPath() + WAVE/T/Z/SDFR=dfr wv = epochCombineList + KillOrMoveToTrash(wv = wv) + + switch(channelType) + case CHANNEL_TYPE_DAC: + DFREF dfr = GetWaveBuilderDataDAPath() + break + case CHANNEL_TYPE_TTL: + DFREF dfr = GetWaveBuilderDataTTLPath() + break + default: + ASSERT(0, "Unknown channel type") + endswitch + WAVE/T/Z/SDFR=dfr wv = epochCombineList if(WaveExists(wv)) return wv endif - Make/T/N=(1, 2) dfr:epochCombineList/Wave=wv + Make/T/N=(0, 2) dfr:epochCombineList/Wave=wv SetDimLabel 1, 0, Shorthand, wv SetDimLabel 1, 1, Stimset, wv + WB_UpdateEpochCombineList(wv, channelType) + return wv End @@ -4253,7 +4298,7 @@ Function/WAVE GetEpochParameterNames() Make/T/FREE st_5 = {"Amplitude", "Amplitude delta", "Amplitude dme", "Amplitude ldel", "Amplitude op", "Duration", "Duration delta", "Duration dme", "Duration ldel", "Duration op", "Duration type [User/Automatic]", "Number of pulses", "Number of pulses delta", "Number of pulses dme", "Number of pulses ldel", "Number of pulses op", "Offset", "Offset delta", "Offset dme", "Offset ldel", "Offset op", "Poisson distribution true/false", "PT [First Mixed Frequency]", "PT [First Mixed Frequency] delta", "PT [First Mixed Frequency] dme", "PT [First Mixed Frequency] ldel", "PT [First Mixed Frequency] op", "PT [Last Mixed Frequency]", "PT [Last Mixed Frequency] delta", "PT [Last Mixed Frequency] dme", "PT [Last Mixed Frequency] ldel", "PT [Last Mixed Frequency] op", "PT [Mixed Frequency]", "PT [Shuffle]", "Pulse train type (index)", "Random Seed", "Reseed RNG for each epoch", "Reseed RNG for each step", "Sin/chirp/saw frequency", "Sin/chirp/saw frequency delta", "Sin/chirp/saw frequency dme", "Sin/chirp/saw frequency ldel", "Sin/chirp/saw frequency op", "Train pulse duration", "Train pulse duration delta", "Train pulse duration dme", "Train pulse duration ldel", "Train pulse duration op"} Make/T/FREE st_6 = {"Amplitude", "Amplitude delta", "Amplitude dme", "Amplitude ldel", "Amplitude op", "Duration", "Duration delta", "Duration dme", "Duration ldel", "Duration op", "Offset", "Offset delta", "Offset dme", "Offset ldel", "Offset op", "PSC exp decay time 1/2", "PSC exp decay time 1/2 delta", "PSC exp decay time 1/2 dme", "PSC exp decay time 1/2 ldel", "PSC exp decay time 1/2 op", "PSC exp decay time 2/2", "PSC exp decay time 2/2 delta", "PSC exp decay time 2/2 dme", "PSC exp decay time 2/2 ldel", "PSC exp decay time 2/2 op", "PSC exp rise time", "PSC exp rise time delta", "PSC exp rise time dme", "PSC exp rise time ldel", "PSC exp rise time op", "PSC ratio decay times", "PSC ratio decay times delta", "PSC ratio decay times dme", "PSC ratio decay times ldel", "PSC ratio decay times op"} Make/T/FREE st_7 = {"Custom epoch wave name", "Offset", "Offset delta", "Offset dme", "Offset ldel", "Offset op"} - Make/T/FREE st_8 = {"Combine epoch formula"} + Make/T/FREE st_8 = {"Combine epoch formula", "Combine epoch formula version"} /// @} Make/FREE sizes = {DimSize(st_0, ROWS), DimSize(st_1, ROWS), DimSize(st_2, ROWS), DimSize(st_3, ROWS), DimSize(st_4, ROWS), DimSize(st_5, ROWS), DimSize(st_6, ROWS), DimSize(st_7, ROWS), DimSize(st_8, ROWS)} diff --git a/Packages/tests/Basic/UTF_DAEphyswoHardware.ipf b/Packages/tests/Basic/UTF_DAEphyswoHardware.ipf index 70ad6985a8..beeb3fcf2f 100644 --- a/Packages/tests/Basic/UTF_DAEphyswoHardware.ipf +++ b/Packages/tests/Basic/UTF_DAEphyswoHardware.ipf @@ -183,7 +183,7 @@ Function CheckStimsetUpdateAndSearch([STRUCT IUTF_mData &m]) WAVE/T stimsetsFromMenu = GetStimsetFromUserData(device, ctrlWave) CHECK_EQUAL_TEXTWAVES(stimsetsEmpty, stimsetsFromMenu) - DAP_UpdateDaEphysStimulusSetPopups(device = device) + WB_UpdateChangedStimsets(device = device) // updated WAVE/T stimsetsFromMenu = GetStimsetFromUserData(device, ctrlWave) @@ -200,7 +200,7 @@ Function CheckStimsetUpdateAndSearch([STRUCT IUTF_mData &m]) // add another stimset and update Make dfr:stimsetD - DAP_UpdateDaEphysStimulusSetPopups(device = device) + WB_UpdateChangedStimsets(device = device) WAVE/T stimsetsFromMenu = GetStimsetFromUserData(device, ctrlWave) CHECK_EQUAL_TEXTWAVES({"stimsetD"}, stimsetsFromMenu) diff --git a/Packages/tests/Basic/UTF_Utils.ipf b/Packages/tests/Basic/UTF_Utils.ipf index dc030d8a83..b5ccde41a9 100644 --- a/Packages/tests/Basic/UTF_Utils.ipf +++ b/Packages/tests/Basic/UTF_Utils.ipf @@ -7256,3 +7256,63 @@ static Function TestErrorCodeConversion() // is idempotent CHECK_EQUAL_VAR(ConvertXOPErrorCode(convErr), 10009) End + +static Function TestRemoveEndingRegex() + + string result + + // does nothing with empty string + result = RemoveEndingRegExp("", ".*") + CHECK_EMPTY_STR(result) + + // does nothing with empty regex + result = RemoveEndingRegExp("abcd", "") + CHECK_EQUAL_STR(result, "abcd") + + // complains with invalid regex + try + RemoveEndingRegExp("abcd", "*") + FAIL() + catch + CHECK_NO_RTE() + endtry + + // matches + result = RemoveEndingRegExp("abcdd", "d*") + CHECK_EQUAL_STR(result, "abc") + + // no match + result = RemoveEndingRegExp("abcd", "efgh") + CHECK_EQUAL_STR(result, "abcd") + + // too many matches + try + RemoveEndingRegExp("abcd", "ab)(cd") + FAIL() + catch + CHECK_NO_RTE() + endtry +End + +Function TestSearchWordInString() + + variable ret + string prefix, suffix + + ret = SearchWordInString("ab cd efgh", "ijk") + CHECK_EQUAL_VAR(ret, 0) + + // no match as no word boundary after "c" + ret = SearchWordInString("ab cd efgh", "c") + CHECK_EQUAL_VAR(ret, 0) + + // match + ret = SearchWordInString("ab cd efgh", "cd") + CHECK_EQUAL_VAR(ret, 1) + + // match with prefix and suffix + ret = SearchWordInString("ab#cd?efgh", "cd", prefix = prefix, suffix = suffix) + CHECK_EQUAL_VAR(ret, 1) + CHECK_EQUAL_STR(prefix, "ab#") + CHECK_EQUAL_STR(suffix, "?efgh") +End diff --git a/Packages/tests/Basic/UTF_WaveBuilder.ipf b/Packages/tests/Basic/UTF_WaveBuilder.ipf index c25691db12..1e21a10b3b 100644 --- a/Packages/tests/Basic/UTF_WaveBuilder.ipf +++ b/Packages/tests/Basic/UTF_WaveBuilder.ipf @@ -357,3 +357,24 @@ Function WB_StimsetWithNoEpochsAreNotSaved() CHECK_EQUAL_STR(ST_GetStimsetList(searchString = basename + "*"), "") End + +Function CombineStimsetSubStrings() + + string setNameA, setNameAA, setNameCombine + + setNameA = ST_CreateStimSet("setABC", CHANNEL_TYPE_DAC) + setNameAA = ST_CreateStimSet("newsetABC", CHANNEL_TYPE_DAC) + + setNameCombine = ST_CreateStimSet("setCombine", CHANNEL_TYPE_DAC) + + ST_SetStimsetParameter(setNameCombine, "Total number of epochs", var = 1) + ST_SetStimsetParameter(setNameCombine, "Type of Epoch 0", var = EPOCH_TYPE_COMBINE) + + ST_SetStimsetParameter(setNameCombine, "Combine epoch formula version", epochIndex = 0, str = WAVEBUILDER_COMBINE_FORMULA_VER) + ST_SetStimsetParameter(setNameCombine, "Combine epoch formula", epochIndex = 0, str = LowerStr(setNameA) + "?" + " + " + LowerStr(setNameAA) + "?") + + WAVE/Z wv = WB_CreateAndGetStimSet(setNameCombine) + CHECK_WAVE(wv, NUMERIC_WAVE) + CHECK_GT_VAR(DimSize(wv, ROWS), 0) + CHECK_NO_RTE() +End diff --git a/Packages/tests/HardwareBasic/UTF_BasicHardwareTests.ipf b/Packages/tests/HardwareBasic/UTF_BasicHardwareTests.ipf index 083d63d163..449050de12 100644 --- a/Packages/tests/HardwareBasic/UTF_BasicHardwareTests.ipf +++ b/Packages/tests/HardwareBasic/UTF_BasicHardwareTests.ipf @@ -1790,6 +1790,7 @@ static Function ExportStimsetsAndRoundtripThem([variable var]) REQUIRE(V_IsFile) DFREF dfr = GetWaveBuilderPath() + KillOrMoveToTrash(dfr = GetWaveBuilderDataPath()) MoveDataFolder dfr, : RenameDataFolder WaveBuilder, old @@ -1798,6 +1799,7 @@ static Function ExportStimsetsAndRoundtripThem([variable var]) NWB_LoadAllStimsets(filename = discLocation) DFREF dfr = GetWaveBuilderPath() + KillOrMoveToTrash(dfr = GetWaveBuilderDataPath()) MoveDataFolder dfr, : RenameDataFolder WaveBuilder, new