switch-pico/tools/switch2_wake_beacon/beacon_protocol.h
Joey Yakimowich-Payne bed71f77f1 feat(wake): add controller-free USB serial wake beacon
Add a standalone Pico2W image reusing the configured nonconnectable wake
burst without Bluepad32, controller-host profiles, Classic/LE-central
roles, connection pools, pairing or writable TLV storage. Explicitly
disable and verify Classic inquiry/page scan before declaring readiness.
Keep the original controller firmware and captured wake identity unchanged.

Expose bounded SPWB1 CDC commands with exactly-once request IDs, explicit
failures and radio progress independent of serial backpressure. Add the
cross-platform switch-pico-wake script with strict preflight, bounded I/O,
no automatic rebroadcast, status-only mode and preserved uncertain-outcome
metadata. Standard USB serial requires no WinUSB/Zadig binding.

Add isolated --wake-only build/publication selection and document setup,
backup and physical-BOOTSEL recovery. Validate776 tests, focused framing
and lifecycle cases, ELF isolation and actual CDC operation on only the
new board. One burst completed in2.095s; malformed/status/reconnect input
and same-ID replay caused no additional broadcast. Original Pico untouched.
Private firmware images, console configuration and backups are excluded.
2026-09-19 22:03:17 -06:00

62 lines
1.6 KiB
C++

#pragma once
#include <stddef.h>
#include <stdint.h>
#include "input/switch2_wake.h"
namespace wake_beacon {
struct RadioStatus {
bool ready = false;
bool failed = false;
bool initialized = false;
Switch2WakeDiagnostics wake{};
};
// Owned entirely by Core 0. Parsing only queues a request; the radio owner calls
// dispatch_pending()/dispatched() separately, outside USB callbacks and IRQs.
class Protocol {
public:
static constexpr size_t kMaxLineBytes = 64; // Excludes LF, includes optional CR.
static constexpr size_t kResponseBytes = 512;
void connected(bool connected);
bool can_receive() const;
bool receive(uint8_t byte);
const char* output_data() const;
size_t output_size() const;
void consume_output(size_t count);
void observe(const RadioStatus& radio);
bool dispatch_pending() const;
void dispatched(bool accepted);
private:
enum class State : uint8_t {
Idle, Queued, Broadcasting, Complete, Unconfigured, Failed,
};
bool active() const;
bool busy() const;
const char* state_name() const;
void command();
void respond(const char* error);
RadioStatus radio_{};
State state_ = State::Idle;
uint32_t request_id_ = 0;
uint32_t accepted_requests_ = 0;
uint32_t local_failures_ = 0;
uint32_t start_completed_ = 0;
uint32_t start_failures_ = 0;
bool connected_ = false;
bool invalid_line_ = false;
char line_[kMaxLineBytes]{};
size_t line_size_ = 0;
char response_[kResponseBytes]{};
size_t response_size_ = 0;
size_t response_offset_ = 0;
};
} // namespace wake_beacon