Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Battery Status Display to Session View 🔋🪫 #3310

Draft
wants to merge 57 commits into
base: community
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
a76d2f6
Battery level indicator, wip
m0nkmaster Jan 19, 2025
9b2476e
Merge remote-tracking branch 'origin/community' into power-level
m0nkmaster Jan 19, 2025
b9fe4c3
Refactor battery status display logic
m0nkmaster Jan 19, 2025
23e88dc
Added displayPotentialBatteryChange method to ensure the display upda…
m0nkmaster Jan 19, 2025
1b59e0d
Re-add makeBattLEDSolid:
m0nkmaster Jan 19, 2025
8ddef37
Removed duplicate drawBatteryStatus from oled.cpp and added back some…
m0nkmaster Jan 19, 2025
42bf0bc
Clean up
m0nkmaster Jan 19, 2025
f2b668c
Revert OLED display positioning
m0nkmaster Jan 19, 2025
9688eaa
renamed drawBatteryStatus to displayBatteryStatus, added displayPoten…
m0nkmaster Jan 20, 2025
f9807ae
Better battery UI
m0nkmaster Jan 20, 2025
ee1b12f
Farting about with battery icons.
m0nkmaster Jan 20, 2025
deb6983
Battery formatting
m0nkmaster Jan 20, 2025
80e823c
Battery alignment
m0nkmaster Jan 20, 2025
4ed4196
Battery alignment
m0nkmaster Jan 20, 2025
e593b7e
Battery alignment
m0nkmaster Jan 20, 2025
4504444
Power
m0nkmaster Jan 20, 2025
36a7e14
Use batteryCurrentRegion to drive battery power icon
m0nkmaster Jan 20, 2025
6ff7419
Use batteryCurrentRegion to drive battery power icon
m0nkmaster Jan 20, 2025
a5bff63
Minor spacing
m0nkmaster Jan 20, 2025
14d82b6
Minor spacing
m0nkmaster Jan 20, 2025
00130d9
Minor spacing
m0nkmaster Jan 20, 2025
5610514
Alter battery thresholds
m0nkmaster Jan 20, 2025
ab94d29
Refactor battery status display in SessionView: Adjusted spacing for …
m0nkmaster Jan 20, 2025
912025b
USB power check
m0nkmaster Jan 20, 2025
57356bf
Add USB power status check
m0nkmaster Jan 20, 2025
21f6447
improve comments and remove unused variable.
m0nkmaster Jan 20, 2025
f8a4d62
USB power check
m0nkmaster Jan 21, 2025
2a7707e
Battery level indicator, wip
m0nkmaster Jan 19, 2025
32c4ec1
Refactor battery status display logic
m0nkmaster Jan 19, 2025
ffea187
Added displayPotentialBatteryChange method to ensure the display upda…
m0nkmaster Jan 19, 2025
5061ae4
Re-add makeBattLEDSolid:
m0nkmaster Jan 19, 2025
c625409
Removed duplicate drawBatteryStatus from oled.cpp and added back some…
m0nkmaster Jan 19, 2025
9113638
Clean up
m0nkmaster Jan 19, 2025
a456acc
Revert OLED display positioning
m0nkmaster Jan 19, 2025
a9e188f
renamed drawBatteryStatus to displayBatteryStatus, added displayPoten…
m0nkmaster Jan 20, 2025
dfd4cce
Better battery UI
m0nkmaster Jan 20, 2025
efcda76
Farting about with battery icons.
m0nkmaster Jan 20, 2025
b0f21a8
Battery formatting
m0nkmaster Jan 20, 2025
fe2b010
Battery alignment
m0nkmaster Jan 20, 2025
a48c3a6
Battery alignment
m0nkmaster Jan 20, 2025
ec20e13
Battery alignment
m0nkmaster Jan 20, 2025
2d0b2b5
Power
m0nkmaster Jan 20, 2025
f3e2c77
Use batteryCurrentRegion to drive battery power icon
m0nkmaster Jan 20, 2025
fc5174f
Use batteryCurrentRegion to drive battery power icon
m0nkmaster Jan 20, 2025
98ae6ec
Minor spacing
m0nkmaster Jan 20, 2025
82b5bad
Minor spacing
m0nkmaster Jan 20, 2025
c80e971
Minor spacing
m0nkmaster Jan 20, 2025
47b182c
Alter battery thresholds
m0nkmaster Jan 20, 2025
b249ed3
Refactor battery status display in SessionView: Adjusted spacing for …
m0nkmaster Jan 20, 2025
8e29114
USB power check
m0nkmaster Jan 20, 2025
79a6a94
Add USB power status check
m0nkmaster Jan 20, 2025
98bb748
improve comments and remove unused variable.
m0nkmaster Jan 20, 2025
744e530
USB power check
m0nkmaster Jan 21, 2025
74b22b1
Merge branch 'power-level' of github.com:m0nkmaster/DelugeFirmware in…
m0nkmaster Jan 23, 2025
32d9197
Merge branch 'SynthstromAudible:community' into power-level
m0nkmaster Jan 23, 2025
8ab6085
Created a power manager class to handle all voltage reading
m0nkmaster Jan 24, 2025
f490d21
Latest changes to battery calculations
m0nkmaster Jan 24, 2025
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
16 changes: 12 additions & 4 deletions src/deluge/deluge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,15 @@ void inputRoutine() {
// We only >> by 15 so that we intentionally double the value, because the incoming voltage is halved by a
// resistive divider already
batteryMV = (voltageReadingLastTime) >> 15;
// D_PRINT("batt mV: ");
// D_PRINTLN(batteryMV);

// See if we've reached threshold to change verdict on battery level
int32_t newBatteryMV = batteryMV;

// Update battery display if voltage has changed significantly
// TODO: Do we need this, can it be self-contained in session_view?
sessionView.displayPotentialBatteryChange(newBatteryMV);
Copy link
Collaborator

@seangoodvibes seangoodvibes Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably don't need it here as I see you already have it in session view :: graphics routine



// See if we've reached threshold to change verdict on battery level
if (batteryCurrentRegion == 0) {
if (batteryMV > 2950) {
makeBattLEDSolid:
Expand All @@ -183,7 +187,11 @@ void inputRoutine() {
batteryCurrentRegion = 0;
batteryLEDBlink();
}

else if (batteryMV > 3800) {
batteryCurrentRegion = 3;
setOutputState(BATTERY_LED.port, BATTERY_LED.pin, true);
uiTimerManager.unsetTimer(TimerName::BATT_LED_BLINK);
}
else if (batteryMV > 3300) {
batteryCurrentRegion = 2;
setOutputState(BATTERY_LED.port, BATTERY_LED.pin, true);
Expand Down
2 changes: 2 additions & 0 deletions src/deluge/deluge.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ extern const size_t l10n_STRING_FOR_USB_DEVICE_NOT_RECOGNIZED;

char const* l10n_get(size_t s);

extern uint8_t batteryCurrentRegion;

#ifdef __cplusplus
}
#endif
77 changes: 76 additions & 1 deletion src/deluge/gui/views/session_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "gui/views/session_view.h"
#include "definitions_cxx.hpp"
#include "deluge/hid/usb_check.h"
#include "dsp/compressor/rms_feedback.h"
#include "extern.h"
#include "gui/colour/colour.h"
Expand Down Expand Up @@ -91,6 +92,9 @@ extern "C" {
using namespace deluge;
using namespace gui;

extern uint16_t batteryMV; // Battery voltage in millivolts
extern uint8_t batteryCurrentRegion; // Battery level (0-3)

SessionView sessionView{};

SessionView::SessionView() {
Expand Down Expand Up @@ -1889,7 +1893,6 @@ void SessionView::renderOLED(deluge::hid::display::oled_canvas::Canvas& canvas)
stemExport.displayStemExportProgressOLED(StemExportType::CLIP);
return;
}

UI* currentUI = getCurrentUI();
if (currentUIMode == UI_MODE_CLIP_PRESSED_IN_SONG_VIEW) {
view.displayOutputName(getCurrentClip()->output, true, getCurrentClip());
Expand Down Expand Up @@ -2026,6 +2029,9 @@ void SessionView::renderViewDisplay() {
int32_t yPos = OLED_MAIN_TOPMOST_PIXEL + 3;
#endif

// Draw battery status
displayBatteryStatus(canvas, false);

DEF_STACK_STRING_BUF(tempoBPM, 10);
lastDisplayedTempo = playbackHandler.calculateBPM(playbackHandler.getTimePerInternalTickFloat());
playbackHandler.getTempoStringForOLED(lastDisplayedTempo, tempoBPM);
Expand Down Expand Up @@ -2083,6 +2089,59 @@ void SessionView::displayTempoBPM(deluge::hid::display::oled_canvas::Canvas& can
canvas.drawGraphicMultiLine(deluge::hid::display::OLED::metronomeIcon, metronomeIconStartX, yPos, 7);
}

void SessionView::displayBatteryStatus(deluge::hid::display::oled_canvas::Canvas& canvas, bool clearArea) {
int32_t x = 0;
int32_t y = OLED_MAIN_TOPMOST_PIXEL + 4;

// Check if USB power is connected. Must be a better way to do this than just checking the battery voltage.
bool usbPowerConnected = (batteryMV > 4600);

int32_t batteryPercent = (batteryMV - BATTERY_MV_MIN) * 100 / (BATTERY_MV_MAX - BATTERY_MV_MIN);

// Battery icon dimensions
int32_t iconWidth = 12; // Main body width
int32_t iconHeight = 7;
int32_t iconSpacing = 3;

if (clearArea) {
// Calculate exact text width for max "100%" (4 chars)
// TODO - 11 for now - to also show mV value
int32_t maxTextWidth = kTextSpacingX * 11;
canvas.clearAreaExact(x, y, x + iconWidth + 1 + iconSpacing + maxTextWidth, y + iconHeight);
}

// Draw battery outline
canvas.drawRectangle(x, y, x + iconWidth - 1, y + iconHeight - 1); // Body (11x7)
canvas.drawRectangle(iconWidth - 1, y + 2, iconWidth, y + 5); // Terminal (1x3)

// When USB power is connected, show charging arrows pattern
if (usbPowerConnected) {
// Draw three arrow patterns using checkerboard pixels
for (int32_t i = 0; i < 3; i++) {
int32_t baseX = x + 2 + (i * 3);
// Three pixel arrow
canvas.drawPixel(baseX, y + 2); // Top pixel
canvas.drawPixel(baseX + 1, y + 3); // Middle pixel
canvas.drawPixel(baseX, y + 4); // Bottom pixel
}

// When USB connected, just show "USB" text
canvas.drawString("USB", x + iconWidth + iconSpacing, y - 1, kTextSpacingX, kTextSpacingY);
}
// Or show battery segments based on battery level (0-3)
else if (batteryCurrentRegion > 0) {
for (int32_t i = 0; i < batteryCurrentRegion; i++) {
int32_t segmentX = x + 2 + (i * 3); // 2px segment + 1px gap
canvas.drawRectangle(segmentX, y + 2, segmentX + 1, y + 4); // 2px wide, 3px tall
}

// Draw percentage text only when on battery power
char text[16];
snprintf(text, sizeof(text), "%d%% %dmV", batteryPercent, batteryMV);
canvas.drawString(text, x + iconWidth + iconSpacing, y - 1, kTextSpacingX, kTextSpacingY);
}
}

void SessionView::displayCurrentRootNoteAndScaleName(deluge::hid::display::oled_canvas::Canvas& canvas,
StringBuf& rootNoteAndScaleName, bool clearArea) {

Expand Down Expand Up @@ -2195,6 +2254,7 @@ void SessionView::graphicsRoutine() {

if (display->haveOLED()) {
displayPotentialTempoChange(this);
displayPotentialBatteryChange(batteryMV);
}

bool reallyNoTickSquare = (!playbackHandler.isEitherClockActive() || currentUIMode == UI_MODE_EXPLODE_ANIMATION
Expand Down Expand Up @@ -2344,6 +2404,7 @@ void SessionView::graphicsRoutine() {
// checks if tempo has changed since it was last rendered on the display and updates it if required
void SessionView::displayPotentialTempoChange(UI* ui) {
// check UI in case graphics routine is called while we're in another UI (e.g. menu)

if (getCurrentUI() == ui) {
float tempo = playbackHandler.calculateBPMForDisplay();
float diff = std::abs(tempo - lastDisplayedTempo);
Expand All @@ -2358,6 +2419,20 @@ void SessionView::displayPotentialTempoChange(UI* ui) {
}
}

// checks if battery voltage has changed and updates it if required
void SessionView::displayPotentialBatteryChange(uint16_t newBatteryMV) {
// Only update display if we're in the session view

if (getCurrentUI() == this) {
// Only redraw display if voltage has changed significantly (50mV roughly 5% of full scale)
if (abs(newBatteryMV - lastDisplayedBatteryMV) > 50) {
lastDisplayedBatteryMV = newBatteryMV;
displayBatteryStatus(deluge::hid::display::OLED::main);
deluge::hid::display::OLED::markChanged();
}
}
}

/// display number of bars or quarter notes remaining until a launch event
int32_t SessionView::displayLoopsRemainingPopup(bool ephemeral) {
int32_t sixteenthNotesRemaining = session.getNumSixteenthNotesRemainingTilLaunch();
Expand Down
10 changes: 10 additions & 0 deletions src/deluge/gui/views/session_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ constexpr uint32_t kGridHeight = kDisplayHeight;

class SessionView final : public ClipNavigationTimelineView {
public:
static constexpr int BATTERY_MV_MAX = 4200; // 4.2V fully charged
static constexpr int BATTERY_MV_MIN = 2900; // 2.9V cutoff voltage

SessionView();
bool getGreyoutColsAndRows(uint32_t* cols, uint32_t* rows) override;
bool opened() override;
Expand Down Expand Up @@ -147,6 +150,10 @@ class SessionView final : public ClipNavigationTimelineView {
void displayTempoBPM(deluge::hid::display::oled_canvas::Canvas& canvas, StringBuf& tempoBPM, bool clearArea);
float lastDisplayedTempo = 0;

// display battery status
void displayPotentialBatteryChange(uint16_t newBatteryMV);
uint16_t lastDisplayedBatteryMV = 0;

// display root note and scale name
void displayCurrentRootNoteAndScaleName(deluge::hid::display::oled_canvas::Canvas& canvas,
StringBuf& rootNoteAndScaleName, bool clearArea);
Expand All @@ -155,6 +162,9 @@ class SessionView final : public ClipNavigationTimelineView {
// convert instrument clip to audio clip
void replaceInstrumentClipWithAudioClip(Clip* clip);

// Draw battery status
void displayBatteryStatus(deluge::hid::display::oled_canvas::Canvas& canvas, bool clearArea = true);

private:
// These and other (future) commandXXX methods perform actions triggered by HID, but contain
// no dispatch logic.
Expand Down
8 changes: 8 additions & 0 deletions src/deluge/hid/usb_check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "RZA1/usb/r_usb_basic/r_usb_basic_if.h"
#include "RZA1/usb/r_usb_basic/src/driver/inc/r_usb_basic_define.h"
#include "RZA1/usb/r_usb_basic/src/driver/inc/r_usb_extern.h"

uint16_t check_usb_power_status(void) {
uint16_t status = usb_pstd_chk_vbsts();
return status;
}
13 changes: 13 additions & 0 deletions src/deluge/hid/usb_check.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

uint16_t check_usb_power_status(void);

#define USB_POWER_ATTACHED 0x0040u

#ifdef __cplusplus
}
#endif