feat(q5_max): add CMD_BATTERY HID push and query for wireless battery level
Adds a new HID_CMD_BATTERY (0x44) command to the shared qmk-host protocol. When the keyboard is in wireless transport mode (BT or 2.4G) the firmware now pushes the current battery percentage to the host: - Periodic push every 5 minutes via timer_read32()/timer_elapsed32(); fires immediately on the first matrix_scan_user() call after boot so qmk-host gets a reading as soon as the keyboard connects over USB in wireless mode. - Redundant sends are suppressed: g_last_sent_bat tracks the last value transmitted and the packet is skipped when the level has not changed. - Query-response path: qmk-host can send CMD_BATTERY with HID_FLAG_QUERY at any time; the keyboard replies with the current percentage or HID_BATT_UNAVAILABLE (0xFF) when in USB transport mode. - All battery and transport code is guarded by #ifdef LK_WIRELESS_ENABLE so the keymap compiles cleanly on any wired-only build. Firmware size delta: +160 bytes (well within flash budget).
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
#define HID_CMD_VOLUME 0x41u // System volume level (host → keyboard)
|
#define HID_CMD_VOLUME 0x41u // System volume level (host → keyboard)
|
||||||
#define HID_CMD_BRIGHTNESS 0x42u // Screen brightness level (host → keyboard)
|
#define HID_CMD_BRIGHTNESS 0x42u // Screen brightness level (host → keyboard)
|
||||||
#define HID_CMD_ACTIVE_APP 0x43u // Active window/app name (reserved — future)
|
#define HID_CMD_ACTIVE_APP 0x43u // Active window/app name (reserved — future)
|
||||||
|
#define HID_CMD_BATTERY 0x44u // Battery level (keyboard → host; wireless mode only)
|
||||||
#define HID_CMD_ACK 0x7Eu // Generic acknowledgement
|
#define HID_CMD_ACK 0x7Eu // Generic acknowledgement
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -80,6 +81,15 @@
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
#define HID_APP_NAME_MAX 28u
|
#define HID_APP_NAME_MAX 28u
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// HID_CMD_BATTERY payload
|
||||||
|
// [0] Battery percentage 0-100, or HID_BATT_UNAVAILABLE when the keyboard
|
||||||
|
// is in USB transport mode (battery reading not meaningful / charging).
|
||||||
|
// Keyboard only sends this packet when get_transport() & TRANSPORT_WIRELESS.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
#define HID_BATT_OFF_LEVEL 0u // Payload byte 0: percentage (0-100)
|
||||||
|
#define HID_BATT_UNAVAILABLE 0xFFu // Sentinel: not in wireless mode
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Packet size
|
// Packet size
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
#include "raw_hid.h"
|
#include "raw_hid.h"
|
||||||
#include "keychron_raw_hid.h"
|
#include "keychron_raw_hid.h"
|
||||||
#include "hid_protocol.h"
|
#include "hid_protocol.h"
|
||||||
|
#ifdef LK_WIRELESS_ENABLE
|
||||||
|
# include "battery.h"
|
||||||
|
# include "transport.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Tap Dance declarations
|
// Tap Dance declarations
|
||||||
enum {
|
enum {
|
||||||
@@ -77,6 +81,34 @@ static uint8_t g_last_sent_layer = 0xFF;
|
|||||||
static uint8_t g_hid_volume = 0;
|
static uint8_t g_hid_volume = 0;
|
||||||
static uint8_t g_hid_brightness = 0;
|
static uint8_t g_hid_brightness = 0;
|
||||||
|
|
||||||
|
// Battery reporting state (wireless mode only).
|
||||||
|
// Pushes the current percentage every BAT_REPORT_INTERVAL_MS ms.
|
||||||
|
// Suppresses redundant sends when the level hasn't changed.
|
||||||
|
#ifdef LK_WIRELESS_ENABLE
|
||||||
|
# define BAT_REPORT_INTERVAL_MS 300000U // 5 minutes
|
||||||
|
static uint32_t g_bat_timer = 0;
|
||||||
|
static bool g_bat_sent_once = false;
|
||||||
|
static uint8_t g_last_sent_bat = HID_BATT_UNAVAILABLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Send the current battery percentage to the host.
|
||||||
|
// Only fires when get_transport() & TRANSPORT_WIRELESS; no-op otherwise.
|
||||||
|
// Suppresses sends when the level matches the last value sent.
|
||||||
|
#ifdef LK_WIRELESS_ENABLE
|
||||||
|
static void hid_send_battery(void) {
|
||||||
|
if (!(get_transport() & TRANSPORT_WIRELESS)) return;
|
||||||
|
uint8_t level = battery_get_percentage();
|
||||||
|
if (level == g_last_sent_bat) return;
|
||||||
|
g_last_sent_bat = level;
|
||||||
|
uint8_t data[HID_PACKET_SIZE] = {0};
|
||||||
|
data[HID_OFF_CMD] = HID_CMD_BATTERY;
|
||||||
|
data[HID_OFF_SRC] = HID_DEV_Q5MAX;
|
||||||
|
data[HID_OFF_FLAGS] = 0;
|
||||||
|
data[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] = level;
|
||||||
|
raw_hid_send(data, HID_PACKET_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Send the current layer state to the host / bridge application.
|
// Send the current layer state to the host / bridge application.
|
||||||
static void hid_send_layer_sync(uint8_t layer, uint8_t locked_mask) {
|
static void hid_send_layer_sync(uint8_t layer, uint8_t locked_mask) {
|
||||||
uint8_t data[HID_PACKET_SIZE] = {0};
|
uint8_t data[HID_PACKET_SIZE] = {0};
|
||||||
@@ -151,6 +183,26 @@ bool kc_raw_hid_rx_kb(uint8_t *data, uint8_t length) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case HID_CMD_BATTERY: {
|
||||||
|
// Host is querying the current battery level.
|
||||||
|
// Reply with the current percentage when in wireless mode, or
|
||||||
|
// HID_BATT_UNAVAILABLE when wired (USB transport / not meaningful).
|
||||||
|
uint8_t resp[HID_PACKET_SIZE] = {0};
|
||||||
|
resp[HID_OFF_CMD] = HID_CMD_BATTERY;
|
||||||
|
resp[HID_OFF_SRC] = HID_DEV_Q5MAX;
|
||||||
|
resp[HID_OFF_FLAGS] = HID_FLAG_RESPONSE;
|
||||||
|
#ifdef LK_WIRELESS_ENABLE
|
||||||
|
resp[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] =
|
||||||
|
(get_transport() & TRANSPORT_WIRELESS)
|
||||||
|
? battery_get_percentage()
|
||||||
|
: HID_BATT_UNAVAILABLE;
|
||||||
|
#else
|
||||||
|
resp[HID_PAYLOAD(HID_BATT_OFF_LEVEL)] = HID_BATT_UNAVAILABLE;
|
||||||
|
#endif
|
||||||
|
raw_hid_send(resp, HID_PACKET_SIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -423,6 +475,17 @@ void matrix_scan_user(void) {
|
|||||||
alt_tab_active = false;
|
alt_tab_active = false;
|
||||||
}
|
}
|
||||||
chord_scan();
|
chord_scan();
|
||||||
|
|
||||||
|
#ifdef LK_WIRELESS_ENABLE
|
||||||
|
// Push battery level to host every BAT_REPORT_INTERVAL_MS when wireless.
|
||||||
|
// First call fires immediately (g_bat_sent_once == false) so the host gets
|
||||||
|
// a reading as soon as the keyboard connects over USB in wireless mode.
|
||||||
|
if (!g_bat_sent_once || timer_elapsed32(g_bat_timer) >= BAT_REPORT_INTERVAL_MS) {
|
||||||
|
g_bat_sent_once = true;
|
||||||
|
g_bat_timer = timer_read32();
|
||||||
|
hid_send_battery();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// RGB Matrix Indicators --------------------------------------------------
|
// RGB Matrix Indicators --------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user