Skip to content
Open
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
12 changes: 8 additions & 4 deletions docs/companion_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,11 +587,12 @@ def parse_device_info(data):
**PACKET_BATTERY** (0x0C):
```
Byte 0: 0x0C
Bytes 1-2: Battery Level (16-bit little-endian, percentage 0-100)
Bytes 1-2: Battery Milli Volts (16-bit little-endian)

Optional (if data size > 3):
Bytes 3-6: Used Storage (32-bit little-endian, KB)
Bytes 7-10: Total Storage (32-bit little-endian, KB)
Bytes 11: Charging/External Power Flag (uint8, 0=no, 1=yes)
```

**Parsing Pseudocode**:
Expand All @@ -600,15 +601,18 @@ def parse_battery(data):
if len(data) < 3:
return None

level = int.from_bytes(data[1:3], 'little')
info = {'level': level}
milli_volts = int.from_bytes(data[1:3], 'little')
info = {'milli_volts': milli_volts}

if len(data) > 3:
if len(data) >= 11:
used_kb = int.from_bytes(data[3:7], 'little')
total_kb = int.from_bytes(data[7:11], 'little')
info['used_kb'] = used_kb
info['total_kb'] = total_kb

if len(data) >= 12:
info['is_charging'] = data[11] == 1

return info
```

Expand Down
29 changes: 28 additions & 1 deletion examples/companion_radio/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <Arduino.h> // needed for PlatformIO
#include <Mesh.h>
#if defined(NRF52_PLATFORM)
#include <nrf.h>
#include <nrf_soc.h>
#endif

#define CMD_APP_START 1
#define CMD_SEND_TXT_MSG 2
Expand Down Expand Up @@ -1309,15 +1313,38 @@ void MyMesh::handleCmdFrame(size_t len) {
}
board.reboot();
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
uint8_t reply[11];
uint8_t reply[12];
int i = 0;
reply[i++] = RESP_CODE_BATT_AND_STORAGE;
uint16_t battery_millivolts = board.getBattMilliVolts();
uint32_t used = _store->getStorageUsedKb();
uint32_t total = _store->getStorageTotalKb();
// Optional extra byte for companion clients:
// 0 = not externally powered, 1 = externally powered/charging source present.
bool external_powered = board.isExternalPowered();
#if defined(NRF52_PLATFORM)
uint8_t sd_enabled = 0;
sd_softdevice_is_enabled(&sd_enabled);
uint32_t usb_status = 0;
if (sd_enabled) {
sd_power_usbregstatus_get(&usb_status);
} else {
usb_status = NRF_POWER->USBREGSTATUS;
}

// Some nRF52 boards report VBUS correctly in USBREGSTATUS while
// board.isExternalPowered() may still resolve false in practice.
uint32_t usb_power_mask = POWER_USBREGSTATUS_VBUSDETECT_Msk;
#ifdef POWER_USBREGSTATUS_OUTPUTRDY_Msk
usb_power_mask |= POWER_USBREGSTATUS_OUTPUTRDY_Msk;
#endif
external_powered = external_powered || ((usb_status & usb_power_mask) != 0);
#endif
uint8_t is_charging = external_powered ? 1 : 0;
memcpy(&reply[i], &battery_millivolts, 2); i += 2;
memcpy(&reply[i], &used, 4); i += 4;
memcpy(&reply[i], &total, 4); i += 4;
reply[i++] = is_charging;
_serial->writeFrame(reply, i);
} else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) {
#if ENABLE_PRIVATE_KEY_EXPORT
Expand Down
9 changes: 7 additions & 2 deletions src/helpers/NRF52Board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,21 @@ void NRF52Board::initPowerMgr() {
}

bool NRF52Board::isExternalPowered() {
uint32_t usb_power_mask = POWER_USBREGSTATUS_VBUSDETECT_Msk;
#ifdef POWER_USBREGSTATUS_OUTPUTRDY_Msk
usb_power_mask |= POWER_USBREGSTATUS_OUTPUTRDY_Msk;
#endif

// Check if SoftDevice is enabled before using its API
uint8_t sd_enabled = 0;
sd_softdevice_is_enabled(&sd_enabled);

if (sd_enabled) {
uint32_t usb_status;
sd_power_usbregstatus_get(&usb_status);
return (usb_status & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0;
return (usb_status & usb_power_mask) != 0;
} else {
return (NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0;
return (NRF_POWER->USBREGSTATUS & usb_power_mask) != 0;
}
}

Expand Down
21 changes: 20 additions & 1 deletion variants/t1000-e/T1000eBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,23 @@ void T1000eBoard::begin() {
Wire.begin();

delay(10); // give sx1262 some time to power up
}
}

bool T1000eBoard::isExternalPowered() {
// T1000-E exposes dedicated detect lines for external power and charge state.
// Use these first, then fall back to NRF52 USB VBUS detection.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does NRF52 fallback provide us with anything? Wouldn't it always be false currently? :)

bool externalPowerDetected = false;
bool chargingDetected = false;

#ifdef EXT_PWR_DETECT
// EXT_PWR_DETECT is high when external power rail is present.
externalPowerDetected = digitalRead(EXT_PWR_DETECT) == HIGH;
#endif

#ifdef EXT_CHRG_DETECT
// Charge detect is typically active-low on PMIC status lines.
chargingDetected = digitalRead(EXT_CHRG_DETECT) == LOW;
#endif

return externalPowerDetected || chargingDetected || NRF52Board::isExternalPowered();
}
1 change: 1 addition & 0 deletions variants/t1000-e/T1000eBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class T1000eBoard : public NRF52BoardDCDC {
public:
T1000eBoard() : NRF52Board("T1000E_OTA") {}
void begin();
bool isExternalPowered() override;

uint16_t getBattMilliVolts() override {
#ifdef BATTERY_PIN
Expand Down