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,6 +1,14 @@
|
||||
set(ADAU_FW_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../Firmware/ADAU1701-Firmware")
|
||||
|
||||
idf_component_register(
|
||||
SRCS "src/component_stub.cpp"
|
||||
INCLUDE_DIRS "include"
|
||||
SRCS
|
||||
"src/Adau1701Driver.cpp"
|
||||
"src/SigmaStudioFW.c"
|
||||
"src/adau1701_program.c"
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
"${ADAU_FW_DIR}"
|
||||
REQUIRES driver esp_driver_gpio esp_driver_i2c
|
||||
)
|
||||
|
||||
target_compile_features(${COMPONENT_LIB} PUBLIC cxx_std_23)
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @file Adau1701Driver.hpp
|
||||
* @brief ADAU1701 SigmaDSP driver — RAM boot on every power-up.
|
||||
*
|
||||
* 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 "adau1701/Adau1701Error.hpp"
|
||||
|
||||
#include <expected>
|
||||
|
||||
namespace adau1701 {
|
||||
|
||||
/**
|
||||
* @brief Adau1701Pins — board GPIO/I2C identifiers for the DSP.
|
||||
*
|
||||
* @dname Adau1701Pins
|
||||
* @return n/a (type)
|
||||
* @pubstate Immutable wiring snapshot from board_pins.hpp.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
struct Adau1701Pins {
|
||||
int i2cSda; ///< I2C SDA GPIO.
|
||||
int i2cScl; ///< I2C SCL GPIO.
|
||||
int resetGpio; ///< DSP RESET# GPIO (active low).
|
||||
int i2cAddr7; ///< 7-bit I2C address of the ADAU1701.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adau1701Driver — owns I2C + reset and loads SigmaStudio RAM.
|
||||
*
|
||||
* @dname Adau1701Driver
|
||||
* @param pins Board wiring for I2C and RESET#.
|
||||
* @return n/a (type)
|
||||
* @pubstate Owns I2C bus/device handles (RAII). booted_ true after a
|
||||
* successful default_download replay.
|
||||
*
|
||||
* Writes the SigmaStudio export from Firmware/ADAU1701-Firmware on every
|
||||
* boot (no EEPROM self-boot on DigiRadio).
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
class Adau1701Driver {
|
||||
public:
|
||||
/**
|
||||
* @brief Adau1701Driver — construct with board pin map.
|
||||
*
|
||||
* @dname Adau1701Driver
|
||||
* @param pins SDA/SCL/reset/address configuration.
|
||||
* @pubstate stores pins_; not booted until boot().
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
explicit Adau1701Driver(Adau1701Pins pins);
|
||||
|
||||
/**
|
||||
* @brief ~Adau1701Driver — release I2C resources.
|
||||
*
|
||||
* @dname ~Adau1701Driver
|
||||
* @pubstate deletes bus/device handles when created.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
~Adau1701Driver();
|
||||
|
||||
Adau1701Driver(const Adau1701Driver&) = delete;
|
||||
Adau1701Driver& operator=(const Adau1701Driver&) = delete;
|
||||
|
||||
/**
|
||||
* @brief boot — reset the DSP and replay the SigmaStudio download.
|
||||
*
|
||||
* @dname boot
|
||||
* @return Ok on success, or Adau1701Error.
|
||||
* @pubstate writes booted_ on success; uses embedded program data.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, Adau1701Error> boot();
|
||||
|
||||
/**
|
||||
* @brief isBooted — query whether RAM download succeeded.
|
||||
*
|
||||
* @dname isBooted
|
||||
* @return true after a successful boot().
|
||||
* @pubstate reads booted_.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] bool isBooted() const noexcept;
|
||||
|
||||
private:
|
||||
Adau1701Pins pins_;
|
||||
bool booted_;
|
||||
void* i2cBus_;
|
||||
void* i2cDev_;
|
||||
};
|
||||
|
||||
} // namespace adau1701
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file Adau1701Error.hpp
|
||||
* @brief Typed errors for ADAU1701 driver operations.
|
||||
*
|
||||
* 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
|
||||
|
||||
namespace adau1701 {
|
||||
|
||||
/**
|
||||
* @brief Adau1701Error — failure causes for ADAU1701 bring-up.
|
||||
*
|
||||
* @dname Adau1701Error
|
||||
* @return n/a (type)
|
||||
* @pubstate n/a
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
enum class Adau1701Error {
|
||||
I2cInitFailed,
|
||||
ResetFailed,
|
||||
DownloadFailed,
|
||||
};
|
||||
|
||||
} // namespace adau1701
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file Adau1701Driver.cpp
|
||||
* @brief Adau1701Driver 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 "adau1701/Adau1701Driver.hpp"
|
||||
|
||||
#include "SigmaStudioFW.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
/** @brief SigmaStudio default program download (generated C, not part of the C++ API). */
|
||||
void adau1701_run_default_download(void);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
namespace adau1701 {
|
||||
|
||||
namespace {
|
||||
constexpr char kTag[] = "Adau1701";
|
||||
constexpr int kI2cPort = 0;
|
||||
} // namespace
|
||||
|
||||
Adau1701Driver::Adau1701Driver(Adau1701Pins pins)
|
||||
: pins_(pins)
|
||||
, booted_(false)
|
||||
, i2cBus_(nullptr)
|
||||
, i2cDev_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Adau1701Driver::~Adau1701Driver()
|
||||
{
|
||||
auto* dev = static_cast<i2c_master_dev_handle_t>(i2cDev_);
|
||||
auto* bus = static_cast<i2c_master_bus_handle_t>(i2cBus_);
|
||||
if (dev != nullptr) {
|
||||
i2c_master_bus_rm_device(dev);
|
||||
}
|
||||
if (bus != nullptr) {
|
||||
i2c_del_master_bus(bus);
|
||||
}
|
||||
}
|
||||
|
||||
std::expected<void, Adau1701Error> Adau1701Driver::boot()
|
||||
{
|
||||
if (booted_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
gpio_config_t resetCfg = {};
|
||||
resetCfg.pin_bit_mask = 1ULL << pins_.resetGpio;
|
||||
resetCfg.mode = GPIO_MODE_OUTPUT;
|
||||
if (gpio_config(&resetCfg) != ESP_OK) {
|
||||
return std::unexpected(Adau1701Error::ResetFailed);
|
||||
}
|
||||
|
||||
gpio_set_level(static_cast<gpio_num_t>(pins_.resetGpio), 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(static_cast<gpio_num_t>(pins_.resetGpio), 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
i2c_master_bus_config_t busCfg = {};
|
||||
busCfg.i2c_port = static_cast<i2c_port_num_t>(kI2cPort);
|
||||
busCfg.sda_io_num = static_cast<gpio_num_t>(pins_.i2cSda);
|
||||
busCfg.scl_io_num = static_cast<gpio_num_t>(pins_.i2cScl);
|
||||
busCfg.clk_source = I2C_CLK_SRC_DEFAULT;
|
||||
busCfg.glitch_ignore_cnt = 7;
|
||||
busCfg.flags.enable_internal_pullup = true;
|
||||
|
||||
i2c_master_bus_handle_t bus = nullptr;
|
||||
if (i2c_new_master_bus(&busCfg, &bus) != ESP_OK) {
|
||||
ESP_LOGE(kTag, "i2c_new_master_bus failed");
|
||||
return std::unexpected(Adau1701Error::I2cInitFailed);
|
||||
}
|
||||
i2cBus_ = bus;
|
||||
|
||||
i2c_device_config_t devCfg = {};
|
||||
devCfg.dev_addr_length = I2C_ADDR_BIT_LEN_7;
|
||||
devCfg.device_address = static_cast<uint16_t>(pins_.i2cAddr7);
|
||||
devCfg.scl_speed_hz = 100000;
|
||||
|
||||
i2c_master_dev_handle_t dev = nullptr;
|
||||
if (i2c_master_bus_add_device(bus, &devCfg, &dev) != ESP_OK) {
|
||||
ESP_LOGE(kTag, "i2c_master_bus_add_device failed");
|
||||
return std::unexpected(Adau1701Error::I2cInitFailed);
|
||||
}
|
||||
i2cDev_ = dev;
|
||||
|
||||
sigma_studio_bind_i2c(kI2cPort, static_cast<unsigned char>(pins_.i2cAddr7));
|
||||
sigma_studio_set_device(dev);
|
||||
|
||||
adau1701_run_default_download();
|
||||
|
||||
booted_ = true;
|
||||
ESP_LOGI(kTag, "SigmaStudio program loaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Adau1701Driver::isBooted() const noexcept
|
||||
{
|
||||
return booted_;
|
||||
}
|
||||
|
||||
} // namespace adau1701
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file SigmaStudioFW.c
|
||||
* @brief SigmaStudio SIGMA_WRITE_REGISTER_BLOCK for ESP-IDF I2C.
|
||||
*
|
||||
* 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 "SigmaStudioFW.h"
|
||||
|
||||
#include "driver/i2c_master.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static i2c_master_dev_handle_t s_dev = NULL;
|
||||
|
||||
void sigma_studio_bind_i2c(int port, unsigned char addr7)
|
||||
{
|
||||
(void)port;
|
||||
(void)addr7;
|
||||
}
|
||||
|
||||
void sigma_studio_set_device(void* i2cDevHandle)
|
||||
{
|
||||
s_dev = (i2c_master_dev_handle_t)i2cDevHandle;
|
||||
}
|
||||
|
||||
void SIGMA_WRITE_REGISTER_BLOCK(unsigned char devAddress,
|
||||
unsigned int address,
|
||||
unsigned char length,
|
||||
ADI_REG_TYPE* pData)
|
||||
{
|
||||
(void)devAddress;
|
||||
if (s_dev == NULL || pData == NULL || length == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
enum { kChunk = 64U };
|
||||
unsigned int addr = address;
|
||||
unsigned char remaining = length;
|
||||
ADI_REG_TYPE* cursor = pData;
|
||||
|
||||
while (remaining > 0U) {
|
||||
const unsigned char chunk =
|
||||
remaining > kChunk ? kChunk : remaining;
|
||||
unsigned char buf[2U + 64U];
|
||||
buf[0] = (unsigned char)((addr >> 8) & 0xFFU);
|
||||
buf[1] = (unsigned char)(addr & 0xFFU);
|
||||
memcpy(buf + 2U, cursor, chunk);
|
||||
i2c_master_transmit(s_dev, buf, (size_t)(2U + chunk), 1000);
|
||||
addr += chunk;
|
||||
cursor += chunk;
|
||||
remaining = (unsigned char)(remaining - chunk);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @file adau1701_program.c
|
||||
* @brief SigmaStudio default download for DigiRadio ADAU1701.
|
||||
*
|
||||
* 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 "SigmaStudioFW.h"
|
||||
#include "DigiRadio_IC_1.h"
|
||||
|
||||
void adau1701_run_default_download(void)
|
||||
{
|
||||
default_download_IC_1();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* @file component_stub.cpp
|
||||
* @brief ADAU1701 driver component placeholder (Slice 5).
|
||||
*
|
||||
* 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 adau1701::detail {
|
||||
|
||||
/**
|
||||
* @brief adau1701ComponentLinked — ensures the driver component links.
|
||||
*
|
||||
* @dname adau1701ComponentLinked
|
||||
* @return n/a (type)
|
||||
* @pubstate n/a
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
void adau1701ComponentLinked() noexcept {}
|
||||
|
||||
} // namespace adau1701::detail
|
||||
Reference in New Issue
Block a user