Embedded Software

Embedded Software

Writing a Python User Application for the SCADE ARINC 661 server

Tagged: ARINC 661, CDS, DF, SCADE, TAF, UA

    • SolutionSolution
      Participant



      The ARINC 661 standard specifies a software architecture for modular, upgradeable airplane cockpits. The standard specifies how the Cockpit Display System (CDS) and its User Applications (UA) work and communicate via a dedicated communication protocol. While the CDS renders widgets and handles low-level interaction, the UA manages the logic — sending commands, reacting to events, and driving the interface dynamically.

      Note: This article assumes familiarity with the ARINC 661 standard. If you need a refresher, you may want to start with this previous article.

      In this article, we’ll look at a development use case: creating a Python-based UA for the SCADE ARINC 661 server.

      Production-grade UAs must be certified as flight software under DO-178C and are typically developed with safety-critical tools such as Ansys SCADE Suite. However, while a UA is under development, it can be useful to create a mock-up / stub / prototype of its behavior. For instance, this can enable early integration testing of the Cockpit Display System. In such a case, using Python is a quick and easy way to create a functional prototype with minimal effort.

      To create our Python UA, we will use a component of SCADE called the Test Automation Framework. Initially developed to enable automated testing of ARINC 661 widgets, this component includes a comprehensive API over ARINC 661 Widgets. It also contains a Server Control Proxy API which allows orchestrating the execution of the CDS and its UAs, as well as observing their state at each step.

      Our approach today will cover:

      • Understanding the required API concepts
      • Creating the DF (Definition File) in SCADE UA Page Creator
      • Setting up the Python environment with the local SCADE installation
      • Writing the UA logic in Python
      • Running and testing it with the SCADE ARINC 661 Server

      Key API concepts

      The SCADE ARINC 661 ecosystem separates graphical rendering (CDS server) from logic execution (UA). Communication between both is enabled by the ARINC 661 protocol — messages about widget states, parameter changes, and user interactions.

      The SCADE ARINC 661 Widgets API abstracts the protocol details into Python classes:

      • Each widget type (Label, PushButton, Slider, etc.) becomes a Python class.
      • You create widget objects, set parameters, and send events without manually encoding binary messages.
      • Incoming notifications from the server are automatically parsed into meaningful Python objects.

      This API is your bridge between ARINC 661 binary protocol and readable Python code — you focus on “what to do” instead of “how to encode it.”

      The Python API also provides other services, such as classes to interact with UAs, functions to encode/decode ARINC 661 messages, as well as the Server Control Proxy, a service that allows interacting with / observing / piloting the server using Python calls.

      You may find a comprehensive documentation of all these Python classes here in our online docs.

      Creating the Definition File (DF) in SCADE UA Page Creator

      An ARINC 661 DF describes the graphical page corresponding to the UA. It is composed of ARINC 661 widgets and includes, for each one, IDs, types and layout information.

      For the sake of simplicity, we will build a small DF: a label displaying the current time, and a button that updates the time value when clicked. Each update triggers a round-trip between the CDS, which detects the click, and the UA, which queries current time and sends it back.

      In SCADE UA Page Creator, we’ll first create a new UA page and assign it a UA ID (arbitrarily, 1). Then, we’ll add the following widgets:

      • Label (Widget ID 1) – static text – LabelString=Current Time
      • Label (Widget ID 2) – time display – LabelString=13:37:00
      • PushButton (Widget ID 3) – trigger to update the time – LabelString=Update Time

      Finally, we position our widgets as follows on the design surface:



      We can now save our project and generate the binary DF using the “DF Generation” generation configuration.

      Setting up the Python environment

      SCADE comes with its own Python distribution and the Test Automation Framework component.

      1. Locate the Python install provided with SCADE

      %SCADE_INSTALL%\SCADE\contrib\Python310
      

      2. Create and activate a virtual environment using SCADE’s Python

      cd my_project
      "%SCADE_INSTALL%\SCADE\contrib\Python310\python" -m venv .venv
      .venv\Scripts\activate
      

      Note: A venv is not required here but it is good practice to operate in one for repeatability.

      3. Set the PYTHONPATH so your UA can import the SCADE and ARINC 661 Widgets API

      set "PYTHONPATH=%SCADE_INSTALL%\SCADE A661\PythonLib;%SCADE_INSTALL%\SCADE\APIs\Python\lib"
      

      Writing the Python UA logic prototype

      It is now time to write our UA logic prototype. For our simple application, we want our Python script to:

      • Launch a SCADE CDS server as a background process
      • Parse the DF and build a Python representation of its contents
      • Connect to the server as UA 1
      • Start an infinite polling loop

      In the polling loop, we want to:

      • Receive notifications coming from the CDS
      • Determine whether the “Update Time” PushButton has been clicked
      • If so, read the current time into a string and send it back to be displayed by the target Label

      Note: for the sake of convenience, we mix, in the same Python script, the prototype logic of our UA with start-up instructions for the CDS server. This allows us to launch everything from a self-contained piece of code. Alternatively, we could choose to start the CDS and our UA prototype in separate terminals.

      Initializing the API

      We start our script by calling Standard_rev9_v1(). It selects the generated ARINC 661 Widgets API that matches the server’s ARINC 661 supplement and widget library version.

      Starting the CDS server

      Then, we instantiate a Server object and call the run() method on it. This ensures we have a CDS to connect to with our prototype UA.

      Parsing the DF and connecting as a UA

      Then, we call taf.a661libutil.create_df_from_sgfx() on the SCADE .sgfx file representing our DF. This automatically parses the DF and creates a tree of Python objects matching its contents: ARINC 661 layers, widgets, and their parameters. These classes include typed helpers to build ARINC 661 messages without hand-encoding bytes.

      We then proceed to create a UA object and call connect(), then register_df() on it to establish a link with the server.

      Notes:

      • The UA class is central to the SCADE ARINC 661 Python library. All communication with the server is done through it: connection and runtime communication via messages and notifications.
      • ua1.connect() defaults to localhost:1230 (TCP) unless you override it; that’s the default port for UA 1.

      Polling loop

      Once connected, we poll notifications with ua1.get_notifications(), which returns a list of dictionaries like:

      {
        "kind": "A661_NOTIFY_WIDGET_EVENT",
        "widget_id": 3,
        "notif": <event object with .name etc.>
        # ...plus app_id/layer_id/context
      }
      

      These keys/structures are standardized by the framework, so you don’t parse raw bytes. You filter what you care about (e.g., a “Selection” event on a PushButton) and react.

      In our script, we want to watch for:

      • kind == 'A661_NOTIFY_WIDGET_EVENT'
      • widget_id == pushButton.get_wid()
      • notif.name == 'A661_EVT_SELECTION'

      When that happens, we send a block to update our target’s string: target_label.string("...") creates an ARINC 661 SET_PARAMETER for the STRING parameter; ua1.send_block(...) pushes it to the server.

      Note: Helper method names match the ARINC 661 parameter (without the A661_ prefix, lowercase). So, .string() maps to A661_STRING.

      Timing, loop rate, and not burning CPU

      We set a PERIOD = 0.020 (20 ms) constant, and sleep(PERIOD) at the end of each loop. This is a nice compromise: low latency for UI interactions without busy-waiting. For a chattier system, we’d add a tiny queue or backoff mechanism, but we don’t need those in our simple example.

      Note: If you need deterministic coupling of your UA and server steps, you can use the Server Control Proxy component to drive steps from Python. For today’s example, a simple polling loop is fine.

      Common pitfalls (so you don’t trip)

      • Mismatched rev/version → wrong module imported or wrong Standard_revX_vY() initializer. Always match the server build.
      • Forgot to register_df(df) → you’ll still receive events, but decoding lacks widget typing; notification checks may look odd.
      • PYTHONPATH not set → imports like from taf.a661libgen_rev6_v1 import ... fail. Ensure your venv sees %SCADE_INSTALL%\SCADE A661\PythonLib and %SCADE_INSTALL%\SCADE\APIs\Python\lib.
      • Encoding → if your DF uses a non-ASCII charset (e.g., UTF-8), initialize the standard with that, e.g. Standard_rev9_v1('utf-8') so that string parameters encode correctly.

      Putting it all together

      Below is our complete UA script, a clean, minimal UA. It’s a kind of “hello world” (or rather “what time is it?”) example for Python UA prototyping.

      """Minimal script prototyping the logic of an ARINC 661 User Application (UA)."""
      
      import datetime
      import os
      from pathlib import Path
      from time import sleep
      
      from taf.a661libgen_rev9_v1 import UA, Server, Standard_rev9_v1
      import taf.a661libutil
      
      # Initialize SCADE ARINC 661 Widget API and constants
      Standard_rev9_v1()
      PERIOD = 0.020  # in seconds
      SCADE_INSTALL = os.getenv("SCADE_INSTALL")
      if not Path(SCADE_INSTALL).exists():
          print(f"Invalid SCADE installation path, exiting.\nPath is: {SCADE_INSTALL}")
          exit(code=1)
      
      # Start a SCADE CDS server as a background task
      cds = Server(
          exe=f"{SCADE_INSTALL}/SCADE A661/bin/A661Server.exe",
          df_list=["graphics/DF/UA_1.bin"],
      )
      cds.run(debug="all")
      
      # Parse DF and connect to the server as UA 1
      df_from_sgfx = taf.a661libutil.create_df_from_sgfx(
          sgfx_path="graphics/UADF.sgfx",
          a661_path=f"{SCADE_INSTALL}/SCADE A661/server/a661_description/a661.xml",
      )
      ua1 = UA(ua_id=1).connect()
      ua1.register_df(df_object=df_from_sgfx)
      
      # Start polling loop
      pushbutton = ua1.get_widget(layer_id=1, widget_id=3)
      target_label = ua1.get_widget(layer_id=1, widget_id=2)
      while True:
          notifs = ua1.get_notifications()
          if notifs:
              for notif in notifs:
                  if (
                      notif["kind"] == "A661_NOTIFY_WIDGET_EVENT"
                      and notif["widget_id"] == pushbutton.get_wid()
                      and notif["notif"].name == "A661_EVT_SELECTION"
                  ):
                      now = datetime.datetime.now()
                      ua1.send_block(target_label.string(now.strftime("%H:%M:%S")))
          sleep(PERIOD)
      

      Testing the UA

      We are finally ready to run everything on our local machine: the SCADE CDS with our DF loaded and our Python UA.

      .venv\Scripts\activate
      set "PYTHONPATH=%SCADE_INSTALL%\SCADE A661\PythonLib;%SCADE_INSTALL%\SCADE\APIs\Python\lib"
      python logic\UA.py
      

      When interacting with the PushButton in the server display window, Label 2 should update with the current time.

      Here is a video showcasing our complete example:

      Explore further

      In this article, we saw how to quickly build lightweight prototypes of ARINC 661 User Application logic, by leveraging the SCADE ARINC 661 Test Automation Framework component and its Python API.

      This enables CDS activities, such as integration testing, to proceed while User Applications are not yet fully developed.

      If you have a SCADE license and wish to experiment, you may download this article’s example model here (or browse its sources).

      If you’d like to learn more about Ansys SCADE Solutions for ARINC 661 Compliant Systems, we’d love to hear from you! Get in touch on our product page.

      About the author



      Ludovic Oddos (LinkedIn) is a Lead Product Specialist at Ansys. He has been supporting SCADE field engagements, in many industries, for more than 15 years. He has deep expertise in embedded software and its integration into various target environments.