Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05ea46cbd3 | ||
|
|
63fcfb91ea | ||
|
|
5425b21f00 | ||
|
|
4552fd2b41 | ||
|
|
f8d79b3007 | ||
|
|
b03415fdb8 | ||
|
|
79d8841040 | ||
|
|
fb68ea5608 |
@@ -104,8 +104,40 @@ jobs:
|
||||
cmake --build build/debug --target ds5-bridge
|
||||
cp build/debug/ds5-bridge-oled.uf2 "artifacts/ds5-bridge-oled-debug-${{ github.event.release.tag_name }}.uf2"
|
||||
|
||||
- name: Upload UF2 files to release
|
||||
- name: Compute UF2 checksums + append to release notes
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
# Generate SHA256SUMS.txt next to the UF2s
|
||||
( cd artifacts && sha256sum *.uf2 > SHA256SUMS.txt )
|
||||
cat artifacts/SHA256SUMS.txt
|
||||
# Append the same hashes (markdown-formatted) to the existing release body
|
||||
BODY=$(gh release view "$TAG" --json body --jq .body)
|
||||
{
|
||||
printf '%s\n' "$BODY"
|
||||
printf '\n---\n\n## Checksums\n\n```\n'
|
||||
cat artifacts/SHA256SUMS.txt
|
||||
printf '```\n'
|
||||
} > /tmp/release-notes.md
|
||||
gh release edit "$TAG" --notes-file /tmp/release-notes.md
|
||||
|
||||
- name: Upload UF2 files + SHA256SUMS to release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release upload "${{ github.event.release.tag_name }}" artifacts/*.uf2 --clobber
|
||||
gh release upload "${{ github.event.release.tag_name }}" artifacts/*.uf2 artifacts/SHA256SUMS.txt --clobber
|
||||
|
||||
# Notify the web config repo so its GH Pages deploy rebuilds and
|
||||
# bundles this fresh UF2 into the site. If the WEB_REPO_DISPATCH_PAT
|
||||
# secret isn't configured on this repo, the dispatch call fails 401
|
||||
# and continue-on-error swallows it — the web app keeps serving the
|
||||
# previously-bundled UF2 until its own deploy is manually triggered.
|
||||
- name: Trigger web config rebuild
|
||||
continue-on-error: true
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.WEB_REPO_DISPATCH_PAT }}
|
||||
repository: MarcelineVPQ/DS5Dongle-OLED-Config-Web
|
||||
event-type: firmware-released
|
||||
client-payload: '{"tag": "${{ github.event.release.tag_name }}", "title": "${{ github.event.release.name }}"}'
|
||||
|
||||
@@ -6,6 +6,35 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Version
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
---
|
||||
|
||||
## [0.6.1-oled-edition] — 2026-05-18
|
||||
|
||||
Tagged release of the v0.6.0-oled-edition follow-up. UF2s attached to [the GitHub release](https://github.com/MarcelineVPQ/DS5Dongle-OLED-Edition/releases/tag/v0.6.1-oled-edition) (built by `.github/workflows/release.yml`).
|
||||
|
||||
### Added
|
||||
|
||||
- **CPU / Clock diagnostics screen** (`kScreenCpu`, inserted between Diagnostics and BT Signal in the K0 cycle). Shows the configured system clock (`SYS_CLOCK_KHZ` — the overclock target), the *actually running* `clk_sys` measured live by the RP2350 on-chip frequency counter against the crystal reference, the core voltage read back from the regulator (`vreg_get_voltage()`, not the compile-time constant), and the RP2350 on-die temperature (ADC input 4). Pure read-only instrumentation; one-time ADC bring-up and no other code path uses the ADC, so it is conflict-free. `render_screen_cpu()` is `noinline` like the other render functions (Thumb literal-pool reach). Adds `hardware_adc` to `target_link_libraries`. The frequency-counter measurement (a multi-ms busy-wait) runs **once on screen entry** and is cached — `clk_sys` is fixed at boot, so only the temperature refreshes per frame, avoiding a per-frame BT/audio hitch while the screen is visible. `oled_loop()` gained a generic `screen_entered` flag for this. Hardware-verified on Pico 2 W + OLED. Also exported over a new HID feature report **`0xfc`** (`src/cmd.cpp`) — 11 bytes: set_khz, cached real_khz, vreg code, ADC ch4 raw — so the web config emulator can show live CPU telemetry (volts/temp math done web-side to keep the firmware HID path float-free).
|
||||
|
||||
### Fixed (web telemetry — latent since the slots/diag reports landed)
|
||||
|
||||
- **CPU/Clock temperature was a single noisy ADC sample.** The RP2350 temp sensor has a shallow slope (−1.721 mV/°C, ~1 LSB ≈ 0.47 °C) so a lone 12-bit reading swings several tenths of a degree per frame — the displayed value just mirrored the latest noisy sample instead of the true die temperature. New `cpu_temp_raw_smoothed()` in `src/cmd.cpp` averages a 256-sample block then runs a slow EMA (α=0.15, seeded on first call). It is the **single source of truth**: both `render_screen_cpu()` and the `0xfc` web telemetry call it, and the duplicated per-site ADC bring-up was removed (ADC now initialised in exactly one place). `oled.cpp` no longer touches the ADC directly (drops `hardware/adc.h`, adds `cmd.h`).
|
||||
- **Live web telemetry over WebHID: not feasible on the target setup; abandoned.** A browser-side read-only diagnostic proved Chrome WebHID returns `NotAllowedError` for any report ID **not declared** in the parsed HID report descriptor (declared `0xF7`/`0xF8`/`0xF9` read fine; undeclared `0xFA`/`0xFB`/`0xFC` fail). Declaring them is therefore mandatory for the web read — but doing so (even applied atomically with a matching `wDescriptorLength`, correct bytes identical in shape to the working `0xF6`–`0xF9`, and a `bcdDevice` cache-bust bump) made the device fail to enumerate as a usable HID device on the user's real Windows machine in **two** independent attempts (Device Manager showed it; WebHID and the PlayStation Accessories app did not). The cloned DualSense HID report descriptor cannot be safely extended on this environment. Reverted to the original descriptor (`0x0141`/`0x01B5`, no vendor feature reports, `bcdDevice 0x0100`). Retained with **no USB impact**: the `0xfc` firmware handler and the temperature smoothing/`cpu_temp_raw_smoothed()`. The on-device CPU/Clock OLED screen is fully working and hardware-verified; the web preview's CPU screen stays on representative mock values (the slots/diagnostics web screens were never readable for the same root cause and are likewise mock-only when connected).
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Low-battery LED keeps blinking after controller disconnect** (`fb68ea5`). When the DualSense's battery dropped low enough to trigger `battery_led_tick`'s blink and the controller subsequently disconnected (typically: battery fully depletes and the BT link drops), the Pico's onboard LED stayed frozen in whichever half-cycle it was in at the moment of disconnect; reconnect-retry windows could even briefly resume blinking. New `battery_led_on_disconnect()` clears blink state, forces LED off, and zeros `last_report_us` so the stale-check early-return blocks any new blink until a fresh 0x31 report arrives on the next connection. Stale-check in the tick also now forces LED off when it fires mid-blink (defense in depth for ungraceful disconnects). Reported by Sura Academy on Discord. Same bug present in upstream — sent back as [awalol/DS5Dongle#101](https://github.com/awalol/DS5Dongle/pull/101).
|
||||
|
||||
---
|
||||
|
||||
## [0.6.0-oled-edition] — 2026-05-17
|
||||
|
||||
Tagged release of the rebase below. UF2s attached to [the GitHub release](https://github.com/MarcelineVPQ/DS5Dongle-OLED-Edition/releases/tag/v0.6.0-oled-edition) (built by `.github/workflows/release.yml`). No code changes vs the rebase; tag exists so users can install from a stable artifact.
|
||||
|
||||
---
|
||||
|
||||
## [0.6.0-rebase] — 2026-05-17
|
||||
|
||||
Rebased onto upstream `awalol/DS5Dongle` `v0.6.0-hotfix`. All OLED Edition features preserved with no user-visible regression.
|
||||
|
||||
@@ -171,6 +171,7 @@ target_link_libraries(ds5-bridge
|
||||
hardware_timer
|
||||
hardware_flash
|
||||
hardware_spi
|
||||
hardware_adc
|
||||
pico_btstack_classic
|
||||
# pico_cyw43_arch_threadsafe_background
|
||||
pico_cyw43_arch_poll
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
> Turn a Raspberry Pi Pico2W into a wireless adapter for the DualSense (DS5) controller — with an optional on-board status display.
|
||||
|
||||
> **OLED Edition** is a fork of **[awalol/DS5Dongle](https://github.com/awalol/DS5Dongle)** (upstream) that adds an optional Pico-OLED-1.3 128×64 display add-on with 10 screens (status, 4-slot multi-controller pairing, lightbar color picker with favorites and effect presets, trigger test, gyro tilt, touchpad, diagnostics, BT signal strength, audio VU meters, and a persistent settings menu), plus a DS5 button-combo soft-reboot. Upstream is the authoritative source for the core bridge firmware; this fork tracks it and layers add-on features on top.
|
||||
> **OLED Edition** is a fork of **[awalol/DS5Dongle](https://github.com/awalol/DS5Dongle)** (upstream) that adds an optional Pico-OLED-1.3 128×64 display add-on with 11 screens (status, 4-slot multi-controller pairing, lightbar color picker with favorites and effect presets, trigger test, gyro tilt, touchpad, diagnostics, CPU/clock, BT signal strength, audio VU meters, and a persistent settings menu), plus a DS5 button-combo soft-reboot. Upstream is the authoritative source for the core bridge firmware; this fork tracks it and layers add-on features on top.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -22,7 +22,7 @@ This project enables the Raspberry Pi Pico2W to function as a Bluetooth bridge f
|
||||
|
||||
**OLED Edition additions:**
|
||||
|
||||
- Optional Pico-OLED-1.3 status display with **10 screens** (status, slots, lightbar, trigger test, gyro tilt, touchpad, diagnostics, RSSI, VU meters, settings)
|
||||
- Optional Pico-OLED-1.3 status display with **11 screens** (status, slots, lightbar, trigger test, gyro tilt, touchpad, diagnostics, CPU/clock, RSSI, VU meters, settings)
|
||||
- **4-slot persistent multi-controller pairing** — bond up to four DualSenses, switch between them from the OLED, slot 0 reconnects automatically on boot
|
||||
- **Lightbar color picker** with 4 user favorite slots + breathing / rainbow / fade effect presets
|
||||
- **Persistent settings menu** for the 8 firmware config fields (haptics gain, speaker volume, polling rate, etc.) with hold-to-confirm Reset and Wipe-all-slots actions
|
||||
|
||||
+20
-2
@@ -37,11 +37,29 @@ void battery_led_note_report(void) {
|
||||
last_report_us = time_us_64();
|
||||
}
|
||||
|
||||
void battery_led_on_disconnect(void) {
|
||||
// Stop any in-progress blink and force the LED off immediately. Zero
|
||||
// last_report_us so the tick's stale-check early-returns until a fresh
|
||||
// 0x31 report arrives on the next connection — prevents the cached
|
||||
// low-battery byte from re-arming a blink during reconnect retries.
|
||||
blinking = false;
|
||||
led_state = false;
|
||||
last_report_us = 0;
|
||||
last_toggle_us = 0;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
||||
}
|
||||
|
||||
void battery_led_tick(void) {
|
||||
const uint64_t now = time_us_64();
|
||||
if (last_report_us == 0 || (now - last_report_us) >= REPORT_STALE_US) {
|
||||
// No fresh data — bt.cpp owns the LED while disconnected.
|
||||
blinking = false;
|
||||
// No fresh data — bt.cpp owns the LED while disconnected. If we
|
||||
// were mid-blink when the report went stale, force the LED off
|
||||
// so it doesn't freeze in whichever half-cycle it was in.
|
||||
if (blinking) {
|
||||
blinking = false;
|
||||
led_state = false;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,3 +16,11 @@ void battery_led_tick(void);
|
||||
// has been copied into interrupt_in_data. Used to detect disconnection
|
||||
// via stale-report timeout.
|
||||
void battery_led_note_report(void);
|
||||
|
||||
// Call from the BT disconnect handler. Cancels any in-progress blink,
|
||||
// forces the LED off, and arms the module so it ignores the cached
|
||||
// (now-stale) battery byte until a fresh report arrives on the next
|
||||
// connection. Without this, the LED can stay frozen in whichever state
|
||||
// it was at the moment of disconnect, or briefly resume blinking during
|
||||
// reconnect retries while interrupt_in_data[52] still reads low.
|
||||
void battery_led_on_disconnect(void);
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include "state_mgr.h"
|
||||
#include "pico/util/queue.h"
|
||||
#include "slots.h"
|
||||
#if ENABLE_BATT_LED
|
||||
#include "battery_led.h"
|
||||
#endif
|
||||
|
||||
#define MTU_CONTROL 672
|
||||
#define MTU_INTERRUPT 672
|
||||
@@ -454,6 +457,9 @@ static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
|
||||
hid_interrupt_cid = 0;
|
||||
feature_data.clear();
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
||||
#if ENABLE_BATT_LED
|
||||
battery_led_on_disconnect();
|
||||
#endif
|
||||
printf("[HCI] Disconnected reason=0x%02X, start inquiry\n", reason);
|
||||
gap_inquiry_start(30);
|
||||
break;
|
||||
|
||||
+69
-1
@@ -14,6 +14,39 @@
|
||||
#include "device/usbd.h"
|
||||
#include "pico/time.h"
|
||||
#include "slots.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/adc.h"
|
||||
#include "hardware/vreg.h"
|
||||
|
||||
uint16_t cpu_temp_raw_smoothed() {
|
||||
// One-time ADC bring-up. This is the only place the ADC is initialised
|
||||
// now (oled.cpp's CPU screen calls through here too). Runs on core0
|
||||
// under the cooperative main loop; adc_select_input(4) is set before
|
||||
// every read, so the shared ADC needs no locking.
|
||||
static bool adc_ready = false;
|
||||
if (!adc_ready) {
|
||||
adc_init();
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
adc_ready = true;
|
||||
}
|
||||
adc_select_input(4);
|
||||
|
||||
// The temp sensor has a shallow slope (-1.721 mV/C) and ~1 LSB ≈ 0.47 C,
|
||||
// so a lone 12-bit sample swings several tenths of a degree frame to
|
||||
// frame. Average a big block to kill that...
|
||||
constexpr int kSamples = 256;
|
||||
uint32_t acc = 0;
|
||||
for (int i = 0; i < kSamples; i++) acc += adc_read();
|
||||
const float mean = (float)acc / (float)kSamples;
|
||||
|
||||
// ...then a slow EMA so the displayed value glides to the true die
|
||||
// temperature rather than mirroring the latest block. Seeded on the
|
||||
// first call so it doesn't ramp up from zero.
|
||||
static float ema = -1.0f;
|
||||
if (ema < 0.0f) ema = mean;
|
||||
else ema += (mean - ema) * 0.15f;
|
||||
return (uint16_t)(ema + 0.5f);
|
||||
}
|
||||
|
||||
bool is_pico_cmd(uint8_t report_id) {
|
||||
if (report_id == 0xf6 ||
|
||||
@@ -21,7 +54,8 @@ bool is_pico_cmd(uint8_t report_id) {
|
||||
report_id == 0xf8 ||
|
||||
report_id == 0xf9 ||
|
||||
report_id == 0xfa ||
|
||||
report_id == 0xfb
|
||||
report_id == 0xfb ||
|
||||
report_id == 0xfc
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@@ -93,6 +127,40 @@ uint16_t pico_cmd_get(uint8_t report_id, uint8_t *buffer, uint16_t reqlen) {
|
||||
memcpy(buffer + 14, &hci_errs, 4);
|
||||
return want;
|
||||
}
|
||||
if (report_id == 0xfc) {
|
||||
// OLED Edition: CPU / Clock telemetry for the web emulator. 11 bytes:
|
||||
// [0..3] set_khz uint32 configured clk_sys (SYS_CLOCK_KHZ)
|
||||
// [4..7] real_khz uint32 measured clk_sys (cached, see below)
|
||||
// [8] vcode uint8 vreg_get_voltage() raw enum code
|
||||
// [9..10] temp_raw uint16 ADC ch4 12-bit reading
|
||||
// The web side does the volts/temperature math (same formulas as
|
||||
// render_screen_cpu) so the firmware HID path stays float-free.
|
||||
constexpr uint16_t want = 11;
|
||||
if (reqlen < want) {
|
||||
printf("[HID] 0xfc reqlen=%u too small for cpu payload (%u)\n", reqlen, want);
|
||||
return 0;
|
||||
}
|
||||
const uint32_t set_khz = (uint32_t)SYS_CLOCK_KHZ;
|
||||
|
||||
// clk_sys is fixed at boot and frequency_count_khz() busy-waits a few
|
||||
// ms — measure exactly once (lazily) and cache. Doing it here on the
|
||||
// first poll keeps it off the boot path; one ~ms stall in a single
|
||||
// GET_REPORT is acceptable.
|
||||
static uint32_t cached_real_khz = 0;
|
||||
if (cached_real_khz == 0) {
|
||||
cached_real_khz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
|
||||
}
|
||||
|
||||
const uint16_t temp_raw = cpu_temp_raw_smoothed();
|
||||
|
||||
const uint8_t vcode = (uint8_t)vreg_get_voltage();
|
||||
|
||||
memcpy(buffer + 0, &set_khz, 4);
|
||||
memcpy(buffer + 4, &cached_real_khz, 4);
|
||||
buffer[8] = vcode;
|
||||
memcpy(buffer + 9, &temp_raw, 2);
|
||||
return want;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,4 +11,11 @@ bool is_pico_cmd(uint8_t report_id);
|
||||
uint16_t pico_cmd_get(uint8_t report_id, uint8_t *buffer,uint16_t reqlen);
|
||||
void pico_cmd_set(uint8_t report_id, uint8_t const *buffer,uint16_t bufsize);
|
||||
|
||||
// Smoothed RP2350 on-die temperature sensor reading (ADC input 4, 12-bit
|
||||
// raw). A single sample is very noisy; this averages a large block and runs
|
||||
// a slow EMA so the value converges to the true die temperature instead of
|
||||
// chasing per-sample noise. Single source of truth — the OLED CPU screen and
|
||||
// the 0xfc web telemetry both call this so device and web always agree.
|
||||
uint16_t cpu_temp_raw_smoothed();
|
||||
|
||||
#endif //DS5_BRIDGE_CMD_H
|
||||
|
||||
+70
-4
@@ -10,6 +10,9 @@
|
||||
#include "hardware/spi.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/vreg.h"
|
||||
#include "cmd.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
extern uint8_t interrupt_in_data[63]; // defined in main.cpp
|
||||
@@ -70,10 +73,11 @@ constexpr int kScreenTriggers = 3;
|
||||
constexpr int kScreenGyro = 4;
|
||||
constexpr int kScreenTouchpad = 5;
|
||||
constexpr int kScreenDiag = 6;
|
||||
constexpr int kScreenRssi = 7;
|
||||
constexpr int kScreenVU = 8;
|
||||
constexpr int kScreenSettings = 9;
|
||||
constexpr int kNumScreens = 10;
|
||||
constexpr int kScreenCpu = 7;
|
||||
constexpr int kScreenRssi = 8;
|
||||
constexpr int kScreenVU = 9;
|
||||
constexpr int kScreenSettings = 10;
|
||||
constexpr int kNumScreens = 11;
|
||||
int current_screen = 0;
|
||||
|
||||
// Lightbar mode cycle: 0=LIVE, 1-4=FAV0-3, 5=BREATHING, 6=RAINBOW, 7=FADE
|
||||
@@ -601,6 +605,60 @@ __attribute__((noinline)) void render_screen_diag() {
|
||||
flush_fb();
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void render_screen_cpu(bool entered) {
|
||||
fb_clear();
|
||||
draw_text(0, 0, "CPU / Clock");
|
||||
|
||||
char buf[24];
|
||||
|
||||
// Configured system clock — compile-time SYS_CLOCK_KHZ, set in main()
|
||||
// via set_sys_clock_khz(). This is the *target*.
|
||||
const uint32_t set_khz = (uint32_t)SYS_CLOCK_KHZ;
|
||||
snprintf(buf, sizeof(buf), "Set : %lu MHz", (unsigned long)(set_khz / 1000u));
|
||||
draw_text(0, 12, buf);
|
||||
|
||||
// Actually running clk_sys, measured by the on-chip frequency counter
|
||||
// against the crystal reference (not just what we asked for). The counter
|
||||
// busy-waits a few ms per call, so measure ONCE on screen entry and cache
|
||||
// it — clk_sys is fixed at boot and never changes, so the temperature
|
||||
// (which legitimately drifts) is the only thing worth refreshing per
|
||||
// frame. cached_real_khz==0 also forces a (re)measure as a safety net.
|
||||
static uint32_t cached_real_khz = 0;
|
||||
if (entered || cached_real_khz == 0) {
|
||||
cached_real_khz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
|
||||
}
|
||||
const uint32_t real_khz = cached_real_khz;
|
||||
snprintf(buf, sizeof(buf), "Real: %lu.%01lu MHz",
|
||||
(unsigned long)(real_khz / 1000u),
|
||||
(unsigned long)((real_khz % 1000u) / 100u));
|
||||
draw_text(0, 22, buf);
|
||||
|
||||
// Core voltage actually programmed into the regulator, read back (not the
|
||||
// compile-time constant). Codes 0..15 are linear 0.05 V steps from 0.55 V.
|
||||
const int vcode = (int)vreg_get_voltage();
|
||||
if (vcode >= 0 && vcode <= 0b01111) {
|
||||
const unsigned mv = 550u + 50u * (unsigned)vcode;
|
||||
snprintf(buf, sizeof(buf), "Vcore: %u.%02u V", mv / 1000u, (mv % 1000u) / 10u);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Vcore: code %d", vcode);
|
||||
}
|
||||
draw_text(0, 32, buf);
|
||||
|
||||
// RP2350 on-die temperature sensor. Smoothed + averaged in cmd.cpp
|
||||
// (single source of truth shared with the 0xfc web telemetry) so the
|
||||
// reading converges to the true die temp instead of chasing ADC noise.
|
||||
const uint16_t raw = cpu_temp_raw_smoothed();
|
||||
const float volts = (float)raw * 3.3f / 4096.0f;
|
||||
const float temp_c = 27.0f - (volts - 0.706f) / 0.001721f;
|
||||
const int t10 = (int)(temp_c * 10.0f + (temp_c >= 0 ? 0.5f : -0.5f));
|
||||
snprintf(buf, sizeof(buf), "Temp : %d.%d C", t10 / 10,
|
||||
(t10 < 0 ? -t10 : t10) % 10);
|
||||
draw_text(0, 42, buf);
|
||||
|
||||
draw_text(0, 56, "K0=next K1=back");
|
||||
flush_fb();
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void render_screen_triggers() {
|
||||
fb_clear();
|
||||
draw_text(0, 0, "Trigger Test");
|
||||
@@ -1204,6 +1262,13 @@ void oled_loop() {
|
||||
const bool idle = (now - last_activity_us) > kAutoDimUs;
|
||||
sh1107_set_contrast(idle ? kDimContrast : kBrightLevels[bright_idx]);
|
||||
|
||||
// True on the first render after navigating to a different screen.
|
||||
// Lets a screen do expensive one-shot work on entry (the CPU screen
|
||||
// caches its frequency-counter measurement here).
|
||||
static int last_rendered_screen = -1;
|
||||
const bool screen_entered = (current_screen != last_rendered_screen);
|
||||
last_rendered_screen = current_screen;
|
||||
|
||||
switch (current_screen) {
|
||||
case kScreenStatus: render_screen(); break;
|
||||
case kScreenSlots: render_screen_slots(); break;
|
||||
@@ -1212,6 +1277,7 @@ void oled_loop() {
|
||||
case kScreenGyro: render_screen_gyro(); break;
|
||||
case kScreenTouchpad: render_screen_touchpad(); break;
|
||||
case kScreenDiag: render_screen_diag(); break;
|
||||
case kScreenCpu: render_screen_cpu(screen_entered); break;
|
||||
case kScreenRssi: render_screen_rssi(); break;
|
||||
case kScreenVU: render_screen_vu(); break;
|
||||
case kScreenSettings: render_screen_settings(); break;
|
||||
|
||||
Reference in New Issue
Block a user