Project Overview
ATMs rely on the XFS (eXtension for Financial Services) device protocol, which abstracts the details of interacting with a wide range of hardware devices through a service-provider model. While XFS provides a unified API, its design and tooling make it practical to use only with C and C++, due to their direct access to low-level structures and Windows messaging mechanisms.
Motivation
Although C and C++ are suitable for interacting with XFS, building a full ATM controller in these languages posed several challenges:
-
Monolithic UI development was impractical, since modern UI frameworks were immature at the time, or too verbose and restrictive in C/C++.
-
Hiring and onboarding developers fluent in both C/C++ and the complexities of XFS was difficult and time-consuming.
-
XFS defined 20+ device categories, each with numerous structures and constants, making manula development error-prone and difficult to maintain.
-
Debugging was limited: developers often had to keep PDF specifications open on separate monitors and inspect opaque low-level structures that standard debuggers struggled to interpret.
To overcome these constraints, we needed a way to expose the XFS APIs to higher-level languages such as C# and Java, enabling use of modern UI frameworks like WPF (Windows Presentation Foundation) for building rich ATM interfaces.
Technical Approach
Developing this framework required extensive research and experimentation. A major challenge was that XFS relies heavily on the Windows Messaging API and WNDPROC callbacks, using message IDs above 1024. Earlier versions of .NET were unable to receive such messages, and even after the issue was fixed, the structures were still delivered as unmanaged pointers—making marshaling into C# extremely complex.
To solve this, instead of writing a pure C# wrapper (as in earlier versions), we implemented a C++/CLI (Managed C++) bridge that combined unmanaged and managed code in a single module. This allowed us to:
- Correctly receive XFS Windows messages
- Unmarshal low-level structures into managed equivalents
- Expose clean, high-level managed objects usable directly from C# or VB.NET. The final resulr included XML documents so all the info related to a struct was shown by the IDE to developers, removing the time consuming need to scroll up and down in the original documentation.
Automated Code Generation
XFS documentation follows a strict and consistent format. We leveraged this by building a tool that:
- Parsed the official XFS PDF documentation
- Extracted all device structures, constants, and APIs
- Generated configuration files containing the protocol metadata
- Used custom code generators to automatically produce:
- Managed wrappers
- Marshalling logic
- High-level APIs for each device category
With this metadata-driven approach, we also created an automated, exhaustive test suite ensuring reliability across the entire framework.
Simulators
To simplify development, we implemented device simulators for all XFS device types—including cash dispensers, card readers, printers, sensor units, and operator panels. Developers no longer needed physical ATMs; instead, they could run a full ATM stack locally with realistic device behavior.
Because our implementation adhered closely to the protocol, these simulators were highly representative of real hardware.
Impact
This framework was used not only internally but also sold to other companies working with ATM controllers and related financial devices. It significantly accelerated development workflows, improved testability, and enabled modern UI development on top of legacy device protocols.