Сделан русский текст
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "App.h"
|
||||
#include "Config.h"
|
||||
#include "Config_Text.h"
|
||||
#include "Log.h"
|
||||
#include <WiFi.h>
|
||||
#include <esp_mac.h>
|
||||
@@ -30,12 +31,36 @@ void formatErrorDuty(float duty, char *out, size_t size) {
|
||||
else snprintf(out, size, "%.1f%%", duty);
|
||||
}
|
||||
|
||||
size_t utf8CharacterCount(const char *text) {
|
||||
size_t count = 0;
|
||||
while (text && *text) {
|
||||
const uint8_t byte = static_cast<uint8_t>(*text++);
|
||||
// Continuation bytes (10xxxxxx) belong to the preceding UTF-8 character.
|
||||
if ((byte & 0xC0U) != 0x80U) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const char *uiRoleName(Role role) {
|
||||
const uint8_t index = static_cast<uint8_t>(role);
|
||||
return index < sizeof(UiText::ROLE_NAMES) / sizeof(UiText::ROLE_NAMES[0])
|
||||
? UiText::ROLE_NAMES[index] : "?";
|
||||
}
|
||||
|
||||
const char *uiFailName(FailReason reason) {
|
||||
const uint8_t index = static_cast<uint8_t>(reason);
|
||||
return index < sizeof(UiText::FAIL_NAMES) / sizeof(UiText::FAIL_NAMES[0])
|
||||
? UiText::FAIL_NAMES[index] : "UNKNOWN";
|
||||
}
|
||||
|
||||
void formatMenuLine(const char *label, const char *value, char *out, size_t size) {
|
||||
constexpr size_t OLED_TEXT_COLUMNS = 21;
|
||||
const size_t valueLength = strlen(value);
|
||||
const int labelWidth = static_cast<int>(
|
||||
valueLength < OLED_TEXT_COLUMNS ? OLED_TEXT_COLUMNS - valueLength : 1U);
|
||||
snprintf(out, size, "%-*s%s", labelWidth, label, value);
|
||||
const size_t labelLength = utf8CharacterCount(label);
|
||||
const size_t valueLength = utf8CharacterCount(value);
|
||||
const size_t usedColumns = labelLength + valueLength;
|
||||
const int padding = static_cast<int>(
|
||||
usedColumns < OLED_TEXT_COLUMNS ? OLED_TEXT_COLUMNS - usedColumns : 0U);
|
||||
snprintf(out, size, "%s%*s%s", label, padding, "", value);
|
||||
}
|
||||
|
||||
uint32_t overallProgress(uint32_t stageIndex, uint8_t step) {
|
||||
@@ -173,8 +198,9 @@ void App::update() {
|
||||
void App::showIdle() {
|
||||
setActivePerformance(false);
|
||||
lastUserActivityMs_ = millis();
|
||||
char one[24]; snprintf(one, sizeof(one), "MODE: %s", roleName(static_cast<Role>(settings_.role)));
|
||||
display_.show(one, "START=RUN");
|
||||
char one[64]; snprintf(one, sizeof(one), "%s%s", UiText::MODE_PREFIX,
|
||||
uiRoleName(static_cast<Role>(settings_.role)));
|
||||
display_.show(one, UiText::START_RUN);
|
||||
}
|
||||
|
||||
void App::sanitizeRange() {
|
||||
@@ -198,35 +224,35 @@ void App::changeMenu(int d) {
|
||||
}
|
||||
|
||||
void App::showMenu() {
|
||||
char one[22], value[12], total[22], all[12];
|
||||
char one[64], value[24], total[64], all[12];
|
||||
const char *label = nullptr;
|
||||
Display::formatDuration(actualNominalTotalUs(), all, sizeof(all));
|
||||
switch (menuItem_) {
|
||||
case 0:
|
||||
Display::formatTestFrequency(params_.startHz, value, sizeof(value));
|
||||
strncat(value, " Hz", sizeof(value) - strlen(value) - 1U);
|
||||
label = "START FREQ:";
|
||||
strncat(value, UiText::FREQUENCY_UNIT, sizeof(value) - strlen(value) - 1U);
|
||||
label = UiText::MENU_START_FREQUENCY;
|
||||
break;
|
||||
case 1:
|
||||
Display::formatTestFrequency(params_.endHz, value, sizeof(value));
|
||||
strncat(value, " Hz", sizeof(value) - strlen(value) - 1U);
|
||||
label = "END FREQ:";
|
||||
strncat(value, UiText::FREQUENCY_UNIT, sizeof(value) - strlen(value) - 1U);
|
||||
label = UiText::MENU_END_FREQUENCY;
|
||||
break;
|
||||
case 2:
|
||||
snprintf(value, sizeof(value), "+/-%g%%", params_.accuracyPct);
|
||||
label = "ACCURACY:";
|
||||
label = UiText::MENU_ACCURACY;
|
||||
break;
|
||||
case 3:
|
||||
snprintf(value, sizeof(value), "%.1fs", params_.testTimeMs / 1000.0f);
|
||||
label = "TEST TIME:";
|
||||
label = UiText::MENU_TEST_TIME;
|
||||
break;
|
||||
default:
|
||||
snprintf(value, sizeof(value), "%u%%", params_.dutyPct);
|
||||
label = "PWM DUTY:";
|
||||
label = UiText::MENU_PWM_DUTY;
|
||||
break;
|
||||
}
|
||||
formatMenuLine(label, value, one, sizeof(one));
|
||||
formatMenuLine("TOTAL TIME:", all, total, sizeof(total));
|
||||
formatMenuLine(UiText::MENU_TOTAL_TIME, all, total, sizeof(total));
|
||||
display_.show(one, total);
|
||||
}
|
||||
|
||||
@@ -253,7 +279,7 @@ void App::startTest() {
|
||||
state_ = AppState::SOLO_MEASURE;
|
||||
} else if (!radio_.begin()) finish(false, FailReason::LINK_LOST);
|
||||
else if (role == Role::MASTER) startMasterDiscovery();
|
||||
else { state_ = AppState::SLAVE_READY; Log::event("TEST", "Slave armed and waiting for Master"); display_.show("SLAVE READY", "WAIT MASTER"); }
|
||||
else { state_ = AppState::SLAVE_READY; Log::event("TEST", "Slave armed and waiting for Master"); display_.show(UiText::SLAVE_READY, UiText::WAIT_MASTER); }
|
||||
}
|
||||
|
||||
bool App::armSlave(bool preserveDisplay) {
|
||||
@@ -266,13 +292,13 @@ bool App::armSlave(bool preserveDisplay) {
|
||||
if (!radio_.begin()) {
|
||||
state_ = AppState::FINISHED; pendingReason_ = FailReason::LINK_LOST;
|
||||
slaveRearmAtMs_ = millis() + LINK_HEARTBEAT_TIMEOUT_MS;
|
||||
display_.show("LINK FAILED", "RADIO ERROR");
|
||||
display_.show(UiText::LINK_FAILED, UiText::RADIO_ERROR);
|
||||
return false;
|
||||
}
|
||||
radio_.setWindowedReceive(true);
|
||||
radio_.flush(); state_ = AppState::SLAVE_READY;
|
||||
Log::event("TEST", "Slave automatically armed and waiting for Master");
|
||||
if (!preserveDisplay) display_.show("SLAVE READY", "WAIT MASTER");
|
||||
if (!preserveDisplay) display_.show(UiText::SLAVE_READY, UiText::WAIT_MASTER);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -336,7 +362,7 @@ void App::startMasterDiscovery() {
|
||||
pendingPacket_ = makePacket(MessageType::DISCOVER); radio_.sendBroadcast(pendingPacket_);
|
||||
lastSendMs_ = millis(); retries_ = 0;
|
||||
state_ = AppState::MASTER_DISCOVER; Log::printf("ESP-NOW", "discovery started session=%08lX", session_);
|
||||
display_.show("MASTER SEARCH", "HOLD START=STOP");
|
||||
display_.show(UiText::MASTER_SEARCH, UiText::HOLD_START_STOP);
|
||||
}
|
||||
|
||||
ProtocolPacket App::makePacket(MessageType type) const {
|
||||
@@ -400,7 +426,7 @@ void App::handleRadio() {
|
||||
memcpy(peer_, r.mac, 6); havePeer_ = true; session_ = r.packet.session; stageIndex_ = 0; sequence_ = r.packet.sequence;
|
||||
lastPeerSeenMs_ = millis();
|
||||
ProtocolPacket ack = makePacket(MessageType::DISCOVER_ACK); ack.sequence = r.packet.sequence; sendLinked(ack);
|
||||
state_ = AppState::SLAVE_WAIT_START; display_.show("MASTER SEEN", "ACK SENT"); continue;
|
||||
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_) {
|
||||
memcpy(peer_, r.mac, 6); havePeer_ = true; lastPeerSeenMs_ = lastHeartbeatMs_ = millis();
|
||||
@@ -497,7 +523,7 @@ void App::handleRadio() {
|
||||
if (pendingPacket_.passed) {
|
||||
if (r.packet.passed) {
|
||||
radio_.end(); pendingReason_ = FailReason::NONE;
|
||||
if (armSlave(true)) display_.show("SLAVE PASS", "WAIT MASTER");
|
||||
if (armSlave(true)) display_.show(UiText::PASS_WORD, UiText::WAIT_MASTER);
|
||||
} else {
|
||||
stageIndex_ = static_cast<uint32_t>(r.packet.stage) + 1U;
|
||||
state_ = AppState::SLAVE_WAIT_START;
|
||||
@@ -614,30 +640,30 @@ void App::finish(bool pass, FailReason reason, bool preserveDisplay) {
|
||||
setActivePerformance(false);
|
||||
lastUserActivityMs_ = millis();
|
||||
if (slaveLinkLost) {
|
||||
char target[12], one[24];
|
||||
char target[12], one[64];
|
||||
Display::formatTestFrequency(actual_.actualHz ? actual_.actualHz : requestedHz_, target, sizeof(target));
|
||||
snprintf(one, sizeof(one), "FAIL %s %.0f%%", target,
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target,
|
||||
actual_.actualDutyPct > 0.0f ? actual_.actualDutyPct : params_.dutyPct);
|
||||
display_.show(one, failName(reason), stageIndex_ + 1, stageCount_);
|
||||
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_);
|
||||
armSlave(true);
|
||||
return;
|
||||
}
|
||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) slaveRearmAtMs_ = millis() + 2000;
|
||||
if (preserveDisplay) return;
|
||||
char one[24];
|
||||
char one[64];
|
||||
if (pass) {
|
||||
const Role role = static_cast<Role>(settings_.role);
|
||||
snprintf(one, sizeof(one), "%s PASS", roleName(role));
|
||||
display_.show(one, role == Role::SLAVE ? "WAIT MASTER" : "START=AGAIN");
|
||||
snprintf(one, sizeof(one), "%s %s", uiRoleName(role), UiText::PASS_WORD);
|
||||
display_.show(one, role == Role::SLAVE ? UiText::WAIT_MASTER : UiText::START_AGAIN);
|
||||
}
|
||||
else if (requestedHz_) {
|
||||
char frequency[12];
|
||||
Display::formatTestFrequency(actual_.actualHz ? actual_.actualHz : requestedHz_, frequency, sizeof(frequency));
|
||||
snprintf(one, sizeof(one), "FAIL %s %.0f%%", frequency,
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, frequency,
|
||||
actual_.actualDutyPct > 0.0f ? actual_.actualDutyPct : params_.dutyPct);
|
||||
display_.show(one, failName(reason), stageIndex_ + 1, stageCount_);
|
||||
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_);
|
||||
} else {
|
||||
display_.show("TEST FAILED", failName(reason));
|
||||
display_.show(UiText::TEST_FAILED, uiFailName(reason));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,28 +765,28 @@ void App::printStageStats(const StageStats &s, uint32_t hz) {
|
||||
}
|
||||
|
||||
void App::showStageResult(const StageStats &s) {
|
||||
char one[24], two[24];
|
||||
char one[64], two[64];
|
||||
char target[12]; Display::formatTestFrequency(actual_.actualHz, target, sizeof(target));
|
||||
if (s.reason != FailReason::NONE) {
|
||||
snprintf(one, sizeof(one), "FAIL %s %.0f%%", target, actual_.actualDutyPct);
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target, actual_.actualDutyPct);
|
||||
if (s.reason == FailReason::PERIOD_OUT && s.badFrequency > 0.0f) {
|
||||
char frequency[12];
|
||||
Display::formatTestFrequency(static_cast<uint32_t>(lroundf(s.badFrequency)), frequency, sizeof(frequency));
|
||||
snprintf(two, sizeof(two), "PERIOD OUT %s", frequency);
|
||||
snprintf(two, sizeof(two), UiText::PERIOD_OUT_FORMAT, frequency);
|
||||
} else if (s.reason == FailReason::DUTY_OUT && s.badFrequency > 0.0f) {
|
||||
char duty[10]; formatErrorDuty(s.badDuty, duty, sizeof(duty));
|
||||
snprintf(two, sizeof(two), "DUTY OUT %s", duty);
|
||||
snprintf(two, sizeof(two), UiText::DUTY_OUT_FORMAT, duty);
|
||||
} else {
|
||||
snprintf(two, sizeof(two), "%s", failName(s.reason));
|
||||
snprintf(two, sizeof(two), "%s", uiFailName(s.reason));
|
||||
}
|
||||
display_.show(one, two, overallProgress(stageIndex_, measurement_.progressStep()),
|
||||
overallProgressTotal(stageCount_));
|
||||
return;
|
||||
}
|
||||
snprintf(one, sizeof(one), "Test:%-6s %2.0f%% %2lu/%2lu",
|
||||
target, actual_.actualDutyPct, stageIndex_ + 1, stageCount_);
|
||||
char stage[12]; snprintf(stage, sizeof(stage), "%lu/%lu", stageIndex_ + 1, stageCount_);
|
||||
snprintf(one, sizeof(one), UiText::TEST_FORMAT, target, actual_.actualDutyPct, stage);
|
||||
if (!s.periods || !s.periodSum) {
|
||||
display_.show(one, "F:--- D:---%", overallProgress(stageIndex_, measurement_.progressStep()),
|
||||
display_.show(one, UiText::NO_MEASUREMENT, overallProgress(stageIndex_, measurement_.progressStep()),
|
||||
overallProgressTotal(stageCount_));
|
||||
return;
|
||||
}
|
||||
@@ -775,29 +801,30 @@ void App::showStageResult(const StageStats &s) {
|
||||
void App::showRemoteResult(const ProtocolPacket &packet) {
|
||||
const FailReason reason = packet.reason <= static_cast<uint8_t>(FailReason::ABORTED)
|
||||
? static_cast<FailReason>(packet.reason) : FailReason::UNSUPPORTED;
|
||||
char target[12], one[24], two[24];
|
||||
char target[12], one[64], two[64];
|
||||
Display::formatTestFrequency(packet.actualHz ? packet.actualHz : packet.requestedHz,
|
||||
target, sizeof(target));
|
||||
if (reason == FailReason::NONE) {
|
||||
snprintf(one, sizeof(one), "Test:%-6s %2.0f%% %2lu/%2lu",
|
||||
target, packet.actualDutyX100 / 100.0f, stageIndex_ + 1, stageCount_);
|
||||
char stage[12]; snprintf(stage, sizeof(stage), "%lu/%lu", stageIndex_ + 1, stageCount_);
|
||||
snprintf(one, sizeof(one), UiText::TEST_FORMAT,
|
||||
target, packet.actualDutyX100 / 100.0f, stage);
|
||||
if (packet.measuredHzX10) {
|
||||
char measured[12];
|
||||
Display::formatFrequency(packet.measuredHzX10 / 10.0f, measured, sizeof(measured));
|
||||
snprintf(two, sizeof(two), "F:%-8s D:%4.1f%%", measured, packet.measuredDutyX10 / 10.0f);
|
||||
} else snprintf(two, sizeof(two), "F:--- D:---%%");
|
||||
} else snprintf(two, sizeof(two), "%s", UiText::NO_MEASUREMENT);
|
||||
} else if (reason == FailReason::PERIOD_OUT && packet.measuredHzX10) {
|
||||
snprintf(one, sizeof(one), "FAIL %s %.0f%%", target, packet.actualDutyX100 / 100.0f);
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target, packet.actualDutyX100 / 100.0f);
|
||||
char measured[12];
|
||||
Display::formatTestFrequency((packet.measuredHzX10 + 5U) / 10U, measured, sizeof(measured));
|
||||
snprintf(two, sizeof(two), "PERIOD OUT %s", measured);
|
||||
snprintf(two, sizeof(two), UiText::PERIOD_OUT_FORMAT, measured);
|
||||
} else if (reason == FailReason::DUTY_OUT && packet.measuredDutyX10) {
|
||||
snprintf(one, sizeof(one), "FAIL %s %.0f%%", target, packet.actualDutyX100 / 100.0f);
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target, packet.actualDutyX100 / 100.0f);
|
||||
char duty[10]; formatErrorDuty(packet.measuredDutyX10 / 10.0f, duty, sizeof(duty));
|
||||
snprintf(two, sizeof(two), "DUTY OUT %s", duty);
|
||||
snprintf(two, sizeof(two), UiText::DUTY_OUT_FORMAT, duty);
|
||||
} else {
|
||||
snprintf(one, sizeof(one), "FAIL %s %.0f%%", target, packet.actualDutyX100 / 100.0f);
|
||||
snprintf(two, sizeof(two), "%s", failName(reason));
|
||||
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target, packet.actualDutyX100 / 100.0f);
|
||||
snprintf(two, sizeof(two), "%s", uiFailName(reason));
|
||||
}
|
||||
display_.show(one, two, overallProgress(stageIndex_, packet.progressStep),
|
||||
overallProgressTotal(stageCount_));
|
||||
@@ -817,10 +844,10 @@ void App::fillMeasuredResult(ProtocolPacket &packet, const StageStats &stats) co
|
||||
}
|
||||
|
||||
void App::showStageProgress() {
|
||||
char target[12], one[24];
|
||||
char target[12], one[64], stage[12];
|
||||
Display::formatTestFrequency(actual_.actualHz, target, sizeof(target));
|
||||
snprintf(one, sizeof(one), "Test:%-6s %2.0f%% %2lu/%2lu",
|
||||
target, actual_.actualDutyPct, stageIndex_ + 1, stageCount_);
|
||||
display_.show(one, "F:--- D:---%", overallProgress(stageIndex_, 0),
|
||||
snprintf(stage, sizeof(stage), "%lu/%lu", stageIndex_ + 1, stageCount_);
|
||||
snprintf(one, sizeof(one), UiText::TEST_FORMAT, target, actual_.actualDutyPct, stage);
|
||||
display_.show(one, UiText::NO_MEASUREMENT, overallProgress(stageIndex_, 0),
|
||||
overallProgressTotal(stageCount_));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user