The Script Structure

A script for SignalShark is a Python file containing a class derived from ‘UsrScriptBase’. Thus, it can be recognized, displayed and executed by the Narda Script Launcher. It has the file extension ‘.py’.

It is recommended to create a new script based one of the available template files described in the section Script Templates of the file Cheat Sheet (Copy & Paste).

1
2
3
4
5
6
class MyUserScript(UsrScriptBase):
    """User script class"""

    def __init__(self, main_gui, dev=SignalSharkDev()):
        """Initialization. Please leave this line unchanged"""
        super().__init__(main_gui, dev, __file__)

Through this it can be recognized, displayed and executed by the Narda Script Launcher application.

A script for SignalShark consists at least of two methods:


def __init__(…:

1
2
3
def __init__(self, main_gui, dev=SignalSharkDev()):
    """Initialization. Please leave this code unchanged"""
    super().__init__(main_gui, dev, __file__)

This method contains the settings for the script button visualization in the Narda Script Launcher. Additionally all class variables should be initialized here.

Init method
self._tab_name:
Sets the name of the script category tab.
self._scr_title:
Sets the title text of the script button
self._scr_description:
Sets the description text of the script button
self._icon_path:
Here an icon path could be defined that is used to display a special script icon. If the path is not set, a default icon will be used.
self._list_prio:
Defines the position of the script button in the list. A value of 0 means that it is the first item.
self._nsl_executed_behavior:
This is an enum value, that defines the behavior of the Narda Script Launcher after the execution of the script.
  • NSL_Executed_Behaviors.MINIMIZE_NSL: The Narda Script Launcher application will be minimized.

  • NSL_Executed_Behaviors.SHOW_NSL: The Narda Script Launcher application will be shown.

  • NSL_Executed_Behaviors.CLOSE_NSL: The Narda Script Launcher application will be closed.

def _run_script(self, args):

1
2
3
4
5
def _run_script(self, args):
    """
    Script main function
    This method is called when a user clicks on the corresponding script button.
    """

This method is called, if a user taps on the corresponding script button. The actual script code should be placed here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def _run_script(self, args):
    """
    Script main function
    This method is called when a user clicks on the corresponding script button.
    """

    # Add your code here:
    # e.g. show a message box:
    self.MessageBoxModal('This is a wxPython messagebox.', 'MyUserScript',
                  wx.OK | wx.ICON_INFORMATION)

UsrScriptBase Class Members:

The base class UsrScriptBase supports some useful functions that allow an easy access to the SignalShark and to store configuration parameters.

self.signalshark:

The class member ‘self.signalshark’ allows easy access to the SignalShark device and offers functions to establish a connection and request device information.

For a detailed description of the field 'self.signalshark' see:

1
2
3
4
5
6
7
8
# Connect to device:
self.signalshark.connect()

# Get *IDN information:
idn = self.signalshark.device_info

# Disconnect from device:
self.signalshark.disconnect()

self.signalshark.scpi:

SignalShark supports the SCPI standard for remote controlled operation.

Standard Commands for Programmable Instruments (SCPI) is a standard that defines a syntax and command structure to remotely control measurement devices. The data exchange is text-based in ASCII format. For use in Python, data such as level or GNSS values must be converted from ASCII text to the corresponding Python data types.

The ‘nardascripting’ API takes care of the communication with the instrument and wraps most of the ASCII-based SignalShark SCPI commands to Python methods that also handle parsing and data type conversion.

The available commands are divided into groups for a better overview.

The field ‘scpi’ provides access to the different SCPI command groups and supports some additional helper functions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 # Connect to device:
 self.signalshark.connect()

 # Sends the SCPI command 'DISPlay:UNIT?' from the SCPI group display.
 self.signalshark.scpi.display.get_unit()

 # Helper function to check SCPI error queue.
 self.signalshark.scpi.check_error()

 # Disconnect from device:
 self.signalshark.disconnect()

For a detailed description of all supportet SCPI commands see: SCPI Command Reference.

self.config:

This class field can be used to load and store configuration values.

It is a python dictionary that will be stored to a json-file when the Narda Script Launcher is closing. The file name is the same as the module name and it will be stored into the modules folder.

When Narda Script Launcher is opened, the corresponding file will be loaded back to the dictionary.

With the method ‘self.config.get(key, default_value)’ you can request a value. If the key does not exist, it will take the provided default value.

1
2
3
4
5
6
7
my_value = self.config.get('my_value', 10)

new_value = my_value + 1

# By using 'self.config[key] =' you can save a value to the configuration dictionary.
# The key will be added if it not already exists.
self.config['my_value'] = new_value

self.ShowDlgModalTop(dlg) & self.frm_dlghelper:

Narda Script Launcher provides a wrapper function ‘self.ShowDlgModalTop(dlg)’ which ensures that the dialog always remains in the foreground.

Please use ‘self.frm_dlghelper’ as dialog parent and the wrapper function ‘self.ShowDlgModalTop(dlg)’ instead of ‘dlg.ShowModal()’!

1
2
3
4
5
6
# Ask the user to enter some text
dlg = wx.TextEntryDialog(self.frm_dlghelper, 'Enter some text', 'Caption')
dlg.SetValue('Default text')
if self.ShowDlgModalTop(dlg) == wx.ID_OK:
   print('You entered:' + dlg.GetValue())
dlg.Destroy()  # Please do not forget to destroy the created dialog if you do not need it anymore

For more information see: Dialog Code Snippets

Additional Multithreading Functions:

The template tmpusrscriptmthread.py contains some additional functions regarding multithreading.

mthread = MeasDlgThread(

An additional thread of type ‘MeasDlgThread’ can be used, to keep the GUI alive while executing the function ‘_run_measurement’ that is expected to take a considerable amount of time.

class nardascripting.base.measthread.MeasDlgThread(main_gui: nardascripting.base.gui.maingui.FrmMainBase, dlg: nardascripting.base.measthread.DataVisualizationDlg = None, callback=None, args=(), destroy_dlg: bool = True)

Base class for measurement thread with progress dialog synchronization

__init__(main_gui: nardascripting.base.gui.maingui.FrmMainBase, dlg: nardascripting.base.measthread.DataVisualizationDlg = None, callback=None, args=(), destroy_dlg: bool = True)

MeasDlgThread constructor.

Parameters
  • main_gui – The Narda Script Launcher main GUI (‘self.main_gui’).

  • dlg – An optional data visualization dialog based on class ‘DataVisualizationDlg’. If no value or None is provided, the default ProgressDlg will be used.

  • callback – The method ‘_run_measurement(‘ that is executed within a separate thread. Please rename the thread function call ‘MyUserScript._run_measurement’ according to your class name!

  • args – With ‘args=[param1, parm2, paramn]’ you can pass some optional parameters to the thread function ‘_run_measurement’.

  • destroy_dlg – Destroys the dialog after finishing the thread, if true. Default value is True.

1
2
3
4
5
6
7
8
 # Optional: Prepare some parameters for the measurement.
 measurement_steps = 10

 # Create an additional measurement thread to keep the GUI alive.
 # Please change 'MyUserScript._run_measurement' according to your class name.
 # With 'args=[param1, parm2, paramn]' you can pass some optional parameters to the measurement thread.
 mthread = MeasDlgThread(main_gui=self.main_gui, dlg=None, callback=MyUserScript._run_measurement,
                         args=[self.signalshark.addr, measurement_steps], destroy_dlg=True)

mthread.start_measurement()

The next line of code starts the measurement thread and shows a visualization (progress) dialog.

1
2
3
4
 # Start the measurement thread and show a visualization (progress) dialog.
 mthread.start_measurement()
 # The lines of code below will be executed after the measurement thread has done it's job.
 # ...

def _run_measurement(

You can place all time consuming code into the thread function ‘_run_measurement’.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 @staticmethod
 def _run_measurement(stopevent, update_progress, wait_for_stopevent,
                      signalshark_addr: str):
     """ Main method of the measurement thread that handles a time consuming measurement.

     Please do NOT use any wxPython elements like a MessageBox or a Dialog here!
     They are only permitted in the GUI thread ('_run_script' method).
     Please use the 'update_progress' method to display information!

     :param stopevent: Thread flag that indicates whether the procedure should be finished/cancelled
     :param update_progress: Delegate method to update a progress bar, message string and icon
     :param wait_for_stopevent: Delegate method to wait until stopevent is raised with possibility to show a message.
     :param signalshark_addr: Custom parameter to handover the ip address of the SignalShark
     :return:
     """

stopevent

From time to time it must be checked if the user clicked the Cancel button to cancel the task function. This can be achieved by querying the stop event status.

1
2
 if stopevent.isSet():
     return

update_progress

It is not allowed to access the GUI thread directly from a thread function, e.g. to display a message box. For this reason the thread function ‘_run_measurement’ offers the special parameter ‘update_progress’ which allows to show the user the current progress and messages. Furthermore, various buttons and icons can be displayed.

class nardascripting.base.measthread.MeasDlgThread(main_gui: nardascripting.base.gui.maingui.FrmMainBase, dlg: nardascripting.base.measthread.DataVisualizationDlg = None, callback=None, args=(), destroy_dlg: bool = True)

Base class for measurement thread with progress dialog synchronization

update_progress(msg=None, show_progress=True, progress: float = None, data=None, btn_style=None, icon_style=None, help_text: str = None, force_update: bool = False)

Sends data to the GUI thread and updates progressbar and message text

Parameters
  • msg (str) – A status message as string. None means no status text update.

  • show_progress (bool) – Flag indicating whether the progress bar is visible or not. True = visible.

  • progress (float) – Progress level in % as float. Value less than zero means marquee effect. None means no progress level update.

  • data – Measurement data for visualization.

  • btn_style – Button style flags to define the buttons to show (wx.ID_NONE, wx.OK, wx.CANCEL, wx.HELP)

  • icon_style – Icon style flags to define the icon to show (wx.ICON_NONE, wx.ICON_ERROR, wx.ICON_WARNING, wx.ICON_QUESTION, wx.ICON_INFORMATION, wx.ICON_EXCLAMATION, wx.ICON_HAND, …)

  • help_text (str) – Text that is displayed when the user presses the help button.

  • force_update (bool) – Force an update if True.

Returns

Returns True if the call was successful.

Return type

bool

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 # Display a message
 update_progress(msg='This is a message')

 # Show a progress bar
 update_progress(show_progress=True)

 # Update the current progress (e.g. to 50%)
 update_progress(progress=0.5)

 # Show a help button with detailed help information
 update_progress(help_text='Text that is displayed when the user presses the help button.')

 # Change the displayed buttons:
 update_progress(btn_style= wx.CANCEL | wx.HELP)

 # Change the displayed icons:
 update_progress(icon_style=wx.ICON_INFORMATION)

 # Handover some data to the dialog:
 # If the data is generated faster than the dialog can process it, the method returns False and discards the data.
 handled = update_progress(progress=act_progress, data=det_val)

 # You can force an update by setting the parameter 'force_update' to True:
 update_progress(msg='This is an important message', force_update=True)

The image below shows an example of the default data visualization dialog (‘ProgressDlg’) that can be controlled by the parameter ‘update_progress’:

Progress dialog

wait_for_stopevent

The parameter ‘wait_for_stopevent’ allows it to display a message to the user and wait until the user has pressed a button.

class nardascripting.base.measthread.MeasDlgThread(main_gui: nardascripting.base.gui.maingui.FrmMainBase, dlg: nardascripting.base.measthread.DataVisualizationDlg = None, callback=None, args=(), destroy_dlg: bool = True)

Base class for measurement thread with progress dialog synchronization

wait_for_stopevent(msg: str = 'Unknown.', btn_style=16, icon_style=2048, help_text: str = None, timeout_s: int = None)

Shows a message text and waits for user to click “exit” button.

Parameters
  • msg (str) – The message to display.

  • btn_style – Button style flags to define the buttons to show (wx.ID_NONE, wx.OK, wx.CANCEL, wx.HELP)

  • icon_style – Icon style flags to define the icon to show (wx.ICON_NONE, wx.ICON_ERROR, wx.ICON_WARNING, wx.ICON_QUESTION, wx.ICON_INFORMATION, wx.ICON_EXCLAMATION, wx.ICON_HAND, …)

  • help_text (str) – Text that is displayed when the user presses the help button.

  • timeout_s (int) – An optional timeout time in seconds.

Returns

None

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 @staticmethod
 def _run_measurement(stopevent, update_progress, wait_for_stopevent,
                      signalshark_addr: str):
     """ Main method of the measurement thread that handles a time consuming measurement.

     Please do NOT use any wxPython elements like a MessageBox or a Dialog here!
     They are only permitted in the GUI thread ('_run_script' method).
     Please use the 'update_progress' method to display information!

     :param stopevent: Thread flag that indicates whether the procedure should be finished/cancelled
     :param update_progress: Delegate method to update a progress bar, message string and icon
     :param wait_for_stopevent: Delegate method to wait until stopevent is raised with possibility to show a message.
     :param signalshark_addr: Custom parameter to handover the ip address of the SignalShark
     :return: Optional custom parameter
     """
     # Setup connection to the SignalShark and display error message if connection fails.
     signalshark = SignalSharkDev(signalshark_addr)
     if not signalshark.connect():
         return wait_for_stopevent(msg='Cannot connect to the device!', icon_style=wx.ICON_ERROR)  # Returns None

     try:
         # Do some measurement stuff
         #...

         wait_for_stopevent('Measurement done!')
     except Exception as e:
         # Do some error handling
         return wait_for_stopevent(str(e), icon_style=wx.ICON_ERROR)  # Returns None
     finally:
         # Close connection.
         signalshark.disconnect()

return

With the keyword return, the thread function can be terminated and optionally parameters can be returned to ‘_run_script’.

1
 return calculated_value