SatNOGS-COMMS  4.1.0
A COMMS subsystem for CubeSats
Loading...
Searching...
No Matches
Adding Mission specific features

Classes

class  satnogs::comms::mission
 Mission specific generic callback service. More...

Detailed Description

SatNOGS-COMMS reference firmware can operate out-of-the-box without any modification. However, this has a little use. Every mission is unique and has its own needs/requirements. For this reason, the architecture of the SatNOGS-COMMS firmware has been designed to be easily expandable without the need of modifying the original codebase. This makes the code maintenance easier, and promoted contributions so the entire community can benefit.

General architecture

The project has been implemented in such a way so it can be imported from a mission specific code repository. We strongly propose to include the SatNOGS-COMMS repository as a git submodule. With this way you have a strict versioning control and you can easily track and contribute back possible enchantments or fixes.

The CMake build system exposes the codebase of the firmware as an INTERFACE library under the satnogs-comms-base target.

add_library(satnogs-comms-base INTERFACE)
target_sources(
  satnogs-comms-base
  INTERFACE # cmake-format: sortable
            src/bsp/bsp.cpp
            src/callbacks.cpp
            src/error_handler.cpp
            src/io.cpp
            src/io_wdg.cpp
            src/logger.cpp
            src/mission.cpp
            src/msg_arbiter.cpp
            src/settings.cpp
            src/startup.cpp
            src/telecommand.cpp
            src/telemetry.cpp
            src/tests/test.cpp
            src/time.cpp)

In a nutshell, this means that no compilation of the source files is performed. However, third party projects can import the project and use the satnogs-comms-base target to include in their codebase all the necessary files, include directories and compilation options dictated by the SatNOGS-COMMS reference Firmware.

Regardless the usage, all customization options and methods documented at Configuration and customization are still relevant. Of course, missions can define their custom devicetree overlays and configuration opitons and override or extend the existing, by using properly the EXTRA_DTC_OVERLAY_FILE and EXTRA_CONF_FILE environmental variables during the west Building and flashing the firmware.

In addition, the SatNOGS-COMMS reference Firmware provides several hooks/callbacks placed in strategically selected places of the codebase. Those hooks can significantly extend the capabilities of the existing codebase, with mission specific functionality, with minimal actions required by the user and zero modifications of the SatNOGS-COMMS reference Firmware. For more information please refer to the documentation of the mission class.

Define mission specific settings

SatNOGS-COMMS provides a set of persistent settings through the satnogs::comms::settings class. The settings are stored in the a dedicaed partition of the flash memory of the MCU. The underlying implementation is based on the Zephyr-RTOS settings subsystem which for the case of the board operates on the LittleFS filesystem.

The design of the settings class allows to define mission specific settings in a very easy and reliable way, utilizing C++ templates and compile time meta-programming. Users should define a special constxpr satnogs::comms::utils::hash_map static object with the mission specific settings. After that, the functionality of the satnogs::comms::settings class will be available without any further action.

A possible use case could be:

enum class custom_param : uint32_t
{
CUSTOM_SETTTING0,
CUSTOM_SETTTING1
};
custom_settings_map{
std::make_pair(custom_param::CUSTOM_SETTTING0,
sc::settings::param_info{"/lfs1/custom0", 0U}),
std::make_pair(
custom_param::CUSTOM_SETTTING1,
"/lfs1/custom1", 0.7f})};
.
.
.
auto &settings = sc::settings::get_instance();
settings.set<custom_param::CUSTOM_SETTTING1, custom_settings_map>(0.2f);
settings.reset<custom_param::CUSTOM_SETTTING0, custom_settings_map>();
auto x = settings.get<custom_param::CUSTOM_SETTTING1, custom_settings_map>();
static settings & get_instance()
Get a singleton access to the settings subsystem.
Definition settings.hpp:210
basic_param_info<> param_info
Definition settings.hpp:202
Compile-time hash-map (associative key-value container) that performs all operations in constexpr con...
Definition hash_map.hpp:66

How to import the firmware

The mission specific code repository should follow closely the Zephyr-RTOS application structure. Assuming that the SatNOGS-COMMS reference Firmware codebase is placed inside the root directory of the mission repository, the CMakeLists.txt should be something like:

cmake_minimum_required(VERSION 3.20)

# Set the board root to the SatNOGS-COMMS root directory
set(BOARD_ROOT "${CMAKE_CURRENT_LIST_DIR}/satnogs-comms")

# Include both the mission and SatNOGS-COMMS project configuration
set(CONF_FILE prj.conf "${CMAKE_CURRENT_SOURCE_DIR}/satnogs-comms/prj.conf")
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(
  phasma-tcnc-sw
  LANGUAGES C CXX
  VERSION 1.0.0)

set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED True)
set(CMAKE_CXX_STANDARD_REQUIRED True)

include(FetchContent)
FetchContent_Declare(
  satnogs-comms-base-fw SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/satnogs-comms"
                        BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/satnogs-comms")

# Tell the SatNOGS-COMMS build system that we are importing it
set(SATNOGS_COMMS_IMPORTED ON)
FetchContent_MakeAvailable(satnogs-comms-base-fw)

set(app_sources # cmake-format: sortable
                src/main.cpp)

target_sources(app PRIVATE ${app_sources})
target_link_libraries(app PRIVATE satnogs-comms-base)

Then initializing and starting the custom firmware expanded with mission specific code would be as easy as:

#include <mission.hpp>
#include <startup.hpp>
#include <zephyr/kernel.h>
void
post_init() {
// Do stuff
}
int
main(void)
{
// This should be the first call!
auto &startup = startup::get_instance();
auto &mission = mission::get_instance();
auto &err = error_handler::get_instance();
// Custom code here
// ....
// ...
// Register mission specific functionality
auto pinit = etl::delegate<void(void)>::create<post_init>();
mission.register_post_init(pinit);
startup.prepare();
// Custom code here
// ....
// ...
startup.start();
// Custom add threads, calls, etc
// ....
// ...
while (1) {
try {
task_wdt_feed(startup.wdg_id());
k_msleep(500);
} catch (const satnogs::comms::lib::exception &e) {
err.handle(e);
}
catch (std::exception &e) {
err.handle(e);
}
}
return 0;
}
comms::lib::leds & leds()
Returns a reference to the LEDs subsystem.
Definition board.cpp:124
static board & get_instance()
Gets a reference to the single instance of the Board interface class.
Definition board.cpp:66
Exception base class.
Definition exception.hpp:63
int main(void)
The main sequence to initialize the Satnogs-COMMS board.
Definition main.cpp:38