Files
DigiRadio/Software/components/drivers/si4684/include/si4684/Si4684Tuner.hpp
T
micheleandClaude Sonnet 5 6f7b6dd12c Add internet radio streaming with runtime API, modernize web UI, remove auto-tune/beep at boot
Streaming (main feature this session):
- New WebRadioConfig/WebRadioJson core types, ISecureStore-backed persistence
- New webradio::WebRadioService (thread-safe live config) + GET/POST /api/streaming
- web_radio_stream task now runtime-toggleable (no reboot), no hardcoded URL
- Content-Type diagnostic: warns clearly when a URL is a webpage, not an audio stream

Boot cleanup:
- Removed boot-time auto FM/DAB tune, auto-beep, and the (now-concluded) Si4684
  crystal IBIAS/CTUN empirical sweep from main.cpp — tuning/beep are on-demand
  via the existing REST API only

Web UI:
- Modernized styling (cards, gradients, toggle switches, light/dark theme)
- New Stream tab wired to /api/streaming

Fixes found via real idf.py build (not just clangd):
- Restored wrongly-removed si4684/Si4684Tuner.hpp include in main.cpp
- Fixed MP3Decode() argument types in web_radio_stream.cpp (unsigned char**/int*)

Quality-gate fixes:
- Host-test stub headers (esp_log.h, freertos/*) so TunerService.cpp's
  scanForStation logging/pacing compiles for station_service_test /
  integration_service_test instead of running stale binaries
- Added WifiScanner and WebRadioService manual sections; filled in missing
  Doxygen docs on BluetoothService, i2s_sdata_probe, test_firmware, Bt1035At
- Ignore clangd's .cache/ index directory

Also includes prior uncommitted work carried in the tree: Wi-Fi/Bluetooth
device scan REST API and UI (WifiScanner, BT scan), SigmaStudio TCP bridge,
and the current ADAU1701 SigmaStudio DSP program export.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-08 21:15:22 +02:00

219 lines
6.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file Si4684Tuner.hpp
* @brief core::ITuner adapter over Si4684Driver.
*
* 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 "core/DabDynamicLabelAccumulator.hpp"
#include "core/FrequencyKHz.hpp"
#include "core/ITuner.hpp"
#include "core/RdsMetadataAccumulator.hpp"
#include "si4684/Si4684Driver.hpp"
#include <optional>
namespace si4684 {
/**
* @brief Si4684Tuner — maps Si4684Driver to core::ITuner.
*
* @dname Si4684Tuner
* @param driver Borrowed Si4684Driver (must outlive this adapter).
* @return n/a (type)
* @pubstate Borrows driver_. Caches last DAB index, FM frequency, and volume
* for status reporting. No public data members.
*
* Translates domain calls into SPI commands and maps Si4684Error to
* core::TunerError at this boundary.
*
* @author Michele Bigi
* @date 2026-07-06
*/
class Si4684Tuner : public core::ITuner {
public:
/**
* @brief Si4684Tuner — bind to a booted or bootable driver instance.
*
* @dname Si4684Tuner
* @param driver Si4684 driver constructed by HardwareBootstrap.
* @pubstate stores driver reference; sets default tune targets.
*
* @author Michele Bigi
* @date 2026-07-06
*/
explicit Si4684Tuner(Si4684Driver& driver);
/**
* @brief boot — load the requested Si4684 application image.
*
* @dname boot
* @param band DAB or FM image to load.
* @return Ok on success, or a mapped TunerError.
* @pubstate delegates to driver_.boot().
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::TunerError> boot(
core::TunerBand band) override;
/**
* @brief currentBand — read the loaded application band.
*
* @dname currentBand
* @return Active TunerBand, or TunerError::NotBooted.
* @pubstate reads driver_.loadedBand().
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<core::TunerBand, core::TunerError> currentBand()
const override;
/**
* @brief readStatus — build a core TunerStatus from driver metrics.
*
* @dname readStatus
* @return TunerStatus on success, or a mapped TunerError.
* @pubstate reads driver_; refreshes cached tune targets from RSQ/DIGRAD.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<core::TunerStatus, core::TunerError> readStatus()
override;
/**
* @brief tuneDab — tune to a Band III ensemble index.
*
* @dname tuneDab
* @param freqIndex Ensemble index 037.
* @return Ok on success, or a mapped TunerError.
* @pubstate writes dabIndex_ on success.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::TunerError> tuneDab(
std::uint8_t freqIndex) override;
/**
* @brief tuneFm — tune to an FM centre frequency in kHz.
*
* @dname tuneFm
* @param frequency Validated FM centre frequency.
* @return Ok on success, or a mapped TunerError.
* @pubstate writes fmFrequency_ on success.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::TunerError> tuneFm(
core::FrequencyKHz frequency) override;
/**
* @brief seekFm — seek FM with band wrap.
*
* @dname seekFm
* @param direction Up or Down scan direction.
* @return New centre frequency, or a mapped TunerError.
* @pubstate writes fmFrequency_ on success.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<core::FrequencyKHz, core::TunerError> seekFm(
core::SeekDirection direction) override;
/**
* @brief listDabServices — fetch programmes for the current ensemble.
*
* @dname listDabServices
* @return Service entries, ServiceListEmpty, or a mapped TunerError.
* @pubstate reads driver_ service list when ready.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<std::vector<core::TunerServiceEntry>,
core::TunerError>
listDabServices() override;
/**
* @brief playDabService — start DAB audio output.
*
* @dname playDabService
* @param serviceId Selected service identifier.
* @param componentId Audio component within the service.
* @return Ok on success, or a mapped TunerError.
* @pubstate delegates to driver_.startDabService().
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::TunerError> playDabService(
std::uint32_t serviceId, std::uint32_t componentId) override;
/**
* @brief setVolume — set Si4684 output attenuation.
*
* @dname setVolume
* @param level Attenuator 063.
* @return Ok on success, or a mapped TunerError.
* @pubstate writes volume_ on success.
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] std::expected<void, core::TunerError> setVolume(
std::uint8_t level) override;
private:
/**
* @brief mapError — translate Si4684Error to core::TunerError.
*
* @dname mapError
* @param error Driver-level failure cause.
* @return Equivalent TunerError for services and HTTP layer.
* @pubstate none
*
* @author Michele Bigi
* @date 2026-07-06
*/
[[nodiscard]] static core::TunerError mapError(Si4684Error error) noexcept;
/**
* @brief ensureBandLoaded — HOST_LOAD FM/DAB image when band differs.
*
* @dname ensureBandLoaded
* @param band Required application band for the next operation.
* @return Ok when the chip runs the requested image.
* @pubstate may reload firmware (~1 s) and stop an active DAB service.
*
* @author Michele Bigi
* @date 2026-08-05
*/
[[nodiscard]] std::expected<void, core::TunerError> ensureBandLoaded(
core::TunerBand band);
Si4684Driver& driver_;
std::uint8_t dabIndex_;
core::FrequencyKHz fmFrequency_;
std::uint8_t volume_;
bool fmBandReady_;
core::RdsMetadataAccumulator rdsMetadata_;
core::DabDynamicLabelAccumulator dabDynamicLabel_;
std::optional<std::uint32_t> lastDabServiceId_;
std::optional<std::uint32_t> lastDabComponentId_;
};
} // namespace si4684