#pragma once #include #include #include namespace roro { // Where the firmware's console output goes: the USB serial port, and while the Debug Console is // switched on (ADR 0010) also a ring buffer it sends over Wi-Fi, with what came before the connection. // Use `console` instead of Serial for anything a human should be able to read remotely. class Console : public Print { public: size_t write(uint8_t c) override { return write(&c, 1); } size_t write(const uint8_t* data, size_t len) override; using Print::write; static constexpr size_t kRingBytes = 4096; // The ring exists only while the Debug Console is on: 4 KB of heap a device that never uses it // keeps. False if there's no memory for it. bool openRing(); void closeRing(); bool ringOpen() const { return ring_ != nullptr; } // Also copies ESP-IDF's own log lines into the ring (they still reach the serial port). void captureEspLogs(); // Copies bytes written since `pos` into `out`, and advances `pos`. A reader that fell more than // the ring behind gets the oldest bytes still there, and `skipped` says how many it missed. size_t readSince(uint32_t& pos, uint8_t* out, size_t max, uint32_t& skipped); // The position of the oldest byte still in the ring: a new reader starts there. uint32_t oldest() const; // The ring only, for output that already reaches the serial port another way. void toRing(const uint8_t* data, size_t len); // Who asked for what is being printed. A command typed in the Shell App prints its reply `As` // the Shell, and so does whatever answers it later from another task (a listing read by the // storage task, `tasks` a second on): the one that starts the work notes origin() and the one that // prints takes it back. Everything else is the System's: logs, and the consoles' own commands. enum class Origin : uint8_t { System, Shell }; Origin origin() const; // of the task that asks, now class As { public: explicit As(Origin origin); ~As(); As(const As&) = delete; As& operator=(const As&) = delete; private: bool entered_; }; // A second ring of the same kind, for the Shell App (issue #67): open while the App is. It gets // what is printed As the Shell, and nothing else, so that the Shell shows the replies to its own // commands and not the rest (Q206); or everything, when asked. bool openShellRing(); void closeShellRing(); void shellShowsAll(bool all) { shellAll_ = all; } bool shellShowsAll() const { return shellAll_; } size_t readShellSince(uint32_t& pos, uint8_t* out, size_t max, uint32_t& skipped); private: uint8_t* ring_ = nullptr; uint32_t head_ = 0; // total bytes written since the ring opened; it holds the last kRingBytes of them uint8_t* shellRing_ = nullptr; uint32_t shellHead_ = 0; volatile bool shellAll_ = false; }; extern Console console; } // namespace roro