Коррекция уровня оптики, вкл по умолчанию, выкл в сне
плюс коррекции по отображению
This commit is contained in:
@@ -53,6 +53,12 @@ const char *uiFailName(FailReason reason) {
|
||||
? UiText::FAIL_NAMES[index] : "UNKNOWN";
|
||||
}
|
||||
|
||||
const char *roleCorner(Role role) {
|
||||
static const char *markers[] = {"O", "M", "S"};
|
||||
const uint8_t index = static_cast<uint8_t>(role);
|
||||
return index < sizeof(markers) / sizeof(markers[0]) ? markers[index] : "?";
|
||||
}
|
||||
|
||||
void formatMenuLine(const char *label, const char *value, char *out, size_t size) {
|
||||
constexpr size_t OLED_TEXT_COLUMNS = 21;
|
||||
const size_t labelLength = utf8CharacterCount(label);
|
||||
@@ -198,6 +204,7 @@ void App::update() {
|
||||
|
||||
void App::showIdle() {
|
||||
setActivePerformance(false);
|
||||
setStandbyOpticalOutput();
|
||||
lastUserActivityMs_ = millis();
|
||||
char one[64]; snprintf(one, sizeof(one), "%s%s", UiText::MODE_PREFIX,
|
||||
uiRoleName(static_cast<Role>(settings_.role)));
|
||||
@@ -272,6 +279,7 @@ void App::showMenu() {
|
||||
|
||||
void App::startTest() {
|
||||
leaveIdlePowerSave();
|
||||
pwm_.stop();
|
||||
setActivePerformance(true);
|
||||
params_ = store_.params(settings_); stageCount_ = frequencyPointCount(params_.startHz, params_.endHz);
|
||||
stageIndex_ = 0; requestedHz_ = 0; pendingReason_ = FailReason::NONE;
|
||||
@@ -298,6 +306,7 @@ void App::startTest() {
|
||||
|
||||
bool App::armSlave(bool preserveDisplay) {
|
||||
setActivePerformance(false);
|
||||
pwm_.stop();
|
||||
lastUserActivityMs_ = millis();
|
||||
params_ = store_.params(settings_);
|
||||
stageIndex_ = 0; stageCount_ = frequencyPointCount(params_.startHz, params_.endHz);
|
||||
@@ -306,7 +315,8 @@ bool App::armSlave(bool preserveDisplay) {
|
||||
if (!radio_.begin()) {
|
||||
state_ = AppState::FINISHED; pendingReason_ = FailReason::LINK_LOST;
|
||||
slaveRearmAtMs_ = millis() + LINK_HEARTBEAT_TIMEOUT_MS;
|
||||
display_.show(UiText::LINK_FAILED, UiText::RADIO_ERROR);
|
||||
display_.show(UiText::LINK_FAILED, UiText::RADIO_ERROR,
|
||||
0, 0, roleCorner(Role::SLAVE));
|
||||
return false;
|
||||
}
|
||||
radio_.setWindowedReceive(true);
|
||||
@@ -373,6 +383,9 @@ void App::stagePassed() {
|
||||
void App::startMasterDiscovery() {
|
||||
session_ = esp_random(); if (!session_) session_ = 1;
|
||||
sequence_ = 1; stageIndex_ = 0; requestedHz_ = 0; havePeer_ = false; radio_.flush();
|
||||
opticalWakeActive_ = true;
|
||||
lastOpticalWakeToggleMs_ = millis();
|
||||
pwm_.active();
|
||||
pendingPacket_ = makePacket(MessageType::DISCOVER); radio_.sendBroadcast(pendingPacket_);
|
||||
lastSendMs_ = millis(); retries_ = 0;
|
||||
state_ = AppState::MASTER_DISCOVER; Log::printf("ESP-NOW", "discovery started session=%08lX", session_);
|
||||
@@ -435,6 +448,7 @@ void App::handleRadio() {
|
||||
if ((state_ == AppState::SLAVE_READY || state_ == AppState::SLAVE_WAIT_START) &&
|
||||
type == MessageType::DISCOVER && (!havePeer_ || !memcmp(peer_, r.mac, 6))) {
|
||||
leaveIdlePowerSave();
|
||||
pwm_.stop();
|
||||
setActivePerformance(true);
|
||||
radio_.setWindowedReceive(false);
|
||||
memcpy(peer_, r.mac, 6); havePeer_ = true; session_ = r.packet.session; stageIndex_ = 0; sequence_ = r.packet.sequence;
|
||||
@@ -443,6 +457,8 @@ void App::handleRadio() {
|
||||
state_ = AppState::SLAVE_WAIT_START; display_.show(UiText::MASTER_SEEN, UiText::ACK_SENT); continue;
|
||||
}
|
||||
if (state_ == AppState::MASTER_DISCOVER && type == MessageType::DISCOVER_ACK && r.packet.session == session_) {
|
||||
opticalWakeActive_ = false;
|
||||
pwm_.stop();
|
||||
memcpy(peer_, r.mac, 6); havePeer_ = true; lastPeerSeenMs_ = lastHeartbeatMs_ = millis();
|
||||
requestedHz_ = frequencyAt(params_.startHz, params_.endHz, stageIndex_);
|
||||
sendCurrent(MessageType::PREPARE); state_ = AppState::MASTER_WAIT_READY; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
||||
@@ -551,6 +567,12 @@ void App::handleRadio() {
|
||||
void App::updateMaster() {
|
||||
const uint32_t now = millis();
|
||||
if (state_ == AppState::MASTER_DISCOVER) {
|
||||
if (now - lastOpticalWakeToggleMs_ >= OPTICAL_WAKE_HALF_PERIOD_MS) {
|
||||
opticalWakeActive_ = !opticalWakeActive_;
|
||||
if (opticalWakeActive_) pwm_.active();
|
||||
else pwm_.stop();
|
||||
lastOpticalWakeToggleMs_ = now;
|
||||
}
|
||||
if (now - lastSendMs_ >= DISCOVERY_RETRY_INTERVAL_MS) {
|
||||
if (++retries_ % 50U == 0U) Log::event("ESP-NOW", "DISCOVER burst continues");
|
||||
radio_.sendBroadcast(pendingPacket_);
|
||||
@@ -651,6 +673,7 @@ void App::finish(bool pass, FailReason reason, bool preserveDisplay) {
|
||||
if (!pass && masterActive && havePeer_ && reason != FailReason::ABORTED) sendAbort(reason);
|
||||
if (state_ != AppState::IDLE && state_ != AppState::MENU) radio_.end();
|
||||
state_ = AppState::FINISHED; pendingReason_ = reason;
|
||||
setStandbyOpticalOutput();
|
||||
setActivePerformance(false);
|
||||
lastUserActivityMs_ = millis();
|
||||
if (slaveLinkLost) {
|
||||
@@ -658,7 +681,8 @@ void App::finish(bool pass, FailReason reason, bool preserveDisplay) {
|
||||
Display::formatTestFrequency(actual_.actualHz ? actual_.actualHz : requestedHz_, target, sizeof(target));
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target,
|
||||
actual_.actualDutyPct > 0.0f ? actual_.actualDutyPct : params_.dutyPct);
|
||||
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_);
|
||||
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_,
|
||||
roleCorner(Role::SLAVE));
|
||||
armSlave(true);
|
||||
return;
|
||||
}
|
||||
@@ -675,9 +699,11 @@ void App::finish(bool pass, FailReason reason, bool preserveDisplay) {
|
||||
Display::formatTestFrequency(actual_.actualHz ? actual_.actualHz : requestedHz_, frequency, sizeof(frequency));
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, frequency,
|
||||
actual_.actualDutyPct > 0.0f ? actual_.actualDutyPct : params_.dutyPct);
|
||||
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_);
|
||||
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_,
|
||||
roleCorner(static_cast<Role>(settings_.role)));
|
||||
} else {
|
||||
display_.show(UiText::TEST_FAILED, uiFailName(reason));
|
||||
display_.show(UiText::TEST_FAILED, uiFailName(reason), 0, 0,
|
||||
roleCorner(static_cast<Role>(settings_.role)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,6 +712,11 @@ bool App::idlePowerSaveAllowed() const {
|
||||
state_ == AppState::FINISHED || state_ == AppState::SLAVE_READY);
|
||||
}
|
||||
|
||||
void App::setStandbyOpticalOutput() {
|
||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) pwm_.stop();
|
||||
else pwm_.active();
|
||||
}
|
||||
|
||||
void App::setActivePerformance(bool active) {
|
||||
const uint32_t targetMhz = active ? 160U : 80U;
|
||||
if (getCpuFrequencyMhz() != targetMhz && !setCpuFrequencyMhz(targetMhz))
|
||||
@@ -699,6 +730,15 @@ void App::leaveIdlePowerSave(bool wakeDisplay) {
|
||||
}
|
||||
idlePowerSave_ = false;
|
||||
lastUserActivityMs_ = millis();
|
||||
setStandbyOpticalOutput();
|
||||
if (idleSleepRadioStopped_) {
|
||||
idleSleepRadioStopped_ = false;
|
||||
if (radio_.begin()) {
|
||||
radio_.setWindowedReceive(true);
|
||||
radio_.flush();
|
||||
Log::event("POWER", "Slave ESP-NOW restored after external wake");
|
||||
} else Log::event("POWER", "Slave ESP-NOW restore FAILED after external wake");
|
||||
}
|
||||
if (wakeDisplay) display_.setPower(true);
|
||||
Log::event("POWER", "idle light sleep ended");
|
||||
}
|
||||
@@ -716,6 +756,11 @@ void App::serviceIdlePowerSave() {
|
||||
return;
|
||||
}
|
||||
idlePowerSave_ = true;
|
||||
pwm_.stop();
|
||||
if (state_ == AppState::SLAVE_READY) {
|
||||
radio_.end();
|
||||
idleSleepRadioStopped_ = true;
|
||||
}
|
||||
display_.setPower(false);
|
||||
Log::event("POWER", "idle timeout; OLED off and light sleep started");
|
||||
}
|
||||
@@ -724,8 +769,16 @@ void App::serviceIdlePowerSave() {
|
||||
BUTTON_ACTIVE_LEVEL == LOW ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);
|
||||
gpio_wakeup_enable(static_cast<gpio_num_t>(GPIO_BUTTON_MODE),
|
||||
BUTTON_ACTIVE_LEVEL == LOW ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);
|
||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) {
|
||||
// Light-sleep GPIO wake is level-triggered in ESP-IDF. Arm the level
|
||||
// opposite to the one sampled immediately before sleep, which makes a
|
||||
// transition (either edge) necessary and prevents a steady RX level from
|
||||
// waking Slave continuously.
|
||||
const bool currentRxHigh = gpio_get_level(static_cast<gpio_num_t>(GPIO_RX)) != 0;
|
||||
gpio_wakeup_enable(static_cast<gpio_num_t>(GPIO_RX),
|
||||
currentRxHigh ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL);
|
||||
} else gpio_wakeup_disable(static_cast<gpio_num_t>(GPIO_RX));
|
||||
esp_sleep_enable_gpio_wakeup();
|
||||
esp_sleep_enable_timer_wakeup(IDLE_LIGHT_SLEEP_SLICE_US);
|
||||
const esp_err_t result = esp_light_sleep_start();
|
||||
if (result != ESP_OK) {
|
||||
delay(1);
|
||||
@@ -733,12 +786,19 @@ void App::serviceIdlePowerSave() {
|
||||
}
|
||||
|
||||
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO) {
|
||||
// The wake-up press is deliberately consumed. Holding or releasing it
|
||||
// must not later turn into a SHORT, LONG, or REPEAT event.
|
||||
startButton_.suppressUntilRelease();
|
||||
modeButton_.suppressUntilRelease();
|
||||
leaveIdlePowerSave();
|
||||
Log::event("POWER", "button wake consumed; next press will perform the action");
|
||||
const bool buttonWake = digitalRead(GPIO_BUTTON_START) == BUTTON_ACTIVE_LEVEL ||
|
||||
digitalRead(GPIO_BUTTON_MODE) == BUTTON_ACTIVE_LEVEL;
|
||||
if (buttonWake) {
|
||||
// The wake-up press is deliberately consumed. Holding or releasing it
|
||||
// must not later turn into a SHORT, LONG, or REPEAT event.
|
||||
startButton_.suppressUntilRelease();
|
||||
modeButton_.suppressUntilRelease();
|
||||
leaveIdlePowerSave();
|
||||
Log::event("POWER", "button wake consumed; next press will perform the action");
|
||||
} else if (static_cast<Role>(settings_.role) == Role::SLAVE) {
|
||||
leaveIdlePowerSave();
|
||||
Log::event("POWER", "optical input woke Slave");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -794,7 +854,7 @@ void App::showStageResult(const StageStats &s) {
|
||||
snprintf(two, sizeof(two), "%s", uiFailName(s.reason));
|
||||
}
|
||||
display_.show(one, two, overallProgress(stageIndex_, measurement_.progressStep()),
|
||||
overallProgressTotal(stageCount_));
|
||||
overallProgressTotal(stageCount_), roleCorner(static_cast<Role>(settings_.role)));
|
||||
return;
|
||||
}
|
||||
char stage[12]; snprintf(stage, sizeof(stage), "%lu/%lu", stageIndex_ + 1, stageCount_);
|
||||
@@ -841,7 +901,8 @@ void App::showRemoteResult(const ProtocolPacket &packet) {
|
||||
snprintf(two, sizeof(two), "%s", uiFailName(reason));
|
||||
}
|
||||
display_.show(one, two, overallProgress(stageIndex_, packet.progressStep),
|
||||
overallProgressTotal(stageCount_));
|
||||
overallProgressTotal(stageCount_), reason == FailReason::NONE ? nullptr :
|
||||
roleCorner(static_cast<Role>(settings_.role)));
|
||||
}
|
||||
|
||||
void App::fillMeasuredResult(ProtocolPacket &packet, const StageStats &stats) const {
|
||||
|
||||
Reference in New Issue
Block a user