156 lines
5.7 KiB
C++
156 lines
5.7 KiB
C++
#include <helpers/ui/SSD1306Display.h>
|
|
#include <assert.h>
|
|
#include <initializer_list>
|
|
#include <stdio.h>
|
|
|
|
static constexpr uint8_t RAIL_PIN = 7;
|
|
|
|
static void resetBoundary() {
|
|
panel_state = PanelState();
|
|
Wire = TwoWire();
|
|
for (unsigned i = 0; i < 64; ++i) pin_levels[i] = pin_modes[i] = 0;
|
|
}
|
|
|
|
static void fail(bool allocation) {
|
|
panel_state.allocation_ok = !allocation;
|
|
Wire.result = allocation ? 0 : 2;
|
|
}
|
|
|
|
static void repair() { panel_state.allocation_ok = true; Wire.result = 0; }
|
|
|
|
static void expectNotReady(SSD1306Display& panel) {
|
|
assert(!panel.isOn());
|
|
const unsigned before = panel_state.rotations;
|
|
panel.setFlipped(true);
|
|
assert(panel.setRotationDegrees(90));
|
|
panel.setFlipped(false);
|
|
assert(panel.setRotationDegrees(0));
|
|
assert(panel_state.rotations == before);
|
|
}
|
|
|
|
static void failedBoot(bool allocation, bool other_owner, bool shared) {
|
|
resetBoundary();
|
|
RefCountedDigitalPin rail(RAIL_PIN);
|
|
rail.begin();
|
|
if (other_owner) rail.claim();
|
|
SSD1306Display panel(shared ? &rail : nullptr);
|
|
fail(allocation);
|
|
for (unsigned attempt = 0; attempt < 3; ++attempt) {
|
|
// This is the caller's real admission contract: failed panels never get a
|
|
// UI task which could later turn them off and release a phantom claim.
|
|
DisplayDriver* ui = panel.begin() ? &panel : nullptr;
|
|
assert(ui == nullptr);
|
|
expectNotReady(panel);
|
|
assert(digitalRead(RAIL_PIN) == (other_owner ? HIGH : LOW));
|
|
if (shared && PIN_OLED_RESET >= 0) assert(digitalRead(PIN_OLED_RESET) == LOW);
|
|
}
|
|
assert(panel_state.begins == 3);
|
|
assert(Wire.probes == (allocation ? 0U : 3U));
|
|
// A failed panel owns nothing: repeated off may not steal another owner's
|
|
// claim. Once that independent owner stops, the rail must really turn off.
|
|
for (unsigned i = 0; i < 3; ++i) panel.turnOff();
|
|
assert(digitalRead(RAIL_PIN) == (other_owner ? HIGH : LOW));
|
|
if (other_owner) rail.release();
|
|
assert(digitalRead(RAIL_PIN) == LOW);
|
|
repair();
|
|
assert(panel.begin() && panel.isOn());
|
|
assert(digitalRead(RAIL_PIN) == (shared ? HIGH : LOW));
|
|
assert(panel.begin()); // Already on: do not acquire a second display claim.
|
|
panel.turnOff();
|
|
assert(!panel.isOn() && digitalRead(RAIL_PIN) == LOW);
|
|
// Claim/release after all failures proves the counter has not underflowed.
|
|
rail.claim(); assert(digitalRead(RAIL_PIN) == HIGH);
|
|
rail.release(); assert(digitalRead(RAIL_PIN) == LOW);
|
|
}
|
|
|
|
static void failedReinitialization(bool allocation, bool other_owner, bool shared) {
|
|
resetBoundary();
|
|
RefCountedDigitalPin rail(RAIL_PIN);
|
|
rail.begin();
|
|
if (other_owner) rail.claim();
|
|
SSD1306Display panel(shared ? &rail : nullptr);
|
|
assert(panel.begin());
|
|
const unsigned rotations = panel_state.rotations;
|
|
fail(allocation);
|
|
assert(!panel.begin()); // Already-on begin has exactly one claim to roll back.
|
|
expectNotReady(panel);
|
|
assert(panel_state.rotations == rotations);
|
|
assert(digitalRead(RAIL_PIN) == (other_owner ? HIGH : LOW));
|
|
if (other_owner) rail.release();
|
|
assert(digitalRead(RAIL_PIN) == LOW);
|
|
repair();
|
|
assert(panel.begin());
|
|
panel.turnOff();
|
|
assert(digitalRead(RAIL_PIN) == LOW);
|
|
}
|
|
|
|
static void failedWake(bool allocation, bool other_owner, bool shared) {
|
|
resetBoundary();
|
|
RefCountedDigitalPin rail(RAIL_PIN);
|
|
rail.begin();
|
|
if (other_owner) rail.claim();
|
|
SSD1306Display panel(shared ? &rail : nullptr);
|
|
assert(panel.begin());
|
|
if (shared) panel.turnOff();
|
|
else {
|
|
// A continuously powered panel normally needs no reinit after turnOff.
|
|
// Mark it unready through a real failed begin before testing failed wake.
|
|
fail(allocation);
|
|
assert(!panel.begin());
|
|
}
|
|
fail(allocation);
|
|
const unsigned commands = panel_state.on_commands, begins = panel_state.begins;
|
|
for (unsigned attempt = 0; attempt < 3; ++attempt) {
|
|
panel.turnOn();
|
|
expectNotReady(panel);
|
|
assert(panel_state.on_commands == commands);
|
|
assert(panel_state.begins == begins + attempt + 1);
|
|
assert(digitalRead(RAIL_PIN) == (other_owner ? HIGH : LOW));
|
|
}
|
|
repair();
|
|
panel.turnOn();
|
|
assert(panel.isOn() && panel_state.on_commands == commands + 1);
|
|
assert(digitalRead(RAIL_PIN) == ((shared || other_owner) ? HIGH : LOW));
|
|
panel.turnOff();
|
|
if (other_owner) {
|
|
assert(digitalRead(RAIL_PIN) == HIGH);
|
|
rail.release();
|
|
}
|
|
assert(digitalRead(RAIL_PIN) == LOW);
|
|
}
|
|
|
|
static void ordinarySuccess(bool shared) {
|
|
resetBoundary();
|
|
RefCountedDigitalPin rail(RAIL_PIN);
|
|
rail.begin();
|
|
SSD1306Display panel(shared ? &rail : nullptr);
|
|
assert(panel.begin());
|
|
assert(panel.isOn() && panel_state.begins == 1 && panel_state.rotations == 1);
|
|
panel.turnOn();
|
|
assert(panel_state.begins == 1 && panel_state.on_commands == 1);
|
|
panel.turnOff();
|
|
assert(!panel.isOn() && digitalRead(RAIL_PIN) == LOW);
|
|
panel.turnOn();
|
|
assert(panel.isOn() && panel_state.begins == (shared ? 2U : 1U));
|
|
assert(panel_state.on_commands == 2);
|
|
panel.turnOff();
|
|
mesh::ui::displayPowerPrefs() = mesh::ui::DisplayPowerPrefs();
|
|
mesh::ui::displayPowerPrefs().battery.mode = mesh::ui::DisplayMode::On;
|
|
assert(panel.servicePower(false) && panel.isOn());
|
|
mesh::ui::displayPowerPrefs().battery.mode = mesh::ui::DisplayMode::Off;
|
|
assert(panel.servicePower(false) && !panel.isOn());
|
|
assert(digitalRead(RAIL_PIN) == LOW);
|
|
}
|
|
|
|
int main() {
|
|
unsigned checks = 0;
|
|
for (bool allocation : {false, true}) for (bool other_owner : {false, true})
|
|
for (bool shared : {false, true}) {
|
|
failedBoot(allocation, other_owner, shared); ++checks;
|
|
failedReinitialization(allocation, other_owner, shared); ++checks;
|
|
failedWake(allocation, other_owner, shared); ++checks;
|
|
}
|
|
for (bool shared : {false, true}) { ordinarySuccess(shared); ++checks; }
|
|
printf("PASS: actual SSD1306 power ownership (%u scenarios)\n", checks);
|
|
}
|