доработки по интерфейсу
This commit is contained in:
@@ -123,13 +123,16 @@ void formatMenuLine(const char *label, const char *value, char *out, size_t size
|
|||||||
snprintf(out, size, "%s%*s%s", label, padding, "", value);
|
snprintf(out, size, "%s%*s%s", label, padding, "", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t overallProgress(uint32_t stageIndex, uint8_t step) {
|
uint32_t overallProgress(uint32_t stageIndex, uint8_t step,
|
||||||
if (step > MEASUREMENT_PROGRESS_STEPS) step = MEASUREMENT_PROGRESS_STEPS;
|
uint8_t stepsPerStage = MEASUREMENT_PROGRESS_STEPS) {
|
||||||
return stageIndex * MEASUREMENT_PROGRESS_STEPS + step;
|
if (step > stepsPerStage) step = stepsPerStage;
|
||||||
|
return stageIndex * stepsPerStage + step;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t overallProgressTotal(uint32_t stageCount) {
|
uint32_t overallProgressTotal(
|
||||||
return stageCount * MEASUREMENT_PROGRESS_STEPS;
|
uint32_t stageCount,
|
||||||
|
uint8_t stepsPerStage = MEASUREMENT_PROGRESS_STEPS) {
|
||||||
|
return stageCount * stepsPerStage;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t stageWallTimeMs(uint32_t testTimeMs, uint32_t frequencyHz) {
|
uint32_t stageWallTimeMs(uint32_t testTimeMs, uint32_t frequencyHz) {
|
||||||
@@ -1536,10 +1539,13 @@ void App::showDriverResult(const DriverStats &s, bool testPassed) {
|
|||||||
snprintf(two, sizeof(two), UiText::DRIVER_MEASUREMENT_FORMAT,
|
snprintf(two, sizeof(two), UiText::DRIVER_MEASUREMENT_FORMAT,
|
||||||
delay, response);
|
delay, response);
|
||||||
}
|
}
|
||||||
|
const bool finished = testPassed || s.reason != FailReason::NONE;
|
||||||
|
const uint8_t progressSteps = driverTest_.progressSteps();
|
||||||
display_.show(one, two,
|
display_.show(one, two,
|
||||||
overallProgress(stageIndex_, driverTest_.progressStep()),
|
finished ? 0U : overallProgress(
|
||||||
overallProgressTotal(stageCount_), s.reason == FailReason::NONE ? nullptr :
|
stageIndex_, driverTest_.progressStep(), progressSteps),
|
||||||
roleCorner(Role::SOLO));
|
finished ? 0U : overallProgressTotal(stageCount_, progressSteps),
|
||||||
|
s.reason == FailReason::NONE ? nullptr : roleCorner(Role::SOLO));
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::showRemoteResult(const ProtocolPacket &packet) {
|
void App::showRemoteResult(const ProtocolPacket &packet) {
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ static_assert(MEASUREMENT_AVERAGING_PERIODS > 0,
|
|||||||
"Averaging window must contain at least one period");
|
"Averaging window must contain at least one period");
|
||||||
constexpr uint8_t MEASUREMENT_PROGRESS_STEPS = 10;
|
constexpr uint8_t MEASUREMENT_PROGRESS_STEPS = 10;
|
||||||
constexpr uint32_t OLED_PROGRESS_UPDATE_MS = 15;
|
constexpr uint32_t OLED_PROGRESS_UPDATE_MS = 15;
|
||||||
|
constexpr uint8_t DRIVER_SHORT_SAMPLE_PROGRESS_STEPS = 10;
|
||||||
|
constexpr uint32_t DRIVER_PROGRESS_INTERVAL_MS = 100;
|
||||||
|
|
||||||
constexpr uint32_t IDLE_POWER_SAVE_TIMEOUT_MS = 60000;
|
constexpr uint32_t IDLE_POWER_SAVE_TIMEOUT_MS = 60000;
|
||||||
// usb_serial_jtag_is_connected() needs no open COM port or CDC traffic, but a
|
// usb_serial_jtag_is_connected() needs no open COM port or CDC traffic, but a
|
||||||
@@ -162,10 +164,10 @@ constexpr uint32_t DRIVER_RESPONSE_TIMEOUT_NS = 10000;
|
|||||||
// the selected maximum down to the selected minimum. Widths are stored in
|
// the selected maximum down to the selected minimum. Widths are stored in
|
||||||
// nanoseconds so sub-microsecond pulses remain representable without floats.
|
// nanoseconds so sub-microsecond pulses remain representable without floats.
|
||||||
constexpr uint32_t PWM_FREQUENCY_OPTIONS_HZ[] = {
|
constexpr uint32_t PWM_FREQUENCY_OPTIONS_HZ[] = {
|
||||||
500, 1000, 2000, 5000, 10000, 25000,
|
500, 1000, 2000, 5000, 10000,
|
||||||
};
|
};
|
||||||
constexpr uint32_t MAX_PULSE_OPTIONS_NS[] = {
|
constexpr uint32_t MAX_PULSE_OPTIONS_NS[] = {
|
||||||
2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000
|
2000, 5000, 10000, 50000, 100000, 500000
|
||||||
};
|
};
|
||||||
constexpr uint32_t MIN_PULSE_OPTIONS_NS[] = {
|
constexpr uint32_t MIN_PULSE_OPTIONS_NS[] = {
|
||||||
250, 500, 1000, 2000, 5000, 10000, 50000
|
250, 500, 1000, 2000, 5000, 10000, 50000
|
||||||
@@ -175,6 +177,6 @@ constexpr uint32_t TEST_PULSE_WIDTHS_NS[] = {
|
|||||||
100000, 200000, 500000, 1000000
|
100000, 200000, 500000, 1000000
|
||||||
};
|
};
|
||||||
constexpr float ACCURACY_OPTIONS_PCT[] = {1.0f, 2.0f, 5.0f, 10.0f};
|
constexpr float ACCURACY_OPTIONS_PCT[] = {1.0f, 2.0f, 5.0f, 10.0f};
|
||||||
constexpr uint32_t TEST_TIME_OPTIONS_MS[] = {100, 250, 500, 1000, 2000, 5000};
|
constexpr uint32_t TEST_TIME_OPTIONS_MS[] = {100, 250, 500, 1000, 2000, 5000, 60000};
|
||||||
|
|
||||||
template <typename T, size_t N> constexpr size_t countOf(const T (&)[N]) { return N; }
|
template <typename T, size_t N> constexpr size_t countOf(const T (&)[N]) { return N; }
|
||||||
|
|||||||
@@ -5,11 +5,22 @@
|
|||||||
|
|
||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
#include <esp_cpu.h>
|
#include <esp_cpu.h>
|
||||||
|
#include <esp_task_wdt.h>
|
||||||
#include <esp_timer.h>
|
#include <esp_timer.h>
|
||||||
#include <esp32-hal-cpu.h>
|
#include <esp32-hal-cpu.h>
|
||||||
#include <soc/gpio_struct.h>
|
#include <soc/gpio_struct.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static inline uint32_t IRAM_ATTR maskAllInterrupts() {
|
||||||
|
uint32_t state;
|
||||||
|
asm volatile("rsil %0, 15" : "=a"(state) :: "memory");
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void IRAM_ATTR restoreInterrupts(uint32_t state) {
|
||||||
|
asm volatile("wsr %0, ps\nrsync" :: "a"(state) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
void DriverEdgeStats::reset() {
|
void DriverEdgeStats::reset() {
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
minDelayTicks = minResponseTicks = UINT32_MAX;
|
minDelayTicks = minResponseTicks = UINT32_MAX;
|
||||||
@@ -78,7 +89,13 @@ bool DriverTest::start(uint32_t frequencyHz, uint32_t pulseNs,
|
|||||||
faultLongTicks_ = nsToTicks(DRIVER_FAULT_MIN_NS);
|
faultLongTicks_ = nsToTicks(DRIVER_FAULT_MIN_NS);
|
||||||
stuckTicks_ = nsToTicks(DRIVER_RX_STUCK_MIN_NS);
|
stuckTicks_ = nsToTicks(DRIVER_RX_STUCK_MIN_NS);
|
||||||
testTicks_ = static_cast<uint64_t>(captureHz_) * testTimeMs / 1000ULL;
|
testTicks_ = static_cast<uint64_t>(captureHz_) * testTimeMs / 1000ULL;
|
||||||
subsampleTicks_ = testTicks_ / SUBSAMPLE_COUNT;
|
const uint32_t requestedSubsamples = testTimeMs < 1000U ?
|
||||||
|
DRIVER_SHORT_SAMPLE_PROGRESS_STEPS :
|
||||||
|
(testTimeMs + DRIVER_PROGRESS_INTERVAL_MS - 1U) /
|
||||||
|
DRIVER_PROGRESS_INTERVAL_MS;
|
||||||
|
subsampleCount_ = static_cast<uint8_t>(
|
||||||
|
requestedSubsamples > UINT8_MAX ? UINT8_MAX : requestedSubsamples);
|
||||||
|
subsampleTicks_ = testTicks_ / subsampleCount_;
|
||||||
if (!pollPeriodCycles_ || !pollWindowAfterCycles_ ||
|
if (!pollPeriodCycles_ || !pollWindowAfterCycles_ ||
|
||||||
!ackStartMaxTicks_ || !faultLongTicks_ || !stuckTicks_ ||
|
!ackStartMaxTicks_ || !faultLongTicks_ || !stuckTicks_ ||
|
||||||
!testTicks_ || !subsampleTicks_)
|
!testTicks_ || !subsampleTicks_)
|
||||||
@@ -117,14 +134,14 @@ bool DriverTest::start(uint32_t frequencyHz, uint32_t pulseNs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DriverTest::armCapture() {
|
bool DriverTest::armCapture() {
|
||||||
Serial.flush();
|
// Never wait for USB/Serial here: a disconnected or slow host must not
|
||||||
|
// delay a subsample or consume the test's global timeout.
|
||||||
if (!__atomic_load_n(&core0WdtDisabled_, __ATOMIC_ACQUIRE)) {
|
if (!__atomic_load_n(&core0WdtDisabled_, __ATOMIC_ACQUIRE)) {
|
||||||
const bool disabled = disableCore0WDT();
|
TaskHandle_t idle0 = xTaskGetIdleTaskHandleForCore(0);
|
||||||
|
const bool watched = idle0 && esp_task_wdt_status(idle0) == ESP_OK;
|
||||||
|
const bool disabled = watched && disableCore0WDT();
|
||||||
__atomic_store_n(&core0WdtDisabled_, disabled, __ATOMIC_RELEASE);
|
__atomic_store_n(&core0WdtDisabled_, disabled, __ATOMIC_RELEASE);
|
||||||
if (!disabled) {
|
// If IDLE0 is not watched there is nothing to remove or restore.
|
||||||
state_ = DriverState::IDLE;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
__atomic_store_n(&captureReady_, false, __ATOMIC_RELEASE);
|
__atomic_store_n(&captureReady_, false, __ATOMIC_RELEASE);
|
||||||
__atomic_store_n(&captureActive_, true, __ATOMIC_RELEASE);
|
__atomic_store_n(&captureActive_, true, __ATOMIC_RELEASE);
|
||||||
@@ -184,6 +201,8 @@ void IRAM_ATTR DriverTest::pollTaskLoop() {
|
|||||||
uint8_t hotCount = 0;
|
uint8_t hotCount = 0;
|
||||||
bool sawTxStart = false;
|
bool sawTxStart = false;
|
||||||
bool critical = false;
|
bool critical = false;
|
||||||
|
bool allInterruptsMasked = false;
|
||||||
|
uint32_t interruptState = 0;
|
||||||
|
|
||||||
auto sampleOnce = [&]() {
|
auto sampleOnce = [&]() {
|
||||||
const uint32_t current = GPIO.in & PIN_MASK;
|
const uint32_t current = GPIO.in & PIN_MASK;
|
||||||
@@ -218,12 +237,18 @@ void IRAM_ATTR DriverTest::pollTaskLoop() {
|
|||||||
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
||||||
if (sawTxStart) windowEnd = lastTxStart + pollWindowAfterCycles_;
|
if (sawTxStart) windowEnd = lastTxStart + pollWindowAfterCycles_;
|
||||||
const bool synchronized = sawTxStart;
|
const bool synchronized = sawTxStart;
|
||||||
|
if (synchronized) {
|
||||||
|
interruptState = maskAllInterrupts();
|
||||||
|
allInterruptsMasked = true;
|
||||||
|
}
|
||||||
|
|
||||||
while (__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE) && synchronized) {
|
while (__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE) && synchronized) {
|
||||||
while (__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE) &&
|
while (__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE) &&
|
||||||
static_cast<int32_t>(esp_cpu_get_cycle_count() - windowEnd) < 0)
|
static_cast<int32_t>(esp_cpu_get_cycle_count() - windowEnd) < 0)
|
||||||
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
||||||
|
|
||||||
|
restoreInterrupts(interruptState);
|
||||||
|
allInterruptsMasked = false;
|
||||||
portEXIT_CRITICAL(&pollMux_);
|
portEXIT_CRITICAL(&pollMux_);
|
||||||
critical = false;
|
critical = false;
|
||||||
flushHot();
|
flushHot();
|
||||||
@@ -249,8 +274,11 @@ void IRAM_ATTR DriverTest::pollTaskLoop() {
|
|||||||
|
|
||||||
portENTER_CRITICAL(&pollMux_);
|
portENTER_CRITICAL(&pollMux_);
|
||||||
critical = true;
|
critical = true;
|
||||||
|
interruptState = maskAllInterrupts();
|
||||||
|
allInterruptsMasked = true;
|
||||||
windowEnd = nextStart + pollWindowAfterCycles_;
|
windowEnd = nextStart + pollWindowAfterCycles_;
|
||||||
}
|
}
|
||||||
|
if (allInterruptsMasked) restoreInterrupts(interruptState);
|
||||||
if (critical) portEXIT_CRITICAL(&pollMux_);
|
if (critical) portEXIT_CRITICAL(&pollMux_);
|
||||||
flushHot();
|
flushHot();
|
||||||
if (__atomic_exchange_n(&core0WdtDisabled_, false,
|
if (__atomic_exchange_n(&core0WdtDisabled_, false,
|
||||||
@@ -325,7 +353,7 @@ void DriverTest::processSettling(const TimedEvent &event) {
|
|||||||
const uint64_t measuredBefore =
|
const uint64_t measuredBefore =
|
||||||
static_cast<uint64_t>(completedSubsamples_) * subsampleTicks_;
|
static_cast<uint64_t>(completedSubsamples_) * subsampleTicks_;
|
||||||
const uint64_t thisSubsampleTicks =
|
const uint64_t thisSubsampleTicks =
|
||||||
completedSubsamples_ + 1U == SUBSAMPLE_COUNT ?
|
completedSubsamples_ + 1U == subsampleCount_ ?
|
||||||
testTicks_ - measuredBefore : subsampleTicks_;
|
testTicks_ - measuredBefore : subsampleTicks_;
|
||||||
deadlineTick_ = event.tick + thisSubsampleTicks;
|
deadlineTick_ = event.tick + thisSubsampleTicks;
|
||||||
processTx(event, lightOn);
|
processTx(event, lightOn);
|
||||||
@@ -509,7 +537,7 @@ void DriverTest::completeIfPossible(uint64_t now) {
|
|||||||
fail(FailReason::DATA_LOSS, lastEventTick_);
|
fail(FailReason::DATA_LOSS, lastEventTick_);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (completedSubsamples_ >= SUBSAMPLE_COUNT) {
|
if (completedSubsamples_ >= subsampleCount_) {
|
||||||
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
state_ = DriverState::PASS;
|
state_ = DriverState::PASS;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class DriverTest {
|
|||||||
void printSummary() const;
|
void printSummary() const;
|
||||||
void printTrace() const;
|
void printTrace() const;
|
||||||
uint8_t progressStep() const { return currentStep_; }
|
uint8_t progressStep() const { return currentStep_; }
|
||||||
|
uint8_t progressSteps() const { return subsampleCount_; }
|
||||||
uint32_t tickHz() const { return captureHz_; }
|
uint32_t tickHz() const { return captureHz_; }
|
||||||
const DriverStats &stats() const { return publishedStats_; }
|
const DriverStats &stats() const { return publishedStats_; }
|
||||||
|
|
||||||
@@ -113,7 +114,6 @@ class DriverTest {
|
|||||||
uint64_t ticksToNs(uint64_t ticks) const;
|
uint64_t ticksToNs(uint64_t ticks) const;
|
||||||
|
|
||||||
static constexpr uint8_t MAX_PENDING = 8;
|
static constexpr uint8_t MAX_PENDING = 8;
|
||||||
static constexpr uint8_t SUBSAMPLE_COUNT = 10;
|
|
||||||
static constexpr uint16_t RING_CAPACITY = 2048;
|
static constexpr uint16_t RING_CAPACITY = 2048;
|
||||||
static constexpr uint8_t TRACE_CAPACITY = 32;
|
static constexpr uint8_t TRACE_CAPACITY = 32;
|
||||||
static_assert((RING_CAPACITY & (RING_CAPACITY - 1U)) == 0,
|
static_assert((RING_CAPACITY & (RING_CAPACITY - 1U)) == 0,
|
||||||
@@ -161,6 +161,7 @@ class DriverTest {
|
|||||||
uint64_t lastActiveTxTick_ = 0;
|
uint64_t lastActiveTxTick_ = 0;
|
||||||
uint8_t settleCycles_ = 0;
|
uint8_t settleCycles_ = 0;
|
||||||
uint8_t settledCycles_ = 0;
|
uint8_t settledCycles_ = 0;
|
||||||
|
uint8_t subsampleCount_ = DRIVER_SHORT_SAMPLE_PROGRESS_STEPS;
|
||||||
uint8_t completedSubsamples_ = 0;
|
uint8_t completedSubsamples_ = 0;
|
||||||
bool rxActiveRawHigh_ = true;
|
bool rxActiveRawHigh_ = true;
|
||||||
bool txPulseLightOn_ = true;
|
bool txPulseLightOn_ = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user