diff --git a/examples/niscope/niscope_configured_acquisition/README.md b/examples/niscope/niscope_configured_acquisition/README.md
new file mode 100644
index 0000000..2aaf1ad
--- /dev/null
+++ b/examples/niscope/niscope_configured_acquisition/README.md
@@ -0,0 +1,23 @@
+Prerequisites
+===============
+Requires a Physical or Simulated Device. Refer to the [Getting Started Section](https://github.com/ni/nidaqmx-python/blob/master/README.rst) to learn how to create a simulated device. This example uses NI oscilloscopes and digitizers like the NI PXIe-5114
+
+## Sample
+
+This is an nipanel example that displays an interactive Streamlit app and updates and fetches data from an NI device.
+
+### Feature
+
+Script demonstrates how to configure vertical, horizontal, and triggering properties and allows you to experiment with numerous configurations, including acquisition types and triggering mode.
+- Supports various data types
+
+### Required Software
+
+- Python 3.9 or later
+
+### Usage
+
+```pwsh
+poetry install --with examples
+poetry run examples\niscope\niscope_configured_acquisition\niscope_configured_acquisition.py
+```
diff --git a/examples/niscope/niscope_configured_acquisition/niscope_configured_acquisition.py b/examples/niscope/niscope_configured_acquisition/niscope_configured_acquisition.py
new file mode 100644
index 0000000..c1f9695
--- /dev/null
+++ b/examples/niscope/niscope_configured_acquisition/niscope_configured_acquisition.py
@@ -0,0 +1,119 @@
+"""Continuously acquires waveforms from NI-SCOPE, and configures desired acquisition settings."""
+
+import time
+from pathlib import Path
+
+import hightime
+import niscope
+import numpy as np
+from niscope.errors import Error
+
+import nipanel
+
+panel_script_path = Path(__file__).with_name("niscope_configured_acquisition_panel.py")
+panel = nipanel.create_streamlit_panel(panel_script_path)
+
+panel.set_value("is_running", False)
+panel.set_value("run_button", False)
+
+try:
+ panel.set_value("scope_error", "")
+ print(f"Panel URL: {panel.panel_url}")
+ print(f"Waiting for the 'Run' button to be pressed...")
+ print(f"(Press Ctrl + C to quit)")
+ while True:
+ panel.set_value("run_button", False)
+ while not panel.get_value("run_button", False):
+ time.sleep(0.1)
+ with niscope.Session(resource_name=panel.get_value("resource_name", "Dev1")) as session:
+ session.configure_vertical(
+ range=panel.get_value("vertical_range", 5.0),
+ coupling=niscope.VerticalCoupling.DC,
+ offset=panel.get_value("vertical_offset", 0.0),
+ )
+ session.configure_chan_characteristics(
+ input_impedance=panel.get_value("input_impedance", 1.0e6),
+ max_input_frequency=panel.get_value("max_input_frequency", 100.0e6),
+ )
+ session.configure_horizontal_timing(
+ min_sample_rate=panel.get_value("min_sample_rate", 10.0e6),
+ min_num_pts=panel.get_value("min_record_length", 1000),
+ ref_position=panel.get_value("ref_position", 0.0),
+ num_records=1000,
+ enforce_realtime=panel.get_value("enforce_realtime", True),
+ )
+ trigger_type = int(panel.get_value("trigger_type", "1"))
+ if trigger_type == 1:
+ immediate = session.configure_trigger_immediate()
+ elif trigger_type == 2:
+ edge = session.configure_trigger_edge(
+ trigger_source=str(panel.get_value("edge_source", 0)),
+ level=panel.get_value("edge_level", 0.0),
+ slope=panel.get_value("edge_slope", niscope.TriggerSlope.POSITIVE),
+ trigger_coupling=panel.get_value("edge_coupling", niscope.TriggerCoupling.DC),
+ delay=hightime.timedelta(seconds=panel.get_value("trigger_delay", 0.0)),
+ )
+ elif trigger_type == 3:
+ digital = session.configure_trigger_digital(
+ trigger_source=panel.get_value("digital_source", "PFI 1"),
+ slope=panel.get_value("digital_slope", niscope.TriggerSlope.POSITIVE),
+ delay=hightime.timedelta(seconds=panel.get_value("trigger_delay", 0.0)),
+ )
+ elif trigger_type == 4:
+ window = session.configure_trigger_window(
+ trigger_source=str(panel.get_value("window_source", 0)),
+ window_mode=panel.get_value("window_mode", niscope.TriggerWindowMode.ENTERING),
+ low_level=panel.get_value("window_low_level", -0.1),
+ high_level=panel.get_value("window_high_level", 0.1),
+ trigger_coupling=panel.get_value("window_coupling", niscope.TriggerCoupling.DC),
+ delay=hightime.timedelta(seconds=panel.get_value("trigger_delay", 0.0)),
+ )
+ else:
+ hysteresis = session.configure_trigger_hysteresis(
+ trigger_source=str(panel.get_value("hysteresis_source", 0)),
+ level=panel.get_value("hysteresis_level", 0.0),
+ hysteresis=panel.get_value("hysteresis", 0.05),
+ slope=panel.get_value("hysteresis_slope", niscope.TriggerSlope.POSITIVE),
+ trigger_coupling=panel.get_value(
+ "hysteresis_coupling", niscope.TriggerCoupling.DC
+ ),
+ delay=hightime.timedelta(seconds=panel.get_value("trigger_delay", 0.0)),
+ )
+
+ with session.initiate():
+ wfm = np.array(
+ session.channels[panel.get_value("channel_number", 0)].fetch(
+ num_samples=1000,
+ num_records=1000,
+ relative_to=niscope.FetchRelativeTo.READ_POINTER,
+ offset=0,
+ timeout=hightime.timedelta(seconds=panel.get_value("timeout", 5.0)),
+ )
+ )
+ try:
+ panel.set_value("is_running", True)
+
+ panel.set_value("stop_button", False)
+ while not panel.get_value("stop_button", False):
+
+ for i in range(len(wfm)):
+ if panel.get_value("stop_button", True):
+ break
+ else:
+ data = wfm[i].samples.tolist()
+ panel.set_value("waveform_data", data)
+ panel.set_value("actual_record_length", session.horz_record_length)
+ panel.set_value("actual_sample_rate", session.samp_clk_timebase_rate)
+ panel.set_value("auto_triggered", session.trigger_auto_triggered)
+ except KeyboardInterrupt:
+ pass
+ finally:
+ panel.set_value("is_running", False)
+
+except Error as e:
+ scope_error = str(e)
+ print(scope_error)
+ panel.set_value("scope_error", scope_error)
+
+except KeyboardInterrupt:
+ pass
diff --git a/examples/niscope/niscope_configured_acquisition/niscope_configured_acquisition_panel.py b/examples/niscope/niscope_configured_acquisition/niscope_configured_acquisition_panel.py
new file mode 100644
index 0000000..d1b5e24
--- /dev/null
+++ b/examples/niscope/niscope_configured_acquisition/niscope_configured_acquisition_panel.py
@@ -0,0 +1,361 @@
+"""Streamlit dashboard for visualizing NI-SCOPE waveform data in real time."""
+
+from enum import Enum
+
+import extra_streamlit_components as stx # type: ignore[import-untyped]
+import niscope
+import streamlit as st
+from streamlit_echarts import st_echarts
+
+import nipanel
+from nipanel.controls import enum_selectbox
+
+
+class ChannelSource(Enum):
+ """Enum for channel source options."""
+
+ CHANNEL_0 = 0
+ CHANNEL_1 = 1
+ CHANNEL_2 = 2
+ CHANNEL_3 = 3
+ CHANNEL_4 = 4
+ CHANNEL_5 = 5
+ CHANNEL_6 = 6
+ CHANNEL_7 = 7
+
+
+st.set_page_config(page_title="NI-SCOPE EX Configured Acquisition", page_icon="📈", layout="wide")
+st.title("NI-SCOPE EX Configured Acquisition")
+panel = nipanel.get_streamlit_panel_accessor()
+
+left_col, right_col = st.columns(2)
+
+
+st.markdown(
+ """
+
+
+ """,
+ unsafe_allow_html=True,
+)
+
+with left_col:
+ with st.container(border=True):
+ if panel.get_value("is_running", False):
+ st.button(r"⏹️ Stop", key="stop_button")
+ elif not panel.get_value("is_running", False) and panel.get_value("scope_error", "") == "":
+ run_button = st.button(r"▶️ Run", key="run_button")
+ else:
+ st.error(
+ f"There was an error running the script. Fix the issue and re-run niscope_binary_acquisition.py \n\n {panel.get_value('scope_error', '')}"
+ )
+
+ st.text_input(
+ label="Resource Name",
+ value="Dev1",
+ disabled=panel.get_value("is_running", False),
+ key="resource_name",
+ )
+ st.number_input(
+ "Channel",
+ value=0,
+ step=1,
+ disabled=panel.get_value("is_running", False),
+ key="channel_number",
+ )
+ st.number_input(
+ "Timeout(s)",
+ value=5.00,
+ step=1.00,
+ disabled=panel.get_value("is_running", False),
+ key="timeout",
+ )
+
+ st.title("Vertical")
+ st.number_input(
+ "Vertical Range(V)",
+ value=5.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="vertical_range",
+ )
+ st.number_input(
+ "Probe Attenuation",
+ value=1.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="probe_attenuation",
+ )
+ st.number_input(
+ "Vertical Offset",
+ value=0.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="vertical_offset",
+ )
+ enum_selectbox(
+ panel,
+ label="Vertical Coupling",
+ value=niscope.VerticalCoupling.DC,
+ disabled=panel.get_value("is_running", False),
+ key="vertical_coupling",
+ )
+
+ st.title("Channel")
+ st.number_input(
+ "Max. Input Frequency(Hz)",
+ value=0.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="max_input_frequency",
+ )
+ st.number_input(
+ "Input Impedance",
+ value=1.0e6,
+ step=1000.0,
+ disabled=panel.get_value("is_running", False),
+ key="input_impedance",
+ )
+
+ st.title("Horizontal")
+ st.radio(
+ "Enforce Realtime",
+ options=[True, False],
+ disabled=panel.get_value("is_running", False),
+ key="enforce_realtime",
+ )
+
+ sample_rate = st.number_input(
+ "Min Sample Rate",
+ value=10000000.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="min_sample_rate",
+ )
+ st.number_input(
+ "Actual Sample Rate",
+ value=panel.get_value("actual_sample_rate", 1.0e7),
+ step=1.0,
+ disabled=True,
+ key="actual_sample_rate",
+ )
+ record_length = st.number_input(
+ "Min Record Length",
+ value=1000,
+ step=1,
+ disabled=panel.get_value("is_running", False),
+ key="min_record_length",
+ )
+ st.number_input(
+ "Actual Record Length",
+ value=panel.get_value("actual_record_length", 1000),
+ step=1,
+ disabled=True,
+ key="actual_record_length",
+ )
+
+
+with right_col:
+ with st.container(border=True):
+ st.title("Waveform Graph")
+ waveform_data = panel.get_value("waveform_data", [0.0])
+ waveform_graph = {
+ "animation": False,
+ "tooltip": {"trigger": "axis"},
+ "legend": {"data": ["Amplitude (V)"]},
+ "xAxis": {
+ "type": "category",
+ "data": [x / record_length for x in range(len(waveform_data))],
+ "name": "Time (s)",
+ "nameLocation": "center",
+ "nameGap": 40,
+ },
+ "yAxis": {
+ "type": "value",
+ "name": "Amplitude(V)",
+ "nameRotate": 90,
+ "nameLocation": "center",
+ "nameGap": 40,
+ },
+ "series": [
+ {
+ "name": "niscope data",
+ "type": "line",
+ "data": waveform_data,
+ "emphasis": {"focus": "series"},
+ "smooth": True,
+ "seriesLayoutBy": "row",
+ },
+ ],
+ }
+ st_echarts(options=waveform_graph, height="400px", width="75%", key="waveform_graph")
+ st.title("Trigger")
+ trigger_type = stx.tab_bar(
+ data=[
+ stx.TabBarItemData(id=1, title="Immediate", description=""),
+ stx.TabBarItemData(id=2, title="Edge", description=""),
+ stx.TabBarItemData(id=3, title="Digital", description=""),
+ stx.TabBarItemData(id=4, title="Window", description=""),
+ stx.TabBarItemData(id=5, title="Hysteresis", description=""),
+ ],
+ default=1,
+ )
+ panel.set_value("trigger_type", trigger_type)
+
+ if trigger_type == "1":
+ with st.container(border=True):
+ st.write(
+ "Note: When configured for Immediate reference trigger, this example does not configure any additional trigger settings - the acquisition is triggered as soon as possible after being initiated by driver software."
+ )
+ if trigger_type == "2":
+ with st.container(border=True):
+ st.selectbox(
+ "Trigger Source",
+ options=list(ChannelSource),
+ format_func=lambda x: f"Channel {x.value}",
+ disabled=panel.get_value("is_running", False),
+ key="edge_source",
+ )
+ st.number_input(
+ "Trigger Level",
+ value=0.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="edge_level",
+ )
+ enum_selectbox(
+ panel,
+ label="Trigger Slope",
+ value=niscope.TriggerSlope.POSITIVE,
+ disabled=panel.get_value("is_running", False),
+ key="edge_slope",
+ )
+ enum_selectbox(
+ panel,
+ label="Trigger Coupling",
+ value=niscope.TriggerCoupling.DC,
+ disabled=panel.get_value("is_running", False),
+ key="edge_coupling",
+ )
+ if trigger_type == "3":
+ with st.container(border=True):
+ st.text_input(
+ "Trigger Source",
+ value="PFI 1",
+ disabled=panel.get_value("is_running", False),
+ key="digital_source",
+ )
+ enum_selectbox(
+ panel,
+ label="Trigger Slope",
+ value=niscope.TriggerSlope.POSITIVE,
+ disabled=panel.get_value("is_running", False),
+ key="digital_slope",
+ )
+ if trigger_type == "4":
+ with st.container(border=True):
+ st.selectbox(
+ "Trigger Source",
+ options=list(ChannelSource),
+ format_func=lambda x: f"Channel {x.value}",
+ disabled=panel.get_value("is_running", False),
+ key="window_source",
+ )
+ enum_selectbox(
+ panel,
+ label="Window Mode",
+ value=niscope.TriggerWindowMode.ENTERING,
+ disabled=panel.get_value("is_running", False),
+ key="window_mode",
+ )
+ st.number_input(
+ "Window Low Level",
+ value=-0.1,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="window_low_level",
+ )
+ st.number_input(
+ "Window High Level",
+ value=0.1,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="window_high_level",
+ )
+ enum_selectbox(
+ panel,
+ label="Trigger Coupling",
+ value=niscope.TriggerCoupling.DC,
+ disabled=panel.get_value("is_running", False),
+ key="window_coupling",
+ )
+
+ if trigger_type == "5":
+ with st.container(border=True):
+ st.selectbox(
+ "Trigger Source",
+ options=list(ChannelSource),
+ format_func=lambda x: f"Channel {x.value}",
+ disabled=panel.get_value("is_running", False),
+ key="hysteresis_source",
+ )
+ st.number_input(
+ "Trigger Level",
+ value=0.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="hysteresis_trigger_level",
+ )
+ st.number_input(
+ "Hysteresis",
+ value=0.05,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="hysteresis",
+ )
+ enum_selectbox(
+ panel,
+ label="Trigger Slope",
+ value=niscope.TriggerSlope.POSITIVE,
+ disabled=panel.get_value("is_running", False),
+ key="hysteresis_slope",
+ )
+ enum_selectbox(
+ panel,
+ label="Trigger Coupling",
+ value=niscope.TriggerCoupling.DC,
+ disabled=panel.get_value("is_running", False),
+ key="hysteresis_coupling",
+ )
+ st.title("Common Trigger Settings")
+ st.number_input(
+ "Trigger Delay (s)",
+ value=0.0,
+ step=0.1,
+ disabled=panel.get_value("is_running", False),
+ key="trigger_delay",
+ )
+ st.number_input(
+ "Ref Position",
+ value=50.0,
+ step=1.0,
+ disabled=panel.get_value("is_running", False),
+ key="ref_position",
+ )
+ if panel.get_value("auto_triggered", False):
+ st.write("This acquisition is auto-triggered.")
+ else:
+ st.write("This acquisition is not auto-triggered.")