diff --git a/Packages/MIES/MIES_TestPulse.ipf b/Packages/MIES/MIES_TestPulse.ipf index 56dfab1b0b..b97b3a4f84 100644 --- a/Packages/MIES/MIES_TestPulse.ipf +++ b/Packages/MIES/MIES_TestPulse.ipf @@ -106,45 +106,178 @@ Function TP_StoreTP(device, TPWave, tpMarker, hsList) SetNumberInWaveNote(storedTP, NOTE_INDEX, index) End -/// @brief Return a number of consecutive test pulses ending with the TP -/// identified by tpMarker. -/// -/// The wave reference wave will have as many columns as active headstages were used. -Function/WAVE TP_GetStoredTPs(string device, variable tpMarker, variable number) +static Function TP_GetStoredTPIndex(string device, variable tpMarker) variable numEntries WAVE/WAVE storedTP = GetStoredTestPulseWave(device) numEntries = GetNumberFromWaveNote(storedTP, NOTE_INDEX) - if(numEntries == 0) - return $"" + return NaN endif Make/FREE/N=(numEntries) matches - Multithread matches[0, numEntries - 1] = GetNumberFromWaveNote(storedTP[p], "TPMarker") == tpMarker - FindValue/V=1 matches - if(V_row == -1) + return NaN + endif + + return V_row +End + +/// @brief Returns data about a stored TestPulse from a given tpMarker +/// +/// Returns a wave reference wave with 3 entries: +/// 0 : numeric wave with the acquired AD data of the test pulse (signal) in the format as created by @ref TP_StoreTP +/// 1 : numeric wave with the recreated DA data of the test pulse (command) +/// 2 : Additional information for the test pulse from creation and analysis in the format described for @ref GetTPStorage +/// As the information is for a single TP only, the wave contains a single slice (1 row) +/// +/// @param device device name +/// @param tpMarker testpulse marker +/// @param includeDAC flag, when set the DAC wave of the testpulse is recreated +Function/WAVE TP_GetStoredTP(string device, variable tpMarker, variable includeDAC) + + variable tpIndex, numEntries, dimMarker, headstage + + includeDAC = !!includeDAC + + tpIndex = TP_GetStoredTPIndex(device, tpMarker) + if(IsNaN(tpIndex)) return $"" endif - Make/FREE/N=(number)/WAVE result + WAVE/WAVE tpStored = GetStoredTestPulseWave(device) + WAVE tpADC = tpStored[tpIndex] + + WAVE tpStorage = GetTPStorage(device) + numEntries = GetNumberFromWaveNote(tpStorage, NOTE_INDEX) + dimMarker = FindDimLabel(tpStorage, LAYERS, "TPMarker") + FindValue/RMD=[][0][dimMarker]/V=(tpMarker) tpStorage + ASSERT(V_row >= 0, "Inconsistent TP data") + Duplicate/FREE/RMD=[V_row][][] tpStorage, tpResult + + if(includeDAC) + for(headstage = 0; headstage < NUM_HEADSTAGES; headstage += 1) + if(!IsNaN(tpResult[0][headstage][%TPLENGTHPOINTSADC])) + break + endif + endfor + Make/FREE/D/N=0 tpDAC + TP_CreateTestPulseWaveImpl(tpDAC, tpResult[0][headstage][%TPLENGTHPOINTSDAC][0], tpResult[0][headstage][%PULSESTARTPOINTSDAC], tpResult[0][headstage][%PULSELENGTHPOINTSDAC]) + tpDAC *= tpResult[0][headstage][%CLAMPAMP] + SetScale/P x, 0, tpResult[0][headstage][%SAMPLINGINTERVALADC], "ms", tpDAC + SetScale d, 0, 0, GetADChannelUnit(tpResult[0][headstage][%ClampMode]), tpDAC + else + WAVE/Z tpDAC = $"" + endif + + Make/FREE/WAVE tpAll = {tpADC, tpDAC, tpResult} + + return tpAll +End + +/// @brief Returns data about stored TestPulses from a given cycle id +/// +/// Returns a wave reference wave with 3 entries: +/// 0 : wave ref wave that stores numeric waves with the acquired AD data of the test pulse (signal) in the format as created by @ref TP_StoreTP +/// The number of elements in the wave ref wave equals the number of test pulses in the cycle. +/// 1 : numeric wave with the recreated DA data of the test pulse (command) +/// Note: here only a single wave is recreated because the DA data for all test pulses of that cycle is identical +/// 2 : wave ref wave that stores additional information for the test pulses from creation and analysis in the format described for @ref GetTPStorage +/// The number of elements in the wave ref wave equals the number of test pulses in the cycle and has the same order as the signal waves from index 0. +/// Each element is a single slice (1 row) of tpStorage. +/// +/// If no test pulses exist for the given cycle id a null wave is returned. +/// +/// @param device device name +/// @param cycleId test pulse cycle id +/// @param includeDAC flag, when set the DAC wave of the testpulse is recreated +Function/WAVE TP_GetStoredTPsFromCycle(string device, variable cycleId, variable includeDAC) + + variable i, numEntries, dimMarker, headstage, numStored, numIndices, marker + + includeDAC = !!includeDAC + + WAVE/WAVE tpStored = GetStoredTestPulseWave(device) + numStored = GetNumberFromWaveNote(tpStored, NOTE_INDEX) + Make/FREE/D/N=(numStored) matchCycleId + matchCycleId[] = cycleId == GetNumberFromWaveNote(tpStored[p], "TPCycleID") ? p : NaN + WAVE/Z tpIndices = ZapNaNs(matchCycleId) + if(!WaveExists(tpIndices)) + return $"" + endif + + numIndices = DimSize(tpIndices, ROWS) + Make/FREE/WAVE/N=(numIndices) tpsADC + tpsADC[] = tpStored[tpIndices[p]] + + Make/FREE/D/N=(numIndices) tpMarkers + tpMarkers[] = GetNumberFromWaveNote(tpsADC[p], "TPMarker") + + WAVE tpStorage = GetTPStorage(device) + numEntries = GetNumberFromWaveNote(tpStorage, NOTE_INDEX) + dimMarker = FindDimLabel(tpStorage, LAYERS, "TPMarker") + + Make/FREE/WAVE/N=(numIndices) tpsResult + for(marker : tpMarkers) + + FindValue/RMD=[][0][dimMarker]/V=(marker) tpStorage + ASSERT(V_row >= 0, "Inconsistent TP data") + Duplicate/FREE/RMD=[V_row][][] tpStorage, tpResult + tpsResult[i] = tpResult + i += 1 + endfor + + if(includeDAC) + for(headstage = 0; headstage < NUM_HEADSTAGES; headstage += 1) + if(!IsNaN(tpResult[0][headstage][%TPLENGTHPOINTSADC])) + break + endif + endfor + Make/FREE/D/N=0 tpDAC + TP_CreateTestPulseWaveImpl(tpDAC, tpResult[0][headstage][%TPLENGTHPOINTSDAC][0], tpResult[0][headstage][%PULSESTARTPOINTSDAC], tpResult[0][headstage][%PULSELENGTHPOINTSDAC]) + tpDAC *= tpResult[0][headstage][%CLAMPAMP] + SetScale/P x, 0, tpResult[0][headstage][%SAMPLINGINTERVALADC], "ms", tpDAC + SetScale d, 0, 0, GetADChannelUnit(tpResult[0][headstage][%ClampMode]), tpDAC + else + WAVE/Z tpDAC = $"" + endif - if(number > V_row + 1) + Make/FREE/WAVE tpAll = {tpsADC, tpDAC, tpsResult} + + return tpAll +End + +/// @brief Return a number of consecutive test pulses ending with the TP +/// identified by tpMarker. +/// +/// The wave reference wave will have as many columns as active headstages were used. +Function/WAVE TP_GetConsecutiveTPsUptoMarker(string device, variable tpMarker, variable number) + + variable tpIndex, tpCycleId + + tpIndex = TP_GetStoredTPIndex(device, tpMarker) + if(IsNaN(tpIndex)) + return $"" + endif + + if(number > tpIndex + 1) // too few TPs available return $"" endif - result[] = storedTP[V_row - number + 1 + p] + Make/FREE/N=(number)/WAVE result - // check that they all belong to the same TP cycle - Redimension/N=(number) matches - matches[] = GetNumberFromWaveNote(result[0], "TPCycleID") == GetNumberFromWaveNote(result[p], "TPCycleID") + WAVE/WAVE storedTP = GetStoredTestPulseWave(device) + result[] = storedTP[tpIndex - number + 1 + p] - if(Sum(matches) < number) + // check that they all belong to the same TP cycle + Make/FREE/N=(number) matches + tpCycleId = GetNumberFromWaveNote(result[0], "TPCycleID") + matches[] = tpCycleId == GetNumberFromWaveNote(result[p], "TPCycleID") + if(sum(matches) < number) return $"" endif @@ -318,7 +451,7 @@ End /// - Active headstages static Function/WAVE TP_GetTPWaveForAutoTP(string device, variable marker) - WAVE/WAVE/Z TPs = TP_GetStoredTPs(device, marker, 2) + WAVE/WAVE/Z TPs = TP_GetConsecutiveTPsUptoMarker(device, marker, 2) if(!WaveExists(TPs)) return $"" diff --git a/Packages/tests/Basic/UTF_Testpulse.ipf b/Packages/tests/Basic/UTF_Testpulse.ipf index 9f920a7ec4..629e7d039a 100644 --- a/Packages/tests/Basic/UTF_Testpulse.ipf +++ b/Packages/tests/Basic/UTF_Testpulse.ipf @@ -39,29 +39,29 @@ static Function FetchingTestpulsesWorks() string device = "myDevice" // emty stored TPs - WAVE/Z result = TP_GetStoredTPs(device, 0xA, 1) + WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xA, 1) CHECK_WAVE(result, NULL_WAVE) TP_StoreTP(device, {1}, 0xA, "I_DONT_CARE") // not found - WAVE/Z result = TP_GetStoredTPs(device, 0xB, 1) + WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xB, 1) CHECK_WAVE(result, NULL_WAVE) // requested too many - WAVE/Z result = TP_GetStoredTPs(device, 0xA, 2) + WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xA, 2) CHECK_WAVE(result, NULL_WAVE) TP_StoreTP(device, {2}, 0xB, "I_DONT_CARE") // works with fetching one TP - WAVE/WAVE/Z result = TP_GetStoredTPs(device, 0xA, 1) + WAVE/WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xA, 1) CHECK_WAVE(result, WAVE_WAVE) CHECK_EQUAL_VAR(DimSize(result, ROWS), 1) CHECK_EQUAL_WAVES(WaveRef(result, row = 0), {{1}}, mode = WAVE_DATA) // works with fetching two TPs - WAVE/WAVE/Z result = TP_GetStoredTPs(device, 0xB, 2) + WAVE/WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xB, 2) CHECK_WAVE(result, WAVE_WAVE) CHECK_EQUAL_VAR(DimSize(result, ROWS), 2) CHECK_EQUAL_WAVES(WaveRef(result, row = 0), {{1}}, mode = WAVE_DATA) @@ -74,12 +74,12 @@ static Function FetchingTestpulsesWorks() SetNumberInWaveNote(storedTPs[2], "TPCycleID", 4711) // fetching one works - WAVE/WAVE/Z result = TP_GetStoredTPs(device, 0xC, 1) + WAVE/WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xC, 1) CHECK_WAVE(result, WAVE_WAVE) CHECK_EQUAL_VAR(DimSize(result, ROWS), 1) CHECK_EQUAL_WAVES(WaveRef(result, row = 0), {{3}}, mode = WAVE_DATA) // but two not because 0xB has a different cycle id - WAVE/WAVE/Z result = TP_GetStoredTPs(device, 0xC, 2) + WAVE/WAVE/Z result = TP_GetConsecutiveTPsUptoMarker(device, 0xC, 2) CHECK_WAVE(result, NULL_WAVE) End diff --git a/Packages/tests/HardwareBasic/UTF_TestPulseAndTPDuringDAQ.ipf b/Packages/tests/HardwareBasic/UTF_TestPulseAndTPDuringDAQ.ipf index 7848691417..8d4badf931 100644 --- a/Packages/tests/HardwareBasic/UTF_TestPulseAndTPDuringDAQ.ipf +++ b/Packages/tests/HardwareBasic/UTF_TestPulseAndTPDuringDAQ.ipf @@ -1252,6 +1252,83 @@ static Function TPDuringDAQwithPS_PreAcq(device) PGC_SetAndActivateControl(device, "check_settings_show_power", val = 1) End +/// UTF_TD_GENERATOR DeviceNameGeneratorMD1 +static Function GetStoredTPTest([str]) + string str + + STRUCT DAQSettings s + InitDAQSettingsFromString(s, "MD1_RA0_I0_L0_BKG1_STP1_TP1" + \ + "__HS0_DA0_AD0_CM:IC:_ST:TestPulse:") + + AcquireData_NG(s, str) + + CtrlNamedBackGround StopTPAfterFiveSeconds, start=(ticks + TP_DURATION_S * 60), period=1, proc=StopTPAfterFiveSeconds_IGNORE +End + +static Function GetStoredTPTest_REENTRY([str]) + string str + variable sweepNo, marker, cycleId + + CHECK_EQUAL_VAR(GetSetVariable(str, "SetVar_Sweep"), 0) + + sweepNo = AFH_GetLastSweepAcquired(str) + CHECK_EQUAL_VAR(sweepNo, NaN) + + WaitAndCheckStoredTPs_IGNORE(str, 1) + + WAVE/Z TPStorage = GetTPStorage(str) + CHECK_WAVE(TPStorage, NUMERIC_WAVE) + marker = TPStorage[0][0][%TPMarker] + CHECK_NEQ_VAR(marker, NaN) + + // Check GetStoredTP + WAVE/Z storedTPData = TP_GetStoredTP(str, NaN, 1) + CHECK_WAVE(storedTPData, NULL_WAVE) + + WAVE/Z storedTPData = TP_GetStoredTP(str, marker, 1) + CHECK_WAVE(storedTPData, WAVE_WAVE) + CHECK_EQUAL_VAR(DimSize(storedTPData, ROWS), 3) + + WAVE/WAVE tpData = storedTPData + WAVE/Z tpADC = tpData[0] + WAVE/Z tpDAC = tpData[1] + WAVE/Z tpInfo = tpData[2] + + CHECK_WAVE(tpADC, NUMERIC_WAVE) + CHECK_GE_VAR(DimSize(tpADC, ROWS), 1) + CHECK_WAVE(tpDAC, NUMERIC_WAVE) + CHECK_GE_VAR(DimSize(tpDAC, ROWS), 1) + + Duplicate/FREE/RMD=[0][][] TPStorage, tpResult + CHECK_EQUAL_WAVES(tpInfo, tpResult) + + // Check TP_GetStoredTPsFromCycle + cycleId = TPStorage[0][0][%TPCycleID] + CHECK_NEQ_VAR(cycleId, NaN) + + WAVE/Z storedTPData = TP_GetStoredTPsFromCycle(str, NaN, 1) + CHECK_WAVE(storedTPData, NULL_WAVE) + + WAVE/Z storedTPData = TP_GetStoredTPsFromCycle(str, cycleId, 1) + CHECK_WAVE(storedTPData, WAVE_WAVE) + CHECK_EQUAL_VAR(DimSize(storedTPData, ROWS), 3) + + WAVE/WAVE tpData = storedTPData + WAVE/WAVE/Z tpADC = tpData[0] + WAVE/Z tpDAC = tpData[1] + WAVE/WAVE/Z tpInfoWref = tpData[2] + + CHECK_WAVE(tpADC, WAVE_WAVE) + CHECK_GE_VAR(DimSize(tpADC, ROWS), 1) + CHECK_WAVE(tpDAC, NUMERIC_WAVE) + CHECK_GE_VAR(DimSize(tpDAC, ROWS), 1) + CHECK_WAVE(tpInfoWref, WAVE_WAVE) + CHECK_EQUAL_VAR(DimSize(tpADC, ROWS), DimSize(tpInfoWref, ROWS)) + + WAVE tpInfo0 = tpInfoWref[0] + CHECK_EQUAL_WAVES(tpInfo0, tpResult) +End + // UTF_TD_GENERATOR DeviceNameGeneratorMD1 static Function TPDuringDAQwithPS([str]) string str