Facades and Backends
The SPARK SDK employs a facade-backend architecture to create an interface for the underlying hardware-specific implementations. This article outlines the roles of facades and backends and how to effectively work with them in the context of SPARK’s SDK.
Facades
Purpose and Design: Facades serve as interfaces for platform-specific features such as SPI communication, IRQ handling, timer functions, and context switching mechanisms. By encapsulating the functionality of low-level drivers within a single header file, the facade creates a cohesive API that can be seamlessly ported to various hardware platforms via their backends.
Usage Example: When using the SPARK Wireless Core library, the developer interacts solely with the facade interfaces which act as a gateway to the backend functionalities. This provides a consistent API, regardless of the underlying hardware.
Backends
Platform-specific Implementations: The backends are the implementations of the functionalities declared by the facades. They are written to cater to the specifics of the target platform, ensuring that the SPARK Cores and other components, such as the example apps and modules, can easily be ported to user-specific hardware.
Working with Facades and Backends
Developing Backends:
To support a new hardware platform, developers must implement the backend for each facade used by components included in the user project.
Implementations should adhere to the definitions provided by the facade interfaces.
Integrating with the Build System:
The build system should be configured to include the appropriate backend implementation files based on the target platform for which the application is being compiled.
Testing and Validation:
Each backend implementation must be tested to ensure that it conforms to the facade’s API.
Developers can utilize the BSP Validator tool to validate the correctness of the backend implementations for the SPARK Wireless Core.
By understanding and applying the facade-backend architecture, developers can create applications with the SPARK components that are portable across a multitude of hardware platforms.
List of Components with Facades
SDK Example Apps and Tools
Audio Bidirectional
Audio Unidirectional
Connection Priority
Fragmentation
Hello World
Hello World RTOS
Star Network
Datalink
BSP Validator
Cores
Pairing process
Wireless core
Audio core
Modules/Middleware
tinyUSB module Baremetal
tinyUSB module (RTOS)
Hello-World Porting Example
If a developer wishes to port the Hello-World example they will need to implement the backends for the application facade and its dependencies. In this instance, this involves implementing two backends: one for the Hello-World facade and another for the Wireless Core facade.
Each facade is located in its respective component under the facade/ folder. The backend implementation can be placed anywhere; it does not need to reside within the component folder. We recommend that developers create their backend implementations external to the SDK. Users can integrate their backends by adding their source files to the component_name_backend CMake library.
target_sources(hello_world_backend PRIVATE user_backend.c)
To add extra dependencies to the CMake library, like a user board support package, the user can link libraries.
target_link_libraries(hello_world_backend PRIVATE user_bsp)
In the SDK, SPARK has organized all backend implementations into a dedicated folder. This organization demonstrates that backend implementations do not need to be situated adjacently to their facade or code component. We advise users to refrain from adding code directly to the SDK package. Due to the CMake architecture and approach, the backend implementation can be seamlessly integrated into the SDK from the user’s code base.
CMake Architecture and Dependencies
Given that the creation of a user-specified top-level CMakeLists.txt file is encouraged, it is crucial to take into account the dependencies of the SDK’s underlying components. An overview of the CMake library architecture and build sequence within the SPARK SDK, which minimizes inter-dependencies between components, is provided below and is organized from the first to be included to the last:
SPARK Libraries and Third-Party Libraries: SPARK’s own libraries and those from third parties.
Driver: This layer includes all the drivers necessary for hardware interaction.
Board Support Package (BSP): This package provides all the necessary support for board-specific functions and initialization.
Middleware: Middleware components act as intermediaries, offering common services and features for higher-level software.
Core: The core layer contains essential libraries and frameworks that form the backbone of the SDK.
Modules: These are discrete functional units that provide specific capabilities or services within the system.
Applications: This final layer includes example applications, BSP-validator, demo, and other application-level projects.
The inclusion rules are structured such that each level can include and depend on components from lower levels, but must not include components from higher levels. This hierarchical structuring ensures clarity and minimizes dependency conflicts across the SDK.