Release fw 0.8.4: doc sync, System UI, BT/FM polish.

Align README, manual, and backlog to 0.8.4; add Web UI System tab for OTA/DSP uploads, serial in health header, FM seek down, and BT1035 paired list plus auto-reconnect API.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 09:56:44 +02:00
co-authored by Cursor
parent b9ed8a2dcd
commit 176cdd9319
28 changed files with 988 additions and 66 deletions
@@ -17,7 +17,9 @@
#include "core/Bt1035At.hpp"
#include <expected>
#include <string>
#include <string_view>
#include <vector>
namespace bt1035 {
@@ -183,11 +185,62 @@ public:
[[nodiscard]] std::expected<void, Bt1035Error> setDeviceName(
std::string_view name);
/**
* @brief queryDeviceName — read GAP friendly name (AT+NAME).
*
* @dname queryDeviceName
* @return Module name on success, or Bt1035Error.
* @pubstate writes UART; parses +NAME= from the reply.
*
* @author Michele Bigi
* @date 2026-07-07
*/
[[nodiscard]] std::expected<std::string, Bt1035Error> queryDeviceName();
/**
* @brief setAutoReconnect — configure power-on reconnect (AT+AUTOCONN).
*
* @dname setAutoReconnect
* @param times 0 off, 115 attempts per Feasycom manual.
* @return Ok on success, or Bt1035Error.
* @pubstate writes UART.
*
* @author Michele Bigi
* @date 2026-07-07
*/
[[nodiscard]] std::expected<void, Bt1035Error> setAutoReconnect(
std::uint8_t times);
/**
* @brief queryAutoReconnect — read AT+AUTOCONN setting.
*
* @dname queryAutoReconnect
* @return Reconnect count 015, or Bt1035Error.
* @pubstate writes UART.
*
* @author Michele Bigi
* @date 2026-07-07
*/
[[nodiscard]] std::expected<std::uint8_t, Bt1035Error> queryAutoReconnect();
/**
* @brief queryPairedList — enumerate paired remotes (AT+PLIST).
*
* @dname queryPairedList
* @return Parsed paired devices, or Bt1035Error.
* @pubstate writes UART; may take longer than a single-line command.
*
* @author Michele Bigi
* @date 2026-07-07
*/
[[nodiscard]] std::expected<std::vector<core::Bt1035PairedDevice>, Bt1035Error>
queryPairedList();
private:
[[nodiscard]] std::expected<void, Bt1035Error> ensureBooted() const;
[[nodiscard]] std::expected<void, Bt1035Error> runInitSequence();
[[nodiscard]] std::expected<std::string, Bt1035Error> transmitAndCollect(
std::string_view commandLine);
std::string_view commandLine, int timeoutMs = kResponseTimeoutMs);
[[nodiscard]] std::expected<void, Bt1035Error> transmitAndExpectOk(
std::string_view commandLine);
@@ -22,6 +22,7 @@
#include <array>
#include <string>
#include <string_view>
#include <vector>
namespace bt1035 {
@@ -66,7 +67,7 @@ std::expected<void, Bt1035Error> Bt1035Driver::ensureBooted() const
}
std::expected<std::string, Bt1035Error> Bt1035Driver::transmitAndCollect(
std::string_view commandLine)
std::string_view commandLine, int timeoutMs)
{
const int written = uart_write_bytes(static_cast<uart_port_t>(uartPort_),
commandLine.data(),
@@ -79,7 +80,7 @@ std::expected<std::string, Bt1035Error> Bt1035Driver::transmitAndCollect(
std::array<char, 128> buffer{};
std::string accumulated;
const TickType_t deadline =
xTaskGetTickCount() + pdMS_TO_TICKS(kResponseTimeoutMs);
xTaskGetTickCount() + pdMS_TO_TICKS(timeoutMs);
while (xTaskGetTickCount() < deadline) {
const int received = uart_read_bytes(static_cast<uart_port_t>(uartPort_),
@@ -175,6 +176,68 @@ std::expected<void, Bt1035Error> Bt1035Driver::setDeviceName(
return transmitAndExpectOk(line);
}
std::expected<std::string, Bt1035Error> Bt1035Driver::queryDeviceName()
{
if (auto ready = ensureBooted(); !ready) {
return std::unexpected(ready.error());
}
auto response =
transmitAndCollect(core::buildBt1035AtLine(core::Bt1035AtCommand::QueryName));
if (!response) {
return std::unexpected(response.error());
}
auto parsed = core::parseBt1035NameResponse(*response);
if (!parsed) {
return std::unexpected(Bt1035Error::UnexpectedResponse);
}
return *parsed;
}
std::expected<void, Bt1035Error> Bt1035Driver::setAutoReconnect(
std::uint8_t times)
{
if (auto ready = ensureBooted(); !ready) {
return ready;
}
return transmitAndExpectOk(core::buildBt1035SetAutoConnLine(times));
}
std::expected<std::uint8_t, Bt1035Error> Bt1035Driver::queryAutoReconnect()
{
if (auto ready = ensureBooted(); !ready) {
return std::unexpected(ready.error());
}
auto response = transmitAndCollect(
core::buildBt1035AtLine(core::Bt1035AtCommand::QueryAutoConn));
if (!response) {
return std::unexpected(response.error());
}
auto parsed = core::parseBt1035AutoConnResponse(*response);
if (!parsed) {
return std::unexpected(Bt1035Error::UnexpectedResponse);
}
return *parsed;
}
std::expected<std::vector<core::Bt1035PairedDevice>, Bt1035Error>
Bt1035Driver::queryPairedList()
{
if (auto ready = ensureBooted(); !ready) {
return std::unexpected(ready.error());
}
auto response = transmitAndCollect(
core::buildBt1035AtLine(core::Bt1035AtCommand::QueryPairedList),
4000);
if (!response) {
return std::unexpected(response.error());
}
auto parsed = core::parseBt1035PairedListResponse(*response);
if (!parsed) {
return std::unexpected(Bt1035Error::UnexpectedResponse);
}
return *parsed;
}
std::expected<void, Bt1035Error> Bt1035Driver::runInitSequence()
{
for (const core::Bt1035AtCommand command : core::bootInitSequence()) {