Adamant: A Soon-to-be Open Source, Mission-Critical Flight Software Framework Written in Ada

The challenge faced by flight software engineers at the Laboratory for Atmospheric and Space Physics (LASP) at the University of Colorado Boulder became evident when tasked with developing the onboard software for NASA’s new Climate Absolute Radiance and Refractivity Observatory (CLARREO) Pathfinder Reflected Solar mission. The goal of measuring Earth-reflected sunlight with an accuracy of 0.3 percent (k=1), surpassing existing sensors by five to tenfold, from an instrument mounted beneath the International Space Station (ISS), produced a complex set of requirements.

The avionics needed to balance multiple functions, including a high-rate control law, numerous hard real-time deadlines, interfaces with half a dozen external subsystems, and management of commands, telemetry and fault protection, all while capturing high-resolution science images at 15 frames per second. Ensuring uninterrupted operation within the unforgiving environment of low-Earth orbit necessitated the software run on a single Arm Cortex-M1 microprocessor instantiated at 50 megahertz (MHz) inside a radiation tolerant field-programmable gate array (FPGA) (Microchip RTG4), with only 4MB of RAM. The engineers quickly realized that existing flight software solutions at LASP were not equipped to handle this combination of hard real-time performance and heavy multitasking within such a constrained processing environment.

Flight software engineers at the Laboratory for Atmospheric and Space Physics at the University of Colorado Boulder were tasked with developing the onboard software for NASA’s new Climate Absolute Radiance and Refractivity Observatory (CLARREO) Pathfinder Reflected Solar mission. (Image: NASA)

To meet these challenges, LASP undertook the development of a new software framework with a focus on three core objectives: high performance, reliability, and reusability.

The framework needed to produce code that was not only efficient and deterministic but also capable of executing parallel to maximize performance on the sluggish computing platforms available for spacecraft. Required to sustain autonomous operation onboard the ISS for several years, the software needed to be high quality and free of defects. With future missions at LASP likely to demand even greater capabilities, the framework also needed to include a mechanism for effective transfer and reuse of flight-proven code from one mission to the next.

Developing Adamant

What was created is a component-based and model-driven framework called Adamant.

Prior to writing code, engineers employ a straightforward domain-specific modeling language to describe the architecture of their system. Architectures consists of a collection of tightly scoped components, each performing a specific function, that have no compile-time dependencies on one another. To maintain efficiency, components communicate with one another, point-to-point, through strongly typed “connectors.” Features are organized into components following the principle of separation of concerns. Mission-specific code is implemented in components distinct from those components intended to be reusable for future missions.

Adamant models not only describe components and their connections but also specify essential elements such as data types, commands, telemetry, unit tests, and requirements. From these models, rich and precise documentation is generated alongside the components’ structural code, guaranteeing an implementation that always adheres faithfully to the design. Left to the developers is the task of defining the software’s behavior by filling in designated subprograms with hand-written code. This paradigm has proven highly effective, with a remarkable 85 percent of the code for CLARREO generated from these models, leaving only 15 percent to be implemented by hand.

While the design of Adamant provides a well-defined pattern for direct code reuse, to achieve the goals of high performance and reliability, LASP engineers recognized the need to pair the framework with a programming language that aligned with these objectives. Although the majority of in-house flight software at LASP was coded in C or C++, the team began a trade study to explore alternatives. In particular, Ada was suggested by one senior engineer, even though it was unfamiliar to the rest of the team.

The Climate Absolute Radiance and Refractivity Observatory Pathfinder (CLARREO-PF) is an instrument payload that will measure reflected solar radiation at an unprecedented level of accuracy. (Image: NASA)

To facilitate thorough evaluation, prototypes of Adamant were implemented in both C++ and Ada. With a C++ background, the team was able to get up to speed and begin writing effective Ada within a few weeks. After a six month trial period, testing both systems in parallel, the team unanimously decided to embrace Ada for two compelling reasons.

First, Ada offers error prevention features not available in C++, which the developers enjoyed leveraging. Second, Ada includes a bare metal multi-tasking runtime, empowering the software to handle concurrent tasks without the need to manage, configure, and interface with a real-time operating system (RTOS).

What is Ada

The Ada programming language emerged in the 1970s as a response to the growing demand for a modular and hardware-independent language. Ada was designed to prioritize software correctness, which led to its widespread adoption for safety- critical systems during the 1980s and early 1990s. The language’s emphasis on readability, maintainability, and rigorous type checking made it an attractive choice, especially for industries where software failures could have disastrous consequences.

However, as time went on, the allure of new languages like C++ began to rise. These languages offered greater freedom and flexibility, compared to the strictness of Ada, and were more suitable for general-purpose programming, leading to their widespread adoption in various domains.

As a result, Ada gradually fell out of favor for most mainstream software development, which, surprisingly, includes the majority of flight software developed for NASA projects today. Languages like C++ try to stay out of the way of the programmer, trusting them to create correct code. This paradigm might work except that software developers, like all humans, make mistakes. So instead of using a language like Ada, NASA projects often augment their use of error-prone languages with cumbersome process, external static analyzers, and stringent coding standards. The advantage of an Ada-centric process lies in its ability to expose software defects at an early stage, without a host of external tools, because error detection features are implemented in the language itself.

To maintain efficiency, components communicate with one another, point-to-point, through strongly typed “connectors.” (Image: LASP)

Bugs are either prevented or spotted before the code is integrated into a larger system, where troubleshooting becomes much more costly.

Benefits of Ada

Ada derives its reliability first and foremost from its strong type system. In Ada, all types are incompatible by default. Type conversions are explicit and only allowed under specific conditions. Additionally, Ada’s types can be constrained to valid ranges (i.e., an integer that can only be assigned to values between 0 and 10). Variables are checked against these ranges both at compile-time and runtime. LASP engineers found the language to be strict, but also precise. They changed their approach to development. By applying careful thought to the design of types and abstractions prior to considering behavior, they were able to harness the Ada compiler to write well-defined, defect resistant code.

In Ada, errors that go undetected during compile time are instead checked dynamically at runtime. By default, this includes array index checks and variable range checks. The language also allowed LASP engineers to incorporate custom checking through “design by contract” mechanisms, such as preconditions, postconditions, and predicates. While runtime checks do impose a small performance penalty, they can be selectively disabled for high- performance code sections. These checks proved invaluable during the creation of Adamant, as numerous defects were uncovered early on during development.

Runtime checks are effective but imagine if these errors could instead be caught before the code is run. Ada can be elevated to this next level via SPARK. SPARK represents a subset of the Ada language that is specifically tailored for formal analysis. SPARK code can be analyzed at different levels, each offering an increasing degree of assurance, from guarantees that code is free of runtime errors to full verification of the key integrity properties of a program. LASP employed this technology to write the critical boot software for CLARREO. Not only was the algorithm proven free of runtime errors, it was also proven functionally correct, adhering to its intended design. Interestingly, this was accomplished by an engineer with no prior experience in formal proofs, highlighting the accessibility of SPARK.

The most compelling reason for choosing Ada as the implementation language for Adamant is its built-in, bare metal tasking system. Adamant requires a priority-preemptive task scheduler to manage concurrent operations, but does not need any of the other extraneous features provided by common real time operating systems. In Ada, concurrency is made possible by the language’s first-class support for tasking. Whether operating on Linux or a bare metal environment, the syntax and semantics remain the same. The Ada runtime is lightweight, and for Adamant, eliminates the need for a separate RTOS or its associated API calls.

Adamant utilizes runtimes that adhere to the Ravenscar profile. This committee-designed standard limits Ada’s tasking facilities to a subset qualified for safety-critical, hard real-time computing. The profile ensures a small memory footprint and offers efficient, deterministic execution of tasks, while eliminating issues such as deadlock and priority inversion.

Most importantly, the runtime is manageable in code size, allowing engineers to fully understand their entire stack from the bare metal up. In the domain of spacecraft flight software, reliability still stands as an unwavering necessity. Adamant, with its successful implementation on CLARREO, exemplifies the pivotal role that programming language choice plays in ensuring the success of a mission. Building on this success, LASP is proud to release Adamant open-source on GitHub  later this year. By embracing an open-source approach, Adamant opens the doors to wider collaboration, community contributions, and the exchange of best practices in the discipline of flight software.

This article was written by Kevin Dinkel, Professional Research Assistant, Laboratory for Atmospheric and Space Physics, University of Colorado Boulder. For more information, visit here  .