Omit unsupported regulator vtable slots on integrated STM32WL
This commit is contained in:
1 parent
758004373d
commit
a886f618f1
6 files changed
+133
-15
No files matched your search
+4
-4
@@ -37,12 +37,12 @@ public:
|
||||
*/
|
||||
class Radio {
|
||||
public:
|
||||
virtual uint8_t regulatorModes() const { return 0; }
|
||||
virtual power::RegulatorMode defaultRegulatorMode() const { return power::RegulatorMode::Default; }
|
||||
MESH_REGULATOR_VIRTUAL uint8_t regulatorModes() const { return 0; }
|
||||
MESH_REGULATOR_VIRTUAL power::RegulatorMode defaultRegulatorMode() const { return power::RegulatorMode::Default; }
|
||||
// Cache a selection before the first hardware initialization. Save later
|
||||
// choices for the next reboot; never change a live RX/TX regulator here.
|
||||
virtual bool configureBootRegulator(power::RegulatorMode) { return false; }
|
||||
virtual power::RegulatorMode activeRegulatorMode() const { return power::RegulatorMode::Default; }
|
||||
MESH_REGULATOR_VIRTUAL bool configureBootRegulator(power::RegulatorMode) { return false; }
|
||||
MESH_REGULATOR_VIRTUAL power::RegulatorMode activeRegulatorMode() const { return power::RegulatorMode::Default; }
|
||||
static constexpr uint32_t CarrierWaveDefaultMillis = 10000;
|
||||
static constexpr uint32_t CarrierWaveMaxMillis = 60000;
|
||||
virtual bool supportsCarrierWave() const { return false; }
|
||||
|
||||
+4
-4
@@ -146,12 +146,12 @@ public:
|
||||
virtual void onBeforeTransmit() { }
|
||||
virtual void onAfterTransmit() { }
|
||||
virtual void reboot() = 0;
|
||||
virtual uint8_t mcuRegulatorModes() const { return 0; }
|
||||
virtual power::RegulatorMode defaultMcuRegulatorMode() const {
|
||||
MESH_REGULATOR_VIRTUAL uint8_t mcuRegulatorModes() const { return 0; }
|
||||
MESH_REGULATOR_VIRTUAL power::RegulatorMode defaultMcuRegulatorMode() const {
|
||||
return power::RegulatorMode::Default;
|
||||
}
|
||||
virtual bool applyMcuRegulator(power::RegulatorMode) { return false; }
|
||||
virtual power::RegulatorMode activeMcuRegulatorMode() const {
|
||||
MESH_REGULATOR_VIRTUAL bool applyMcuRegulator(power::RegulatorMode) { return false; }
|
||||
MESH_REGULATOR_VIRTUAL power::RegulatorMode activeMcuRegulatorMode() const {
|
||||
return power::RegulatorMode::Default;
|
||||
}
|
||||
// Reboot into a UF2-capable bootloader when the platform supports the
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
// The current integrated STM32WL driver has no selectable supply domain:
|
||||
// MCU and radio share a regulator and need coordinated support first. Keep
|
||||
// its unsupported defaults out of every board/radio vtable as well as the
|
||||
// settings implementation. Other drivers/platforms retain virtual dispatch.
|
||||
#define MESH_REGULATOR_FIXED_RADIO_CustomSTM32WLx 1
|
||||
#define MESH_REGULATOR_FIXED_RADIO_I(type) MESH_REGULATOR_FIXED_RADIO_##type
|
||||
#define MESH_REGULATOR_FIXED_RADIO(type) MESH_REGULATOR_FIXED_RADIO_I(type)
|
||||
#if defined(STM32_PLATFORM) && MESH_REGULATOR_FIXED_RADIO(RADIO_CLASS)
|
||||
#define MESH_REGULATOR_FIXED_SUPPLY 1
|
||||
#define MESH_REGULATOR_VIRTUAL
|
||||
#else
|
||||
#define MESH_REGULATOR_FIXED_SUPPLY 0
|
||||
#define MESH_REGULATOR_VIRTUAL virtual
|
||||
#endif
|
||||
#undef MESH_REGULATOR_FIXED_RADIO
|
||||
#undef MESH_REGULATOR_FIXED_RADIO_I
|
||||
#undef MESH_REGULATOR_FIXED_RADIO_CustomSTM32WLx
|
||||
|
||||
namespace mesh { namespace power {
|
||||
|
||||
enum class RegulatorMode : uint8_t { Default = 0, Dcdc = 1, Ldo = 2 };
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
// nRF52 plus an external radio. Do not retain the unreachable persistence and
|
||||
// recovery machinery on these flash-constrained targets. Match this exact
|
||||
// driver: an STM32 target with a different radio keeps the ordinary path.
|
||||
#define MESH_REGULATOR_FIXED_RADIO_CustomSTM32WLx 1
|
||||
#define MESH_REGULATOR_FIXED_RADIO_I(type) MESH_REGULATOR_FIXED_RADIO_##type
|
||||
#define MESH_REGULATOR_FIXED_RADIO(type) MESH_REGULATOR_FIXED_RADIO_I(type)
|
||||
#if defined(STM32_PLATFORM) && MESH_REGULATOR_FIXED_RADIO(RADIO_CLASS)
|
||||
#if MESH_REGULATOR_FIXED_SUPPLY
|
||||
namespace mesh { namespace power {
|
||||
bool beginRegulatorSettings(MainBoard&, Radio&, FILESYSTEM*) { return true; }
|
||||
void serviceRegulatorSettings() {}
|
||||
@@ -320,9 +317,6 @@ void resumeRegulatorRecovery() {
|
||||
|
||||
}} // namespace mesh::power
|
||||
#endif
|
||||
#undef MESH_REGULATOR_FIXED_RADIO
|
||||
#undef MESH_REGULATOR_FIXED_RADIO_I
|
||||
#undef MESH_REGULATOR_FIXED_RADIO_CustomSTM32WLx
|
||||
|
||||
extern "C" void meshRegulatorCleanReset() {
|
||||
// Intentional resets can happen before the settings/filesystem is ready.
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#include <cassert>
|
||||
#include <MeshCore.h>
|
||||
#include <Dispatcher.h>
|
||||
using mesh::power::RegulatorMode;
|
||||
|
||||
#if MESH_REGULATOR_FIXED_SUPPLY && !defined(REQUIRE_VIRTUAL_REGULATOR_API)
|
||||
#define REGULATOR_OVERRIDE
|
||||
#else
|
||||
#define REGULATOR_OVERRIDE override
|
||||
#endif
|
||||
|
||||
struct BoardDefaults : mesh::MainBoard {
|
||||
uint16_t getBattMilliVolts() override { return 0; }
|
||||
const char* getManufacturerName() const override { return "test"; }
|
||||
uint8_t getStartupReason() const override { return 0; }
|
||||
void reboot() override {}
|
||||
void sleep(uint32_t) override {} // The host must not assemble the MCU's WFI.
|
||||
};
|
||||
struct BoardSelection : BoardDefaults {
|
||||
uint8_t mcuRegulatorModes() const REGULATOR_OVERRIDE { return 3; }
|
||||
RegulatorMode defaultMcuRegulatorMode() const REGULATOR_OVERRIDE { return RegulatorMode::Dcdc; }
|
||||
bool applyMcuRegulator(RegulatorMode) REGULATOR_OVERRIDE { return true; }
|
||||
RegulatorMode activeMcuRegulatorMode() const REGULATOR_OVERRIDE { return RegulatorMode::Ldo; }
|
||||
};
|
||||
struct RadioDefaults : mesh::Radio {
|
||||
int recvRaw(uint8_t*, int) override { return 0; }
|
||||
uint32_t getEstAirtimeFor(int) override { return 0; }
|
||||
float packetScore(float, int) override { return 0; }
|
||||
bool startSendRaw(const uint8_t*, int) override { return false; }
|
||||
bool isSendComplete() override { return true; }
|
||||
void onSendFinished() override {}
|
||||
bool isInRecvMode() const override { return false; }
|
||||
};
|
||||
struct RadioSelection : RadioDefaults {
|
||||
uint8_t regulatorModes() const REGULATOR_OVERRIDE { return 3; }
|
||||
RegulatorMode defaultRegulatorMode() const REGULATOR_OVERRIDE { return RegulatorMode::Dcdc; }
|
||||
bool configureBootRegulator(RegulatorMode) REGULATOR_OVERRIDE { return true; }
|
||||
RegulatorMode activeRegulatorMode() const REGULATOR_OVERRIDE { return RegulatorMode::Ldo; }
|
||||
};
|
||||
|
||||
// Exercise the actual production base declarations through references. On
|
||||
// fixed STM32WL the shadows cannot add a runtime capability; everywhere else
|
||||
// all eight overrides must remain virtual and reachable through the API.
|
||||
__attribute__((noinline)) void check(mesh::MainBoard& board, mesh::Radio& radio) {
|
||||
constexpr bool fixed = EXPECT_FIXED_REGULATOR_API;
|
||||
assert(board.mcuRegulatorModes() == (fixed ? 0 : 3));
|
||||
assert(radio.regulatorModes() == (fixed ? 0 : 3));
|
||||
assert(board.defaultMcuRegulatorMode() == (fixed ? RegulatorMode::Default : RegulatorMode::Dcdc));
|
||||
assert(radio.defaultRegulatorMode() == (fixed ? RegulatorMode::Default : RegulatorMode::Dcdc));
|
||||
assert(board.applyMcuRegulator(RegulatorMode::Dcdc) == !fixed);
|
||||
assert(radio.configureBootRegulator(RegulatorMode::Dcdc) == !fixed);
|
||||
assert(board.activeMcuRegulatorMode() == (fixed ? RegulatorMode::Default : RegulatorMode::Ldo));
|
||||
assert(radio.activeRegulatorMode() == (fixed ? RegulatorMode::Default : RegulatorMode::Ldo));
|
||||
}
|
||||
int main() {
|
||||
static_assert(MESH_REGULATOR_FIXED_SUPPLY == EXPECT_FIXED_REGULATOR_API,
|
||||
"the fixed supply guard must match this exact platform/driver");
|
||||
BoardSelection board;
|
||||
RadioSelection radio;
|
||||
assert(board.mcuRegulatorModes() == 3 && radio.regulatorModes() == 3);
|
||||
check(board, radio);
|
||||
}
|
||||
@@ -276,5 +276,49 @@ class RegulatorSettingsTests(unittest.TestCase):
|
||||
self.assertNotIn('beginRegulatorSettings(',other)
|
||||
|
||||
|
||||
class RegulatorAPIDispatchTests(unittest.TestCase):
|
||||
def compile_api(self, flags, fixed, require_virtual=False):
|
||||
compiler = os.environ.get('CXX') or shutil.which('g++') or shutil.which('clang++')
|
||||
if not compiler:
|
||||
self.skipTest('native C++ compiler unavailable')
|
||||
with tempfile.TemporaryDirectory(prefix='mesh-regulator-api-') as directory:
|
||||
folder = Path(directory)
|
||||
(folder/'Stream.h').write_text('#pragma once\nclass Stream {};\n')
|
||||
binary = folder/'test'
|
||||
command = [compiler,'-std=c++17','-O2','-Wall','-Wextra','-Werror',
|
||||
'-Wno-unused-parameter','-Wno-reorder',*SANITIZER_FLAGS,*flags,
|
||||
f'-DEXPECT_FIXED_REGULATOR_API={int(fixed)}',
|
||||
'-I',str(folder),'-I',str(ROOT/'src'),
|
||||
str(ROOT/'test/fixtures/regulator_api_dispatch.cpp'),'-o',str(binary)]
|
||||
if require_virtual:
|
||||
command.append('-DREQUIRE_VIRTUAL_REGULATOR_API=1')
|
||||
result = subprocess.run(command,text=True,capture_output=True,timeout=45)
|
||||
if require_virtual and fixed:
|
||||
self.assertNotEqual(result.returncode,0)
|
||||
for method in ('mcuRegulatorModes','defaultMcuRegulatorMode',
|
||||
'applyMcuRegulator','activeMcuRegulatorMode','regulatorModes',
|
||||
'defaultRegulatorMode','configureBootRegulator','activeRegulatorMode'):
|
||||
self.assertIn(method,result.stderr)
|
||||
else:
|
||||
self.assertEqual(result.returncode,0,result.stdout+result.stderr)
|
||||
result = subprocess.run([str(binary)],text=True,capture_output=True,timeout=10)
|
||||
self.assertEqual(result.returncode,0,result.stdout+result.stderr)
|
||||
|
||||
def test_actual_fixed_stm32wl_base_defaults_are_not_overridden(self):
|
||||
self.compile_api(['-DSTM32_PLATFORM=1','-DRADIO_CLASS=CustomSTM32WLx'],True)
|
||||
|
||||
def test_all_eight_fixed_stm32wl_regulator_methods_reject_override_annotations(self):
|
||||
self.compile_api(['-DSTM32_PLATFORM=1','-DRADIO_CLASS=CustomSTM32WLx'],True,True)
|
||||
|
||||
def test_other_platforms_and_future_stm32_radios_keep_all_eight_virtual_methods(self):
|
||||
for flags in ([],['-DESP32=1','-DRADIO_CLASS=CustomSTM32WLx'],
|
||||
['-DNRF52_PLATFORM=1','-DRADIO_CLASS=CustomSX1262'],
|
||||
['-DRP2040_PLATFORM=1','-DRADIO_CLASS=CustomSX1262'],
|
||||
['-DSTM32_PLATFORM=1','-DRADIO_CLASS=CustomSX1262'],
|
||||
['-DSTM32_PLATFORM=1']):
|
||||
with self.subTest(flags=flags):
|
||||
self.compile_api(flags,False,True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user