Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/v2/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ namespace pocketpd {
bool l_short() const {
return id == ButtonId::L && gesture == Gesture::SHORT;
}

bool lr_long() const {
return id == ButtonId::L_R && gesture == Gesture::LONG;
}
};

/**
Expand Down
17 changes: 17 additions & 0 deletions include/v2/images.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,23 @@ namespace pocketpd::bitmap {
0x00, 0x00, 0x00, 0x00,
};

/**
* @brief Padlock, 8x8px. Used as the input-lock indicator on NormalStage / EnergyStage.
* ```
* ..####..
* .#....#.
* .#....#.
* ########
* ########
* ###..###
* ########
* ########
* ```
*/
inline constexpr std::array<uint8_t, 8> PADLOCK = {
0x3C, 0x42, 0x42, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF,
};

// --- Arrow rotation animation, 20x20px per frame, 28 frames total ---
// Frames 12-25 share identical bitmap data (held position).

Expand Down
19 changes: 15 additions & 4 deletions include/v2/stages/energy/energy_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace pocketpd {
uint32_t total_seconds = 0;
uint8_t arrow_frame = 0;
bool output_enabled = false;
bool locked = false;
};

class EnergyView {
Expand All @@ -51,6 +52,11 @@ namespace pocketpd {
using Display = tempo::Display;

public:
static constexpr uint8_t PADLOCK_X = 116;
static constexpr uint8_t PADLOCK_Y = 0;
static constexpr uint8_t PADLOCK_W = 8;
static constexpr uint8_t PADLOCK_H = 8;

static void render(Display& display, const EnergyViewModel& vm) {
display.clear();
std::array<char, 16> buf{};
Expand All @@ -62,32 +68,37 @@ namespace pocketpd {
display.draw_xbm(ARROW_X, ARROW_Y, ARROW_W, ARROW_H, bitmap);
}

// Top row — live V/A
display.set_font(tempo::Font::BASE);

// Mid — Voltage Current
format_milli(buf, vm.snapshot.vbus_mv, 'V');
display.draw_text(V_X, ROW2_Y - 10, buf.data());

format_milli(buf, vm.snapshot.current_ma, 'A');
display.draw_text(A_X, ROW2_Y + 5, buf.data());

// Bottom row — Wh Time Ah
format_time(buf, vm.total_seconds);
display.draw_text(T_X, ROW3_Y, buf.data());


format_auto(buf, vm.accumulated_wh);
draw_value(display, COL1_X, ROW3_Y, buf.data(), "Wh");

format_auto(buf, vm.accumulated_ah);
draw_value(display, COL2_X, ROW3_Y, buf.data(), "Ah");

// Mid — watts and watt-hours
// The big W label in the middle
display.set_font(tempo::Font::XL);
const double watts = (vm.snapshot.vbus_mv * vm.snapshot.current_ma) / 1'000'000.0;

format_auto(buf, watts);
draw_value(display, COL1_X, ROW2_Y, buf.data(), "W");

if (vm.locked) {
display.draw_xbm(
PADLOCK_X, PADLOCK_Y, PADLOCK_W, PADLOCK_H, bitmap::PADLOCK.data()
);
}

display.flush();
}

Expand Down
17 changes: 16 additions & 1 deletion include/v2/stages/energy_stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace pocketpd {
int8_t m_active_pdo_index = -1;
tempo::IntervalTimer m_render_interval{40};
uint8_t m_arrow_frame = 0;
bool m_locked = false;

static constexpr uint32_t SENSOR_EMA_DEN = 4;

Expand All @@ -55,11 +56,16 @@ namespace pocketpd {
return m_active_pdo_index;
}

bool locked() const {
return m_locked;
}

void prepare(int8_t pdo_index = -1) {
m_active_pdo_index = pdo_index;
}

void on_enter(Conductor&) override {
m_locked = false;
log.info("Entered Energy screen pdo_index={}", m_active_pdo_index);
draw();
}
Expand All @@ -73,11 +79,19 @@ namespace pocketpd {
void on_event(Conductor& conductor, const Event& event, uint32_t) override {
auto handler = tempo::overloaded{
[&](const ButtonEvent& evt) {
// L+R combo always reachable; must precede lock guard so a locked screen can unlock.
if (evt.lr_long()) {
m_locked = !m_locked;
return;
}
if (m_locked) {
return;
}

if (evt.r_short()) {
m_output_gate.toggle();
return;
}

if (evt.r_long()) {
conductor.request<NormalStage>(m_active_pdo_index);
}
Expand Down Expand Up @@ -115,6 +129,7 @@ namespace pocketpd {
.total_seconds = m_energy.total_seconds,
.arrow_frame = m_arrow_frame,
.output_enabled = m_output_gate.is_enabled(),
.locked = m_locked,
};
}

Expand Down
29 changes: 21 additions & 8 deletions include/v2/stages/normal/normal_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace pocketpd {
bool has_profile = false;
bool is_pps = false;
bool output_enabled = false;
bool locked = false;
uint8_t arrow_frame = 0;
SensorSnapshot snapshot{};

Expand Down Expand Up @@ -59,6 +60,11 @@ namespace pocketpd {
static constexpr uint8_t CURSOR_W = 7;

public:
static constexpr uint8_t PADLOCK_X = 116;
static constexpr uint8_t PADLOCK_Y = 0;
static constexpr uint8_t PADLOCK_W = 8;
static constexpr uint8_t PADLOCK_H = 8;

static void render(tempo::Display& d, const NormalViewModel& vm) {
d.clear();

Expand All @@ -81,7 +87,6 @@ namespace pocketpd {
const auto INDEX_X = STATUS_X - d.text_width(buf.data()) - 2;
d.draw_text(INDEX_X, 63, buf.data());
d.draw_text(STATUS_X, 64, vm.is_pps ? "PPS" : "PDO");
d.draw_text(INDEX_X + 2, 8, vm.output_enabled ? "ON" : "OFF");

if (vm.is_pps) {
draw_target_pps(d, vm, buf);
Expand All @@ -94,12 +99,22 @@ namespace pocketpd {
d.draw_xbm(ARROW_X, ARROW_Y, ARROW_W, ARROW_H, bitmap::ARROW_FRAMES.at(frame));
}

if (vm.locked) {
d.draw_text(INDEX_X + 2, 8, vm.output_enabled ? "ON" : "OFF");
d.draw_xbm(PADLOCK_X, PADLOCK_Y, PADLOCK_W, PADLOCK_H, bitmap::PADLOCK.data());
} else {
d.draw_text(PADLOCK_X - 6, 8, vm.output_enabled ? "ON" : "OFF");
}

d.flush();
}

private:
static void draw_measured(
tempo::Display& d, const char* label, uint8_t y, uint32_t value,
tempo::Display& d,
const char* label,
uint8_t y,
uint32_t value,
std::array<char, 32>& buf
) {
d.draw_text(1, y, label);
Expand All @@ -110,9 +125,8 @@ namespace pocketpd {
d.draw_text(static_cast<uint8_t>(TARGET_RIGHT_X - width), y, buf.data());
}

static void draw_target_fixed(
tempo::Display& d, const NormalViewModel& vm, std::array<char, 32>& buf
) {
static void
draw_target_fixed(tempo::Display& d, const NormalViewModel& vm, std::array<char, 32>& buf) {
std::snprintf(buf.data(), buf.size(), "%ld mV", static_cast<long>(vm.pdo_max_mv));
auto w = d.text_width(buf.data());
d.draw_text(static_cast<uint8_t>(TARGET_RIGHT_X - w), V_TARGET_Y, buf.data());
Expand All @@ -122,9 +136,8 @@ namespace pocketpd {
d.draw_text(static_cast<uint8_t>(TARGET_RIGHT_X - w), A_TARGET_Y, buf.data());
}

static void draw_target_pps(
tempo::Display& d, const NormalViewModel& vm, std::array<char, 32>& buf
) {
static void
draw_target_pps(tempo::Display& d, const NormalViewModel& vm, std::array<char, 32>& buf) {
std::snprintf(buf.data(), buf.size(), "%ld mV", static_cast<long>(vm.target_mv));
auto w = d.text_width(buf.data());
d.draw_text(static_cast<uint8_t>(TARGET_RIGHT_X - w), V_TARGET_Y, buf.data());
Expand Down
20 changes: 20 additions & 0 deletions include/v2/stages/normal_stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace pocketpd {

int8_t m_active_pdo_index = -1;
int8_t m_last_active_index = -1;
bool m_locked = false;
Mode m_mode;

IntervalTimer m_render_interval{40};
Expand All @@ -59,6 +60,10 @@ namespace pocketpd {
return m_active_pdo_index;
}

bool locked() const {
return m_locked;
}

const Mode& mode() const {
return m_mode;
}
Expand Down Expand Up @@ -89,6 +94,8 @@ namespace pocketpd {
}

void on_enter(Conductor&) override {
m_locked = false;

// Turns off output if the profile has changed
if (m_active_pdo_index != m_last_active_index) {
m_output_gate.disable();
Expand Down Expand Up @@ -126,6 +133,15 @@ namespace pocketpd {
void on_event(Conductor& conductor, const Event& event, uint32_t) override {
auto handler = tempo::overloaded{
[&](const ButtonEvent& evt) {
// L+R combo always reachable; must precede lock guard so a locked screen can unlock.
if (evt.lr_long()) {
m_locked = !m_locked;
return;
}
if (m_locked) {
return;
}

if (evt.r_short()) {
m_output_gate.toggle();
return;
Expand All @@ -147,6 +163,9 @@ namespace pocketpd {
}
},
[&](const EncoderEvent& evt) {
if (m_locked) {
return;
}
auto* pps = std::get_if<PPSMode>(&m_mode);
if (pps == nullptr) {
return;
Expand Down Expand Up @@ -225,6 +244,7 @@ namespace pocketpd {
.active_pdo_index = m_active_pdo_index,
.has_profile = m_active_pdo_index >= 0,
.output_enabled = m_output_gate.is_enabled(),
.locked = m_locked,
.arrow_frame = m_arrow_frame,
.snapshot = m_snapshot,
};
Expand Down
Loading
Loading