From 00021cceeac4d0054c76038c8d12ac8086f24811 Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Tue, 27 Oct 2026 10:25:51 +0000 Subject: [PATCH 1/7] Adding Multi Record in NI-Scope --- CHANGELOG.md | 1 + build/templates/tox-system_tests.ini.mako | 3 + docs/niscope/examples.rst | 9 +++ generated/niscope/tox-system_tests.ini | 1 + src/niscope/examples/niscope_multi_record.py | 83 ++++++++++++++++++++ 5 files changed, 97 insertions(+) create mode 100644 src/niscope/examples/niscope_multi_record.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bc3af6804..afa19c6325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1901,6 +1901,7 @@ #### [niscope] Unreleased - Added - (Common) Added `nitlsconfig[grpc]>=1.0.0a2` to the optional gRPC dependencies. + - Added the `niscope_multi_record.py` example. - Changed - Removed diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index c2b3d9131d..9c7f07cb3e 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -76,6 +76,9 @@ deps = % endif % if module_name == 'nidigital': ${module_name}-system_tests: nisync +% endif +% if module_name == 'niscope': + ${module_name}-system_tests: matplotlib; sys_platform != "win32" % endif ${module_name}-system_tests: pytest ${module_name}-system_tests: coverage diff --git a/docs/niscope/examples.rst b/docs/niscope/examples.rst index 71f84c469c..bb8fb969ad 100644 --- a/docs/niscope/examples.rst +++ b/docs/niscope/examples.rst @@ -30,6 +30,15 @@ niscope_fetch_into.py :encoding: utf8 :caption: `(niscope_fetch_into.py) `_ +niscope_multi_record.py +----------------------- + +.. literalinclude:: ../../src/niscope/examples/niscope_multi_record.py + :language: python + :linenos: + :encoding: utf8 + :caption: `(niscope_multi_record.py) `_ + niscope_read.py --------------- diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index 2f232d27ab..afadc34815 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -39,6 +39,7 @@ commands = deps = niscope-wheel_dep: build + niscope-system_tests: matplotlib; sys_platform != "win32" niscope-system_tests: pytest niscope-system_tests: coverage niscope-system_tests: numpy diff --git a/src/niscope/examples/niscope_multi_record.py b/src/niscope/examples/niscope_multi_record.py new file mode 100644 index 0000000000..88cda150de --- /dev/null +++ b/src/niscope/examples/niscope_multi_record.py @@ -0,0 +1,83 @@ +#!/usr/bin/python + +import argparse +import niscope +import pytest +import sys + +PLOT_STYLES = {'LINE': '-', 'POINTS': '.'} +PLOT_RELATIVE_TO = ('TRIGGER', 'ABSOLUTE') + + +def _plot_records(plt, waveforms, plot_style, plot_relative_to): + figure, axes = plt.subplots() + axes.set_title('Scope Multi Record') + axes.set_xlabel('Time relative to trigger (s)' if plot_relative_to == 'TRIGGER' else 'Absolute time (s)') + axes.set_ylabel('Amplitude (V)') + axes.grid(True) + for waveform in waveforms: + initial_x = waveform.relative_initial_x if plot_relative_to == 'TRIGGER' else waveform.absolute_initial_x + samples = waveform.samples.tolist() # samples is a memoryview, which matplotlib cannot plot + x = [initial_x + i * waveform.x_increment for i in range(len(samples))] + axes.plot(x, samples, PLOT_STYLES[plot_style], label=f'Record {waveform.record}') + axes.legend(loc='upper right') + return figure + + +def example(resource_name, options, channel, vertical_range, min_sample_rate, min_record_length, num_records, plot_style, plot_relative_to): + import matplotlib.pyplot as plt + + with niscope.Session(resource_name=resource_name, options=options) as session: + session.configure_vertical(range=vertical_range, coupling=niscope.VerticalCoupling.DC) + session.configure_horizontal_timing(min_sample_rate=min_sample_rate, min_num_pts=min_record_length, ref_position=50.0, num_records=num_records, enforce_realtime=True) + # The VI uses a fixed edge trigger on channel 0. + session.configure_trigger_edge(trigger_source='0', level=0.0, trigger_coupling=niscope.TriggerCoupling.DC, slope=niscope.TriggerSlope.POSITIVE) + with session.initiate(): + # Fetch waits for all records to be acquired and returns them all. + waveforms = session.channels[channel].fetch(num_records=num_records) + + figure = _plot_records(plt, waveforms, plot_style, plot_relative_to) + try: + if plt.fignum_exists(figure.number): + plt.show() + finally: + plt.close(figure) + return waveforms + + +def _main(argsv): + parser = argparse.ArgumentParser(description='Acquires multiple triggered records from a channel and plots them.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-n', '--resource-name', default='PXI1Slot2', help='Specifies the resource name of the device to initialize.') + parser.add_argument('-c', '--channel', default='0', help='Channel to use') + parser.add_argument('-v', '--vertical-range', default=5.0, type=float, help='Specifies the absolute value of the input range for a channel in volts.') + parser.add_argument('-r', '--min-sample-rate', default=1e7, type=float, help='The sampling rate for the acquisition.') + parser.add_argument('-N', '--num-records', default=2, type=int, help='The number of records to acquire') + parser.add_argument('-l', '--min-record-length', default=256, type=int, help='The minimum number of points you need in the record for each channel.') + parser.add_argument('-R', '--plot-relative-to', default='TRIGGER', choices=PLOT_RELATIVE_TO, type=str.upper, help='Time reference for the plot; ABSOLUTE requires a device that supports absolute timestamps.') + parser.add_argument('-p', '--plot-style', default='POINTS', choices=PLOT_STYLES.keys(), type=str.upper, help='Plot the records as a continuous line or as individual points.') + parser.add_argument('-op', '--option-string', default='', type=str, help='Specifies the initial value of certain properties for the session.') + args = parser.parse_args(argsv) + example(args.resource_name, args.option_string, args.channel, args.vertical_range, args.min_sample_rate, args.min_record_length, args.num_records, args.plot_style, args.plot_relative_to) + + +def main(): + _main(sys.argv[1:]) + + +def test_example(): + plt = pytest.importorskip('matplotlib.pyplot') + plt.switch_backend('Agg') # Avoid opening a chart window during the test + options = {'simulate': True, 'driver_setup': {'Model': '5164', 'BoardType': 'PXIe', }, } + waveforms = example('PXI1Slot2', options, '0', 5.0, 1e7, 256, 3, 'POINTS', 'TRIGGER') + assert len(waveforms) == 3 + + +def test_main(): + plt = pytest.importorskip('matplotlib.pyplot') + plt.switch_backend('Agg') # Avoid opening a chart window during the test + cmd_line = ['--option-string', 'Simulate=1, DriverSetup=Model:5164; BoardType:PXIe', '--num-records', '2', ] + _main(cmd_line) + + +if __name__ == '__main__': + main() From 3d2662cc05a5155a59b443f3065c80d8964240b6 Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Tue, 27 Oct 2026 12:15:42 +0000 Subject: [PATCH 2/7] Adding additional parameter trigger type The additional trigger type since this example is independent of the trigger type and the LV as well documented that it is avoided to simplify the VI, but adding this will let the user aware that they can configure any type of trigger instead of just the edge trigger --- src/niscope/examples/niscope_multi_record.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/niscope/examples/niscope_multi_record.py b/src/niscope/examples/niscope_multi_record.py index 88cda150de..f6b1c466ac 100644 --- a/src/niscope/examples/niscope_multi_record.py +++ b/src/niscope/examples/niscope_multi_record.py @@ -7,6 +7,7 @@ PLOT_STYLES = {'LINE': '-', 'POINTS': '.'} PLOT_RELATIVE_TO = ('TRIGGER', 'ABSOLUTE') +TRIGGER_TYPES = ('EDGE', 'IMMEDIATE') def _plot_records(plt, waveforms, plot_style, plot_relative_to): @@ -24,14 +25,18 @@ def _plot_records(plt, waveforms, plot_style, plot_relative_to): return figure -def example(resource_name, options, channel, vertical_range, min_sample_rate, min_record_length, num_records, plot_style, plot_relative_to): +def example(resource_name, options, channel, vertical_range, min_sample_rate, min_record_length, num_records, plot_style, plot_relative_to, + trigger_type): import matplotlib.pyplot as plt with niscope.Session(resource_name=resource_name, options=options) as session: session.configure_vertical(range=vertical_range, coupling=niscope.VerticalCoupling.DC) session.configure_horizontal_timing(min_sample_rate=min_sample_rate, min_num_pts=min_record_length, ref_position=50.0, num_records=num_records, enforce_realtime=True) - # The VI uses a fixed edge trigger on channel 0. - session.configure_trigger_edge(trigger_source='0', level=0.0, trigger_coupling=niscope.TriggerCoupling.DC, slope=niscope.TriggerSlope.POSITIVE) + # Other trigger types (for example hysteresis or window) can be configured here; IMMEDIATE acquires without an input signal crossing the edge level. + if trigger_type == 'EDGE': + session.configure_trigger_edge(trigger_source='0', level=0.0, trigger_coupling=niscope.TriggerCoupling.DC, slope=niscope.TriggerSlope.POSITIVE) + else: + session.configure_trigger_immediate() with session.initiate(): # Fetch waits for all records to be acquired and returns them all. waveforms = session.channels[channel].fetch(num_records=num_records) @@ -49,6 +54,7 @@ def _main(argsv): parser = argparse.ArgumentParser(description='Acquires multiple triggered records from a channel and plots them.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('-n', '--resource-name', default='PXI1Slot2', help='Specifies the resource name of the device to initialize.') parser.add_argument('-c', '--channel', default='0', help='Channel to use') + parser.add_argument('-T', '--trigger-type', default='EDGE', choices=TRIGGER_TYPES, type=str.upper, help='EDGE configures the digitizer for edge triggering (channel 0, 0 V, DC coupling, rising slope). IMMEDIATE triggers as soon as the pretrigger samples are acquired.') parser.add_argument('-v', '--vertical-range', default=5.0, type=float, help='Specifies the absolute value of the input range for a channel in volts.') parser.add_argument('-r', '--min-sample-rate', default=1e7, type=float, help='The sampling rate for the acquisition.') parser.add_argument('-N', '--num-records', default=2, type=int, help='The number of records to acquire') @@ -57,7 +63,8 @@ def _main(argsv): parser.add_argument('-p', '--plot-style', default='POINTS', choices=PLOT_STYLES.keys(), type=str.upper, help='Plot the records as a continuous line or as individual points.') parser.add_argument('-op', '--option-string', default='', type=str, help='Specifies the initial value of certain properties for the session.') args = parser.parse_args(argsv) - example(args.resource_name, args.option_string, args.channel, args.vertical_range, args.min_sample_rate, args.min_record_length, args.num_records, args.plot_style, args.plot_relative_to) + example(args.resource_name, args.option_string, args.channel, args.vertical_range, args.min_sample_rate, args.min_record_length, args.num_records, args.plot_style, args.plot_relative_to, + args.trigger_type) def main(): @@ -68,7 +75,7 @@ def test_example(): plt = pytest.importorskip('matplotlib.pyplot') plt.switch_backend('Agg') # Avoid opening a chart window during the test options = {'simulate': True, 'driver_setup': {'Model': '5164', 'BoardType': 'PXIe', }, } - waveforms = example('PXI1Slot2', options, '0', 5.0, 1e7, 256, 3, 'POINTS', 'TRIGGER') + waveforms = example('PXI1Slot2', options, '0', 5.0, 1e7, 256, 3, 'POINTS', 'TRIGGER', 'EDGE') assert len(waveforms) == 3 From f9bc87d816022deee87dfebf5281ca7f31d0dafd Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Thu, 29 Oct 2026 07:22:42 +0000 Subject: [PATCH 3/7] Rephrasing comments and changing the session config behaviour --- src/niscope/examples/niscope_multi_record.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/niscope/examples/niscope_multi_record.py b/src/niscope/examples/niscope_multi_record.py index f6b1c466ac..116dfd1d7d 100644 --- a/src/niscope/examples/niscope_multi_record.py +++ b/src/niscope/examples/niscope_multi_record.py @@ -30,15 +30,15 @@ def example(resource_name, options, channel, vertical_range, min_sample_rate, mi import matplotlib.pyplot as plt with niscope.Session(resource_name=resource_name, options=options) as session: - session.configure_vertical(range=vertical_range, coupling=niscope.VerticalCoupling.DC) + session.channels[channel].configure_vertical(range=vertical_range, coupling=niscope.VerticalCoupling.DC) session.configure_horizontal_timing(min_sample_rate=min_sample_rate, min_num_pts=min_record_length, ref_position=50.0, num_records=num_records, enforce_realtime=True) - # Other trigger types (for example hysteresis or window) can be configured here; IMMEDIATE acquires without an input signal crossing the edge level. + # Configure the selected trigger here; add other trigger types to this block as needed. if trigger_type == 'EDGE': session.configure_trigger_edge(trigger_source='0', level=0.0, trigger_coupling=niscope.TriggerCoupling.DC, slope=niscope.TriggerSlope.POSITIVE) else: session.configure_trigger_immediate() with session.initiate(): - # Fetch waits for all records to be acquired and returns them all. + # Wait for num_records to be acquired, then return their waveforms. waveforms = session.channels[channel].fetch(num_records=num_records) figure = _plot_records(plt, waveforms, plot_style, plot_relative_to) From 750b9eaeca6706bad22062524e469268e73bac8b Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Mon, 2 Nov 2026 12:06:46 +0000 Subject: [PATCH 4/7] Removing graph plotting --- build/templates/tox-system_tests.ini.mako | 3 -- generated/niscope/tox-system_tests.ini | 1 - src/niscope/examples/niscope_multi_record.py | 43 +++----------------- 3 files changed, 6 insertions(+), 41 deletions(-) diff --git a/build/templates/tox-system_tests.ini.mako b/build/templates/tox-system_tests.ini.mako index 9c7f07cb3e..c2b3d9131d 100644 --- a/build/templates/tox-system_tests.ini.mako +++ b/build/templates/tox-system_tests.ini.mako @@ -76,9 +76,6 @@ deps = % endif % if module_name == 'nidigital': ${module_name}-system_tests: nisync -% endif -% if module_name == 'niscope': - ${module_name}-system_tests: matplotlib; sys_platform != "win32" % endif ${module_name}-system_tests: pytest ${module_name}-system_tests: coverage diff --git a/generated/niscope/tox-system_tests.ini b/generated/niscope/tox-system_tests.ini index afadc34815..2f232d27ab 100644 --- a/generated/niscope/tox-system_tests.ini +++ b/generated/niscope/tox-system_tests.ini @@ -39,7 +39,6 @@ commands = deps = niscope-wheel_dep: build - niscope-system_tests: matplotlib; sys_platform != "win32" niscope-system_tests: pytest niscope-system_tests: coverage niscope-system_tests: numpy diff --git a/src/niscope/examples/niscope_multi_record.py b/src/niscope/examples/niscope_multi_record.py index 116dfd1d7d..f960b982ed 100644 --- a/src/niscope/examples/niscope_multi_record.py +++ b/src/niscope/examples/niscope_multi_record.py @@ -2,33 +2,13 @@ import argparse import niscope -import pytest import sys -PLOT_STYLES = {'LINE': '-', 'POINTS': '.'} -PLOT_RELATIVE_TO = ('TRIGGER', 'ABSOLUTE') TRIGGER_TYPES = ('EDGE', 'IMMEDIATE') -def _plot_records(plt, waveforms, plot_style, plot_relative_to): - figure, axes = plt.subplots() - axes.set_title('Scope Multi Record') - axes.set_xlabel('Time relative to trigger (s)' if plot_relative_to == 'TRIGGER' else 'Absolute time (s)') - axes.set_ylabel('Amplitude (V)') - axes.grid(True) - for waveform in waveforms: - initial_x = waveform.relative_initial_x if plot_relative_to == 'TRIGGER' else waveform.absolute_initial_x - samples = waveform.samples.tolist() # samples is a memoryview, which matplotlib cannot plot - x = [initial_x + i * waveform.x_increment for i in range(len(samples))] - axes.plot(x, samples, PLOT_STYLES[plot_style], label=f'Record {waveform.record}') - axes.legend(loc='upper right') - return figure - - -def example(resource_name, options, channel, vertical_range, min_sample_rate, min_record_length, num_records, plot_style, plot_relative_to, - trigger_type): - import matplotlib.pyplot as plt - +def example(resource_name, options, channel, vertical_range, min_sample_rate, min_record_length, num_records, trigger_type): + print(f'Starting acquisition on resource {resource_name}, for {num_records} records.') with niscope.Session(resource_name=resource_name, options=options) as session: session.channels[channel].configure_vertical(range=vertical_range, coupling=niscope.VerticalCoupling.DC) session.configure_horizontal_timing(min_sample_rate=min_sample_rate, min_num_pts=min_record_length, ref_position=50.0, num_records=num_records, enforce_realtime=True) @@ -41,17 +21,12 @@ def example(resource_name, options, channel, vertical_range, min_sample_rate, mi # Wait for num_records to be acquired, then return their waveforms. waveforms = session.channels[channel].fetch(num_records=num_records) - figure = _plot_records(plt, waveforms, plot_style, plot_relative_to) - try: - if plt.fignum_exists(figure.number): - plt.show() - finally: - plt.close(figure) + print('Acquired {} records.'.format(len(waveforms))) return waveforms def _main(argsv): - parser = argparse.ArgumentParser(description='Acquires multiple triggered records from a channel and plots them.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser = argparse.ArgumentParser(description='Acquires multiple triggered records from a channel.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('-n', '--resource-name', default='PXI1Slot2', help='Specifies the resource name of the device to initialize.') parser.add_argument('-c', '--channel', default='0', help='Channel to use') parser.add_argument('-T', '--trigger-type', default='EDGE', choices=TRIGGER_TYPES, type=str.upper, help='EDGE configures the digitizer for edge triggering (channel 0, 0 V, DC coupling, rising slope). IMMEDIATE triggers as soon as the pretrigger samples are acquired.') @@ -59,11 +34,9 @@ def _main(argsv): parser.add_argument('-r', '--min-sample-rate', default=1e7, type=float, help='The sampling rate for the acquisition.') parser.add_argument('-N', '--num-records', default=2, type=int, help='The number of records to acquire') parser.add_argument('-l', '--min-record-length', default=256, type=int, help='The minimum number of points you need in the record for each channel.') - parser.add_argument('-R', '--plot-relative-to', default='TRIGGER', choices=PLOT_RELATIVE_TO, type=str.upper, help='Time reference for the plot; ABSOLUTE requires a device that supports absolute timestamps.') - parser.add_argument('-p', '--plot-style', default='POINTS', choices=PLOT_STYLES.keys(), type=str.upper, help='Plot the records as a continuous line or as individual points.') parser.add_argument('-op', '--option-string', default='', type=str, help='Specifies the initial value of certain properties for the session.') args = parser.parse_args(argsv) - example(args.resource_name, args.option_string, args.channel, args.vertical_range, args.min_sample_rate, args.min_record_length, args.num_records, args.plot_style, args.plot_relative_to, + example(args.resource_name, args.option_string, args.channel, args.vertical_range, args.min_sample_rate, args.min_record_length, args.num_records, args.trigger_type) @@ -72,16 +45,12 @@ def main(): def test_example(): - plt = pytest.importorskip('matplotlib.pyplot') - plt.switch_backend('Agg') # Avoid opening a chart window during the test options = {'simulate': True, 'driver_setup': {'Model': '5164', 'BoardType': 'PXIe', }, } - waveforms = example('PXI1Slot2', options, '0', 5.0, 1e7, 256, 3, 'POINTS', 'TRIGGER', 'EDGE') + waveforms = example('PXI1Slot2', options, '0', 5.0, 1e7, 256, 3, 'EDGE') assert len(waveforms) == 3 def test_main(): - plt = pytest.importorskip('matplotlib.pyplot') - plt.switch_backend('Agg') # Avoid opening a chart window during the test cmd_line = ['--option-string', 'Simulate=1, DriverSetup=Model:5164; BoardType:PXIe', '--num-records', '2', ] _main(cmd_line) From 5ff15cc9e36b661b2d5a1e2b4883e79b02153f63 Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Thu, 5 Nov 2026 15:45:42 +0000 Subject: [PATCH 5/7] Adding Source Waveform example in NI-Digital --- CHANGELOG.md | 1 + docs/nidigital/examples.rst | 9 ++ .../examples/source_waveform/Pattern.digipat | Bin 0 -> 5413 bytes .../source_waveform/PinLevels.digilevels | 15 +++ .../examples/source_waveform/PinMap.pinmap | 51 +++++++++ .../source_waveform/SourceWaveform.tdms | Bin 0 -> 1619 bytes .../source_waveform/Specifications.specs | 9 ++ .../source_waveform/Timing.digitiming | 23 ++++ .../nidigital_source_waveform.py | 100 ++++++++++++++++++ .../source_waveform/source_waveform.digiproj | 39 +++++++ 10 files changed, 247 insertions(+) create mode 100644 src/nidigital/examples/source_waveform/Pattern.digipat create mode 100644 src/nidigital/examples/source_waveform/PinLevels.digilevels create mode 100644 src/nidigital/examples/source_waveform/PinMap.pinmap create mode 100644 src/nidigital/examples/source_waveform/SourceWaveform.tdms create mode 100644 src/nidigital/examples/source_waveform/Specifications.specs create mode 100644 src/nidigital/examples/source_waveform/Timing.digitiming create mode 100644 src/nidigital/examples/source_waveform/nidigital_source_waveform.py create mode 100644 src/nidigital/examples/source_waveform/source_waveform.digiproj diff --git a/CHANGELOG.md b/CHANGELOG.md index 83d1d3267b..7fefe411b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -558,6 +558,7 @@ #### [nidigital] Unreleased - Added - (Common) Added `nitlsconfig[grpc]>=1.0.0a2` to the optional gRPC dependencies. + - Added the `nidigital_source_waveform.py` example. - Changed - Removed diff --git a/docs/nidigital/examples.rst b/docs/nidigital/examples.rst index b8c8cc689a..303dcff661 100644 --- a/docs/nidigital/examples.rst +++ b/docs/nidigital/examples.rst @@ -30,3 +30,12 @@ nidigital_ppmu_source_and_measure.py :encoding: utf8 :caption: `(nidigital_ppmu_source_and_measure.py) `_ +nidigital_source_waveform.py +---------------------------- + +.. literalinclude:: ../../src/nidigital/examples/source_waveform/nidigital_source_waveform.py + :language: python + :linenos: + :encoding: utf8 + :caption: `(nidigital_source_waveform.py) `_ + diff --git a/src/nidigital/examples/source_waveform/Pattern.digipat b/src/nidigital/examples/source_waveform/Pattern.digipat new file mode 100644 index 0000000000000000000000000000000000000000..0ee9d4fef983edd6c923bfa0c4eeb74e1a9f9bf2 GIT binary patch literal 5413 zcmcgwTXP#V6y9(x<&uWN3^Ux6;bDhPr*2vb<=zk%aGTOh?KV7-S=(}~va2<+T(@uG zjTv6~A^Zz|Ryp79IgXsz9dCj;6XjdW(sw>dM@L$>>dow>D2mLRQPd`c39isHO6@7x z3-o|ulT0hZm#OR|-fL%HrN^!wcAOb_lUsZXdy$GaJ}sJ~0)CQ_@8?e8BUvl(ezB~I z1gE^?L+BkYtsd_UN(CX$W#$n)#&ez;Y~|U&q`JFneE)%VLz0aFk)02@J}&Db!DC#n zQ3LLOCwZ7Vkf70tNsOIM@+B(~Jf`FWYH-I`lZ`SAF7c+F>bf(Jw3{B_N~lff1Q(;d z*)=|Y7VQ_TR`3|@`_!PGkL|uox_UQp*4X{KwwXNAQ)17pg<@qz1;P3Xm0J9xCK?wb zPEk20Ai?zpeT`T*gfKyLLtsp}YB5b?rmc_PqiRJ3O^(`gR58aJsz=uNy`gtBI>lYX z0c~)dAUvF#WM!|4N-< zf*^aFN-Y+$;^_yMj|NLzf7wiekn!#u8QgzNqil2*<_1R-R7u8@1Wr=7MP-7Tb`Av%bi?lf^sBM4?Bk8ny$MWHb^x-Ll+cnk_~!SJ*cqWL4A< zB4HePrIcMNUcTk#=w5MSh(~6aN=0&Q-VEs1={bzC!+kd=+@~CbiLS}4^?0mN4~yOrNCCy;L=|GfAp; z>2$5_Xu569jj7lfZ8$X`T;4H&@wBjS+4Zh-z*f zVFQPBSNMzY0H@$ literal 0 HcmV?d00001 diff --git a/src/nidigital/examples/source_waveform/PinLevels.digilevels b/src/nidigital/examples/source_waveform/PinLevels.digilevels new file mode 100644 index 0000000000..1908b117fa --- /dev/null +++ b/src/nidigital/examples/source_waveform/PinLevels.digilevels @@ -0,0 +1,15 @@ + + + + + + 0 + 3.3 + 0.8 + 2 + 0 + HighZ + + + + \ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/PinMap.pinmap b/src/nidigital/examples/source_waveform/PinMap.pinmap new file mode 100644 index 0000000000..46d985a9f9 --- /dev/null +++ b/src/nidigital/examples/source_waveform/PinMap.pinmap @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/SourceWaveform.tdms b/src/nidigital/examples/source_waveform/SourceWaveform.tdms new file mode 100644 index 0000000000000000000000000000000000000000..4f85ffcdff1deaa6c969a39131b2c23dc77153ea GIT binary patch literal 1619 zcmeHHO-sW-5RD&IL{L!CYi_yq<6_T-C{~CTQtdG;$=VJyA8fYv>Oa>vX%^N(iQ=^b z!`sg8yf?ee%p{1iBgb**0uE#|xQ8`+?+bQ_1$!pH-QL$8soQexlM{)z>w2n!!^{*zbxRh zN!h{f1?(=lZ=Sg4*rKsxin46R#R-UfRfseZm9|wzwT9yuY*E>`$@-ZdFqnmQ!BqdzGNJ6} bRs2T8V2cRmsr_7UQdP~Y?_g)p?RWd%nF`^h literal 0 HcmV?d00001 diff --git a/src/nidigital/examples/source_waveform/Specifications.specs b/src/nidigital/examples/source_waveform/Specifications.specs new file mode 100644 index 0000000000..65c615cfd6 --- /dev/null +++ b/src/nidigital/examples/source_waveform/Specifications.specs @@ -0,0 +1,9 @@ + + +
+ + 1 µs + +
+ +
\ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/Timing.digitiming b/src/nidigital/examples/source_waveform/Timing.digitiming new file mode 100644 index 0000000000..b5908eabfb --- /dev/null +++ b/src/nidigital/examples/source_waveform/Timing.digitiming @@ -0,0 +1,23 @@ + + + + + + timing.period + + + + 0 ns + timing.period / 2 + timing.period + + + (3 * timing.period) / 4 + + Pattern + + + + + + \ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/nidigital_source_waveform.py b/src/nidigital/examples/source_waveform/nidigital_source_waveform.py new file mode 100644 index 0000000000..266d731ca5 --- /dev/null +++ b/src/nidigital/examples/source_waveform/nidigital_source_waveform.py @@ -0,0 +1,100 @@ +#!/usr/bin/python + +import argparse +import nidigital +import os +import sys + + +def example(resource_name, options, source_waveform_type='PARALLEL', data_mapping='BROADCAST', waveform_name='new_waveform', start_label='new_pattern', + parallel_channel_list='PinGroup1', serial_channel_list='DUTPin1', sample_width=32, bit_order='MSB', waveform_file=None, write_waveform_data=True): + + with nidigital.Session(resource_name=resource_name, options=options) as session: + + dir = os.path.join(os.path.dirname(__file__)) + if waveform_file is None: + waveform_file = os.path.join(dir, 'SourceWaveform.tdms') + + session.load_pin_map(os.path.join(dir, 'PinMap.pinmap')) + + spec_filename = os.path.join(dir, 'Specifications.specs') + levels_filename = os.path.join(dir, 'PinLevels.digilevels') + timing_filename = os.path.join(dir, 'Timing.digitiming') + session.load_specifications_levels_and_timing(spec_filename, levels_filename, timing_filename) + + session.apply_levels_and_timing(levels_filename, timing_filename) + + session.load_pattern(os.path.join(dir, 'Pattern.digipat')) + + mapping = nidigital.SourceDataMapping[data_mapping] + + # Configure the source waveform type + if source_waveform_type == 'PARALLEL': + session.pins[parallel_channel_list].create_source_waveform_parallel(waveform_name, mapping) + elif source_waveform_type == 'SERIAL': + session.pins[serial_channel_list].create_source_waveform_serial(waveform_name, mapping, sample_width, nidigital.BitOrder[bit_order]) + elif source_waveform_type == 'TDMS': + # Waveform configuration and data are read from the TDMS file + session.create_source_waveform_from_file_tdms(waveform_name, waveform_file, write_waveform_data) + + # Write the source waveform data + if source_waveform_type != 'TDMS': + # Placeholder ramp data for illustration; replace with your own waveform samples + sample_count = 2 ** min(sample_width, 8) if source_waveform_type == 'SERIAL' else 256 + samples = [i % sample_count for i in range(sample_count)] + if mapping == nidigital.SourceDataMapping.BROADCAST: + session.write_source_waveform_broadcast(waveform_name, samples) + else: + # Site-unique data is a dict of site number to samples; both sites use the same placeholder data here + session.write_source_waveform_site_unique(waveform_name, {0: samples, 1: samples}) + + print('Start bursting pattern') + session.burst_pattern(start_label=start_label) + + session.selected_function = nidigital.SelectedFunction.DISCONNECT + print('Done bursting pattern') + + +def _main(argsv): + parser = argparse.ArgumentParser(description='Demonstrates how to configure, write, and burst a source waveform using NI-Digital source memory.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-n', '--resource-name', default='PXI1Slot2,PXI1Slot3', help='The specified resource name shown in Measurement & Automation Explorer (MAX) for a digital pattern instrument, for example, PXI1Slot3, where PXI1Slot3 is an instrument resource name.') + parser.add_argument('-s', '--simulate', default='True', choices=['True', 'False'], help='Whether to run on simulated hardware or real hardware') + parser.add_argument('-w', '--waveform-name', default='new_waveform', help='The name to assign to the waveform. Use the waveform_name with source_start opcode in your pattern.') + parser.add_argument('-l', '--start-label', default='new_pattern', help='Pattern name or exported pattern label from which to start bursting the pattern.') + parser.add_argument('-d', '--data-mapping', default='BROADCAST', choices=nidigital.SourceDataMapping.__members__.keys(), type=str.upper, help='Parameter that specifies how to map data on multiple sites.') + parser.add_argument('-t', '--source-waveform-type', default='PARALLEL', choices=['PARALLEL', 'SERIAL', 'TDMS'], type=str.upper, help='Type of source waveform to configure.') + parser.add_argument('--parallel-channel-list', default='PinGroup1', help='Pins that source data for a parallel waveform.') + parser.add_argument('--serial-channel-list', default='DUTPin1', help='Pins that source data for a serial waveform.') + parser.add_argument('--sample-width', default=32, type=int, help='Width in bits of each serial sample. Valid values are between 1 and 32.') + parser.add_argument('--bit-order', default='MSB', choices=nidigital.BitOrder.__members__.keys(), type=str.upper, help='Order in which to shift the bits.') + parser.add_argument('--waveform-file', default=None, help='Absolute file path to the load source waveform file (.tdms). Defaults to SourceWaveform.tdms next to this example.') + parser.add_argument('--write-waveform-data', default='True', choices=['True', 'False'], help='A Boolean that writes waveform data to source memory if True and the waveform data is in the file.') + args = parser.parse_args(argsv) + + example(args.resource_name, + 'Simulate=1, DriverSetup=Model:6571' if args.simulate == 'True' else '', + args.source_waveform_type, args.data_mapping, args.waveform_name, args.start_label, + args.parallel_channel_list, args.serial_channel_list, args.sample_width, args.bit_order, + args.waveform_file, args.write_waveform_data == 'True') + + +def main(): + _main(sys.argv[1:]) + + +def test_main(): + _main([]) + _main(['--source-waveform-type', 'SERIAL', '--data-mapping', 'SITE_UNIQUE']) + _main(['--source-waveform-type', 'TDMS']) + + +def test_example(): + resource_name = 'PXI1Slot2,PXI1Slot3' + options = {'simulate': True, 'driver_setup': {'Model': '6571'}, } + example(resource_name, options) + example(resource_name, options, 'SERIAL', 'SITE_UNIQUE') + example(resource_name, options, 'TDMS') + + +if __name__ == '__main__': + main() diff --git a/src/nidigital/examples/source_waveform/source_waveform.digiproj b/src/nidigital/examples/source_waveform/source_waveform.digiproj new file mode 100644 index 0000000000..971b8ff9b9 --- /dev/null +++ b/src/nidigital/examples/source_waveform/source_waveform.digiproj @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From b151b5e8b7604a4af3dfd2d50237b939146de0b8 Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Thu, 5 Nov 2026 15:46:25 +0000 Subject: [PATCH 6/7] Revert "Adding Source Waveform example in NI-Digital" This reverts commit 5ff15cc9e36b661b2d5a1e2b4883e79b02153f63. --- CHANGELOG.md | 1 - docs/nidigital/examples.rst | 9 -- .../examples/source_waveform/Pattern.digipat | Bin 5413 -> 0 bytes .../source_waveform/PinLevels.digilevels | 15 --- .../examples/source_waveform/PinMap.pinmap | 51 --------- .../source_waveform/SourceWaveform.tdms | Bin 1619 -> 0 bytes .../source_waveform/Specifications.specs | 9 -- .../source_waveform/Timing.digitiming | 23 ---- .../nidigital_source_waveform.py | 100 ------------------ .../source_waveform/source_waveform.digiproj | 39 ------- 10 files changed, 247 deletions(-) delete mode 100644 src/nidigital/examples/source_waveform/Pattern.digipat delete mode 100644 src/nidigital/examples/source_waveform/PinLevels.digilevels delete mode 100644 src/nidigital/examples/source_waveform/PinMap.pinmap delete mode 100644 src/nidigital/examples/source_waveform/SourceWaveform.tdms delete mode 100644 src/nidigital/examples/source_waveform/Specifications.specs delete mode 100644 src/nidigital/examples/source_waveform/Timing.digitiming delete mode 100644 src/nidigital/examples/source_waveform/nidigital_source_waveform.py delete mode 100644 src/nidigital/examples/source_waveform/source_waveform.digiproj diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fefe411b8..83d1d3267b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -558,7 +558,6 @@ #### [nidigital] Unreleased - Added - (Common) Added `nitlsconfig[grpc]>=1.0.0a2` to the optional gRPC dependencies. - - Added the `nidigital_source_waveform.py` example. - Changed - Removed diff --git a/docs/nidigital/examples.rst b/docs/nidigital/examples.rst index 303dcff661..b8c8cc689a 100644 --- a/docs/nidigital/examples.rst +++ b/docs/nidigital/examples.rst @@ -30,12 +30,3 @@ nidigital_ppmu_source_and_measure.py :encoding: utf8 :caption: `(nidigital_ppmu_source_and_measure.py) `_ -nidigital_source_waveform.py ----------------------------- - -.. literalinclude:: ../../src/nidigital/examples/source_waveform/nidigital_source_waveform.py - :language: python - :linenos: - :encoding: utf8 - :caption: `(nidigital_source_waveform.py) `_ - diff --git a/src/nidigital/examples/source_waveform/Pattern.digipat b/src/nidigital/examples/source_waveform/Pattern.digipat deleted file mode 100644 index 0ee9d4fef983edd6c923bfa0c4eeb74e1a9f9bf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5413 zcmcgwTXP#V6y9(x<&uWN3^Ux6;bDhPr*2vb<=zk%aGTOh?KV7-S=(}~va2<+T(@uG zjTv6~A^Zz|Ryp79IgXsz9dCj;6XjdW(sw>dM@L$>>dow>D2mLRQPd`c39isHO6@7x z3-o|ulT0hZm#OR|-fL%HrN^!wcAOb_lUsZXdy$GaJ}sJ~0)CQ_@8?e8BUvl(ezB~I z1gE^?L+BkYtsd_UN(CX$W#$n)#&ez;Y~|U&q`JFneE)%VLz0aFk)02@J}&Db!DC#n zQ3LLOCwZ7Vkf70tNsOIM@+B(~Jf`FWYH-I`lZ`SAF7c+F>bf(Jw3{B_N~lff1Q(;d z*)=|Y7VQ_TR`3|@`_!PGkL|uox_UQp*4X{KwwXNAQ)17pg<@qz1;P3Xm0J9xCK?wb zPEk20Ai?zpeT`T*gfKyLLtsp}YB5b?rmc_PqiRJ3O^(`gR58aJsz=uNy`gtBI>lYX z0c~)dAUvF#WM!|4N-< zf*^aFN-Y+$;^_yMj|NLzf7wiekn!#u8QgzNqil2*<_1R-R7u8@1Wr=7MP-7Tb`Av%bi?lf^sBM4?Bk8ny$MWHb^x-Ll+cnk_~!SJ*cqWL4A< zB4HePrIcMNUcTk#=w5MSh(~6aN=0&Q-VEs1={bzC!+kd=+@~CbiLS}4^?0mN4~yOrNCCy;L=|GfAp; z>2$5_Xu569jj7lfZ8$X`T;4H&@wBjS+4Zh-z*f zVFQPBSNMzY0H@$ diff --git a/src/nidigital/examples/source_waveform/PinLevels.digilevels b/src/nidigital/examples/source_waveform/PinLevels.digilevels deleted file mode 100644 index 1908b117fa..0000000000 --- a/src/nidigital/examples/source_waveform/PinLevels.digilevels +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - 0 - 3.3 - 0.8 - 2 - 0 - HighZ - - - - \ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/PinMap.pinmap b/src/nidigital/examples/source_waveform/PinMap.pinmap deleted file mode 100644 index 46d985a9f9..0000000000 --- a/src/nidigital/examples/source_waveform/PinMap.pinmap +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/SourceWaveform.tdms b/src/nidigital/examples/source_waveform/SourceWaveform.tdms deleted file mode 100644 index 4f85ffcdff1deaa6c969a39131b2c23dc77153ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1619 zcmeHHO-sW-5RD&IL{L!CYi_yq<6_T-C{~CTQtdG;$=VJyA8fYv>Oa>vX%^N(iQ=^b z!`sg8yf?ee%p{1iBgb**0uE#|xQ8`+?+bQ_1$!pH-QL$8soQexlM{)z>w2n!!^{*zbxRh zN!h{f1?(=lZ=Sg4*rKsxin46R#R-UfRfseZm9|wzwT9yuY*E>`$@-ZdFqnmQ!BqdzGNJ6} bRs2T8V2cRmsr_7UQdP~Y?_g)p?RWd%nF`^h diff --git a/src/nidigital/examples/source_waveform/Specifications.specs b/src/nidigital/examples/source_waveform/Specifications.specs deleted file mode 100644 index 65c615cfd6..0000000000 --- a/src/nidigital/examples/source_waveform/Specifications.specs +++ /dev/null @@ -1,9 +0,0 @@ - - -
- - 1 µs - -
- -
\ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/Timing.digitiming b/src/nidigital/examples/source_waveform/Timing.digitiming deleted file mode 100644 index b5908eabfb..0000000000 --- a/src/nidigital/examples/source_waveform/Timing.digitiming +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - timing.period - - - - 0 ns - timing.period / 2 - timing.period - - - (3 * timing.period) / 4 - - Pattern - - - - - - \ No newline at end of file diff --git a/src/nidigital/examples/source_waveform/nidigital_source_waveform.py b/src/nidigital/examples/source_waveform/nidigital_source_waveform.py deleted file mode 100644 index 266d731ca5..0000000000 --- a/src/nidigital/examples/source_waveform/nidigital_source_waveform.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/python - -import argparse -import nidigital -import os -import sys - - -def example(resource_name, options, source_waveform_type='PARALLEL', data_mapping='BROADCAST', waveform_name='new_waveform', start_label='new_pattern', - parallel_channel_list='PinGroup1', serial_channel_list='DUTPin1', sample_width=32, bit_order='MSB', waveform_file=None, write_waveform_data=True): - - with nidigital.Session(resource_name=resource_name, options=options) as session: - - dir = os.path.join(os.path.dirname(__file__)) - if waveform_file is None: - waveform_file = os.path.join(dir, 'SourceWaveform.tdms') - - session.load_pin_map(os.path.join(dir, 'PinMap.pinmap')) - - spec_filename = os.path.join(dir, 'Specifications.specs') - levels_filename = os.path.join(dir, 'PinLevels.digilevels') - timing_filename = os.path.join(dir, 'Timing.digitiming') - session.load_specifications_levels_and_timing(spec_filename, levels_filename, timing_filename) - - session.apply_levels_and_timing(levels_filename, timing_filename) - - session.load_pattern(os.path.join(dir, 'Pattern.digipat')) - - mapping = nidigital.SourceDataMapping[data_mapping] - - # Configure the source waveform type - if source_waveform_type == 'PARALLEL': - session.pins[parallel_channel_list].create_source_waveform_parallel(waveform_name, mapping) - elif source_waveform_type == 'SERIAL': - session.pins[serial_channel_list].create_source_waveform_serial(waveform_name, mapping, sample_width, nidigital.BitOrder[bit_order]) - elif source_waveform_type == 'TDMS': - # Waveform configuration and data are read from the TDMS file - session.create_source_waveform_from_file_tdms(waveform_name, waveform_file, write_waveform_data) - - # Write the source waveform data - if source_waveform_type != 'TDMS': - # Placeholder ramp data for illustration; replace with your own waveform samples - sample_count = 2 ** min(sample_width, 8) if source_waveform_type == 'SERIAL' else 256 - samples = [i % sample_count for i in range(sample_count)] - if mapping == nidigital.SourceDataMapping.BROADCAST: - session.write_source_waveform_broadcast(waveform_name, samples) - else: - # Site-unique data is a dict of site number to samples; both sites use the same placeholder data here - session.write_source_waveform_site_unique(waveform_name, {0: samples, 1: samples}) - - print('Start bursting pattern') - session.burst_pattern(start_label=start_label) - - session.selected_function = nidigital.SelectedFunction.DISCONNECT - print('Done bursting pattern') - - -def _main(argsv): - parser = argparse.ArgumentParser(description='Demonstrates how to configure, write, and burst a source waveform using NI-Digital source memory.', formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('-n', '--resource-name', default='PXI1Slot2,PXI1Slot3', help='The specified resource name shown in Measurement & Automation Explorer (MAX) for a digital pattern instrument, for example, PXI1Slot3, where PXI1Slot3 is an instrument resource name.') - parser.add_argument('-s', '--simulate', default='True', choices=['True', 'False'], help='Whether to run on simulated hardware or real hardware') - parser.add_argument('-w', '--waveform-name', default='new_waveform', help='The name to assign to the waveform. Use the waveform_name with source_start opcode in your pattern.') - parser.add_argument('-l', '--start-label', default='new_pattern', help='Pattern name or exported pattern label from which to start bursting the pattern.') - parser.add_argument('-d', '--data-mapping', default='BROADCAST', choices=nidigital.SourceDataMapping.__members__.keys(), type=str.upper, help='Parameter that specifies how to map data on multiple sites.') - parser.add_argument('-t', '--source-waveform-type', default='PARALLEL', choices=['PARALLEL', 'SERIAL', 'TDMS'], type=str.upper, help='Type of source waveform to configure.') - parser.add_argument('--parallel-channel-list', default='PinGroup1', help='Pins that source data for a parallel waveform.') - parser.add_argument('--serial-channel-list', default='DUTPin1', help='Pins that source data for a serial waveform.') - parser.add_argument('--sample-width', default=32, type=int, help='Width in bits of each serial sample. Valid values are between 1 and 32.') - parser.add_argument('--bit-order', default='MSB', choices=nidigital.BitOrder.__members__.keys(), type=str.upper, help='Order in which to shift the bits.') - parser.add_argument('--waveform-file', default=None, help='Absolute file path to the load source waveform file (.tdms). Defaults to SourceWaveform.tdms next to this example.') - parser.add_argument('--write-waveform-data', default='True', choices=['True', 'False'], help='A Boolean that writes waveform data to source memory if True and the waveform data is in the file.') - args = parser.parse_args(argsv) - - example(args.resource_name, - 'Simulate=1, DriverSetup=Model:6571' if args.simulate == 'True' else '', - args.source_waveform_type, args.data_mapping, args.waveform_name, args.start_label, - args.parallel_channel_list, args.serial_channel_list, args.sample_width, args.bit_order, - args.waveform_file, args.write_waveform_data == 'True') - - -def main(): - _main(sys.argv[1:]) - - -def test_main(): - _main([]) - _main(['--source-waveform-type', 'SERIAL', '--data-mapping', 'SITE_UNIQUE']) - _main(['--source-waveform-type', 'TDMS']) - - -def test_example(): - resource_name = 'PXI1Slot2,PXI1Slot3' - options = {'simulate': True, 'driver_setup': {'Model': '6571'}, } - example(resource_name, options) - example(resource_name, options, 'SERIAL', 'SITE_UNIQUE') - example(resource_name, options, 'TDMS') - - -if __name__ == '__main__': - main() diff --git a/src/nidigital/examples/source_waveform/source_waveform.digiproj b/src/nidigital/examples/source_waveform/source_waveform.digiproj deleted file mode 100644 index 971b8ff9b9..0000000000 --- a/src/nidigital/examples/source_waveform/source_waveform.digiproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 9d0efce902f86bfa577f97e2fa2642bcab805761 Mon Sep 17 00:00:00 2001 From: NI-velmurugan Date: Wed, 11 Nov 2026 14:35:43 +0000 Subject: [PATCH 7/7] Trigger CI build