diff --git a/JenkinsfileHW b/JenkinsfileHW index f2fbca0..090effb 100644 --- a/JenkinsfileHW +++ b/JenkinsfileHW @@ -1,6 +1,6 @@ // Pipeline -lock(label: 'adgt_test_harness_boards') { - @Library('sdgtt-lib@adgt-test-harness') _ // Not necessary when we turn on global libraries :) +lock('nuc04') { + @Library('sdgtt-lib@nuc4-libm2k') _ // Not necessary when we turn on global libraries :) def hdlBranch = "NA" def linuxBranch = "NA" def bootPartitionBranch = "2021_r2" @@ -17,7 +17,8 @@ lock(label: 'adgt_test_harness_boards') { // harness.set_env('telemetry_repo', 'http://gateway.englab:3000/mirrors/telemetry.git') // harness.set_env('telemetry_branch', 'master') harness.set_env('matlab_repo', 'https://github.com/analogdevicesinc/PrecisionToolbox.git') // Not necessary when using checkout scm - harness.set_env('matlab_release','R2021b') + harness.set_env('matlab_branch','main') + harness.set_env('matlab_release','R2022b') harness.set_matlab_timeout('30m') //Update nebula config from netbox @@ -26,18 +27,21 @@ lock(label: 'adgt_test_harness_boards') { harness.set_env('netbox_ip','primary.englab') harness.set_env('netbox_port','8000') harness.set_env('netbox_base_url','netbox') - harness.set_env('netbox_token','0123456789abcdef0123456789abcdef01234567') - harness.set_env('netbox_devices_tag','active') + withCredentials([string(credentialsId: 'netbox_token', variable: 'TOKEN')]) { + harness.set_env('netbox_token', TOKEN) + } + harness.set_env('netbox_devices_tag','precision') //Update agent with required deps - harness.set_required_agent(["sdg-nuc-01"]) + harness.set_required_agent(["sdg-nuc-04"]) harness.set_env('update_container_lib', true) harness.set_env('update_lib_requirements', true) harness.update_agents() //Set other test parameters + harness.set_env('docker_image', 'tfcollins/test-harness-ci:libm2k') harness.set_nebula_debug(true) - harness.set_enable_docker(true) + harness.set_enable_docker(false) harness.set_docker_host_mode(false) harness.set_send_telemetry(false) harness.set_log_jira(false) @@ -50,7 +54,9 @@ lock(label: 'adgt_test_harness_boards') { // "zynq-zed-ad4030", // "zynq-zed-ad4630-16", // "zynq-zed-ad4630-24"]) - harness.set_required_hardware(["zynq-zed-adv7511-ad7768-1-evb"]) + harness.set_required_hardware(["zynq-zed-adv7511-ad7768-1-evb-precision", + "zynq-zed-adv7511-ad4630-24-precision", + "zynq-zed-adv7511-ad7768-axi-adc-precision"]) harness.set_docker_args(['Vivado', 'MATLAB']) harness.set_nebula_local_fs_source_root("artifactory.analog.com") diff --git a/test/AD4630_24Tests.m b/test/AD4630_24Tests.m index b06a676..010fb50 100644 --- a/test/AD4630_24Tests.m +++ b/test/AD4630_24Tests.m @@ -1,29 +1,158 @@ classdef AD4630_24Tests < HardwareTests - properties(TestParameter) - end properties uri = 'ip:analog-2.local'; author = 'ADI'; end - + + properties(TestParameter) + % start frequency, stop frequency, step, tolerance, repeats + signal_test = {{10000,250000,2500,0.05,10}}; + signal_vpp = {0.1, 0.3, 0.5}; + + sample_rate = {'10000', '50000', '100000', ... + '200000', '500000', '1000000', ... + '1760000', '2000000'}; + + sample_averaging_length = { ... + '2', '4', '8', '16', '32', '64', '128', '256', ... + '512', '1024', '2048', '4096', '8192', '16384', ... + '32768', '65536'}; + end + methods(TestClassSetup) % Check hardware connected function CheckForHardware(testCase) - Device = @()adi.AD4630_24.Rx; + Device = @()adi.AD4630_24.Rx('uri',testCase.uri); testCase.CheckDevice('ip',Device,testCase.uri(4:end),false); end end + + methods (Static) + function freq = estFrequencyMax(data,fs) + nSamp = length(data); + FFTRxData = fftshift(10*log10(abs(fft(data)))); + df = fs/nSamp; freqRangeRx = (0:df:fs/2-df).'; + % Disregard DC + [~,ind] = maxk(FFTRxData(end-length(freqRangeRx)+1:end,:),2); + freq = max(freqRangeRx(ind)); + end + end methods (Test) function testAD4630_24Smoke(testCase) adc = adi.AD4630_24.Rx('uri',testCase.uri); - data = adc(); + [data,valid] = adc(); adc.release(); + testCase.assertTrue(valid); testCase.assertTrue(sum(abs(double(data)))>0); end - + + function testAD4630_24AttrSampleRate(testCase,sample_rate) + % '1750000' is set as '1754386' + adc = adi.AD4630_24.Rx('uri',testCase.uri); + adc.uri = testCase.uri; + val = sample_rate; + adc.SampleRate = val; + [data,valid] = adc(); + ret_val = adc.getDeviceAttributeRAW('sampling_frequency',9); + adc.release(); + testCase.assertTrue(valid); + testCase.assertTrue(sum(abs(double(data)))>0); +% testCase.assertTrue(strcmp(val,string(ret_val)), ... +% 'Sample rate unexpected') + testCase.verifyEqual(str2double(ret_val),str2double(val), ... + 'RelTol',0,'Sample rate unexpected') + end + + % function testAD4630_24AttrSampleAveragingLength(testCase,sample_averaging_length) + % % The average mode works only with the output data mode set to 30-bit average + % % Skip test for now since it causes ERROR:READ LINE: -32 in iio_info + % adc = adi.AD4630_24.Rx('uri',testCase.uri); + % val = sample_averaging_length; + % adc.SampleAveragingLength = val; + % [data,valid] = adc(); + % ret_val = adc.getDeviceAttributeRAW('sample_averaging',8); + % adc.release(); + % testCase.assertTrue(valid); + % testCase.assertTrue(sum(abs(double(data)))>0); + % testCase.assertTrue(strcmp(val,string(ret_val))); + % end + + function testAD4630_24DifferentialInputRMS(testCase,signal_vpp) + % Signal source setup + m2k_class = instr_m2k(); + m2k = m2k_class.connect(getenv('M2K_URI'), false); + siggen = m2k_class.create_instr(m2k, "siggen"); + % ADC setup + adc = adi.AD4630_24.Rx('uri',testCase.uri); + fs = str2double(adc.SampleRate); + + % Set channel 1 to 50KHz, 500mHz and minimize channel 2 amplitude + signal_frequency = 5e4; + m2k_class.control(siggen, 0, [signal_frequency, signal_vpp, 0, 0]); + m2k_class.control(siggen, 1, [signal_frequency, 0.000001, 0, 0]); + for k = 1:5 + [data,valid] = adc(); + end + data = double(data); + % Generate same signal in channel 2 to double signal at differential inputs + m2k_class.control(siggen, 1, [signal_frequency, signal_vpp, 0, 0]); + for k = 1:5 + [data1,valid1] = adc(); + end + data1 = double(data1); + + % Clean up + adc.release(); + m2k_class.contextClose(); + + % Assertions + testCase.assertTrue(valid & valid1); + testCase.verifyEqual(rms(data1),rms(data)*2,'RelTol',0.3) + end + + function testAD4630_24DifferentialInputSweep(testCase,signal_test) + % Signal source setup + m2k_class = instr_m2k(); + m2k = m2k_class.connect(getenv('M2K_URI'), false); + siggen = m2k_class.create_instr(m2k, "siggen"); + % ADC setup + adc = adi.AD4630_24.Rx('uri',testCase.uri); + adc.EnabledChannels = [1,2]; + fs = str2double(adc.SampleRate); + + start = signal_test{1}; + stop = signal_test{2}; + step = signal_test{3}; + tol = signal_test{4}; + repeats = signal_test{5}; + numints = round((stop-start)/step); + for ii = 1:repeats + ind = randi([0, numints]); + frequency = start+(step*ind); + m2k_class.control(siggen, 0, [frequency, 0.5, 0, 0]); + m2k_class.control(siggen, 1, [frequency, 0.5, 0, 0]); + for k = 1:5 + [data,valid] = adc(); + end + data = double(data); + freq = estFrequencyMax(double(data),fs); + + % Assertions + testCase.assertTrue(valid); + testCase.verifyEqual(freq(1),freq(2),'RelTol',tol) + testCase.verifyEqual(mean(freq),frequency,'RelTol',tol,... + 'Frequency of signal unexpected') + end + + % Clean up + adc.release(); + m2k_class.contextClose(); + + + end end end diff --git a/test/AD7768Tests.m b/test/AD7768Tests.m index 1e79617..f699593 100644 --- a/test/AD7768Tests.m +++ b/test/AD7768Tests.m @@ -1,11 +1,17 @@ classdef AD7768Tests < HardwareTests - - properties(TestParameter) - end + properties uri = 'ip:analog-2.local'; author = 'ADI'; end + + properties(TestParameter) + % start frequency. stop frequency, step, tolerance, repeats + signal_test = {{1000,100000,2500,0.025,10}}; + sample_rate = {'256000', '128000', '64000', ... + '32000', '16000', '8000', '4000', ... + '2000', '1000'}; + end methods(TestClassSetup) % Check hardware connected @@ -14,6 +20,17 @@ function CheckForHardware(testCase) testCase.CheckDevice('ip',Device,testCase.uri(4:end),false); end end + + methods (Static) + function freq = estFrequencyMax(data,fs) + nSamp = length(data); + FFTRxData = fftshift(10*log10(abs(fft(data)))); + df = fs/nSamp; freqRangeRx = (0:df:fs/2-df).'; + % Disregard DC + [~,ind] = maxk(FFTRxData(end-length(freqRangeRx)+1:end,:),2); + freq = max(freqRangeRx(ind)); + end + end methods (Test) @@ -23,6 +40,41 @@ function testAD7768Smoke(testCase) adc.release(); testCase.assertTrue(sum(abs(double(data)))>0); end + + function testAD7768Signal(testCase,signal_test) + % Signal source setup + m2k_class = instr_m2k(); + m2k = m2k_class.connect(getenv('M2K_URI'), false); + siggen = m2k_class.create_instr(m2k, "siggen"); + % ADC setup + adc = adi.AD7768.Rx; + adc.uri = testCase.uri; + adc.EnabledChannels = [1 2 3 4 5 6 7 8]; + + start = signal_test{1}; + stop = signal_test{2}; + step = signal_test{3}; + tol = signal_test{4}; + repeats = signal_test{5}; + numints = round((stop-start)/step); + for ii = 1:repeats + ind = randi([0, numints]); + frequency = start+(step*ind); + m2k_class.control(siggen, 0, [frequency, 0.5, 0.5, 0]); + m2k_class.control(siggen, 1, [frequency, 0.5, 0.5, 0]); + for k = 1:5 + data = adc(); + end + for ch = adc.EnabledChannels + freqEst = testCase.estFrequencyMax(data(:,ch),str2double(adc.SampleRate)); + testCase.assertTrue(sum(abs(double(data(:,ch))))>0); + testCase.verifyEqual(freqEst,frequency,'RelTol',tol,... + 'Frequency of signal unexpected') + end + end + adc.release(); + m2k_class.contextClose(); + end end diff --git a/test/AD7768_1Tests.m b/test/AD7768_1Tests.m index f1854eb..4c4c3dc 100644 --- a/test/AD7768_1Tests.m +++ b/test/AD7768_1Tests.m @@ -1,12 +1,22 @@ classdef AD7768_1Tests < HardwareTests - - properties(TestParameter) - end + properties uri = 'ip:analog'; author = 'ADI'; end - + + properties(TestParameter) + % start frequency. stop frequency, step, tolerance, repeats + signal_test = {{1000,125000,2500,0.015,10}}; + samples_per_frame = {{2^1,2^24,2^8,0.0,10}}; + sample_rate = {'256000', '128000', '64000', ... + '32000', '16000', '8000', '4000', ... + '2000', '1000'}; + common_mode_voltage = { '(AVDD1-AVSS)/2','2V5', ... + '2V05','1V9','1V65','1V1','0V9', ... + 'OFF'}; + end + methods(TestClassSetup) % Check hardware connected function CheckForHardware(testCase) @@ -14,17 +24,113 @@ function CheckForHardware(testCase) testCase.CheckDevice('ip',Device,testCase.uri(4:end),false); end end + + methods (Static) + function freq = estFrequencyMax(data,fs) + nSamp = length(data); + FFTRxData = fftshift(10*log10(abs(fft(data)))); + df = fs/nSamp; freqRangeRx = (0:df:fs/2-df).'; + % Disregard DC + [~,ind] = maxk(FFTRxData(end-length(freqRangeRx)+1:end,:),2); + freq = max(freqRangeRx(ind)); + end + end methods (Test) function testAD7768_1Smoke(testCase) adc = adi.AD7768_1.Rx; adc.uri = testCase.uri; - data = adc(); + [data,valid] = adc(); adc.release(); + testCase.assertTrue(valid); testCase.assertTrue(sum(abs(double(data)))>0); end - + + function testAD7768_1Signal(testCase,signal_test) + % Signal source setup + m2k_class = instr_m2k(); + m2k = m2k_class.connect(getenv('M2K_URI'), false); + siggen = m2k_class.create_instr(m2k, "siggen"); + % ADC setup + adc = adi.AD7768_1.Rx; + adc.uri = testCase.uri; + + start = signal_test{1}; + stop = signal_test{2}; + step = signal_test{3}; + tol = signal_test{4}; + repeats = signal_test{5}; + numints = round((stop-start)/step); + for ii = 1:repeats + ind = randi([0, numints]); + frequency = start+(step*ind); + m2k_class.control(siggen, 0, [frequency, 0.5, 0, 0]); + for k = 1:5 + [data,valid] = adc(); + end + freqEst = testCase.estFrequencyMax(data,str2double(adc.SampleRate)); + testCase.assertTrue(valid); + testCase.assertTrue(sum(abs(double(data)))>0); + testCase.verifyEqual(freqEst,frequency,'RelTol',tol,... + 'Frequency of signal unexpected') + end + adc.release(); + m2k_class.contextClose(); + end + + function testAD7768_1AttrSampleRate(testCase,sample_rate) + % FIXME: Hangs unless board is rebooted + adc = adi.AD7768_1.Rx; + adc.uri = testCase.uri; + val = sample_rate; + adc.SampleRate = val; + [data,valid] = adc(); + ret_val = adc.getDeviceAttributeRAW('sampling_frequency',8); + adc.release(); + testCase.assertTrue(valid); + testCase.assertTrue(sum(abs(double(data)))>0); + testCase.assertTrue(strcmp(val,string(ret_val))); + end + + function testAD7768_1AttrCommonModeVolage(testCase,common_mode_voltage) + % FIXME: Hangs unless board is rebooted + adc = adi.AD7768_1.Rx; + adc.uri = testCase.uri; + val = common_mode_voltage; + adc.CommonModeVolts = val; + [data,valid] = adc(); + ret_val = adc.getDeviceAttributeRAW('common_mode_voltage',8); + adc.release(); + testCase.assertTrue(valid); + testCase.assertTrue(sum(abs(double(data)))>0); + testCase.assertTrue(strcmp(val,string(ret_val))); + end + + function testAD7768_1AttrSamplesPerFrame(testCase,samples_per_frame) + % This is not written to the device. Should this even be tested? + adc = adi.AD7768_1.Rx; + adc.uri = testCase.uri; + + start = samples_per_frame{1}; + stop = samples_per_frame{2}; + step = samples_per_frame{3}; + tol = samples_per_frame{4}; + repeats = samples_per_frame{5}; + numints = round((stop-start)/step); + for ii = 1:repeats + ind = randi([0, numints]); + val = start+(step*ind); + adc.SamplesPerFrame = val; + [data, valid] = adc(); + [ret_val,~] = size(data); + adc.release(); + testCase.assertTrue(valid); + testCase.assertTrue(sum(abs(double(data)))>0); + testCase.verifyEqual(ret_val,val,'RelTol',tol,... + 'Frequency of signal unexpected') + end + end end end diff --git a/test/instr_m2k.m b/test/instr_m2k.m new file mode 100644 index 0000000..d08fe31 --- /dev/null +++ b/test/instr_m2k.m @@ -0,0 +1,174 @@ +classdef instr_m2k < handle + + properties + DAC_available_sample_rates = [750, 7500, 75000, 750000, 7500000, 75000000]; + DAC_max_rate + DAC_min_nr_of_points = 10; + max_buffer_size = 500000; + ADC_available_sample_rates = [1000, 10000, 100000, 1000000, 10000000, 100000000]; + ADC_max_rate + ADC_min_nr_of_points = 10; + end + + methods + function [best_ratio, best_fract] = get_best_ratio(obj, ratio) + max_it = obj.max_buffer_size / ratio; + best_ratio = ratio; + best_fract = 1; + + for i = 1 : fix(max_it) + new_ratio = i * ratio; + % (new_fract, integral) = math.modf(new_ratio) + new_fract = mod(abs(new_ratio),1); + % integral = fix(new_ratio); + if new_fract < best_fract + best_fract = new_fract; + best_ratio = new_ratio; + end + if new_fract == 0 + break + end + end + end + + function size = get_samples_count(obj, rate, freq, mode) + ratio = rate / freq; + if mode == "DAC" + min_nr_of_points = obj.DAC_min_nr_of_points; + max_rate = obj.DAC_max_rate; + elseif mode == "ADC" + min_nr_of_points = obj.ADC_min_nr_of_points; + max_rate = obj.ADC_max_rate; + end + + if ratio < min_nr_of_points && rate < max_rate + size = 0; + return + end + if ratio < 2 + size = 0; + return + end + + [ratio, fract] = obj.get_best_ratio(ratio); + % ratio = number of periods in buffer + % fract = what is left over - error + + size = fix(ratio); + while bitand(size, uint16(0x03)) + size = size * 2; % double instead of python << + end + while size < 1024 + size = size * 2; % double instead of python << + end + end + + function rate = get_optimal_sample_rate(obj, freq, mode) + if mode == "DAC" + available_sample_rates = obj.DAC_available_sample_rates; + elseif mode == "ADC" + available_sample_rates = obj.ADC_available_sample_rates; + end + + for rate = available_sample_rates + buf_size = obj.get_samples_count(rate, freq, mode); + if buf_size + break + end + end + end + + function [sample_rate, buf] = sine_buffer_generator(obj, freq, ampl, offset, phase) + sample_rate = obj.get_optimal_sample_rate(freq, "DAC"); + nr_of_samples = obj.get_samples_count(sample_rate, freq, "DAC"); + samples_per_period = sample_rate / freq; + phase_in_samples = (phase / 360) * samples_per_period; + + buf = zeros(1,nr_of_samples); + + for i = 1:nr_of_samples + buf(i) = (... + offset ... + + ampl ... + * (sin(((i + phase_in_samples) / samples_per_period) * 2 * pi)) ... + ); + end + end + end + + + methods + % Constructor + function obj = instr_m2k() + obj.DAC_max_rate = obj.DAC_available_sample_rates(end); % last sample rate = max rate + obj.ADC_max_rate = obj.ADC_available_sample_rates(end); % last sample rate = max rate + end + + function m2k = connect(obj, uri, calibrate) + import clib.libm2k.libm2k.* + m2k = context.m2kOpen(uri); + if clibIsNull(m2k) + clib.libm2k.libm2k.context.contextCloseAll(uri); + m2k = context.m2kOpen(); + end + if isempty(m2k) + error('M2K device not found'); + end + if calibrate + m2k.calibrateDAC(); + m2k.calibrateADC(); + end + end + + % function m2k = calibrate() + % end + + function instr = create_instr(obj, ctx, instrument) + % Method to create instrument object from ctx + if instrument == "siggen" + instr = ctx.getAnalogOut(); + elseif instrument == "specanalyzer" | instrument == "voltmeter" + instr = ctx.getAnalogIn(); + elseif instrument == "powersupply" + instr = ctx.getPowerSupply(); + end + end + + function retval = control(obj, instr, chan, control_param) + % Generic control method for any instrument + % instr - instrument object + % chan - ADC or DAC channel, 0 or 1 only + % control_param - a list containing control parameters + % siggen - [tone_frequency,ampl,offset,phase] + % TODO: implement other instruments + % control_param should be treated as varargin + + if isa(instr, 'clib.libm2k.libm2k.analog.M2kAnalogOut') && length(control_param) == 4 + % Generates sinewave at chan + % Known issue - signal generated at one channel appears at the other + control_param = num2cell(control_param); + [tone_frequency, ampl, offset, phase] = control_param{:}; + [samp, buf] = obj.sine_buffer_generator(tone_frequency, ampl, offset, phase); + instr.enableChannel(chan, true); + instr.setSampleRate(chan, samp); + instr.push(chan, buf); + retval = 1; + end + end + + function contextClose(obj) + import clib.libm2k.libm2k.* + clib.libm2k.libm2k.context.contextCloseAll(); + end + + function delete(obj, m2k) + vars = who; + for i = 1 : length(vars) + if contains(class(eval(vars{i})),'clib.libm2k.libm2k.analog') + evalin('base', "clear " + string(vars{1})); + end + end + end + + end +end \ No newline at end of file diff --git a/test/runHWTests.m b/test/runHWTests.m index e718ada..92ead75 100644 --- a/test/runHWTests.m +++ b/test/runHWTests.m @@ -1,71 +1,75 @@ function runHWTests(board) -import matlab.unittest.TestRunner; -import matlab.unittest.TestSuite; -import matlab.unittest.plugins.TestReportPlugin; -import matlab.unittest.plugins.XMLPlugin -import matlab.unittest.plugins.DiagnosticsValidationPlugin -import matlab.unittest.parameters.Parameter -import matlab.unittest.plugins.ToUniqueFile; -import matlab.unittest.plugins.TAPPlugin; -import matlab.unittest.constraints.ContainsSubstring; -import matlab.unittest.selectors.HasName; -import matlab.unittest.selectors.HasProcedureName; - -switch board - case "zynq-zed-ad7380" - at = 'AD7380'; - case "zynq-zed-ad7768" - at = 'AD7768'; - case "zynq-zed-adv7511-ad7768-1-evb" - at = 'AD7768_1'; - case "zynq-zed-ad4030" - at = 'AD4030'; - case "zynq-zed-ad4630-16" - at = 'AD4630_16'; - case "zynq-zed-ad4630-24" - at = 'AD4630_24'; - - otherwise - error('%s unsupported for HW test harness', board); -end -ats = {'AD7380Tests','AD7768Tests','AD7768_1Tests','AD4030Tests',... - 'AD4630_16Tests','AD4630_24Tests'}; - -if nargin == 0 - suite = testsuite(ats); -else - suite = testsuite(ats); - suite = selectIf(suite,HasProcedureName(ContainsSubstring(at,'IgnoringCase',true))); -end - -try + import matlab.unittest.TestRunner; + import matlab.unittest.TestSuite; + import matlab.unittest.plugins.TestReportPlugin; + import matlab.unittest.plugins.XMLPlugin + import matlab.unittest.plugins.DiagnosticsValidationPlugin + import matlab.unittest.parameters.Parameter + import matlab.unittest.plugins.ToUniqueFile; + import matlab.unittest.plugins.TAPPlugin; + import matlab.unittest.constraints.ContainsSubstring; + import matlab.unittest.selectors.HasName; + import matlab.unittest.selectors.HasProcedureName; - runner = matlab.unittest.TestRunner.withTextOutput('OutputDetail',1); - runner.addPlugin(DiagnosticsValidationPlugin) - xmlFile = board+"_HWTestResults.xml"; - plugin = XMLPlugin.producingJUnitFormat(xmlFile); + switch board + case "zynq-zed-ad7380" + at = 'AD7380'; + case {"zynq-zed-ad7768", ... + "zynq-zed-adv7511-ad7768-axi-adc-precision"} + at = 'AD7768'; + case {"zynq-zed-adv7511-ad7768-1-evb", ... + "zynq-zed-adv7511-ad7768-1-evb-precision"} + at = 'AD7768_1'; + case "zynq-zed-ad4030" + at = 'AD4030'; + case "zynq-zed-ad4630-16" + at = 'AD4630_16'; + case {"zynq-zed-ad4630-24", ... + "zynq-zed-adv7511-ad4630-24-precision"} + at = 'AD4630_24'; + + otherwise + error('%s unsupported for HW test harness', board); + end + ats = {'AD7380Tests','AD7768Tests','AD7768_1Tests','AD4030Tests',... + 'AD4630_16Tests','AD4630_24Tests'}; - runner.addPlugin(plugin); - results = runner.run(suite); + if nargin == 0 + suite = testsuite(ats); + else + suite = testsuite(ats); + suite = selectIf(suite,HasProcedureName(ContainsSubstring(at,'IgnoringCase',true))); + end - t = table(results); - disp(t); - disp(repmat('#',1,80)); - fid = fopen('failures.txt','a+'); - for test = results - if test.Failed - disp(test.Name); - fprintf(fid,string(test.Name)+'\n'); + try + + runner = matlab.unittest.TestRunner.withTextOutput('OutputDetail',1); + runner.addPlugin(DiagnosticsValidationPlugin) + xmlFile = board+"_HWTestResults.xml"; + plugin = XMLPlugin.producingJUnitFormat(xmlFile); + + runner.addPlugin(plugin); + results = runner.run(suite); + + t = table(results); + disp(t); + disp(repmat('#',1,80)); + fid = fopen('failures.txt','a+'); + for test = results + if test.Failed + disp(test.Name); + fprintf(fid,string(test.Name)+'\n'); + end end + fclose(fid); + catch e + disp(getReport(e,'extended')); + bdclose('all'); + exit(1); end - fclose(fid); -catch e - disp(getReport(e,'extended')); + save(['BSPTest_',datestr(now,'dd_mm_yyyy-HH_MM_SS'),'.mat'],'t'); bdclose('all'); - exit(1); -end -save(['BSPTest_',datestr(now,'dd_mm_yyyy-HH_MM_SS'),'.mat'],'t'); -bdclose('all'); -exit(any([results.Failed])); -end + exit(any([results.Failed])); + end + \ No newline at end of file