Add Slice 4 tuner stack with AGENTS-compliant core types and HTTP API.
Introduces Si4684/ADAU1701 drivers, TunerService, FrequencyKHz, SeekDirection, /api/tuner routes without file-scope globals, host tests, and firmware blob tooling (binaries remain gitignored). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
idf_component_register(
|
||||
SRCS "main.cpp"
|
||||
SRCS
|
||||
"main.cpp"
|
||||
"hardware_bootstrap.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES core net secure_store
|
||||
REQUIRES core net secure_store adau1701 si4684 tuner
|
||||
)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file hardware_bootstrap.cpp
|
||||
* @brief HardwareBootstrap 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 "hardware_bootstrap.hpp"
|
||||
|
||||
#include "adau1701/Adau1701Driver.hpp"
|
||||
#include "board_pins.hpp"
|
||||
#include "si4684/Si4684Band.hpp"
|
||||
#include "si4684/Si4684Driver.hpp"
|
||||
#include "si4684/Si4684EmbeddedImages.hpp"
|
||||
#include "si4684/Si4684Tuner.hpp"
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
namespace hardware {
|
||||
|
||||
namespace {
|
||||
constexpr char kTag[] = "hw_boot";
|
||||
|
||||
si4684::Si4684EmbeddedImages gImages;
|
||||
si4684::Si4684Driver gSi4684(
|
||||
si4684::Si4684Pins{
|
||||
.spiHost = SPI2_HOST,
|
||||
.csGpio = board::pins::Si4684Cs,
|
||||
.misoGpio = board::pins::Si4684Miso,
|
||||
.mosiGpio = board::pins::Si4684Mosi,
|
||||
.sclkGpio = board::pins::Si4684Sclk,
|
||||
.rstbGpio = board::pins::Si4684Rstb,
|
||||
.intbGpio = board::pins::Si4684Intb,
|
||||
},
|
||||
gImages.romPatch(),
|
||||
gImages.dabFirmware(),
|
||||
gImages.fmFirmware());
|
||||
si4684::Si4684Tuner gSi4684Tuner(gSi4684);
|
||||
|
||||
adau1701::Adau1701Driver gAdau1701(
|
||||
adau1701::Adau1701Pins{
|
||||
.i2cSda = board::pins::Adau1701Sda,
|
||||
.i2cScl = board::pins::Adau1701Scl,
|
||||
.resetGpio = board::pins::Adau1701Reset,
|
||||
.i2cAddr7 = board::pins::Adau1701Addr,
|
||||
});
|
||||
|
||||
bool gReady = false;
|
||||
} // namespace
|
||||
|
||||
std::expected<void, HardwareBootError> HardwareBootstrap::boot()
|
||||
{
|
||||
if (gReady) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto tunerResult = gSi4684.boot(si4684::Si4684Band::Dab); !tunerResult) {
|
||||
ESP_LOGE(kTag, "Si4684 boot failed");
|
||||
return std::unexpected(HardwareBootError::Si4684BootFailed);
|
||||
}
|
||||
|
||||
if (!gAdau1701.isBooted()) {
|
||||
auto dspResult = gAdau1701.boot();
|
||||
if (!dspResult) {
|
||||
ESP_LOGE(kTag, "ADAU1701 boot failed");
|
||||
return std::unexpected(HardwareBootError::Adau1701BootFailed);
|
||||
}
|
||||
}
|
||||
|
||||
gReady = true;
|
||||
ESP_LOGI(kTag, "companion chips ready");
|
||||
return {};
|
||||
}
|
||||
|
||||
si4684::Si4684Tuner& HardwareBootstrap::si4684Tuner()
|
||||
{
|
||||
return gSi4684Tuner;
|
||||
}
|
||||
|
||||
} // namespace hardware
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file hardware_bootstrap.hpp
|
||||
* @brief Boot Si4684 and ADAU1701 companion chips at application start.
|
||||
*
|
||||
* 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 <expected>
|
||||
|
||||
namespace si4684 {
|
||||
class Si4684Tuner;
|
||||
} // namespace si4684
|
||||
|
||||
namespace hardware {
|
||||
|
||||
/**
|
||||
* @brief HardwareBootError — companion-chip boot failure causes.
|
||||
*
|
||||
* @dname HardwareBootError
|
||||
* @return n/a (type)
|
||||
* @pubstate n/a
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
enum class HardwareBootError {
|
||||
Si4684BootFailed,
|
||||
Adau1701BootFailed,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HardwareBootstrap — orchestrates Si4684 then ADAU1701 bring-up.
|
||||
*
|
||||
* @dname HardwareBootstrap
|
||||
* @return n/a (type)
|
||||
* @pubstate Owns static driver instances for the process lifetime. Must be
|
||||
* called once from app_main before network start.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
class HardwareBootstrap {
|
||||
public:
|
||||
/**
|
||||
* @brief boot — load Si4684 DAB image then replay ADAU1701 program.
|
||||
*
|
||||
* @dname boot
|
||||
* @return Ok on success, or HardwareBootError.
|
||||
* @pubstate constructs static Si4684 and ADAU1701 drivers on first call.
|
||||
*
|
||||
* Fail-closed: callers must not start Wi-Fi when this returns an error.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] static std::expected<void, HardwareBootError> boot();
|
||||
|
||||
/**
|
||||
* @brief si4684Tuner — borrow the Si4684 ITuner adapter after boot.
|
||||
*
|
||||
* @dname si4684Tuner
|
||||
* @return Reference to the static Si4684Tuner instance.
|
||||
* @pubstate reads static storage initialised by boot().
|
||||
*
|
||||
* Valid only after a successful boot() call in the same process.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] static si4684::Si4684Tuner& si4684Tuner();
|
||||
};
|
||||
|
||||
} // namespace hardware
|
||||
+15
-22
@@ -7,17 +7,14 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "hardware_bootstrap.hpp"
|
||||
#include "net/NetBootstrap.hpp"
|
||||
#include "secure_store/NvsSecureStore.hpp"
|
||||
#include "tuner/TunerService.hpp"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@@ -28,16 +25,6 @@ namespace {
|
||||
constexpr char kTag[] = "digiradio";
|
||||
constexpr TickType_t kHeartbeatPeriod = pdMS_TO_TICKS(5000);
|
||||
|
||||
/**
|
||||
* @brief heartbeatTask — periodic alive log for bring-up verification.
|
||||
*
|
||||
* @dname heartbeatTask
|
||||
* @param arg Unused task parameter.
|
||||
* @pubstate none
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
void heartbeatTask(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
@@ -50,24 +37,30 @@ void heartbeatTask(void* arg)
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief app_main — ESP-IDF application entry point.
|
||||
* @brief app_main — ESP-IDF entry point for DigiRadio firmware.
|
||||
*
|
||||
* @dname app_main
|
||||
* @pubstate starts NvsSecureStore, NetBootstrap, and the heartbeat task.
|
||||
*
|
||||
* Slice 2: joins a stored Wi-Fi network when credentials exist, otherwise
|
||||
* opens the DigiRadio-setup SoftAP for provisioning via the web UI.
|
||||
* @pubstate boots companion chips, network stack, and heartbeat task.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
extern "C" void app_main()
|
||||
{
|
||||
ESP_LOGI(kTag, "DigiRadio firmware boot — Slice 2");
|
||||
ESP_LOGI(kTag, "DigiRadio firmware boot — Slice 4");
|
||||
|
||||
auto hwResult = hardware::HardwareBootstrap::boot();
|
||||
if (!hwResult) {
|
||||
ESP_LOGE(kTag, "companion chip boot failed — halting");
|
||||
return;
|
||||
}
|
||||
|
||||
static tuner::TunerService tunerService(
|
||||
hardware::HardwareBootstrap::si4684Tuner());
|
||||
|
||||
static secure_store::NvsSecureStore store;
|
||||
|
||||
auto netResult = net::NetBootstrap::start(store);
|
||||
auto netResult = net::NetBootstrap::start(store, tunerService);
|
||||
if (!netResult) {
|
||||
ESP_LOGE(kTag, "network bootstrap failed");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user