-
-
August 26, 2025 at 7:40 am
Solution
ParticipantThe 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 APIset "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 therun()
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 callconnect()
, thenregister_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 tolocalhost: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 661SET_PARAMETER
for theSTRING
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 toA661_STRING
.Timing, loop rate, and not burning CPU
We set a
PERIOD = 0.020
(20 ms) constant, andsleep(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 likefrom 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.
-

Introducing Ansys Electronics Desktop on Ansys Cloud
The Watch & Learn video article provides an overview of cloud computing from Electronics Desktop and details the product licenses and subscriptions to ANSYS Cloud Service that are...

How to Create a Reflector for a Center High-Mounted Stop Lamp (CHMSL)
This video article demonstrates how to create a reflector for a center high-mounted stop lamp. Optical Part design in Ansys SPEOS enables the design and validation of multiple...

Introducing the GEKO Turbulence Model in Ansys Fluent
The GEKO (GEneralized K-Omega) turbulence model offers a flexible, robust, general-purpose approach to RANS turbulence modeling. Introducing 2 videos: Part 1 provides background information on the model and a...

Postprocessing on Ansys EnSight
This video demonstrates exporting data from Fluent in EnSight Case Gold format, and it reviews the basic postprocessing capabilities of EnSight.
- Scade One – Bridging the Gap between Model-Based Design and Traditional Programming
- Scade One – An Open Model-Based Ecosystem, Ready for MBSE
- Scade One – A Visual Coding Experience
- ARINC 661: the standard behind modern cockpit display systems
- How to Verify a Model on Host with SCADE Test? (Part 4 of 6)
- Using the SCADE Python APIs from your favorite IDE
- An introduction to DO-178C
- Introduction to the SCADE Environment (Part 1 of 5)
- How to integrate multiple SCADE models into one executable
- Scade One – Democratizing model-based development
© 2025 Copyright ANSYS, Inc. All rights reserved.