Skip to content

MIES freezes for 10-15s when changing clampMode #2401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
t-b opened this issue Apr 11, 2025 · 3 comments
Open

MIES freezes for 10-15s when changing clampMode #2401

t-b opened this issue Apr 11, 2025 · 3 comments
Assignees
Labels
Amplifier bug Something isn't working PatchLink

Comments

@t-b
Copy link
Collaborator

t-b commented Apr 11, 2025

Megan Koch reported an issue with #2230 where changing the clamp mode takes way too long (10-15s).

I've tried reproducing that with 5b0bbdd (tests/Basic: Ensure that we don't get unexpected ZeroMQ messages, 2025-04-11) of branch feature/2230-Add_zeromq_pub_filters_for_TP with an ITC18 and a real MCC. But failed.

See also the following screencast.

Igor.Pro.9.06B01.64-bit.2025-04-12.00-42-57.mp4
@t-b t-b added Amplifier bug Something isn't working PatchLink labels Apr 11, 2025
@timjarsky
Copy link
Collaborator

timjarsky commented Apr 15, 2025

@t-b

EDIT: These are from running the TP, not the clamp mode switch. I noticed the TP is running about 10X slower than it normally does.

Total time: 50.4178, Time in Function code: 15.4583 (30.7%)
Top function percentages:
Function MIES_TestPulse.ipf TP_GetValuesFromTPStorage: 27%
Function MIES_IVSCC.ipf IVS_SaveExperiment: 20%
Function MIES_TestPulse.ipf TP_AutoFitBaseline: 15%
Function MIES_DAC-Hardware.ipf HW_NI_ReadDigital: 7%
Function MIES_ThreadsafeUtilities.ipf TS_GetNewestFromThreadQueue: 5%
Function MIES_DAC-Hardware.ipf HW_NI_ReadAnalogSingleAndSlow: 4%
Function MIES_DAC-Hardware.ipf HW_NI_WriteAnalogSingleAndSlow: 3%

Annotated Top Functions:

*******************************************************************************************
Function: MIES_TestPulse.ipf TP_GetValuesFromTPStorage; Percent total 27%
*******************************************************************************************
[00]*         	|Function/WAVE TP_GetValuesFromTPStorage(WAVE TPStorage, variable headstage, string entry, variable numReqEntries, [variable options])
[00]          	|
[00]          	|	variable i, idx, value, entryLayer, lastValidEntry, numValidEntries, currentAutoTPCycleID, latestAutoTPCycleID
[00]          	|
[00]*         	|	if(ParamIsDefault(options))
[00]*         	|		options = TP_GETVALUES_DEFAULT
[00]          	|	else
[00]*         	|		ASSERT(options == TP_GETVALUES_DEFAULT || options == TP_GETVALUES_LATEST_AUTOTPCYCLE, "Invalid option")
[00]          	|	endif
[00]          	|
[00]          	|	// NOTE_INDEX gives the next free index and therefore also the number of valid entries
[00]*         	|	numValidEntries = GetNumberFromWaveNote(TPStorage, NOTE_INDEX)
[00]          	|
[00]*         	|	if(numValidEntries <= 0)
[00]*         	|		return $""
[00]*         	|	endif
[00]          	|
[00]*         	|	lastValidEntry = numValidEntries - 1
[00]          	|
[00]*         	|	latestAutoTPCycleID = TPStorage[lastValidEntry][headstage][%autoTPCycleID]
[00]          	|
[00]*         	|	if(numReqEntries == Inf)
[00]          	|		entryLayer = FindDimLabel(TPstorage, LAYERS, entry)
[00]          	|		ASSERT(entryLayer >= 0, "Invalid entry")
[00]          	|		Duplicate/FREE/RMD=[0, lastValidEntry][headstage][entryLayer] TPStorage, slice
[00]          	|		Redimension/N=(numpnts(slice))/E=1 slice
[00]          	|
[00]          	|		if(options == TP_GETVALUES_LATEST_AUTOTPCYCLE)
[00]          	|			// filter all entries which don't have the latest ID out
[00]          	|			slice[] = (TPStorage[p][headstage][%autoTPCycleID] == latestAutoTPCycleID) ? slice[p] : NaN
[00]          	|		endif
[00]          	|
[00]*         	|		return ZapNaNs(slice)
[00]*         	|	endif
[00]          	|
[00]*         	|	ASSERT(IsInteger(numReqEntries) && numReqEntries > 0, "Number of required entries must be larger than zero")
[00]          	|
[00]*         	|	if(numReqEntries > numValidEntries)
[00]          	|		return $""
[00]*         	|	endif
[00]          	|
[00]*         	|	Make/FREE/D/N=(numReqEntries) result = NaN
[00]          	|
[00]          	|	// take the last finite values
[03]*         	|	for(i = lastValidEntry; i >= 0; i -= 1)
[00]*         	|		if(idx == numReqEntries)
[00]*         	|			break
[00]*         	|		endif
[00]          	|
[19]**        	|		value = TPStorage[i][headstage][%$entry]
[00]          	|
[05]*         	|		if(!IsFinite(value))
[00]*         	|			continue
[00]*         	|		endif
[00]          	|
[00]*         	|		if(options == TP_GETVALUES_LATEST_AUTOTPCYCLE)
[00]*         	|			currentAutoTPCycleID = TPStorage[i][headstage][%autoTPCycleID]
[00]          	|
[00]*         	|			if(currentAutoTPCycleID != latestAutoTPCycleID)
[00]          	|				continue
[00]          	|			endif
[00]*         	|		endif
[00]          	|
[00]*         	|		result[idx++] = value
[00]*         	|	endfor
[00]          	|
[00]*         	|	if(idx == numReqEntries)
[00]*         	|		ASSERT(!IsNaN(Sum(result)), "Expected non-nan sum")
[00]*         	|		return result
[00]          	|	endif
[00]          	|
[00]*         	|	return $""
[00]*         	|End

*******************************************************************************************
Function: MIES_IVSCC.ipf IVS_SaveExperiment; Percent total 20%
*******************************************************************************************
[00]          	|Function IVS_SaveExperiment(string filename)
[00]          	|
[00]          	|	variable err
[00]          	|
[00]          	|	AssertOnAndClearRTError()
[00]          	|	try
[20]**        	|		SaveExperiment/C/F={1, "", 2}/P=home as filename + ".pxp"; AbortOnRTE
[00]          	|	catch
[00]          	|		err = ClearRTError()
[00]          	|		ASSERT(0, "Could not save experiment due to code: " + num2istr(err))
[00]          	|	endtry
[00]          	|End


*******************************************************************************************
Function: MIES_TestPulse.ipf TP_AutoFitBaseline; Percent total 15%
*******************************************************************************************
[00]*         	|static Function [variable result, variable tau, variable baseline] TP_AutoFitBaseline(WAVE data, variable pulseLengthMS)
[00]          	|
[00]          	|	variable first, last, firstPnt, lastPnt, totalLength, debugEnabled, fitQuality, referenceThreshold
[00]          	|	variable V_FitQuitReason, V_FitOptions, V_FitError, V_AbortCode
[00]          	|	string msg, win
[00]          	|
[00]*         	|	ASSERT(IsFloatingPointWave(data), "Expected floating point wave")
[00]*         	|	ASSERT(DimSize(data, COLS) <= 1, "Invalid data dimensions")
[00]*         	|	ASSERT(DimOffset(data, ROWS) == 0, "Invalid dimension offset")
[00]*         	|	ASSERT(pulseLengthMS > 0, "Expected valid pulse length")
[00]          	|
[00]          	|	totalLength = DimDelta(data, ROWS) * (DimSize(data, ROWS) - 1)
[00]          	|
[00]*         	|	first = 1 / 4 * totalLength + 1 / 2 * pulseLengthMS
[00]*         	|	last  = 3 / 4 * totalLength - 1 / 2 * pulseLengthMS
[00]*         	|	ASSERT(first < last, "Invalid first/last")
[00]          	|
[00]*         	|	baseline = last - first
[00]          	|
[00]          	|	first += TP_BASELINE_FITTING_INSET
[00]          	|	last  -= TP_BASELINE_FITTING_INSET
[00]          	|
[00]          	|#ifdef DEBUGGING_ENABLED
[00]          	|	if(DP_DebuggingEnabledForCaller())
[00]          	|		debugEnabled = 1
[00]          	|
[00]          	|		Duplicate/O data, root:AutoTPDebuggingData/WAVE=displayedData
[00]          	|		Duplicate/O data, root:Res_AutoTPDebuggingData/WAVE=residuals
[00]          	|
[00]          	|		if(!WindowExists("AutoTPDebugging"))
[00]          	|			Display/K=1/N=AutoTPDebugging displayedData
[00]          	|
[00]          	|			AppendToGraph/W=AutoTPDebugging/L=res residuals
[00]          	|			AppendToGraph/W=AutoTPDebugging displayedData
[00]          	|			ModifyGraph/W=AutoTPDebugging rgb(Res_AutoTPDebuggingData)=(0, 0, 0), rgb(AutoTPDebuggingData)=(655355, 0, 0)
[00]          	|			ModifyGraph axisEnab(left)={0, 0.65}, axisEnab(res)={0.7, 1}, freePos(res)=0
[00]          	|		endif
[00]          	|
[00]          	|		Cursor/W=AutoTPDebugging A, $NameOfWave(displayedData), first
[00]          	|		Cursor/W=AutoTPDebugging B, $NameOfWave(displayedData), last
[00]          	|
[00]          	|		WAVE data      = root:AutoTPDebuggingData
[00]          	|		WAVE residuals = root:Res_AutoTPDebuggingData
[00]          	|	endif
[00]          	|#endif // DEBUGGING_ENABLED
[00]          	|
[00]*         	|	if(!debugEnabled)
[00]*         	|		Duplicate/FREE data, residuals
[00]          	|	endif
[00]          	|
[01]*         	|	residuals = NaN
[00]          	|
[00]*         	|	Make/FREE/D/N=3 coefWave
[00]          	|
[00]          	|	V_FitOptions = 4
[00]          	|
[00]*         	|	AssertOnAndClearRTError()
[00]          	|	try
[00]          	|		V_FitError  = 0
[00]          	|		V_AbortCode = 0
[00]          	|
[00]*         	|		firstPnt = ScaleToIndex(data, first, ROWS)
[00]*         	|		lastPnt  = ScaleToIndex(data, last, ROWS)
[13]*         	|		CurveFit/Q=(!debugEnabled)/N=(!debugEnabled)/NTHR=1/M=0/W=2 exp_XOffset, kwCWave=coefWave, data[firstPnt, lastPnt]/A=(debugEnabled)/R=residuals; AbortOnRTE
[00]*         	|	catch
[00]          	|		msg = GetRTErrMessage()
[00]          	|		ClearRTError()
[00]          	|
[00]          	|		ASSERT(0, "CurveFit failed with error: " + msg)
[00]          	|	endtry
[00]          	|
[00]*         	|	MakeWaveFree($"W_Sigma")
[00]*         	|	MakeWaveFree($"W_FitConstants")
[00]          	|
[00]*         	|	sprintf msg, "Fit result: tau %g, V_FitError %g, V_FitQuitReason %g\r", coefWave[2], V_FitError, V_FitQuitReason
[00]*         	|	DEBUGPRINT(msg)
[00]          	|
[00]*         	|	if(V_FitError || V_FitQuitReason)
[00]          	|		return [TP_BASELINE_FIT_RESULT_ERROR, NaN, baseline]
[00]          	|	endif
[00]          	|
[00]          	|	// @todo check coefficient sign, range, etc
[00]          	|
[00]          	|	// detect residuals being too large
[00]*         	|	Multithread residuals = residuals[p]^2
[00]*         	|	fitQuality         = Sum(residuals, first, last) / (lastPnt - firstPnt)
[00]*         	|	referenceThreshold = 0.25 * abs(WaveMax(data, first, last))
[00]          	|
[00]*         	|	sprintf msg, "fitQuality %g, referenceThreshold %g\r", fitQuality, referenceThreshold
[00]*         	|	DEBUGPRINT(msg)
[00]          	|
[00]*         	|	ASSERT(IsFinite(fitQuality), "Invalid fit quality")
[00]          	|
[00]*         	|	if(fitQuality > referenceThreshold)
[00]*         	|		return [TP_BASELINE_FIT_RESULT_TOO_NOISY, NaN, baseline]
[00]          	|	endif
[00]          	|
[00]*         	|	return [TP_BASELINE_FIT_RESULT_OK, coefWave[2], baseline]
[00]*         	|End

*******************************************************************************************
Function: MIES_DAC-Hardware.ipf HW_NI_ReadDigital; Percent total 07%
*******************************************************************************************
[00]*         	|Function HW_NI_ReadDigital(string device, [variable DIOPort, variable DIOLine, variable flags])
[00]          	|
[00]          	|	variable taskID, ret, result, lineGrouping
[00]          	|	string line
[00]          	|
[00]*         	|	DEBUGPRINTSTACKINFO()
[00]          	|
[00]*         	|	if(ParamIsDefault(DIOPort))
[00]*         	|		DIOPort = 0
[00]          	|	endif
[00]          	|
[00]*         	|	if(ParamIsDefault(DIOLine))
[00]          	|		sprintf line, "/%s/port%d", device, DIOPort
[00]*         	|		lineGrouping = 0
[00]          	|	else
[00]*         	|		lineGrouping = 1
[02]*         	|		ASSERT(DIOline <= fDAQmx_DIO_PortWidth(device, DIOport), "Line does not exist in port")
[00]*         	|		sprintf line, "/%s/port%d/line%d", device, DIOPort, DIOline
[00]*         	|	endif
[00]          	|
[00]*         	|	AssertOnAndClearRTError()
[04]*         	|	DAQmx_DIO_Config/DEV=device/DIR=1/LGRP=(lineGrouping) line
[00]          	|
[00]*         	|	if(ClearRTError())
[00]          	|		print fDAQmx_ErrorString()
[00]          	|		ControlWindowToFront()
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error calling DAQmx_DIO_Config")
[00]          	|		endif
[00]*         	|		return NaN
[00]*         	|	endif
[00]          	|
[00]*         	|	taskID = V_DAQmx_DIO_TaskNumber
[00]          	|
[01]*         	|	result = fDAQmx_DIO_Read(device, taskID)
[00]          	|
[01]*         	|	ret = fDAQmx_DIO_Finished(device, taskID)
[00]*         	|	if(ret)
[00]          	|		print fDAQmx_ErrorString()
[00]          	|		printf "Error %d: fDAQmx_DIO_Finished\r", ret
[00]          	|		ControlWindowToFront()
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error calling fDAQmx_DIO_Finished")
[00]*         	|		endif
[00]          	|	endif
[00]          	|
[00]*         	|	return result
[00]*         	|End

*******************************************************************************************
Function: MIES_ThreadsafeUtilities.ipf TS_GetNewestFromThreadQueue; Percent total 05%
*******************************************************************************************
[00]*         	|Function TS_GetNewestFromThreadQueue(variable tgID, string varName, [variable timeout_default, variable timeout_tries])
[00]          	|
[00]          	|	variable var, err, i
[00]          	|
[00]*         	|	ASSERT_TS(!isEmpty(varName), "varName must not be empty")
[00]          	|
[00]*         	|	if(IsNaN(tgID))
[00]*         	|		return NaN
[00]*         	|	endif
[00]          	|
[00]*         	|	if(ParamIsDefault(timeout_default))
[00]*         	|		timeout_default = NaN
[00]*         	|	endif
[00]          	|
[00]*         	|	if(ParamIsDefault(timeout_tries))
[00]*         	|		timeout_tries = Inf
[00]          	|	else
[00]*         	|		ASSERT(IsInteger(timeout_tries) && timeout_tries > 0, "Invalid timeout_tries")
[00]          	|	endif
[00]          	|
[00]          	|	var = NaN
[00]          	|
[00]*         	|	for(i = 0; i < timeout_tries; i += 1)
[00]*         	|		AssertOnAndClearRTError()
[05]*         	|		DFREF dfr = ThreadGroupGetDFR(tgID, TS_GET_REPEAT_TIMEOUT_IN_MS); err = GetRTError(1)
[00]          	|
[00]*         	|		if(err)
[00]          	|			ASSERT(err == TS_ERROR_INVALID_TGID, "Unexpected error value of " + num2str(err))
[00]*         	|			return NaN
[00]*         	|		endif
[00]          	|
[00]*         	|		if(!DataFolderRefStatus(dfr))
[00]*         	|			if(IsFinite(var))
[00]*         	|				return var
[00]*         	|			elseif(TS_ThreadGroupFinished(tgID))
[00]*         	|				return NaN
[00]          	|			else
[00]*         	|				continue
[00]*         	|			endif
[00]          	|		endif
[00]          	|
[00]*         	|		NVAR/Z/SDFR=dfr var_thread = $varName
[00]          	|
[00]*         	|		ASSERT_TS(NVAR_Exists(var_thread), "Expected variable from thread does not exist: " + varName)
[00]          	|
[00]          	|		// overwrite old values
[00]*         	|		var = var_thread
[00]          	|	endfor
[00]          	|
[00]          	|	return timeout_default
[00]*         	|End

*******************************************************************************************
Function: MIES_DAC-Hardware.ipf HW_NI_ReadAnalogSingleAndSlow; Percent total 04%
*******************************************************************************************
[00]*         	|Function HW_NI_ReadAnalogSingleAndSlow(string device, variable channel, [variable flags])
[00]          	|
[00]          	|	variable value
[00]          	|
[00]          	|	DEBUGPRINTSTACKINFO()
[00]          	|
[04]*         	|	value = fDAQmx_ReadChan(device, channel, HW_NI_MIN_VOLTAGE, HW_NI_MAX_VOLTAGE, HW_NI_DIFFERENTIAL_SETUP)
[00]          	|
[00]*         	|	if(!IsFinite(value))
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error " + fDAQmx_ErrorString())
[00]          	|		else
[00]          	|			DEBUGPRINT("Error: ", str = fDAQmx_ErrorString())
[00]*         	|		endif
[00]          	|	endif
[00]          	|
[00]*         	|	return value
[00]*         	|End

*******************************************************************************************
Function: MIES_DAC-Hardware.ipf HW_NI_WriteAnalogSingleAndSlow; Percent total 03%
*******************************************************************************************
[00]*         	|Function HW_NI_WriteAnalogSingleAndSlow(string device, variable channel, variable value, [variable flags])
[00]          	|
[00]          	|	variable ret
[00]          	|
[00]*         	|	DEBUGPRINTSTACKINFO()
[00]          	|
[00]*         	|	ASSERT(value < HW_NI_MAX_VOLTAGE && value > HW_NI_MIN_VOLTAGE, "Value to set is out of range")
[03]*         	|	ret = fDAQmx_WriteChan(device, channel, value, HW_NI_MIN_VOLTAGE, HW_NI_MAX_VOLTAGE)
[00]          	|
[00]*         	|	if(ret)
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error: " + fDAQmx_ErrorString())
[00]          	|		else
[00]          	|			DEBUGPRINT("Error: ", str = fDAQmx_ErrorString())
[00]*         	|		endif
[00]*         	|	endif
[00]          	|
[00]*         	|	return ret
[00]*         	|End

@timjarsky
Copy link
Collaborator

@t-b

profiling results with zeromq_stop(), after MIES DA_ephys GUI clamp-mode switch, and TP in MIES was noticeably slow.

Total time: 12.6324, Time in Function code: 0.473828 (3.75%)
Top function percentages:
Function MIES_ThreadsafeUtilities.ipf TS_GetNewestFromThreadQueue: 33%
Function MIES_DAC-Hardware.ipf HW_NI_ReadDigital: 27%
Function MIES_DAC-Hardware.ipf HW_NI_WriteAnalogSingleAndSlow: 9%
Function MIES_Oscilloscope.ipf SCOPE_ITC_UpdateOscilloscope: 4%
Function MIES_Oscilloscope.ipf SCOPE_UpdateGraph: 3%
Function MIES_TestPulse.ipf TP_ROAnalysis: 3%
Function MIES_Oscilloscope.ipf SCOPE_UpdateOscilloscopeData: 2%

Annotated Top Functions:

*******************************************************************************************
Function: MIES_ThreadsafeUtilities.ipf TS_GetNewestFromThreadQueue; Percent total 33%
*******************************************************************************************
[00]*         	|Function TS_GetNewestFromThreadQueue(variable tgID, string varName, [variable timeout_default, variable timeout_tries])
[00]          	|
[00]          	|	variable var, err, i
[00]          	|
[00]*         	|	ASSERT_TS(!isEmpty(varName), "varName must not be empty")
[00]          	|
[00]*         	|	if(IsNaN(tgID))
[00]          	|		return NaN
[00]*         	|	endif
[00]          	|
[00]*         	|	if(ParamIsDefault(timeout_default))
[00]*         	|		timeout_default = NaN
[00]          	|	endif
[00]          	|
[00]*         	|	if(ParamIsDefault(timeout_tries))
[00]          	|		timeout_tries = Inf
[00]          	|	else
[00]*         	|		ASSERT(IsInteger(timeout_tries) && timeout_tries > 0, "Invalid timeout_tries")
[00]          	|	endif
[00]          	|
[00]*         	|	var = NaN
[00]          	|
[00]*         	|	for(i = 0; i < timeout_tries; i += 1)
[00]*         	|		AssertOnAndClearRTError()
[33]***       	|		DFREF dfr = ThreadGroupGetDFR(tgID, TS_GET_REPEAT_TIMEOUT_IN_MS); err = GetRTError(1)
[00]          	|
[00]*         	|		if(err)
[00]          	|			ASSERT(err == TS_ERROR_INVALID_TGID, "Unexpected error value of " + num2str(err))
[00]          	|			return NaN
[00]*         	|		endif
[00]          	|
[00]*         	|		if(!DataFolderRefStatus(dfr))
[00]*         	|			if(IsFinite(var))
[00]*         	|				return var
[00]          	|			elseif(TS_ThreadGroupFinished(tgID))
[00]          	|				return NaN
[00]          	|			else
[00]          	|				continue
[00]          	|			endif
[00]          	|		endif
[00]          	|
[00]*         	|		NVAR/Z/SDFR=dfr var_thread = $varName
[00]          	|
[00]*         	|		ASSERT_TS(NVAR_Exists(var_thread), "Expected variable from thread does not exist: " + varName)
[00]          	|
[00]          	|		// overwrite old values
[00]          	|		var = var_thread
[00]*         	|	endfor
[00]          	|
[00]*         	|	return timeout_default
[00]*         	|End

*******************************************************************************************
Function: MIES_DAC-Hardware.ipf HW_NI_ReadDigital; Percent total 27%
*******************************************************************************************
[00]*         	|Function HW_NI_ReadDigital(string device, [variable DIOPort, variable DIOLine, variable flags])
[00]          	|
[00]          	|	variable taskID, ret, result, lineGrouping
[00]          	|	string line
[00]          	|
[00]          	|	DEBUGPRINTSTACKINFO()
[00]          	|
[00]*         	|	if(ParamIsDefault(DIOPort))
[00]          	|		DIOPort = 0
[00]          	|	endif
[00]          	|
[00]          	|	if(ParamIsDefault(DIOLine))
[00]          	|		sprintf line, "/%s/port%d", device, DIOPort
[00]*         	|		lineGrouping = 0
[00]          	|	else
[00]*         	|		lineGrouping = 1
[06]*         	|		ASSERT(DIOline <= fDAQmx_DIO_PortWidth(device, DIOport), "Line does not exist in port")
[00]*         	|		sprintf line, "/%s/port%d/line%d", device, DIOPort, DIOline
[00]          	|	endif
[00]          	|
[00]*         	|	AssertOnAndClearRTError()
[13]*         	|	DAQmx_DIO_Config/DEV=device/DIR=1/LGRP=(lineGrouping) line
[00]          	|
[00]*         	|	if(ClearRTError())
[00]          	|		print fDAQmx_ErrorString()
[00]          	|		ControlWindowToFront()
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error calling DAQmx_DIO_Config")
[00]          	|		endif
[00]*         	|		return NaN
[00]*         	|	endif
[00]          	|
[00]*         	|	taskID = V_DAQmx_DIO_TaskNumber
[00]          	|
[05]*         	|	result = fDAQmx_DIO_Read(device, taskID)
[00]          	|
[02]*         	|	ret = fDAQmx_DIO_Finished(device, taskID)
[00]*         	|	if(ret)
[00]          	|		print fDAQmx_ErrorString()
[00]          	|		printf "Error %d: fDAQmx_DIO_Finished\r", ret
[00]          	|		ControlWindowToFront()
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error calling fDAQmx_DIO_Finished")
[00]*         	|		endif
[00]          	|	endif
[00]          	|
[00]*         	|	return result
[00]*         	|End

*******************************************************************************************
Function: MIES_DAC-Hardware.ipf HW_NI_WriteAnalogSingleAndSlow; Percent total 09%
*******************************************************************************************
[00]*         	|Function HW_NI_WriteAnalogSingleAndSlow(string device, variable channel, variable value, [variable flags])
[00]          	|
[00]          	|	variable ret
[00]          	|
[00]*         	|	DEBUGPRINTSTACKINFO()
[00]          	|
[00]*         	|	ASSERT(value < HW_NI_MAX_VOLTAGE && value > HW_NI_MIN_VOLTAGE, "Value to set is out of range")
[09]*         	|	ret = fDAQmx_WriteChan(device, channel, value, HW_NI_MIN_VOLTAGE, HW_NI_MAX_VOLTAGE)
[00]          	|
[00]*         	|	if(ret)
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error: " + fDAQmx_ErrorString())
[00]          	|		else
[00]          	|			DEBUGPRINT("Error: ", str = fDAQmx_ErrorString())
[00]          	|		endif
[00]          	|	endif
[00]          	|
[00]*         	|	return ret
[00]*         	|End

*******************************************************************************************
Function: MIES_DAC-Hardware.ipf HW_NI_WriteAnalogSingleAndSlow; Percent total 09%
*******************************************************************************************
[00]*         	|Function HW_NI_WriteAnalogSingleAndSlow(string device, variable channel, variable value, [variable flags])
[00]          	|
[00]          	|	variable ret
[00]          	|
[00]*         	|	DEBUGPRINTSTACKINFO()
[00]          	|
[00]*         	|	ASSERT(value < HW_NI_MAX_VOLTAGE && value > HW_NI_MIN_VOLTAGE, "Value to set is out of range")
[09]*         	|	ret = fDAQmx_WriteChan(device, channel, value, HW_NI_MIN_VOLTAGE, HW_NI_MAX_VOLTAGE)
[00]          	|
[00]*         	|	if(ret)
[00]          	|		if(flags & HARDWARE_ABORT_ON_ERROR)
[00]          	|			ASSERT(0, "Error: " + fDAQmx_ErrorString())
[00]          	|		else
[00]          	|			DEBUGPRINT("Error: ", str = fDAQmx_ErrorString())
[00]          	|		endif
[00]          	|	endif
[00]          	|
[00]*         	|	return ret
[00]*         	|End

*******************************************************************************************
Function: MIES_Oscilloscope.ipf SCOPE_ITC_UpdateOscilloscope; Percent total 04%
*******************************************************************************************
[00]*         	|static Function SCOPE_ITC_UpdateOscilloscope(string device, variable dataAcqOrTP, variable chunk, variable fifoPos)
[00]          	|
[00]          	|	WAVE OscilloscopeData = GetOscilloscopeWave(device)
[00]          	|	variable length, first, last
[00]          	|	variable startOfADColumns, endOfADColumns, decMethod, decFactor, i
[00]          	|	string msg
[00]*         	|	WAVE/WAVE scaledDataWave = GetScaledDataWave(device)
[00]          	|	WAVE      DAQDataWave    = GetDAQDataWave(device, dataAcqOrTP)
[00]          	|	WAVE      DAQConfigWave  = GetDAQConfigWave(device)
[00]*         	|	WAVE      ADCs           = GetADCListFromConfig(DAQConfigWave)
[00]*         	|	WAVE      DACs           = GetDACListFromConfig(DAQConfigWave)
[00]          	|	startOfADColumns = DimSize(DACs, ROWS)
[00]*         	|	endOfADColumns   = startOfADColumns + DimSize(ADCs, ROWS)
[00]          	|
[00]*         	|	WAVE allGain = SWS_GETChannelGains(device, timing = GAIN_AFTER_DAQ)
[00]          	|
[00]          	|	if(dataAcqOrTP == TEST_PULSE_MODE)
[00]*         	|		WAVE TPSettingsCalc = GetTPSettingsCalculated(device)
[00]*         	|		length = TPSettingsCalc[%totalLengthPointsTP_ADC]
[00]          	|		first  = chunk * length
[00]*         	|		last   = first + length - 1
[00]*         	|		ASSERT(first >= 0 && last < DimSize(DAQDataWave, ROWS) && first < last, "Invalid wave subrange")
[00]          	|
[00]          	|#ifdef DEBUGGING_ENABLED
[00]          	|		if(DP_DebuggingEnabledForCaller())
[00]          	|
[00]          	|			DAQDataWave[0][0] += 0
[00]          	|			if(!WindowExists("DAQDataWaveTPMD"))
[00]          	|				Display/N=DAQDataWaveTPMD DAQDataWave[][1]
[00]          	|			endif
[00]          	|
[00]          	|			Cursor/W=DAQDataWaveTPMD/H=2/P A, $NameOfWave(DAQDataWave), first
[00]          	|			Cursor/W=DAQDataWaveTPMD/H=2/P B, $NameOfWave(DAQDataWave), last
[00]          	|		endif
[00]          	|#endif // DEBUGGING_ENABLED
[00]          	|
[03]*         	|		Multithread OscilloscopeData[][startOfADColumns, endOfADColumns - 1] = DAQDataWave[first + p][q] / allGain[q]
[00]*         	|		for(i = startOfADColumns; i < endOfADColumns; i += 1)
[00]*         	|			WAVE scaledChannel = scaledDataWave[i]
[01]*         	|			Multithread scaledChannel[] = OscilloscopeData[p][i]
[00]          	|		endfor
[00]          	|
[00]*         	|		Make/FREE/N=(DimSize(ADCs, ROWS)) tpColumns
[00]*         	|		tpColumns[] = startOfADColumns + p
[00]          	|		SCOPE_UpdatePowerSpectrum(device, tpColumns)
[00]          	|
[00]          	|	elseif(dataAcqOrTP == DATA_ACQUISITION_MODE)
[00]          	|
[00]          	|		if(fifopos <= 0)
[00]          	|			return NaN
[00]          	|		endif
[00]          	|
[00]          	|		NVAR fifoPosGlobal = $GetFifoPosition(device)
[00]          	|
[00]          	|		if(fifoPosGlobal == fifoPos)
[00]          	|			return NaN
[00]          	|		endif
[00]          	|
[00]          	|		AssertOnAndClearRTError()
[00]          	|		try
[00]          	|			for(i = startOfADColumns; i < endOfADColumns; i += 1)
[00]          	|				WAVE scaledChannel = scaledDataWave[i]
[00]          	|				Multithread scaledChannel[fifoPosGlobal, fifoPos - 1] = DAQDataWave[p][i] / allGain[i]; AbortOnRTE
[00]          	|			endfor
[00]          	|		catch
[00]          	|			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))
[00]          	|			ASSERT(0, msg)
[00]          	|		endtry
[00]          	|
[00]          	|		decMethod = GetNumberFromWaveNote(OscilloscopeData, "DecimationMethod")
[00]          	|		decFactor = GetNumberFromWaveNote(OscilloscopeData, "DecimationFactor")
[00]          	|
[00]          	|		switch(decMethod)
[00]          	|			case DECIMATION_NONE:
[00]          	|				Multithread OscilloscopeData[fifoPosGlobal, fifoPos - 1][startOfADColumns, endOfADColumns - 1] = DAQDataWave[p][q] / allGain[q]
[00]          	|				break
[00]          	|			default:
[00]          	|				Duplicate/FREE/RMD=[startOfADColumns, endOfADColumns - 1] allGain, gain
[00]          	|				gain[] = 1 / gain[p]
[00]          	|				DecimateWithMethod(DAQDataWave, OscilloscopeData, decFactor, decMethod, firstRowInp = fifoPosGlobal, lastRowInp = fifoPos - 1, firstColInp = startOfADColumns, lastColInp = endOfADColumns - 1, factor = gain)
[00]          	|		endswitch
[00]          	|	else
[00]*         	|		ASSERT(0, "Invalid dataAcqOrTP value")
[00]*         	|	endif
[00]          	|End

*******************************************************************************************
Function: MIES_Oscilloscope.ipf SCOPE_UpdateGraph; Percent total 03%
*******************************************************************************************
[00]*         	|Function SCOPE_UpdateGraph(string device, variable dataAcqOrTP)
[00]          	|
[00]          	|	variable i, numADCs, range, numDACs, statsMin, statsMax
[00]          	|	variable axisMin, axisMax, spacing, additionalSpacing
[00]          	|	variable showSteadyStateResistance, showPeakResistance, showPowerSpectrum
[00]          	|	variable updateInt, now
[00]          	|	string graph, leftAxis
[00]          	|
[00]*         	|	NVAR timestamp = $GetLastAcqHookCallTimeStamp(device)
[00]*         	|	updateInt = DAG_GetNumericalValue(device, "setvar_Settings_OsciUpdInt")
[00]*         	|	now       = DateTime
[00]*         	|	if((now - timestamp) < (updateInt * MILLI_TO_ONE))
[00]          	|		return 0
[00]          	|	endif
[00]*         	|	timestamp = now
[00]          	|
[00]          	|	graph = SCOPE_GetGraph(device)
[00]*         	|	if(SCOPE_GetTPTopAxisStart(device, axisMin))
[00]          	|		SetAxis/W=$graph $AXIS_SCOPE_TP_TIME, axisMin, axisMin + SCOPE_TIMEAXIS_RESISTANCE_RANGE
[00]*         	|	endif
[00]          	|
[00]*         	|	if(DAG_GetNumericalValue(device, "Popup_Settings_OsciUpdMode") != GUI_SETTING_OSCI_SCALE_INTERVAL)
[00]          	|		return 0
[00]*         	|	endif
[00]          	|
[00]*         	|	[showSteadyStateResistance, showPeakResistance, showPowerSpectrum] = SCOPE_GetCheckBoxesForAddons(device, dataAcqOrTP)
[00]          	|
[00]*         	|	if(showPowerSpectrum)
[00]          	|		return NaN
[00]          	|	endif
[00]          	|
[00]          	|	if(!GotTPChannelsOnADCs(device))
[00]          	|		return NaN
[00]          	|	endif
[00]          	|
[00]*         	|	WAVE config  = GetDAQConfigWave(device)
[00]*         	|	WAVE ADCmode = GetADCTypesFromConfig(config)
[00]*         	|	WAVE ADCs    = GetADCListFromConfig(config)
[00]*         	|	WAVE DACs    = GetDACListFromConfig(config)
[00]*         	|	numADCs = DimSize(ADCs, ROWS)
[00]*         	|	numDACs = DimSize(DACs, ROWS)
[00]          	|
[00]*         	|	if(dataAcqOrTP == DATA_ACQUISITION_MODE)
[00]          	|		WAVE TPData = GetTPOscilloscopeWave(device)
[00]          	|	else
[00]*         	|		WAVE TPData = GetOscilloscopeWave(device)
[00]*         	|	endif
[00]          	|
[00]*         	|	additionalSpacing = DAG_GetNumericalValue(device, "setvar_Settings_OsciUpdExt") * PERCENT_TO_ONE
[00]          	|
[00]          	|	// scale the left AD axes
[00]*         	|	for(i = 0; i < numADCs; i += 1)
[00]          	|
[00]*         	|		if(ADCmode[i] != DAQ_CHANNEL_TYPE_TP)
[00]          	|			continue
[00]*         	|		endif
[00]          	|
[00]*         	|		leftAxis = AXIS_SCOPE_AD + num2str(ADCs[i])
[00]          	|
[03]*         	|		WaveStats/M=1/Q/RMD=[][numDACs + i] TPData
[00]          	|
[00]*         	|		statsMin = V_min
[00]*         	|		statsMax = V_max
[00]          	|
[00]          	|		// data is propably just zero, skip the axis
[00]*         	|		if(statsMin == statsMax || (IsNaN(statsMin) && IsNaN(statsMax)))
[00]          	|			continue
[00]          	|		endif
[00]          	|
[00]*         	|		GetAxis/Q/W=$graph $leftAxis
[00]*         	|		ASSERT(!V_Flag, "Expected axis does not exist")
[00]          	|
[00]          	|		axisMin = V_min
[00]          	|		axisMax = V_max
[00]          	|
[00]*         	|		if(axisMax == axisMin || (axisMin == -1 && axisMax == 1))
[00]          	|			spacing = (statsMax - statsMin) * additionalSpacing
[00]          	|		else
[00]*         	|			spacing = (axisMax - axisMin) * additionalSpacing
[00]          	|		endif
[00]          	|
[00]*         	|		if(axisMin < statsMin && abs(statsMin - axisMin) < spacing)
[00]*         	|			if(axisMax > statsMax && abs(statsMax - axisMax) < spacing)
[00]          	|				continue
[00]          	|			endif
[00]          	|		endif
[00]          	|
[00]          	|		SetAxis/W=$graph $leftAxis, statsMin - spacing / 2.0, statsMax + spacing / 2.0
[00]*         	|	endfor
[00]          	|End
*******************************************************************************************
Function: MIES_TestPulse.ipf TP_ROAnalysis; Percent total 03%
*******************************************************************************************
[00]*         	|Function TP_ROAnalysis(STRUCT ASYNC_ReadOutStruct &ar)
[00]          	|
[00]          	|	variable i, j, bufSize, headstage, marker
[00]          	|	variable posMarker, posAsync
[00]          	|	string lbl
[00]          	|
[00]*         	|	if(ar.rtErr || ar.abortCode)
[00]          	|		ASSERT(!ar.rtErr, "TP analysis thread encountered RTE " + ar.rtErrMsg)
[00]          	|		ASSERT(!ar.abortCode, "TP analysis thread aborted with code: " + GetErrMessage(ar.abortCode))
[00]          	|	endif
[00]          	|
[00]*         	|	DFREF dfr = ar.dfr
[00]          	|
[00]*         	|	WAVE/SDFR=dfr inData = tpData
[00]*         	|	SVAR/SDFR=dfr device = device
[00]*         	|	headstage = inData[%HEADSTAGE]
[00]*         	|	marker    = inData[%MARKER]
[00]          	|
[00]*         	|	WAVE asyncBuffer = GetTPResultAsyncBuffer(device)
[00]          	|
[00]*         	|	bufSize   = DimSize(asyncBuffer, ROWS)
[00]*         	|	posMarker = FindDimLabel(asyncBuffer, LAYERS, "MARKER")
[00]*         	|	posAsync  = FindDimLabel(asyncBuffer, COLS, "ASYNCDATA")
[00]          	|
[00]*         	|	FindValue/RMD=[][posAsync][posMarker, posMarker]/V=(marker)/T=0 asyncBuffer
[00]*         	|	i = (V_Value >= 0) ? V_Row : bufSize
[00]          	|
[00]*         	|	if(i == bufSize)
[00]*         	|		Redimension/N=(bufSize + 1, -1, -1) asyncBuffer
[00]*         	|		asyncBuffer[bufSize][][]                      = NaN
[00]*         	|		asyncBuffer[bufSize][posAsync][%REC_CHANNELS] = 0
[00]*         	|		asyncBuffer[bufSize][posAsync][posMarker]     = marker
[00]          	|	endif
[00]          	|
[00]*         	|	WAVE/T dimLabels = ListToTextWave(TP_ANALYSIS_DATA_LABELS, ";")
[00]*         	|	for(lbl : dimLabels)
[00]*         	|		asyncBuffer[i][%$lbl][headstage] = inData[%$lbl]
[00]          	|	endfor
[00]*         	|	asyncBuffer[i][posAsync][%REC_CHANNELS] += 1
[00]          	|
[00]          	|	// got one set of results ready
[00]*         	|	if(asyncBuffer[i][posAsync][%REC_CHANNELS] == inData[%NUMBER_OF_TP_CHANNELS])
[00]          	|
[00]*         	|		WAVE TPResults  = GetTPResults(device)
[00]*         	|		WAVE TPSettings = GetTPSettings(device)
[00]          	|
[00]*         	|		MultiThread TPResults[%BaselineSteadyState][] = asyncBuffer[i][%BASELINE][q]
[00]*         	|		MultiThread TPResults[%ResistanceSteadyState][] = asyncBuffer[i][%STEADYSTATERES][q]
[00]*         	|		MultiThread TPResults[%ResistanceInst][] = asyncBuffer[i][%INSTANTRES][q]
[00]*         	|		MultiThread TPResults[%ElevatedSteadyState][] = asyncBuffer[i][%ELEVATED_SS][q]
[00]*         	|		MultiThread TPResults[%ElevatedInst][] = asyncBuffer[i][%ELEVATED_INST][q]
[00]*         	|		MultiThread TPResults[%NOW][] = asyncBuffer[i][%NOW][q]
[00]*         	|		MultiThread TPResults[%HEADSTAGE][] = asyncBuffer[i][%HEADSTAGE][q]
[00]*         	|		MultiThread TPResults[%MARKER][] = asyncBuffer[i][%MARKER][q]
[00]*         	|		MultiThread TPResults[%NUMBER_OF_TP_CHANNELS][] = asyncBuffer[i][%NUMBER_OF_TP_CHANNELS][q]
[00]*         	|		MultiThread TPResults[%TIMESTAMP][] = asyncBuffer[i][%TIMESTAMP][q]
[00]*         	|		MultiThread TPResults[%TIMESTAMPUTC][] = asyncBuffer[i][%TIMESTAMPUTC][q]
[00]*         	|		MultiThread TPResults[%CLAMPMODE][] = asyncBuffer[i][%CLAMPMODE][q]
[00]*         	|		MultiThread TPResults[%CLAMPAMP][] = asyncBuffer[i][%CLAMPAMP][q]
[00]*         	|		MultiThread TPResults[%BASELINEFRAC][] = asyncBuffer[i][%BASELINEFRAC][q]
[00]*         	|		MultiThread TPResults[%CYCLEID][] = asyncBuffer[i][%CYCLEID][q]
[00]*         	|		MultiThread TPResults[%TPLENGTHPOINTSADC][] = asyncBuffer[i][%TPLENGTHPOINTSADC][q]
[00]*         	|		MultiThread TPResults[%PULSELENGTHPOINTSADC][] = asyncBuffer[i][%PULSELENGTHPOINTSADC][q]
[00]*         	|		MultiThread TPResults[%PULSESTARTPOINTSADC][] = asyncBuffer[i][%PULSESTARTPOINTSADC][q]
[00]*         	|		MultiThread TPResults[%SAMPLINGINTERVALADC][] = asyncBuffer[i][%SAMPLINGINTERVALADC][q]
[00]*         	|		MultiThread TPResults[%TPLENGTHPOINTSDAC][] = asyncBuffer[i][%TPLENGTHPOINTSDAC][q]
[00]*         	|		MultiThread TPResults[%PULSELENGTHPOINTSDAC][] = asyncBuffer[i][%PULSELENGTHPOINTSDAC][q]
[00]*         	|		MultiThread TPResults[%PULSESTARTPOINTSDAC][] = asyncBuffer[i][%PULSESTARTPOINTSDAC][q]
[00]*         	|		MultiThread TPResults[%SAMPLINGINTERVALDAC][] = asyncBuffer[i][%SAMPLINGINTERVALDAC][q]
[00]          	|
[00]          	|		// Remove finished results from buffer
[00]*         	|		DeletePoints i, 1, asyncBuffer
[00]          	|		if(!DimSize(asyncBuffer, ROWS))
[00]*         	|			KillOrMoveToTrash(wv = asyncBuffer)
[00]          	|		endif
[00]          	|
[00]*         	|		if(TPSettings[%bufferSize][INDEP_HEADSTAGE] > 1)
[00]          	|			WAVE TPResultsBuffer = GetTPResultsBuffer(device)
[00]          	|			TP_CalculateAverage(TPResultsBuffer, TPResults)
[00]*         	|		endif
[00]          	|
[00]*         	|		TPResults[%AutoTPAmplitude][]             = NaN
[00]*         	|		TPResults[%AutoTPBaseline][]              = NaN
[00]*         	|		TPResults[%AutoTPBaselineRangeExceeded][] = NaN
[00]*         	|		TPResults[%AutoTPBaselineFitResult][]     = NaN
[00]          	|
[00]*         	|		MultiThread TPResults[%AutoTPDeltaV][] = TPResults[%ElevatedSteadyState][q] - TPResults[%BaselineSteadyState][q]
[00]          	|
[00]*         	|		TP_AutoAmplitudeAndBaseline(device, TPResults, marker)
[00]*         	|		DQ_ApplyAutoBias(device, TPResults)
[00]*         	|		TP_RecordTP(device, TPResults, inData[%NOW])
[00]*         	|	endif
[00]          	|End
*******************************************************************************************
Function: MIES_Oscilloscope.ipf SCOPE_UpdateOscilloscopeData; Percent total 02%
*******************************************************************************************
[00]*         	|Function SCOPE_UpdateOscilloscopeData(string device, variable dataAcqOrTP, [variable chunk, variable fifoPos, variable deviceID])
[00]          	|
[00]          	|	STRUCT TPAnalysisInput tpInput
[00]          	|	variable i, j
[00]          	|	variable tpChannels, numADCs, numDACs, tpLengthPointsADC, tpStart, tpEnd, tpStartPos
[00]          	|	variable TPChanIndex, saveTP, clampAmp
[00]          	|	variable headstage, fifoLatest, channelIndex
[00]          	|	string hsList
[00]          	|
[00]*         	|	variable hardwareType = GetHardwareType(device)
[00]*         	|	switch(hardwareType)
[00]          	|		case HARDWARE_ITC_DAC:
[00]*         	|			if(dataAcqOrTP == TEST_PULSE_MODE)
[00]          	|				if(ParamIsDefault(chunk))
[00]          	|					chunk = 0
[00]          	|				endif
[00]*         	|				ASSERT(ParamIsDefault(fifoPos), "optional parameter fifoPos is not possible with TEST_PULSE_MODE")
[00]          	|			elseif(dataAcqOrTP == DATA_ACQUISITION_MODE)
[00]          	|				ASSERT(!ParamIsDefault(fifoPos), "optional parameter fifoPos missing")
[00]          	|				ASSERT(ParamIsDefault(chunk), "optional parameter chunk is not possible with DATA_ACQUISITION_MODE")
[00]          	|				fifopos = SCOPE_ITC_AdjustFIFOPos(device, fifopos)
[00]*         	|				ASSERT(IsFinite(fifopos), "Invalid fifo position")
[00]          	|			endif
[00]*         	|			SCOPE_ITC_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos)
[00]*         	|			break
[00]          	|		case HARDWARE_NI_DAC:
[00]          	|			ASSERT(!ParamIsDefault(deviceID), "optional parameter deviceID missing (required for NI devices in TP mode)")
[00]          	|			SCOPE_NI_UpdateOscilloscope(device, dataAcqOrTP, deviceID, fifoPos)
[00]          	|			break
[00]          	|		case HARDWARE_SUTTER_DAC:
[00]          	|			if(dataAcqOrTP == TEST_PULSE_MODE)
[00]          	|				ASSERT(!ParamIsDefault(chunk), "optional parameter chunk is missing with TEST_PULSE_MODE")
[00]          	|				ASSERT(ParamIsDefault(fifoPos), "optional parameter fifoPos is not possible with TEST_PULSE_MODE")
[00]          	|			elseif(dataAcqOrTP == DATA_ACQUISITION_MODE)
[00]          	|				ASSERT(!ParamIsDefault(fifoPos), "optional parameter fifoPos missing")
[00]          	|				ASSERT(ParamIsDefault(chunk), "optional parameter chunk is not possible with DATA_ACQUISITION_MODE")
[00]          	|			endif
[00]          	|			SCOPE_SU_UpdateOscilloscope(device, dataAcqOrTP, chunk, fifoPos)
[00]          	|			break
[00]          	|		default:
[00]*         	|			ASSERT(0, "Unsupported hardware type")
[00]          	|	endswitch
[00]          	|
[00]*         	|	WAVE config  = GetDAQConfigWave(device)
[00]          	|	WAVE ADCmode = GetADCTypesFromConfig(config)
[00]*         	|	tpChannels = GetNrOfTypedChannels(ADCmode, DAQ_CHANNEL_TYPE_TP)
[00]          	|
[00]          	|	// send data to TP Analysis if TP present
[00]*         	|	NVAR fifoPosGlobal = $GetFifoPosition(device)
[00]          	|
[00]*         	|	if(tpChannels)
[00]          	|		saveTP = DAG_GetNumericalValue(device, "check_Settings_TP_SaveTP")
[00]          	|		WAVE TPSettings     = GetTPSettings(device)
[00]*         	|		WAVE TPSettingsCalc = GetTPSettingsCalculated(device)
[00]          	|
[00]*         	|		tpLengthPointsADC = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%totalLengthPointsTP_ADC] : TPSettingsCalc[%totalLengthPointsDAQ_ADC]
[00]          	|
[00]          	|		// use a 'virtual' end position for fifoLatest for TP Mode since the input data contains one TP only
[00]*         	|		fifoLatest = (dataAcqOrTP == TEST_PULSE_MODE) ? tpLengthPointsADC : fifoPos
[00]          	|
[00]*         	|		WAVE ADCs   = GetADCListFromConfig(config)
[00]*         	|		WAVE DACs   = GetDACListFromConfig(config)
[00]*         	|		WAVE hsProp = GetHSProperties(device)
[00]          	|
[00]*         	|		WAVE/WAVE scaledDataWave = GetScaledDataWave(device)
[00]*         	|		numDACs = DimSize(DACs, ROWS)
[00]          	|		numADCs = DimSize(ADCs, ROWS)
[00]          	|
[00]          	|		// note: currently this works for multiplier = 1 only, see DC_PlaceDataInDAQDataWave
[00]*         	|		Make/FREE/N=(tpLengthPointsADC) channelData
[00]*         	|		WAVE tpInput.data = channelData
[00]          	|
[00]*         	|		tpInput.device               = device
[00]*         	|		tpInput.tpLengthPointsADC    = tpLengthPointsADC
[00]*         	|		tpInput.pulseLengthPointsADC = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%pulseLengthPointsTP_ADC] : TPSettingsCalc[%pulseLengthPointsDAQ_ADC]
[00]*         	|		tpInput.pulseStartPointsADC  = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%pulseStartPointsTP_ADC] : TPSettingsCalc[%pulseStartPointsDAQ_ADC]
[00]*         	|		tpInput.samplingIntervalADC  = DimDelta(scaledDataWave[numDACs], ROWS)
[00]*         	|		tpInput.tpLengthPointsDAC    = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%totalLengthPointsTP] : TPSettingsCalc[%totalLengthPointsDAQ]
[00]*         	|		tpInput.pulseLengthPointsDAC = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%pulseLengthPointsTP] : TPSettingsCalc[%pulseLengthPointsDAQ]
[00]*         	|		tpInput.pulseStartPointsDAC  = (dataAcqOrTP == TEST_PULSE_MODE) ? TPSettingsCalc[%pulseStartPointsTP] : TPSettingsCalc[%pulseStartPointsDAQ]
[00]*         	|		tpInput.samplingIntervalDAC  = DimDelta(scaledDataWave[0], ROWS)
[00]*         	|		tpInput.baselineFrac         = TPSettingsCalc[%baselineFrac]
[00]*         	|		tpInput.readTimeStamp        = ticks * TICKS_TO_SECONDS
[00]          	|		tpInput.activeADCs           = tpChannels
[00]          	|		tpInput.cycleId              = ROVAR(GetTestpulseCycleID(device))
[00]          	|
[00]*         	|		tpStart = trunc(fifoPosGlobal / tpLengthPointsADC)
[00]          	|		tpEnd   = trunc(fifoLatest / tpLengthPointsADC)
[00]*         	|		ASSERT(tpStart <= tpEnd, "New fifopos is smaller than previous fifopos")
[00]*         	|		Make/FREE/D/N=(tpEnd - tpStart) tpMarker
[00]*         	|		NewRandomSeed()
[00]*         	|		tpMarker[] = GetUniqueInteger()
[00]          	|
[00]*         	|		DEBUGPRINT("tpChannels: ", var = tpChannels)
[00]          	|		DEBUGPRINT("tpLength: ", var = tpLengthPointsADC)
[00]          	|
[00]          	|		for(i = tpStart; i < tpEnd; i += 1)
[00]          	|
[00]*         	|			tpInput.measurementMarker = tpMarker[i - tpStart]
[00]*         	|			tpStartPos                = i * tpLengthPointsADC
[00]          	|
[00]          	|			if(saveTP)
[00]          	|				Make/FREE/N=(tpLengthPointsADC, tpChannels) StoreTPWave
[00]          	|				for(j = 0; j < tpChannels; j += 1)
[00]          	|					WAVE scaledChannel = scaledDataWave[numDACs + j]
[00]          	|					Multithread StoreTPWave[][j] = scaledChannel[tpStartPos + p]
[00]          	|				endfor
[00]          	|				CopyScales/P scaledChannel, StoreTPWave
[00]          	|				TPChanIndex = 0
[00]*         	|				hsList      = ""
[00]          	|			endif
[00]          	|
[00]          	|			// Use same time for all headstages
[00]*         	|			tpInput.timeStamp     = DateTime
[00]*         	|			tpInput.timeStampUTC  = DateTimeInUTC()
[00]*         	|			tpInput.sendTPMessage = 1
[00]          	|
[00]*         	|			for(j = 0; j < numADCs; j += 1)
[00]          	|				if(ADCmode[j] == DAQ_CHANNEL_TYPE_TP)
[00]          	|
[00]*         	|					WAVE scaledChannel = scaledDataWave[numDACs + j]
[01]*         	|					MultiThread channelData[] = scaledChannel[tpStartPos + p]
[00]*         	|					CopyScales/P scaledChannel, channelData
[00]          	|
[00]*         	|					headstage = AFH_GetHeadstageFromADC(device, ADCs[j])
[00]*         	|					if(hsProp[headstage][%ClampMode] == I_CLAMP_MODE)
[00]          	|						clampAmp = TPSettings[%amplitudeIC][headstage]
[00]          	|					else
[00]*         	|						clampAmp = TPSettings[%amplitudeVC][headstage]
[00]          	|					endif
[00]          	|					tpInput.clampAmp  = clampAmp
[00]*         	|					tpInput.clampMode = hsProp[headstage][%ClampMode]
[00]*         	|					tpInput.headstage = headstage
[00]          	|
[00]*         	|					DEBUGPRINT("headstage: ", var = headstage)
[00]*         	|					DEBUGPRINT("channel: ", var = numDACs + j)
[00]          	|
[00]*         	|					TP_SendToAnalysis(device, tpInput)
[00]          	|
[00]*         	|					if(saveTP)
[00]          	|						hsList = AddListItem(num2str(headstage), hsList, ",", Inf)
[00]          	|						if(TPChanIndex != j)
[00]          	|							MultiThread StoreTPWave[][TPChanIndex] = channelData[p]
[00]          	|						endif
[00]*         	|						TPChanIndex += 1
[00]          	|					endif
[00]          	|
[00]          	|				endif
[00]          	|			endfor
[00]          	|
[00]          	|			if(saveTP)
[00]          	|				DEBUGPRINT("Storing TP with marker: ", var = tpInput.measurementMarker)
[00]          	|				TP_StoreTP(device, StoreTPWave, tpInput.measurementMarker, hsList)
[00]          	|				WaveClear StoreTPWave
[00]          	|			endif
[00]          	|
[00]          	|		endfor
[00]          	|
[00]          	|		if(dataAcqOrTP == DATA_ACQUISITION_MODE && tpEnd > tpStart)
[00]          	|			tpStartPos = (tpEnd - 1) * tpLengthPointsADC
[00]          	|			if(DAG_GetNumericalValue(device, "check_settings_show_power"))
[00]          	|				WAVE tpOsciForPowerSpectrum = GetScaledTPTempWave(device)
[00]          	|				Make/FREE/D/N=(numADCs) tpColumns
[00]          	|				j = 0
[00]          	|				for(i = 0; i < numADCs; i += 1)
[00]          	|					if(ADCmode[i] == DAQ_CHANNEL_TYPE_TP)
[00]          	|						channelIndex = numDACs + i
[00]          	|						WAVE scaledChannel = scaledDataWave[channelIndex]
[00]          	|						MultiThread tpOsciForPowerSpectrum[][channelIndex] = scaledChannel[tpStartPos + p]
[00]          	|						tpColumns[j] = channelIndex
[00]          	|						j           += 1
[00]          	|					endif
[00]          	|					CopyScales/P scaledChannel, tpOsciForPowerSpectrum
[00]          	|				endfor
[00]          	|				Redimension/N=(j) tpColumns
[00]          	|				SCOPE_UpdatePowerSpectrum(device, tpColumns, osci = tpOsciForPowerSpectrum)
[00]          	|			else
[00]          	|				WAVE TPOscilloscopeData = GetTPOscilloscopeWave(device)
[00]          	|				for(i = 0; i < numADCs; i += 1)
[00]          	|					if(ADCmode[i] == DAQ_CHANNEL_TYPE_TP)
[00]          	|						channelIndex = numDACs + i
[00]          	|						WAVE scaledChannel = scaledDataWave[channelIndex]
[00]          	|						MultiThread TPOscilloscopeData[][channelIndex] = scaledChannel[tpStartPos + p]
[00]          	|					endif
[00]          	|				endfor
[00]          	|			endif
[00]          	|		endif
[00]          	|	endif
[00]          	|
[00]          	|	// Sync fifo position
[00]*         	|	fifoPosGlobal = fifoPos
[00]          	|
[00]*         	|	ASYNC_ThreadReadOut()
[00]          	|End

@t-b
Copy link
Collaborator Author

t-b commented Apr 16, 2025

Notes from live debug session (16th April 2025)

DebugLogs.zip

@t-b t-b self-assigned this Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Amplifier bug Something isn't working PatchLink
Projects
None yet
Development

No branches or pull requests

2 participants