diff --git a/.github/workflows/run-unit-tests.yml b/.github/workflows/run-unit-tests.yml index 0c919f842..08e935e4c 100644 --- a/.github/workflows/run-unit-tests.yml +++ b/.github/workflows/run-unit-tests.yml @@ -317,6 +317,7 @@ jobs: python3 -B test/test_sensor_tracker_gps.py -v python3 -B test/test_sensor_tracker_sleep.py -v python3 -B test/test_power_saving_deadlines.py -v + python3 -B test/test_t096_regulator.py -v python3 -B test/test_power_saving_diagnostics.py -v python3 -B test/test_power_saving_role_diagnostics.py -v python3 -B test/test_companion_power_diagnostics.py -v diff --git a/test/test_t096_regulator.py b/test/test_t096_regulator.py new file mode 100644 index 000000000..97c01bd7f --- /dev/null +++ b/test/test_t096_regulator.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""Execute T096 startup and the real DC/DC initializer with counted SDK I/O.""" +from pathlib import Path +import os +import subprocess +import tempfile +import unittest + +from cpp_source import body + +ROOT = Path(__file__).resolve().parents[1] + + +class T096RegulatorTests(unittest.TestCase): + def test_startup_selects_dcdc_before_voltage_check_with_or_without_softdevice(self): + methods = body((ROOT / 'src/helpers/NRF52Board.cpp').read_text(), + 'void NRF52BoardDCDC::begin()') + methods += body((ROOT / 'variants/heltec_t096/T096Board.cpp').read_text(), + 'void T096Board::begin()') + source = r''' +#include +#include +#define NRF52_POWER_MANAGEMENT 1 +#define PIN_BOARD_SDA 1 +#define PIN_BOARD_SCL 2 +constexpr int OUTPUT = 1, LOW = 0, P_LORA_TX_LED = 28; +constexpr int NRF_POWER_DCDC_ENABLE = 1; +static unsigned base_calls, sdk_calls, voltage_checks; +static uint8_t softdevice; +struct Power { unsigned DCDCEN; } power; +#define NRF_POWER (&power) +namespace mesh_nrf52 { +void softdeviceIsEnabled(uint8_t& enabled) { enabled = softdevice; } +} +void sd_power_dcdc_mode_set(int mode) { + assert(softdevice && mode == NRF_POWER_DCDC_ENABLE); + ++sdk_calls; +} +void pinMode(int, int) {} +void digitalWrite(int, int) {} +void delay(unsigned) {} +struct Bus { void setPins(int, int) {} void begin() {} } Wire; +struct Peripheral { void begin() {} void init() {} }; +struct Config {} power_config; +struct NRF52Board { void begin() { ++base_calls; } }; +struct NRF52BoardDCDC : NRF52Board { void begin(); }; +struct T096Board : NRF52BoardDCDC { + Peripheral periph_power, loRaFEMControl; + void begin(); + void checkBootVoltage(const Config*) { + ++voltage_checks; + assert(softdevice ? sdk_calls == 1 : power.DCDCEN == 1); + } +}; +@METHODS@ +int main() { + for (softdevice = 0; softdevice < 2; ++softdevice) { + power.DCDCEN = base_calls = sdk_calls = voltage_checks = 0; + T096Board board; + board.begin(); + assert(base_calls == 1 && voltage_checks == 1); + assert(sdk_calls == softdevice); + assert(power.DCDCEN == (softdevice ? 0U : 1U)); + } +} +''' + with tempfile.TemporaryDirectory(prefix='meshcore-t096-regulator-') as tmp: + cpp, binary = Path(tmp) / 'test.cpp', Path(tmp) / 'test' + cpp.write_text(source.replace('@METHODS@', methods), encoding='ascii') + subprocess.run([os.environ.get('CXX', 'c++'), '-std=c++17', + '-Wall', '-Wextra', '-Werror', str(cpp), '-o', str(binary)], + check=True, capture_output=True, text=True, timeout=60) + result = subprocess.run([str(binary)], capture_output=True, text=True, timeout=10) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + + +if __name__ == '__main__': + unittest.main() diff --git a/variants/heltec_t096/T096Board.cpp b/variants/heltec_t096/T096Board.cpp index f46481f88..2d87d11a9 100644 --- a/variants/heltec_t096/T096Board.cpp +++ b/variants/heltec_t096/T096Board.cpp @@ -33,7 +33,9 @@ void T096Board::initiateShutdown(uint8_t reason) { #endif // NRF52_POWER_MANAGEMENT void T096Board::begin() { - NRF52Board::begin(); + // T096 populates the nRF52840 DC/DC network. Do not bypass the regulator + // initializer and leave application efficiency dependent on bootloader state. + NRF52BoardDCDC::begin(); #ifdef NRF52_POWER_MANAGEMENT // Boot voltage protection check (may not return if voltage too low)