Add integration startup service and fix Doxygen (fw 0.8.1).

Replace the services stub with IntegrationService for boot preset recall and tune orchestration, persist last preset in NVS, and remove invalid @return tags that broke CI on T4 metadata headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 00:17:13 +02:00
co-authored by Cursor
parent 0fc714e431
commit d13012ce4b
24 changed files with 858 additions and 92 deletions
@@ -1,6 +1,8 @@
idf_component_register(
SRCS "src/component_stub.cpp"
SRCS
"src/IntegrationService.cpp"
INCLUDE_DIRS "include"
REQUIRES core tuner audio station
)
target_compile_features(${COMPONENT_LIB} PUBLIC cxx_std_23)
@@ -0,0 +1,132 @@
/**
* @file IntegrationService.hpp
* @brief Orchestrates tuner, audio, and preset recall for app_main.
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* @author Michele Bigi
* @date 2026-07-06
*/
#pragma once
#include "audio/AudioService.hpp"
#include "core/IntegrationError.hpp"
#include "core/ISecureStore.hpp"
#include "station/StationService.hpp"
#include "tuner/TunerService.hpp"
#include <cstddef>
#include <expected>
namespace integration {
/**
* @brief IntegrationService — end-to-end radio listening orchestration.
*
* @dname IntegrationService
* @return n/a (type)
* @pubstate Borrows store, tuner, audio, and stations for process lifetime.
* Called from app_main for startup and from HTTP for preset recall.
*
* @author Michele Bigi
* @date 2026-07-06
*/
class IntegrationService {
public:
/**
* @brief IntegrationService — bind application services.
*
* @dname IntegrationService
* @param store Secure persistence for presets and last recall index.
* @param tuner Tuner orchestration.
* @param audio ADAU1701 profile orchestration.
* @param stations Preset list CRUD and tune delegation.
* @pubstate stores references; no side effects until startup().
*
* @author Michele Bigi
* @date 2026-07-06
*/
IntegrationService(core::ISecureStore& store,
tuner::TunerService& tuner,
audio::AudioService& audio,
station::StationService& stations);
/**
* @brief startup — load presets and recall the last station if stored.
*
* @dname startup
* @return Ok on success, or IntegrationError when recall fails.
* @pubstate loads station list; may tune and refresh the audio profile.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::IntegrationError> startup();
/**
* @brief recallPreset — tune a preset and apply the saved audio profile.
*
* @dname recallPreset
* @param index Zero-based preset list position.
* @return Ok on success, or IntegrationError.
* @pubstate tunes via StationService, safeloads AudioProfile, persists index.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::IntegrationError> recallPreset(
std::size_t index);
/**
* @brief stations — access the preset list service.
*
* @dname stations
* @return Reference to the injected StationService.
* @pubstate reads stations_.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] station::StationService& stations() noexcept;
/**
* @brief tuner — access the tuner service.
*
* @dname tuner
* @return Reference to the injected TunerService.
* @pubstate reads tuner_.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] tuner::TunerService& tuner() noexcept;
/**
* @brief audio — access the audio service.
*
* @dname audio
* @return Reference to the injected AudioService.
* @pubstate reads audio_.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] audio::AudioService& audio() noexcept;
private:
[[nodiscard]] std::expected<void, core::IntegrationError>
applyStoredAudioProfile();
[[nodiscard]] std::expected<void, core::StoreError> persistLastPreset(
std::size_t index);
core::ISecureStore& store_;
tuner::TunerService& tuner_;
audio::AudioService& audio_;
station::StationService& stations_;
};
} // namespace integration
@@ -0,0 +1,109 @@
/**
* @file IntegrationService.cpp
* @brief IntegrationService implementation.
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* @author Michele Bigi
* @date 2026-07-06
*/
#include "integration/IntegrationService.hpp"
namespace integration {
IntegrationService::IntegrationService(core::ISecureStore& store,
tuner::TunerService& tuner,
audio::AudioService& audio,
station::StationService& stations)
: store_(store)
, tuner_(tuner)
, audio_(audio)
, stations_(stations)
{
}
std::expected<void, core::IntegrationError> IntegrationService::startup()
{
if (auto loaded = stations_.loadFromStore(); !loaded) {
return std::unexpected(core::IntegrationError::StoreFailed);
}
if (!store_.hasLastPresetIndex()) {
return {};
}
const auto index = store_.loadLastPresetIndex();
if (!index) {
return std::unexpected(core::IntegrationError::StoreFailed);
}
if (*index >= stations_.list().stations().size()) {
(void)store_.clearLastPresetIndex();
return {};
}
(void)recallPreset(*index);
return {};
}
std::expected<void, core::IntegrationError> IntegrationService::recallPreset(
std::size_t index)
{
if (index >= stations_.list().stations().size()) {
return std::unexpected(core::IntegrationError::PresetNotFound);
}
if (auto tuned = stations_.tuneToIndex(index); !tuned) {
return std::unexpected(core::IntegrationError::TuneFailed);
}
if (auto applied = applyStoredAudioProfile(); !applied) {
return applied;
}
if (auto saved = persistLastPreset(index); !saved) {
return std::unexpected(core::IntegrationError::StoreFailed);
}
return {};
}
station::StationService& IntegrationService::stations() noexcept
{
return stations_;
}
tuner::TunerService& IntegrationService::tuner() noexcept
{
return tuner_;
}
audio::AudioService& IntegrationService::audio() noexcept
{
return audio_;
}
std::expected<void, core::IntegrationError>
IntegrationService::applyStoredAudioProfile()
{
if (auto applied = audio_.applyProfile(audio_.currentProfile(), false);
!applied) {
return std::unexpected(core::IntegrationError::AudioFailed);
}
return {};
}
std::expected<void, core::StoreError> IntegrationService::persistLastPreset(
std::size_t index)
{
if (index > 255U) {
return std::unexpected(core::StoreError::InvalidData);
}
return store_.saveLastPresetIndex(static_cast<std::uint8_t>(index));
}
} // namespace integration
@@ -1,33 +0,0 @@
/**
* @file component_stub.cpp
* @brief Application services placeholder (Slice 7).
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* @author Michele Bigi
* @date 2026-07-06
*/
namespace services::detail {
/**
* @brief servicesComponentLinked — ensures the services component links.
*
* @dname servicesComponentLinked
* @return n/a (type)
* @pubstate n/a
*
* @author Michele Bigi
* @date 2026-07-06
*/
void servicesComponentLinked() noexcept {}
} // namespace services::detail