Add BT1035 pairing and station presets (fw 0.7.0).
Expose discoverable mode and A2DP control over REST, add persisted DAB/FM preset list with web UI, and document gaps in docs/TODO.md. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -119,9 +119,60 @@ public:
|
||||
[[nodiscard]] std::expected<void, Bt1035Error> sendCommand(
|
||||
core::Bt1035AtCommand command);
|
||||
|
||||
/**
|
||||
* @brief enterPairingMode — make module discoverable (AT+PAIR=1).
|
||||
*
|
||||
* @dname enterPairingMode
|
||||
* @return Ok on OK response, or Bt1035Error.
|
||||
* @pubstate writes UART; module advertises until paired or leavePairingMode().
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, Bt1035Error> enterPairingMode();
|
||||
|
||||
/**
|
||||
* @brief leavePairingMode — stop discoverable advertising (AT+PAIR=0).
|
||||
*
|
||||
* @dname leavePairingMode
|
||||
* @return Ok on OK response, or Bt1035Error.
|
||||
* @pubstate writes UART.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, Bt1035Error> leavePairingMode();
|
||||
|
||||
/**
|
||||
* @brief queryA2dpState — read current A2DP link state (AT+A2DPSTAT).
|
||||
*
|
||||
* @dname queryA2dpState
|
||||
* @return Parsed A2DP state on success, or Bt1035Error.
|
||||
* @pubstate writes UART; parses +A2DPSTAT from the reply.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<core::Bt1035A2dpState, Bt1035Error>
|
||||
queryA2dpState();
|
||||
|
||||
/**
|
||||
* @brief disconnectA2dp — release the active A2DP session (AT+A2DPDISC).
|
||||
*
|
||||
* @dname disconnectA2dp
|
||||
* @return Ok on OK response, or Bt1035Error.
|
||||
* @pubstate writes UART.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, Bt1035Error> disconnectA2dp();
|
||||
|
||||
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);
|
||||
[[nodiscard]] std::expected<void, Bt1035Error> transmitAndExpectOk(
|
||||
std::string_view commandLine);
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ std::expected<void, Bt1035Error> Bt1035Driver::ensureBooted() const
|
||||
return {};
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::transmitAndExpectOk(
|
||||
std::expected<std::string, Bt1035Error> Bt1035Driver::transmitAndCollect(
|
||||
std::string_view commandLine)
|
||||
{
|
||||
const int written = uart_write_bytes(static_cast<uart_port_t>(uartPort_),
|
||||
@@ -89,7 +89,7 @@ std::expected<void, Bt1035Error> Bt1035Driver::transmitAndExpectOk(
|
||||
const core::Bt1035AtResponseKind kind =
|
||||
core::parseBt1035AtResponse(accumulated);
|
||||
if (kind == core::Bt1035AtResponseKind::Ok) {
|
||||
return {};
|
||||
return accumulated;
|
||||
}
|
||||
if (kind == core::Bt1035AtResponseKind::Error) {
|
||||
return std::unexpected(Bt1035Error::AtError);
|
||||
@@ -100,6 +100,15 @@ std::expected<void, Bt1035Error> Bt1035Driver::transmitAndExpectOk(
|
||||
return std::unexpected(Bt1035Error::AtTimeout);
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::transmitAndExpectOk(
|
||||
std::string_view commandLine)
|
||||
{
|
||||
if (auto collected = transmitAndCollect(commandLine); collected) {
|
||||
return {};
|
||||
}
|
||||
return std::unexpected(collected.error());
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::sendCommand(
|
||||
core::Bt1035AtCommand command)
|
||||
{
|
||||
@@ -109,6 +118,49 @@ std::expected<void, Bt1035Error> Bt1035Driver::sendCommand(
|
||||
return transmitAndExpectOk(core::buildBt1035AtLine(command));
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::enterPairingMode()
|
||||
{
|
||||
if (auto ready = ensureBooted(); !ready) {
|
||||
return ready;
|
||||
}
|
||||
return sendCommand(core::Bt1035AtCommand::PairDiscoverable);
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::leavePairingMode()
|
||||
{
|
||||
if (auto ready = ensureBooted(); !ready) {
|
||||
return ready;
|
||||
}
|
||||
return sendCommand(core::Bt1035AtCommand::PairHidden);
|
||||
}
|
||||
|
||||
std::expected<core::Bt1035A2dpState, Bt1035Error> Bt1035Driver::queryA2dpState()
|
||||
{
|
||||
if (auto ready = ensureBooted(); !ready) {
|
||||
return std::unexpected(ready.error());
|
||||
}
|
||||
|
||||
auto response =
|
||||
transmitAndCollect(core::buildBt1035AtLine(core::Bt1035AtCommand::A2dpStat));
|
||||
if (!response) {
|
||||
return std::unexpected(response.error());
|
||||
}
|
||||
|
||||
auto parsed = core::parseBt1035A2dpStatResponse(*response);
|
||||
if (!parsed) {
|
||||
return std::unexpected(Bt1035Error::UnexpectedResponse);
|
||||
}
|
||||
return *parsed;
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::disconnectA2dp()
|
||||
{
|
||||
if (auto ready = ensureBooted(); !ready) {
|
||||
return ready;
|
||||
}
|
||||
return sendCommand(core::Bt1035AtCommand::A2dpDisconnect);
|
||||
}
|
||||
|
||||
std::expected<void, Bt1035Error> Bt1035Driver::runInitSequence()
|
||||
{
|
||||
for (const core::Bt1035AtCommand command : core::bootInitSequence()) {
|
||||
|
||||
Reference in New Issue
Block a user