Compare commits
28 Commits
fb40f3ddef
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dda98860d1 | ||
|
|
30264698b8 | ||
|
|
e1fcd0b7fe | ||
|
|
a2de62f61d | ||
|
|
bff0294a22 | ||
|
|
8699f8e4eb | ||
|
|
3907cbcf77 | ||
|
|
49332aa028 | ||
|
|
035792aedd | ||
|
|
037bb37e62 | ||
|
|
a17e8962b4 | ||
|
|
1db89fca79 | ||
|
|
862781fa6a | ||
|
|
f56595f767 | ||
|
|
9d474eb62b | ||
|
|
7db164b979 | ||
|
|
eaddf277ea | ||
|
|
706ae4de82 | ||
|
|
cec997d1d2 | ||
|
|
61d3aeaba6 | ||
|
|
34581913ff | ||
|
|
be1a90afac | ||
|
|
70fe3566b4 | ||
|
|
c952c165f8 | ||
|
|
21f8fe8e13 | ||
|
|
a8099bf2b8 | ||
|
|
4b88ac6a42 | ||
|
|
f52f65686d |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1 +1,8 @@
|
|||||||
/tests/
|
/tests/
|
||||||
|
__Previews/
|
||||||
|
History
|
||||||
|
Project Logs*/
|
||||||
|
Project Outputs*/
|
||||||
|
/.build/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[submodule "PCB_Charger"]
|
||||||
|
path = PCB_Charger
|
||||||
|
url = https://git.rd12.ru/Razvalyaev/Charger.git
|
||||||
|
branch = master
|
||||||
@@ -1,15 +1,26 @@
|
|||||||
#include "App.h"
|
#include "App.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "Config_Text.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <esp_mac.h>
|
#include <esp_mac.h>
|
||||||
|
#include <esp_sleep.h>
|
||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
|
#include <esp32-hal-cpu.h>
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
constexpr uint8_t MENU_OPTICAL_CALIBRATION_ITEM = 7;
|
||||||
|
|
||||||
|
const char *uiFailName(FailReason reason);
|
||||||
|
|
||||||
const char *appStateName(AppState state) {
|
const char *appStateName(AppState state) {
|
||||||
static const char *names[] = {"IDLE", "MENU", "SOLO_MEASURE", "MASTER_DISCOVER",
|
static const char *names[] = {"IDLE", "MENU", "BOARD_TEST", "SOLO_MEASURE", "SOLO_DRIVER", "MASTER_DISCOVER",
|
||||||
"MASTER_WAIT_READY", "MASTER_WAIT_RESULT", "SLAVE_READY", "SLAVE_WAIT_START",
|
"MASTER_WAIT_READY", "MASTER_WAIT_RESULT", "MASTER_FINALIZE", "SLAVE_READY", "SLAVE_WAIT_START",
|
||||||
"SLAVE_MEASURE", "SLAVE_WAIT_ACK", "FINISHED"};
|
"SLAVE_MEASURE", "SLAVE_WAIT_ACK", "FINISHED"};
|
||||||
const uint8_t index = static_cast<uint8_t>(state);
|
const uint8_t index = static_cast<uint8_t>(state);
|
||||||
return index < sizeof(names) / sizeof(names[0]) ? names[index] : "UNKNOWN";
|
return index < sizeof(names) / sizeof(names[0]) ? names[index] : "UNKNOWN";
|
||||||
@@ -20,12 +31,272 @@ const char *buttonEventName(ButtonEvent event) {
|
|||||||
const uint8_t index = static_cast<uint8_t>(event);
|
const uint8_t index = static_cast<uint8_t>(event);
|
||||||
return index < sizeof(names) / sizeof(names[0]) ? names[index] : "UNKNOWN";
|
return index < sizeof(names) / sizeof(names[0]) ? names[index] : "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t pulseFromDuty(float hz, float dutyPct) {
|
||||||
|
return hz > 0.0f ? static_cast<uint32_t>(lroundf(dutyPct * 10000000.0f / hz)) : 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
App::App() : startButton_(GPIO_BUTTON_START), modeButton_(GPIO_BUTTON_MODE), measurement_(receiver_) {}
|
float dutyFromPulse(uint32_t hz, uint32_t pulseNs) {
|
||||||
|
return static_cast<float>(static_cast<double>(hz) * pulseNs / 10000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool configuredTxPulseLightOn(const Settings &settings) {
|
||||||
|
return static_cast<TestKind>(settings.testKind) == TestKind::DRIVER
|
||||||
|
? txActiveLightOn(settings) : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *configuredLevelName(const Settings &settings) {
|
||||||
|
return static_cast<TestKind>(settings.testKind) == TestKind::DRIVER
|
||||||
|
? lightCodeName(static_cast<LightCode>(settings.lightCode)) : "AUTO";
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatTarget(uint32_t hz, uint32_t pulseNs, char *out, size_t size) {
|
||||||
|
char frequency[16], pulse[12];
|
||||||
|
Display::formatPwmFrequency(hz, frequency, sizeof(frequency));
|
||||||
|
Display::formatPulse(pulseNs, pulse, sizeof(pulse));
|
||||||
|
snprintf(out, size, UiText::TEST_FORMAT, frequency, pulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatMeasured(float hz, uint32_t pulseNs, char *out, size_t size) {
|
||||||
|
char frequency[12], pulse[12];
|
||||||
|
Display::formatFrequency(hz, frequency, sizeof(frequency));
|
||||||
|
Display::formatPulse(pulseNs, pulse, sizeof(pulse), true);
|
||||||
|
snprintf(out, size, "F:%s, P:%s", frequency, pulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatTestTarget(uint32_t hz, uint32_t pulseNs, char *out, size_t size) {
|
||||||
|
char target[32];
|
||||||
|
formatTarget(hz, pulseNs, target, sizeof(target));
|
||||||
|
snprintf(out, size, UiText::TEST_TARGET_FORMAT, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatFailure(FailReason reason, uint32_t hz, uint32_t pulseNs,
|
||||||
|
char *out, size_t size) {
|
||||||
|
(void)reason;
|
||||||
|
char target[32];
|
||||||
|
formatTarget(hz, pulseNs, target, sizeof(target));
|
||||||
|
snprintf(out, size, UiText::FAIL_TARGET_FORMAT, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatElapsedNs(uint64_t ns, char *out, size_t size) {
|
||||||
|
// Compact form keeps error timing within 21 OLED columns.
|
||||||
|
// Exact nanoseconds remain available in the Serial diagnostic.
|
||||||
|
if (ns < 1000ULL) snprintf(out, size, "%llun", ns);
|
||||||
|
else if (ns < 1000000ULL) snprintf(out, size, "%.1fu", ns / 1000.0);
|
||||||
|
else if (ns < 1000000000ULL) snprintf(out, size, "%.0fm", ns / 1000000.0);
|
||||||
|
else snprintf(out, size, "%.2fs", ns / 1000000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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,
|
||||||
|
uint8_t stepsPerStage = MEASUREMENT_PROGRESS_STEPS) {
|
||||||
|
if (step > stepsPerStage) step = stepsPerStage;
|
||||||
|
return stageIndex * stepsPerStage + step;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t overallProgressTotal(
|
||||||
|
uint32_t stageCount,
|
||||||
|
uint8_t stepsPerStage = MEASUREMENT_PROGRESS_STEPS) {
|
||||||
|
return stageCount * stepsPerStage;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stageWallTimeMs(uint32_t testTimeMs, uint32_t frequencyHz) {
|
||||||
|
return static_cast<uint32_t>((nominalStageUs(frequencyHz, testTimeMs, PWM_SETTLE_CYCLES) + 999ULL) / 1000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *uiTestName(TestKind kind) {
|
||||||
|
const uint8_t index = static_cast<uint8_t>(kind);
|
||||||
|
return index < sizeof(UiText::TEST_NAMES) / sizeof(UiText::TEST_NAMES[0])
|
||||||
|
? UiText::TEST_NAMES[index] : "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *uiTestGroupName(TestGroup group) {
|
||||||
|
const uint8_t index = static_cast<uint8_t>(group);
|
||||||
|
return index < sizeof(UiText::TEST_GROUP_NAMES) / sizeof(UiText::TEST_GROUP_NAMES[0])
|
||||||
|
? UiText::TEST_GROUP_NAMES[index] : "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *uiBoardTestName(BoardTest test) {
|
||||||
|
const uint8_t index = static_cast<uint8_t>(test);
|
||||||
|
return index < sizeof(UiText::BOARD_TEST_NAMES) / sizeof(UiText::BOARD_TEST_NAMES[0])
|
||||||
|
? UiText::BOARD_TEST_NAMES[index] : "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boardTestAvailable(BoardTest test) {
|
||||||
|
if (test == BoardTest::PWM_OUTPUT) return true;
|
||||||
|
if (test == BoardTest::ADC) return BOARD_RX_USES_ADC && BOARD_ADC_AVAILABLE;
|
||||||
|
if (test == BoardTest::RX_INPUT) return !BOARD_RX_USES_ADC;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoardTest defaultBoardTest() {
|
||||||
|
return BOARD_RX_USES_ADC && BOARD_ADC_AVAILABLE
|
||||||
|
? BoardTest::ADC : BoardTest::RX_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t lastValidMaxPulseIndex(uint32_t frequencyHz) {
|
||||||
|
uint8_t last = static_cast<uint8_t>(countOf(MAX_PULSE_OPTIONS_NS) - 1U);
|
||||||
|
while (last && static_cast<uint64_t>(MAX_PULSE_OPTIONS_NS[last]) * frequencyHz >= 1000000000ULL)
|
||||||
|
--last;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t firstMaxPulseIndexAtLeast(uint32_t pulseNs, uint8_t last) {
|
||||||
|
for (uint8_t i = 0; i <= last; ++i)
|
||||||
|
if (MAX_PULSE_OPTIONS_NS[i] >= pulseNs) return i;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t lastMinPulseIndexAtMost(uint32_t pulseNs) {
|
||||||
|
for (size_t i = countOf(MIN_PULSE_OPTIONS_NS); i > 0; --i)
|
||||||
|
if (MIN_PULSE_OPTIONS_NS[i - 1U] <= pulseNs) return static_cast<uint8_t>(i - 1U);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t plannedPulseCaptureHz(uint32_t frequencyHz, float dutyPct) {
|
||||||
|
if (!frequencyHz || dutyPct <= 0.0f || dutyPct >= 100.0f) return 0;
|
||||||
|
return MCPWM_CAPTURE_RESOLUTION_HZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t plannedCaptureHz(uint32_t frequencyHz, float dutyPct) {
|
||||||
|
// One 32-bit S3 MCPWM capture timer measures period and pulse at 80 MHz.
|
||||||
|
return plannedPulseCaptureHz(frequencyHz, dutyPct);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pulsePointHasResolution(uint32_t hz, uint32_t pulseNs, float accuracyPct) {
|
||||||
|
uint32_t actualHz = 0, actualPulseNs = 0;
|
||||||
|
uint8_t bits = 0;
|
||||||
|
if (TARGET_IS_C3) {
|
||||||
|
IntegerPwmConfig config = {};
|
||||||
|
if (!choosePwmConfig(hz, pulseNs, LEDC_SOURCE_CLOCK_HZ, LEDC_MAX_BITS, config)) return false;
|
||||||
|
actualHz = config.actualHz;
|
||||||
|
actualPulseNs = config.actualPulseNs;
|
||||||
|
bits = config.bits;
|
||||||
|
} else {
|
||||||
|
if (!hz || MCPWM_RESOLUTION_HZ % hz) return false;
|
||||||
|
const uint32_t periodTicks = MCPWM_RESOLUTION_HZ / hz;
|
||||||
|
if (periodTicks < 2U || periodTicks > MCPWM_MAX_PERIOD_TICKS) return false;
|
||||||
|
uint32_t activeTicks = static_cast<uint32_t>(
|
||||||
|
(static_cast<uint64_t>(pulseNs) * MCPWM_RESOLUTION_HZ + 500000000ULL) / 1000000000ULL);
|
||||||
|
if (!activeTicks || activeTicks >= periodTicks) return false;
|
||||||
|
actualHz = hz;
|
||||||
|
actualPulseNs = static_cast<uint32_t>(
|
||||||
|
(static_cast<uint64_t>(activeTicks) * 1000000000ULL + MCPWM_RESOLUTION_HZ / 2U) /
|
||||||
|
MCPWM_RESOLUTION_HZ);
|
||||||
|
bits = 1;
|
||||||
|
for (uint32_t ticks = periodTicks; ticks > 1U; ticks >>= 1U) ++bits;
|
||||||
|
}
|
||||||
|
if (!periodWithin(actualHz, hz, accuracyPct) ||
|
||||||
|
!periodWithin(actualPulseNs, pulseNs, accuracyPct)) return false;
|
||||||
|
const float dutyPct = dutyFromPulse(actualHz, actualPulseNs);
|
||||||
|
const uint32_t captureHz = plannedCaptureHz(actualHz, dutyPct);
|
||||||
|
const uint32_t pulseCaptureHz = plannedPulseCaptureHz(actualHz, dutyPct);
|
||||||
|
return captureHz && pulseCaptureHz && validateResolution(actualHz, dutyPct, accuracyPct,
|
||||||
|
captureHz, pulseCaptureHz, bits, MEASUREMENT_AVERAGING_PERIODS) == FailReason::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t minimumPulseForAccuracy(uint32_t frequencyHz, float accuracyPct) {
|
||||||
|
for (uint32_t pulseNs : TEST_PULSE_WIDTHS_NS)
|
||||||
|
if (pulsePointHasResolution(frequencyHz, pulseNs, accuracyPct)) return pulseNs;
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t firstMinPulseIndexAtLeast(uint32_t pulseNs, uint8_t last) {
|
||||||
|
for (uint8_t i = 0; i <= last; ++i)
|
||||||
|
if (MIN_PULSE_OPTIONS_NS[i] >= pulseNs) return i;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cycleIndex(uint8_t value, uint8_t first, uint8_t last, int direction) {
|
||||||
|
if (first >= last) return first;
|
||||||
|
if (direction > 0) return value >= last ? first : static_cast<uint8_t>(value + 1U);
|
||||||
|
return value <= first ? last : static_cast<uint8_t>(value - 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nextMenuItem(uint8_t current, TestGroup group) {
|
||||||
|
if (group == TestGroup::BOARD)
|
||||||
|
return current == 0U ? MENU_OPTICAL_CALIBRATION_ITEM : 0U;
|
||||||
|
return current >= MENU_OPTICAL_CALIBRATION_ITEM ? 0U
|
||||||
|
: static_cast<uint8_t>(current + 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseUnsigned(const char *text, uint32_t &value) {
|
||||||
|
if (!text || !*text || *text == '-') return false;
|
||||||
|
char *end = nullptr;
|
||||||
|
const unsigned long parsed = strtoul(text, &end, 10);
|
||||||
|
if (!end || *end) return false;
|
||||||
|
value = static_cast<uint32_t>(parsed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
int optionIndex(const uint32_t (&options)[N], uint32_t value) {
|
||||||
|
for (size_t i = 0; i < N; ++i)
|
||||||
|
if (options[i] == value) return static_cast<int>(i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int accuracyOptionIndex(const char *text) {
|
||||||
|
if (!text || !*text) return -1;
|
||||||
|
char *end = nullptr;
|
||||||
|
const float value = strtof(text, &end);
|
||||||
|
if (!end || *end) return -1;
|
||||||
|
for (size_t i = 0; i < countOf(ACCURACY_OPTIONS_PCT); ++i)
|
||||||
|
if (fabsf(ACCURACY_OPTIONS_PCT[i] - value) < 0.001f) return static_cast<int>(i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lowerAscii(char *text) {
|
||||||
|
for (; text && *text; ++text)
|
||||||
|
if (*text >= 'A' && *text <= 'Z') *text = static_cast<char>(*text - 'A' + 'a');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App::App() : startButton_(GPIO_BUTTON_START), modeButton_(GPIO_BUTTON_MODE),
|
||||||
|
measurement_(receiver_), driverTest_(receiver_) {}
|
||||||
|
|
||||||
void App::begin() {
|
void App::begin() {
|
||||||
Serial.begin(SERIAL_BAUD);
|
Serial.begin(SERIAL_BAUD);
|
||||||
|
#if ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
Serial.setTxTimeoutMs(SERIAL_TX_TIMEOUT_MS);
|
||||||
|
#endif
|
||||||
Log::printf("BOOT", "firmware start, Serial=%lu baud", SERIAL_BAUD);
|
Log::printf("BOOT", "firmware start, Serial=%lu baud", SERIAL_BAUD);
|
||||||
startButton_.begin(); modeButton_.begin(); pwm_.begin();
|
startButton_.begin(); modeButton_.begin(); pwm_.begin();
|
||||||
bootCheckStartedMs_ = millis();
|
bootCheckStartedMs_ = millis();
|
||||||
@@ -42,17 +313,24 @@ void App::finishInitialization(bool factoryReset) {
|
|||||||
} else if (!store_.load(settings_)) {
|
} else if (!store_.load(settings_)) {
|
||||||
store_.save(settings_); Log::event("BOOT", "NVS invalid/missing: defaults loaded");
|
store_.save(settings_); Log::event("BOOT", "NVS invalid/missing: defaults loaded");
|
||||||
}
|
}
|
||||||
|
sanitizeRange();
|
||||||
params_ = store_.params(settings_);
|
params_ = store_.params(settings_);
|
||||||
|
pwm_.configureActiveLight(configuredTxPulseLightOn(settings_));
|
||||||
if (!display_.begin()) Log::event("BOOT", "OLED unavailable; Serial UI remains fully operational");
|
if (!display_.begin()) Log::event("BOOT", "OLED unavailable; Serial UI remains fully operational");
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
if (!receiver_.begin()) { Log::event("BOOT", "FATAL: capture peripheral init failed"); finish(false, FailReason::UNSUPPORTED); return; }
|
if (!receiver_.begin()) { Log::event("BOOT", "FATAL: capture peripheral init failed"); finish(false, FailReason::UNSUPPORTED); return; }
|
||||||
Log::printf("BOOT", "capture initialized: %s", receiver_.highRateBackend() ? "RMT DMA" : "RMT ping-pong");
|
Log::printf("BOOT", "capture initialized: %s", receiver_.highRateBackend() ? "MCPWM 80MHz" : "GPIO cycle counter");
|
||||||
|
lastUserActivityMs_ = millis();
|
||||||
|
setActivePerformance(false);
|
||||||
printConfiguration();
|
printConfiguration();
|
||||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::OPTICS &&
|
||||||
|
static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
||||||
else showIdle();
|
else showIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::update() {
|
void App::update() {
|
||||||
|
serviceSerialConsole();
|
||||||
|
serviceIdlePowerSave();
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
const ButtonEvent startEvent = startButton_.update(now);
|
const ButtonEvent startEvent = startButton_.update(now);
|
||||||
const ButtonEvent modeEvent = modeButton_.update(now);
|
const ButtonEvent modeEvent = modeButton_.update(now);
|
||||||
@@ -60,11 +338,24 @@ void App::update() {
|
|||||||
Log::printf("INPUT", "START %s state=%s", buttonEventName(startEvent), appStateName(state_));
|
Log::printf("INPUT", "START %s state=%s", buttonEventName(startEvent), appStateName(state_));
|
||||||
if (modeEvent != ButtonEvent::NONE)
|
if (modeEvent != ButtonEvent::NONE)
|
||||||
Log::printf("INPUT", "MODE %s state=%s", buttonEventName(modeEvent), appStateName(state_));
|
Log::printf("INPUT", "MODE %s state=%s", buttonEventName(modeEvent), appStateName(state_));
|
||||||
|
if (startEvent != ButtonEvent::NONE || modeEvent != ButtonEvent::NONE) {
|
||||||
|
lastUserActivityMs_ = now;
|
||||||
|
leaveIdlePowerSave();
|
||||||
|
}
|
||||||
if (!initialized_) {
|
if (!initialized_) {
|
||||||
if (!startButton_.pressed() || !modeButton_.pressed()) finishInitialization(false);
|
if (!startButton_.pressed() || !modeButton_.pressed()) finishInitialization(false);
|
||||||
else if (now - bootCheckStartedMs_ >= FACTORY_RESET_HOLD_MS) finishInitialization(true);
|
else if (now - bootCheckStartedMs_ >= FACTORY_RESET_HOLD_MS) finishInitialization(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (state_ == AppState::BOARD_TEST) {
|
||||||
|
if (startEvent == ButtonEvent::LONG) stopBoardTest();
|
||||||
|
else {
|
||||||
|
if (modeEvent != ButtonEvent::NONE)
|
||||||
|
Log::event("ACTION", "MODE ignored while board test is active");
|
||||||
|
updateBoardTest(now);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (state_ != AppState::IDLE && state_ != AppState::MENU && state_ != AppState::FINISHED &&
|
if (state_ != AppState::IDLE && state_ != AppState::MENU && state_ != AppState::FINISHED &&
|
||||||
startEvent == ButtonEvent::LONG) { abortTest(); return; }
|
startEvent == ButtonEvent::LONG) { abortTest(); return; }
|
||||||
if (state_ != AppState::IDLE && state_ != AppState::MENU && state_ != AppState::FINISHED &&
|
if (state_ != AppState::IDLE && state_ != AppState::MENU && state_ != AppState::FINISHED &&
|
||||||
@@ -72,22 +363,31 @@ void App::update() {
|
|||||||
|
|
||||||
if (state_ == AppState::IDLE || state_ == AppState::FINISHED) {
|
if (state_ == AppState::IDLE || state_ == AppState::FINISHED) {
|
||||||
if (modeEvent == ButtonEvent::SHORT) {
|
if (modeEvent == ButtonEvent::SHORT) {
|
||||||
settings_.role = (settings_.role + 1U) % 3U; const bool saved = store_.save(settings_);
|
cycleRunMode(); sanitizeRange(); const bool saved = store_.save(settings_);
|
||||||
params_ = store_.params(settings_);
|
params_ = store_.params(settings_);
|
||||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::OPTICS &&
|
||||||
|
static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
||||||
else showIdle();
|
else showIdle();
|
||||||
Log::printf("ACTION", "role changed to %s, NVS=%s", roleName(static_cast<Role>(settings_.role)), saved ? "OK" : "FAILED");
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD)
|
||||||
|
Log::printf("ACTION", "board test changed to %s, NVS=%s",
|
||||||
|
boardTestName(static_cast<BoardTest>(settings_.boardTest)), saved ? "OK" : "FAILED");
|
||||||
|
else
|
||||||
|
Log::printf("ACTION", "mode changed to %s/%s, NVS=%s",
|
||||||
|
roleName(static_cast<Role>(settings_.role)),
|
||||||
|
testKindName(static_cast<TestKind>(settings_.testKind)), saved ? "OK" : "FAILED");
|
||||||
} else if (modeEvent == ButtonEvent::LONG) {
|
} else if (modeEvent == ButtonEvent::LONG) {
|
||||||
state_ = AppState::MENU; menuItem_ = 0; Log::event("ACTION", "settings menu entered"); showMenu();
|
state_ = AppState::MENU; menuItem_ = 0; Log::event("ACTION", "settings menu entered"); showMenu();
|
||||||
} else if (startEvent == ButtonEvent::SHORT) { Log::event("ACTION", "test start requested"); startTest(); }
|
} else if (startEvent == ButtonEvent::SHORT) { Log::event("ACTION", "test start requested"); startTest(); }
|
||||||
else if (state_ == AppState::FINISHED && static_cast<Role>(settings_.role) == Role::SLAVE &&
|
else if (state_ == AppState::FINISHED && static_cast<Role>(settings_.role) == Role::SLAVE &&
|
||||||
now >= slaveRearmAtMs_) armSlave();
|
now >= slaveRearmAtMs_) armSlave(pendingReason_ != FailReason::NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state_ == AppState::SLAVE_READY && modeEvent != ButtonEvent::NONE) {
|
if (state_ == AppState::SLAVE_READY && modeEvent != ButtonEvent::NONE) {
|
||||||
radio_.end(); havePeer_ = false;
|
radio_.end(); havePeer_ = false;
|
||||||
if (modeEvent == ButtonEvent::SHORT) {
|
if (modeEvent == ButtonEvent::SHORT) {
|
||||||
settings_.role = static_cast<uint8_t>(Role::SOLO); const bool saved = store_.save(settings_);
|
settings_.role = static_cast<uint8_t>(Role::SOLO);
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL);
|
||||||
|
const bool saved = store_.save(settings_);
|
||||||
params_ = store_.params(settings_); state_ = AppState::IDLE; showIdle();
|
params_ = store_.params(settings_); state_ = AppState::IDLE; showIdle();
|
||||||
Log::printf("ACTION", "role changed to SOLO, NVS=%s", saved ? "OK" : "FAILED");
|
Log::printf("ACTION", "role changed to SOLO, NVS=%s", saved ? "OK" : "FAILED");
|
||||||
} else if (modeEvent == ButtonEvent::LONG) {
|
} else if (modeEvent == ButtonEvent::LONG) {
|
||||||
@@ -97,30 +397,83 @@ void App::update() {
|
|||||||
}
|
}
|
||||||
if (state_ == AppState::MENU) {
|
if (state_ == AppState::MENU) {
|
||||||
if (modeEvent == ButtonEvent::SHORT) {
|
if (modeEvent == ButtonEvent::SHORT) {
|
||||||
menuItem_ = (menuItem_ + 1U) % 7U; Log::printf("ACTION", "menu item selected index=%u", menuItem_); showMenu();
|
leaveOpticalCalibration();
|
||||||
|
menuItem_ = nextMenuItem(menuItem_,
|
||||||
|
static_cast<TestGroup>(settings_.testGroup));
|
||||||
|
Log::printf("ACTION", "menu item selected index=%u", menuItem_);
|
||||||
|
showMenu();
|
||||||
}
|
}
|
||||||
else if (modeEvent == ButtonEvent::LONG) {
|
else if (modeEvent == ButtonEvent::LONG) {
|
||||||
|
leaveOpticalCalibration();
|
||||||
sanitizeRange(); const bool saved = store_.save(settings_); params_ = store_.params(settings_);
|
sanitizeRange(); const bool saved = store_.save(settings_); params_ = store_.params(settings_);
|
||||||
Log::printf("ACTION", "settings menu saved and closed, NVS=%s", saved ? "OK" : "FAILED");
|
Log::printf("ACTION", "settings menu saved and closed, NVS=%s", saved ? "OK" : "FAILED");
|
||||||
state_ = AppState::IDLE; printConfiguration();
|
state_ = AppState::IDLE; printConfiguration();
|
||||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::OPTICS &&
|
||||||
|
static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
||||||
else showIdle();
|
else showIdle();
|
||||||
} else if (startEvent == ButtonEvent::SHORT) changeMenu(+1);
|
} else if (menuItem_ != MENU_OPTICAL_CALIBRATION_ITEM &&
|
||||||
else if (startEvent == ButtonEvent::LONG || startEvent == ButtonEvent::REPEAT) changeMenu(-1);
|
startEvent == ButtonEvent::SHORT) changeMenu(+1);
|
||||||
|
else if (menuItem_ != MENU_OPTICAL_CALIBRATION_ITEM &&
|
||||||
|
(startEvent == ButtonEvent::LONG || startEvent == ButtonEvent::REPEAT)) changeMenu(-1);
|
||||||
|
updateOpticalCalibration(now);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state_ == AppState::SOLO_MEASURE) {
|
if (state_ == AppState::SOLO_MEASURE) {
|
||||||
const MeasureState ms = measurement_.update();
|
if (static_cast<int32_t>(now - localMeasurementDeadlineMs_) >= 0) {
|
||||||
if (ms == MeasureState::FAIL) { printStageStats(measurement_.stats(), requestedHz_); finish(false, measurement_.reason()); }
|
Log::event("MEASURE", "local stage watchdog expired");
|
||||||
else if (ms == MeasureState::PASS) {
|
measurement_.forceFail(FailReason::LOST_EDGE);
|
||||||
printStageStats(measurement_.stats(), requestedHz_);
|
|
||||||
if (measurement_.reason() == FailReason::DATA_LOST) {
|
|
||||||
sweepHadDataLoss_ = true; if (!firstDataLossHz_) firstDataLossHz_ = requestedHz_;
|
|
||||||
}
|
}
|
||||||
|
const MeasureState ms = measurement_.update();
|
||||||
|
if (ms == MeasureState::FAIL) {
|
||||||
|
pwm_.stop();
|
||||||
|
printStageStats(measurement_.stats(), actual_.actualHz);
|
||||||
|
showStageResult(measurement_.stats());
|
||||||
|
finish(false, measurement_.reason(), true);
|
||||||
|
}
|
||||||
|
else if (ms == MeasureState::PASS) {
|
||||||
|
pwm_.stop();
|
||||||
|
printStageStats(measurement_.stats(), actual_.actualHz);
|
||||||
|
showStageResult(measurement_.stats());
|
||||||
|
stagePassed();
|
||||||
|
} else if (measurement_.takeProgressUpdate()) {
|
||||||
|
StageStats live = {};
|
||||||
|
if (measurement_.statsSnapshot(live)) showStageResult(live);
|
||||||
|
}
|
||||||
|
} else if (state_ == AppState::SOLO_DRIVER) {
|
||||||
|
if (static_cast<int32_t>(now - localMeasurementDeadlineMs_) >= 0)
|
||||||
|
driverTest_.forceFail(FailReason::LOST_EDGE);
|
||||||
|
const DriverState ds = driverTest_.update();
|
||||||
|
if (ds == DriverState::SUBSAMPLE_DONE) {
|
||||||
|
// Capture is already stopped. Update the OLED only in this quiet gap,
|
||||||
|
// then restart the same PWM point and arm the next tenth of the sample.
|
||||||
|
pwm_.stop();
|
||||||
|
driverTest_.takeProgressUpdate();
|
||||||
|
showDriverResult(driverTest_.stats());
|
||||||
|
ActualPwm resumed = {};
|
||||||
|
if (!pwm_.start(requestedHz_, requestedPulseNs_, resumed)) {
|
||||||
|
driverTest_.forceFail(FailReason::RESOLUTION);
|
||||||
|
} else {
|
||||||
|
actual_ = resumed;
|
||||||
|
if (!driverTest_.resumeSubsample()) {
|
||||||
|
pwm_.stop();
|
||||||
|
driverTest_.forceFail(FailReason::DATA_LOSS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ds == DriverState::FAIL) {
|
||||||
|
pwm_.stop(); receiver_.stop();
|
||||||
|
driverTest_.printSummary();
|
||||||
|
driverTest_.printTrace();
|
||||||
|
showDriverResult(driverTest_.stats());
|
||||||
|
finish(false, driverTest_.stats().reason, true);
|
||||||
|
} else if (ds == DriverState::PASS) {
|
||||||
|
pwm_.stop();
|
||||||
|
driverTest_.printSummary();
|
||||||
|
const bool finalPoint = stageIndex_ + 1U >= stageCount_;
|
||||||
|
showDriverResult(driverTest_.stats(), finalPoint);
|
||||||
stagePassed();
|
stagePassed();
|
||||||
}
|
}
|
||||||
} else if (state_ == AppState::MASTER_DISCOVER || state_ == AppState::MASTER_WAIT_READY ||
|
} else if (state_ == AppState::MASTER_DISCOVER || state_ == AppState::MASTER_WAIT_READY ||
|
||||||
state_ == AppState::MASTER_WAIT_RESULT) {
|
state_ == AppState::MASTER_WAIT_RESULT || state_ == AppState::MASTER_FINALIZE) {
|
||||||
handleRadio(); updateMaster();
|
handleRadio(); updateMaster();
|
||||||
} else {
|
} else {
|
||||||
handleRadio(); updateSlave();
|
handleRadio(); updateSlave();
|
||||||
@@ -128,137 +481,665 @@ void App::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void App::showIdle() {
|
void App::showIdle() {
|
||||||
char one[24]; snprintf(one, sizeof(one), "MODE: %s", roleName(static_cast<Role>(settings_.role)));
|
setActivePerformance(false);
|
||||||
display_.show(one, "START=RUN");
|
setStandbyOpticalOutput();
|
||||||
|
lastUserActivityMs_ = millis();
|
||||||
|
char one[64];
|
||||||
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD) {
|
||||||
|
snprintf(one, sizeof(one), "%s: %s", uiTestGroupName(TestGroup::BOARD),
|
||||||
|
uiBoardTestName(static_cast<BoardTest>(settings_.boardTest)));
|
||||||
|
display_.show(one, UiText::BOARD_READY);
|
||||||
|
} else {
|
||||||
|
snprintf(one, sizeof(one), "%s: %s",
|
||||||
|
uiRoleName(static_cast<Role>(settings_.role)),
|
||||||
|
uiTestName(static_cast<TestKind>(settings_.testKind)));
|
||||||
|
display_.show(one, UiText::START_RUN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::serviceSerialConsole() {
|
||||||
|
while (Serial.available() > 0) {
|
||||||
|
const int raw = Serial.read();
|
||||||
|
if (raw < 0) break;
|
||||||
|
const char c = static_cast<char>(raw);
|
||||||
|
lastUserActivityMs_ = millis();
|
||||||
|
leaveIdlePowerSave();
|
||||||
|
|
||||||
|
if (c == '\r') continue;
|
||||||
|
if (c == '\n') {
|
||||||
|
if (serialLineOverflow_) Serial.println("ERR command too long");
|
||||||
|
else if (serialLineLength_) {
|
||||||
|
serialLine_[serialLineLength_] = '\0';
|
||||||
|
handleSerialCommand(serialLine_);
|
||||||
|
}
|
||||||
|
serialLineLength_ = 0;
|
||||||
|
serialLineOverflow_ = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c < ' ' || c > '~') continue;
|
||||||
|
if (serialLineLength_ + 1U < sizeof(serialLine_))
|
||||||
|
serialLine_[serialLineLength_++] = c;
|
||||||
|
else serialLineOverflow_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::printSerialHelp() {
|
||||||
|
Serial.println("COMMANDS (send with newline):");
|
||||||
|
Serial.println(" help | status | start | stop | defaults");
|
||||||
|
Serial.println(" set group optics|board");
|
||||||
|
Serial.println(" set boardtest adc|pwm|rx");
|
||||||
|
Serial.println(" set role solo|master|slave");
|
||||||
|
Serial.println(" set test optical|driver");
|
||||||
|
Serial.println(" set frequency 500|1000|2000|5000|10000|25000");
|
||||||
|
Serial.println(" set max 2000|5000|10000|20000|50000|100000|200000|500000");
|
||||||
|
Serial.println(" set min 250|500|1000|2000|5000|10000|50000");
|
||||||
|
Serial.println(" set accuracy 1|2|5|10");
|
||||||
|
Serial.println(" set time 100|250|500|1000|2000|5000 (ms)");
|
||||||
|
Serial.println(" set light HH|HL|LH|LL (DRIVER only)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::printSerialStatus() {
|
||||||
|
if (!initialized_) {
|
||||||
|
Serial.println("STATUS initializing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
params_ = store_.params(settings_);
|
||||||
|
Serial.printf("STATUS state=%s group=%s boardtest=%s role=%s test=%s frequency=%luHz max=%luns min=%luns accuracy=%.2f%% time=%lums light=%s usb=%s\n",
|
||||||
|
appStateName(state_), testGroupName(static_cast<TestGroup>(settings_.testGroup)),
|
||||||
|
boardTestName(static_cast<BoardTest>(settings_.boardTest)), roleName(static_cast<Role>(settings_.role)),
|
||||||
|
testKindName(static_cast<TestKind>(settings_.testKind)), params_.frequencyHz,
|
||||||
|
params_.maxPulseNs, params_.minPulseNs, params_.accuracyPct, params_.testTimeMs,
|
||||||
|
configuredLevelName(settings_),
|
||||||
|
usbHostPresent() ? "connected" : "disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::serialSettingsMutable() const {
|
||||||
|
return initialized_ && (state_ == AppState::IDLE || state_ == AppState::FINISHED ||
|
||||||
|
state_ == AppState::MENU || state_ == AppState::SLAVE_READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::finishSerialSettingsChange() {
|
||||||
|
if (state_ == AppState::SLAVE_READY) radio_.end();
|
||||||
|
leaveOpticalCalibration();
|
||||||
|
state_ = AppState::IDLE;
|
||||||
|
sanitizeRange();
|
||||||
|
params_ = store_.params(settings_);
|
||||||
|
pwm_.configureActiveLight(configuredTxPulseLightOn(settings_));
|
||||||
|
const bool saved = store_.save(settings_);
|
||||||
|
Serial.printf("OK settings saved=%s\n", saved ? "yes" : "no");
|
||||||
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::OPTICS &&
|
||||||
|
static_cast<Role>(settings_.role) == Role::SLAVE) armSlave();
|
||||||
|
else showIdle();
|
||||||
|
printSerialStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::handleSerialCommand(char *line) {
|
||||||
|
lowerAscii(line);
|
||||||
|
char *save = nullptr;
|
||||||
|
char *command = strtok_r(line, " \t", &save);
|
||||||
|
char *name = strtok_r(nullptr, " \t", &save);
|
||||||
|
char *value = strtok_r(nullptr, " \t", &save);
|
||||||
|
char *extra = strtok_r(nullptr, " \t", &save);
|
||||||
|
if (!command) return;
|
||||||
|
|
||||||
|
if ((!strcmp(command, "help") || !strcmp(command, "?")) && !name) {
|
||||||
|
printSerialHelp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((!strcmp(command, "status") || !strcmp(command, "get")) && !name) {
|
||||||
|
printSerialStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(command, "start") && !name) {
|
||||||
|
if (!initialized_) Serial.println("ERR still initializing");
|
||||||
|
else if (state_ == AppState::IDLE || state_ == AppState::FINISHED) {
|
||||||
|
Serial.println("OK test start requested");
|
||||||
|
startTest();
|
||||||
|
} else if (state_ == AppState::SLAVE_READY) Serial.println("OK slave already armed");
|
||||||
|
else Serial.printf("ERR busy state=%s\n", appStateName(state_));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((!strcmp(command, "stop") || !strcmp(command, "abort")) && !name) {
|
||||||
|
if (!initialized_) Serial.println("ERR still initializing");
|
||||||
|
else if (state_ == AppState::IDLE || state_ == AppState::FINISHED) Serial.println("OK already stopped");
|
||||||
|
else if (state_ == AppState::BOARD_TEST) {
|
||||||
|
Serial.println("OK board test stopped");
|
||||||
|
stopBoardTest();
|
||||||
|
} else if (state_ == AppState::MENU) {
|
||||||
|
leaveOpticalCalibration();
|
||||||
|
state_ = AppState::IDLE; showIdle(); Serial.println("OK menu closed");
|
||||||
|
} else if (state_ == AppState::SLAVE_READY) Serial.println("OK slave is armed; no test is running");
|
||||||
|
else {
|
||||||
|
Serial.println("OK abort requested");
|
||||||
|
abortTest();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(command, "defaults") && !name) {
|
||||||
|
if (!serialSettingsMutable()) {
|
||||||
|
Serial.printf("ERR settings locked state=%s\n", appStateName(state_));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
store_.defaults(settings_);
|
||||||
|
finishSerialSettingsChange();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "set") || !name || !value || extra) {
|
||||||
|
Serial.println("ERR unknown command; send 'help'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!serialSettingsMutable()) {
|
||||||
|
Serial.printf("ERR settings locked state=%s; stop the test first\n", appStateName(state_));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool accepted = false;
|
||||||
|
uint32_t numeric = 0;
|
||||||
|
if (!strcmp(name, "group")) {
|
||||||
|
if (!strcmp(value, "optics") || !strcmp(value, "optical")) {
|
||||||
|
settings_.testGroup = static_cast<uint8_t>(TestGroup::OPTICS); accepted = true;
|
||||||
|
} else if (!strcmp(value, "board")) {
|
||||||
|
settings_.testGroup = static_cast<uint8_t>(TestGroup::BOARD); accepted = true;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(name, "boardtest") || !strcmp(name, "board")) {
|
||||||
|
BoardTest selected = static_cast<BoardTest>(UINT8_MAX);
|
||||||
|
if (!strcmp(value, "adc")) selected = BoardTest::ADC;
|
||||||
|
else if (!strcmp(value, "pwm")) selected = BoardTest::PWM_OUTPUT;
|
||||||
|
else if (!strcmp(value, "rx")) selected = BoardTest::RX_INPUT;
|
||||||
|
if (boardTestAvailable(selected)) {
|
||||||
|
settings_.boardTest = static_cast<uint8_t>(selected);
|
||||||
|
accepted = true;
|
||||||
|
}
|
||||||
|
} else if (!strcmp(name, "role")) {
|
||||||
|
if (!strcmp(value, "solo")) { settings_.role = static_cast<uint8_t>(Role::SOLO); accepted = true; }
|
||||||
|
else if (!strcmp(value, "master")) { settings_.role = static_cast<uint8_t>(Role::MASTER); accepted = true; }
|
||||||
|
else if (!strcmp(value, "slave")) { settings_.role = static_cast<uint8_t>(Role::SLAVE); accepted = true; }
|
||||||
|
} else if (!strcmp(name, "test")) {
|
||||||
|
if (!strcmp(value, "optical")) { settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL); accepted = true; }
|
||||||
|
else if (!strcmp(value, "driver") && !TARGET_IS_C3 &&
|
||||||
|
static_cast<Role>(settings_.role) == Role::SOLO) {
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::DRIVER); accepted = true;
|
||||||
|
}
|
||||||
|
} else if ((!strcmp(name, "frequency") || !strcmp(name, "freq")) && parseUnsigned(value, numeric)) {
|
||||||
|
const int index = optionIndex(PWM_FREQUENCY_OPTIONS_HZ, numeric);
|
||||||
|
if (index >= 0) { settings_.frequencyIndex = static_cast<uint8_t>(index); accepted = true; }
|
||||||
|
} else if ((!strcmp(name, "max") || !strcmp(name, "maxpulse")) && parseUnsigned(value, numeric)) {
|
||||||
|
const int index = optionIndex(MAX_PULSE_OPTIONS_NS, numeric);
|
||||||
|
if (index >= 0) { settings_.maxPulseIndex = static_cast<uint8_t>(index); accepted = true; }
|
||||||
|
} else if ((!strcmp(name, "min") || !strcmp(name, "minpulse")) && parseUnsigned(value, numeric)) {
|
||||||
|
const int index = optionIndex(MIN_PULSE_OPTIONS_NS, numeric);
|
||||||
|
if (index >= 0) { settings_.minPulseIndex = static_cast<uint8_t>(index); accepted = true; }
|
||||||
|
} else if (!strcmp(name, "accuracy")) {
|
||||||
|
const int index = accuracyOptionIndex(value);
|
||||||
|
if (index >= 0) { settings_.accuracyIndex = static_cast<uint8_t>(index); accepted = true; }
|
||||||
|
} else if ((!strcmp(name, "time") || !strcmp(name, "duration")) && parseUnsigned(value, numeric)) {
|
||||||
|
const int index = optionIndex(TEST_TIME_OPTIONS_MS, numeric);
|
||||||
|
if (index >= 0) { settings_.timeIndex = static_cast<uint8_t>(index); accepted = true; }
|
||||||
|
} else if (!strcmp(name, "light")) {
|
||||||
|
if (static_cast<TestKind>(settings_.testKind) != TestKind::DRIVER) {
|
||||||
|
Serial.println("ERR level setting is available only in DRIVER test");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(value, "hh")) { settings_.lightCode = static_cast<uint8_t>(LightCode::HH); accepted = true; }
|
||||||
|
else if (!strcmp(value, "hl")) { settings_.lightCode = static_cast<uint8_t>(LightCode::HL); accepted = true; }
|
||||||
|
else if (!strcmp(value, "lh")) { settings_.lightCode = static_cast<uint8_t>(LightCode::LH); accepted = true; }
|
||||||
|
else if (!strcmp(value, "ll")) { settings_.lightCode = static_cast<uint8_t>(LightCode::LL); accepted = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accepted) {
|
||||||
|
Serial.println("ERR invalid setting or value; send 'help'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finishSerialSettingsChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::cycleRunMode() {
|
||||||
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD) {
|
||||||
|
do {
|
||||||
|
settings_.boardTest = (settings_.boardTest + 1U) %
|
||||||
|
(static_cast<uint8_t>(BoardTest::RX_INPUT) + 1U);
|
||||||
|
} while (!boardTestAvailable(static_cast<BoardTest>(settings_.boardTest)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Role role = static_cast<Role>(settings_.role);
|
||||||
|
const TestKind kind = static_cast<TestKind>(settings_.testKind);
|
||||||
|
if (role == Role::SOLO && kind == TestKind::OPTICAL && !TARGET_IS_C3) {
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::DRIVER);
|
||||||
|
} else if (role == Role::SOLO) {
|
||||||
|
settings_.role = static_cast<uint8_t>(Role::MASTER);
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL);
|
||||||
|
} else if (role == Role::MASTER) {
|
||||||
|
settings_.role = static_cast<uint8_t>(Role::SLAVE);
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL);
|
||||||
|
} else {
|
||||||
|
settings_.role = static_cast<uint8_t>(Role::SOLO);
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::sanitizeRange() {
|
void App::sanitizeRange() {
|
||||||
settings_.startIndex %= countOf(START_FREQ_OPTIONS_HZ); settings_.endIndex %= countOf(END_FREQ_OPTIONS_HZ);
|
if (settings_.testGroup > static_cast<uint8_t>(TestGroup::BOARD))
|
||||||
if (END_FREQ_OPTIONS_HZ[settings_.endIndex] <= START_FREQ_OPTIONS_HZ[settings_.startIndex]) {
|
settings_.testGroup = static_cast<uint8_t>(TestGroup::OPTICS);
|
||||||
size_t i = 0;
|
if (settings_.boardTest > static_cast<uint8_t>(BoardTest::RX_INPUT) ||
|
||||||
while (i < countOf(END_FREQ_OPTIONS_HZ) && END_FREQ_OPTIONS_HZ[i] <= START_FREQ_OPTIONS_HZ[settings_.startIndex]) ++i;
|
!boardTestAvailable(static_cast<BoardTest>(settings_.boardTest)))
|
||||||
if (i == countOf(END_FREQ_OPTIONS_HZ)) { settings_.startIndex = 0; i = countOf(END_FREQ_OPTIONS_HZ) - 1; }
|
settings_.boardTest = static_cast<uint8_t>(defaultBoardTest());
|
||||||
settings_.endIndex = i;
|
if (settings_.role > static_cast<uint8_t>(Role::SLAVE))
|
||||||
|
settings_.role = static_cast<uint8_t>(Role::SOLO);
|
||||||
|
if (settings_.testKind > static_cast<uint8_t>(TestKind::DRIVER))
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL);
|
||||||
|
if (settings_.lightCode > static_cast<uint8_t>(LightCode::LL))
|
||||||
|
settings_.lightCode = static_cast<uint8_t>(LightCode::HH);
|
||||||
|
if (settings_.role != static_cast<uint8_t>(Role::SOLO) ||
|
||||||
|
(TARGET_IS_C3 && settings_.testKind == static_cast<uint8_t>(TestKind::DRIVER)))
|
||||||
|
settings_.testKind = static_cast<uint8_t>(TestKind::OPTICAL);
|
||||||
|
settings_.frequencyIndex %= countOf(PWM_FREQUENCY_OPTIONS_HZ);
|
||||||
|
settings_.maxPulseIndex %= countOf(MAX_PULSE_OPTIONS_NS);
|
||||||
|
settings_.minPulseIndex %= countOf(MIN_PULSE_OPTIONS_NS);
|
||||||
|
settings_.accuracyIndex %= countOf(ACCURACY_OPTIONS_PCT);
|
||||||
|
settings_.timeIndex %= countOf(TEST_TIME_OPTIONS_MS);
|
||||||
|
const uint32_t hz = PWM_FREQUENCY_OPTIONS_HZ[settings_.frequencyIndex];
|
||||||
|
const uint8_t lastValid = lastValidMaxPulseIndex(hz);
|
||||||
|
if (settings_.maxPulseIndex > lastValid) settings_.maxPulseIndex = lastValid;
|
||||||
|
const uint8_t lastMin = lastMinPulseIndexAtMost(MAX_PULSE_OPTIONS_NS[settings_.maxPulseIndex]);
|
||||||
|
if (settings_.minPulseIndex > lastMin) settings_.minPulseIndex = lastMin;
|
||||||
|
if (settings_.testKind == static_cast<uint8_t>(TestKind::DRIVER)) {
|
||||||
|
const uint8_t driverLastMin = lastMinPulseIndexAtMost(
|
||||||
|
MAX_PULSE_OPTIONS_NS[settings_.maxPulseIndex]);
|
||||||
|
const uint8_t firstDriverMin = firstMinPulseIndexAtLeast(
|
||||||
|
DRIVER_MIN_INPUT_PULSE_NS, driverLastMin);
|
||||||
|
if (settings_.minPulseIndex < firstDriverMin)
|
||||||
|
settings_.minPulseIndex = firstDriverMin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::changeMenu(int d) {
|
void App::changeMenu(int d) {
|
||||||
|
sanitizeRange();
|
||||||
|
if (menuItem_ == 0) {
|
||||||
|
settings_.testGroup = cycleIndex(settings_.testGroup, 0,
|
||||||
|
static_cast<uint8_t>(TestGroup::BOARD), d);
|
||||||
|
} else if (menuItem_ == 2) {
|
||||||
|
const uint8_t last = lastValidMaxPulseIndex(
|
||||||
|
PWM_FREQUENCY_OPTIONS_HZ[settings_.frequencyIndex]);
|
||||||
|
const uint8_t first = firstMaxPulseIndexAtLeast(
|
||||||
|
MIN_PULSE_OPTIONS_NS[settings_.minPulseIndex], last);
|
||||||
|
settings_.maxPulseIndex = cycleIndex(settings_.maxPulseIndex,
|
||||||
|
first, last, d);
|
||||||
|
} else if (menuItem_ == 3) {
|
||||||
|
const uint8_t last = lastMinPulseIndexAtMost(
|
||||||
|
MAX_PULSE_OPTIONS_NS[settings_.maxPulseIndex]);
|
||||||
|
const uint8_t first = static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER
|
||||||
|
? firstMinPulseIndexAtLeast(DRIVER_MIN_INPUT_PULSE_NS, last) : 0U;
|
||||||
|
settings_.minPulseIndex = cycleIndex(settings_.minPulseIndex, first, last, d);
|
||||||
|
} else {
|
||||||
uint8_t *value = nullptr; size_t count = 0;
|
uint8_t *value = nullptr; size_t count = 0;
|
||||||
switch (menuItem_) {
|
switch (menuItem_) {
|
||||||
case 0: value = &settings_.startIndex; count = countOf(START_FREQ_OPTIONS_HZ); break;
|
case 1: value = &settings_.frequencyIndex; count = countOf(PWM_FREQUENCY_OPTIONS_HZ); break;
|
||||||
case 1: value = &settings_.endIndex; count = countOf(END_FREQ_OPTIONS_HZ); break;
|
case 4: value = &settings_.accuracyIndex; count = countOf(ACCURACY_OPTIONS_PCT); break;
|
||||||
case 2: value = &settings_.stepIndex; count = countOf(STEP_OPTIONS_HZ); break;
|
case 5: value = &settings_.timeIndex; count = countOf(TEST_TIME_OPTIONS_MS); break;
|
||||||
case 3: value = &settings_.accuracyIndex; count = countOf(ACCURACY_OPTIONS_PCT); break;
|
case 6:
|
||||||
case 4: value = &settings_.timeIndex; count = countOf(TEST_TIME_OPTIONS_MS); break;
|
if (static_cast<TestKind>(settings_.testKind) != TestKind::DRIVER) {
|
||||||
case 5: value = &settings_.repeatIndex; count = countOf(REPEAT_OPTIONS); break;
|
showMenu();
|
||||||
default: value = &settings_.dutyIndex; count = countOf(DUTY_OPTIONS_PCT); break;
|
return;
|
||||||
}
|
}
|
||||||
*value = static_cast<uint8_t>((*value + count + d) % count);
|
value = &settings_.lightCode; count = 4; break;
|
||||||
Log::printf("ACTION", "menu item=%u changed direction=%+d new-index=%u", menuItem_, d, *value);
|
default: return;
|
||||||
sanitizeRange(); params_ = store_.params(settings_); showMenu();
|
}
|
||||||
|
*value = cycleIndex(*value, 0, static_cast<uint8_t>(count - 1U), d);
|
||||||
|
}
|
||||||
|
sanitizeRange(); params_ = store_.params(settings_);
|
||||||
|
pwm_.configureActiveLight(configuredTxPulseLightOn(settings_));
|
||||||
|
Log::printf("ACTION", "menu item=%u changed direction=%+d frequency=%u max-pulse=%u min-pulse=%u accuracy=%u time=%u light=%s",
|
||||||
|
menuItem_, d, settings_.frequencyIndex, settings_.maxPulseIndex,
|
||||||
|
settings_.minPulseIndex, settings_.accuracyIndex, settings_.timeIndex,
|
||||||
|
configuredLevelName(settings_));
|
||||||
|
showMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::showMenu() {
|
void App::showMenu() {
|
||||||
char one[22], two[22], all[12];
|
char one[64], value[24], total[64], all[12];
|
||||||
|
const char *label = nullptr;
|
||||||
Display::formatDuration(actualNominalTotalUs(), all, sizeof(all));
|
Display::formatDuration(actualNominalTotalUs(), all, sizeof(all));
|
||||||
switch (menuItem_) {
|
switch (menuItem_) {
|
||||||
case 0: snprintf(one, sizeof(one), "START FREQ"); Display::formatFrequency(params_.startHz, two, sizeof(two)); break;
|
case 0:
|
||||||
case 1: snprintf(one, sizeof(one), "END FREQ"); Display::formatFrequency(params_.endHz, two, sizeof(two)); break;
|
snprintf(value, sizeof(value), "%s",
|
||||||
case 2: snprintf(one, sizeof(one), "FREQ STEP"); Display::formatFrequency(params_.stepHz, two, sizeof(two)); break;
|
uiTestGroupName(static_cast<TestGroup>(settings_.testGroup)));
|
||||||
case 3: snprintf(one, sizeof(one), "ACCURACY"); snprintf(two, sizeof(two), "+/-%g%%", params_.accuracyPct); break;
|
label = UiText::MENU_TEST_GROUP;
|
||||||
case 4: snprintf(one, sizeof(one), "TEST TIME"); snprintf(two, sizeof(two), "%.1fs", params_.testTimeMs / 1000.0f); break;
|
break;
|
||||||
case 5: snprintf(one, sizeof(one), "REPEATS"); snprintf(two, sizeof(two), "%ux", params_.repeats); break;
|
case 1:
|
||||||
default: snprintf(one, sizeof(one), "PWM DUTY"); snprintf(two, sizeof(two), "%u%%", params_.dutyPct); break;
|
Display::formatPwmFrequency(params_.frequencyHz, value, sizeof(value));
|
||||||
|
label = UiText::MENU_FREQUENCY;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Display::formatPulse(params_.maxPulseNs, value, sizeof(value));
|
||||||
|
label = UiText::MENU_MAX_PULSE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Display::formatPulse(params_.minPulseNs, value, sizeof(value));
|
||||||
|
label = UiText::MENU_MIN_PULSE;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
snprintf(value, sizeof(value), "+/-%g%%", params_.accuracyPct);
|
||||||
|
label = UiText::MENU_ACCURACY;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
snprintf(value, sizeof(value), "%.1fs", params_.testTimeMs / 1000.0f);
|
||||||
|
label = UiText::MENU_TEST_TIME;
|
||||||
|
break;
|
||||||
|
case 6: {
|
||||||
|
if (static_cast<TestKind>(settings_.testKind) != TestKind::DRIVER) {
|
||||||
|
snprintf(value, sizeof(value), "%s", UiText::LIGHT_AUTO);
|
||||||
|
label = UiText::MENU_LIGHT_CODE;
|
||||||
|
formatMenuLine(label, value, one, sizeof(one));
|
||||||
|
display_.show(one, UiText::LIGHT_AUTO_FORMAT);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const size_t used = strlen(two); snprintf(two + used, sizeof(two) - used, " ALL %s", all); display_.show(one, two);
|
const char *code = lightCodeName(static_cast<LightCode>(settings_.lightCode));
|
||||||
|
snprintf(value, sizeof(value), "%s", code);
|
||||||
|
label = UiText::MENU_LIGHT_CODE;
|
||||||
|
formatMenuLine(label, value, one, sizeof(one));
|
||||||
|
snprintf(total, sizeof(total), UiText::LIGHT_CODE_FORMAT, code[0], code[1]);
|
||||||
|
display_.show(one, total);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MENU_OPTICAL_CALIBRATION_ITEM:
|
||||||
|
enterOpticalCalibration(millis());
|
||||||
|
return;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
formatMenuLine(label, value, one, sizeof(one));
|
||||||
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD)
|
||||||
|
snprintf(total, sizeof(total), "%s", UiText::BOARD_READY);
|
||||||
|
else
|
||||||
|
formatMenuLine(UiText::MENU_TOTAL_TIME, all, total, sizeof(total));
|
||||||
|
display_.show(one, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::enterOpticalCalibration(uint32_t now) {
|
||||||
|
if (opticalCalibrationActive_) return;
|
||||||
|
optical_current_begin();
|
||||||
|
pwm_.lightOn();
|
||||||
|
opticalCalibrationActive_ = true;
|
||||||
|
opticalCalibrationStartedMs_ = now;
|
||||||
|
opticalCalibrationUpdatedMs_ = 0;
|
||||||
|
display_.show("Idiode: --.- mA", "Vcc: --.-- V");
|
||||||
|
Log::printf("CALIB", "optical LED ON; sense GPIO=%u, VCC GPIO=%u, settling %lums",
|
||||||
|
GPIO_OPTICAL_CURRENT, GPIO_OPTICAL_VCC, OPTICAL_CURRENT_SETTLE_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::updateOpticalCalibration(uint32_t now, bool force) {
|
||||||
|
if (!opticalCalibrationActive_ ||
|
||||||
|
now - opticalCalibrationStartedMs_ < OPTICAL_CURRENT_SETTLE_MS) return;
|
||||||
|
(void)force;
|
||||||
|
OpticalCurrentMeasurement reading = {};
|
||||||
|
if (!optical_current_poll(reading)) return;
|
||||||
|
opticalCalibrationUpdatedMs_ = now;
|
||||||
|
char current[32], vcc[24];
|
||||||
|
snprintf(current, sizeof(current), "Idiode: %.1f mA", reading.currentMa);
|
||||||
|
snprintf(vcc, sizeof(vcc), "Vcc: %.2f V", reading.vccVoltage);
|
||||||
|
display_.show(current, vcc);
|
||||||
|
Log::printf("CALIB",
|
||||||
|
"raw sense=%u vcc=%u | ADC sense=%.3fV vcc=%.3fV | Usense=%.3fV Vcc=%.3fV | Idiode=%.1fmA",
|
||||||
|
reading.senseRaw, reading.vccRaw, reading.senseAdcVoltage,
|
||||||
|
reading.vccAdcVoltage, reading.senseVoltage, reading.vccVoltage,
|
||||||
|
reading.currentMa);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::leaveOpticalCalibration() {
|
||||||
|
if (!opticalCalibrationActive_) return;
|
||||||
|
pwm_.stop();
|
||||||
|
opticalCalibrationActive_ = false;
|
||||||
|
Log::event("CALIB", "optical LED OFF; calibration menu left");
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::startTest() {
|
void App::startTest() {
|
||||||
params_ = store_.params(settings_); stageCount_ = frequencyPointCount(params_.startHz, params_.endHz, params_.stepHz);
|
leaveIdlePowerSave();
|
||||||
stageIndex_ = 0; requestedHz_ = 0; pendingReason_ = FailReason::NONE; sweepHadDataLoss_ = false; firstDataLossHz_ = 0;
|
pwm_.stop();
|
||||||
|
setActivePerformance(true);
|
||||||
|
sanitizeRange();
|
||||||
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD) {
|
||||||
|
startBoardTest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
params_ = store_.params(settings_); stageCount_ = pulseWidthPointCount(params_.maxPulseNs, params_.minPulseNs);
|
||||||
|
stageIndex_ = 0; requestedHz_ = params_.frequencyHz; requestedPulseNs_ = 0; pendingReason_ = FailReason::NONE;
|
||||||
havePeer_ = false; lastHeartbeatMs_ = 0; lastPeerSeenMs_ = 0;
|
havePeer_ = false; lastHeartbeatMs_ = 0; lastPeerSeenMs_ = 0;
|
||||||
if (!stageCount_) { finish(false, FailReason::UNSUPPORTED); return; }
|
if (!stageCount_) { finish(false, FailReason::UNSUPPORTED); return; }
|
||||||
Log::printf("TEST", "starting role=%s stages=%lu", roleName(static_cast<Role>(settings_.role)), stageCount_);
|
Log::printf("TEST", "starting role=%s test=%s light=%s stages=%lu",
|
||||||
if (SERIAL_MINIMAL_LOG)
|
roleName(static_cast<Role>(settings_.role)),
|
||||||
Log::printf("CONFIG", "mode=%s range=%lu..%luHz step=%luHz accuracy=%.2f%% time=%lums repeats=%u duty=%u%% stages=%lu",
|
testKindName(static_cast<TestKind>(settings_.testKind)),
|
||||||
roleName(static_cast<Role>(settings_.role)), params_.startHz, params_.endHz, params_.stepHz,
|
configuredLevelName(settings_), stageCount_);
|
||||||
params_.accuracyPct, params_.testTimeMs, params_.repeats, params_.dutyPct, stageCount_);
|
if (SERIAL_MINIMAL_LOG) {
|
||||||
|
Log::printf("CONFIG", "mode=%s/%s frequency=%luHz pulse=%lu..%luns accuracy=%.2f%% time=%lums LIGHT=%s stages=%lu",
|
||||||
|
roleName(static_cast<Role>(settings_.role)),
|
||||||
|
testKindName(static_cast<TestKind>(settings_.testKind)), params_.frequencyHz,
|
||||||
|
params_.maxPulseNs, params_.minPulseNs, params_.accuracyPct, params_.testTimeMs,
|
||||||
|
configuredLevelName(settings_),
|
||||||
|
stageCount_);
|
||||||
|
}
|
||||||
printConfiguration();
|
printConfiguration();
|
||||||
const Role role = static_cast<Role>(settings_.role);
|
const Role role = static_cast<Role>(settings_.role);
|
||||||
if (role == Role::SOLO) {
|
if (role == Role::SOLO) {
|
||||||
if (!prepareStage()) return;
|
if (!prepareStage()) return;
|
||||||
state_ = AppState::SOLO_MEASURE;
|
state_ = static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER
|
||||||
|
? AppState::SOLO_DRIVER : AppState::SOLO_MEASURE;
|
||||||
} else if (!radio_.begin()) finish(false, FailReason::LINK_LOST);
|
} else if (!radio_.begin()) finish(false, FailReason::LINK_LOST);
|
||||||
else if (role == Role::MASTER) startMasterDiscovery();
|
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() {
|
void App::startBoardTest() {
|
||||||
|
const BoardTest test = static_cast<BoardTest>(settings_.boardTest);
|
||||||
|
state_ = AppState::BOARD_TEST;
|
||||||
|
boardTestUpdatedMs_ = boardDisplayUpdatedMs_ = 0;
|
||||||
|
boardPwmLightOn_ = false;
|
||||||
|
rxPinStateKnown_ = false;
|
||||||
|
Log::printf("BOARD", "starting test=%s", boardTestName(test));
|
||||||
|
|
||||||
|
// ADC and RX checks need the optical transmitter continuously illuminated.
|
||||||
|
// The PWM-output check drives the same pin itself and therefore replaces
|
||||||
|
// the constant active level with its test waveform.
|
||||||
|
if (test != BoardTest::PWM_OUTPUT) {
|
||||||
|
pwm_.lightOn();
|
||||||
|
Log::printf("BOARD", "optical output active GPIO=%u level=%s", GPIO_PWM,
|
||||||
|
TX_LIGHT_ON_GPIO_LEVEL == HIGH ? "HIGH" : "LOW");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test == BoardTest::ADC) {
|
||||||
|
if (!BOARD_ADC_AVAILABLE) {
|
||||||
|
Serial.println("BOARD ADC: unavailable in MAKETKA profile");
|
||||||
|
display_.show(UiText::ADC_UNAVAILABLE, UiText::BOARD_STOP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pinMode(GPIO_ANALOG_RX, INPUT);
|
||||||
|
pinMode(GPIO_VBAT, INPUT);
|
||||||
|
display_.show(UiText::BOARD_TEST_NAMES[static_cast<uint8_t>(BoardTest::ADC)],
|
||||||
|
UiText::BOARD_STOP);
|
||||||
|
} else if (test == BoardTest::PWM_OUTPUT) {
|
||||||
|
boardPwmLightOn_ = true;
|
||||||
|
boardTestUpdatedMs_ = millis();
|
||||||
|
pwm_.lightOn();
|
||||||
|
Serial.printf("BOARD PWM: GPIO=%u frequency=%luHz duty=50%% light=ON\n",
|
||||||
|
GPIO_PWM, BOARD_PWM_TEST_FREQUENCY_HZ);
|
||||||
|
display_.show(UiText::BOARD_TEST_NAMES[static_cast<uint8_t>(test)], UiText::BOARD_STOP);
|
||||||
|
} else {
|
||||||
|
pinMode(GPIO_RX, INPUT);
|
||||||
|
display_.show(UiText::BOARD_TEST_NAMES[static_cast<uint8_t>(test)], UiText::BOARD_STOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::updateBoardTest(uint32_t now) {
|
||||||
|
const BoardTest test = static_cast<BoardTest>(settings_.boardTest);
|
||||||
|
if (test == BoardTest::ADC) {
|
||||||
|
if (!BOARD_ADC_AVAILABLE || now - boardTestUpdatedMs_ < BOARD_ADC_PRINT_INTERVAL_MS) return;
|
||||||
|
boardTestUpdatedMs_ = now;
|
||||||
|
const uint16_t analogRx = analogRead(GPIO_ANALOG_RX);
|
||||||
|
const uint16_t vbat = analogRead(GPIO_VBAT);
|
||||||
|
Serial.printf("ADC analog_rx=%u vbat=%u\n", analogRx, vbat);
|
||||||
|
if (now - boardDisplayUpdatedMs_ >= BOARD_TEST_DISPLAY_INTERVAL_MS) {
|
||||||
|
boardDisplayUpdatedMs_ = now;
|
||||||
|
char one[32], two[32];
|
||||||
|
snprintf(one, sizeof(one), "ADC RX: %u", analogRx);
|
||||||
|
snprintf(two, sizeof(two), "ADC VBAT: %u", vbat);
|
||||||
|
display_.show(one, two);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test == BoardTest::PWM_OUTPUT) {
|
||||||
|
if (now - boardTestUpdatedMs_ < BOARD_PWM_TEST_HALF_PERIOD_MS) return;
|
||||||
|
boardTestUpdatedMs_ = now;
|
||||||
|
boardPwmLightOn_ = !boardPwmLightOn_;
|
||||||
|
if (boardPwmLightOn_) pwm_.lightOn();
|
||||||
|
else pwm_.stop();
|
||||||
|
Serial.printf("BOARD PWM: light=%s\n", boardPwmLightOn_ ? "ON" : "OFF");
|
||||||
|
char two[32];
|
||||||
|
snprintf(two, sizeof(two), "%luHz 50%%: %s", BOARD_PWM_TEST_FREQUENCY_HZ,
|
||||||
|
boardPwmLightOn_ ? "ON" : "OFF");
|
||||||
|
display_.show(UiText::BOARD_TEST_NAMES[static_cast<uint8_t>(test)], two);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool level = digitalRead(GPIO_RX) == HIGH;
|
||||||
|
if (!rxPinStateKnown_ || level != rxPinState_) {
|
||||||
|
rxPinState_ = level;
|
||||||
|
rxPinStateKnown_ = true;
|
||||||
|
Serial.printf("RX GPIO=%u state=%s (%u)\n", GPIO_RX,
|
||||||
|
level ? "HIGH" : "LOW", level ? 1U : 0U);
|
||||||
|
char two[32];
|
||||||
|
snprintf(two, sizeof(two), "GPIO %u: %s", GPIO_RX, level ? "HIGH" : "LOW");
|
||||||
|
display_.show(UiText::BOARD_TEST_NAMES[static_cast<uint8_t>(test)], two);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::stopBoardTest() {
|
||||||
|
Log::printf("BOARD", "stopping test=%s", boardTestName(static_cast<BoardTest>(settings_.boardTest)));
|
||||||
|
pwm_.stop();
|
||||||
|
state_ = AppState::IDLE;
|
||||||
|
setActivePerformance(false);
|
||||||
|
showIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::armSlave(bool preserveDisplay) {
|
||||||
|
setActivePerformance(false);
|
||||||
|
pwm_.stop();
|
||||||
|
lastUserActivityMs_ = millis();
|
||||||
params_ = store_.params(settings_);
|
params_ = store_.params(settings_);
|
||||||
stageIndex_ = 0; stageCount_ = frequencyPointCount(params_.startHz, params_.endHz, params_.stepHz);
|
stageIndex_ = 0; stageCount_ = pulseWidthPointCount(params_.maxPulseNs, params_.minPulseNs);
|
||||||
requestedHz_ = 0; session_ = 0; sequence_ = 0; havePeer_ = false;
|
requestedHz_ = params_.frequencyHz; requestedPulseNs_ = 0; session_ = 0; sequence_ = 0; havePeer_ = false;
|
||||||
lastHeartbeatMs_ = 0; lastPeerSeenMs_ = 0; retries_ = 0; slaveRearmAtMs_ = 0;
|
lastHeartbeatMs_ = 0; lastPeerSeenMs_ = 0; retries_ = 0; slaveRearmAtMs_ = 0;
|
||||||
if (!radio_.begin()) {
|
if (!radio_.begin()) {
|
||||||
state_ = AppState::FINISHED; pendingReason_ = FailReason::LINK_LOST;
|
state_ = AppState::FINISHED; pendingReason_ = FailReason::LINK_LOST;
|
||||||
slaveRearmAtMs_ = millis() + LINK_HEARTBEAT_TIMEOUT_MS;
|
slaveRearmAtMs_ = millis() + LINK_HEARTBEAT_TIMEOUT_MS;
|
||||||
display_.show("LINK FAILED", "RADIO ERROR");
|
display_.show(UiText::LINK_FAILED, UiText::RADIO_ERROR,
|
||||||
|
0, 0, roleCorner(Role::SLAVE));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
radio_.setWindowedReceive(true);
|
||||||
radio_.flush(); state_ = AppState::SLAVE_READY;
|
radio_.flush(); state_ = AppState::SLAVE_READY;
|
||||||
Log::event("TEST", "Slave automatically armed and waiting for Master");
|
Log::event("TEST", "Slave automatically armed and waiting for Master");
|
||||||
display_.show("SLAVE READY", "WAIT MASTER");
|
if (!preserveDisplay) display_.show(UiText::SLAVE_READY, UiText::WAIT_MASTER);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool App::prepareStage() {
|
bool App::prepareStage(bool showProgress) {
|
||||||
requestedHz_ = frequencyAt(params_.startHz, params_.endHz, params_.stepHz, stageIndex_);
|
requestedHz_ = params_.frequencyHz;
|
||||||
|
requestedPulseNs_ = pulseWidthAt(params_.maxPulseNs, params_.minPulseNs, stageIndex_);
|
||||||
|
actual_ = {};
|
||||||
const uint32_t maxHz = TARGET_IS_C3 ? C3_STRICT_MAX_HZ :
|
const uint32_t maxHz = TARGET_IS_C3 ? C3_STRICT_MAX_HZ :
|
||||||
(receiver_.highRateBackend() ? S3_STRICT_MAX_HZ : C3_STRICT_MAX_HZ);
|
(receiver_.highRateBackend() ? S3_STRICT_MAX_HZ : C3_STRICT_MAX_HZ);
|
||||||
if (requestedHz_ > maxHz) { finish(false, FailReason::UNSUPPORTED); return false; }
|
if (requestedHz_ > maxHz) { finish(false, FailReason::UNSUPPORTED); return false; }
|
||||||
Log::printf("PWM", "starting GPIO=%u requested=%luHz duty=%u%%", GPIO_PWM, requestedHz_, params_.dutyPct);
|
Log::printf("PWM", "starting GPIO=%u requested=%luHz pulse=%luns", GPIO_PWM, requestedHz_, requestedPulseNs_);
|
||||||
if (!pwm_.start(requestedHz_, params_.dutyPct, actual_)) {
|
if (!pwm_.start(requestedHz_, requestedPulseNs_, actual_)) {
|
||||||
Log::printf("PWM", "START FAILED GPIO=%u requested=%luHz; LEDC attach/write/read failed",
|
Log::printf("PWM", "START FAILED GPIO=%u requested=%luHz pulse=%luns; PWM setup failed",
|
||||||
GPIO_PWM, requestedHz_);
|
GPIO_PWM, requestedHz_, requestedPulseNs_);
|
||||||
finish(false, FailReason::RESOLUTION); return false;
|
finish(false, FailReason::RESOLUTION); return false;
|
||||||
}
|
}
|
||||||
const FailReason resolution = validateResolution(actual_.actualHz, actual_.actualDutyPct, params_.accuracyPct,
|
if (!periodWithin(actual_.actualHz, requestedHz_, params_.accuracyPct) ||
|
||||||
receiver_.tickHz(), actual_.bits);
|
!periodWithin(actual_.actualPulseNs, requestedPulseNs_, params_.accuracyPct)) {
|
||||||
|
Log::printf("PWM", "requested point cannot be generated within tolerance: requested=%luHz/%luns actual=%luHz/%luns tolerance=%.2f%%",
|
||||||
|
requestedHz_, requestedPulseNs_, actual_.actualHz, actual_.actualPulseNs,
|
||||||
|
params_.accuracyPct);
|
||||||
|
finish(false, FailReason::RESOLUTION); return false;
|
||||||
|
}
|
||||||
|
const bool driverMode = static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER;
|
||||||
|
if (!driverMode) {
|
||||||
|
const uint32_t plannedRxHz = receiver_.plannedTickHz(actual_.actualHz, actual_.actualDutyPct);
|
||||||
|
const uint32_t plannedPulseRxHz = receiver_.plannedPulseTickHz(
|
||||||
|
actual_.actualHz, actual_.actualDutyPct);
|
||||||
|
const FailReason resolution = validateResolution(actual_.actualHz, actual_.actualDutyPct,
|
||||||
|
params_.accuracyPct, plannedRxHz, plannedPulseRxHz, actual_.bits,
|
||||||
|
MEASUREMENT_AVERAGING_PERIODS);
|
||||||
if (resolution != FailReason::NONE) {
|
if (resolution != FailReason::NONE) {
|
||||||
Log::printf("PWM", "resolution rejected: actual=%luHz duty=%.3f%% bits=%u RXclock=%luHz tolerance=%.3f%%",
|
Log::printf("PWM", "resolution rejected: actual=%luHz duty=%.3f%% bits=%u period-capture=%luHz pulse-capture=%luHz tolerance=%.3f%%",
|
||||||
actual_.actualHz, actual_.actualDutyPct, actual_.bits, receiver_.tickHz(), params_.accuracyPct);
|
actual_.actualHz, actual_.actualDutyPct, actual_.bits, plannedRxHz,
|
||||||
|
plannedPulseRxHz, effectiveTolerancePct(params_.accuracyPct));
|
||||||
finish(false, resolution); return false;
|
finish(false, resolution); return false;
|
||||||
}
|
}
|
||||||
Log::printf("PWM", "stage=%lu/%lu requested=%luHz actual=%luHz duty=%.2f%% bits=%u STARTED",
|
} else if (!receiver_.highRateBackend()) {
|
||||||
stageIndex_ + 1, stageCount_, requestedHz_, actual_.actualHz, actual_.actualDutyPct, actual_.bits);
|
|
||||||
char f[12], one[24], two[24]; Display::formatFrequency(actual_.actualHz, f, sizeof(f));
|
|
||||||
snprintf(one, sizeof(one), "F %s D %.1f%%", f, actual_.actualDutyPct);
|
|
||||||
snprintf(two, sizeof(two), "%lu/%lu RUN", stageIndex_ + 1, stageCount_); display_.show(one, two);
|
|
||||||
if (static_cast<Role>(settings_.role) == Role::SOLO && !startLocalMeasurement(actual_.actualHz, actual_.actualDutyPct)) {
|
|
||||||
finish(false, FailReason::UNSUPPORTED); return false;
|
finish(false, FailReason::UNSUPPORTED); return false;
|
||||||
}
|
}
|
||||||
|
Log::printf("PWM", "stage=%lu/%lu requested=%luHz/%luns actual=%luHz/%luns duty=%.3f%% bits=%u STARTED",
|
||||||
|
stageIndex_ + 1, stageCount_, requestedHz_, requestedPulseNs_, actual_.actualHz,
|
||||||
|
actual_.actualPulseNs, actual_.actualDutyPct, actual_.bits);
|
||||||
|
if (showProgress) showStageProgress();
|
||||||
|
if (static_cast<Role>(settings_.role) == Role::SOLO) {
|
||||||
|
const bool started = driverMode ? startDriverMeasurement() :
|
||||||
|
startLocalMeasurement(actual_.actualHz, actual_.actualDutyPct);
|
||||||
|
if (!started) { finish(false, FailReason::UNSUPPORTED); return false; }
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool App::startLocalMeasurement(float hz, float duty) {
|
bool App::startLocalMeasurement(float hz, float duty) {
|
||||||
Log::printf("MEASURE", "arming expected=%.3fHz duty=%.3f%% tolerance=%.3f%% settle=%u cycles window=%lums x%u; per-pulse logging suspended",
|
Log::printf("MEASURE", "arming expected=%.3fHz duty=%.3f%% tolerance=%.3f%% period-capture=%luHz pulse-capture=%luHz settle=%u cycles window=%lums; every pulse validated",
|
||||||
hz, duty, params_.accuracyPct, PWM_SETTLE_CYCLES, params_.testTimeMs, params_.repeats);
|
hz, duty, effectiveTolerancePct(params_.accuracyPct), receiver_.plannedTickHz(static_cast<uint32_t>(hz + 0.5f), duty),
|
||||||
const bool ok = measurement_.start(hz, duty, params_.accuracyPct, params_.testTimeMs, params_.repeats, PWM_SETTLE_CYCLES);
|
receiver_.plannedPulseTickHz(static_cast<uint32_t>(hz + 0.5f), duty),
|
||||||
Log::printf("MEASURE", "receiver start %s, RMT chunk=%u symbols", ok ? "OK" : "FAILED",
|
PWM_SETTLE_CYCLES, params_.testTimeMs);
|
||||||
receiver_.receiveChunkSymbols());
|
const bool ok = measurement_.start(hz, duty, params_.accuracyPct, params_.testTimeMs,
|
||||||
|
MEASUREMENT_AVERAGING_PERIODS, PWM_SETTLE_CYCLES, true);
|
||||||
|
const uint32_t nominalMs = stageWallTimeMs(params_.testTimeMs,
|
||||||
|
static_cast<uint32_t>(hz + 0.5f));
|
||||||
|
const uint64_t watchdogMs = static_cast<uint64_t>(nominalMs) * 2ULL + 2000ULL;
|
||||||
|
localMeasurementDeadlineMs_ = millis() + static_cast<uint32_t>(
|
||||||
|
watchdogMs > UINT32_MAX ? UINT32_MAX : watchdogMs);
|
||||||
|
Log::printf("MEASURE", "receiver start %s, continuous edge capture", ok ? "OK" : "FAILED");
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::startDriverMeasurement() {
|
||||||
|
const bool ok = driverTest_.start(actual_.actualHz, actual_.actualPulseNs,
|
||||||
|
params_.accuracyPct, params_.testTimeMs, PWM_SETTLE_CYCLES,
|
||||||
|
txActiveLightOn(settings_), rxActiveLightOn(settings_));
|
||||||
|
const uint32_t nominalMs = stageWallTimeMs(params_.testTimeMs, actual_.actualHz);
|
||||||
|
const uint64_t watchdogMs = static_cast<uint64_t>(nominalMs) * 2ULL + 2000ULL;
|
||||||
|
localMeasurementDeadlineMs_ = millis() + static_cast<uint32_t>(
|
||||||
|
watchdogMs > UINT32_MAX ? UINT32_MAX : watchdogMs);
|
||||||
|
if (!ok) Log::event("DRIVER", "response test start FAILED");
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::stagePassed() {
|
void App::stagePassed() {
|
||||||
Log::printf("TEST", "stage %lu/%lu PASS; PWM stopping", stageIndex_ + 1, stageCount_);
|
Log::printf("TEST", "stage %lu/%lu PASS; PWM stopping", stageIndex_ + 1, stageCount_);
|
||||||
pwm_.stop();
|
pwm_.stop();
|
||||||
|
// With PWM already quiet it is safe to stop capture before clearing its
|
||||||
|
// queue for the next pulse width. Never reset a FreeRTOS queue concurrently
|
||||||
|
// with the capture ISR.
|
||||||
|
if (static_cast<Role>(settings_.role) == Role::SOLO) receiver_.stop();
|
||||||
if (++stageIndex_ >= stageCount_) {
|
if (++stageIndex_ >= stageCount_) {
|
||||||
if (sweepHadDataLoss_) { requestedHz_ = firstDataLossHz_; finish(false, FailReason::DATA_LOST); }
|
const bool preserveDriverMeasurements =
|
||||||
else finish(true, FailReason::NONE);
|
static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER;
|
||||||
|
finish(true, FailReason::NONE, preserveDriverMeasurements);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (static_cast<Role>(settings_.role) == Role::SOLO) { if (prepareStage()) state_ = AppState::SOLO_MEASURE; }
|
if (static_cast<Role>(settings_.role) == Role::SOLO) {
|
||||||
|
if (prepareStage()) state_ = static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER
|
||||||
|
? AppState::SOLO_DRIVER : AppState::SOLO_MEASURE;
|
||||||
|
}
|
||||||
else if (static_cast<Role>(settings_.role) == Role::MASTER) {
|
else if (static_cast<Role>(settings_.role) == Role::MASTER) {
|
||||||
requestedHz_ = frequencyAt(params_.startHz, params_.endHz, params_.stepHz, stageIndex_);
|
requestedHz_ = params_.frequencyHz;
|
||||||
|
requestedPulseNs_ = pulseWidthAt(params_.maxPulseNs, params_.minPulseNs, stageIndex_);
|
||||||
|
actual_ = {};
|
||||||
|
stageStartConfirmed_ = false;
|
||||||
pendingPacket_ = makePacket(MessageType::PREPARE); sendCurrent(MessageType::PREPARE);
|
pendingPacket_ = makePacket(MessageType::PREPARE); sendCurrent(MessageType::PREPARE);
|
||||||
state_ = AppState::MASTER_WAIT_READY; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
state_ = AppState::MASTER_WAIT_READY; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
||||||
}
|
}
|
||||||
@@ -266,32 +1147,44 @@ void App::stagePassed() {
|
|||||||
|
|
||||||
void App::startMasterDiscovery() {
|
void App::startMasterDiscovery() {
|
||||||
session_ = esp_random(); if (!session_) session_ = 1;
|
session_ = esp_random(); if (!session_) session_ = 1;
|
||||||
sequence_ = 1; stageIndex_ = 0; requestedHz_ = 0; havePeer_ = false; radio_.flush();
|
sequence_ = 1; stageIndex_ = 0; requestedHz_ = params_.frequencyHz;
|
||||||
|
requestedPulseNs_ = 0; havePeer_ = false; radio_.flush();
|
||||||
|
opticalWakeActive_ = true;
|
||||||
|
lastOpticalWakeToggleMs_ = millis();
|
||||||
|
pwm_.lightOn();
|
||||||
pendingPacket_ = makePacket(MessageType::DISCOVER); radio_.sendBroadcast(pendingPacket_);
|
pendingPacket_ = makePacket(MessageType::DISCOVER); radio_.sendBroadcast(pendingPacket_);
|
||||||
lastSendMs_ = millis(); retries_ = 0;
|
lastSendMs_ = millis(); retries_ = 0;
|
||||||
state_ = AppState::MASTER_DISCOVER; Log::printf("ESP-NOW", "discovery started session=%08lX", session_);
|
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 {
|
ProtocolPacket App::makePacket(MessageType type) const {
|
||||||
ProtocolPacket p = {};
|
ProtocolPacket p = {};
|
||||||
p.type = static_cast<uint8_t>(type); p.session = session_; p.stage = stageIndex_; p.sequence = sequence_;
|
p.type = static_cast<uint8_t>(type); p.session = session_; p.stage = stageIndex_;
|
||||||
p.requestedHz = requestedHz_; p.actualHz = actual_.actualHz;
|
p.stageCount = static_cast<uint16_t>(stageCount_); p.sequence = sequence_;
|
||||||
p.actualDutyX100 = static_cast<uint16_t>(actual_.actualDutyPct * 100.0f + 0.5f);
|
p.requestedHz = requestedHz_; p.requestedPulseNs = requestedPulseNs_;
|
||||||
p.testTimeMs = params_.testTimeMs; p.repeats = params_.repeats;
|
p.actualHz = actual_.actualHz; p.actualPulseNs = actual_.actualPulseNs;
|
||||||
p.accuracyX100 = static_cast<uint16_t>(params_.accuracyPct * 100.0f + 0.5f); p.settleCycles = PWM_SETTLE_CYCLES;
|
p.testTimeMs = params_.testTimeMs;
|
||||||
|
p.accuracyX100 = static_cast<uint16_t>(params_.accuracyPct * 100.0f + 0.5f);
|
||||||
|
p.lightCode = settings_.lightCode;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::sendCurrent(MessageType type) {
|
void App::sendCurrent(MessageType type) {
|
||||||
++sequence_; pendingPacket_ = makePacket(type);
|
++sequence_; pendingPacket_ = makePacket(type);
|
||||||
const bool ok = radio_.sendBroadcast(pendingPacket_); lastSendMs_ = millis();
|
const bool ok = sendLinked(pendingPacket_); lastSendMs_ = millis();
|
||||||
if (!ok) Log::printf("ESP-NOW", "sendCurrent %s FAILED", messageName(type));
|
if (!ok) Log::printf("ESP-NOW", "sendCurrent %s FAILED", messageName(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool App::sendLinked(ProtocolPacket packet) {
|
||||||
|
return havePeer_ ? radio_.sendTo(peer_, packet) : radio_.sendBroadcast(packet);
|
||||||
|
}
|
||||||
|
|
||||||
void App::updateHeartbeat() {
|
void App::updateHeartbeat() {
|
||||||
if (!havePeer_ || state_ == AppState::FINISHED) return;
|
if (!havePeer_ || state_ == AppState::FINISHED) return;
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
|
const uint32_t radioRxMs = radio_.lastReceiveMs();
|
||||||
|
if (radioRxMs && now - radioRxMs < now - lastPeerSeenMs_) lastPeerSeenMs_ = radioRxMs;
|
||||||
if (now - lastPeerSeenMs_ >= LINK_HEARTBEAT_TIMEOUT_MS) {
|
if (now - lastPeerSeenMs_ >= LINK_HEARTBEAT_TIMEOUT_MS) {
|
||||||
Log::event("ESP-NOW", "peer heartbeat timeout");
|
Log::event("ESP-NOW", "peer heartbeat timeout");
|
||||||
finish(false, FailReason::LINK_LOST);
|
finish(false, FailReason::LINK_LOST);
|
||||||
@@ -301,7 +1194,7 @@ void App::updateHeartbeat() {
|
|||||||
now - lastHeartbeatMs_ >= LINK_HEARTBEAT_INTERVAL_MS) {
|
now - lastHeartbeatMs_ >= LINK_HEARTBEAT_INTERVAL_MS) {
|
||||||
ProtocolPacket heartbeat = makePacket(MessageType::HEARTBEAT);
|
ProtocolPacket heartbeat = makePacket(MessageType::HEARTBEAT);
|
||||||
heartbeat.sequence = sequence_;
|
heartbeat.sequence = sequence_;
|
||||||
radio_.sendBroadcast(heartbeat);
|
sendLinked(heartbeat);
|
||||||
lastHeartbeatMs_ = now;
|
lastHeartbeatMs_ = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,57 +1207,136 @@ void App::handleRadio() {
|
|||||||
ReceivedPacket r;
|
ReceivedPacket r;
|
||||||
while (radio_.receive(r)) {
|
while (radio_.receive(r)) {
|
||||||
const MessageType type = static_cast<MessageType>(r.packet.type);
|
const MessageType type = static_cast<MessageType>(r.packet.type);
|
||||||
if (type != MessageType::HEARTBEAT && type != MessageType::HEARTBEAT_ACK &&
|
if (type != MessageType::HEARTBEAT && type != MessageType::HEARTBEAT_ACK && type != MessageType::PROGRESS &&
|
||||||
state_ != AppState::SLAVE_MEASURE)
|
state_ != AppState::SLAVE_MEASURE)
|
||||||
Log::printf("ESP-NOW", "RX %s session=%08lX stage=%u seq=%u",
|
Log::printf("ESP-NOW", "RX %s session=%08lX stage=%u seq=%u",
|
||||||
messageName(type), r.packet.session, r.packet.stage, r.packet.sequence);
|
messageName(type), r.packet.session, r.packet.stage, r.packet.sequence);
|
||||||
if ((state_ == AppState::SLAVE_READY || state_ == AppState::SLAVE_WAIT_START) &&
|
if ((state_ == AppState::SLAVE_READY || state_ == AppState::SLAVE_WAIT_START) &&
|
||||||
type == MessageType::DISCOVER && (!havePeer_ || !memcmp(peer_, r.mac, 6))) {
|
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;
|
memcpy(peer_, r.mac, 6); havePeer_ = true; session_ = r.packet.session; stageIndex_ = 0; sequence_ = r.packet.sequence;
|
||||||
lastPeerSeenMs_ = millis();
|
lastPeerSeenMs_ = millis();
|
||||||
ProtocolPacket ack = makePacket(MessageType::DISCOVER_ACK); ack.sequence = r.packet.sequence; radio_.sendBroadcast(ack);
|
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_) {
|
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();
|
memcpy(peer_, r.mac, 6); havePeer_ = true; lastPeerSeenMs_ = lastHeartbeatMs_ = millis();
|
||||||
requestedHz_ = frequencyAt(params_.startHz, params_.endHz, params_.stepHz, stageIndex_);
|
requestedHz_ = params_.frequencyHz;
|
||||||
|
requestedPulseNs_ = pulseWidthAt(params_.maxPulseNs, params_.minPulseNs, stageIndex_);
|
||||||
sendCurrent(MessageType::PREPARE); state_ = AppState::MASTER_WAIT_READY; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
sendCurrent(MessageType::PREPARE); state_ = AppState::MASTER_WAIT_READY; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
||||||
char mac[20]; Radio::macText(peer_, mac, sizeof(mac)); Log::printf("ESP-NOW", "Slave selected %s", mac); continue;
|
char mac[20]; Radio::macText(peer_, mac, sizeof(mac)); Log::printf("ESP-NOW", "Slave selected %s", mac); continue;
|
||||||
}
|
}
|
||||||
if (havePeer_ && !memcmp(peer_, r.mac, 6) && r.packet.session == session_) lastPeerSeenMs_ = millis();
|
if (havePeer_ && !memcmp(peer_, r.mac, 6) && r.packet.session == session_) lastPeerSeenMs_ = millis();
|
||||||
if (havePeer_ && !memcmp(peer_, r.mac, 6) && r.packet.session == session_ &&
|
if (havePeer_ && !memcmp(peer_, r.mac, 6) && r.packet.session == session_ &&
|
||||||
type == MessageType::HEARTBEAT) {
|
type == MessageType::HEARTBEAT) {
|
||||||
ProtocolPacket ack = makePacket(MessageType::HEARTBEAT_ACK);
|
continue; // Radio's priority heartbeat task has already sent the ACK.
|
||||||
ack.sequence = r.packet.sequence; radio_.sendBroadcast(ack); continue;
|
|
||||||
}
|
}
|
||||||
if (type == MessageType::HEARTBEAT_ACK) continue;
|
if (type == MessageType::HEARTBEAT_ACK) continue;
|
||||||
if (havePeer_ && !memcmp(peer_, r.mac, 6) && type == MessageType::RESULT &&
|
if (havePeer_ && !memcmp(peer_, r.mac, 6) && type == MessageType::RESULT &&
|
||||||
r.packet.session == session_ && r.packet.stage < stageIndex_) {
|
r.packet.session == session_ && r.packet.stage < stageIndex_) {
|
||||||
ProtocolPacket ack = {}; ack.type = static_cast<uint8_t>(MessageType::ACK);
|
ProtocolPacket ack = {}; ack.type = static_cast<uint8_t>(MessageType::ACK);
|
||||||
ack.session = session_; ack.stage = r.packet.stage; ack.sequence = r.packet.sequence;
|
ack.session = session_; ack.stage = r.packet.stage; ack.sequence = r.packet.sequence;
|
||||||
radio_.sendBroadcast(ack); continue; // idempotent ACK for a retried old result
|
sendLinked(ack); continue; // idempotent ACK for a retried old result
|
||||||
|
}
|
||||||
|
const bool matchingPeer = havePeer_ && !memcmp(peer_, r.mac, 6) && r.packet.session == session_;
|
||||||
|
if (matchingPeer && type == MessageType::PREPARE) {
|
||||||
|
const bool expected = state_ == AppState::SLAVE_WAIT_START && r.packet.stage == stageIndex_;
|
||||||
|
const bool implicitAck = state_ == AppState::SLAVE_WAIT_ACK && pendingPacket_.passed &&
|
||||||
|
r.packet.stage == static_cast<uint16_t>(pendingPacket_.stage + 1U);
|
||||||
|
if (expected || implicitAck) {
|
||||||
|
stageIndex_ = r.packet.stage;
|
||||||
|
sequence_ = r.packet.sequence;
|
||||||
|
state_ = AppState::SLAVE_WAIT_START;
|
||||||
|
params_.testTimeMs = r.packet.testTimeMs;
|
||||||
|
params_.accuracyPct = r.packet.accuracyX100 / 100.0f;
|
||||||
|
if (r.packet.lightCode <= static_cast<uint8_t>(LightCode::LL))
|
||||||
|
settings_.lightCode = r.packet.lightCode;
|
||||||
|
requestedHz_ = r.packet.requestedHz; requestedPulseNs_ = r.packet.requestedPulseNs;
|
||||||
|
stageCount_ = r.packet.stageCount;
|
||||||
|
actual_ = {};
|
||||||
|
ProtocolPacket ready = makePacket(MessageType::READY);
|
||||||
|
ready.sequence = r.packet.sequence; sendLinked(ready);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (!havePeer_ || memcmp(peer_, r.mac, 6) || !packetForCurrent(r.packet)) continue;
|
if (!havePeer_ || memcmp(peer_, r.mac, 6) || !packetForCurrent(r.packet)) continue;
|
||||||
if (type == MessageType::ABORT) { finish(false, FailReason::ABORTED); continue; }
|
if (type == MessageType::ABORT) {
|
||||||
|
const FailReason reason = r.packet.reason > static_cast<uint8_t>(FailReason::NONE) &&
|
||||||
|
r.packet.reason <= static_cast<uint8_t>(FailReason::ABORTED)
|
||||||
|
? static_cast<FailReason>(r.packet.reason) : FailReason::ABORTED;
|
||||||
|
if (r.packet.requestedHz) requestedHz_ = r.packet.requestedHz;
|
||||||
|
if (r.packet.requestedPulseNs) requestedPulseNs_ = r.packet.requestedPulseNs;
|
||||||
|
actual_.actualHz = r.packet.actualHz ? r.packet.actualHz : requestedHz_;
|
||||||
|
actual_.actualPulseNs = r.packet.actualPulseNs ? r.packet.actualPulseNs : requestedPulseNs_;
|
||||||
|
actual_.actualDutyPct = dutyFromPulse(actual_.actualHz, actual_.actualPulseNs);
|
||||||
|
measurement_.abort(); finish(false, reason); continue;
|
||||||
|
}
|
||||||
if (state_ == AppState::MASTER_WAIT_READY && type == MessageType::READY) {
|
if (state_ == AppState::MASTER_WAIT_READY && type == MessageType::READY) {
|
||||||
if (!prepareStage()) continue;
|
if (!prepareStage(false)) continue;
|
||||||
sendCurrent(MessageType::START_STAGE); state_ = AppState::MASTER_WAIT_RESULT; retries_ = 0; deadlineMs_ = millis() +
|
sendCurrent(MessageType::START_STAGE); state_ = AppState::MASTER_WAIT_RESULT;
|
||||||
params_.testTimeMs * params_.repeats + LINK_REPLY_TIMEOUT_MS + (1000UL * PWM_SETTLE_CYCLES / actual_.actualHz) + 20;
|
stageStartConfirmed_ = false; retries_ = 0;
|
||||||
|
deadlineMs_ = millis() + LINK_RETRY_INTERVAL_MS;
|
||||||
|
} else if (state_ == AppState::MASTER_WAIT_RESULT && type == MessageType::READY &&
|
||||||
|
r.packet.sequence == pendingPacket_.sequence) {
|
||||||
|
if (!stageStartConfirmed_) showStageProgress();
|
||||||
|
stageStartConfirmed_ = true;
|
||||||
|
deadlineMs_ = millis() + stageWallTimeMs(params_.testTimeMs, actual_.actualHz) +
|
||||||
|
LINK_REPLY_TIMEOUT_MS + 20;
|
||||||
|
} else if (state_ == AppState::MASTER_WAIT_RESULT && type == MessageType::PROGRESS) {
|
||||||
|
stageStartConfirmed_ = true;
|
||||||
|
deadlineMs_ = millis() + stageWallTimeMs(params_.testTimeMs, actual_.actualHz) +
|
||||||
|
LINK_REPLY_TIMEOUT_MS;
|
||||||
|
showRemoteResult(r.packet);
|
||||||
} else if (state_ == AppState::MASTER_WAIT_RESULT && type == MessageType::RESULT) {
|
} else if (state_ == AppState::MASTER_WAIT_RESULT && type == MessageType::RESULT) {
|
||||||
ProtocolPacket ack = makePacket(MessageType::ACK); ack.sequence = r.packet.sequence; radio_.sendBroadcast(ack); pwm_.stop();
|
ProtocolPacket ack = makePacket(MessageType::ACK); ack.sequence = r.packet.sequence;
|
||||||
if (!r.packet.passed) finish(false, static_cast<FailReason>(r.packet.reason)); else stagePassed();
|
ack.passed = r.packet.passed && stageIndex_ + 1U >= stageCount_;
|
||||||
} else if (state_ == AppState::SLAVE_WAIT_START && type == MessageType::PREPARE) {
|
sendLinked(ack); pwm_.stop();
|
||||||
params_.testTimeMs = r.packet.testTimeMs; params_.repeats = r.packet.repeats;
|
showRemoteResult(r.packet);
|
||||||
params_.accuracyPct = r.packet.accuracyX100 / 100.0f; requestedHz_ = r.packet.requestedHz;
|
if (!r.packet.passed) {
|
||||||
ProtocolPacket ready = makePacket(MessageType::READY); ready.sequence = r.packet.sequence; radio_.sendBroadcast(ready);
|
finish(false, static_cast<FailReason>(r.packet.reason), true);
|
||||||
display_.show("SLAVE LINKED", "MASTER ONLINE");
|
} else if (ack.passed) {
|
||||||
|
pendingPacket_ = ack;
|
||||||
|
state_ = AppState::MASTER_FINALIZE; retries_ = 0;
|
||||||
|
deadlineMs_ = millis() + FINAL_ACK_RETRY_INTERVAL_MS;
|
||||||
|
} else stagePassed();
|
||||||
|
} else if (state_ == AppState::MASTER_FINALIZE && type == MessageType::RESULT) {
|
||||||
|
// The Slave did not receive the final ACK and repeated RESULT.
|
||||||
|
sendLinked(pendingPacket_);
|
||||||
} else if (state_ == AppState::SLAVE_WAIT_START && type == MessageType::START_STAGE) {
|
} else if (state_ == AppState::SLAVE_WAIT_START && type == MessageType::START_STAGE) {
|
||||||
actual_.actualHz = r.packet.actualHz; actual_.actualDutyPct = r.packet.actualDutyX100 / 100.0f;
|
sequence_ = r.packet.sequence;
|
||||||
|
actual_.actualHz = r.packet.actualHz; actual_.actualPulseNs = r.packet.actualPulseNs;
|
||||||
|
actual_.actualDutyPct = dutyFromPulse(actual_.actualHz, actual_.actualPulseNs);
|
||||||
if (!startLocalMeasurement(actual_.actualHz, actual_.actualDutyPct)) { finish(false, FailReason::UNSUPPORTED); continue; }
|
if (!startLocalMeasurement(actual_.actualHz, actual_.actualDutyPct)) { finish(false, FailReason::UNSUPPORTED); continue; }
|
||||||
state_ = AppState::SLAVE_MEASURE; deadlineMs_ = millis() + params_.testTimeMs * params_.repeats + LINK_REPLY_TIMEOUT_MS;
|
showStageProgress();
|
||||||
|
state_ = AppState::SLAVE_MEASURE;
|
||||||
|
deadlineMs_ = millis() + stageWallTimeMs(params_.testTimeMs, actual_.actualHz) + LINK_REPLY_TIMEOUT_MS;
|
||||||
|
ProtocolPacket started = makePacket(MessageType::READY);
|
||||||
|
started.sequence = r.packet.sequence; sendLinked(started);
|
||||||
|
} else if (state_ == AppState::SLAVE_MEASURE && type == MessageType::START_STAGE) {
|
||||||
|
// START_STAGE or its acknowledgement was lost. Do not restart the
|
||||||
|
// measurement; only confirm the already running stage again.
|
||||||
|
ProtocolPacket started = makePacket(MessageType::READY);
|
||||||
|
started.sequence = r.packet.sequence; sendLinked(started);
|
||||||
} else if (state_ == AppState::SLAVE_WAIT_ACK && type == MessageType::ACK && r.packet.sequence == pendingPacket_.sequence) {
|
} else if (state_ == AppState::SLAVE_WAIT_ACK && type == MessageType::ACK && r.packet.sequence == pendingPacket_.sequence) {
|
||||||
if (pendingPacket_.passed) { ++stageIndex_; state_ = AppState::SLAVE_WAIT_START; display_.show("SLAVE READY", "WAIT PREPARE"); }
|
if (pendingPacket_.passed) {
|
||||||
else finish(false, static_cast<FailReason>(pendingPacket_.reason));
|
// Master sends ACK only after stopping its PWM. Disable capture for
|
||||||
|
// every completed stage, so the next start can clear its queue without
|
||||||
|
// racing the ISR (not only after the final stage).
|
||||||
|
receiver_.stop();
|
||||||
|
if (r.packet.passed) {
|
||||||
|
radio_.end(); pendingReason_ = FailReason::NONE;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else finish(false, static_cast<FailReason>(pendingPacket_.reason), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,56 +1344,106 @@ void App::handleRadio() {
|
|||||||
void App::updateMaster() {
|
void App::updateMaster() {
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
if (state_ == AppState::MASTER_DISCOVER) {
|
if (state_ == AppState::MASTER_DISCOVER) {
|
||||||
if (now - lastSendMs_ >= LINK_RETRY_INTERVAL_MS) {
|
if (now - lastOpticalWakeToggleMs_ >= OPTICAL_WAKE_HALF_PERIOD_MS) {
|
||||||
Log::event("ESP-NOW", "DISCOVER retry"); radio_.sendBroadcast(pendingPacket_);
|
opticalWakeActive_ = !opticalWakeActive_;
|
||||||
|
if (opticalWakeActive_) pwm_.lightOn();
|
||||||
|
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_);
|
||||||
lastSendMs_ = now;
|
lastSendMs_ = now;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (state_ == AppState::MASTER_FINALIZE) {
|
||||||
|
if (now < deadlineMs_) return;
|
||||||
|
if (retries_++ < FINAL_ACK_RETRIES) {
|
||||||
|
sendLinked(pendingPacket_);
|
||||||
|
deadlineMs_ = now + FINAL_ACK_RETRY_INTERVAL_MS;
|
||||||
|
} else finish(true, FailReason::NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
updateHeartbeat();
|
updateHeartbeat();
|
||||||
if (state_ == AppState::FINISHED) return;
|
if (state_ == AppState::FINISHED) return;
|
||||||
if (now < deadlineMs_) return;
|
if (now < deadlineMs_) return;
|
||||||
if (retries_ >= LINK_PACKET_RETRIES) { finish(false, FailReason::LINK_LOST); return; }
|
if (retries_ >= LINK_PACKET_RETRIES) { finish(false, FailReason::LINK_LOST); return; }
|
||||||
Log::printf("ESP-NOW", "%s retry=%u", messageName(static_cast<MessageType>(pendingPacket_.type)), retries_ + 1);
|
Log::printf("ESP-NOW", "%s retry=%u", messageName(static_cast<MessageType>(pendingPacket_.type)), retries_ + 1);
|
||||||
radio_.sendBroadcast(pendingPacket_); ++retries_;
|
sendLinked(pendingPacket_); ++retries_;
|
||||||
deadlineMs_ = now + (state_ == AppState::MASTER_WAIT_RESULT ?
|
deadlineMs_ = now + (state_ == AppState::MASTER_WAIT_RESULT ?
|
||||||
params_.testTimeMs * params_.repeats + LINK_REPLY_TIMEOUT_MS : LINK_REPLY_TIMEOUT_MS);
|
(stageStartConfirmed_ ? stageWallTimeMs(params_.testTimeMs, actual_.actualHz) + LINK_REPLY_TIMEOUT_MS : LINK_RETRY_INTERVAL_MS) :
|
||||||
|
LINK_REPLY_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::updateSlave() {
|
void App::updateSlave() {
|
||||||
updateHeartbeat();
|
updateHeartbeat();
|
||||||
if (state_ == AppState::FINISHED) return;
|
if (state_ == AppState::FINISHED) return;
|
||||||
if (state_ == AppState::SLAVE_MEASURE) {
|
if (state_ == AppState::SLAVE_MEASURE) {
|
||||||
|
if (static_cast<int32_t>(millis() - localMeasurementDeadlineMs_) >= 0) {
|
||||||
|
Log::event("MEASURE", "Slave local stage watchdog expired");
|
||||||
|
measurement_.forceFail(FailReason::LOST_EDGE);
|
||||||
|
}
|
||||||
const MeasureState ms = measurement_.update();
|
const MeasureState ms = measurement_.update();
|
||||||
if (ms != MeasureState::PASS && ms != MeasureState::FAIL) return;
|
if (measurement_.takeProgressUpdate()) {
|
||||||
printStageStats(measurement_.stats(), requestedHz_);
|
StageStats live = {};
|
||||||
|
if (measurement_.statsSnapshot(live)) {
|
||||||
|
ProtocolPacket progress = makePacket(MessageType::PROGRESS);
|
||||||
|
progress.progressStep = measurement_.progressStep();
|
||||||
|
fillMeasuredResult(progress, live);
|
||||||
|
progress.sequence = sequence_; sendLinked(progress);
|
||||||
|
showStageResult(live);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ms != MeasureState::PASS && ms != MeasureState::FAIL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printStageStats(measurement_.stats(), actual_.actualHz);
|
||||||
|
showStageResult(measurement_.stats());
|
||||||
pendingPacket_ = makePacket(MessageType::RESULT);
|
pendingPacket_ = makePacket(MessageType::RESULT);
|
||||||
|
pendingPacket_.progressStep = ms == MeasureState::PASS ?
|
||||||
|
MEASUREMENT_PROGRESS_STEPS : measurement_.progressStep();
|
||||||
pendingPacket_.passed = ms == MeasureState::PASS && measurement_.reason() == FailReason::NONE;
|
pendingPacket_.passed = ms == MeasureState::PASS && measurement_.reason() == FailReason::NONE;
|
||||||
pendingPacket_.reason = static_cast<uint8_t>(measurement_.reason()); pendingPacket_.periods = measurement_.stats().periods;
|
pendingPacket_.reason = static_cast<uint8_t>(measurement_.reason()); pendingPacket_.periods = measurement_.stats().periods;
|
||||||
|
fillMeasuredResult(pendingPacket_, measurement_.stats());
|
||||||
pendingPacket_.minPeriodTicks = measurement_.stats().minPeriod; pendingPacket_.maxPeriodTicks = measurement_.stats().maxPeriod;
|
pendingPacket_.minPeriodTicks = measurement_.stats().minPeriod; pendingPacket_.maxPeriodTicks = measurement_.stats().maxPeriod;
|
||||||
pendingPacket_.sequence = ++sequence_; radio_.sendBroadcast(pendingPacket_);
|
pendingPacket_.sequence = ++sequence_; sendLinked(pendingPacket_);
|
||||||
Log::printf("TEST", "Slave result prepared: %s reason=%s periods=%lu",
|
Log::printf("TEST", "Slave result prepared: %s reason=%s periods=%lu",
|
||||||
pendingPacket_.passed ? "PASS" : "FAIL", failName(static_cast<FailReason>(pendingPacket_.reason)), pendingPacket_.periods);
|
pendingPacket_.passed ? "PASS" : "FAIL", failName(static_cast<FailReason>(pendingPacket_.reason)), pendingPacket_.periods);
|
||||||
state_ = AppState::SLAVE_WAIT_ACK; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
state_ = AppState::SLAVE_WAIT_ACK; retries_ = 0; deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS;
|
||||||
} else if (state_ == AppState::SLAVE_WAIT_ACK && millis() >= deadlineMs_) {
|
} else if (state_ == AppState::SLAVE_WAIT_ACK && millis() >= deadlineMs_) {
|
||||||
if (retries_++ >= LINK_PACKET_RETRIES) finish(false, FailReason::LINK_LOST);
|
if (retries_++ >= LINK_PACKET_RETRIES) finish(false, FailReason::LINK_LOST);
|
||||||
else { Log::printf("ESP-NOW", "RESULT retry=%u", retries_); radio_.sendBroadcast(pendingPacket_); deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS; }
|
else { Log::printf("ESP-NOW", "RESULT retry=%u", retries_); sendLinked(pendingPacket_); deadlineMs_ = millis() + LINK_REPLY_TIMEOUT_MS; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::sendAbort() { if (havePeer_) sendCurrent(MessageType::ABORT); }
|
void App::sendAbort(FailReason reason) {
|
||||||
|
if (!havePeer_) return;
|
||||||
|
++sequence_;
|
||||||
|
ProtocolPacket packet = makePacket(MessageType::ABORT);
|
||||||
|
packet.reason = static_cast<uint8_t>(reason);
|
||||||
|
if (!packet.actualPulseNs) packet.actualPulseNs = requestedPulseNs_;
|
||||||
|
sendLinked(packet);
|
||||||
|
}
|
||||||
|
|
||||||
void App::abortTest() {
|
void App::abortTest() {
|
||||||
Log::event("ACTION", "abort requested: sending ABORT, stopping receiver and PWM");
|
Log::event("ACTION", "abort requested: sending ABORT, stopping receiver and PWM");
|
||||||
sendAbort(); measurement_.abort(); finish(false, FailReason::ABORTED);
|
sendAbort(FailReason::ABORTED);
|
||||||
|
measurement_.abort();
|
||||||
|
driverTest_.abort();
|
||||||
|
finish(false, FailReason::ABORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::finish(bool pass, FailReason reason) {
|
void App::finish(bool pass, FailReason reason, bool preserveDisplay) {
|
||||||
Log::printf("TEST", "finishing result=%s reason=%s", pass ? "PASS" : "FAIL", failName(reason));
|
Log::printf("TEST", "finishing result=%s reason=%s", pass ? "PASS" : "FAIL", failName(reason));
|
||||||
const AppState failedState = state_;
|
const AppState failedState = state_;
|
||||||
const bool masterLinkLost = reason == FailReason::LINK_LOST &&
|
const bool masterLinkLost = reason == FailReason::LINK_LOST &&
|
||||||
(failedState == AppState::MASTER_DISCOVER || failedState == AppState::MASTER_WAIT_READY ||
|
(failedState == AppState::MASTER_DISCOVER || failedState == AppState::MASTER_WAIT_READY ||
|
||||||
failedState == AppState::MASTER_WAIT_RESULT);
|
failedState == AppState::MASTER_WAIT_RESULT || failedState == AppState::MASTER_FINALIZE);
|
||||||
|
const bool masterActive = failedState == AppState::MASTER_DISCOVER ||
|
||||||
|
failedState == AppState::MASTER_WAIT_READY || failedState == AppState::MASTER_WAIT_RESULT ||
|
||||||
|
failedState == AppState::MASTER_FINALIZE;
|
||||||
const bool slaveLinkLost = reason == FailReason::LINK_LOST &&
|
const bool slaveLinkLost = reason == FailReason::LINK_LOST &&
|
||||||
(failedState == AppState::SLAVE_READY || failedState == AppState::SLAVE_WAIT_START ||
|
(failedState == AppState::SLAVE_READY || failedState == AppState::SLAVE_WAIT_START ||
|
||||||
failedState == AppState::SLAVE_MEASURE || failedState == AppState::SLAVE_WAIT_ACK);
|
failedState == AppState::SLAVE_MEASURE || failedState == AppState::SLAVE_WAIT_ACK);
|
||||||
@@ -431,36 +1453,222 @@ void App::finish(bool pass, FailReason reason) {
|
|||||||
startMasterDiscovery();
|
startMasterDiscovery();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!pass && masterActive && havePeer_ && reason != FailReason::ABORTED) sendAbort(reason);
|
||||||
if (state_ != AppState::IDLE && state_ != AppState::MENU) radio_.end();
|
if (state_ != AppState::IDLE && state_ != AppState::MENU) radio_.end();
|
||||||
state_ = AppState::FINISHED; pendingReason_ = reason;
|
state_ = AppState::FINISHED; pendingReason_ = reason;
|
||||||
|
setStandbyOpticalOutput();
|
||||||
|
setActivePerformance(false);
|
||||||
|
lastUserActivityMs_ = millis();
|
||||||
if (slaveLinkLost) {
|
if (slaveLinkLost) {
|
||||||
if (armSlave()) display_.show("MASTER LOST", "WAIT MASTER");
|
char target[32], one[64];
|
||||||
|
formatTarget(requestedHz_, requestedPulseNs_, target, sizeof(target));
|
||||||
|
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target);
|
||||||
|
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_,
|
||||||
|
roleCorner(Role::SLAVE));
|
||||||
|
armSlave(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (static_cast<Role>(settings_.role) == Role::SLAVE) slaveRearmAtMs_ = millis() + 2000;
|
// The result has already been acknowledged before a normal measurement
|
||||||
char one[24];
|
// failure reaches here. Re-arm ESP-NOW immediately so a quick retry from
|
||||||
if (pass) { snprintf(one, sizeof(one), "PASS %luHz-%lu", params_.startHz, params_.endHz); display_.show(one, "START=REPEAT"); }
|
// Master is not hidden behind the former two-second delay; preserve the
|
||||||
else if (requestedHz_) {
|
// failure screen while listening.
|
||||||
snprintf(one, sizeof(one), "FAIL AT %lu", requestedHz_); display_.show(one, failName(reason));
|
if (static_cast<Role>(settings_.role) == Role::SLAVE) {
|
||||||
} else {
|
armSlave(true);
|
||||||
display_.show("TEST FAILED", failName(reason));
|
return;
|
||||||
}
|
}
|
||||||
|
if (preserveDisplay) return;
|
||||||
|
char one[64];
|
||||||
|
if (pass) {
|
||||||
|
const Role role = static_cast<Role>(settings_.role);
|
||||||
|
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 target[32];
|
||||||
|
formatTarget(requestedHz_, requestedPulseNs_, target, sizeof(target));
|
||||||
|
snprintf(one, sizeof(one), UiText::FAIL_FORMAT, target);
|
||||||
|
display_.show(one, uiFailName(reason), stageIndex_ + 1, stageCount_,
|
||||||
|
roleCorner(static_cast<Role>(settings_.role)));
|
||||||
|
} else {
|
||||||
|
display_.show(UiText::TEST_FAILED, uiFailName(reason), 0, 0,
|
||||||
|
roleCorner(static_cast<Role>(settings_.role)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::idlePowerSaveAllowed() const {
|
||||||
|
// Never enter blocking light sleep while the settings screen is open. A
|
||||||
|
// wake-up press is deliberately consumed by the button state machine, which
|
||||||
|
// is useful in IDLE but makes menu navigation appear frozen.
|
||||||
|
return !usbHostPresent() && initialized_ && (state_ == AppState::IDLE ||
|
||||||
|
state_ == AppState::FINISHED || state_ == AppState::SLAVE_READY);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::usbHostPresent() const {
|
||||||
|
#if ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT && SOC_USB_SERIAL_JTAG_SUPPORTED
|
||||||
|
// This is driven by USB SOF packets, not by CDC traffic: an enumerated host
|
||||||
|
// keeps the board awake even if COM is closed and no bytes are exchanged.
|
||||||
|
// Retain the state across short SOF/driver glitches.
|
||||||
|
const uint32_t now = millis();
|
||||||
|
if (Serial.isPlugged()) {
|
||||||
|
lastUsbHostSeenMs_ = now ? now : 1U;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return lastUsbHostSeenMs_ &&
|
||||||
|
now - lastUsbHostSeenMs_ <= USB_HOST_DISCONNECT_GRACE_MS;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::setStandbyOpticalOutput() {
|
||||||
|
// Calibration and tests may hold the transmitter active. Idle/result
|
||||||
|
// screens must always detach PWM and restore the physical light-OFF level.
|
||||||
|
pwm_.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::setActivePerformance(bool active) {
|
||||||
|
const bool driverMode = initialized_ &&
|
||||||
|
static_cast<TestGroup>(settings_.testGroup) == TestGroup::OPTICS &&
|
||||||
|
static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER;
|
||||||
|
const uint32_t targetMhz = active ? (driverMode ? 240U : 160U) : 80U;
|
||||||
|
if (getCpuFrequencyMhz() != targetMhz && !setCpuFrequencyMhz(targetMhz))
|
||||||
|
Log::printf("POWER", "CPU frequency change to %luMHz FAILED", targetMhz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::leaveIdlePowerSave(bool wakeDisplay) {
|
||||||
|
if (!idlePowerSave_) {
|
||||||
|
if (wakeDisplay) display_.setPower(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::serviceIdlePowerSave() {
|
||||||
|
if (!idlePowerSaveAllowed()) {
|
||||||
|
leaveIdlePowerSave(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t now = millis();
|
||||||
|
if (!idlePowerSave_) {
|
||||||
|
if (now - lastUserActivityMs_ < IDLE_POWER_SAVE_TIMEOUT_MS) {
|
||||||
|
delay(1); // allow the FreeRTOS idle task to halt the CPU between UI polls
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
idlePowerSave_ = true;
|
||||||
|
pwm_.stop();
|
||||||
|
if (state_ == AppState::SLAVE_READY) {
|
||||||
|
radio_.end();
|
||||||
|
idleSleepRadioStopped_ = true;
|
||||||
|
}
|
||||||
|
display_.setPower(false);
|
||||||
|
Log::event("POWER", "idle timeout; preparing light sleep");
|
||||||
|
Serial.flush();
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_wakeup_enable(static_cast<gpio_num_t>(GPIO_BUTTON_START),
|
||||||
|
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) {
|
||||||
|
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();
|
||||||
|
const esp_err_t result = esp_light_sleep_start();
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
leaveIdlePowerSave(true);
|
||||||
|
delay(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||||
|
const bool buttonWake = digitalRead(GPIO_BUTTON_START) == BUTTON_ACTIVE_LEVEL ||
|
||||||
|
digitalRead(GPIO_BUTTON_MODE) == BUTTON_ACTIVE_LEVEL;
|
||||||
|
if (buttonWake) {
|
||||||
|
startButton_.suppressUntilRelease();
|
||||||
|
modeButton_.suppressUntilRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPIO wake worked, so disarm all level sources before peripherals and the
|
||||||
|
// button state machines are brought back up.
|
||||||
|
gpio_wakeup_disable(static_cast<gpio_num_t>(GPIO_BUTTON_START));
|
||||||
|
gpio_wakeup_disable(static_cast<gpio_num_t>(GPIO_BUTTON_MODE));
|
||||||
|
gpio_wakeup_disable(static_cast<gpio_num_t>(GPIO_RX));
|
||||||
|
|
||||||
|
// Native USB and I2C can retain stale driver state across light sleep even
|
||||||
|
// though their clocks have stopped. A full end/begin cycle prevents the
|
||||||
|
// several-second button stalls and restores Serial output after wake.
|
||||||
|
setActivePerformance(false);
|
||||||
|
Serial.end();
|
||||||
|
delay(2);
|
||||||
|
Serial.begin(SERIAL_BAUD);
|
||||||
|
#if ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
Serial.setTxTimeoutMs(SERIAL_TX_TIMEOUT_MS);
|
||||||
|
#endif
|
||||||
|
Wire.end();
|
||||||
|
Wire.begin(GPIO_SDA, GPIO_SCL);
|
||||||
|
Wire.setClock(400000);
|
||||||
|
Wire.setTimeOut(30);
|
||||||
|
|
||||||
|
// This also restores ESP-NOW when Slave stopped it before sleeping.
|
||||||
|
leaveIdlePowerSave(true);
|
||||||
|
Log::printf("POWER", "light sleep wake cause=%u button=%s; peripherals restored",
|
||||||
|
static_cast<unsigned>(cause), buttonWake ? "YES" : "NO");
|
||||||
|
if (buttonWake)
|
||||||
|
Log::event("POWER", "wake button consumed; next press will perform the action");
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::printConfiguration() {
|
void App::printConfiguration() {
|
||||||
if (SERIAL_MINIMAL_LOG) return;
|
if (SERIAL_MINIMAL_LOG) return;
|
||||||
const char *board = TARGET_IS_C3 ? "ESP32-C3" : "ESP32-S3";
|
const char *board = TARGET_IS_C3 ? "ESP32-C3" : "ESP32-S3";
|
||||||
uint8_t mac[6] = {}; esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
uint8_t mac[6] = {}; esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||||
Serial.printf("\nOptical Channel Tester | %s | mode=%s\n", board, roleName(static_cast<Role>(settings_.role)));
|
if (static_cast<TestGroup>(settings_.testGroup) == TestGroup::BOARD) {
|
||||||
|
Serial.printf("\nOptical Channel Tester | %s | group=BOARD | test=%s\n", board,
|
||||||
|
boardTestName(static_cast<BoardTest>(settings_.boardTest)));
|
||||||
|
Serial.printf("GPIO PWM=%u RX=%u ANALOG_RX=%u VBAT=%u START=%u MODE=%u SDA=%u SCL=%u\n",
|
||||||
|
GPIO_PWM, GPIO_RX, GPIO_ANALOG_RX, GPIO_VBAT, GPIO_BUTTON_START,
|
||||||
|
GPIO_BUTTON_MODE, GPIO_SDA, GPIO_SCL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("\nOptical Channel Tester | %s | group=OPTICS | mode=%s/%s | light=%s\n", board,
|
||||||
|
roleName(static_cast<Role>(settings_.role)),
|
||||||
|
testKindName(static_cast<TestKind>(settings_.testKind)),
|
||||||
|
configuredLevelName(settings_));
|
||||||
Serial.printf("MAC=%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
Serial.printf("MAC=%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
Serial.printf("GPIO PWM=%u RX=%u START=%u MODE=%u SDA=%u SCL=%u\n", GPIO_PWM, GPIO_RX,
|
Serial.printf("GPIO PWM=%u RX=%u START=%u MODE=%u SDA=%u SCL=%u\n", GPIO_PWM, GPIO_RX,
|
||||||
GPIO_BUTTON_START, GPIO_BUTTON_MODE, GPIO_SDA, GPIO_SCL);
|
GPIO_BUTTON_START, GPIO_BUTTON_MODE, GPIO_SDA, GPIO_SCL);
|
||||||
Serial.printf("Test %lu..%lu step %lu Hz, accuracy %.2f%%, %lums x%u, duty %u%%\n",
|
if (static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER) {
|
||||||
params_.startHz, params_.endHz, params_.stepHz, params_.accuracyPct, params_.testTimeMs, params_.repeats, params_.dutyPct);
|
const char *code = lightCodeName(static_cast<LightCode>(settings_.lightCode));
|
||||||
stageCount_ = frequencyPointCount(params_.startHz, params_.endHz, params_.stepHz);
|
Serial.printf("Test %lu Hz, pulse %lu..%lu ns, accuracy %.2f%%, %lums, TX light=%c RX active light=%c\n",
|
||||||
Serial.printf("Frequencies (%lu): ", stageCount_);
|
params_.frequencyHz, params_.maxPulseNs, params_.minPulseNs,
|
||||||
for (uint32_t i = 0; i < stageCount_; ++i) Serial.printf("%lu%s", frequencyAt(params_.startHz, params_.endHz, params_.stepHz, i), i + 1 == stageCount_ ? "\n" : ",");
|
params_.accuracyPct, params_.testTimeMs, code[0], code[1]);
|
||||||
Serial.printf("ALL nominal: %llu us | RX=%s\n", actualNominalTotalUs(), receiver_.highRateBackend() ? "RMT DMA" : "RMT ping-pong");
|
} else {
|
||||||
|
Serial.printf("Test %lu Hz, pulse %lu..%lu ns, accuracy %.2f%%, %lums, optical polarity=AUTO\n",
|
||||||
|
params_.frequencyHz, params_.maxPulseNs, params_.minPulseNs,
|
||||||
|
params_.accuracyPct, params_.testTimeMs);
|
||||||
|
}
|
||||||
|
stageCount_ = pulseWidthPointCount(params_.maxPulseNs, params_.minPulseNs);
|
||||||
|
Serial.printf("Pulse widths descending (%lu): ", stageCount_);
|
||||||
|
for (uint32_t i = 0; i < stageCount_; ++i)
|
||||||
|
Serial.printf("%lu%s", pulseWidthAt(params_.maxPulseNs, params_.minPulseNs, i),
|
||||||
|
i + 1 == stageCount_ ? " ns\n" : ",");
|
||||||
|
Serial.printf("ALL nominal: %llu us | RX=%s\n", actualNominalTotalUs(),
|
||||||
|
receiver_.highRateBackend() ? "MCPWM 80MHz" : "GPIO cycle counter");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t App::actualNominalTotalUs() {
|
uint64_t App::actualNominalTotalUs() {
|
||||||
@@ -473,10 +1681,165 @@ uint64_t App::actualNominalTotalUs() {
|
|||||||
void App::printStageStats(const StageStats &s, uint32_t hz) {
|
void App::printStageStats(const StageStats &s, uint32_t hz) {
|
||||||
if (!s.periods) return;
|
if (!s.periods) return;
|
||||||
const float measuredHz = static_cast<float>(receiver_.tickHz()) * s.periods / s.periodSum;
|
const float measuredHz = static_cast<float>(receiver_.tickHz()) * s.periods / s.periodSum;
|
||||||
const float measuredDuty = 100.0f * s.activeSum / s.periodSum;
|
const uint32_t measuredPulseNs = static_cast<uint32_t>(lround(
|
||||||
const char *status = s.reason == FailReason::NONE ? "PASS" :
|
static_cast<double>(s.activeSum) * 1000000000.0 /
|
||||||
(s.reason == FailReason::DATA_LOST ? "DATA_LOST" : "FAIL");
|
(static_cast<uint64_t>(receiver_.pulseTickHz()) * s.periods)));
|
||||||
Log::printf("RESULT", "%luHz %s periods=%lu measured=%.2fHz duty=%.2f%% lost=%lu%s%s",
|
char requestedText[12], measuredText[12];
|
||||||
hz, status, s.periods, measuredHz, measuredDuty, s.lostItems,
|
Display::formatFrequency(hz, requestedText, sizeof(requestedText));
|
||||||
|
Display::formatFrequency(measuredHz, measuredText, sizeof(measuredText));
|
||||||
|
const char *status = s.reason == FailReason::NONE ? "PASS" : "FAIL";
|
||||||
|
Log::printf("RESULT", "%s/%luns %s periods=%lu measured=%s/%luns skipped=%lu%s%s",
|
||||||
|
requestedText, requestedPulseNs_, status, s.periods, measuredText, measuredPulseNs, s.droppedItems,
|
||||||
s.reason == FailReason::NONE ? "" : " reason=", s.reason == FailReason::NONE ? "" : failName(s.reason));
|
s.reason == FailReason::NONE ? "" : " reason=", s.reason == FailReason::NONE ? "" : failName(s.reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::showStageResult(const StageStats &s) {
|
||||||
|
char one[64], two[64];
|
||||||
|
formatTestTarget(requestedHz_, requestedPulseNs_, one, sizeof(one));
|
||||||
|
if (s.reason != FailReason::NONE) {
|
||||||
|
formatFailure(s.reason, requestedHz_, requestedPulseNs_, one, sizeof(one));
|
||||||
|
if (s.reason == FailReason::PERIOD_OUT && s.badFrequency > 0.0f) {
|
||||||
|
char frequency[12];
|
||||||
|
Display::formatFrequency(s.badFrequency, frequency, sizeof(frequency));
|
||||||
|
snprintf(two, sizeof(two), UiText::PERIOD_OUT_FORMAT, frequency);
|
||||||
|
} else if (s.reason == FailReason::DUTY_OUT && s.badFrequency > 0.0f) {
|
||||||
|
char pulse[12];
|
||||||
|
Display::formatPulse(pulseFromDuty(s.badFrequency, s.badDuty), pulse,
|
||||||
|
sizeof(pulse), true);
|
||||||
|
snprintf(two, sizeof(two), UiText::DUTY_OUT_FORMAT, pulse);
|
||||||
|
} else {
|
||||||
|
snprintf(two, sizeof(two), "%s", uiFailName(s.reason));
|
||||||
|
}
|
||||||
|
display_.show(one, two, overallProgress(stageIndex_, measurement_.progressStep()),
|
||||||
|
overallProgressTotal(stageCount_), roleCorner(static_cast<Role>(settings_.role)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!s.periods || !s.periodSum) {
|
||||||
|
display_.show(one, UiText::NO_MEASUREMENT, overallProgress(stageIndex_, measurement_.progressStep()),
|
||||||
|
overallProgressTotal(stageCount_));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const float measuredHz = static_cast<float>(receiver_.tickHz()) * s.periods / s.periodSum;
|
||||||
|
const uint32_t measuredPulseNs = static_cast<uint32_t>(lround(
|
||||||
|
static_cast<double>(s.activeSum) * 1000000000.0 /
|
||||||
|
(static_cast<uint64_t>(receiver_.pulseTickHz()) * s.periods)));
|
||||||
|
formatMeasured(measuredHz, measuredPulseNs, two, sizeof(two));
|
||||||
|
display_.show(one, two, overallProgress(stageIndex_, measurement_.progressStep()),
|
||||||
|
overallProgressTotal(stageCount_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::showDriverResult(const DriverStats &s, bool testPassed) {
|
||||||
|
char one[64], two[64];
|
||||||
|
const bool haveResponse = s.responses || s.lastResponseTicks;
|
||||||
|
const uint64_t delaySumTicks =
|
||||||
|
s.turnOn.delaySumTicks + s.turnOff.delaySumTicks;
|
||||||
|
const uint64_t responseSumTicks =
|
||||||
|
s.turnOn.responseSumTicks + s.turnOff.responseSumTicks;
|
||||||
|
const uint64_t displayedDelayTicks = s.responses ?
|
||||||
|
delaySumTicks / s.responses : s.lastDelayTicks;
|
||||||
|
const uint64_t displayedResponseTicks = s.responses ?
|
||||||
|
responseSumTicks / s.responses : s.lastResponseTicks;
|
||||||
|
const uint32_t delayNs = static_cast<uint32_t>(
|
||||||
|
(displayedDelayTicks * 1000000000ULL +
|
||||||
|
driverTest_.tickHz() / 2U) / driverTest_.tickHz());
|
||||||
|
const uint32_t responseNs = static_cast<uint32_t>(
|
||||||
|
(displayedResponseTicks * 1000000000ULL +
|
||||||
|
driverTest_.tickHz() / 2U) / driverTest_.tickHz());
|
||||||
|
char delay[12] = "---", response[12] = "---";
|
||||||
|
if (haveResponse) {
|
||||||
|
Display::formatPulse(delayNs, delay, sizeof(delay));
|
||||||
|
Display::formatPulse(responseNs, response, sizeof(response));
|
||||||
|
}
|
||||||
|
if (testPassed) {
|
||||||
|
snprintf(one, sizeof(one), "%s", UiText::PASS_WORD);
|
||||||
|
snprintf(two, sizeof(two), UiText::DRIVER_MEASUREMENT_FORMAT,
|
||||||
|
delay, response);
|
||||||
|
} else if (s.reason != FailReason::NONE) {
|
||||||
|
snprintf(one, sizeof(one), "%s", uiFailName(s.reason));
|
||||||
|
char elapsed[12] = "---", errorPulse[12] = "---";
|
||||||
|
if (s.errorTriggerValid) {
|
||||||
|
const uint64_t elapsedNs =
|
||||||
|
(static_cast<uint64_t>(s.errorTriggerTicks) * 1000000000ULL +
|
||||||
|
driverTest_.tickHz() / 2U) /
|
||||||
|
driverTest_.tickHz();
|
||||||
|
formatElapsedNs(elapsedNs, elapsed, sizeof(elapsed));
|
||||||
|
}
|
||||||
|
if (s.errorPulseValid) {
|
||||||
|
const uint64_t errorPulseNs =
|
||||||
|
(static_cast<uint64_t>(s.errorPulseTicks) * 1000000000ULL +
|
||||||
|
driverTest_.tickHz() / 2U) / driverTest_.tickHz();
|
||||||
|
formatElapsedNs(errorPulseNs, errorPulse, sizeof(errorPulse));
|
||||||
|
}
|
||||||
|
if (s.errorPulseValid)
|
||||||
|
snprintf(two, sizeof(two), "T:%s P:%s", elapsed, errorPulse);
|
||||||
|
else snprintf(two, sizeof(two), "T:%s", elapsed);
|
||||||
|
} else {
|
||||||
|
formatTestTarget(requestedHz_, requestedPulseNs_, one, sizeof(one));
|
||||||
|
snprintf(two, sizeof(two), UiText::DRIVER_MEASUREMENT_FORMAT,
|
||||||
|
delay, response);
|
||||||
|
}
|
||||||
|
const bool finished = testPassed || s.reason != FailReason::NONE;
|
||||||
|
const uint8_t progressSteps = driverTest_.progressSteps();
|
||||||
|
display_.show(one, two,
|
||||||
|
finished ? 0U : overallProgress(
|
||||||
|
stageIndex_, driverTest_.progressStep(), progressSteps),
|
||||||
|
finished ? 0U : overallProgressTotal(stageCount_, progressSteps),
|
||||||
|
s.reason == FailReason::NONE ? nullptr : roleCorner(Role::SOLO));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 one[64], two[64];
|
||||||
|
formatTestTarget(packet.requestedHz, packet.requestedPulseNs, one, sizeof(one));
|
||||||
|
if (reason == FailReason::NONE) {
|
||||||
|
if (packet.measuredHzX10) {
|
||||||
|
formatMeasured(packet.measuredHzX10 / 10.0f, packet.measuredPulseNs, two, sizeof(two));
|
||||||
|
} else snprintf(two, sizeof(two), "%s", UiText::NO_MEASUREMENT);
|
||||||
|
} else if (reason == FailReason::PERIOD_OUT && packet.measuredHzX10) {
|
||||||
|
char frequency[12];
|
||||||
|
Display::formatFrequency(packet.measuredHzX10 / 10.0f, frequency, sizeof(frequency));
|
||||||
|
snprintf(two, sizeof(two), UiText::PERIOD_OUT_FORMAT, frequency);
|
||||||
|
} else if (reason == FailReason::DUTY_OUT && packet.measuredPulseNs) {
|
||||||
|
char pulse[12];
|
||||||
|
Display::formatPulse(packet.measuredPulseNs, pulse, sizeof(pulse), true);
|
||||||
|
snprintf(two, sizeof(two), UiText::DUTY_OUT_FORMAT, pulse);
|
||||||
|
} else {
|
||||||
|
snprintf(two, sizeof(two), "%s", uiFailName(reason));
|
||||||
|
}
|
||||||
|
if (reason != FailReason::NONE)
|
||||||
|
formatFailure(reason, packet.requestedHz, packet.requestedPulseNs, one, sizeof(one));
|
||||||
|
display_.show(one, two, overallProgress(stageIndex_, packet.progressStep),
|
||||||
|
overallProgressTotal(stageCount_), reason == FailReason::NONE ? nullptr :
|
||||||
|
roleCorner(static_cast<Role>(settings_.role)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::fillMeasuredResult(ProtocolPacket &packet, const StageStats &stats) const {
|
||||||
|
packet.reason = static_cast<uint8_t>(stats.reason);
|
||||||
|
packet.periods = stats.periods;
|
||||||
|
if (!stats.periods || !stats.periodSum) return;
|
||||||
|
const bool badPeriod = (stats.reason == FailReason::PERIOD_OUT || stats.reason == FailReason::DUTY_OUT) &&
|
||||||
|
stats.badFrequency > 0.0f;
|
||||||
|
const float measuredHz = badPeriod ? stats.badFrequency :
|
||||||
|
static_cast<float>(receiver_.tickHz()) * stats.periods / stats.periodSum;
|
||||||
|
packet.measuredHzX10 = static_cast<uint32_t>(lroundf(measuredHz * 10.0f));
|
||||||
|
packet.measuredPulseNs = badPeriod ? pulseFromDuty(measuredHz, stats.badDuty) :
|
||||||
|
static_cast<uint32_t>(lround(static_cast<double>(stats.activeSum) * 1000000000.0 /
|
||||||
|
(static_cast<uint64_t>(receiver_.pulseTickHz()) * stats.periods)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::showStageProgress() {
|
||||||
|
if (static_cast<TestKind>(settings_.testKind) == TestKind::DRIVER) {
|
||||||
|
char one[64], two[64];
|
||||||
|
formatTestTarget(requestedHz_, requestedPulseNs_, one, sizeof(one));
|
||||||
|
snprintf(two, sizeof(two), UiText::DRIVER_MEASUREMENT_FORMAT,
|
||||||
|
"---", "---");
|
||||||
|
display_.show(one, two, overallProgress(stageIndex_, 0),
|
||||||
|
overallProgressTotal(stageCount_));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char one[64];
|
||||||
|
formatTestTarget(requestedHz_, requestedPulseNs_, one, sizeof(one));
|
||||||
|
display_.show(one, UiText::NO_MEASUREMENT, overallProgress(stageIndex_, 0),
|
||||||
|
overallProgressTotal(stageCount_));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Buttons.h"
|
#include "Buttons.h"
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
|
#include "DriverTest.h"
|
||||||
#include "Measurement.h"
|
#include "Measurement.h"
|
||||||
|
#include "OpticalCurrent.h"
|
||||||
#include "Pwm.h"
|
#include "Pwm.h"
|
||||||
#include "Radio.h"
|
#include "Radio.h"
|
||||||
#include "SettingsStore.h"
|
#include "SettingsStore.h"
|
||||||
|
|
||||||
enum class AppState : uint8_t {
|
enum class AppState : uint8_t {
|
||||||
IDLE, MENU, SOLO_MEASURE, MASTER_DISCOVER, MASTER_WAIT_READY,
|
IDLE, MENU, BOARD_TEST, SOLO_MEASURE, SOLO_DRIVER, MASTER_DISCOVER, MASTER_WAIT_READY,
|
||||||
MASTER_WAIT_RESULT, SLAVE_READY, SLAVE_WAIT_START, SLAVE_MEASURE,
|
MASTER_WAIT_RESULT, MASTER_FINALIZE, SLAVE_READY, SLAVE_WAIT_START, SLAVE_MEASURE,
|
||||||
SLAVE_WAIT_ACK, FINISHED
|
SLAVE_WAIT_ACK, FINISHED
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,26 +24,52 @@ class App {
|
|||||||
void finishInitialization(bool factoryReset);
|
void finishInitialization(bool factoryReset);
|
||||||
void showMenu();
|
void showMenu();
|
||||||
void changeMenu(int direction);
|
void changeMenu(int direction);
|
||||||
|
void enterOpticalCalibration(uint32_t now);
|
||||||
|
void updateOpticalCalibration(uint32_t now, bool force = false);
|
||||||
|
void leaveOpticalCalibration();
|
||||||
|
void cycleRunMode();
|
||||||
void sanitizeRange();
|
void sanitizeRange();
|
||||||
void startTest();
|
void startTest();
|
||||||
bool armSlave();
|
void startBoardTest();
|
||||||
bool prepareStage();
|
void updateBoardTest(uint32_t now);
|
||||||
|
void stopBoardTest();
|
||||||
|
bool armSlave(bool preserveDisplay = false);
|
||||||
|
bool prepareStage(bool showProgress = true);
|
||||||
bool startLocalMeasurement(float hz, float duty);
|
bool startLocalMeasurement(float hz, float duty);
|
||||||
|
bool startDriverMeasurement();
|
||||||
void startMasterDiscovery();
|
void startMasterDiscovery();
|
||||||
void handleRadio();
|
void handleRadio();
|
||||||
void updateMaster();
|
void updateMaster();
|
||||||
void updateSlave();
|
void updateSlave();
|
||||||
void stagePassed();
|
void stagePassed();
|
||||||
void finish(bool pass, FailReason reason);
|
void finish(bool pass, FailReason reason, bool preserveDisplay = false);
|
||||||
void abortTest();
|
void abortTest();
|
||||||
void sendAbort();
|
void sendAbort(FailReason reason = FailReason::ABORTED);
|
||||||
void printConfiguration();
|
void printConfiguration();
|
||||||
void printStageStats(const StageStats &s, uint32_t hz);
|
void printStageStats(const StageStats &s, uint32_t hz);
|
||||||
|
void showStageResult(const StageStats &s);
|
||||||
|
void showDriverResult(const DriverStats &s, bool testPassed = false);
|
||||||
|
void showRemoteResult(const ProtocolPacket &packet);
|
||||||
|
void fillMeasuredResult(ProtocolPacket &packet, const StageStats &stats) const;
|
||||||
|
void showStageProgress();
|
||||||
uint64_t actualNominalTotalUs();
|
uint64_t actualNominalTotalUs();
|
||||||
ProtocolPacket makePacket(MessageType type) const;
|
ProtocolPacket makePacket(MessageType type) const;
|
||||||
|
bool sendLinked(ProtocolPacket packet);
|
||||||
void sendCurrent(MessageType type);
|
void sendCurrent(MessageType type);
|
||||||
void updateHeartbeat();
|
void updateHeartbeat();
|
||||||
bool packetForCurrent(const ProtocolPacket &p) const;
|
bool packetForCurrent(const ProtocolPacket &p) const;
|
||||||
|
void serviceIdlePowerSave();
|
||||||
|
void serviceSerialConsole();
|
||||||
|
void handleSerialCommand(char *line);
|
||||||
|
void printSerialHelp();
|
||||||
|
void printSerialStatus();
|
||||||
|
bool serialSettingsMutable() const;
|
||||||
|
void finishSerialSettingsChange();
|
||||||
|
void leaveIdlePowerSave(bool wakeDisplay = true);
|
||||||
|
bool idlePowerSaveAllowed() const;
|
||||||
|
bool usbHostPresent() const;
|
||||||
|
void setStandbyOpticalOutput();
|
||||||
|
void setActivePerformance(bool active);
|
||||||
|
|
||||||
Button startButton_, modeButton_;
|
Button startButton_, modeButton_;
|
||||||
Display display_;
|
Display display_;
|
||||||
@@ -51,11 +79,12 @@ class App {
|
|||||||
PwmGenerator pwm_;
|
PwmGenerator pwm_;
|
||||||
PulseReceiver receiver_;
|
PulseReceiver receiver_;
|
||||||
Measurement measurement_;
|
Measurement measurement_;
|
||||||
|
DriverTest driverTest_;
|
||||||
Radio radio_;
|
Radio radio_;
|
||||||
AppState state_ = AppState::IDLE;
|
AppState state_ = AppState::IDLE;
|
||||||
uint8_t menuItem_ = 0;
|
uint8_t menuItem_ = 0;
|
||||||
uint32_t stageIndex_ = 0, stageCount_ = 0;
|
uint32_t stageIndex_ = 0, stageCount_ = 0;
|
||||||
uint32_t requestedHz_ = 0;
|
uint32_t requestedHz_ = 0, requestedPulseNs_ = 0;
|
||||||
ActualPwm actual_ = {};
|
ActualPwm actual_ = {};
|
||||||
FailReason pendingReason_ = FailReason::NONE;
|
FailReason pendingReason_ = FailReason::NONE;
|
||||||
uint32_t session_ = 0;
|
uint32_t session_ = 0;
|
||||||
@@ -63,12 +92,28 @@ class App {
|
|||||||
uint8_t peer_[6] = {};
|
uint8_t peer_[6] = {};
|
||||||
bool havePeer_ = false;
|
bool havePeer_ = false;
|
||||||
uint32_t deadlineMs_ = 0, lastSendMs_ = 0;
|
uint32_t deadlineMs_ = 0, lastSendMs_ = 0;
|
||||||
|
uint32_t localMeasurementDeadlineMs_ = 0;
|
||||||
uint32_t lastHeartbeatMs_ = 0, lastPeerSeenMs_ = 0;
|
uint32_t lastHeartbeatMs_ = 0, lastPeerSeenMs_ = 0;
|
||||||
uint8_t retries_ = 0;
|
uint8_t retries_ = 0;
|
||||||
ProtocolPacket pendingPacket_ = {};
|
ProtocolPacket pendingPacket_ = {};
|
||||||
bool initialized_ = false, bootResetCandidate_ = false;
|
bool initialized_ = false, bootResetCandidate_ = false;
|
||||||
bool sweepHadDataLoss_ = false;
|
|
||||||
uint32_t firstDataLossHz_ = 0;
|
|
||||||
uint32_t bootCheckStartedMs_ = 0;
|
uint32_t bootCheckStartedMs_ = 0;
|
||||||
uint32_t slaveRearmAtMs_ = 0;
|
uint32_t slaveRearmAtMs_ = 0;
|
||||||
|
bool stageStartConfirmed_ = false;
|
||||||
|
uint32_t lastUserActivityMs_ = 0;
|
||||||
|
bool idlePowerSave_ = false;
|
||||||
|
bool idleSleepRadioStopped_ = false;
|
||||||
|
uint32_t lastOpticalWakeToggleMs_ = 0;
|
||||||
|
bool opticalWakeActive_ = false;
|
||||||
|
bool rxPinStateKnown_ = false, rxPinState_ = false;
|
||||||
|
uint32_t boardTestUpdatedMs_ = 0;
|
||||||
|
uint32_t boardDisplayUpdatedMs_ = 0;
|
||||||
|
bool boardPwmLightOn_ = false;
|
||||||
|
bool opticalCalibrationActive_ = false;
|
||||||
|
uint32_t opticalCalibrationStartedMs_ = 0;
|
||||||
|
uint32_t opticalCalibrationUpdatedMs_ = 0;
|
||||||
|
mutable uint32_t lastUsbHostSeenMs_ = 0;
|
||||||
|
char serialLine_[96] = {};
|
||||||
|
uint8_t serialLineLength_ = 0;
|
||||||
|
bool serialLineOverflow_ = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,8 +7,21 @@ void Button::begin() {
|
|||||||
changedAt_ = millis();
|
changedAt_ = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Button::suppressUntilRelease() {
|
||||||
|
suppressed_ = true;
|
||||||
|
raw_ = stable_ = (digitalRead(pin_) == BUTTON_ACTIVE_LEVEL);
|
||||||
|
changedAt_ = millis();
|
||||||
|
longSent_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
ButtonEvent Button::update(uint32_t now) {
|
ButtonEvent Button::update(uint32_t now) {
|
||||||
const bool sample = (digitalRead(pin_) == BUTTON_ACTIVE_LEVEL);
|
const bool sample = (digitalRead(pin_) == BUTTON_ACTIVE_LEVEL);
|
||||||
|
if (suppressed_) {
|
||||||
|
raw_ = stable_ = sample;
|
||||||
|
changedAt_ = now;
|
||||||
|
if (!sample) { suppressed_ = false; longSent_ = false; }
|
||||||
|
return ButtonEvent::NONE;
|
||||||
|
}
|
||||||
if (sample != raw_) { raw_ = sample; changedAt_ = now; }
|
if (sample != raw_) { raw_ = sample; changedAt_ = now; }
|
||||||
if (raw_ != stable_ && now - changedAt_ >= BUTTON_DEBOUNCE_MS) {
|
if (raw_ != stable_ && now - changedAt_ >= BUTTON_DEBOUNCE_MS) {
|
||||||
stable_ = raw_;
|
stable_ = raw_;
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ class Button {
|
|||||||
explicit Button(uint8_t pin) : pin_(pin) {}
|
explicit Button(uint8_t pin) : pin_(pin) {}
|
||||||
void begin();
|
void begin();
|
||||||
ButtonEvent update(uint32_t nowMs);
|
ButtonEvent update(uint32_t nowMs);
|
||||||
|
void suppressUntilRelease();
|
||||||
bool pressed() const { return stable_; }
|
bool pressed() const { return stable_; }
|
||||||
private:
|
private:
|
||||||
uint8_t pin_;
|
uint8_t pin_;
|
||||||
bool raw_ = false, stable_ = false, longSent_ = false;
|
bool raw_ = false, stable_ = false, longSent_ = false;
|
||||||
|
bool suppressed_ = false;
|
||||||
uint32_t changedAt_ = 0, pressedAt_ = 0, nextRepeat_ = 0;
|
uint32_t changedAt_ = 0, pressedAt_ = 0, nextRepeat_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,42 +3,138 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
// ------------------------- Hardware configuration -------------------------
|
// ------------------------- Hardware configuration -------------------------
|
||||||
|
// Enabled for the hand-wired prototype. Comment out for the production PCB.
|
||||||
|
// Both profiles map S3 signals by physical header position with 5V/GND aligned.
|
||||||
|
#define MAKETKA
|
||||||
|
|
||||||
|
// Select exactly one populated receiver circuit. Use
|
||||||
|
// BOARD_RX_INTERFACE_DIGITAL for MAKETKA and boards fitted with GPIO_RX.
|
||||||
|
#define BOARD_RX_INTERFACE_ADC 1
|
||||||
|
#define BOARD_RX_INTERFACE_DIGITAL 2
|
||||||
|
#ifndef BOARD_RX_INTERFACE
|
||||||
|
#define BOARD_RX_INTERFACE BOARD_RX_INTERFACE_DIGITAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOARD_RX_INTERFACE != BOARD_RX_INTERFACE_ADC && \
|
||||||
|
BOARD_RX_INTERFACE != BOARD_RX_INTERFACE_DIGITAL
|
||||||
|
#error "BOARD_RX_INTERFACE must select ADC or DIGITAL"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MAKETKA) && BOARD_RX_INTERFACE == BOARD_RX_INTERFACE_ADC
|
||||||
|
#error "MAKETKA requires BOARD_RX_INTERFACE_DIGITAL"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr bool BOARD_RX_USES_ADC =
|
||||||
|
BOARD_RX_INTERFACE == BOARD_RX_INTERFACE_ADC;
|
||||||
|
|
||||||
|
// Board-test parameters. These checks are selected at runtime from the UI;
|
||||||
|
// no special diagnostic firmware build is required.
|
||||||
|
constexpr uint32_t BOARD_PWM_TEST_FREQUENCY_HZ = 1;
|
||||||
|
constexpr uint32_t BOARD_PWM_TEST_HALF_PERIOD_MS = 500;
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32C3
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
constexpr bool TARGET_IS_C3 = true;
|
constexpr bool TARGET_IS_C3 = true;
|
||||||
constexpr uint8_t GPIO_PWM = 3;
|
constexpr uint8_t GPIO_PWM = 3;
|
||||||
constexpr uint8_t GPIO_RX = 4;
|
constexpr uint8_t GPIO_RX = 4;
|
||||||
|
#ifdef MAKETKA
|
||||||
|
constexpr bool BOARD_ADC_AVAILABLE = false;
|
||||||
constexpr uint8_t GPIO_BUTTON_MODE = 0;
|
constexpr uint8_t GPIO_BUTTON_MODE = 0;
|
||||||
constexpr uint8_t GPIO_BUTTON_START = 1;
|
constexpr uint8_t GPIO_BUTTON_START = 1;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_CURRENT = 2;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_VCC = 5;
|
||||||
|
constexpr uint8_t GPIO_VBAT = UINT8_MAX;
|
||||||
|
constexpr uint8_t GPIO_ANALOG_RX = UINT8_MAX;
|
||||||
|
#else
|
||||||
|
constexpr bool BOARD_ADC_AVAILABLE = true;
|
||||||
|
constexpr uint8_t GPIO_BUTTON_MODE = 20;
|
||||||
|
constexpr uint8_t GPIO_BUTTON_START = 10;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_CURRENT = 1;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_VCC = 5;
|
||||||
|
constexpr uint8_t GPIO_VBAT = 2;
|
||||||
|
constexpr uint8_t GPIO_ANALOG_RX = 0;
|
||||||
|
#endif
|
||||||
constexpr uint8_t GPIO_SDA = 6;
|
constexpr uint8_t GPIO_SDA = 6;
|
||||||
constexpr uint8_t GPIO_SCL = 7;
|
constexpr uint8_t GPIO_SCL = 7;
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
constexpr bool TARGET_IS_C3 = false;
|
constexpr bool TARGET_IS_C3 = false;
|
||||||
constexpr uint8_t GPIO_PWM = 4;
|
#ifdef MAKETKA
|
||||||
constexpr uint8_t GPIO_RX = 5;
|
constexpr bool BOARD_ADC_AVAILABLE = false;
|
||||||
constexpr uint8_t GPIO_BUTTON_MODE = 6;
|
// Same physical header contacts as the C3 MAKETKA profile when 5V/GND align.
|
||||||
constexpr uint8_t GPIO_BUTTON_START = 7;
|
constexpr uint8_t GPIO_PWM = 12;
|
||||||
constexpr uint8_t GPIO_SDA = 8;
|
constexpr uint8_t GPIO_RX = 13;
|
||||||
constexpr uint8_t GPIO_SCL = 9;
|
constexpr uint8_t GPIO_BUTTON_MODE = 9;
|
||||||
|
constexpr uint8_t GPIO_BUTTON_START = 10;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_CURRENT = 2;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_VCC = 6;
|
||||||
|
constexpr uint8_t GPIO_SDA = 44;
|
||||||
|
constexpr uint8_t GPIO_SCL = 1;
|
||||||
|
constexpr uint8_t GPIO_VBAT = UINT8_MAX;
|
||||||
|
constexpr uint8_t GPIO_ANALOG_RX = UINT8_MAX;
|
||||||
|
#else
|
||||||
|
constexpr bool BOARD_ADC_AVAILABLE = true;
|
||||||
|
// The S3 SuperMini is fitted so its 5V and GND pins occupy the same PCB
|
||||||
|
// contacts as on the C3 SuperMini. Signals therefore follow header position.
|
||||||
|
constexpr uint8_t GPIO_PWM = 12;
|
||||||
|
constexpr uint8_t GPIO_RX = 13;
|
||||||
|
constexpr uint8_t GPIO_BUTTON_MODE = 5;
|
||||||
|
constexpr uint8_t GPIO_BUTTON_START = 4;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_CURRENT = 10;
|
||||||
|
constexpr uint8_t GPIO_OPTICAL_VCC = 6;
|
||||||
|
constexpr uint8_t GPIO_SDA = 44;
|
||||||
|
constexpr uint8_t GPIO_SCL = 1;
|
||||||
|
constexpr uint8_t GPIO_VBAT = 11;
|
||||||
|
constexpr uint8_t GPIO_ANALOG_RX = 9;
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#error "Only ESP32-C3 and ESP32-S3 are supported"
|
#error "Only ESP32-C3 and ESP32-S3 are supported"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static_assert(GPIO_OPTICAL_CURRENT != GPIO_PWM &&
|
||||||
|
GPIO_OPTICAL_CURRENT != GPIO_RX &&
|
||||||
|
GPIO_OPTICAL_CURRENT != GPIO_BUTTON_MODE &&
|
||||||
|
GPIO_OPTICAL_CURRENT != GPIO_BUTTON_START &&
|
||||||
|
GPIO_OPTICAL_CURRENT != GPIO_SDA &&
|
||||||
|
GPIO_OPTICAL_CURRENT != GPIO_SCL,
|
||||||
|
"Optical-current ADC GPIO conflicts with another board signal");
|
||||||
|
static_assert(GPIO_OPTICAL_VCC != GPIO_OPTICAL_CURRENT &&
|
||||||
|
GPIO_OPTICAL_VCC != GPIO_PWM &&
|
||||||
|
GPIO_OPTICAL_VCC != GPIO_RX &&
|
||||||
|
GPIO_OPTICAL_VCC != GPIO_BUTTON_MODE &&
|
||||||
|
GPIO_OPTICAL_VCC != GPIO_BUTTON_START &&
|
||||||
|
GPIO_OPTICAL_VCC != GPIO_SDA &&
|
||||||
|
GPIO_OPTICAL_VCC != GPIO_SCL,
|
||||||
|
"Optical-VCC ADC GPIO conflicts with another board signal");
|
||||||
|
|
||||||
constexpr uint8_t OLED_ROTATION = 0;
|
constexpr uint8_t OLED_ROTATION = 0;
|
||||||
|
|
||||||
constexpr uint8_t OLED_ADDRESS = 0x3C;
|
constexpr uint8_t OLED_ADDRESS = 0x3C;
|
||||||
constexpr uint8_t ESPNOW_WIFI_CHANNEL = 6;
|
constexpr uint8_t ESPNOW_WIFI_CHANNEL = 6;
|
||||||
constexpr uint32_t SERIAL_BAUD = 115200;
|
constexpr uint32_t SERIAL_BAUD = 115200;
|
||||||
|
// Native USB CDC may keep a stale "connected" state after light sleep. Keep
|
||||||
|
// logging non-blocking so a missing host can never delay button polling.
|
||||||
|
constexpr uint32_t SERIAL_TX_TIMEOUT_MS = 2;
|
||||||
|
constexpr uint32_t BOARD_ADC_PRINT_INTERVAL_MS = 100;
|
||||||
|
constexpr uint32_t BOARD_TEST_DISPLAY_INTERVAL_MS = 250;
|
||||||
|
constexpr float OPTICAL_VCC = 5.1f;
|
||||||
|
constexpr float OPTICAL_SENSE_R = 47.0f;
|
||||||
|
constexpr float OPTICAL_DIVIDER_RATIO = 2.0f;
|
||||||
|
constexpr uint32_t OPTICAL_CURRENT_SETTLE_MS = 20;
|
||||||
|
constexpr uint32_t OPTICAL_CURRENT_AVERAGING_MS = 200;
|
||||||
constexpr bool SERIAL_ACTION_LOG = true;
|
constexpr bool SERIAL_ACTION_LOG = true;
|
||||||
constexpr bool SERIAL_LOG_TIMESTAMPS = true;
|
constexpr bool SERIAL_LOG_TIMESTAMPS = true;
|
||||||
constexpr bool SERIAL_MINIMAL_LOG = true;
|
constexpr bool SERIAL_MINIMAL_LOG = true;
|
||||||
|
|
||||||
#define BUTTON_ACTIVE_LEVEL LOW
|
#define BUTTON_ACTIVE_LEVEL LOW
|
||||||
#define RX_SIGNAL_INVERTED false
|
// Fixed PCB conversion between electrical GPIO levels and actual optical
|
||||||
#define PWM_SAFE_LEVEL LOW
|
// light. User settings HH/HL/LH/LL operate only in the optical domain and
|
||||||
|
// never change these hardware facts.
|
||||||
|
#define TX_LIGHT_ON_GPIO_LEVEL LOW
|
||||||
|
#define RX_LIGHT_ON_GPIO_LEVEL LOW
|
||||||
|
#define TX_LIGHT_OFF_GPIO_LEVEL (TX_LIGHT_ON_GPIO_LEVEL == HIGH ? LOW : HIGH)
|
||||||
#define PWM_SETTLE_CYCLES 5U
|
#define PWM_SETTLE_CYCLES 5U
|
||||||
|
|
||||||
constexpr uint32_t BUTTON_DEBOUNCE_MS = 30;
|
constexpr uint32_t BUTTON_DEBOUNCE_MS = 30;
|
||||||
constexpr uint32_t BUTTON_LONG_PRESS_MS = 800;
|
constexpr uint32_t BUTTON_LONG_PRESS_MS = 500;
|
||||||
constexpr uint32_t BUTTON_REPEAT_DELAY_MS = 600;
|
constexpr uint32_t BUTTON_REPEAT_DELAY_MS = 600;
|
||||||
constexpr uint32_t BUTTON_REPEAT_MS = 180;
|
constexpr uint32_t BUTTON_REPEAT_MS = 180;
|
||||||
constexpr uint32_t FACTORY_RESET_HOLD_MS = 1500;
|
constexpr uint32_t FACTORY_RESET_HOLD_MS = 1500;
|
||||||
@@ -46,32 +142,92 @@ constexpr uint32_t FACTORY_RESET_HOLD_MS = 1500;
|
|||||||
constexpr uint32_t LINK_REPLY_TIMEOUT_MS = 1500;
|
constexpr uint32_t LINK_REPLY_TIMEOUT_MS = 1500;
|
||||||
constexpr uint8_t LINK_PACKET_RETRIES = 10;
|
constexpr uint8_t LINK_PACKET_RETRIES = 10;
|
||||||
constexpr uint32_t LINK_RETRY_INTERVAL_MS = 1000;
|
constexpr uint32_t LINK_RETRY_INTERVAL_MS = 1000;
|
||||||
|
constexpr uint32_t DISCOVERY_RETRY_INTERVAL_MS = 20;
|
||||||
|
// During discovery Master alternates actual optical light ON and OFF to wake
|
||||||
|
// a sleeping Slave through the optical channel.
|
||||||
|
constexpr uint32_t OPTICAL_WAKE_HALF_PERIOD_MS = 50;
|
||||||
constexpr uint32_t LINK_HEARTBEAT_INTERVAL_MS = 500;
|
constexpr uint32_t LINK_HEARTBEAT_INTERVAL_MS = 500;
|
||||||
constexpr uint32_t LINK_HEARTBEAT_TIMEOUT_MS = 2500;
|
constexpr uint32_t LINK_HEARTBEAT_TIMEOUT_MS = 2500;
|
||||||
|
constexpr uint32_t FINAL_ACK_RETRY_INTERVAL_MS = 50;
|
||||||
|
constexpr uint8_t FINAL_ACK_RETRIES = 2;
|
||||||
constexpr uint8_t NO_SIGNAL_TIMEOUT_PERIODS = 8;
|
constexpr uint8_t NO_SIGNAL_TIMEOUT_PERIODS = 8;
|
||||||
constexpr uint16_t RMT_MIN_RECEIVE_SYMBOLS = 48;
|
|
||||||
constexpr uint16_t RMT_MAX_RECEIVE_SYMBOLS = 512;
|
|
||||||
constexpr uint32_t RMT_TARGET_CHUNK_US = 5000;
|
|
||||||
constexpr uint8_t RMT_QUEUE_BLOCKS = 8;
|
|
||||||
constexpr uint16_t PERIOD_BATCH_SIZE = 128;
|
constexpr uint16_t PERIOD_BATCH_SIZE = 128;
|
||||||
|
// Retained as the minimum statistical depth used by the hardware-resolution
|
||||||
|
// calculation and diagnostics. PASS/FAIL is evaluated for every complete
|
||||||
|
// pulse independently; accumulated values are used only for display.
|
||||||
|
constexpr uint16_t MEASUREMENT_AVERAGING_PERIODS = 100;
|
||||||
|
static_assert(MEASUREMENT_AVERAGING_PERIODS > 0,
|
||||||
|
"Averaging window must contain at least one period");
|
||||||
|
constexpr uint8_t MEASUREMENT_PROGRESS_STEPS = 10;
|
||||||
|
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;
|
||||||
|
// usb_serial_jtag_is_connected() needs no open COM port or CDC traffic, but a
|
||||||
|
// short SOF detection gap must not send the board to sleep.
|
||||||
|
constexpr uint32_t USB_HOST_DISCONNECT_GRACE_MS = 5000;
|
||||||
|
constexpr uint16_t SLAVE_LISTEN_INTERVAL_MS = 100;
|
||||||
|
constexpr uint16_t SLAVE_LISTEN_WINDOW_MS = 20;
|
||||||
|
static_assert(SLAVE_LISTEN_WINDOW_MS < SLAVE_LISTEN_INTERVAL_MS,
|
||||||
|
"Slave listen window must be shorter than its interval");
|
||||||
|
// Conservative sustained validation rate calibrated from real C3 logs.
|
||||||
|
constexpr uint32_t RX_PROCESSING_PERIODS_PER_SECOND = 300000;
|
||||||
|
|
||||||
constexpr uint32_t C3_STRICT_MAX_HZ = 1000000;
|
constexpr uint32_t C3_STRICT_MAX_HZ = 1000000;
|
||||||
constexpr uint32_t S3_STRICT_MAX_HZ = 1000000;
|
constexpr uint32_t S3_STRICT_MAX_HZ = 1000000;
|
||||||
constexpr uint32_t CAPTURE_RESOLUTION_HZ = 80000000;
|
// S3 MCPWM Capture uses one 32-bit 80 MHz timer for both edges. Unlike RMT,
|
||||||
// Arduino-ESP32 uses the 40 MHz crystal as the default LEDC clock on C3/S3.
|
// its width does not constrain long LOW/HIGH intervals, so capture precision
|
||||||
|
// stays at 12.5 ns for every selectable PWM frequency and pulse length.
|
||||||
|
constexpr uint32_t MCPWM_CAPTURE_RESOLUTION_HZ = 80000000;
|
||||||
|
// C3 uses the 40 MHz crystal as the LEDC clock.
|
||||||
// Keep this explicit so the resolution calculation never asks LEDC for an
|
// Keep this explicit so the resolution calculation never asks LEDC for an
|
||||||
// impossible frequency/resolution combination.
|
// impossible frequency/resolution combination.
|
||||||
constexpr uint32_t LEDC_SOURCE_CLOCK_HZ = 40000000;
|
constexpr uint32_t LEDC_SOURCE_CLOCK_HZ = 40000000;
|
||||||
constexpr uint8_t LEDC_CHANNEL = 0;
|
constexpr uint8_t LEDC_CHANNEL = 0;
|
||||||
constexpr uint8_t LEDC_MAX_BITS = 14;
|
constexpr uint8_t LEDC_MAX_BITS = 14;
|
||||||
|
// S3 uses the dedicated MCPWM peripheral. A 20 MHz timer clock keeps the
|
||||||
|
// selectable 500 Hz period within the S3's 16-bit counter while retaining
|
||||||
|
// 50 ns pulse resolution and exact periods for every menu frequency.
|
||||||
|
constexpr uint32_t MCPWM_RESOLUTION_HZ = 20000000;
|
||||||
|
constexpr uint32_t MCPWM_MAX_PERIOD_TICKS = 65535;
|
||||||
|
|
||||||
|
// Concept 1SP0635 status acknowledgement, expressed in the optical domain.
|
||||||
|
constexpr uint32_t DRIVER_MIN_INPUT_PULSE_NS = 2000;
|
||||||
|
constexpr uint32_t DRIVER_ACK_DELAY_NS = 250;
|
||||||
|
constexpr uint32_t DRIVER_ACK_WIDTH_NS = 700;
|
||||||
|
constexpr uint32_t DRIVER_ACK_START_MAX_NS = 2000;
|
||||||
|
constexpr uint32_t DRIVER_ACK_MERGE_MARGIN_NS = 250;
|
||||||
|
// The first MCPWM TX end may belong to a pulse that was already active when
|
||||||
|
// capture was enabled. The following period also drains capture events that
|
||||||
|
// were pending independently in the rising/falling channels. Validation
|
||||||
|
// therefore begins at the third TX period.
|
||||||
|
constexpr uint8_t DRIVER_CAPTURE_SYNC_CYCLES = 2;
|
||||||
|
// Any response this long is a fault, not a normal acknowledgement.
|
||||||
|
constexpr uint32_t DRIVER_FAULT_MIN_NS = 1500;
|
||||||
|
constexpr uint32_t DRIVER_RX_STUCK_MIN_NS = 20000;
|
||||||
|
// Retained by the generic receiver backend; the driver test itself uses the
|
||||||
|
// stricter ACK start deadline above.
|
||||||
|
constexpr uint32_t DRIVER_RESPONSE_TIMEOUT_NS = 10000;
|
||||||
|
|
||||||
// -------------------------- Menu value arrays -----------------------------
|
// -------------------------- Menu value arrays -----------------------------
|
||||||
constexpr uint32_t START_FREQ_OPTIONS_HZ[] = {1000, 2000, 5000, 10000, 20000, 50000};
|
// The test uses one selected PWM frequency and walks the pulse-width list from
|
||||||
constexpr uint32_t END_FREQ_OPTIONS_HZ[] = {100000, 200000, 500000, 750000, 1000000};
|
// the selected maximum down to the selected minimum. Widths are stored in
|
||||||
constexpr uint32_t STEP_OPTIONS_HZ[] = {1000, 2000, 5000, 10000, 20000, 50000, 100000};
|
// nanoseconds so sub-microsecond pulses remain representable without floats.
|
||||||
|
constexpr uint32_t PWM_FREQUENCY_OPTIONS_HZ[] = {
|
||||||
|
500, 1000, 2000, 5000, 10000,
|
||||||
|
};
|
||||||
|
constexpr uint32_t MAX_PULSE_OPTIONS_NS[] = {
|
||||||
|
2000, 5000, 10000, 50000, 100000, 500000
|
||||||
|
};
|
||||||
|
constexpr uint32_t MIN_PULSE_OPTIONS_NS[] = {
|
||||||
|
250, 500, 1000, 2000, 5000, 10000, 50000
|
||||||
|
};
|
||||||
|
constexpr uint32_t TEST_PULSE_WIDTHS_NS[] = {
|
||||||
|
50, 100, 150, 200, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000,
|
||||||
|
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};
|
||||||
constexpr uint8_t REPEAT_OPTIONS[] = {1, 2, 3, 5, 10};
|
|
||||||
constexpr uint8_t DUTY_OPTIONS_PCT[] = {10, 25, 50, 75, 90};
|
|
||||||
|
|
||||||
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; }
|
||||||
|
|||||||
176
OpticalChannelTester/Config_Text.h
Normal file
176
OpticalChannelTester/Config_Text.h
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Select the language used by the OLED interface.
|
||||||
|
// Build with UI_LANGUAGE_EN for English or UI_LANGUAGE_RU for Russian.
|
||||||
|
#define UI_LANGUAGE_EN 0
|
||||||
|
#define UI_LANGUAGE_RU 1
|
||||||
|
|
||||||
|
#ifndef UI_LANGUAGE
|
||||||
|
#define UI_LANGUAGE UI_LANGUAGE_RU
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace UiText {
|
||||||
|
|
||||||
|
#if UI_LANGUAGE == UI_LANGUAGE_RU
|
||||||
|
|
||||||
|
constexpr const char *ROLE_NAMES[] = {
|
||||||
|
"СОЛО", "МАСТЕР", "СЛЕЙВ"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *TEST_NAMES[] = {
|
||||||
|
"ОПТИКА", "ДРАЙВЕР"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *TEST_GROUP_NAMES[] = {
|
||||||
|
"ОПТИКА", "ПЛАТА"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *BOARD_TEST_NAMES[] = {
|
||||||
|
"АЦП", "ШИМ ВЫХОД", "RX ВХОД"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *FAIL_NAMES[] = {
|
||||||
|
"НЕТ ОШИБКИ",
|
||||||
|
"НЕТ СИГНАЛА",
|
||||||
|
"ПЕРИОД ВНЕ ДОПУСКА",
|
||||||
|
"ИМПУЛЬС ВНЕ ДОПУСКА",
|
||||||
|
"ЛИШНИЙ ФРОНТ",
|
||||||
|
"ИМПУЛЬСНАЯ ПОМЕХА",
|
||||||
|
"ПРОПУЩЕН ФРОНТ",
|
||||||
|
"ОШИБКА ПОТЕРИ ДАННЫХ",
|
||||||
|
"СВЯЗЬ ПОТЕРЯНА",
|
||||||
|
"РЕЖИМ НЕ ПОДДЕРЖИВ.",
|
||||||
|
"НЕ ХВАТАЕТ ТОЧНОСТИ",
|
||||||
|
"ТЕСТ ОСТАНОВЛЕН",
|
||||||
|
"НЕТ ОТВЕТА ACK",
|
||||||
|
"ТАЙМИНГ ACK",
|
||||||
|
"АВАРИЯ ДРАЙВЕРА",
|
||||||
|
"ОТВЕТЫ ACK СЛИЛИСЬ"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *MODE_PREFIX = "РЕЖИМ: ";
|
||||||
|
constexpr const char *START_RUN = "ГОТОВ К ЗАПУСКУ";
|
||||||
|
|
||||||
|
constexpr const char *MENU_FREQUENCY = "ЧАСТОТА ШИМ:";
|
||||||
|
constexpr const char *MENU_TEST_GROUP = "ГРУППА ТЕСТОВ:";
|
||||||
|
constexpr const char *MENU_MAX_PULSE = "МАКС. ИМПУЛЬС:";
|
||||||
|
constexpr const char *MENU_MIN_PULSE = "МИН. ИМПУЛЬС:";
|
||||||
|
constexpr const char *MENU_ACCURACY = "ТОЧНОСТЬ:";
|
||||||
|
constexpr const char *MENU_TEST_TIME = "ВРЕМЯ ВЫБОРКИ:";
|
||||||
|
constexpr const char *MENU_LIGHT_CODE = "АКТ. УРОВЕНЬ:";
|
||||||
|
constexpr const char *MENU_OPTICAL_CALIBRATION = "КАЛИБР. ОПТИКИ";
|
||||||
|
constexpr const char *LIGHT_CODE_FORMAT = "TX:%c, RX:%c";
|
||||||
|
constexpr const char *LIGHT_AUTO = "АВТО";
|
||||||
|
constexpr const char *LIGHT_AUTO_FORMAT = "TX/RX: АВТО";
|
||||||
|
constexpr const char *MENU_TOTAL_TIME = "ОБЩЕЕ ВРЕМЯ:";
|
||||||
|
constexpr const char *BOARD_READY = "START: ЗАПУСК";
|
||||||
|
constexpr const char *BOARD_STOP = "УДЕРЖ START: СТОП";
|
||||||
|
constexpr const char *ADC_UNAVAILABLE = "АЦП НЕТ НА МАКЕТКЕ";
|
||||||
|
constexpr const char *FREQUENCY_UNIT = " Гц";
|
||||||
|
|
||||||
|
constexpr const char *SLAVE_READY = "СЛЕЙВ ГОТОВ";
|
||||||
|
constexpr const char *WAIT_MASTER = "ОЖИДАНИЕ МАСТЕРА";
|
||||||
|
constexpr const char *LINK_FAILED = "СВЯЗЬ НЕ УСТАНОВЛЕНА";
|
||||||
|
constexpr const char *RADIO_ERROR = "ОШИБКА СВЯЗИ";
|
||||||
|
constexpr const char *MASTER_SEARCH = "ПОИСК СЛЕЙВА";
|
||||||
|
constexpr const char *HOLD_START_STOP = "УДЕРЖ. ПУСК ДЛЯ СТОП";
|
||||||
|
constexpr const char *MASTER_SEEN = "МАСТЕР ОБНАРУЖЕН";
|
||||||
|
constexpr const char *ACK_SENT = "ОТВЕТ ОТПРАВЛЕН";
|
||||||
|
constexpr const char *START_AGAIN = "ГОТОВ К ЗАПУСКУ";
|
||||||
|
constexpr const char *TEST_FAILED = "ТЕСТ НЕ ПРОЙДЕН";
|
||||||
|
|
||||||
|
constexpr const char *PASS_WORD = "ТЕСТ ПРОЙДЕН";
|
||||||
|
constexpr const char *FAIL_FORMAT = "СБОЙ %s";
|
||||||
|
constexpr const char *TEST_FORMAT = "%s, %s";
|
||||||
|
constexpr const char *TEST_TARGET_FORMAT = "ТЕСТ: %s";
|
||||||
|
constexpr const char *FAIL_TARGET_FORMAT = "СБОЙ: %s";
|
||||||
|
constexpr const char *PERIOD_OUT_FORMAT = "ЧАСТОТА: %s";
|
||||||
|
constexpr const char *DUTY_OUT_FORMAT = "ИМПУЛЬС: %s";
|
||||||
|
constexpr const char *NO_MEASUREMENT = "F:---, P:---";
|
||||||
|
constexpr const char *DRIVER_RESPONSE_FORMAT = "ACK:%lu D:%luns";
|
||||||
|
constexpr const char *DRIVER_MEASUREMENT_FORMAT = "D: %s, P: %s";
|
||||||
|
|
||||||
|
#elif UI_LANGUAGE == UI_LANGUAGE_EN
|
||||||
|
|
||||||
|
constexpr const char *ROLE_NAMES[] = {
|
||||||
|
"SOLO", "MASTER", "SLAVE"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *TEST_NAMES[] = {
|
||||||
|
"OPTICAL", "DRIVER"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *TEST_GROUP_NAMES[] = {
|
||||||
|
"OPTICS", "BOARD"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *BOARD_TEST_NAMES[] = {
|
||||||
|
"ADC", "PWM OUTPUT", "RX INPUT"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *FAIL_NAMES[] = {
|
||||||
|
"NONE",
|
||||||
|
"NO SIGNAL",
|
||||||
|
"PERIOD OUT",
|
||||||
|
"PULSE OUT",
|
||||||
|
"EXTRA EDGE",
|
||||||
|
"GLITCH",
|
||||||
|
"LOST EDGE",
|
||||||
|
"DATA LOSS ERROR",
|
||||||
|
"LINK LOST",
|
||||||
|
"UNSUPPORTED",
|
||||||
|
"RESOLUTION",
|
||||||
|
"ABORTED",
|
||||||
|
"ACK MISSING",
|
||||||
|
"ACK TIMING",
|
||||||
|
"DRIVER FAULT",
|
||||||
|
"ACK MERGED"
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char *MODE_PREFIX = "MODE: ";
|
||||||
|
constexpr const char *START_RUN = "READY TO START";
|
||||||
|
|
||||||
|
constexpr const char *MENU_FREQUENCY = "PWM FREQUENCY:";
|
||||||
|
constexpr const char *MENU_TEST_GROUP = "TEST GROUP:";
|
||||||
|
constexpr const char *MENU_MAX_PULSE = "MAX PULSE:";
|
||||||
|
constexpr const char *MENU_MIN_PULSE = "MIN PULSE:";
|
||||||
|
constexpr const char *MENU_ACCURACY = "ACCURACY:";
|
||||||
|
constexpr const char *MENU_TEST_TIME = "TEST TIME:";
|
||||||
|
constexpr const char *MENU_LIGHT_CODE = "ACTIVE LEVEL:";
|
||||||
|
constexpr const char *MENU_OPTICAL_CALIBRATION = "OPTICAL CALIBRATION";
|
||||||
|
constexpr const char *LIGHT_CODE_FORMAT = "TX:%c, RX:%c";
|
||||||
|
constexpr const char *LIGHT_AUTO = "AUTO";
|
||||||
|
constexpr const char *LIGHT_AUTO_FORMAT = "TX/RX: AUTO";
|
||||||
|
constexpr const char *MENU_TOTAL_TIME = "TOTAL TIME:";
|
||||||
|
constexpr const char *BOARD_READY = "START TO RUN";
|
||||||
|
constexpr const char *BOARD_STOP = "HOLD START TO STOP";
|
||||||
|
constexpr const char *ADC_UNAVAILABLE = "ADC ABSENT ON PROTOTYPE";
|
||||||
|
constexpr const char *FREQUENCY_UNIT = " Hz";
|
||||||
|
|
||||||
|
constexpr const char *SLAVE_READY = "SLAVE READY";
|
||||||
|
constexpr const char *WAIT_MASTER = "WAIT MASTER";
|
||||||
|
constexpr const char *LINK_FAILED = "LINK FAILED";
|
||||||
|
constexpr const char *RADIO_ERROR = "RADIO ERROR";
|
||||||
|
constexpr const char *MASTER_SEARCH = "MASTER SEARCH";
|
||||||
|
constexpr const char *HOLD_START_STOP = "HOLD START TO STOP";
|
||||||
|
constexpr const char *MASTER_SEEN = "MASTER SEEN";
|
||||||
|
constexpr const char *ACK_SENT = "ACK SENT";
|
||||||
|
constexpr const char *START_AGAIN = "READY TO START";
|
||||||
|
constexpr const char *TEST_FAILED = "TEST FAILED";
|
||||||
|
|
||||||
|
constexpr const char *PASS_WORD = "TEST PASS";
|
||||||
|
constexpr const char *FAIL_FORMAT = "FAIL %s";
|
||||||
|
constexpr const char *TEST_FORMAT = "%s, %s";
|
||||||
|
constexpr const char *TEST_TARGET_FORMAT = "TEST: %s";
|
||||||
|
constexpr const char *FAIL_TARGET_FORMAT = "FAIL AT %s";
|
||||||
|
constexpr const char *PERIOD_OUT_FORMAT = "FREQ OUT %s";
|
||||||
|
constexpr const char *DUTY_OUT_FORMAT = "PULSE OUT %s";
|
||||||
|
constexpr const char *NO_MEASUREMENT = "F:---, P:---";
|
||||||
|
constexpr const char *DRIVER_RESPONSE_FORMAT = "ACK:%lu D:%luns";
|
||||||
|
constexpr const char *DRIVER_MEASUREMENT_FORMAT = "D: %s, P: %s";
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "UI_LANGUAGE must be UI_LANGUAGE_EN or UI_LANGUAGE_RU"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace UiText
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
|
#include "Config.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -8,10 +9,35 @@ const char *roleName(Role r) {
|
|||||||
return i < 3 ? names[i] : "?";
|
return i < 3 ? names[i] : "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *testGroupName(TestGroup group) {
|
||||||
|
static const char *names[] = {"OPTICS", "BOARD"};
|
||||||
|
const uint8_t i = static_cast<uint8_t>(group);
|
||||||
|
return i < 2 ? names[i] : "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *testKindName(TestKind kind) {
|
||||||
|
static const char *names[] = {"OPTICAL", "DRIVER"};
|
||||||
|
const uint8_t i = static_cast<uint8_t>(kind);
|
||||||
|
return i < 2 ? names[i] : "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *boardTestName(BoardTest test) {
|
||||||
|
static const char *names[] = {"ADC", "PWM OUTPUT", "RX INPUT"};
|
||||||
|
const uint8_t i = static_cast<uint8_t>(test);
|
||||||
|
return i < 3 ? names[i] : "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lightCodeName(LightCode code) {
|
||||||
|
static const char *names[] = {"HH", "HL", "LH", "LL"};
|
||||||
|
const uint8_t i = static_cast<uint8_t>(code);
|
||||||
|
return i < 4 ? names[i] : "??";
|
||||||
|
}
|
||||||
|
|
||||||
const char *failName(FailReason r) {
|
const char *failName(FailReason r) {
|
||||||
static const char *names[] = {"NONE", "NO SIGNAL", "PERIOD OUT", "DUTY OUT",
|
static const char *names[] = {"NONE", "NO SIGNAL", "PERIOD OUT", "PULSE OUT",
|
||||||
"EXTRA EDGE", "GLITCH", "LOST EDGE", "TOO FEW PERIODS", "LINK LOST",
|
"EXTRA EDGE", "GLITCH", "LOST EDGE", "DATA LOSS ERROR", "LINK LOST",
|
||||||
"UNSUPPORTED", "RESOLUTION", "ABORTED", "DATA LOST"};
|
"UNSUPPORTED", "RESOLUTION", "ABORTED", "ACK MISSING", "ACK TIMING",
|
||||||
|
"DRIVER FAULT", "ACK MERGED"};
|
||||||
const uint8_t i = static_cast<uint8_t>(r);
|
const uint8_t i = static_cast<uint8_t>(r);
|
||||||
return i < (sizeof(names) / sizeof(names[0])) ? names[i] : "UNKNOWN";
|
return i < (sizeof(names) / sizeof(names[0])) ? names[i] : "UNKNOWN";
|
||||||
}
|
}
|
||||||
@@ -30,29 +56,52 @@ uint32_t settingsChecksum(const Settings &s) {
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t frequencyPointCount(uint32_t startHz, uint32_t endHz, uint32_t stepHz) {
|
bool txActiveLightOn(const Settings &s) {
|
||||||
if (!startHz || !stepHz || endHz <= startHz) return 0;
|
return static_cast<uint8_t>(s.lightCode) < static_cast<uint8_t>(LightCode::LH);
|
||||||
const uint64_t span = static_cast<uint64_t>(endHz) - startHz;
|
|
||||||
return static_cast<uint32_t>(span / stepHz + 1U + ((span % stepHz) ? 1U : 0U));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t frequencyAt(uint32_t startHz, uint32_t endHz, uint32_t stepHz, uint32_t index) {
|
bool rxActiveLightOn(const Settings &s) {
|
||||||
const uint32_t count = frequencyPointCount(startHz, endHz, stepHz);
|
return (static_cast<uint8_t>(s.lightCode) & 1U) == 0U;
|
||||||
if (!count || index >= count) return 0;
|
}
|
||||||
if (index == count - 1) return endHz;
|
|
||||||
const uint64_t v = static_cast<uint64_t>(startHz) + static_cast<uint64_t>(stepHz) * index;
|
uint32_t pulseWidthPointCount(uint32_t maxPulseNs, uint32_t minPulseNs) {
|
||||||
return v < endHz ? static_cast<uint32_t>(v) : endHz;
|
if (!minPulseNs || maxPulseNs < minPulseNs) return 0;
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (size_t i = 0; i < countOf(TEST_PULSE_WIDTHS_NS); ++i)
|
||||||
|
if (TEST_PULSE_WIDTHS_NS[i] >= minPulseNs && TEST_PULSE_WIDTHS_NS[i] <= maxPulseNs) ++count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pulseWidthAt(uint32_t maxPulseNs, uint32_t minPulseNs, uint32_t index) {
|
||||||
|
for (size_t i = countOf(TEST_PULSE_WIDTHS_NS); i > 0; --i) {
|
||||||
|
const uint32_t pulseNs = TEST_PULSE_WIDTHS_NS[i - 1U];
|
||||||
|
if (pulseNs < minPulseNs || pulseNs > maxPulseNs) continue;
|
||||||
|
if (!index--) return pulseNs;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t nominalStageUs(uint32_t frequencyHz, uint32_t sampleTimeMs, uint32_t settleCycles) {
|
||||||
|
if (!frequencyHz || !sampleTimeMs) return 0;
|
||||||
|
const uint64_t sampleUs = static_cast<uint64_t>(sampleTimeMs) * 1000ULL;
|
||||||
|
// At high frequency the CPU needs longer than the requested sample window
|
||||||
|
// to validate every captured period. Use the measured sustained C3 rate.
|
||||||
|
const uint64_t processingUs =
|
||||||
|
(static_cast<uint64_t>(frequencyHz) * sampleTimeMs * 1000ULL +
|
||||||
|
RX_PROCESSING_PERIODS_PER_SECOND - 1U) / RX_PROCESSING_PERIODS_PER_SECOND;
|
||||||
|
const uint64_t samplingWallUs = processingUs > sampleUs ? processingUs : sampleUs;
|
||||||
|
|
||||||
|
const uint64_t settleUs =
|
||||||
|
(1000000ULL * settleCycles * MEASUREMENT_PROGRESS_STEPS + frequencyHz - 1U) / frequencyHz;
|
||||||
|
// Initial stage screen, nine intermediate screens and the final result.
|
||||||
|
const uint64_t displayUs = static_cast<uint64_t>(OLED_PROGRESS_UPDATE_MS) * 1000ULL *
|
||||||
|
(MEASUREMENT_PROGRESS_STEPS + 1U);
|
||||||
|
return samplingWallUs + settleUs + displayUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t nominalTotalUs(const TestParams &p, uint32_t settleCycles) {
|
uint64_t nominalTotalUs(const TestParams &p, uint32_t settleCycles) {
|
||||||
uint64_t total = 0;
|
return static_cast<uint64_t>(pulseWidthPointCount(p.maxPulseNs, p.minPulseNs)) *
|
||||||
const uint32_t count = frequencyPointCount(p.startHz, p.endHz, p.stepHz);
|
nominalStageUs(p.frequencyHz, p.testTimeMs, settleCycles);
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
|
||||||
const uint32_t f = frequencyAt(p.startHz, p.endHz, p.stepHz, i);
|
|
||||||
total += (1000000ULL * settleCycles + f - 1) / f;
|
|
||||||
total += static_cast<uint64_t>(p.testTimeMs) * 1000ULL * p.repeats;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool periodWithin(float measured, float expected, float tolerance) {
|
bool periodWithin(float measured, float expected, float tolerance) {
|
||||||
@@ -63,6 +112,10 @@ bool dutyWithin(float measured, float expected, float tolerance) {
|
|||||||
return fabsf(measured - expected) <= tolerance + 0.0001f;
|
return fabsf(measured - expected) <= tolerance + 0.0001f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float effectiveTolerancePct(float configured) {
|
||||||
|
return configured;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
||||||
uint8_t maxBits) {
|
uint8_t maxBits) {
|
||||||
if (!frequencyHz || !sourceClockHz || !maxBits) return 0;
|
if (!frequencyHz || !sourceClockHz || !maxBits) return 0;
|
||||||
@@ -72,37 +125,140 @@ uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
|||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t chooseStablePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
||||||
|
uint8_t maxBits, uint8_t dutyPct) {
|
||||||
|
const uint8_t fallback = choosePwmResolution(frequencyHz, sourceClockHz, maxBits);
|
||||||
|
if (!fallback || dutyPct > 100U) return fallback;
|
||||||
|
for (uint8_t bits = fallback; bits > 0; --bits) {
|
||||||
|
const uint32_t levels = 1UL << bits;
|
||||||
|
const uint64_t denominator = static_cast<uint64_t>(frequencyHz) * levels;
|
||||||
|
if (denominator > sourceClockHz || sourceClockHz % denominator) continue;
|
||||||
|
const uint32_t divider = static_cast<uint32_t>(sourceClockHz / denominator);
|
||||||
|
if (!divider || divider > 1024U) continue;
|
||||||
|
if ((static_cast<uint32_t>(levels) * dutyPct) % 100U == 0U) return bits;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool choosePwmConfig(uint32_t requestedHz, uint32_t requestedPulseNs,
|
||||||
|
uint32_t sourceClockHz, uint8_t maxBits,
|
||||||
|
IntegerPwmConfig &config) {
|
||||||
|
if (!requestedHz || !requestedPulseNs || !sourceClockHz || !maxBits) return false;
|
||||||
|
|
||||||
|
constexpr uint32_t FRACTION_SCALE = 256U;
|
||||||
|
constexpr uint32_t MAX_DIVIDER_RAW = 1024U * FRACTION_SCALE - 1U;
|
||||||
|
bool found = false;
|
||||||
|
uint32_t bestFrequencyError = UINT32_MAX;
|
||||||
|
uint32_t bestPulseError = UINT32_MAX;
|
||||||
|
|
||||||
|
for (uint8_t bits = 1; bits <= maxBits && bits < 31; ++bits) {
|
||||||
|
const uint32_t levels = 1UL << bits;
|
||||||
|
const uint64_t dividerNumerator = static_cast<uint64_t>(sourceClockHz) * FRACTION_SCALE;
|
||||||
|
const uint64_t dividerDenominator = static_cast<uint64_t>(requestedHz) * levels;
|
||||||
|
const uint32_t dividerFloor = static_cast<uint32_t>(dividerNumerator / dividerDenominator);
|
||||||
|
const uint32_t candidates[] = {dividerFloor, dividerFloor + 1U};
|
||||||
|
for (uint32_t dividerRaw : candidates) {
|
||||||
|
if (dividerRaw < FRACTION_SCALE || dividerRaw > MAX_DIVIDER_RAW) continue;
|
||||||
|
const uint64_t frequencyDenominator = static_cast<uint64_t>(levels) * dividerRaw;
|
||||||
|
const uint32_t actualHz = static_cast<uint32_t>(
|
||||||
|
(dividerNumerator + frequencyDenominator / 2U) / frequencyDenominator);
|
||||||
|
if (!actualHz) continue;
|
||||||
|
|
||||||
|
const uint64_t dutyNumerator = static_cast<uint64_t>(requestedPulseNs) *
|
||||||
|
sourceClockHz * FRACTION_SCALE;
|
||||||
|
const uint64_t dutyDenominator = static_cast<uint64_t>(dividerRaw) * 1000000000ULL;
|
||||||
|
uint32_t dutyCount = static_cast<uint32_t>((dutyNumerator + dutyDenominator / 2U) /
|
||||||
|
dutyDenominator);
|
||||||
|
if (!dutyCount) dutyCount = 1U;
|
||||||
|
if (dutyCount >= levels) dutyCount = levels - 1U;
|
||||||
|
if (!dutyCount) continue;
|
||||||
|
|
||||||
|
const uint32_t actualPulseNs = static_cast<uint32_t>(
|
||||||
|
(static_cast<uint64_t>(dutyCount) * dividerRaw * 1000000000ULL +
|
||||||
|
static_cast<uint64_t>(sourceClockHz) * FRACTION_SCALE / 2U) /
|
||||||
|
(static_cast<uint64_t>(sourceClockHz) * FRACTION_SCALE));
|
||||||
|
const uint32_t frequencyError = actualHz > requestedHz ? actualHz - requestedHz : requestedHz - actualHz;
|
||||||
|
const uint32_t pulseError = actualPulseNs > requestedPulseNs
|
||||||
|
? actualPulseNs - requestedPulseNs : requestedPulseNs - actualPulseNs;
|
||||||
|
if (found && (frequencyError > bestFrequencyError ||
|
||||||
|
(frequencyError == bestFrequencyError && pulseError > bestPulseError) ||
|
||||||
|
(frequencyError == bestFrequencyError && pulseError == bestPulseError && bits <= config.bits)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
config = {actualHz, dividerRaw, dutyCount, actualPulseNs, bits};
|
||||||
|
bestFrequencyError = frequencyError;
|
||||||
|
bestPulseError = pulseError;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accuracyPct,
|
FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accuracyPct,
|
||||||
uint32_t captureHz, uint8_t pwmBits) {
|
uint32_t periodCaptureHz, uint32_t pulseCaptureHz,
|
||||||
if (!frequencyHz || !captureHz || !pwmBits) return FailReason::RESOLUTION;
|
uint8_t pwmBits,
|
||||||
const float periodTicks = static_cast<float>(captureHz) / frequencyHz;
|
uint16_t averagingPeriods) {
|
||||||
const float activeTicks = periodTicks * dutyPct / 100.0f;
|
if (!frequencyHz || !periodCaptureHz || !pulseCaptureHz || !pwmBits || !averagingPeriods)
|
||||||
const float inactiveTicks = periodTicks - activeTicks;
|
return FailReason::RESOLUTION;
|
||||||
if (periodTicks < 4.0f || activeTicks < 2.0f || inactiveTicks < 2.0f) return FailReason::RESOLUTION;
|
const float periodTicks = static_cast<float>(periodCaptureHz) / frequencyHz;
|
||||||
|
const float activeTicks = static_cast<float>(pulseCaptureHz) * dutyPct /
|
||||||
|
(100.0f * frequencyHz);
|
||||||
|
if (periodTicks < 4.0f || activeTicks < 2.0f) return FailReason::RESOLUTION;
|
||||||
const float timerPeriodError = 100.0f / periodTicks;
|
const float timerPeriodError = 100.0f / periodTicks;
|
||||||
const float timerDutyError = 100.0f / periodTicks;
|
const float timerPulseError = 100.0f / activeTicks;
|
||||||
// Measurement uses the duty actually programmed into LEDC. A coarse PWM
|
// Measurement uses the duty actually programmed into LEDC. A coarse PWM
|
||||||
// step is not itself an error when the requested value (e.g. 50%) is exactly
|
// step is not itself an error when the requested value (e.g. 50%) is exactly
|
||||||
// representable; only the selected value's actual quantization matters.
|
// representable; only the selected value's actual quantization matters.
|
||||||
return (timerPeriodError > accuracyPct || timerDutyError > accuracyPct)
|
const float effectiveAccuracy = effectiveTolerancePct(accuracyPct);
|
||||||
|
return (timerPeriodError > effectiveAccuracy || timerPulseError > effectiveAccuracy)
|
||||||
? FailReason::RESOLUTION : FailReason::NONE;
|
? FailReason::RESOLUTION : FailReason::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FailReason evaluatePeriod(const PulsePeriod &p, uint32_t tickHz, float expectedHz,
|
FailReason evaluatePeriod(const PulsePeriod &p, uint32_t tickHz, float expectedHz,
|
||||||
float expectedDuty, float tolerance, uint8_t repeat,
|
float expectedDuty, float tolerance, uint8_t repeat,
|
||||||
StageStats &s) {
|
StageStats &s) {
|
||||||
if (!p.periodTicks || p.activeTicks >= p.periodTicks) return FailReason::EXTRA_EDGE;
|
const uint32_t pulseTickHz = p.activeTickHz ? p.activeTickHz : tickHz;
|
||||||
|
if (!p.periodTicks || !p.activeTicks || !tickHz || !pulseTickHz || expectedHz <= 0.0f)
|
||||||
|
return FailReason::EXTRA_EDGE;
|
||||||
const float hz = static_cast<float>(tickHz) / p.periodTicks;
|
const float hz = static_cast<float>(tickHz) / p.periodTicks;
|
||||||
const float duty = 100.0f * p.activeTicks / p.periodTicks;
|
const float duty = static_cast<float>(100.0 * p.activeTicks * tickHz /
|
||||||
|
(static_cast<double>(pulseTickHz) * p.periodTicks));
|
||||||
++s.periods;
|
++s.periods;
|
||||||
s.periodSum += p.periodTicks; s.activeSum += p.activeTicks;
|
s.periodSum += p.periodTicks; s.activeSum += p.activeTicks;
|
||||||
if (p.periodTicks < s.minPeriod) s.minPeriod = p.periodTicks;
|
if (p.periodTicks < s.minPeriod) s.minPeriod = p.periodTicks;
|
||||||
if (p.periodTicks > s.maxPeriod) s.maxPeriod = p.periodTicks;
|
if (p.periodTicks > s.maxPeriod) s.maxPeriod = p.periodTicks;
|
||||||
if (p.activeTicks < s.minActive) s.minActive = p.activeTicks;
|
if (p.activeTicks < s.minActive) s.minActive = p.activeTicks;
|
||||||
if (p.activeTicks > s.maxActive) s.maxActive = p.activeTicks;
|
if (p.activeTicks > s.maxActive) s.maxActive = p.activeTicks;
|
||||||
FailReason reason = FailReason::NONE;
|
// Validate every complete period independently. A single capture tick is the
|
||||||
if (!periodWithin(hz, expectedHz, tolerance)) reason = FailReason::PERIOD_OUT;
|
// unavoidable endpoint uncertainty, so only that one tick may be corrected
|
||||||
else if (!dutyWithin(duty, expectedDuty, tolerance)) reason = FailReason::DUTY_OUT;
|
// toward the expected value. It cannot hide a larger isolated distortion.
|
||||||
|
bool frequencyOk = periodWithin(hz, expectedHz, tolerance);
|
||||||
|
if (!frequencyOk) {
|
||||||
|
uint32_t correctedPeriod = p.periodTicks;
|
||||||
|
if (hz > expectedHz) ++correctedPeriod;
|
||||||
|
else if (correctedPeriod > 1U) --correctedPeriod;
|
||||||
|
frequencyOk = periodWithin(static_cast<float>(tickHz) / correctedPeriod,
|
||||||
|
expectedHz, tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
const double expectedPulseTicks = static_cast<double>(pulseTickHz) * expectedDuty /
|
||||||
|
(100.0 * expectedHz);
|
||||||
|
bool pulseOk = expectedPulseTicks > 0.0 &&
|
||||||
|
fabs(static_cast<double>(p.activeTicks) - expectedPulseTicks) * 100.0 /
|
||||||
|
expectedPulseTicks <= tolerance + 0.0001;
|
||||||
|
if (!pulseOk) {
|
||||||
|
uint32_t correctedActive = p.activeTicks;
|
||||||
|
if (correctedActive > expectedPulseTicks) {
|
||||||
|
if (correctedActive) --correctedActive;
|
||||||
|
} else {
|
||||||
|
++correctedActive;
|
||||||
|
}
|
||||||
|
pulseOk = fabs(static_cast<double>(correctedActive) - expectedPulseTicks) *
|
||||||
|
100.0 / expectedPulseTicks <= tolerance + 0.0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FailReason reason = !frequencyOk ? FailReason::PERIOD_OUT :
|
||||||
|
(!pulseOk ? FailReason::DUTY_OUT : FailReason::NONE);
|
||||||
if (reason != FailReason::NONE && s.reason == FailReason::NONE) {
|
if (reason != FailReason::NONE && s.reason == FailReason::NONE) {
|
||||||
s.reason = reason; s.firstBadPeriod = s.periods; s.firstBadRepeat = repeat;
|
s.reason = reason; s.firstBadPeriod = s.periods; s.firstBadRepeat = repeat;
|
||||||
s.badFrequency = hz; s.badDuty = duty;
|
s.badFrequency = hz; s.badDuty = duty;
|
||||||
@@ -162,3 +318,64 @@ FailReason evaluatePeriodFast(const PulsePeriod &p, uint32_t tickHz,
|
|||||||
}
|
}
|
||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FailReason evaluatePeriodWindow(uint64_t periodSum, uint64_t activeSum,
|
||||||
|
uint32_t periodCount, uint32_t tickHz,
|
||||||
|
float expectedHz, float expectedDuty,
|
||||||
|
float tolerance,
|
||||||
|
uint32_t minPeriod, uint32_t maxPeriod,
|
||||||
|
uint8_t repeat,
|
||||||
|
StageStats &s) {
|
||||||
|
if (!periodSum || !periodCount || activeSum >= periodSum || !tickHz)
|
||||||
|
return FailReason::EXTRA_EDGE;
|
||||||
|
const float hz = static_cast<float>(
|
||||||
|
static_cast<double>(tickHz) * periodCount / periodSum);
|
||||||
|
const float duty = static_cast<float>(
|
||||||
|
100.0 * static_cast<double>(activeSum) / periodSum);
|
||||||
|
bool frequencyOk = periodWithin(hz, expectedHz, tolerance);
|
||||||
|
if (!frequencyOk && maxPeriod == minPeriod + 1U) {
|
||||||
|
// At a tolerance boundary, alternating adjacent capture counts prove that the
|
||||||
|
// result is quantization-limited. Accept only when a one-tick correction
|
||||||
|
// toward the expected value returns the averaged frequency into tolerance.
|
||||||
|
// Consecutive periods telescope into one first-to-last edge interval, so
|
||||||
|
// the whole window has a one-tick endpoint uncertainty, not one tick per
|
||||||
|
// period.
|
||||||
|
uint64_t correctedPeriodSum = periodSum;
|
||||||
|
if (hz > expectedHz) ++correctedPeriodSum;
|
||||||
|
else if (periodSum > 1U) --correctedPeriodSum;
|
||||||
|
const float correctedHz = static_cast<float>(
|
||||||
|
static_cast<double>(tickHz) * periodCount / correctedPeriodSum);
|
||||||
|
frequencyOk = periodWithin(correctedHz, expectedHz, tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
const double expectedPulseTicks = static_cast<double>(tickHz) * expectedDuty /
|
||||||
|
(100.0 * expectedHz);
|
||||||
|
const double measuredPulseTicks = static_cast<double>(activeSum) / periodCount;
|
||||||
|
bool pulseOk = expectedPulseTicks > 0.0 &&
|
||||||
|
fabs(measuredPulseTicks - expectedPulseTicks) * 100.0 / expectedPulseTicks <= tolerance + 0.0001;
|
||||||
|
if (!pulseOk) {
|
||||||
|
// Unlike full periods, active intervals do not telescope: every pulse is
|
||||||
|
// bounded by a different rising/falling edge pair. With slowly drifting
|
||||||
|
// asynchronous clocks an entire short window can therefore quantize to
|
||||||
|
// the same adjacent count (e.g. 41/80 for a true 50% duty). Apply one tick
|
||||||
|
// per active interval even when minActive == maxActive.
|
||||||
|
const bool dutyHigh = measuredPulseTicks > expectedPulseTicks;
|
||||||
|
const uint64_t correctedActive = dutyHigh
|
||||||
|
? (activeSum > periodCount ? activeSum - periodCount : 0U)
|
||||||
|
: activeSum + periodCount;
|
||||||
|
const double correctedPulseTicks = static_cast<double>(correctedActive) / periodCount;
|
||||||
|
pulseOk = fabs(correctedPulseTicks - expectedPulseTicks) * 100.0 /
|
||||||
|
expectedPulseTicks <= tolerance + 0.0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
FailReason reason = !frequencyOk ? FailReason::PERIOD_OUT :
|
||||||
|
(!pulseOk ? FailReason::DUTY_OUT : FailReason::NONE);
|
||||||
|
if (reason != FailReason::NONE && s.reason == FailReason::NONE) {
|
||||||
|
s.reason = reason;
|
||||||
|
s.firstBadPeriod = s.periods >= periodCount ? s.periods - periodCount + 1U : 1U;
|
||||||
|
s.firstBadRepeat = repeat;
|
||||||
|
s.badFrequency = hz;
|
||||||
|
s.badDuty = duty;
|
||||||
|
}
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,41 +4,51 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
enum class Role : uint8_t { SOLO, MASTER, SLAVE };
|
enum class Role : uint8_t { SOLO, MASTER, SLAVE };
|
||||||
|
enum class TestGroup : uint8_t { OPTICS, BOARD };
|
||||||
|
enum class TestKind : uint8_t { OPTICAL, DRIVER };
|
||||||
|
enum class BoardTest : uint8_t { ADC, PWM_OUTPUT, RX_INPUT };
|
||||||
|
enum class LightCode : uint8_t { HH, HL, LH, LL };
|
||||||
enum class FailReason : uint8_t {
|
enum class FailReason : uint8_t {
|
||||||
NONE, NO_SIGNAL, PERIOD_OUT, DUTY_OUT, EXTRA_EDGE, GLITCH, LOST_EDGE,
|
NONE, NO_SIGNAL, PERIOD_OUT, DUTY_OUT, EXTRA_EDGE, GLITCH, LOST_EDGE,
|
||||||
TOO_FEW_PERIODS, LINK_LOST, UNSUPPORTED, RESOLUTION, ABORTED, DATA_LOST
|
DATA_LOSS, LINK_LOST, UNSUPPORTED, RESOLUTION, ABORTED,
|
||||||
|
ACK_MISSING, ACK_TIMING, DRIVER_FAULT, ACK_MERGED
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *roleName(Role role);
|
const char *roleName(Role role);
|
||||||
|
const char *testGroupName(TestGroup group);
|
||||||
|
const char *testKindName(TestKind kind);
|
||||||
|
const char *boardTestName(BoardTest test);
|
||||||
|
const char *lightCodeName(LightCode code);
|
||||||
const char *failName(FailReason reason);
|
const char *failName(FailReason reason);
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
uint8_t role;
|
uint8_t role;
|
||||||
uint8_t startIndex;
|
uint8_t testKind;
|
||||||
uint8_t endIndex;
|
uint8_t lightCode;
|
||||||
uint8_t stepIndex;
|
uint8_t frequencyIndex;
|
||||||
|
uint8_t maxPulseIndex;
|
||||||
|
uint8_t minPulseIndex;
|
||||||
uint8_t accuracyIndex;
|
uint8_t accuracyIndex;
|
||||||
uint8_t timeIndex;
|
uint8_t timeIndex;
|
||||||
uint8_t repeatIndex;
|
uint8_t testGroup;
|
||||||
uint8_t dutyIndex;
|
uint8_t boardTest;
|
||||||
uint32_t checksum;
|
uint32_t checksum;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestParams {
|
struct TestParams {
|
||||||
uint32_t startHz;
|
uint32_t frequencyHz;
|
||||||
uint32_t endHz;
|
uint32_t maxPulseNs;
|
||||||
uint32_t stepHz;
|
uint32_t minPulseNs;
|
||||||
float accuracyPct;
|
float accuracyPct;
|
||||||
uint32_t testTimeMs;
|
uint32_t testTimeMs;
|
||||||
uint8_t repeats;
|
|
||||||
uint8_t dutyPct;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PulsePeriod {
|
struct PulsePeriod {
|
||||||
uint64_t startTick;
|
uint64_t startTick;
|
||||||
uint32_t periodTicks;
|
uint32_t periodTicks;
|
||||||
uint32_t activeTicks;
|
uint32_t activeTicks;
|
||||||
|
uint32_t activeTickHz;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StageStats {
|
struct StageStats {
|
||||||
@@ -53,7 +63,7 @@ struct StageStats {
|
|||||||
uint8_t firstBadRepeat;
|
uint8_t firstBadRepeat;
|
||||||
float badFrequency;
|
float badFrequency;
|
||||||
float badDuty;
|
float badDuty;
|
||||||
uint32_t lostItems;
|
uint32_t droppedItems;
|
||||||
FailReason reason;
|
FailReason reason;
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
@@ -65,16 +75,35 @@ struct PeriodLimits {
|
|||||||
uint32_t maxDutyX100;
|
uint32_t maxDutyX100;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IntegerPwmConfig {
|
||||||
|
uint32_t actualHz;
|
||||||
|
uint32_t dividerRaw;
|
||||||
|
uint32_t dutyCount;
|
||||||
|
uint32_t actualPulseNs;
|
||||||
|
uint8_t bits;
|
||||||
|
};
|
||||||
|
|
||||||
uint32_t settingsChecksum(const Settings &s);
|
uint32_t settingsChecksum(const Settings &s);
|
||||||
uint32_t frequencyPointCount(uint32_t startHz, uint32_t endHz, uint32_t stepHz);
|
bool txActiveLightOn(const Settings &s);
|
||||||
uint32_t frequencyAt(uint32_t startHz, uint32_t endHz, uint32_t stepHz, uint32_t index);
|
bool rxActiveLightOn(const Settings &s);
|
||||||
|
uint32_t pulseWidthPointCount(uint32_t maxPulseNs, uint32_t minPulseNs);
|
||||||
|
uint32_t pulseWidthAt(uint32_t maxPulseNs, uint32_t minPulseNs, uint32_t index);
|
||||||
|
uint64_t nominalStageUs(uint32_t frequencyHz, uint32_t sampleTimeMs, uint32_t settleCycles);
|
||||||
uint64_t nominalTotalUs(const TestParams &p, uint32_t settleCycles);
|
uint64_t nominalTotalUs(const TestParams &p, uint32_t settleCycles);
|
||||||
bool periodWithin(float measuredHz, float expectedHz, float tolerancePct);
|
bool periodWithin(float measuredHz, float expectedHz, float tolerancePct);
|
||||||
bool dutyWithin(float measuredPct, float expectedPct, float tolerancePct);
|
bool dutyWithin(float measuredPct, float expectedPct, float tolerancePct);
|
||||||
|
float effectiveTolerancePct(float configuredPct);
|
||||||
uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
uint8_t choosePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
||||||
uint8_t maxBits);
|
uint8_t maxBits);
|
||||||
|
uint8_t chooseStablePwmResolution(uint32_t frequencyHz, uint32_t sourceClockHz,
|
||||||
|
uint8_t maxBits, uint8_t dutyPct);
|
||||||
|
bool choosePwmConfig(uint32_t requestedHz, uint32_t requestedPulseNs,
|
||||||
|
uint32_t sourceClockHz, uint8_t maxBits,
|
||||||
|
IntegerPwmConfig &config);
|
||||||
FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accuracyPct,
|
FailReason validateResolution(uint32_t frequencyHz, float dutyPct, float accuracyPct,
|
||||||
uint32_t captureResolutionHz, uint8_t pwmBits);
|
uint32_t periodResolutionHz, uint32_t pulseResolutionHz,
|
||||||
|
uint8_t pwmBits,
|
||||||
|
uint16_t averagingPeriods);
|
||||||
FailReason evaluatePeriod(const PulsePeriod &period, uint32_t tickHz, float expectedHz,
|
FailReason evaluatePeriod(const PulsePeriod &period, uint32_t tickHz, float expectedHz,
|
||||||
float expectedDuty, float tolerancePct, uint8_t repeat,
|
float expectedDuty, float tolerancePct, uint8_t repeat,
|
||||||
StageStats &stats);
|
StageStats &stats);
|
||||||
@@ -83,3 +112,10 @@ bool makePeriodLimits(uint32_t expectedHz, float expectedDuty, float tolerancePc
|
|||||||
FailReason evaluatePeriodFast(const PulsePeriod &period, uint32_t tickHz,
|
FailReason evaluatePeriodFast(const PulsePeriod &period, uint32_t tickHz,
|
||||||
const PeriodLimits &limits, uint8_t repeat,
|
const PeriodLimits &limits, uint8_t repeat,
|
||||||
StageStats &stats);
|
StageStats &stats);
|
||||||
|
FailReason evaluatePeriodWindow(uint64_t periodSum, uint64_t activeSum,
|
||||||
|
uint32_t periodCount, uint32_t tickHz,
|
||||||
|
float expectedHz, float expectedDuty,
|
||||||
|
float tolerancePct,
|
||||||
|
uint32_t minPeriod, uint32_t maxPeriod,
|
||||||
|
uint8_t repeat,
|
||||||
|
StageStats &stats);
|
||||||
|
|||||||
@@ -1,14 +1,32 @@
|
|||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "Font_Cyrillic.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
uint32_t nextUtf8Codepoint(const char *&text) {
|
||||||
|
const uint8_t first = static_cast<uint8_t>(*text++);
|
||||||
|
if (first < 0x80U) return first;
|
||||||
|
if ((first & 0xE0U) == 0xC0U) {
|
||||||
|
const uint8_t second = static_cast<uint8_t>(*text);
|
||||||
|
if ((second & 0xC0U) == 0x80U) {
|
||||||
|
++text;
|
||||||
|
return ((first & 0x1FU) << 6) | (second & 0x3FU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Display::Display() : oled_(128, 32, &Wire, -1) {}
|
Display::Display() : oled_(128, 32, &Wire, -1) {}
|
||||||
|
|
||||||
bool Display::begin() {
|
bool Display::begin() {
|
||||||
Wire.begin(GPIO_SDA, GPIO_SCL);
|
Wire.begin(GPIO_SDA, GPIO_SCL);
|
||||||
|
Wire.setClock(400000); // keeps a full 128x32 framebuffer update near 15 ms
|
||||||
|
Wire.setTimeOut(30); // a faulty/stretched I2C bus must not stall button polling for seconds
|
||||||
// An absent optional OLED produces a large burst of ESP-IDF NACK messages.
|
// An absent optional OLED produces a large burst of ESP-IDF NACK messages.
|
||||||
// Probe it once and keep the I2C driver quiet when no display is connected.
|
// Probe it once and keep the I2C driver quiet when no display is connected.
|
||||||
esp_log_level_set("i2c.master", ESP_LOG_NONE);
|
esp_log_level_set("i2c.master", ESP_LOG_NONE);
|
||||||
@@ -23,39 +41,118 @@ bool Display::begin() {
|
|||||||
oled_.setRotation(OLED_ROTATION);
|
oled_.setRotation(OLED_ROTATION);
|
||||||
oled_.setTextColor(SSD1306_WHITE);
|
oled_.setTextColor(SSD1306_WHITE);
|
||||||
oled_.setTextSize(1);
|
oled_.setTextSize(1);
|
||||||
|
powered_ = true;
|
||||||
}
|
}
|
||||||
Log::printf("OLED", "initialization %s, I2C address=0x%02X", ok_ ? "OK" : "FAILED", OLED_ADDRESS);
|
Log::printf("OLED", "initialization %s, I2C address=0x%02X", ok_ ? "OK" : "FAILED", OLED_ADDRESS);
|
||||||
return ok_;
|
return ok_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::fit(char *s) {
|
void Display::setPower(bool enabled) {
|
||||||
int16_t x, y; uint16_t w, h;
|
if (!ok_ || powered_ == enabled) return;
|
||||||
while (*s) {
|
oled_.ssd1306_command(enabled ? SSD1306_DISPLAYON : SSD1306_DISPLAYOFF);
|
||||||
oled_.getTextBounds(s, 0, 0, &x, &y, &w, &h);
|
powered_ = enabled;
|
||||||
if (w <= 128) break;
|
Log::printf("OLED", "display power %s", enabled ? "ON" : "OFF");
|
||||||
s[strlen(s) - 1] = '\0';
|
}
|
||||||
|
|
||||||
|
void Display::drawTextLine(const char *text, int16_t y, int16_t startX) {
|
||||||
|
int16_t x = startX;
|
||||||
|
while (text && *text && x + CyrillicFont::WIDTH <= oled_.width()) {
|
||||||
|
const uint32_t codepoint = nextUtf8Codepoint(text);
|
||||||
|
const uint8_t *glyph = CyrillicFont::glyph(codepoint);
|
||||||
|
if (glyph) {
|
||||||
|
for (uint8_t row = 0; row < CyrillicFont::HEIGHT; ++row) {
|
||||||
|
const uint8_t pixels = pgm_read_byte(glyph + row);
|
||||||
|
for (uint8_t column = 0; column < CyrillicFont::WIDTH; ++column)
|
||||||
|
if (pixels & (1U << (CyrillicFont::WIDTH - 1U - column)))
|
||||||
|
oled_.drawPixel(x + column, y + row, SSD1306_WHITE);
|
||||||
|
}
|
||||||
|
} else if (codepoint < 0x100U) {
|
||||||
|
oled_.drawChar(x, y, static_cast<unsigned char>(codepoint),
|
||||||
|
SSD1306_WHITE, SSD1306_BLACK, 1);
|
||||||
|
} else {
|
||||||
|
oled_.drawChar(x, y, '?', SSD1306_WHITE, SSD1306_BLACK, 1);
|
||||||
|
}
|
||||||
|
x += CyrillicFont::ADVANCE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::show(const char *a, const char *b) {
|
void Display::show(const char *a, const char *b, uint32_t progress,
|
||||||
char one[32], two[32];
|
uint32_t progressTotal, const char *topRight) {
|
||||||
|
char one[64], two[64];
|
||||||
snprintf(one, sizeof(one), "%s", a ? a : ""); snprintf(two, sizeof(two), "%s", b ? b : "");
|
snprintf(one, sizeof(one), "%s", a ? a : ""); snprintf(two, sizeof(two), "%s", b ? b : "");
|
||||||
// Serial is the primary UI mirror and remains available when OLED is absent.
|
// Serial is the primary UI mirror and remains available when OLED is absent.
|
||||||
Log::printf("UI", "%s | %s", one, two);
|
Log::printf("UI", "%s | %s", one, two);
|
||||||
if (!ok_) return;
|
if (!ok_) return;
|
||||||
fit(one); fit(two);
|
setPower(true);
|
||||||
oled_.clearDisplay(); oled_.setCursor(0, 3); oled_.print(one);
|
oled_.clearDisplay();
|
||||||
oled_.setCursor(0, 19); oled_.print(two); oled_.display();
|
drawTextLine(one, 3);
|
||||||
|
drawTextLine(two, 19);
|
||||||
|
if (topRight && *topRight) {
|
||||||
|
oled_.fillRect(oled_.width() - CyrillicFont::ADVANCE, 0,
|
||||||
|
CyrillicFont::ADVANCE, CyrillicFont::HEIGHT + 3, SSD1306_BLACK);
|
||||||
|
drawTextLine(topRight, 3, oled_.width() - CyrillicFont::ADVANCE);
|
||||||
|
}
|
||||||
|
if (progressTotal) {
|
||||||
|
if (progress > progressTotal) progress = progressTotal;
|
||||||
|
const uint16_t width = static_cast<uint16_t>(
|
||||||
|
(static_cast<uint64_t>(progress) * 128U + progressTotal - 1U) / progressTotal);
|
||||||
|
if (width) oled_.drawFastHLine(0, 31, width, SSD1306_WHITE);
|
||||||
|
}
|
||||||
|
oled_.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::formatFrequency(float hz, char *out, size_t n) {
|
void Display::formatFrequency(float hz, char *out, size_t n) {
|
||||||
if (hz >= 1000000.0f) snprintf(out, n, "%.2fM", hz / 1000000.0f);
|
float value = hz; const char *suffix = "Hz";
|
||||||
else if (hz >= 1000.0f) snprintf(out, n, "%.2fk", hz / 1000.0f);
|
if (hz >= 999950.0f) { value = hz / 1000000.0f; suffix = "M"; }
|
||||||
else snprintf(out, n, "%.0fHz", hz);
|
else if (hz >= 999.5f) { value = hz / 1000.0f; suffix = "k"; }
|
||||||
|
if (suffix[0] == 'M' && fabsf(value - roundf(value)) < 0.0005f)
|
||||||
|
snprintf(out, n, "%.0f%s", value, suffix);
|
||||||
|
else if (value >= 100.0f) snprintf(out, n, "%.1f%s", value, suffix);
|
||||||
|
else if (value >= 10.0f) snprintf(out, n, "%.2f%s", value, suffix);
|
||||||
|
else snprintf(out, n, "%.3f%s", value, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::formatTestFrequency(uint32_t hz, char *out, size_t n) {
|
||||||
|
if (hz >= 1000000U && hz % 1000000U == 0)
|
||||||
|
snprintf(out, n, "%luM", hz / 1000000U);
|
||||||
|
else if (hz >= 1000U && hz % 1000U == 0)
|
||||||
|
snprintf(out, n, "%luk", hz / 1000U);
|
||||||
|
else if (hz >= 1000U) {
|
||||||
|
const float khz = hz / 1000.0f;
|
||||||
|
if (khz >= 100.0f) snprintf(out, n, "%.1fk", khz);
|
||||||
|
else if (khz >= 10.0f) snprintf(out, n, "%.2fk", khz);
|
||||||
|
else snprintf(out, n, "%.3fk", khz);
|
||||||
|
} else
|
||||||
|
snprintf(out, n, "%lu", hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::formatPwmFrequency(uint32_t hz, char *out, size_t n) {
|
||||||
|
if (hz >= 1000000U && hz % 1000000U == 0U)
|
||||||
|
snprintf(out, n, "%luMHz", hz / 1000000U);
|
||||||
|
else if (hz >= 1000U && hz % 1000U == 0U)
|
||||||
|
snprintf(out, n, "%lukHz", hz / 1000U);
|
||||||
|
else if (hz >= 1000U)
|
||||||
|
snprintf(out, n, "%.3gkHz", hz / 1000.0f);
|
||||||
|
else
|
||||||
|
snprintf(out, n, "%luHz", hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::formatPulse(uint32_t pulseNs, char *out, size_t n, bool measured) {
|
||||||
|
if (pulseNs >= 1000U) {
|
||||||
|
const float us = pulseNs / 1000.0f;
|
||||||
|
if (measured) snprintf(out, n, "%.2fu", us);
|
||||||
|
else if (pulseNs % 1000U == 0U) snprintf(out, n, "%luus", pulseNs / 1000U);
|
||||||
|
else snprintf(out, n, "%.2fus", us);
|
||||||
|
} else if (measured) {
|
||||||
|
snprintf(out, n, "%.3fu", pulseNs / 1000.0f);
|
||||||
|
} else {
|
||||||
|
snprintf(out, n, "%luns", pulseNs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::formatDuration(uint64_t us, char *out, size_t n) {
|
void Display::formatDuration(uint64_t us, char *out, size_t n) {
|
||||||
const uint64_t minutes = us / 60000000ULL;
|
const uint64_t totalSeconds = (us + 999999ULL) / 1000000ULL;
|
||||||
if (minutes < 60) snprintf(out, n, "%02llu:%02llu", minutes, (us / 1000000ULL) % 60ULL);
|
const uint64_t minutes = totalSeconds / 60ULL;
|
||||||
|
if (minutes < 60) snprintf(out, n, "%02llu:%02llu", minutes, totalSeconds % 60ULL);
|
||||||
else snprintf(out, n, "%llu:%02llu", minutes / 60ULL, minutes % 60ULL);
|
else snprintf(out, n, "%llu:%02llu", minutes / 60ULL, minutes % 60ULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,20 @@ class Display {
|
|||||||
public:
|
public:
|
||||||
Display();
|
Display();
|
||||||
bool begin();
|
bool begin();
|
||||||
void show(const char *line1, const char *line2);
|
void show(const char *line1, const char *line2,
|
||||||
|
uint32_t progress = 0, uint32_t progressTotal = 0,
|
||||||
|
const char *topRight = nullptr);
|
||||||
|
void setPower(bool enabled);
|
||||||
bool available() const { return ok_; }
|
bool available() const { return ok_; }
|
||||||
|
bool powered() const { return powered_; }
|
||||||
static void formatFrequency(float hz, char *out, size_t size);
|
static void formatFrequency(float hz, char *out, size_t size);
|
||||||
|
static void formatTestFrequency(uint32_t hz, char *out, size_t size);
|
||||||
|
static void formatPwmFrequency(uint32_t hz, char *out, size_t size);
|
||||||
|
static void formatPulse(uint32_t pulseNs, char *out, size_t size, bool measured = false);
|
||||||
static void formatDuration(uint64_t us, char *out, size_t size);
|
static void formatDuration(uint64_t us, char *out, size_t size);
|
||||||
private:
|
private:
|
||||||
void fit(char *text);
|
void drawTextLine(const char *text, int16_t y, int16_t startX = 0);
|
||||||
Adafruit_SSD1306 oled_;
|
Adafruit_SSD1306 oled_;
|
||||||
bool ok_ = false;
|
bool ok_ = false;
|
||||||
|
bool powered_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
736
OpticalChannelTester/DriverTest.cpp
Normal file
736
OpticalChannelTester/DriverTest.cpp
Normal file
@@ -0,0 +1,736 @@
|
|||||||
|
#include "DriverTest.h"
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#include <esp_cpu.h>
|
||||||
|
#include <esp_task_wdt.h>
|
||||||
|
#include <esp_timer.h>
|
||||||
|
#include <esp32-hal-cpu.h>
|
||||||
|
#include <soc/gpio_struct.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() {
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
minDelayTicks = minResponseTicks = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverStats::reset() {
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
minDelayTicks = minResponseTicks = UINT32_MAX;
|
||||||
|
turnOn.reset();
|
||||||
|
turnOff.reset();
|
||||||
|
reason = FailReason::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t DriverTest::nsToTicks(uint32_t ns) const {
|
||||||
|
return (static_cast<uint64_t>(ns) * captureHz_ + 999999999ULL) /
|
||||||
|
1000000000ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t DriverTest::ticksToNs(uint64_t ticks) const {
|
||||||
|
return (ticks * 1000000000ULL + captureHz_ / 2U) / captureHz_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DriverTest::start(uint32_t frequencyHz, uint32_t pulseNs,
|
||||||
|
float tolerancePct, uint32_t testTimeMs,
|
||||||
|
uint8_t settleCycles, bool activeTxLightOn,
|
||||||
|
bool activeRxLightOn) {
|
||||||
|
(void)tolerancePct;
|
||||||
|
(void)settleCycles;
|
||||||
|
if (!receiver_.highRateBackend() || !frequencyHz || !pulseNs ||
|
||||||
|
!testTimeMs || GPIO_PWM >= 32U || GPIO_RX >= 32U) return false;
|
||||||
|
|
||||||
|
requestCaptureStop();
|
||||||
|
if (!waitCaptureStopped(25U)) return false;
|
||||||
|
if (!pollTask_ && xTaskCreatePinnedToCore(pollTaskEntry, "driver-poll",
|
||||||
|
3072, this, configMAX_PRIORITIES - 1U, &pollTask_, 0) != pdPASS)
|
||||||
|
return false;
|
||||||
|
if (!analyzerTask_ && xTaskCreatePinnedToCore(analyzerTaskEntry,
|
||||||
|
"driver-analyze", 4096, this, 4, &analyzerTask_, 1) != pdPASS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The ACK edges can be less than 1 us apart. MCPWM capture delivers all
|
||||||
|
// channels through one group ISR and can overwrite an earlier channel
|
||||||
|
// timestamp before that ISR reaches it. During DRIVER test dedicate core 0
|
||||||
|
// to direct GPIO sampling; PWM itself remains fully hardware-generated.
|
||||||
|
captureHz_ = getCpuFrequencyMhz() * 1000000UL;
|
||||||
|
if (!captureHz_ || captureHz_ % frequencyHz) return false;
|
||||||
|
captureFrequencyHz_ = frequencyHz;
|
||||||
|
capturePulseNs_ = pulseNs;
|
||||||
|
captureTxLightOn_ = activeTxLightOn;
|
||||||
|
txPulseLightOn_ = activeTxLightOn;
|
||||||
|
pollPeriodCycles_ = captureHz_ / frequencyHz;
|
||||||
|
pollWindowBeforeCycles_ = captureHz_ / 200000U; // 5 us
|
||||||
|
const uint64_t periodNs = 1000000000ULL / frequencyHz;
|
||||||
|
uint64_t windowNs = pulseNs + 50000ULL;
|
||||||
|
const uint64_t maximumWindowNs = periodNs * 3ULL / 4ULL;
|
||||||
|
if (windowNs > maximumWindowNs) windowNs = maximumWindowNs;
|
||||||
|
pollWindowAfterCycles_ = static_cast<uint32_t>(
|
||||||
|
windowNs * captureHz_ / 1000000000ULL);
|
||||||
|
const uint8_t activeTxRaw = activeTxLightOn ? TX_LIGHT_ON_GPIO_LEVEL :
|
||||||
|
TX_LIGHT_OFF_GPIO_LEVEL;
|
||||||
|
pollTxStartRawHigh_ = activeTxRaw == HIGH;
|
||||||
|
rxActiveRawHigh_ =
|
||||||
|
((RX_LIGHT_ON_GPIO_LEVEL == HIGH) == activeRxLightOn);
|
||||||
|
|
||||||
|
ackStartMaxTicks_ = nsToTicks(DRIVER_ACK_START_MAX_NS);
|
||||||
|
faultLongTicks_ = nsToTicks(DRIVER_FAULT_MIN_NS);
|
||||||
|
stuckTicks_ = nsToTicks(DRIVER_RX_STUCK_MIN_NS);
|
||||||
|
testTicks_ = static_cast<uint64_t>(captureHz_) * testTimeMs / 1000ULL;
|
||||||
|
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_ ||
|
||||||
|
!ackStartMaxTicks_ || !faultLongTicks_ || !stuckTicks_ ||
|
||||||
|
!testTicks_ || !subsampleTicks_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
clearCapture();
|
||||||
|
stats_.reset();
|
||||||
|
publishStats();
|
||||||
|
pendingCount_ = 0;
|
||||||
|
response_ = {};
|
||||||
|
measurementStartTick_ = deadlineTick_ = 0;
|
||||||
|
pointOriginTick_ = lastEventTick_ = lastActiveTxTick_ = 0;
|
||||||
|
// Skip two complete periods after the polling task synchronizes with TX.
|
||||||
|
settleCycles_ = DRIVER_CAPTURE_SYNC_CYCLES;
|
||||||
|
Log::printf("DRIVER", "capture=GPIO-%luMHz sync-periods=%u ACK-timeout=%luns",
|
||||||
|
static_cast<unsigned long>(captureHz_ / 1000000UL),
|
||||||
|
static_cast<unsigned>(settleCycles_),
|
||||||
|
static_cast<unsigned long>(DRIVER_ACK_START_MAX_NS));
|
||||||
|
const uint64_t periodUs =
|
||||||
|
(1000000ULL + frequencyHz - 1ULL) / frequencyHz;
|
||||||
|
settlingTimeoutUs_ = periodUs *
|
||||||
|
(static_cast<uint64_t>(DRIVER_CAPTURE_SYNC_CYCLES) + 2ULL) + 1000ULL;
|
||||||
|
settlingDeadlineUs_ = 0;
|
||||||
|
settledCycles_ = 0;
|
||||||
|
completedSubsamples_ = 0;
|
||||||
|
measurementClosed_ = false;
|
||||||
|
havePointOrigin_ = false;
|
||||||
|
haveLastActiveTx_ = false;
|
||||||
|
rxActive_ = (gpio_get_level(static_cast<gpio_num_t>(GPIO_RX)) != 0) ==
|
||||||
|
rxActiveRawHigh_;
|
||||||
|
currentStep_ = 0;
|
||||||
|
traceWrite_ = traceCount_ = 0;
|
||||||
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
|
state_ = DriverState::SETTLING;
|
||||||
|
return armCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DriverTest::armCapture() {
|
||||||
|
// 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)) {
|
||||||
|
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);
|
||||||
|
// If IDLE0 is not watched there is nothing to remove or restore.
|
||||||
|
}
|
||||||
|
__atomic_store_n(&captureReady_, false, __ATOMIC_RELEASE);
|
||||||
|
__atomic_store_n(&captureActive_, true, __ATOMIC_RELEASE);
|
||||||
|
xTaskNotifyGive(pollTask_);
|
||||||
|
const uint32_t readyDeadline = millis() + 25U;
|
||||||
|
while (!__atomic_load_n(&captureReady_, __ATOMIC_ACQUIRE) &&
|
||||||
|
static_cast<int32_t>(millis() - readyDeadline) < 0) delay(0);
|
||||||
|
if (!__atomic_load_n(&captureReady_, __ATOMIC_ACQUIRE)) {
|
||||||
|
requestCaptureStop();
|
||||||
|
waitCaptureStopped(25U);
|
||||||
|
state_ = DriverState::IDLE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
settlingDeadlineUs_ = static_cast<uint64_t>(esp_timer_get_time()) +
|
||||||
|
settlingTimeoutUs_;
|
||||||
|
xTaskNotifyGive(analyzerTask_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DriverTest::resumeSubsample() {
|
||||||
|
if (state_ != DriverState::SUBSAMPLE_DONE) return false;
|
||||||
|
if (!waitCaptureStopped(25U)) {
|
||||||
|
fail(FailReason::DATA_LOSS, lastEventTick_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCapture();
|
||||||
|
pendingCount_ = 0;
|
||||||
|
response_ = {};
|
||||||
|
measurementStartTick_ = deadlineTick_ = 0;
|
||||||
|
lastActiveTxTick_ = 0;
|
||||||
|
settlingDeadlineUs_ = 0;
|
||||||
|
settledCycles_ = 0;
|
||||||
|
measurementClosed_ = false;
|
||||||
|
haveLastActiveTx_ = false;
|
||||||
|
rxActive_ = (gpio_get_level(static_cast<gpio_num_t>(GPIO_RX)) != 0) ==
|
||||||
|
rxActiveRawHigh_;
|
||||||
|
state_ = DriverState::SETTLING;
|
||||||
|
if (armCapture()) return true;
|
||||||
|
fail(FailReason::DATA_LOSS, lastEventTick_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::pollTaskEntry(void *context) {
|
||||||
|
static_cast<DriverTest *>(context)->pollTaskLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR DriverTest::pollTaskLoop() {
|
||||||
|
constexpr uint32_t PIN_MASK = (1UL << GPIO_PWM) | (1UL << GPIO_RX);
|
||||||
|
for (;;) {
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
uint32_t levels = GPIO.in & PIN_MASK;
|
||||||
|
uint32_t nextStart = 0;
|
||||||
|
uint32_t windowEnd = 0;
|
||||||
|
uint32_t lastTxStart = 0;
|
||||||
|
RawEvent hotEvents[32] = {};
|
||||||
|
uint8_t hotCount = 0;
|
||||||
|
bool sawTxStart = false;
|
||||||
|
bool critical = false;
|
||||||
|
bool allInterruptsMasked = false;
|
||||||
|
uint32_t interruptState = 0;
|
||||||
|
|
||||||
|
auto sampleOnce = [&]() {
|
||||||
|
const uint32_t current = GPIO.in & PIN_MASK;
|
||||||
|
if (current == levels) return;
|
||||||
|
const uint32_t now = esp_cpu_get_cycle_count();
|
||||||
|
const uint32_t changed = current ^ levels;
|
||||||
|
if ((changed & (1UL << GPIO_PWM)) && hotCount < 32U)
|
||||||
|
hotEvents[hotCount++] = {now,
|
||||||
|
(current & (1UL << GPIO_PWM)) != 0U, Source::TX};
|
||||||
|
if ((changed & (1UL << GPIO_RX)) && hotCount < 32U)
|
||||||
|
hotEvents[hotCount++] = {now,
|
||||||
|
(current & (1UL << GPIO_RX)) != 0U, Source::RX};
|
||||||
|
if ((changed & (1UL << GPIO_PWM)) &&
|
||||||
|
((current & (1UL << GPIO_PWM)) != 0U) == pollTxStartRawHigh_) {
|
||||||
|
lastTxStart = now;
|
||||||
|
sawTxStart = true;
|
||||||
|
}
|
||||||
|
levels = current;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto flushHot = [&]() {
|
||||||
|
for (uint8_t i = 0; i < hotCount; ++i)
|
||||||
|
recordRaw(hotEvents[i].tick, hotEvents[i].rising,
|
||||||
|
hotEvents[i].source);
|
||||||
|
hotCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&pollMux_);
|
||||||
|
critical = true;
|
||||||
|
__atomic_store_n(&captureReady_, true, __ATOMIC_RELEASE);
|
||||||
|
while (__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE) && !sawTxStart)
|
||||||
|
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
||||||
|
if (sawTxStart) windowEnd = lastTxStart + pollWindowAfterCycles_;
|
||||||
|
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) &&
|
||||||
|
static_cast<int32_t>(esp_cpu_get_cycle_count() - windowEnd) < 0)
|
||||||
|
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
||||||
|
|
||||||
|
restoreInterrupts(interruptState);
|
||||||
|
allInterruptsMasked = false;
|
||||||
|
portEXIT_CRITICAL(&pollMux_);
|
||||||
|
critical = false;
|
||||||
|
flushHot();
|
||||||
|
// This marker is written only after every TX/RX edge from the completed
|
||||||
|
// sampling window. The analyzer may now safely decide that an ACK was
|
||||||
|
// absent without racing the producer that writes those edges.
|
||||||
|
recordRaw(esp_cpu_get_cycle_count(), false, Source::WINDOW_END);
|
||||||
|
if (!__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE)) break;
|
||||||
|
nextStart = lastTxStart + pollPeriodCycles_;
|
||||||
|
sawTxStart = false;
|
||||||
|
|
||||||
|
uint32_t outsideSpins = 0;
|
||||||
|
while (__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE) &&
|
||||||
|
static_cast<int32_t>(esp_cpu_get_cycle_count() -
|
||||||
|
(nextStart - pollWindowBeforeCycles_)) < 0) {
|
||||||
|
for (uint8_t i = 0; i < 16U; ++i) sampleOnce();
|
||||||
|
if (++outsideSpins >= 256U) {
|
||||||
|
outsideSpins = 0;
|
||||||
|
taskYIELD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!__atomic_load_n(&captureActive_, __ATOMIC_ACQUIRE)) break;
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&pollMux_);
|
||||||
|
critical = true;
|
||||||
|
interruptState = maskAllInterrupts();
|
||||||
|
allInterruptsMasked = true;
|
||||||
|
windowEnd = nextStart + pollWindowAfterCycles_;
|
||||||
|
}
|
||||||
|
if (allInterruptsMasked) restoreInterrupts(interruptState);
|
||||||
|
if (critical) portEXIT_CRITICAL(&pollMux_);
|
||||||
|
flushHot();
|
||||||
|
if (__atomic_exchange_n(&core0WdtDisabled_, false,
|
||||||
|
__ATOMIC_ACQ_REL)) enableCore0WDT();
|
||||||
|
__atomic_store_n(&captureReady_, false, __ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::analyzerTaskEntry(void *context) {
|
||||||
|
static_cast<DriverTest *>(context)->analyzerTaskLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::analyzerTaskLoop() {
|
||||||
|
TimedEvent events[64] = {};
|
||||||
|
for (;;) {
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
while (state_ == DriverState::SETTLING || state_ == DriverState::RUNNING) {
|
||||||
|
const size_t count = readRaw(events, 64, pdMS_TO_TICKS(1));
|
||||||
|
for (size_t i = 0; i < count &&
|
||||||
|
(state_ == DriverState::SETTLING || state_ == DriverState::RUNNING);
|
||||||
|
++i) processEvent(events[i]);
|
||||||
|
const uint32_t dropped = takeDropped();
|
||||||
|
if (dropped) {
|
||||||
|
stats_.droppedItems += dropped;
|
||||||
|
fail(FailReason::DATA_LOSS, lastEventTick_);
|
||||||
|
}
|
||||||
|
if (!count && state_ == DriverState::SETTLING &&
|
||||||
|
static_cast<uint64_t>(esp_timer_get_time()) >=
|
||||||
|
settlingDeadlineUs_) {
|
||||||
|
fail(FailReason::ACK_MISSING, lastEventTick_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::processEvent(const TimedEvent &event) {
|
||||||
|
lastEventTick_ = event.tick;
|
||||||
|
if (event.source == Source::WINDOW_END) {
|
||||||
|
if (state_ == DriverState::RUNNING) {
|
||||||
|
expirePending(event.tick);
|
||||||
|
if (state_ == DriverState::RUNNING) completeIfPossible(event.tick);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!havePointOrigin_) {
|
||||||
|
pointOriginTick_ = event.tick;
|
||||||
|
havePointOrigin_ = true;
|
||||||
|
}
|
||||||
|
rememberTrace(event);
|
||||||
|
if (state_ == DriverState::SETTLING) processSettling(event);
|
||||||
|
else if (state_ == DriverState::RUNNING) processRunning(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::processSettling(const TimedEvent &event) {
|
||||||
|
if (event.source == Source::RX) {
|
||||||
|
rxActive_ = event.rising == rxActiveRawHigh_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uint8_t rawLevel = event.rising ? HIGH : LOW;
|
||||||
|
const bool lightOn = rawLevel == TX_LIGHT_ON_GPIO_LEVEL;
|
||||||
|
if (lightOn != txPulseLightOn_) return;
|
||||||
|
if (settledCycles_ < settleCycles_) {
|
||||||
|
++settledCycles_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rxActive_) {
|
||||||
|
fail(FailReason::DRIVER_FAULT, event.tick);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state_ = DriverState::RUNNING;
|
||||||
|
measurementStartTick_ = event.tick;
|
||||||
|
const uint64_t measuredBefore =
|
||||||
|
static_cast<uint64_t>(completedSubsamples_) * subsampleTicks_;
|
||||||
|
const uint64_t thisSubsampleTicks =
|
||||||
|
completedSubsamples_ + 1U == subsampleCount_ ?
|
||||||
|
testTicks_ - measuredBefore : subsampleTicks_;
|
||||||
|
deadlineTick_ = event.tick + thisSubsampleTicks;
|
||||||
|
processTx(event, lightOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::processRunning(const TimedEvent &event) {
|
||||||
|
if (response_.active && event.tick - response_.startTick >= stuckTicks_) {
|
||||||
|
const uint64_t delay = response_.associated ?
|
||||||
|
response_.startTick - response_.tx.tick : 0;
|
||||||
|
const uint64_t trigger = haveLastActiveTx_ &&
|
||||||
|
response_.startTick >= lastActiveTxTick_ ?
|
||||||
|
response_.startTick - lastActiveTxTick_ : delay;
|
||||||
|
fail(FailReason::DRIVER_FAULT, event.tick, delay,
|
||||||
|
event.tick - response_.startTick, trigger);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.source == Source::TX) {
|
||||||
|
expirePending(event.tick);
|
||||||
|
if (state_ != DriverState::RUNNING) return;
|
||||||
|
const uint8_t rawLevel = event.rising ? HIGH : LOW;
|
||||||
|
const bool lightOn = rawLevel == TX_LIGHT_ON_GPIO_LEVEL;
|
||||||
|
if (event.tick < deadlineTick_) processTx(event, lightOn);
|
||||||
|
else measurementClosed_ = true;
|
||||||
|
} else {
|
||||||
|
// A delayed fault indication can start after the normal ACK deadline.
|
||||||
|
// Measure the RX pulse before expiring its possible causal TX edge.
|
||||||
|
processRx(event, event.rising == rxActiveRawHigh_);
|
||||||
|
if (state_ != DriverState::RUNNING) return;
|
||||||
|
if (!response_.active) expirePending(event.tick);
|
||||||
|
}
|
||||||
|
if (state_ != DriverState::RUNNING) return;
|
||||||
|
completeIfPossible(event.tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DriverTest::addPending(uint64_t tick, bool lightOn) {
|
||||||
|
if (pendingCount_ >= MAX_PENDING) {
|
||||||
|
fail(FailReason::DATA_LOSS, tick);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pending_[pendingCount_++] = {tick, lightOn};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::processTx(const TimedEvent &event, bool lightOn) {
|
||||||
|
if (!addPending(event.tick, lightOn)) return;
|
||||||
|
if (lightOn == txPulseLightOn_) {
|
||||||
|
lastActiveTxTick_ = event.tick;
|
||||||
|
haveLastActiveTx_ = true;
|
||||||
|
}
|
||||||
|
++stats_.inputEdges;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t DriverTest::matchingPending(uint64_t rxTick) const {
|
||||||
|
for (uint8_t i = 0; i < pendingCount_; ++i)
|
||||||
|
if (rxTick >= pending_[i].tick &&
|
||||||
|
rxTick - pending_[i].tick <= ackStartMaxTicks_)
|
||||||
|
return static_cast<int8_t>(i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::removePending(uint8_t index) {
|
||||||
|
if (index >= pendingCount_) return;
|
||||||
|
for (uint8_t i = index + 1U; i < pendingCount_; ++i)
|
||||||
|
pending_[i - 1U] = pending_[i];
|
||||||
|
--pendingCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::processRx(const TimedEvent &event, bool activeNow) {
|
||||||
|
rxActive_ = activeNow;
|
||||||
|
if (activeNow) {
|
||||||
|
if (response_.active) {
|
||||||
|
fail(FailReason::DATA_LOSS, event.tick);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response_ = {};
|
||||||
|
response_.active = true;
|
||||||
|
response_.startTick = event.tick;
|
||||||
|
const int8_t index = matchingPending(event.tick);
|
||||||
|
if (index >= 0) {
|
||||||
|
response_.associated = true;
|
||||||
|
response_.tx = pending_[index];
|
||||||
|
removePending(static_cast<uint8_t>(index));
|
||||||
|
} else ++stats_.unexpectedResponses;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response_.active) return;
|
||||||
|
const uint64_t width = event.tick - response_.startTick;
|
||||||
|
if (!response_.associated) {
|
||||||
|
const uint64_t trigger = haveLastActiveTx_ &&
|
||||||
|
response_.startTick >= lastActiveTxTick_ ?
|
||||||
|
response_.startTick - lastActiveTxTick_ : 0;
|
||||||
|
response_ = {};
|
||||||
|
fail(FailReason::DRIVER_FAULT, event.tick, trigger, width, trigger);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t guard = mergeGuardTicks();
|
||||||
|
for (uint8_t i = 0; i < pendingCount_; ++i) {
|
||||||
|
if (pending_[i].tick > response_.startTick &&
|
||||||
|
event.tick - pending_[i].tick >= guard) {
|
||||||
|
const uint64_t delay = response_.startTick - response_.tx.tick;
|
||||||
|
const uint64_t trigger = event.tick - pending_[i].tick;
|
||||||
|
response_ = {};
|
||||||
|
fail(FailReason::ACK_MERGED, event.tick, delay, width, trigger);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (width >= faultLongTicks_) {
|
||||||
|
const uint64_t delay = response_.startTick - response_.tx.tick;
|
||||||
|
const uint64_t trigger = haveLastActiveTx_ &&
|
||||||
|
response_.startTick >= lastActiveTxTick_ ?
|
||||||
|
response_.startTick - lastActiveTxTick_ : delay;
|
||||||
|
response_ = {};
|
||||||
|
fail(FailReason::DRIVER_FAULT, event.tick, delay, width, trigger);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t delay = response_.startTick - response_.tx.tick;
|
||||||
|
const bool lightOn = response_.tx.lightOn;
|
||||||
|
response_ = {};
|
||||||
|
acceptAcknowledgement(delay, width, lightOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t DriverTest::mergeGuardTicks() const {
|
||||||
|
uint32_t observedMax = stats_.maxDelayTicks;
|
||||||
|
const uint64_t baseline = observedMax ? observedMax :
|
||||||
|
nsToTicks(DRIVER_ACK_DELAY_NS + 500U);
|
||||||
|
return baseline + nsToTicks(DRIVER_ACK_MERGE_MARGIN_NS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::acceptAcknowledgement(uint64_t delay, uint64_t width,
|
||||||
|
bool lightOn) {
|
||||||
|
const uint32_t delay32 = delay > UINT32_MAX ? UINT32_MAX :
|
||||||
|
static_cast<uint32_t>(delay);
|
||||||
|
const uint32_t width32 = width > UINT32_MAX ? UINT32_MAX :
|
||||||
|
static_cast<uint32_t>(width);
|
||||||
|
stats_.lastDelayTicks = delay32;
|
||||||
|
stats_.lastResponseTicks = width32;
|
||||||
|
++stats_.responses;
|
||||||
|
if (delay32 < stats_.minDelayTicks) stats_.minDelayTicks = delay32;
|
||||||
|
if (delay32 > stats_.maxDelayTicks) stats_.maxDelayTicks = delay32;
|
||||||
|
if (width32 < stats_.minResponseTicks) stats_.minResponseTicks = width32;
|
||||||
|
if (width32 > stats_.maxResponseTicks) stats_.maxResponseTicks = width32;
|
||||||
|
|
||||||
|
DriverEdgeStats &edge = lightOn ? stats_.turnOn : stats_.turnOff;
|
||||||
|
++edge.responses;
|
||||||
|
edge.delaySumTicks += delay32;
|
||||||
|
edge.responseSumTicks += width32;
|
||||||
|
if (delay32 < edge.minDelayTicks) edge.minDelayTicks = delay32;
|
||||||
|
if (delay32 > edge.maxDelayTicks) edge.maxDelayTicks = delay32;
|
||||||
|
if (width32 < edge.minResponseTicks) edge.minResponseTicks = width32;
|
||||||
|
if (width32 > edge.maxResponseTicks) edge.maxResponseTicks = width32;
|
||||||
|
publishStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::expirePending(uint64_t now) {
|
||||||
|
for (uint8_t i = 0; i < pendingCount_; ++i) {
|
||||||
|
if (now < pending_[i].tick + ackStartMaxTicks_) continue;
|
||||||
|
// The failure belongs to the ACK deadline itself. A later TX edge or the
|
||||||
|
// end-of-window marker is only the safe moment when absence is confirmed.
|
||||||
|
fail(FailReason::ACK_MISSING,
|
||||||
|
pending_[i].tick + ackStartMaxTicks_, ackStartMaxTicks_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::completeIfPossible(uint64_t now) {
|
||||||
|
if (state_ != DriverState::RUNNING) return;
|
||||||
|
if (!measurementClosed_ && now >= deadlineTick_) measurementClosed_ = true;
|
||||||
|
if (!measurementClosed_ || response_.active || pendingCount_) return;
|
||||||
|
if (!stats_.turnOn.responses || !stats_.turnOff.responses) {
|
||||||
|
fail(FailReason::ACK_MISSING, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++completedSubsamples_;
|
||||||
|
currentStep_ = completedSubsamples_;
|
||||||
|
publishStats();
|
||||||
|
requestCaptureStop();
|
||||||
|
if (!waitCaptureStopped(25U)) {
|
||||||
|
fail(FailReason::DATA_LOSS, lastEventTick_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (completedSubsamples_ >= subsampleCount_) {
|
||||||
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
|
state_ = DriverState::PASS;
|
||||||
|
} else {
|
||||||
|
__atomic_store_n(&progressUpdatePending_, true, __ATOMIC_RELEASE);
|
||||||
|
state_ = DriverState::SUBSAMPLE_DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::fail(FailReason reason, uint64_t tick, uint64_t delay,
|
||||||
|
uint64_t pulseWidth, uint64_t triggerAfterTx) {
|
||||||
|
if (state_ == DriverState::FAIL || state_ == DriverState::PASS) return;
|
||||||
|
if (stats_.reason == FailReason::NONE) {
|
||||||
|
stats_.reason = reason;
|
||||||
|
if (tick && havePointOrigin_ && tick >= pointOriginTick_)
|
||||||
|
stats_.errorElapsedTicks = tick - pointOriginTick_;
|
||||||
|
const uint64_t trigger = triggerAfterTx ? triggerAfterTx : delay;
|
||||||
|
if (trigger) {
|
||||||
|
stats_.errorTriggerTicks = trigger > UINT32_MAX ? UINT32_MAX :
|
||||||
|
static_cast<uint32_t>(trigger);
|
||||||
|
stats_.errorTriggerValid = true;
|
||||||
|
}
|
||||||
|
if (delay) {
|
||||||
|
stats_.errorDelayTicks = delay > UINT32_MAX ? UINT32_MAX :
|
||||||
|
static_cast<uint32_t>(delay);
|
||||||
|
stats_.errorDelayValid = true;
|
||||||
|
}
|
||||||
|
if (pulseWidth) {
|
||||||
|
stats_.errorPulseTicks = pulseWidth > UINT32_MAX ? UINT32_MAX :
|
||||||
|
static_cast<uint32_t>(pulseWidth);
|
||||||
|
stats_.errorPulseValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publishStats();
|
||||||
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
|
requestCaptureStop();
|
||||||
|
state_ = DriverState::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::publishStats() {
|
||||||
|
portENTER_CRITICAL(&statsMux_);
|
||||||
|
publishedStats_ = stats_;
|
||||||
|
portEXIT_CRITICAL(&statsMux_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::forceFail(FailReason reason) {
|
||||||
|
if (state_ == DriverState::SETTLING || state_ == DriverState::RUNNING ||
|
||||||
|
state_ == DriverState::SUBSAMPLE_DONE)
|
||||||
|
fail(reason, lastEventTick_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::abort() {
|
||||||
|
if (state_ == DriverState::SETTLING || state_ == DriverState::RUNNING ||
|
||||||
|
state_ == DriverState::SUBSAMPLE_DONE)
|
||||||
|
fail(FailReason::ABORTED, lastEventTick_);
|
||||||
|
else {
|
||||||
|
requestCaptureStop();
|
||||||
|
state_ = DriverState::IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DriverTest::takeProgressUpdate() {
|
||||||
|
return __atomic_exchange_n(&progressUpdatePending_, false,
|
||||||
|
__ATOMIC_ACQ_REL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::requestCaptureStop() {
|
||||||
|
__atomic_store_n(&captureActive_, false, __ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DriverTest::waitCaptureStopped(uint32_t timeoutMs) {
|
||||||
|
const uint32_t deadline = millis() + timeoutMs;
|
||||||
|
while (__atomic_load_n(&captureReady_, __ATOMIC_ACQUIRE) &&
|
||||||
|
static_cast<int32_t>(millis() - deadline) < 0) delay(0);
|
||||||
|
if (__atomic_load_n(&captureReady_, __ATOMIC_ACQUIRE)) return false;
|
||||||
|
if (__atomic_exchange_n(&core0WdtDisabled_, false,
|
||||||
|
__ATOMIC_ACQ_REL)) enableCore0WDT();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::clearCapture() {
|
||||||
|
const uint16_t write = __atomic_load_n(&ringWrite_, __ATOMIC_ACQUIRE);
|
||||||
|
__atomic_store_n(&ringRead_, write, __ATOMIC_RELEASE);
|
||||||
|
__atomic_store_n(&droppedItems_, 0U, __ATOMIC_RELEASE);
|
||||||
|
haveRawTick_ = false;
|
||||||
|
lastRawTick_ = 0;
|
||||||
|
tickEpoch_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR DriverTest::recordRaw(uint32_t tick, bool rising,
|
||||||
|
Source source) {
|
||||||
|
const uint16_t write = ringWrite_;
|
||||||
|
const uint16_t next = static_cast<uint16_t>(
|
||||||
|
(write + 1U) & (RING_CAPACITY - 1U));
|
||||||
|
if (next == ringRead_) {
|
||||||
|
++droppedItems_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ring_[write] = {tick, rising, source};
|
||||||
|
asm volatile("memw" ::: "memory");
|
||||||
|
ringWrite_ = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DriverTest::readRaw(TimedEvent *events, size_t capacity,
|
||||||
|
TickType_t waitTicks) {
|
||||||
|
if (!events || !capacity) return 0;
|
||||||
|
uint16_t read = __atomic_load_n(&ringRead_, __ATOMIC_RELAXED);
|
||||||
|
if (read == __atomic_load_n(&ringWrite_, __ATOMIC_ACQUIRE) && waitTicks) {
|
||||||
|
vTaskDelay(waitTicks);
|
||||||
|
read = __atomic_load_n(&ringRead_, __ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
const uint16_t write = __atomic_load_n(&ringWrite_, __ATOMIC_ACQUIRE);
|
||||||
|
size_t count = 0;
|
||||||
|
while (read != write && count < capacity) {
|
||||||
|
const RawEvent raw = ring_[read];
|
||||||
|
read = static_cast<uint16_t>((read + 1U) & (RING_CAPACITY - 1U));
|
||||||
|
if (haveRawTick_ && raw.tick < lastRawTick_ &&
|
||||||
|
lastRawTick_ - raw.tick > 0x80000000UL) tickEpoch_ += 1ULL << 32U;
|
||||||
|
lastRawTick_ = raw.tick;
|
||||||
|
haveRawTick_ = true;
|
||||||
|
events[count++] = {tickEpoch_ + raw.tick, raw.rising, raw.source};
|
||||||
|
}
|
||||||
|
__atomic_store_n(&ringRead_, read, __ATOMIC_RELEASE);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DriverTest::takeDropped() {
|
||||||
|
return __atomic_exchange_n(&droppedItems_, 0U, __ATOMIC_ACQ_REL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::rememberTrace(const TimedEvent &event) {
|
||||||
|
trace_[traceWrite_] = {event.tick, static_cast<uint8_t>(event.source),
|
||||||
|
static_cast<uint8_t>(event.rising), static_cast<uint8_t>(state_),
|
||||||
|
pendingCount_};
|
||||||
|
traceWrite_ = static_cast<uint8_t>((traceWrite_ + 1U) % TRACE_CAPACITY);
|
||||||
|
if (traceCount_ < TRACE_CAPACITY) ++traceCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::printSummary() const {
|
||||||
|
auto printEdge = [&](const char *name, const DriverEdgeStats &edge) {
|
||||||
|
if (!edge.responses) {
|
||||||
|
Log::printf("DRIVER", "%s ACK=0", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log::printf("DRIVER",
|
||||||
|
"%s ACK=%lu D=%lluns/%lluns/%lluns P=%lluns/%lluns/%lluns",
|
||||||
|
name, static_cast<unsigned long>(edge.responses),
|
||||||
|
static_cast<unsigned long long>(ticksToNs(edge.minDelayTicks)),
|
||||||
|
static_cast<unsigned long long>(ticksToNs(
|
||||||
|
edge.delaySumTicks / edge.responses)),
|
||||||
|
static_cast<unsigned long long>(ticksToNs(edge.maxDelayTicks)),
|
||||||
|
static_cast<unsigned long long>(ticksToNs(edge.minResponseTicks)),
|
||||||
|
static_cast<unsigned long long>(ticksToNs(
|
||||||
|
edge.responseSumTicks / edge.responses)),
|
||||||
|
static_cast<unsigned long long>(ticksToNs(edge.maxResponseTicks)));
|
||||||
|
};
|
||||||
|
Log::printf("DRIVER", "TX edges=%lu responses=%lu dropped=%lu unexpected=%lu result=%s",
|
||||||
|
static_cast<unsigned long>(publishedStats_.inputEdges),
|
||||||
|
static_cast<unsigned long>(publishedStats_.responses),
|
||||||
|
static_cast<unsigned long>(publishedStats_.droppedItems),
|
||||||
|
static_cast<unsigned long>(publishedStats_.unexpectedResponses),
|
||||||
|
failName(publishedStats_.reason));
|
||||||
|
if (publishedStats_.reason != FailReason::NONE) {
|
||||||
|
auto formatOptional = [&](bool valid, uint32_t ticks,
|
||||||
|
char *out, size_t size) {
|
||||||
|
if (!valid) snprintf(out, size, "---");
|
||||||
|
else snprintf(out, size, "%lluns",
|
||||||
|
static_cast<unsigned long long>(ticksToNs(ticks)));
|
||||||
|
};
|
||||||
|
char trigger[24], pulse[24];
|
||||||
|
formatOptional(publishedStats_.errorTriggerValid,
|
||||||
|
publishedStats_.errorTriggerTicks, trigger, sizeof(trigger));
|
||||||
|
formatOptional(publishedStats_.errorPulseValid,
|
||||||
|
publishedStats_.errorPulseTicks, pulse, sizeof(pulse));
|
||||||
|
if (publishedStats_.errorPulseValid)
|
||||||
|
Log::printf("DRIVER", "error timing: T=%s P=%s", trigger, pulse);
|
||||||
|
else Log::printf("DRIVER", "error timing: T=%s", trigger);
|
||||||
|
}
|
||||||
|
printEdge("ON", publishedStats_.turnOn);
|
||||||
|
printEdge("OFF", publishedStats_.turnOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DriverTest::printTrace() const {
|
||||||
|
if (!traceCount_) return;
|
||||||
|
const uint8_t first = static_cast<uint8_t>(
|
||||||
|
(traceWrite_ + TRACE_CAPACITY - traceCount_) % TRACE_CAPACITY);
|
||||||
|
const uint64_t origin = trace_[first].tick;
|
||||||
|
Log::printf("DRIVER", "RAM trace: %u events, tick=%luHz", traceCount_,
|
||||||
|
static_cast<unsigned long>(captureHz_));
|
||||||
|
for (uint8_t i = 0; i < traceCount_; ++i) {
|
||||||
|
const TraceEvent &event = trace_[(first + i) % TRACE_CAPACITY];
|
||||||
|
Log::printf("DRIVER", "E%02u +%lluns %s/%s state=%u pending=%u", i,
|
||||||
|
static_cast<unsigned long long>(ticksToNs(event.tick - origin)),
|
||||||
|
event.source == static_cast<uint8_t>(Source::TX) ? "TX" : "RX",
|
||||||
|
event.rising ? "rise" : "fall", event.state, event.pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
180
OpticalChannelTester/DriverTest.h
Normal file
180
OpticalChannelTester/DriverTest.h
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "Receiver.h"
|
||||||
|
|
||||||
|
enum class DriverState : uint8_t {
|
||||||
|
IDLE, SETTLING, RUNNING, SUBSAMPLE_DONE, PASS, FAIL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DriverEdgeStats {
|
||||||
|
uint32_t responses;
|
||||||
|
uint32_t minDelayTicks;
|
||||||
|
uint32_t maxDelayTicks;
|
||||||
|
uint64_t delaySumTicks;
|
||||||
|
uint32_t minResponseTicks;
|
||||||
|
uint32_t maxResponseTicks;
|
||||||
|
uint64_t responseSumTicks;
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DriverStats {
|
||||||
|
uint32_t inputEdges;
|
||||||
|
uint32_t responses;
|
||||||
|
uint32_t minDelayTicks;
|
||||||
|
uint32_t maxDelayTicks;
|
||||||
|
uint32_t minResponseTicks;
|
||||||
|
uint32_t maxResponseTicks;
|
||||||
|
uint32_t lastDelayTicks;
|
||||||
|
uint32_t lastResponseTicks;
|
||||||
|
uint32_t droppedItems;
|
||||||
|
uint32_t unexpectedResponses;
|
||||||
|
uint64_t errorElapsedTicks;
|
||||||
|
uint32_t errorTriggerTicks;
|
||||||
|
uint32_t errorDelayTicks;
|
||||||
|
uint32_t errorPulseTicks;
|
||||||
|
bool errorTriggerValid;
|
||||||
|
bool errorDelayValid;
|
||||||
|
bool errorPulseValid;
|
||||||
|
DriverEdgeStats turnOn;
|
||||||
|
DriverEdgeStats turnOff;
|
||||||
|
FailReason reason;
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class DriverTest {
|
||||||
|
public:
|
||||||
|
explicit DriverTest(PulseReceiver &receiver) : receiver_(receiver) {}
|
||||||
|
bool start(uint32_t frequencyHz, uint32_t pulseNs, float tolerancePct,
|
||||||
|
uint32_t testTimeMs, uint8_t settleCycles,
|
||||||
|
bool activeTxLightOn, bool activeRxLightOn);
|
||||||
|
DriverState update() const { return state_; }
|
||||||
|
void abort();
|
||||||
|
void forceFail(FailReason reason);
|
||||||
|
bool resumeSubsample();
|
||||||
|
bool takeProgressUpdate();
|
||||||
|
void printSummary() const;
|
||||||
|
void printTrace() const;
|
||||||
|
uint8_t progressStep() const { return currentStep_; }
|
||||||
|
uint8_t progressSteps() const { return subsampleCount_; }
|
||||||
|
uint32_t tickHz() const { return captureHz_; }
|
||||||
|
const DriverStats &stats() const { return publishedStats_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Source : uint8_t { TX, RX, WINDOW_END };
|
||||||
|
struct RawEvent { uint32_t tick; bool rising; Source source; };
|
||||||
|
struct TimedEvent { uint64_t tick; bool rising; Source source; };
|
||||||
|
struct PendingTx {
|
||||||
|
uint64_t tick;
|
||||||
|
bool lightOn;
|
||||||
|
};
|
||||||
|
struct Response {
|
||||||
|
bool active;
|
||||||
|
bool associated;
|
||||||
|
uint64_t startTick;
|
||||||
|
PendingTx tx;
|
||||||
|
};
|
||||||
|
struct TraceEvent {
|
||||||
|
uint64_t tick;
|
||||||
|
uint8_t source;
|
||||||
|
uint8_t rising;
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t pending;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void analyzerTaskEntry(void *context);
|
||||||
|
static void pollTaskEntry(void *context);
|
||||||
|
void analyzerTaskLoop();
|
||||||
|
void IRAM_ATTR pollTaskLoop();
|
||||||
|
void processEvent(const TimedEvent &event);
|
||||||
|
void processSettling(const TimedEvent &event);
|
||||||
|
void processRunning(const TimedEvent &event);
|
||||||
|
void processTx(const TimedEvent &event, bool lightOn);
|
||||||
|
void processRx(const TimedEvent &event, bool activeNow);
|
||||||
|
void expirePending(uint64_t now);
|
||||||
|
void completeIfPossible(uint64_t now);
|
||||||
|
bool addPending(uint64_t tick, bool lightOn);
|
||||||
|
int8_t matchingPending(uint64_t rxTick) const;
|
||||||
|
void removePending(uint8_t index);
|
||||||
|
uint64_t mergeGuardTicks() const;
|
||||||
|
void acceptAcknowledgement(uint64_t delay, uint64_t width, bool lightOn);
|
||||||
|
void fail(FailReason reason, uint64_t tick = 0, uint64_t delay = 0,
|
||||||
|
uint64_t pulseWidth = 0, uint64_t triggerAfterTx = 0);
|
||||||
|
void publishStats();
|
||||||
|
void rememberTrace(const TimedEvent &event);
|
||||||
|
bool armCapture();
|
||||||
|
void requestCaptureStop();
|
||||||
|
bool waitCaptureStopped(uint32_t timeoutMs);
|
||||||
|
void clearCapture();
|
||||||
|
void recordRaw(uint32_t tick, bool rising, Source source);
|
||||||
|
size_t readRaw(TimedEvent *events, size_t capacity, TickType_t waitTicks);
|
||||||
|
uint32_t takeDropped();
|
||||||
|
uint64_t nsToTicks(uint32_t ns) const;
|
||||||
|
uint64_t ticksToNs(uint64_t ticks) const;
|
||||||
|
|
||||||
|
static constexpr uint8_t MAX_PENDING = 8;
|
||||||
|
static constexpr uint16_t RING_CAPACITY = 2048;
|
||||||
|
static constexpr uint8_t TRACE_CAPACITY = 32;
|
||||||
|
static_assert((RING_CAPACITY & (RING_CAPACITY - 1U)) == 0,
|
||||||
|
"driver ring capacity must be a power of two");
|
||||||
|
|
||||||
|
PulseReceiver &receiver_;
|
||||||
|
TaskHandle_t analyzerTask_ = nullptr;
|
||||||
|
TaskHandle_t pollTask_ = nullptr;
|
||||||
|
volatile DriverState state_ = DriverState::IDLE;
|
||||||
|
DriverStats stats_ = {};
|
||||||
|
DriverStats publishedStats_ = {};
|
||||||
|
mutable portMUX_TYPE statsMux_ = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
|
RawEvent ring_[RING_CAPACITY] = {};
|
||||||
|
volatile uint16_t ringWrite_ = 0;
|
||||||
|
volatile uint16_t ringRead_ = 0;
|
||||||
|
volatile uint32_t droppedItems_ = 0;
|
||||||
|
volatile bool captureActive_ = false;
|
||||||
|
volatile bool captureReady_ = false;
|
||||||
|
volatile bool core0WdtDisabled_ = false;
|
||||||
|
uint32_t captureHz_ = 0;
|
||||||
|
uint32_t captureFrequencyHz_ = 0;
|
||||||
|
uint32_t capturePulseNs_ = 0;
|
||||||
|
uint32_t pollPeriodCycles_ = 0;
|
||||||
|
uint32_t pollWindowBeforeCycles_ = 0;
|
||||||
|
uint32_t pollWindowAfterCycles_ = 0;
|
||||||
|
bool pollTxStartRawHigh_ = false;
|
||||||
|
bool captureTxLightOn_ = true;
|
||||||
|
portMUX_TYPE pollMux_ = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
|
PendingTx pending_[MAX_PENDING] = {};
|
||||||
|
uint8_t pendingCount_ = 0;
|
||||||
|
Response response_ = {};
|
||||||
|
uint64_t ackStartMaxTicks_ = 0;
|
||||||
|
uint64_t faultLongTicks_ = 0;
|
||||||
|
uint64_t stuckTicks_ = 0;
|
||||||
|
uint64_t testTicks_ = 0;
|
||||||
|
uint64_t subsampleTicks_ = 0;
|
||||||
|
uint64_t settlingTimeoutUs_ = 0;
|
||||||
|
uint64_t settlingDeadlineUs_ = 0;
|
||||||
|
uint64_t measurementStartTick_ = 0;
|
||||||
|
uint64_t deadlineTick_ = 0;
|
||||||
|
uint64_t pointOriginTick_ = 0;
|
||||||
|
uint64_t lastEventTick_ = 0;
|
||||||
|
uint64_t lastActiveTxTick_ = 0;
|
||||||
|
uint8_t settleCycles_ = 0;
|
||||||
|
uint8_t settledCycles_ = 0;
|
||||||
|
uint8_t subsampleCount_ = DRIVER_SHORT_SAMPLE_PROGRESS_STEPS;
|
||||||
|
uint8_t completedSubsamples_ = 0;
|
||||||
|
bool rxActiveRawHigh_ = true;
|
||||||
|
bool txPulseLightOn_ = true;
|
||||||
|
bool rxActive_ = false;
|
||||||
|
bool measurementClosed_ = false;
|
||||||
|
bool havePointOrigin_ = false;
|
||||||
|
bool haveLastActiveTx_ = false;
|
||||||
|
bool haveRawTick_ = false;
|
||||||
|
uint32_t lastRawTick_ = 0;
|
||||||
|
uint64_t tickEpoch_ = 0;
|
||||||
|
volatile uint8_t currentStep_ = 0;
|
||||||
|
volatile bool progressUpdatePending_ = false;
|
||||||
|
TraceEvent trace_[TRACE_CAPACITY] = {};
|
||||||
|
uint8_t traceWrite_ = 0;
|
||||||
|
uint8_t traceCount_ = 0;
|
||||||
|
};
|
||||||
57
OpticalChannelTester/Font_Cyrillic.h
Normal file
57
OpticalChannelTester/Font_Cyrillic.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// Compact 5x7 uppercase Cyrillic font. Lowercase UTF-8 letters are deliberately
|
||||||
|
// rendered with the same uppercase glyphs: at 5x7 pixels this is considerably
|
||||||
|
// clearer than trying to preserve lowercase shapes.
|
||||||
|
namespace CyrillicFont {
|
||||||
|
|
||||||
|
constexpr uint8_t WIDTH = 5;
|
||||||
|
constexpr uint8_t HEIGHT = 7;
|
||||||
|
constexpr uint8_t ADVANCE = 6;
|
||||||
|
|
||||||
|
// Rows are stored top-to-bottom; the low five bits are pixels left-to-right.
|
||||||
|
const uint8_t GLYPHS[][HEIGHT] PROGMEM = {
|
||||||
|
{0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, // А
|
||||||
|
{0x1F, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x1E}, // Б
|
||||||
|
{0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E}, // В
|
||||||
|
{0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, // Г
|
||||||
|
{0x0E, 0x0A, 0x0A, 0x0A, 0x11, 0x1F, 0x11}, // Д
|
||||||
|
{0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F}, // Е
|
||||||
|
{0x15, 0x15, 0x0E, 0x04, 0x0E, 0x15, 0x15}, // Ж
|
||||||
|
{0x0E, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0E}, // З
|
||||||
|
{0x11, 0x13, 0x15, 0x15, 0x19, 0x11, 0x11}, // И
|
||||||
|
{0x0A, 0x11, 0x13, 0x15, 0x19, 0x11, 0x11}, // Й
|
||||||
|
{0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11}, // К
|
||||||
|
{0x07, 0x09, 0x09, 0x09, 0x11, 0x11, 0x11}, // Л
|
||||||
|
{0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11}, // М
|
||||||
|
{0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, // Н
|
||||||
|
{0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, // О
|
||||||
|
{0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // П
|
||||||
|
{0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10}, // Р
|
||||||
|
{0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0F}, // С
|
||||||
|
{0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, // Т
|
||||||
|
{0x11, 0x11, 0x11, 0x0F, 0x01, 0x11, 0x0E}, // У
|
||||||
|
{0x04, 0x0E, 0x15, 0x15, 0x0E, 0x04, 0x04}, // Ф
|
||||||
|
{0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11}, // Х
|
||||||
|
{0x12, 0x12, 0x12, 0x12, 0x12, 0x1E, 0x01}, // Ц
|
||||||
|
{0x11, 0x11, 0x11, 0x0F, 0x01, 0x01, 0x01}, // Ч
|
||||||
|
{0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x1F}, // Ш
|
||||||
|
{0x15, 0x15, 0x15, 0x15, 0x15, 0x1E, 0x01}, // Щ
|
||||||
|
{0x18, 0x08, 0x08, 0x0E, 0x09, 0x09, 0x0E}, // Ъ
|
||||||
|
{0x11, 0x11, 0x11, 0x1D, 0x15, 0x15, 0x1D}, // Ы
|
||||||
|
{0x10, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x1E}, // Ь
|
||||||
|
{0x0E, 0x11, 0x01, 0x07, 0x01, 0x11, 0x0E}, // Э
|
||||||
|
{0x12, 0x15, 0x15, 0x1D, 0x15, 0x15, 0x12}, // Ю
|
||||||
|
{0x0F, 0x11, 0x11, 0x0F, 0x05, 0x09, 0x11} // Я
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const uint8_t *glyph(uint32_t codepoint) {
|
||||||
|
if (codepoint >= 0x0430U && codepoint <= 0x044FU) codepoint -= 0x20U;
|
||||||
|
if (codepoint == 0x0401U || codepoint == 0x0451U) codepoint = 0x0415U; // Ё -> Е
|
||||||
|
if (codepoint < 0x0410U || codepoint > 0x042FU) return nullptr;
|
||||||
|
return GLYPHS[codepoint - 0x0410U];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CyrillicFont
|
||||||
@@ -7,7 +7,8 @@ namespace Log {
|
|||||||
void event(const char *component, const char *message) {
|
void event(const char *component, const char *message) {
|
||||||
if (!SERIAL_ACTION_LOG) return;
|
if (!SERIAL_ACTION_LOG) return;
|
||||||
if (SERIAL_MINIMAL_LOG && strcmp(component, "INPUT") && strcmp(component, "UI") &&
|
if (SERIAL_MINIMAL_LOG && strcmp(component, "INPUT") && strcmp(component, "UI") &&
|
||||||
strcmp(component, "CONFIG") && strcmp(component, "RESULT") && strcmp(component, "ESP-NOW")) return;
|
strcmp(component, "CONFIG") && strcmp(component, "RESULT") && strcmp(component, "CAPTURE") &&
|
||||||
|
strcmp(component, "DRIVER") && strcmp(component, "ESP-NOW")) return;
|
||||||
if (SERIAL_LOG_TIMESTAMPS) Serial.printf("[%10lu][%-8s] %s\n", millis(), component, message);
|
if (SERIAL_LOG_TIMESTAMPS) Serial.printf("[%10lu][%-8s] %s\n", millis(), component, message);
|
||||||
else Serial.printf("[%-8s] %s\n", component, message);
|
else Serial.printf("[%-8s] %s\n", component, message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,87 +3,156 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
bool Measurement::start(float hz, float duty, float tolerance, uint32_t timeMs,
|
bool Measurement::start(float hz, float duty, float tolerance, uint32_t timeMs,
|
||||||
uint8_t repeats, uint8_t settleCycles) {
|
uint16_t averagingPeriods, uint8_t settleCycles,
|
||||||
|
bool activeRxLightOn) {
|
||||||
|
if (!task_ && xTaskCreate(taskEntry, "optical-rx", 4096, this, 4, &task_) != pdPASS) return false;
|
||||||
expectedHz_ = static_cast<uint32_t>(hz + 0.5f);
|
expectedHz_ = static_cast<uint32_t>(hz + 0.5f);
|
||||||
if (!expectedHz_ || !timeMs || !repeats || repeats > 10 ||
|
expectedDutyPct_ = duty;
|
||||||
!makePeriodLimits(expectedHz_, duty, tolerance, receiver_.tickHz(), limits_) ||
|
tolerance = effectiveTolerancePct(tolerance);
|
||||||
!receiver_.start(expectedHz_)) return false;
|
if (!expectedHz_ || !timeMs || !averagingPeriods ||
|
||||||
timeMs_ = timeMs; repeats_ = repeats; settleLeft_ = settleCycles;
|
!receiver_.start(expectedHz_, expectedDutyPct_, activeRxLightOn)) return false;
|
||||||
stats_.reset(); memset(repeatPeriods_, 0, sizeof(repeatPeriods_));
|
settleCycles_ = settleCycles; settleLeft_ = settleCycles;
|
||||||
|
tolerancePct_ = tolerance;
|
||||||
|
stepTimeMs_ = (timeMs + MEASUREMENT_PROGRESS_STEPS - 1U) / MEASUREMENT_PROGRESS_STEPS;
|
||||||
|
stepTicks_ = static_cast<uint64_t>(receiver_.tickHz()) * timeMs /
|
||||||
|
(1000ULL * MEASUREMENT_PROGRESS_STEPS);
|
||||||
|
if (!stepTicks_) stepTicks_ = 1;
|
||||||
|
currentStep_ = 0;
|
||||||
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
|
stats_.reset();
|
||||||
|
publishStats();
|
||||||
measurementStartTick_ = deadlineTick_ = 0; startedMs_ = millis();
|
measurementStartTick_ = deadlineTick_ = 0; startedMs_ = millis();
|
||||||
measurementStartMs_ = lastPeriodMs_ = 0;
|
measurementStartMs_ = lastPeriodMs_ = 0;
|
||||||
currentRepeat_ = 0;
|
|
||||||
expectedPeriodMs_ = static_cast<uint32_t>((1000ULL + expectedHz_ - 1U) / expectedHz_);
|
expectedPeriodMs_ = static_cast<uint32_t>((1000ULL + expectedHz_ - 1U) / expectedHz_);
|
||||||
if (!expectedPeriodMs_) expectedPeriodMs_ = 1;
|
if (!expectedPeriodMs_) expectedPeriodMs_ = 1;
|
||||||
state_ = MeasureState::SETTLING; return true;
|
state_ = MeasureState::SETTLING;
|
||||||
|
xTaskNotifyGive(task_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Measurement::taskEntry(void *context) {
|
||||||
|
static_cast<Measurement *>(context)->taskLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Measurement::taskLoop() {
|
||||||
|
for (;;) {
|
||||||
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
while (state_ == MeasureState::SETTLING || state_ == MeasureState::RUNNING) processOnce();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Measurement::fail(FailReason reason) {
|
void Measurement::fail(FailReason reason) {
|
||||||
if (stats_.reason == FailReason::NONE) stats_.reason = reason;
|
if (stats_.reason == FailReason::NONE) stats_.reason = reason;
|
||||||
receiver_.stop(); state_ = MeasureState::FAIL;
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
|
publishStats();
|
||||||
|
// App stops PWM first and only then disables capture. Disabling MCPWM from
|
||||||
|
// this RX task while input edges are still arriving can race its ISR.
|
||||||
|
state_ = MeasureState::FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Measurement::completeWindow() {
|
void Measurement::completeMeasurement() {
|
||||||
receiver_.stop();
|
const uint32_t dropped = receiver_.takeDroppedItems();
|
||||||
stats_.lostItems += receiver_.takeDroppedItems();
|
stats_.droppedItems += dropped;
|
||||||
if (receiver_.overflowed()) { fail(FailReason::GLITCH); return; }
|
if (dropped) { fail(FailReason::DATA_LOSS); return; }
|
||||||
for (uint8_t i = 0; i < repeats_; ++i) if (!repeatPeriods_[i]) {
|
publishStats();
|
||||||
fail(FailReason::TOO_FEW_PERIODS); return;
|
if (++currentStep_ < MEASUREMENT_PROGRESS_STEPS) {
|
||||||
|
// Capture and validation continue while the main task draws OLED. Pausing
|
||||||
|
// here would overflow the edge queue at higher PWM frequencies; stopping
|
||||||
|
// MCPWM Capture can race an edge ISR. Publish a snapshot, then advance the
|
||||||
|
// edge-based window without interrupting the RX pipeline.
|
||||||
|
__atomic_store_n(&progressUpdatePending_, true, __ATOMIC_RELEASE);
|
||||||
|
measurementStartTick_ = deadlineTick_;
|
||||||
|
deadlineTick_ += stepTicks_;
|
||||||
|
measurementStartMs_ = lastPeriodMs_ = millis();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (stats_.lostItems && stats_.reason == FailReason::NONE) stats_.reason = FailReason::DATA_LOST;
|
if (!stats_.periods) {
|
||||||
|
fail(FailReason::DATA_LOSS); return;
|
||||||
|
}
|
||||||
|
__atomic_store_n(&progressUpdatePending_, false, __ATOMIC_RELEASE);
|
||||||
state_ = MeasureState::PASS;
|
state_ = MeasureState::PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeasureState Measurement::update() {
|
void Measurement::publishStats() {
|
||||||
|
portENTER_CRITICAL(&statsMux_);
|
||||||
|
publishedStats_ = stats_;
|
||||||
|
portEXIT_CRITICAL(&statsMux_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Measurement::statsSnapshot(StageStats &out) const {
|
||||||
|
portENTER_CRITICAL(&statsMux_);
|
||||||
|
out = publishedStats_;
|
||||||
|
portEXIT_CRITICAL(&statsMux_);
|
||||||
|
return out.periods && out.periodSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeasureState Measurement::processOnce() {
|
||||||
if (state_ != MeasureState::SETTLING && state_ != MeasureState::RUNNING) return state_;
|
if (state_ != MeasureState::SETTLING && state_ != MeasureState::RUNNING) return state_;
|
||||||
if (receiver_.overflowed()) { fail(FailReason::GLITCH); return state_; }
|
|
||||||
bool receivedPeriod = false;
|
bool receivedPeriod = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const size_t periodCount = receiver_.readPeriods(periodBatch_, PERIOD_BATCH_SIZE);
|
const size_t periodCount = receiver_.readPeriods(periodBatch_, PERIOD_BATCH_SIZE, pdMS_TO_TICKS(2));
|
||||||
stats_.lostItems += receiver_.takeDroppedItems();
|
const uint32_t dropped = receiver_.takeDroppedItems();
|
||||||
|
stats_.droppedItems += dropped;
|
||||||
|
if (dropped) { fail(FailReason::DATA_LOSS); return state_; }
|
||||||
if (!periodCount) break;
|
if (!periodCount) break;
|
||||||
receivedPeriod = true;
|
receivedPeriod = true;
|
||||||
for (size_t periodIndex = 0; periodIndex < periodCount; ++periodIndex) {
|
for (size_t periodIndex = 0; periodIndex < periodCount; ++periodIndex) {
|
||||||
|
if (state_ != MeasureState::SETTLING && state_ != MeasureState::RUNNING) return state_;
|
||||||
const PulsePeriod &period = periodBatch_[periodIndex];
|
const PulsePeriod &period = periodBatch_[periodIndex];
|
||||||
if (state_ == MeasureState::SETTLING) {
|
if (state_ == MeasureState::SETTLING) {
|
||||||
if (settleLeft_) --settleLeft_;
|
if (settleLeft_) --settleLeft_;
|
||||||
if (!settleLeft_) {
|
if (!settleLeft_) {
|
||||||
measurementStartTick_ = period.startTick + period.periodTicks;
|
measurementStartTick_ = period.startTick + period.periodTicks;
|
||||||
repeatTicks_ = static_cast<uint64_t>(receiver_.tickHz()) * timeMs_ / 1000ULL;
|
deadlineTick_ = measurementStartTick_ + stepTicks_;
|
||||||
deadlineTick_ = measurementStartTick_ + repeatTicks_ * repeats_;
|
measurementStartMs_ = lastPeriodMs_ = millis(); state_ = MeasureState::RUNNING;
|
||||||
nextRepeatTick_ = measurementStartTick_ + repeatTicks_;
|
|
||||||
stats_.reset(); measurementStartMs_ = lastPeriodMs_ = millis(); state_ = MeasureState::RUNNING;
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint64_t endTick = period.startTick + period.periodTicks;
|
|
||||||
if (period.startTick < measurementStartTick_) continue; // leading incomplete period
|
if (period.startTick < measurementStartTick_) continue; // leading incomplete period
|
||||||
if (endTick > deadlineTick_) { completeWindow(); return state_; } // trailing incomplete period
|
while (period.startTick >= deadlineTick_) {
|
||||||
while (currentRepeat_ + 1U < repeats_ && period.startTick >= nextRepeatTick_) {
|
// Progress boundaries never discard a pulse. A complete period is
|
||||||
++currentRepeat_; nextRepeatTick_ += repeatTicks_;
|
// assigned by its start edge, then validated exactly once. The nine
|
||||||
|
// intermediate boundaries only publish UI snapshots.
|
||||||
|
completeMeasurement();
|
||||||
|
if (state_ != MeasureState::RUNNING) return state_;
|
||||||
}
|
}
|
||||||
++repeatPeriods_[currentRepeat_];
|
if (!period.periodTicks || !period.activeTicks || !period.activeTickHz) {
|
||||||
const FailReason r = evaluatePeriodFast(period, receiver_.tickHz(), limits_, currentRepeat_ + 1, stats_);
|
fail(FailReason::EXTRA_EDGE); return state_;
|
||||||
if (r != FailReason::NONE) { fail(r); return state_; }
|
}
|
||||||
|
|
||||||
|
const FailReason result = evaluatePeriod(period, receiver_.tickHz(),
|
||||||
|
expectedHz_, expectedDutyPct_, tolerancePct_, currentStep_ + 1U, stats_);
|
||||||
|
if (result != FailReason::NONE) { fail(result); return state_; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (receivedPeriod && state_ == MeasureState::RUNNING) lastPeriodMs_ = millis();
|
if (receivedPeriod && state_ == MeasureState::RUNNING) lastPeriodMs_ = millis();
|
||||||
const uint64_t edgeBasedTimeout =
|
const uint64_t edgeBasedTimeout =
|
||||||
static_cast<uint64_t>(PWM_SETTLE_CYCLES + NO_SIGNAL_TIMEOUT_PERIODS) * expectedPeriodMs_ + 20;
|
static_cast<uint64_t>(PWM_SETTLE_CYCLES + NO_SIGNAL_TIMEOUT_PERIODS) * expectedPeriodMs_ + 20;
|
||||||
const uint64_t rmtBatchTimeout =
|
const uint64_t settleTimeout = edgeBasedTimeout;
|
||||||
static_cast<uint64_t>(RMT_MIN_RECEIVE_SYMBOLS + NO_SIGNAL_TIMEOUT_PERIODS) * expectedPeriodMs_ + 20;
|
|
||||||
const uint64_t settleTimeout = edgeBasedTimeout > rmtBatchTimeout ? edgeBasedTimeout : rmtBatchTimeout;
|
|
||||||
if (state_ == MeasureState::SETTLING && millis() - startedMs_ > settleTimeout) fail(FailReason::NO_SIGNAL);
|
if (state_ == MeasureState::SETTLING && millis() - startedMs_ > settleTimeout) fail(FailReason::NO_SIGNAL);
|
||||||
if (state_ == MeasureState::RUNNING && measurementStartTick_) {
|
if (state_ == MeasureState::RUNNING && measurementStartTick_) {
|
||||||
const uint32_t now = millis();
|
const uint32_t now = millis();
|
||||||
const uint32_t totalMs = timeMs_ * repeats_;
|
const uint32_t edgeTimeoutMs = expectedPeriodMs_ * NO_SIGNAL_TIMEOUT_PERIODS + 2U;
|
||||||
const uint32_t edgeTimeoutMs = expectedPeriodMs_ * NO_SIGNAL_TIMEOUT_PERIODS + 2;
|
if (now - measurementStartMs_ < stepTimeMs_ && now - lastPeriodMs_ > edgeTimeoutMs) {
|
||||||
if (now - measurementStartMs_ < totalMs && now - lastPeriodMs_ > edgeTimeoutMs) {
|
|
||||||
fail(FailReason::LOST_EDGE); return state_;
|
fail(FailReason::LOST_EDGE); return state_;
|
||||||
}
|
}
|
||||||
if (now - measurementStartMs_ > totalMs + expectedPeriodMs_ + 2) completeWindow();
|
if (now - measurementStartMs_ > stepTimeMs_ + expectedPeriodMs_ + 2) completeMeasurement();
|
||||||
}
|
}
|
||||||
return state_;
|
return state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Measurement::abort() { if (state_ == MeasureState::SETTLING || state_ == MeasureState::RUNNING) fail(FailReason::ABORTED); }
|
MeasureState Measurement::update() { return state_; }
|
||||||
|
|
||||||
|
bool Measurement::takeProgressUpdate() {
|
||||||
|
return __atomic_exchange_n(&progressUpdatePending_, false, __ATOMIC_ACQ_REL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Measurement::abort() {
|
||||||
|
if (state_ == MeasureState::SETTLING || state_ == MeasureState::RUNNING)
|
||||||
|
fail(FailReason::ABORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Measurement::forceFail(FailReason reason) {
|
||||||
|
if (state_ == MeasureState::SETTLING || state_ == MeasureState::RUNNING)
|
||||||
|
fail(reason);
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,25 +7,37 @@ class Measurement {
|
|||||||
public:
|
public:
|
||||||
explicit Measurement(PulseReceiver &receiver) : receiver_(receiver) {}
|
explicit Measurement(PulseReceiver &receiver) : receiver_(receiver) {}
|
||||||
bool start(float expectedHz, float expectedDuty, float tolerancePct,
|
bool start(float expectedHz, float expectedDuty, float tolerancePct,
|
||||||
uint32_t testTimeMs, uint8_t repeats, uint8_t settleCycles);
|
uint32_t testTimeMs, uint16_t averagingPeriods,
|
||||||
|
uint8_t settleCycles, bool activeRxLightOn);
|
||||||
MeasureState update();
|
MeasureState update();
|
||||||
|
bool takeProgressUpdate();
|
||||||
void abort();
|
void abort();
|
||||||
|
void forceFail(FailReason reason);
|
||||||
MeasureState state() const { return state_; }
|
MeasureState state() const { return state_; }
|
||||||
FailReason reason() const { return stats_.reason; }
|
FailReason reason() const { return stats_.reason; }
|
||||||
const StageStats &stats() const { return stats_; }
|
const StageStats &stats() const { return stats_; }
|
||||||
|
uint8_t progressStep() const { return currentStep_; }
|
||||||
|
bool statsSnapshot(StageStats &out) const;
|
||||||
private:
|
private:
|
||||||
|
static void taskEntry(void *context);
|
||||||
|
void taskLoop();
|
||||||
|
MeasureState processOnce();
|
||||||
void fail(FailReason reason);
|
void fail(FailReason reason);
|
||||||
void completeWindow();
|
void completeMeasurement();
|
||||||
|
void publishStats();
|
||||||
PulseReceiver &receiver_;
|
PulseReceiver &receiver_;
|
||||||
MeasureState state_ = MeasureState::IDLE;
|
volatile MeasureState state_ = MeasureState::IDLE;
|
||||||
|
TaskHandle_t task_ = nullptr;
|
||||||
StageStats stats_ = {};
|
StageStats stats_ = {};
|
||||||
PeriodLimits limits_ = {};
|
StageStats publishedStats_ = {};
|
||||||
|
mutable portMUX_TYPE statsMux_ = portMUX_INITIALIZER_UNLOCKED;
|
||||||
uint32_t expectedHz_ = 0;
|
uint32_t expectedHz_ = 0;
|
||||||
uint32_t timeMs_ = 0;
|
float expectedDutyPct_ = 0.0f, tolerancePct_ = 0.0f;
|
||||||
uint8_t repeats_ = 0, settleLeft_ = 0, currentRepeat_ = 0;
|
uint8_t settleCycles_ = 0, settleLeft_ = 0;
|
||||||
uint64_t measurementStartTick_ = 0, deadlineTick_ = 0, repeatTicks_ = 0, nextRepeatTick_ = 0;
|
uint64_t measurementStartTick_ = 0, deadlineTick_ = 0, stepTicks_ = 0;
|
||||||
uint32_t startedMs_ = 0, measurementStartMs_ = 0, lastPeriodMs_ = 0;
|
uint32_t startedMs_ = 0, measurementStartMs_ = 0, lastPeriodMs_ = 0;
|
||||||
uint32_t expectedPeriodMs_ = 1;
|
uint32_t stepTimeMs_ = 1, expectedPeriodMs_ = 1;
|
||||||
uint32_t repeatPeriods_[10] = {};
|
volatile uint8_t currentStep_ = 0;
|
||||||
|
volatile bool progressUpdatePending_ = false;
|
||||||
PulsePeriod periodBatch_[PERIOD_BATCH_SIZE] = {};
|
PulsePeriod periodBatch_[PERIOD_BATCH_SIZE] = {};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "App.h"
|
#include "App.h"
|
||||||
|
|
||||||
App app;
|
App app;
|
||||||
|
|
||||||
void setup() { app.begin(); }
|
void setup() { app.begin(); }
|
||||||
|
|||||||
74
OpticalChannelTester/OpticalCurrent.cpp
Normal file
74
OpticalChannelTester/OpticalCurrent.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "OpticalCurrent.h"
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct AdcAccumulator {
|
||||||
|
uint64_t senseRaw = 0;
|
||||||
|
uint64_t vccRaw = 0;
|
||||||
|
uint64_t senseMillivolts = 0;
|
||||||
|
uint64_t vccMillivolts = 0;
|
||||||
|
uint32_t samples = 0;
|
||||||
|
uint32_t startedMs = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
AdcAccumulator accumulator;
|
||||||
|
|
||||||
|
void resetAccumulator(uint32_t now) {
|
||||||
|
accumulator = {};
|
||||||
|
accumulator.startedMs = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpticalCurrentMeasurement finishMeasurement() {
|
||||||
|
const float senseAdcVoltage =
|
||||||
|
accumulator.senseMillivolts / (1000.0f * accumulator.samples);
|
||||||
|
const float vccAdcVoltage =
|
||||||
|
accumulator.vccMillivolts / (1000.0f * accumulator.samples);
|
||||||
|
const float senseVoltage = senseAdcVoltage * OPTICAL_DIVIDER_RATIO;
|
||||||
|
const float vccVoltage = vccAdcVoltage * OPTICAL_DIVIDER_RATIO;
|
||||||
|
const float resistorVoltage = vccVoltage - senseVoltage;
|
||||||
|
const float currentMa = resistorVoltage * 1000.0f / OPTICAL_SENSE_R;
|
||||||
|
return {
|
||||||
|
static_cast<uint16_t>(accumulator.senseRaw / accumulator.samples),
|
||||||
|
static_cast<uint16_t>(accumulator.vccRaw / accumulator.samples),
|
||||||
|
senseAdcVoltage, vccAdcVoltage, senseVoltage, vccVoltage,
|
||||||
|
currentMa > 0.0f ? currentMa : 0.0f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void optical_current_begin(void) {
|
||||||
|
analogReadResolution(12);
|
||||||
|
pinMode(GPIO_OPTICAL_CURRENT, INPUT);
|
||||||
|
pinMode(GPIO_OPTICAL_VCC, INPUT);
|
||||||
|
// Both 10k/10k dividers can present about 2.5 V to their ADC inputs.
|
||||||
|
analogSetPinAttenuation(GPIO_OPTICAL_CURRENT, ADC_11db);
|
||||||
|
analogSetPinAttenuation(GPIO_OPTICAL_VCC, ADC_11db);
|
||||||
|
resetAccumulator(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool optical_current_poll(OpticalCurrentMeasurement &measurement) {
|
||||||
|
const uint32_t now = millis();
|
||||||
|
if (!accumulator.startedMs) resetAccumulator(now ? now : 1U);
|
||||||
|
|
||||||
|
accumulator.senseRaw += analogRead(GPIO_OPTICAL_CURRENT);
|
||||||
|
accumulator.senseMillivolts += analogReadMilliVolts(GPIO_OPTICAL_CURRENT);
|
||||||
|
accumulator.vccRaw += analogRead(GPIO_OPTICAL_VCC);
|
||||||
|
accumulator.vccMillivolts += analogReadMilliVolts(GPIO_OPTICAL_VCC);
|
||||||
|
++accumulator.samples;
|
||||||
|
|
||||||
|
if (now - accumulator.startedMs < OPTICAL_CURRENT_AVERAGING_MS) return false;
|
||||||
|
measurement = finishMeasurement();
|
||||||
|
resetAccumulator(now);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpticalCurrentMeasurement optical_get_led_measurement(void) {
|
||||||
|
OpticalCurrentMeasurement measurement = {};
|
||||||
|
resetAccumulator(millis());
|
||||||
|
while (!optical_current_poll(measurement)) delay(1);
|
||||||
|
return measurement;
|
||||||
|
}
|
||||||
|
|
||||||
|
float optical_get_led_current_ma(void) {
|
||||||
|
return optical_get_led_measurement().currentMa;
|
||||||
|
}
|
||||||
18
OpticalChannelTester/OpticalCurrent.h
Normal file
18
OpticalChannelTester/OpticalCurrent.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct OpticalCurrentMeasurement {
|
||||||
|
uint16_t senseRaw;
|
||||||
|
uint16_t vccRaw;
|
||||||
|
float senseAdcVoltage;
|
||||||
|
float vccAdcVoltage;
|
||||||
|
float senseVoltage;
|
||||||
|
float vccVoltage;
|
||||||
|
float currentMa;
|
||||||
|
};
|
||||||
|
|
||||||
|
void optical_current_begin(void);
|
||||||
|
bool optical_current_poll(OpticalCurrentMeasurement &measurement);
|
||||||
|
OpticalCurrentMeasurement optical_get_led_measurement(void);
|
||||||
|
float optical_get_led_current_ma(void);
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
const char *messageName(MessageType type) {
|
const char *messageName(MessageType type) {
|
||||||
static const char *names[] = {"DISCOVER", "DISCOVER_ACK", "PREPARE", "READY",
|
static const char *names[] = {"DISCOVER", "DISCOVER_ACK", "PREPARE", "READY",
|
||||||
"START_STAGE", "RESULT", "ACK", "ABORT", "HEARTBEAT", "HEARTBEAT_ACK"};
|
"START_STAGE", "RESULT", "ACK", "ABORT", "HEARTBEAT", "HEARTBEAT_ACK", "PROGRESS"};
|
||||||
const uint8_t index = static_cast<uint8_t>(type);
|
const uint8_t index = static_cast<uint8_t>(type);
|
||||||
return index < sizeof(names) / sizeof(names[0]) ? names[index] : "UNKNOWN";
|
return index < sizeof(names) / sizeof(names[0]) ? names[index] : "UNKNOWN";
|
||||||
}
|
}
|
||||||
@@ -24,5 +24,5 @@ void finalizePacket(ProtocolPacket &p) {
|
|||||||
|
|
||||||
bool validPacket(const ProtocolPacket &p) {
|
bool validPacket(const ProtocolPacket &p) {
|
||||||
return p.magic == PROTOCOL_MAGIC && p.version == PROTOCOL_VERSION &&
|
return p.magic == PROTOCOL_MAGIC && p.version == PROTOCOL_VERSION &&
|
||||||
p.type <= static_cast<uint8_t>(MessageType::HEARTBEAT_ACK) && p.crc == packetCrc(p);
|
p.type <= static_cast<uint8_t>(MessageType::PROGRESS) && p.crc == packetCrc(p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
|
|
||||||
constexpr uint16_t PROTOCOL_MAGIC = 0x4F43;
|
constexpr uint16_t PROTOCOL_MAGIC = 0x4F43;
|
||||||
constexpr uint8_t PROTOCOL_VERSION = 2;
|
constexpr uint8_t PROTOCOL_VERSION = 12;
|
||||||
|
|
||||||
enum class MessageType : uint8_t {
|
enum class MessageType : uint8_t {
|
||||||
DISCOVER, DISCOVER_ACK, PREPARE, READY, START_STAGE, RESULT, ACK, ABORT,
|
DISCOVER, DISCOVER_ACK, PREPARE, READY, START_STAGE, RESULT, ACK, ABORT,
|
||||||
HEARTBEAT, HEARTBEAT_ACK
|
HEARTBEAT, HEARTBEAT_ACK, PROGRESS
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *messageName(MessageType type);
|
const char *messageName(MessageType type);
|
||||||
@@ -18,24 +18,28 @@ struct ProtocolPacket {
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t session;
|
uint32_t session;
|
||||||
uint16_t stage;
|
uint16_t stage;
|
||||||
|
uint16_t stageCount;
|
||||||
uint16_t sequence;
|
uint16_t sequence;
|
||||||
uint32_t requestedHz;
|
uint32_t requestedHz;
|
||||||
|
uint32_t requestedPulseNs;
|
||||||
uint32_t actualHz;
|
uint32_t actualHz;
|
||||||
uint16_t actualDutyX100;
|
uint32_t actualPulseNs;
|
||||||
uint32_t testTimeMs;
|
uint32_t testTimeMs;
|
||||||
uint8_t repeats;
|
|
||||||
uint16_t accuracyX100;
|
uint16_t accuracyX100;
|
||||||
uint8_t settleCycles;
|
uint8_t lightCode;
|
||||||
|
uint8_t progressStep;
|
||||||
uint8_t passed;
|
uint8_t passed;
|
||||||
uint8_t reason;
|
uint8_t reason;
|
||||||
uint32_t periods;
|
uint32_t periods;
|
||||||
|
uint32_t measuredHzX10;
|
||||||
|
uint32_t measuredPulseNs;
|
||||||
uint32_t minPeriodTicks;
|
uint32_t minPeriodTicks;
|
||||||
uint32_t maxPeriodTicks;
|
uint32_t maxPeriodTicks;
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
static_assert(sizeof(ProtocolPacket) == 46, "Protocol layout changed");
|
static_assert(sizeof(ProtocolPacket) == 62, "Protocol layout changed");
|
||||||
|
|
||||||
uint16_t packetCrc(const ProtocolPacket &packet);
|
uint16_t packetCrc(const ProtocolPacket &packet);
|
||||||
void finalizePacket(ProtocolPacket &packet);
|
void finalizePacket(ProtocolPacket &packet);
|
||||||
|
|||||||
@@ -1,31 +1,248 @@
|
|||||||
#include "Pwm.h"
|
#include "Pwm.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
#include <hal/ledc_ll.h>
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
#include <driver/mcpwm_prelude.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
constexpr ledc_mode_t PWM_SPEED_MODE = LEDC_LOW_SPEED_MODE;
|
||||||
|
constexpr ledc_timer_t PWM_TIMER = LEDC_TIMER_0;
|
||||||
|
|
||||||
|
void setDivider(uint32_t dividerRaw) {
|
||||||
|
ledc_dev_t *hardware = LEDC_LL_GET_HW();
|
||||||
|
ledc_ll_timer_pause(hardware, PWM_SPEED_MODE, PWM_TIMER);
|
||||||
|
ledc_ll_set_clock_divider(hardware, PWM_SPEED_MODE, PWM_TIMER,
|
||||||
|
dividerRaw);
|
||||||
|
ledc_ll_timer_rst(hardware, PWM_SPEED_MODE, PWM_TIMER);
|
||||||
|
ledc_ll_ls_timer_update(hardware, PWM_SPEED_MODE, PWM_TIMER);
|
||||||
|
ledc_ll_timer_resume(hardware, PWM_SPEED_MODE, PWM_TIMER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dividerIsSet(uint32_t expectedRaw) {
|
||||||
|
uint32_t rawDivider = 0;
|
||||||
|
ledc_ll_get_clock_divider(LEDC_LL_GET_HW(), PWM_SPEED_MODE, PWM_TIMER, &rawDivider);
|
||||||
|
return rawDivider == expectedRaw;
|
||||||
|
}
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
mcpwm_timer_handle_t mcpwmTimer = nullptr;
|
||||||
|
mcpwm_oper_handle_t mcpwmOperator = nullptr;
|
||||||
|
mcpwm_cmpr_handle_t mcpwmComparator = nullptr;
|
||||||
|
mcpwm_gen_handle_t mcpwmGenerator = nullptr;
|
||||||
|
uint32_t mcpwmFrequencyHz = 0;
|
||||||
|
|
||||||
|
void releaseMcpwm() {
|
||||||
|
if (mcpwmGenerator) {
|
||||||
|
mcpwm_del_generator(mcpwmGenerator);
|
||||||
|
mcpwmGenerator = nullptr;
|
||||||
|
}
|
||||||
|
if (mcpwmComparator) {
|
||||||
|
mcpwm_del_comparator(mcpwmComparator);
|
||||||
|
mcpwmComparator = nullptr;
|
||||||
|
}
|
||||||
|
if (mcpwmOperator) {
|
||||||
|
mcpwm_del_operator(mcpwmOperator);
|
||||||
|
mcpwmOperator = nullptr;
|
||||||
|
}
|
||||||
|
if (mcpwmTimer) {
|
||||||
|
mcpwm_timer_disable(mcpwmTimer);
|
||||||
|
mcpwm_del_timer(mcpwmTimer);
|
||||||
|
mcpwmTimer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t periodResolutionBits(uint32_t periodTicks) {
|
||||||
|
uint8_t bits = 0;
|
||||||
|
while (periodTicks > 1U) {
|
||||||
|
periodTicks >>= 1U;
|
||||||
|
++bits;
|
||||||
|
}
|
||||||
|
return bits ? bits : 1U;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void PwmGenerator::begin() {
|
void PwmGenerator::begin() {
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
// Match LEDC_SOURCE_CLOCK_HZ and make the timer calculation deterministic.
|
// Match LEDC_SOURCE_CLOCK_HZ and make the timer calculation deterministic.
|
||||||
ledcSetClockSource(LEDC_USE_XTAL_CLK);
|
ledcSetClockSource(LEDC_USE_XTAL_CLK);
|
||||||
pinMode(GPIO_PWM, OUTPUT);
|
pinMode(GPIO_PWM, OUTPUT);
|
||||||
stop();
|
stop();
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
mcpwm_timer_config_t timerConfig = {};
|
||||||
|
timerConfig.group_id = 0;
|
||||||
|
timerConfig.clk_src = MCPWM_TIMER_CLK_SRC_PLL160M;
|
||||||
|
timerConfig.resolution_hz = MCPWM_RESOLUTION_HZ;
|
||||||
|
timerConfig.count_mode = MCPWM_TIMER_COUNT_MODE_UP;
|
||||||
|
timerConfig.period_ticks = MCPWM_RESOLUTION_HZ / 1000U;
|
||||||
|
|
||||||
|
mcpwm_operator_config_t operatorConfig = {};
|
||||||
|
operatorConfig.group_id = 0;
|
||||||
|
mcpwm_comparator_config_t comparatorConfig = {};
|
||||||
|
mcpwm_generator_config_t generatorConfig = {};
|
||||||
|
generatorConfig.gen_gpio_num = GPIO_PWM;
|
||||||
|
|
||||||
|
bool ok = mcpwm_new_timer(&timerConfig, &mcpwmTimer) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_new_operator(&operatorConfig, &mcpwmOperator) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_operator_connect_timer(mcpwmOperator, mcpwmTimer) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_new_comparator(mcpwmOperator, &comparatorConfig, &mcpwmComparator) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_new_generator(mcpwmOperator, &generatorConfig, &mcpwmGenerator) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_comparator_set_compare_value(mcpwmComparator,
|
||||||
|
timerConfig.period_ticks / 2U) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_generator_set_action_on_timer_event(mcpwmGenerator,
|
||||||
|
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
|
||||||
|
MCPWM_TIMER_EVENT_EMPTY, TX_LIGHT_ON_GPIO_LEVEL == HIGH ?
|
||||||
|
MCPWM_GEN_ACTION_HIGH : MCPWM_GEN_ACTION_LOW)) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_generator_set_action_on_compare_event(mcpwmGenerator,
|
||||||
|
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
|
||||||
|
mcpwmComparator, TX_LIGHT_OFF_GPIO_LEVEL == HIGH ?
|
||||||
|
MCPWM_GEN_ACTION_HIGH : MCPWM_GEN_ACTION_LOW)) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_timer_enable(mcpwmTimer) == ESP_OK;
|
||||||
|
if (!ok) {
|
||||||
|
releaseMcpwm();
|
||||||
|
pinMode(GPIO_PWM, OUTPUT);
|
||||||
|
digitalWrite(GPIO_PWM, TX_LIGHT_OFF_GPIO_LEVEL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mcpwm_generator_set_force_level(mcpwmGenerator, TX_LIGHT_OFF_GPIO_LEVEL, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PwmGenerator::start(uint32_t hz, uint8_t dutyPct, ActualPwm &a) {
|
bool PwmGenerator::start(uint32_t hz, uint32_t pulseNs, ActualPwm &a) {
|
||||||
stop();
|
const uint8_t activeLevel = activeLightOn_ ? TX_LIGHT_ON_GPIO_LEVEL :
|
||||||
const uint8_t bits = choosePwmResolution(hz, LEDC_SOURCE_CLOCK_HZ, LEDC_MAX_BITS);
|
TX_LIGHT_OFF_GPIO_LEVEL;
|
||||||
if (!bits) return false;
|
const uint8_t inactiveLevel = activeLevel == HIGH ? LOW : HIGH;
|
||||||
if (!ledcAttachChannel(GPIO_PWM, hz, bits, LEDC_CHANNEL)) return false;
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
IntegerPwmConfig config = {};
|
||||||
|
if (!choosePwmConfig(hz, pulseNs, LEDC_SOURCE_CLOCK_HZ, LEDC_MAX_BITS, config)) return false;
|
||||||
|
const uint8_t bits = config.bits;
|
||||||
const uint32_t levels = 1UL << bits;
|
const uint32_t levels = 1UL << bits;
|
||||||
const uint32_t duty = (static_cast<uint64_t>(levels) * dutyPct + 50U) / 100U;
|
const uint32_t duty = config.dutyCount;
|
||||||
if (!ledcWriteChannel(LEDC_CHANNEL, duty)) { ledcDetach(GPIO_PWM); return false; }
|
for (uint8_t attempt = 0; attempt < 2; ++attempt) {
|
||||||
|
stop();
|
||||||
|
const bool attached = ledcAttachChannel(GPIO_PWM, config.actualHz, bits, LEDC_CHANNEL);
|
||||||
|
if (attached) {
|
||||||
|
// Native LEDC produces a HIGH pulse. Invert the GPIO matrix output when
|
||||||
|
// the configured active pulse level is LOW.
|
||||||
|
if (!ledcOutputInvert(GPIO_PWM, activeLevel == LOW)) {
|
||||||
|
ledcDetach(GPIO_PWM);
|
||||||
|
delay(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Apply the selected Q10.8 divider explicitly. This lets pulse width,
|
||||||
|
// rather than duty percentage, drive the hardware quantization.
|
||||||
|
setDivider(config.dividerRaw);
|
||||||
|
}
|
||||||
|
if (attached && dividerIsSet(config.dividerRaw) && ledcWriteChannel(LEDC_CHANNEL, duty)) {
|
||||||
|
// On the first configuration after power-up the duty update is latched
|
||||||
|
// on a timer edge. Reading immediately can therefore return zero.
|
||||||
|
uint32_t settleUs = static_cast<uint32_t>((2000000ULL + hz - 1U) / hz);
|
||||||
|
if (settleUs > 2000U) settleUs = 2000U;
|
||||||
|
delayMicroseconds(settleUs);
|
||||||
const uint32_t actualHz = ledcReadFreq(GPIO_PWM);
|
const uint32_t actualHz = ledcReadFreq(GPIO_PWM);
|
||||||
if (!actualHz) { ledcDetach(GPIO_PWM); return false; }
|
if (actualHz == config.actualHz) {
|
||||||
a = {hz, actualHz, 100.0f * duty / levels, bits};
|
a = {hz, actualHz, pulseNs, config.actualPulseNs,
|
||||||
|
100.0f * duty / levels, bits};
|
||||||
running_ = true;
|
running_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (attached) ledcDetach(GPIO_PWM);
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
|
pinMode(GPIO_PWM, OUTPUT); digitalWrite(GPIO_PWM, TX_LIGHT_OFF_GPIO_LEVEL);
|
||||||
|
return false;
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
if (!mcpwmTimer || !mcpwmComparator || !mcpwmGenerator || !hz || !pulseNs ||
|
||||||
|
MCPWM_RESOLUTION_HZ % hz) return false;
|
||||||
|
const uint32_t periodTicks = MCPWM_RESOLUTION_HZ / hz;
|
||||||
|
if (periodTicks < 2U || periodTicks > MCPWM_MAX_PERIOD_TICKS) return false;
|
||||||
|
uint32_t activeTicks = static_cast<uint32_t>(
|
||||||
|
(static_cast<uint64_t>(pulseNs) * MCPWM_RESOLUTION_HZ + 500000000ULL) /
|
||||||
|
1000000000ULL);
|
||||||
|
if (activeTicks == 0U) activeTicks = 1U;
|
||||||
|
if (activeTicks >= periodTicks) activeTicks = periodTicks - 1U;
|
||||||
|
|
||||||
|
stop();
|
||||||
|
bool ok = mcpwm_timer_set_period(mcpwmTimer, periodTicks) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_comparator_set_compare_value(mcpwmComparator, activeTicks) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_generator_set_action_on_timer_event(mcpwmGenerator,
|
||||||
|
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
|
||||||
|
MCPWM_TIMER_EVENT_EMPTY, activeLevel == HIGH ?
|
||||||
|
MCPWM_GEN_ACTION_HIGH : MCPWM_GEN_ACTION_LOW)) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_generator_set_action_on_compare_event(mcpwmGenerator,
|
||||||
|
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
|
||||||
|
mcpwmComparator, inactiveLevel == HIGH ?
|
||||||
|
MCPWM_GEN_ACTION_HIGH : MCPWM_GEN_ACTION_LOW)) == ESP_OK;
|
||||||
|
// stop() applies a continuous force level (hold_on=true). Remove that same
|
||||||
|
// continuous-force action; hold_on=false addresses a different, one-shot
|
||||||
|
// force mechanism and would leave the safe level permanently active.
|
||||||
|
ok = ok && mcpwm_generator_set_force_level(mcpwmGenerator, -1, true) == ESP_OK;
|
||||||
|
ok = ok && mcpwm_timer_start_stop(mcpwmTimer, MCPWM_TIMER_START_NO_STOP) == ESP_OK;
|
||||||
|
if (!ok) {
|
||||||
|
mcpwm_generator_set_force_level(mcpwmGenerator, TX_LIGHT_OFF_GPIO_LEVEL, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t actualPulseNs = static_cast<uint32_t>(
|
||||||
|
(static_cast<uint64_t>(activeTicks) * 1000000000ULL + MCPWM_RESOLUTION_HZ / 2U) /
|
||||||
|
MCPWM_RESOLUTION_HZ);
|
||||||
|
a = {hz, hz, pulseNs, actualPulseNs, 100.0f * activeTicks / periodTicks,
|
||||||
|
periodResolutionBits(periodTicks)};
|
||||||
|
mcpwmFrequencyHz = hz;
|
||||||
|
running_ = true;
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void PwmGenerator::stop() {
|
void PwmGenerator::stop() {
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
if (running_) ledcDetach(GPIO_PWM);
|
if (running_) ledcDetach(GPIO_PWM);
|
||||||
pinMode(GPIO_PWM, OUTPUT); digitalWrite(GPIO_PWM, PWM_SAFE_LEVEL);
|
pinMode(GPIO_PWM, OUTPUT); digitalWrite(GPIO_PWM, TX_LIGHT_OFF_GPIO_LEVEL);
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
if (mcpwmGenerator) mcpwm_generator_set_force_level(
|
||||||
|
mcpwmGenerator, TX_LIGHT_OFF_GPIO_LEVEL, true);
|
||||||
|
if (running_ && mcpwmTimer) {
|
||||||
|
mcpwm_timer_start_stop(mcpwmTimer, MCPWM_TIMER_STOP_EMPTY);
|
||||||
|
const uint32_t waitUs = mcpwmFrequencyHz ? (1000000U / mcpwmFrequencyHz + 2U) : 2U;
|
||||||
|
delayMicroseconds(waitUs);
|
||||||
|
}
|
||||||
|
mcpwmFrequencyHz = 0;
|
||||||
|
#endif
|
||||||
running_ = false;
|
running_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PwmGenerator::active() {
|
||||||
|
// First detach/stop the PWM peripheral, then apply the same active level
|
||||||
|
// that denotes the pulse during a running test.
|
||||||
|
stop();
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
digitalWrite(GPIO_PWM, activeLightOn_ ? TX_LIGHT_ON_GPIO_LEVEL :
|
||||||
|
TX_LIGHT_OFF_GPIO_LEVEL);
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
const uint8_t level = activeLightOn_ ? TX_LIGHT_ON_GPIO_LEVEL :
|
||||||
|
TX_LIGHT_OFF_GPIO_LEVEL;
|
||||||
|
if (mcpwmGenerator) mcpwm_generator_set_force_level(mcpwmGenerator, level, true);
|
||||||
|
else {
|
||||||
|
pinMode(GPIO_PWM, OUTPUT);
|
||||||
|
digitalWrite(GPIO_PWM, level);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PwmGenerator::lightOn() {
|
||||||
|
stop();
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
|
digitalWrite(GPIO_PWM, TX_LIGHT_ON_GPIO_LEVEL);
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
if (mcpwmGenerator)
|
||||||
|
mcpwm_generator_set_force_level(mcpwmGenerator, TX_LIGHT_ON_GPIO_LEVEL, true);
|
||||||
|
else {
|
||||||
|
pinMode(GPIO_PWM, OUTPUT);
|
||||||
|
digitalWrite(GPIO_PWM, TX_LIGHT_ON_GPIO_LEVEL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
struct ActualPwm { uint32_t requestedHz; uint32_t actualHz; float actualDutyPct; uint8_t bits; };
|
struct ActualPwm {
|
||||||
|
uint32_t requestedHz;
|
||||||
|
uint32_t actualHz;
|
||||||
|
uint32_t requestedPulseNs;
|
||||||
|
uint32_t actualPulseNs;
|
||||||
|
float actualDutyPct;
|
||||||
|
uint8_t bits;
|
||||||
|
};
|
||||||
|
|
||||||
class PwmGenerator {
|
class PwmGenerator {
|
||||||
public:
|
public:
|
||||||
void begin();
|
void begin();
|
||||||
bool start(uint32_t frequencyHz, uint8_t dutyPct, ActualPwm &actual);
|
void configureActiveLight(bool lightOn) { activeLightOn_ = lightOn; }
|
||||||
|
bool start(uint32_t frequencyHz, uint32_t pulseNs, ActualPwm &actual);
|
||||||
|
// Hold the optical level selected as the active TX pulse.
|
||||||
|
void active();
|
||||||
|
// Hold actual optical light ON, independently of HH/HL/LH/LL.
|
||||||
|
void lightOn();
|
||||||
void stop();
|
void stop();
|
||||||
bool running() const { return running_; }
|
bool running() const { return running_; }
|
||||||
private:
|
private:
|
||||||
bool running_ = false;
|
bool running_ = false;
|
||||||
|
bool activeLightOn_ = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,16 +23,22 @@ bool Radio::begin() {
|
|||||||
if (esp_wifi_set_channel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE) != ESP_OK) {
|
if (esp_wifi_set_channel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE) != ESP_OK) {
|
||||||
Log::event("ESP-NOW", "Wi-Fi channel setup FAILED"); return false;
|
Log::event("ESP-NOW", "Wi-Fi channel setup FAILED"); return false;
|
||||||
}
|
}
|
||||||
queue_ = xQueueCreate(8, sizeof(ReceivedPacket));
|
if (!queue_) queue_ = xQueueCreate(8, sizeof(ReceivedPacket));
|
||||||
if (!queue_) { Log::event("ESP-NOW", "receive queue creation FAILED"); return false; }
|
if (!heartbeatQueue_) heartbeatQueue_ = xQueueCreate(4, sizeof(ReceivedPacket));
|
||||||
|
if (!heartbeatTask_ && xTaskCreate(heartbeatTaskEntry, "radio-hb", 2048, this, 5, &heartbeatTask_) != pdPASS)
|
||||||
|
heartbeatTask_ = nullptr;
|
||||||
|
if (!queue_ || !heartbeatQueue_ || !heartbeatTask_) {
|
||||||
|
Log::event("ESP-NOW", "receive/heartbeat service creation FAILED"); return false;
|
||||||
|
}
|
||||||
if (esp_now_init() != ESP_OK) {
|
if (esp_now_init() != ESP_OK) {
|
||||||
vQueueDelete(queue_); queue_ = nullptr;
|
|
||||||
Log::event("ESP-NOW", "initialization FAILED"); return false;
|
Log::event("ESP-NOW", "initialization FAILED"); return false;
|
||||||
}
|
}
|
||||||
const esp_err_t rateResult = esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_1M_L);
|
const esp_err_t rateResult = esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_1M_L);
|
||||||
instance_ = this;
|
instance_ = this;
|
||||||
if (esp_now_register_recv_cb(onReceive) != ESP_OK) { end(); return false; }
|
if (esp_now_register_recv_cb(onReceive) != ESP_OK) {
|
||||||
active_ = true;
|
instance_ = nullptr; esp_now_deinit(); return false;
|
||||||
|
}
|
||||||
|
active_ = true; __atomic_store_n(&lastValidRxMs_, millis(), __ATOMIC_RELAXED);
|
||||||
const bool ok = ensurePeer(BROADCAST_MAC);
|
const bool ok = ensurePeer(BROADCAST_MAC);
|
||||||
uint8_t primaryChannel = 0;
|
uint8_t primaryChannel = 0;
|
||||||
wifi_second_chan_t secondaryChannel = WIFI_SECOND_CHAN_NONE;
|
wifi_second_chan_t secondaryChannel = WIFI_SECOND_CHAN_NONE;
|
||||||
@@ -44,12 +50,45 @@ bool Radio::begin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Radio::end() {
|
void Radio::end() {
|
||||||
if (active_) { esp_now_unregister_recv_cb(); esp_now_deinit(); }
|
const bool wasActive = active_; active_ = false;
|
||||||
if (queue_) { vQueueDelete(queue_); queue_ = nullptr; }
|
if (wasActive) { esp_now_unregister_recv_cb(); esp_now_deinit(); }
|
||||||
active_ = false; if (instance_ == this) instance_ = nullptr;
|
if (queue_) xQueueReset(queue_);
|
||||||
|
if (heartbeatQueue_) xQueueReset(heartbeatQueue_);
|
||||||
|
if (instance_ == this) instance_ = nullptr;
|
||||||
|
windowedReceive_ = false;
|
||||||
|
if (wasActive) WiFi.mode(WIFI_OFF);
|
||||||
Log::event("ESP-NOW", "stopped");
|
Log::event("ESP-NOW", "stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Radio::setWindowedReceive(bool enabled) {
|
||||||
|
if (!active_) return false;
|
||||||
|
if (windowedReceive_ == enabled) return true;
|
||||||
|
|
||||||
|
const uint16_t window = enabled ? SLAVE_LISTEN_WINDOW_MS : UINT16_MAX;
|
||||||
|
const uint16_t interval = enabled ? SLAVE_LISTEN_INTERVAL_MS :
|
||||||
|
ESP_WIFI_CONNECTIONLESS_INTERVAL_DEFAULT_MODE;
|
||||||
|
const esp_err_t windowResult = esp_now_set_wake_window(window);
|
||||||
|
const esp_err_t intervalResult = esp_wifi_connectionless_module_set_wake_interval(interval);
|
||||||
|
const bool sleepResult = WiFi.setSleep(enabled);
|
||||||
|
const bool ok = windowResult == ESP_OK && intervalResult == ESP_OK && sleepResult;
|
||||||
|
|
||||||
|
bool continuousRestored = true;
|
||||||
|
if (!ok) {
|
||||||
|
continuousRestored = esp_now_set_wake_window(UINT16_MAX) == ESP_OK;
|
||||||
|
continuousRestored =
|
||||||
|
esp_wifi_connectionless_module_set_wake_interval(
|
||||||
|
ESP_WIFI_CONNECTIONLESS_INTERVAL_DEFAULT_MODE) == ESP_OK && continuousRestored;
|
||||||
|
continuousRestored = WiFi.setSleep(false) && continuousRestored;
|
||||||
|
windowedReceive_ = false;
|
||||||
|
} else windowedReceive_ = enabled;
|
||||||
|
|
||||||
|
Log::printf("ESP-NOW", "RX power-save %s window=%ums interval=%ums %s%s",
|
||||||
|
enabled ? "ON" : "OFF", window, interval,
|
||||||
|
ok ? "OK" : "FAILED; continuous RX restore ",
|
||||||
|
ok ? "" : (continuousRestored ? "OK" : "FAILED"));
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
bool Radio::ensurePeer(const uint8_t mac[6]) {
|
bool Radio::ensurePeer(const uint8_t mac[6]) {
|
||||||
if (esp_now_is_peer_exist(mac)) return true;
|
if (esp_now_is_peer_exist(mac)) return true;
|
||||||
esp_now_peer_info_t peer = {};
|
esp_now_peer_info_t peer = {};
|
||||||
@@ -72,7 +111,8 @@ bool Radio::sendTo(const uint8_t mac[6], ProtocolPacket p) {
|
|||||||
finalizePacket(p);
|
finalizePacket(p);
|
||||||
const bool ok = esp_now_send(mac, reinterpret_cast<const uint8_t *>(&p), sizeof(p)) == ESP_OK;
|
const bool ok = esp_now_send(mac, reinterpret_cast<const uint8_t *>(&p), sizeof(p)) == ESP_OK;
|
||||||
const MessageType type = static_cast<MessageType>(p.type);
|
const MessageType type = static_cast<MessageType>(p.type);
|
||||||
if (type != MessageType::HEARTBEAT && type != MessageType::HEARTBEAT_ACK)
|
if (type != MessageType::DISCOVER && type != MessageType::HEARTBEAT &&
|
||||||
|
type != MessageType::HEARTBEAT_ACK && type != MessageType::PROGRESS)
|
||||||
Log::printf("ESP-NOW", "TX %s to %s session=%08lX stage=%u seq=%u %s",
|
Log::printf("ESP-NOW", "TX %s to %s session=%08lX stage=%u seq=%u %s",
|
||||||
messageName(type), peer, p.session, p.stage, p.sequence, ok ? "QUEUED" : "FAILED");
|
messageName(type), peer, p.session, p.stage, p.sequence, ok ? "QUEUED" : "FAILED");
|
||||||
return ok;
|
return ok;
|
||||||
@@ -97,16 +137,37 @@ void Radio::maintainChannel() {
|
|||||||
restored ? "RESTORED" : "FAILED");
|
restored ? "RESTORED" : "FAILED");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Radio::flush() { if (queue_) xQueueReset(queue_); }
|
void Radio::flush() {
|
||||||
|
if (queue_) xQueueReset(queue_);
|
||||||
|
if (heartbeatQueue_) xQueueReset(heartbeatQueue_);
|
||||||
|
}
|
||||||
|
|
||||||
void Radio::onReceive(const esp_now_recv_info_t *info, const uint8_t *data, int length) {
|
void Radio::onReceive(const esp_now_recv_info_t *info, const uint8_t *data, int length) {
|
||||||
if (!instance_ || !instance_->queue_ || !info || length != sizeof(ProtocolPacket)) return;
|
if (!instance_ || !instance_->queue_ || !info || length != sizeof(ProtocolPacket)) return;
|
||||||
ReceivedPacket item;
|
ReceivedPacket item;
|
||||||
memcpy(item.mac, info->src_addr, 6); memcpy(&item.packet, data, sizeof(item.packet));
|
memcpy(item.mac, info->src_addr, 6); memcpy(&item.packet, data, sizeof(item.packet));
|
||||||
if (!validPacket(item.packet)) return;
|
if (!validPacket(item.packet)) return;
|
||||||
|
__atomic_store_n(&instance_->lastValidRxMs_, millis(), __ATOMIC_RELAXED);
|
||||||
|
if (static_cast<MessageType>(item.packet.type) == MessageType::HEARTBEAT && instance_->heartbeatQueue_)
|
||||||
|
xQueueSend(instance_->heartbeatQueue_, &item, 0);
|
||||||
xQueueSend(instance_->queue_, &item, 0); // Wi-Fi task callback: copy only, never block
|
xQueueSend(instance_->queue_, &item, 0); // Wi-Fi task callback: copy only, never block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Radio::heartbeatTaskEntry(void *context) {
|
||||||
|
static_cast<Radio *>(context)->heartbeatTaskLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Radio::heartbeatTaskLoop() {
|
||||||
|
ReceivedPacket item;
|
||||||
|
for (;;) {
|
||||||
|
if (xQueueReceive(heartbeatQueue_, &item, portMAX_DELAY) != pdTRUE || !active_) continue;
|
||||||
|
ProtocolPacket ack = item.packet;
|
||||||
|
ack.type = static_cast<uint8_t>(MessageType::HEARTBEAT_ACK);
|
||||||
|
finalizePacket(ack);
|
||||||
|
esp_now_send(item.mac, reinterpret_cast<const uint8_t *>(&ack), sizeof(ack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Radio::macText(const uint8_t mac[6], char *out, size_t n) {
|
void Radio::macText(const uint8_t mac[6], char *out, size_t n) {
|
||||||
snprintf(out, n, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
snprintf(out, n, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,23 @@ class Radio {
|
|||||||
bool sendBroadcast(ProtocolPacket packet);
|
bool sendBroadcast(ProtocolPacket packet);
|
||||||
bool sendTo(const uint8_t mac[6], ProtocolPacket packet);
|
bool sendTo(const uint8_t mac[6], ProtocolPacket packet);
|
||||||
bool receive(ReceivedPacket &received);
|
bool receive(ReceivedPacket &received);
|
||||||
|
bool setWindowedReceive(bool enabled);
|
||||||
void flush();
|
void flush();
|
||||||
|
uint32_t lastReceiveMs() const { return __atomic_load_n(&lastValidRxMs_, __ATOMIC_RELAXED); }
|
||||||
static void macText(const uint8_t mac[6], char *out, size_t size);
|
static void macText(const uint8_t mac[6], char *out, size_t size);
|
||||||
private:
|
private:
|
||||||
static void onReceive(const esp_now_recv_info_t *info, const uint8_t *data, int length);
|
static void onReceive(const esp_now_recv_info_t *info, const uint8_t *data, int length);
|
||||||
|
static void heartbeatTaskEntry(void *context);
|
||||||
|
void heartbeatTaskLoop();
|
||||||
bool ensurePeer(const uint8_t mac[6]);
|
bool ensurePeer(const uint8_t mac[6]);
|
||||||
void maintainChannel();
|
void maintainChannel();
|
||||||
static Radio *instance_;
|
static Radio *instance_;
|
||||||
QueueHandle_t queue_ = nullptr;
|
QueueHandle_t queue_ = nullptr;
|
||||||
bool active_ = false;
|
QueueHandle_t heartbeatQueue_ = nullptr;
|
||||||
|
TaskHandle_t heartbeatTask_ = nullptr;
|
||||||
|
volatile bool active_ = false;
|
||||||
|
volatile uint32_t lastValidRxMs_ = 0;
|
||||||
uint32_t lastChannelCheckMs_ = 0;
|
uint32_t lastChannelCheckMs_ = 0;
|
||||||
|
bool windowedReceive_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,71 @@
|
|||||||
#include "Receiver.h"
|
#include "Receiver.h"
|
||||||
#include "Config.h"
|
#include "Log.h"
|
||||||
#include <string.h>
|
#include <math.h>
|
||||||
#if !OPTICAL_USE_RMT_DMA
|
#if !OPTICAL_USE_MCPWM_CAPTURE
|
||||||
#include <esp_cpu.h>
|
#include <esp_cpu.h>
|
||||||
#include <esp32-hal-cpu.h>
|
#include <esp32-hal-cpu.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t PulseReceiver::tickHz() const {
|
uint32_t PulseReceiver::tickHz() const {
|
||||||
#if OPTICAL_USE_RMT_DMA
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
return CAPTURE_RESOLUTION_HZ;
|
return captureResolutionHz_;
|
||||||
|
#else
|
||||||
|
return cpuTickHz_;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PulseReceiver::plannedTickHz(uint32_t expectedHz, float expectedDutyPct) const {
|
||||||
|
if (!expectedHz || expectedDutyPct <= 0.0f || expectedDutyPct >= 100.0f) return 0;
|
||||||
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
|
return captureResolutionHz_ ? captureResolutionHz_ :
|
||||||
|
MCPWM_CAPTURE_RESOLUTION_HZ;
|
||||||
#else
|
#else
|
||||||
return cpuTickHz_;
|
return cpuTickHz_;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PulseReceiver::begin() {
|
bool PulseReceiver::begin() {
|
||||||
#if OPTICAL_USE_RMT_DMA
|
queue_ = xQueueCreate(512, sizeof(Edge));
|
||||||
queue_ = xQueueCreate(RMT_QUEUE_BLOCKS, sizeof(SymbolBlock));
|
|
||||||
rmt_rx_channel_config_t cfg = {};
|
|
||||||
cfg.clk_src = RMT_CLK_SRC_DEFAULT; cfg.resolution_hz = CAPTURE_RESOLUTION_HZ;
|
|
||||||
cfg.gpio_num = static_cast<gpio_num_t>(GPIO_RX);
|
|
||||||
cfg.flags.invert_in = RX_SIGNAL_INVERTED;
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32S3
|
|
||||||
cfg.mem_block_symbols = 512;
|
|
||||||
cfg.flags.with_dma = true;
|
|
||||||
#else
|
|
||||||
// C3 has 48 RMT symbols per channel and no RMT DMA. A request for 512
|
|
||||||
// consumes all available blocks and fails with "no free rx channels".
|
|
||||||
cfg.mem_block_symbols = RMT_MIN_RECEIVE_SYMBOLS;
|
|
||||||
cfg.flags.with_dma = false; // C3 uses hardware RMT ping-pong partial reception
|
|
||||||
#endif
|
|
||||||
if (!queue_ || rmt_new_rx_channel(&cfg, &channel_) != ESP_OK) return false;
|
|
||||||
rmt_rx_event_callbacks_t callbacks = {}; callbacks.on_recv_done = onRmt;
|
|
||||||
return rmt_rx_register_event_callbacks(channel_, &callbacks, this) == ESP_OK;
|
|
||||||
#else
|
|
||||||
queue_ = xQueueCreate(256, sizeof(Edge));
|
|
||||||
if (!queue_) return false;
|
if (!queue_) return false;
|
||||||
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
|
// PWM generation uses MCPWM group 0. Group 1 is dedicated to input capture,
|
||||||
|
// so RX cannot exhaust or conflict with the generator's resources.
|
||||||
|
mcpwm_capture_timer_config_t timerConfig = {};
|
||||||
|
timerConfig.group_id = 1;
|
||||||
|
timerConfig.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT;
|
||||||
|
timerConfig.resolution_hz = MCPWM_CAPTURE_RESOLUTION_HZ;
|
||||||
|
if (mcpwm_new_capture_timer(&timerConfig, &captureTimer_) != ESP_OK) return false;
|
||||||
|
if (mcpwm_capture_timer_get_resolution(captureTimer_, &captureResolutionHz_) != ESP_OK ||
|
||||||
|
!captureResolutionHz_) return false;
|
||||||
|
|
||||||
|
mcpwm_capture_channel_config_t channelConfig = {};
|
||||||
|
channelConfig.gpio_num = GPIO_RX;
|
||||||
|
// ACK pulses are sub-microsecond and consecutive acknowledgements can be
|
||||||
|
// only 1 us apart. A low-priority capture interrupt can leave the channel
|
||||||
|
// status pending long enough for the next timestamp to overwrite it.
|
||||||
|
channelConfig.intr_priority = 3;
|
||||||
|
channelConfig.prescale = 1;
|
||||||
|
channelConfig.flags.pos_edge = true;
|
||||||
|
channelConfig.flags.neg_edge = false;
|
||||||
|
if (mcpwm_new_capture_channel(captureTimer_, &channelConfig, &risingChannel_) != ESP_OK)
|
||||||
|
return false;
|
||||||
|
mcpwm_capture_event_callbacks_t callbacks = {};
|
||||||
|
callbacks.on_cap = onCapture;
|
||||||
|
if (mcpwm_capture_channel_register_event_callbacks(
|
||||||
|
risingChannel_, &callbacks, this) != ESP_OK) return false;
|
||||||
|
|
||||||
|
channelConfig.flags.pos_edge = false;
|
||||||
|
channelConfig.flags.neg_edge = true;
|
||||||
|
if (mcpwm_new_capture_channel(captureTimer_, &channelConfig, &fallingChannel_) != ESP_OK)
|
||||||
|
return false;
|
||||||
|
if (mcpwm_capture_channel_register_event_callbacks(
|
||||||
|
fallingChannel_, &callbacks, this) != ESP_OK) return false;
|
||||||
|
|
||||||
|
// The TX channel is created immediately before a driver test. Only the end
|
||||||
|
// of the active PWM pulse is armed; handling its start here would occupy the
|
||||||
|
// shared MCPWM ISR during the RX acknowledgement only ~300 ns later.
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
pinMode(GPIO_RX, INPUT);
|
pinMode(GPIO_RX, INPUT);
|
||||||
cpuTickHz_ = getCpuFrequencyMhz() * 1000000UL;
|
cpuTickHz_ = getCpuFrequencyMhz() * 1000000UL;
|
||||||
attachInterruptArg(GPIO_RX, onGpio, this, CHANGE);
|
attachInterruptArg(GPIO_RX, onGpio, this, CHANGE);
|
||||||
@@ -43,138 +73,402 @@ bool PulseReceiver::begin() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PulseReceiver::start(uint32_t expectedHz) {
|
bool PulseReceiver::start(uint32_t expectedHz, float expectedDutyPct,
|
||||||
|
bool activeLightOn) {
|
||||||
|
(void)activeLightOn;
|
||||||
|
if (!plannedTickHz(expectedHz, expectedDutyPct)) return false;
|
||||||
|
expectedHz_ = expectedHz;
|
||||||
|
expectedDutyPct_ = expectedDutyPct;
|
||||||
|
#if !OPTICAL_USE_MCPWM_CAPTURE
|
||||||
|
cpuTickHz_ = getCpuFrequencyMhz() * 1000000UL;
|
||||||
|
if (!cpuTickHz_) return false;
|
||||||
|
#endif
|
||||||
resetStream();
|
resetStream();
|
||||||
#if OPTICAL_USE_RMT_DMA
|
Log::event("CAPTURE", "RX optical polarity will be detected automatically");
|
||||||
// In partial RX mode the callback is delivered when this user buffer fills.
|
return startCapture(false);
|
||||||
// Keep chunks near 5 ms so low-frequency input is reported before NO SIGNAL.
|
}
|
||||||
uint64_t symbols = (static_cast<uint64_t>(expectedHz) * RMT_TARGET_CHUNK_US + 999999ULL) / 1000000ULL;
|
|
||||||
if (symbols < RMT_MIN_RECEIVE_SYMBOLS) symbols = RMT_MIN_RECEIVE_SYMBOLS;
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
if (symbols > RMT_MAX_RECEIVE_SYMBOLS) symbols = RMT_MAX_RECEIVE_SYMBOLS;
|
bool PulseReceiver::configureDriverTxCapture(bool risingEdge) {
|
||||||
receiveChunkSymbols_ = static_cast<uint16_t>(symbols);
|
if (running_) return false;
|
||||||
if (rmt_enable(channel_) != ESP_OK) return false;
|
if (txChannel_) {
|
||||||
rmt_receive_config_t cfg = {};
|
if (mcpwm_del_capture_channel(txChannel_) != ESP_OK) return false;
|
||||||
cfg.signal_range_min_ns = 20;
|
txChannel_ = nullptr;
|
||||||
const uint64_t maxNs = 4000000000ULL / (expectedHz ? expectedHz : 1);
|
}
|
||||||
cfg.signal_range_max_ns = maxNs > 100000000ULL ? 100000000UL : static_cast<uint32_t>(maxNs);
|
mcpwm_capture_channel_config_t config = {};
|
||||||
cfg.flags.en_partial_rx = true;
|
config.gpio_num = GPIO_PWM;
|
||||||
if (rmt_receive(channel_, receiveBuffer_,
|
config.intr_priority = 3;
|
||||||
receiveChunkSymbols_ * sizeof(receiveBuffer_[0]), &cfg) != ESP_OK) {
|
config.prescale = 1;
|
||||||
rmt_disable(channel_); return false;
|
config.flags.pos_edge = risingEdge;
|
||||||
|
config.flags.neg_edge = !risingEdge;
|
||||||
|
config.flags.io_loop_back = true;
|
||||||
|
if (mcpwm_new_capture_channel(captureTimer_, &config, &txChannel_) != ESP_OK)
|
||||||
|
return false;
|
||||||
|
mcpwm_capture_event_callbacks_t callbacks = {};
|
||||||
|
callbacks.on_cap = onCapture;
|
||||||
|
return mcpwm_capture_channel_register_event_callbacks(
|
||||||
|
txChannel_, &callbacks, this) == ESP_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool PulseReceiver::startDriver(uint32_t frequencyHz, uint32_t pulseNs,
|
||||||
|
bool activeTxLightOn) {
|
||||||
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
|
if (!frequencyHz || !pulseNs || !tickHz() || running_) return false;
|
||||||
|
resetStream();
|
||||||
|
const uint64_t pulseTicks =
|
||||||
|
(static_cast<uint64_t>(pulseNs) * tickHz() + 500000000ULL) /
|
||||||
|
1000000000ULL;
|
||||||
|
const uint32_t periodTicks = tickHz() / frequencyHz;
|
||||||
|
if (!pulseTicks || pulseTicks >= periodTicks || pulseTicks > UINT32_MAX)
|
||||||
|
return false;
|
||||||
|
driverPulseTicks_ = static_cast<uint32_t>(pulseTicks);
|
||||||
|
driverReleaseSlackTicks_ = static_cast<uint32_t>(
|
||||||
|
(static_cast<uint64_t>(DRIVER_RESPONSE_TIMEOUT_NS) * tickHz() +
|
||||||
|
999999999ULL) / 1000000000ULL);
|
||||||
|
const uint8_t activeRawLevel = activeTxLightOn ?
|
||||||
|
TX_LIGHT_ON_GPIO_LEVEL : TX_LIGHT_OFF_GPIO_LEVEL;
|
||||||
|
const bool pulseEndIsRising = activeRawLevel == LOW;
|
||||||
|
if (!driverReleaseSlackTicks_ ||
|
||||||
|
!configureDriverTxCapture(pulseEndIsRising)) return false;
|
||||||
|
return startCapture(true);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PulseReceiver::startCapture(bool withTx) {
|
||||||
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
|
// Progress updates keep one capture session alive. Pulse-width stages stop
|
||||||
|
// capture only after PWM is quiet, so resetStream never races the ISR.
|
||||||
|
if (running_) return true;
|
||||||
|
if (mcpwm_capture_timer_enable(captureTimer_) != ESP_OK) return false;
|
||||||
|
if (mcpwm_capture_channel_enable(risingChannel_) != ESP_OK) {
|
||||||
|
mcpwm_capture_timer_disable(captureTimer_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mcpwm_capture_channel_enable(fallingChannel_) != ESP_OK) {
|
||||||
|
mcpwm_capture_channel_disable(risingChannel_);
|
||||||
|
mcpwm_capture_timer_disable(captureTimer_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (withTx && mcpwm_capture_channel_enable(txChannel_) != ESP_OK) {
|
||||||
|
mcpwm_capture_channel_disable(fallingChannel_);
|
||||||
|
mcpwm_capture_channel_disable(risingChannel_);
|
||||||
|
mcpwm_capture_timer_disable(captureTimer_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
txCaptureEnabled_ = withTx;
|
||||||
|
running_ = true;
|
||||||
|
if (mcpwm_capture_timer_start(captureTimer_) != ESP_OK) {
|
||||||
|
running_ = false;
|
||||||
|
if (txCaptureEnabled_) mcpwm_capture_channel_disable(txChannel_);
|
||||||
|
txCaptureEnabled_ = false;
|
||||||
|
mcpwm_capture_channel_disable(fallingChannel_);
|
||||||
|
mcpwm_capture_channel_disable(risingChannel_);
|
||||||
|
mcpwm_capture_timer_disable(captureTimer_);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)expectedHz;
|
if (withTx) return false;
|
||||||
|
running_ = true;
|
||||||
#endif
|
#endif
|
||||||
running_ = true; return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseReceiver::stop() {
|
void PulseReceiver::stop() {
|
||||||
#if OPTICAL_USE_RMT_DMA
|
const bool wasRunning = running_;
|
||||||
if (running_) rmt_disable(channel_);
|
|
||||||
#endif
|
|
||||||
running_ = false;
|
running_ = false;
|
||||||
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
|
if (wasRunning) {
|
||||||
|
// Mask capture interrupts before stopping the shared capture timer.
|
||||||
|
if (txCaptureEnabled_) mcpwm_capture_channel_disable(txChannel_);
|
||||||
|
txCaptureEnabled_ = false;
|
||||||
|
mcpwm_capture_channel_disable(fallingChannel_);
|
||||||
|
mcpwm_capture_channel_disable(risingChannel_);
|
||||||
|
mcpwm_capture_timer_stop(captureTimer_);
|
||||||
|
mcpwm_capture_timer_disable(captureTimer_);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)wasRunning;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseReceiver::resetStream() {
|
void PulseReceiver::resetStream() {
|
||||||
if (queue_) xQueueReset(queue_);
|
if (queue_) xQueueReset(queue_);
|
||||||
overflow_ = false; droppedItems_ = 0; haveRise_ = haveFall_ = haveRawTick_ = false;
|
haveReorderEdge_ = false;
|
||||||
lastRawTick_ = 0; tickEpoch_ = rise_ = fall_ = 0;
|
__atomic_store_n(&driverRingWrite_, 0U, __ATOMIC_RELEASE);
|
||||||
#if OPTICAL_USE_RMT_DMA
|
__atomic_store_n(&driverRingRead_, 0U, __ATOMIC_RELEASE);
|
||||||
block_ = {}; blockIndex_ = 0; phase_ = 0; haveLevel_ = false; level_ = false; rmtTick_ = 0;
|
haveLastDriverEdge_ = false;
|
||||||
#endif
|
lastDriverEdge_ = {};
|
||||||
|
driverPulseTicks_ = 0;
|
||||||
|
driverReleaseSlackTicks_ = 0;
|
||||||
|
droppedItems_ = 0;
|
||||||
|
polarityKnown_ = false;
|
||||||
|
activeStartRising_ = false;
|
||||||
|
polarityEdgeCount_ = 0;
|
||||||
|
memset(polarityEdges_, 0, sizeof(polarityEdges_));
|
||||||
|
waitingForActiveEnd_ = true;
|
||||||
|
activeStart_ = activeEnd_ = 0;
|
||||||
|
haveRawTick_ = false;
|
||||||
|
lastRawTick_ = 0;
|
||||||
|
tickEpoch_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PulseReceiver::consumeEdge(const Edge &e, PulsePeriod &out) {
|
PulseReceiver::TimedEdge PulseReceiver::extendEdge(const Edge &e) {
|
||||||
if (haveRawTick_ && e.tick < lastRawTick_ && lastRawTick_ - e.tick > 0x80000000UL)
|
if (haveRawTick_ && e.tick < lastRawTick_ && lastRawTick_ - e.tick > 0x80000000UL)
|
||||||
tickEpoch_ += 0x100000000ULL;
|
tickEpoch_ += 0x100000000ULL;
|
||||||
haveRawTick_ = true; lastRawTick_ = e.tick;
|
haveRawTick_ = true; lastRawTick_ = e.tick;
|
||||||
const uint64_t tick = tickEpoch_ + e.tick;
|
return {tickEpoch_ + e.tick, e.rising != 0};
|
||||||
if (e.rising) {
|
|
||||||
if (!haveRise_) { rise_ = tick; haveRise_ = true; haveFall_ = false; return false; }
|
|
||||||
if (!haveFall_) { overflow_ = true; rise_ = tick; return false; }
|
|
||||||
const uint32_t period = static_cast<uint32_t>(tick - rise_);
|
|
||||||
const uint32_t active = fall_ - rise_;
|
|
||||||
out = {rise_, period, active}; rise_ = tick; haveFall_ = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Reception can begin in the middle of a HIGH pulse. In that case the first
|
|
||||||
// observable edge is falling and there is no complete period to validate.
|
|
||||||
// Ignore only this leading partial pulse and synchronize on the next rise.
|
|
||||||
if (!haveRise_) return false;
|
|
||||||
if (haveFall_) { overflow_ = true; return false; }
|
|
||||||
fall_ = tick; haveFall_ = true; return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PulseReceiver::overflowed() {
|
bool PulseReceiver::consumeEdge(const Edge &rawEdge, PulsePeriod &out) {
|
||||||
const bool value = overflow_; overflow_ = false; return value;
|
const TimedEdge edge = extendEdge(rawEdge);
|
||||||
|
if (polarityKnown_) {
|
||||||
|
// Deliberately ignore edge type after synchronization. A PWM waveform is
|
||||||
|
// just alternating intervals: active, inactive, active, inactive. An
|
||||||
|
// extra or missing edge therefore becomes a concrete wrong pulse/period
|
||||||
|
// instead of an ambiguous GLITCH state.
|
||||||
|
if (waitingForActiveEnd_) {
|
||||||
|
activeEnd_ = edge.tick;
|
||||||
|
waitingForActiveEnd_ = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const uint64_t periodTicks = edge.tick - activeStart_;
|
||||||
|
const uint64_t activeTicks = activeEnd_ - activeStart_;
|
||||||
|
out = {activeStart_, static_cast<uint32_t>(periodTicks),
|
||||||
|
static_cast<uint32_t>(activeTicks), tickHz()};
|
||||||
|
activeStart_ = edge.tick;
|
||||||
|
waitingForActiveEnd_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optical mode does not use the DRIVER level setting. Compare the first two
|
||||||
|
// alternating intervals with the configured active duration and select the
|
||||||
|
// level that is actually present at RX. Three edges are enough to determine
|
||||||
|
// polarity and, when the first interval is active, produce the first period.
|
||||||
|
polarityEdges_[polarityEdgeCount_++] = edge;
|
||||||
|
if (polarityEdgeCount_ < 3U) return false;
|
||||||
|
|
||||||
|
const uint64_t firstInterval =
|
||||||
|
polarityEdges_[1].tick - polarityEdges_[0].tick;
|
||||||
|
const uint64_t secondInterval =
|
||||||
|
polarityEdges_[2].tick - polarityEdges_[1].tick;
|
||||||
|
const uint64_t expectedPeriod = tickHz() / expectedHz_;
|
||||||
|
const uint64_t expectedActive = static_cast<uint64_t>(
|
||||||
|
expectedPeriod * expectedDutyPct_ / 100.0f + 0.5f);
|
||||||
|
const uint64_t firstError = firstInterval > expectedActive ?
|
||||||
|
firstInterval - expectedActive : expectedActive - firstInterval;
|
||||||
|
const uint64_t secondError = secondInterval > expectedActive ?
|
||||||
|
secondInterval - expectedActive : expectedActive - secondInterval;
|
||||||
|
const bool firstIntervalIsActive = firstError <= secondError;
|
||||||
|
activeStartRising_ = firstIntervalIsActive ? polarityEdges_[0].rising :
|
||||||
|
polarityEdges_[1].rising;
|
||||||
|
polarityKnown_ = true;
|
||||||
|
polarityEdgeCount_ = 0;
|
||||||
|
|
||||||
|
if (firstIntervalIsActive) {
|
||||||
|
out = {polarityEdges_[0].tick,
|
||||||
|
static_cast<uint32_t>(polarityEdges_[2].tick - polarityEdges_[0].tick),
|
||||||
|
static_cast<uint32_t>(firstInterval), tickHz()};
|
||||||
|
activeStart_ = polarityEdges_[2].tick;
|
||||||
|
waitingForActiveEnd_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeStart_ = polarityEdges_[1].tick;
|
||||||
|
activeEnd_ = polarityEdges_[2].tick;
|
||||||
|
waitingForActiveEnd_ = false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PulseReceiver::takeDroppedItems() {
|
uint32_t PulseReceiver::takeDroppedItems() {
|
||||||
return __atomic_exchange_n(&droppedItems_, 0, __ATOMIC_RELAXED);
|
return __atomic_exchange_n(&droppedItems_, 0, __ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OPTICAL_USE_RMT_DMA
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
bool IRAM_ATTR PulseReceiver::onRmt(rmt_channel_handle_t, const rmt_rx_done_event_data_t *data, void *ctx) {
|
bool IRAM_ATTR PulseReceiver::onCapture(mcpwm_cap_channel_handle_t channel,
|
||||||
|
const mcpwm_capture_event_data_t *data,
|
||||||
|
void *ctx) {
|
||||||
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
||||||
|
if (!self->running_) return false;
|
||||||
|
const bool rawRising = data->cap_edge == MCPWM_CAP_EDGE_POS;
|
||||||
|
const Edge edge = {data->cap_value, static_cast<uint8_t>(rawRising),
|
||||||
|
static_cast<uint8_t>(channel == self->txChannel_ ? CaptureSource::TX :
|
||||||
|
CaptureSource::RX)};
|
||||||
|
if (self->txCaptureEnabled_) {
|
||||||
|
// All channels in one MCPWM group are dispatched serially by the same
|
||||||
|
// group ISR. Keep this callback shorter than the minimum interval between
|
||||||
|
// equal RX edges (about 2.1 us at W=2 us): a spinlock and several atomic
|
||||||
|
// RMW operations here can leave the channel pending until its capture
|
||||||
|
// register is overwritten by the next edge.
|
||||||
|
if (self->haveLastDriverEdge_ &&
|
||||||
|
self->lastDriverEdge_.tick == edge.tick &&
|
||||||
|
self->lastDriverEdge_.rising == edge.rising &&
|
||||||
|
self->lastDriverEdge_.source == edge.source) {
|
||||||
|
// The same channel callback can be delivered twice while several MCPWM
|
||||||
|
// capture status bits are pending. Two physical edges cannot have the
|
||||||
|
// same source, direction and 12.5 ns hardware timestamp.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const uint16_t write = self->driverRingWrite_;
|
||||||
|
const uint16_t next = static_cast<uint16_t>(
|
||||||
|
(write + 1U) & (DRIVER_RING_CAPACITY - 1U));
|
||||||
|
if (next == self->driverRingRead_) {
|
||||||
|
++self->droppedItems_;
|
||||||
|
} else {
|
||||||
|
self->driverRing_[write] = edge;
|
||||||
|
self->lastDriverEdge_ = edge;
|
||||||
|
self->haveLastDriverEdge_ = true;
|
||||||
|
asm volatile("memw" ::: "memory");
|
||||||
|
self->driverRingWrite_ = next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
BaseType_t wake = pdFALSE;
|
BaseType_t wake = pdFALSE;
|
||||||
size_t offset = 0;
|
if (xQueueSendFromISR(self->queue_, &edge, &wake) != pdTRUE)
|
||||||
while (offset < data->num_symbols) {
|
__atomic_fetch_add(&self->droppedItems_, 1U, __ATOMIC_RELAXED);
|
||||||
SymbolBlock &b = self->isrBlock_;
|
|
||||||
b.count = static_cast<uint16_t>((data->num_symbols - offset) > BLOCK_SYMBOLS ?
|
|
||||||
BLOCK_SYMBOLS : (data->num_symbols - offset));
|
|
||||||
memcpy(b.symbols, data->received_symbols + offset, b.count * sizeof(rmt_symbol_word_t));
|
|
||||||
if (xQueueSendFromISR(self->queue_, &b, &wake) != pdTRUE)
|
|
||||||
__atomic_fetch_add(&self->droppedItems_, b.count, __ATOMIC_RELAXED);
|
|
||||||
offset += b.count;
|
|
||||||
}
|
|
||||||
return wake == pdTRUE;
|
return wake == pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PulseReceiver::nextRmtEdge(Edge &edge) {
|
|
||||||
for (;;) {
|
|
||||||
if (blockIndex_ >= block_.count) {
|
|
||||||
if (xQueueReceive(queue_, &block_, 0) != pdTRUE) return false;
|
|
||||||
blockIndex_ = 0; phase_ = 0;
|
|
||||||
}
|
|
||||||
const rmt_symbol_word_t &s = block_.symbols[blockIndex_];
|
|
||||||
const bool nextLevel = phase_ == 0 ? s.level0 : s.level1;
|
|
||||||
const uint32_t duration = phase_ == 0 ? s.duration0 : s.duration1;
|
|
||||||
phase_ ^= 1;
|
|
||||||
if (phase_ == 0) ++blockIndex_;
|
|
||||||
if (!duration) continue;
|
|
||||||
if (!haveLevel_) { haveLevel_ = true; level_ = nextLevel; rmtTick_ += duration; continue; }
|
|
||||||
if (nextLevel != level_) {
|
|
||||||
level_ = nextLevel; edge = {rmtTick_, static_cast<uint8_t>(nextLevel)};
|
|
||||||
rmtTick_ += duration; return true;
|
|
||||||
}
|
|
||||||
rmtTick_ += duration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t PulseReceiver::readPeriods(PulsePeriod *periods, size_t capacity) {
|
|
||||||
size_t count = 0;
|
|
||||||
Edge e;
|
|
||||||
while (count < capacity && nextRmtEdge(e))
|
|
||||||
if (consumeEdge(e, periods[count])) ++count;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
void IRAM_ATTR PulseReceiver::onGpio(void *ctx) {
|
void IRAM_ATTR PulseReceiver::onGpio(void *ctx) {
|
||||||
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
PulseReceiver *self = static_cast<PulseReceiver *>(ctx);
|
||||||
bool level = gpio_get_level(static_cast<gpio_num_t>(GPIO_RX));
|
if (!self->running_) return;
|
||||||
if (RX_SIGNAL_INVERTED) level = !level;
|
const bool level = gpio_get_level(static_cast<gpio_num_t>(GPIO_RX));
|
||||||
Edge e = {esp_cpu_get_cycle_count(), static_cast<uint8_t>(level)};
|
const Edge edge = {esp_cpu_get_cycle_count(), static_cast<uint8_t>(level),
|
||||||
|
static_cast<uint8_t>(CaptureSource::RX)};
|
||||||
BaseType_t wake = pdFALSE;
|
BaseType_t wake = pdFALSE;
|
||||||
if (xQueueSendFromISR(self->queue_, &e, &wake) != pdTRUE)
|
if (xQueueSendFromISR(self->queue_, &edge, &wake) != pdTRUE)
|
||||||
__atomic_fetch_add(&self->droppedItems_, 1U, __ATOMIC_RELAXED);
|
__atomic_fetch_add(&self->droppedItems_, 1U, __ATOMIC_RELAXED);
|
||||||
if (wake) portYIELD_FROM_ISR();
|
if (wake) portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t PulseReceiver::readPeriods(PulsePeriod *periods, size_t capacity) {
|
bool PulseReceiver::nextOrderedEdge(Edge &edge, TickType_t waitTicks) {
|
||||||
|
if (!haveReorderEdge_) {
|
||||||
|
if (xQueueReceive(queue_, &reorderEdge_, waitTicks) != pdTRUE) return false;
|
||||||
|
haveReorderEdge_ = true;
|
||||||
|
}
|
||||||
|
Edge next = {};
|
||||||
|
// Keep one-event look-ahead. If both channel interrupts were pending while
|
||||||
|
// OLED/I2C ran, the MCPWM driver may dispatch them by channel number rather
|
||||||
|
// than timestamp. The signed modular comparison restores their real order.
|
||||||
|
if (xQueueReceive(queue_, &next, waitTicks) != pdTRUE) return false;
|
||||||
|
if (static_cast<int32_t>(next.tick - reorderEdge_.tick) < 0) {
|
||||||
|
edge = next;
|
||||||
|
} else {
|
||||||
|
edge = reorderEdge_;
|
||||||
|
reorderEdge_ = next;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PulseReceiver::readPeriods(PulsePeriod *periods, size_t capacity,
|
||||||
|
TickType_t waitTicks) {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
Edge e;
|
Edge edge = {};
|
||||||
while (count < capacity && xQueueReceive(queue_, &e, 0) == pdTRUE)
|
while (count < capacity && nextOrderedEdge(edge, count ? 0 : waitTicks)) {
|
||||||
if (consumeEdge(e, periods[count])) ++count;
|
if (consumeEdge(edge, periods[count])) {
|
||||||
|
periods[count].activeTickHz = tickHz();
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PulseReceiver::readEvents(CaptureEvent *events, size_t capacity,
|
||||||
|
TickType_t waitTicks) {
|
||||||
|
if (!events || capacity < 3U || !txCaptureEnabled_ || !driverPulseTicks_ ||
|
||||||
|
!driverReleaseSlackTicks_) return 0;
|
||||||
|
|
||||||
|
constexpr size_t MAX_BATCH = 64;
|
||||||
|
const size_t limit = capacity < MAX_BATCH ? capacity : MAX_BATCH;
|
||||||
|
Edge ordered[MAX_BATCH] = {};
|
||||||
|
|
||||||
|
uint16_t read = __atomic_load_n(&driverRingRead_, __ATOMIC_RELAXED);
|
||||||
|
if (read == __atomic_load_n(&driverRingWrite_, __ATOMIC_ACQUIRE) && waitTicks) {
|
||||||
|
vTaskDelay(waitTicks);
|
||||||
|
read = __atomic_load_n(&driverRingRead_, __ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
// Work on one immutable producer snapshot. RX belonging to a pulse start is
|
||||||
|
// deliberately retained until that pulse's captured end arrives: only then
|
||||||
|
// can the missing start interrupt be reconstructed and sorted before RX.
|
||||||
|
const uint16_t write = __atomic_load_n(&driverRingWrite_, __ATOMIC_ACQUIRE);
|
||||||
|
uint16_t scan = read;
|
||||||
|
bool haveLatestTxEnd = false;
|
||||||
|
bool haveReleaseTxEnd = false;
|
||||||
|
uint32_t latestTxEnd = 0;
|
||||||
|
uint32_t releaseTxEnd = 0;
|
||||||
|
size_t projectedCount = 0;
|
||||||
|
while (scan != write) {
|
||||||
|
const Edge &edge = driverRing_[scan];
|
||||||
|
const size_t needed = edge.source == static_cast<uint8_t>(CaptureSource::TX)
|
||||||
|
? 2U : 1U;
|
||||||
|
// Reserve one output slot for WINDOW_END.
|
||||||
|
if (projectedCount + needed + 1U > limit) break;
|
||||||
|
projectedCount += needed;
|
||||||
|
if (edge.source == static_cast<uint8_t>(CaptureSource::TX)) {
|
||||||
|
if (haveLatestTxEnd) {
|
||||||
|
releaseTxEnd = latestTxEnd;
|
||||||
|
haveReleaseTxEnd = true;
|
||||||
|
}
|
||||||
|
latestTxEnd = edge.tick;
|
||||||
|
haveLatestTxEnd = true;
|
||||||
|
}
|
||||||
|
scan = static_cast<uint16_t>((scan + 1U) % DRIVER_RING_CAPACITY);
|
||||||
|
}
|
||||||
|
// Keep the newest TX period in the ring. Arrival of the following TX end
|
||||||
|
// proves that the previous end's ACK/fault window has completely elapsed.
|
||||||
|
if (!haveReleaseTxEnd) {
|
||||||
|
if (waitTicks) vTaskDelay(waitTicks);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t releaseThrough = releaseTxEnd + driverReleaseSlackTicks_;
|
||||||
|
size_t count = 0;
|
||||||
|
while (read != write) {
|
||||||
|
const Edge edge = driverRing_[read];
|
||||||
|
if (edge.source == static_cast<uint8_t>(CaptureSource::TX) &&
|
||||||
|
static_cast<int32_t>(edge.tick - releaseTxEnd) > 0)
|
||||||
|
break;
|
||||||
|
if (edge.source == static_cast<uint8_t>(CaptureSource::RX) &&
|
||||||
|
static_cast<int32_t>(edge.tick - releaseThrough) > 0)
|
||||||
|
break;
|
||||||
|
const size_t needed = edge.source == static_cast<uint8_t>(CaptureSource::TX)
|
||||||
|
? 2U : 1U;
|
||||||
|
if (count + needed > limit) break;
|
||||||
|
read = static_cast<uint16_t>((read + 1U) % DRIVER_RING_CAPACITY);
|
||||||
|
if (edge.source == static_cast<uint8_t>(CaptureSource::TX)) {
|
||||||
|
Edge pulseStart = edge;
|
||||||
|
pulseStart.tick -= driverPulseTicks_;
|
||||||
|
pulseStart.rising = !edge.rising;
|
||||||
|
ordered[count++] = pulseStart;
|
||||||
|
}
|
||||||
|
ordered[count++] = edge;
|
||||||
|
}
|
||||||
|
__atomic_store_n(&driverRingRead_, read, __ATOMIC_RELEASE);
|
||||||
|
|
||||||
|
// MCPWM channels share one timer but their callbacks can be dispatched in
|
||||||
|
// channel order when several interrupts are pending. Restore the hardware
|
||||||
|
// order inside the captured batch using the common timestamp.
|
||||||
|
for (size_t i = 1; i < count; ++i) {
|
||||||
|
const Edge key = ordered[i];
|
||||||
|
size_t j = i;
|
||||||
|
while (j && static_cast<int32_t>(ordered[j - 1].tick - key.tick) > 0) {
|
||||||
|
ordered[j] = ordered[j - 1];
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
ordered[j] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
const TimedEdge timed = extendEdge(ordered[i]);
|
||||||
|
events[i] = {timed.tick, timed.rising,
|
||||||
|
static_cast<CaptureSource>(ordered[i].source)};
|
||||||
|
}
|
||||||
|
const Edge marker = {releaseThrough, 0,
|
||||||
|
static_cast<uint8_t>(CaptureSource::WINDOW_END)};
|
||||||
|
const TimedEdge timedMarker = extendEdge(marker);
|
||||||
|
events[count++] = {timedMarker.tick, false, CaptureSource::WINDOW_END};
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,63 +1,90 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <esp_idf_version.h>
|
#include <esp_idf_version.h>
|
||||||
|
#include <driver/gpio.h>
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
|
|
||||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
|
#if CONFIG_IDF_TARGET_ESP32S3 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
|
||||||
#define OPTICAL_USE_RMT_DMA 1
|
#define OPTICAL_USE_MCPWM_CAPTURE 1
|
||||||
#include <driver/rmt_rx.h>
|
#include <driver/mcpwm_cap.h>
|
||||||
#else
|
#else
|
||||||
#define OPTICAL_USE_RMT_DMA 0
|
#define OPTICAL_USE_MCPWM_CAPTURE 0
|
||||||
#include <driver/gpio.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum class CaptureSource : uint8_t { RX, TX, WINDOW_END };
|
||||||
|
|
||||||
|
struct CaptureEvent {
|
||||||
|
uint64_t tick;
|
||||||
|
bool rising;
|
||||||
|
CaptureSource source;
|
||||||
|
};
|
||||||
|
|
||||||
class PulseReceiver {
|
class PulseReceiver {
|
||||||
public:
|
public:
|
||||||
bool begin();
|
bool begin();
|
||||||
bool start(uint32_t expectedHz);
|
bool start(uint32_t expectedHz, float expectedDutyPct, bool activeLightOn);
|
||||||
|
bool startDriver(uint32_t frequencyHz, uint32_t pulseNs,
|
||||||
|
bool activeTxLightOn);
|
||||||
void stop();
|
void stop();
|
||||||
void resetStream();
|
void resetStream();
|
||||||
size_t readPeriods(PulsePeriod *periods, size_t capacity);
|
size_t readPeriods(PulsePeriod *periods, size_t capacity, TickType_t waitTicks = 0);
|
||||||
bool overflowed();
|
size_t readEvents(CaptureEvent *events, size_t capacity, TickType_t waitTicks = 0);
|
||||||
uint32_t takeDroppedItems();
|
uint32_t takeDroppedItems();
|
||||||
uint32_t tickHz() const;
|
uint32_t tickHz() const;
|
||||||
uint16_t receiveChunkSymbols() const { return receiveChunkSymbols_; }
|
uint32_t pulseTickHz() const { return tickHz(); }
|
||||||
bool highRateBackend() const {
|
uint32_t plannedTickHz(uint32_t expectedHz, float expectedDutyPct) const;
|
||||||
#if OPTICAL_USE_RMT_DMA && CONFIG_IDF_TARGET_ESP32S3
|
uint32_t plannedPulseTickHz(uint32_t expectedHz, float expectedDutyPct) const {
|
||||||
return true;
|
return plannedTickHz(expectedHz, expectedDutyPct);
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
private:
|
uint16_t receiveChunkSymbols() const { return 1; }
|
||||||
struct Edge { uint32_t tick; uint8_t rising; };
|
bool highRateBackend() const { return OPTICAL_USE_MCPWM_CAPTURE; }
|
||||||
bool consumeEdge(const Edge &edge, PulsePeriod &period);
|
|
||||||
|
|
||||||
#if OPTICAL_USE_RMT_DMA
|
private:
|
||||||
static constexpr size_t BLOCK_SYMBOLS = RMT_MAX_RECEIVE_SYMBOLS;
|
struct Edge { uint32_t tick; uint8_t rising; uint8_t source; };
|
||||||
struct SymbolBlock { uint16_t count; rmt_symbol_word_t symbols[BLOCK_SYMBOLS]; };
|
static constexpr uint16_t DRIVER_RING_CAPACITY = 512;
|
||||||
static bool IRAM_ATTR onRmt(rmt_channel_handle_t, const rmt_rx_done_event_data_t *, void *);
|
static_assert((DRIVER_RING_CAPACITY & (DRIVER_RING_CAPACITY - 1U)) == 0,
|
||||||
bool nextRmtEdge(Edge &edge);
|
"driver capture ring must be a power of two");
|
||||||
rmt_channel_handle_t channel_ = nullptr;
|
struct TimedEdge { uint64_t tick; bool rising; };
|
||||||
rmt_symbol_word_t receiveBuffer_[RMT_MAX_RECEIVE_SYMBOLS];
|
bool startCapture(bool withTx);
|
||||||
uint16_t receiveChunkSymbols_ = 0;
|
bool consumeEdge(const Edge &edge, PulsePeriod &period);
|
||||||
SymbolBlock isrBlock_ = {};
|
bool nextOrderedEdge(Edge &edge, TickType_t waitTicks);
|
||||||
SymbolBlock block_ = {};
|
TimedEdge extendEdge(const Edge &edge);
|
||||||
uint16_t blockIndex_ = 0;
|
#if OPTICAL_USE_MCPWM_CAPTURE
|
||||||
uint8_t phase_ = 0;
|
bool configureDriverTxCapture(bool risingEdge);
|
||||||
bool haveLevel_ = false;
|
static bool IRAM_ATTR onCapture(mcpwm_cap_channel_handle_t,
|
||||||
bool level_ = false;
|
const mcpwm_capture_event_data_t *, void *);
|
||||||
uint32_t rmtTick_ = 0;
|
mcpwm_cap_timer_handle_t captureTimer_ = nullptr;
|
||||||
|
mcpwm_cap_channel_handle_t risingChannel_ = nullptr;
|
||||||
|
mcpwm_cap_channel_handle_t fallingChannel_ = nullptr;
|
||||||
|
mcpwm_cap_channel_handle_t txChannel_ = nullptr;
|
||||||
|
uint32_t captureResolutionHz_ = 0;
|
||||||
#else
|
#else
|
||||||
static void IRAM_ATTR onGpio(void *ctx);
|
static void IRAM_ATTR onGpio(void *ctx);
|
||||||
uint32_t cpuTickHz_ = 0;
|
uint32_t cpuTickHz_ = 0;
|
||||||
#endif
|
#endif
|
||||||
QueueHandle_t queue_ = nullptr;
|
QueueHandle_t queue_ = nullptr;
|
||||||
volatile bool overflow_ = false;
|
Edge driverRing_[DRIVER_RING_CAPACITY] = {};
|
||||||
|
volatile uint16_t driverRingWrite_ = 0;
|
||||||
|
volatile uint16_t driverRingRead_ = 0;
|
||||||
|
portMUX_TYPE driverRingMux_ = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
Edge lastDriverEdge_ = {};
|
||||||
|
bool haveLastDriverEdge_ = false;
|
||||||
|
uint32_t driverPulseTicks_ = 0;
|
||||||
|
uint32_t driverReleaseSlackTicks_ = 0;
|
||||||
|
Edge reorderEdge_ = {};
|
||||||
|
bool haveReorderEdge_ = false;
|
||||||
volatile uint32_t droppedItems_ = 0;
|
volatile uint32_t droppedItems_ = 0;
|
||||||
bool running_ = false;
|
volatile bool running_ = false;
|
||||||
bool haveRise_ = false, haveFall_ = false, haveRawTick_ = false;
|
volatile bool txCaptureEnabled_ = false;
|
||||||
|
uint32_t expectedHz_ = 0;
|
||||||
|
float expectedDutyPct_ = 50.0f;
|
||||||
|
bool polarityKnown_ = false, activeStartRising_ = false;
|
||||||
|
TimedEdge polarityEdges_[3] = {};
|
||||||
|
uint8_t polarityEdgeCount_ = 0;
|
||||||
|
bool waitingForActiveEnd_ = true;
|
||||||
|
uint64_t activeStart_ = 0, activeEnd_ = 0;
|
||||||
|
bool haveRawTick_ = false;
|
||||||
uint32_t lastRawTick_ = 0;
|
uint32_t lastRawTick_ = 0;
|
||||||
uint64_t tickEpoch_ = 0, rise_ = 0, fall_ = 0;
|
uint64_t tickEpoch_ = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,20 +3,36 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
|
|
||||||
namespace { constexpr uint16_t SETTINGS_VERSION = 1; constexpr char NAMESPACE[] = "opt-test"; }
|
// testGroup/boardTest reuse the former zeroed reserved bytes, so version 11
|
||||||
|
// settings remain binary-compatible and keep the user's optical parameters.
|
||||||
|
namespace { constexpr uint16_t SETTINGS_VERSION = 11; constexpr char NAMESPACE[] = "opt-test"; }
|
||||||
|
|
||||||
void SettingsStore::defaults(Settings &s) const {
|
void SettingsStore::defaults(Settings &s) const {
|
||||||
s = {SETTINGS_VERSION, static_cast<uint8_t>(Role::SOLO), 0, 4, 1, 2, 3, 2, 2, 0};
|
// 2 kHz, 200 us .. 2 us, 5%, 1 s.
|
||||||
|
s = {SETTINGS_VERSION, static_cast<uint8_t>(Role::SOLO),
|
||||||
|
static_cast<uint8_t>(TestKind::OPTICAL), static_cast<uint8_t>(LightCode::HH),
|
||||||
|
2, 6, 3, 2, 3, static_cast<uint8_t>(TestGroup::OPTICS),
|
||||||
|
static_cast<uint8_t>(BoardTest::ADC), 0};
|
||||||
s.checksum = settingsChecksum(s);
|
s.checksum = settingsChecksum(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SettingsStore::valid(const Settings &s) const {
|
bool SettingsStore::valid(const Settings &s) const {
|
||||||
return s.version == SETTINGS_VERSION && s.role <= static_cast<uint8_t>(Role::SLAVE) &&
|
return s.version == SETTINGS_VERSION && s.role <= static_cast<uint8_t>(Role::SLAVE) &&
|
||||||
s.startIndex < countOf(START_FREQ_OPTIONS_HZ) && s.endIndex < countOf(END_FREQ_OPTIONS_HZ) &&
|
s.testGroup <= static_cast<uint8_t>(TestGroup::BOARD) &&
|
||||||
s.stepIndex < countOf(STEP_OPTIONS_HZ) && s.accuracyIndex < countOf(ACCURACY_OPTIONS_PCT) &&
|
s.boardTest <= static_cast<uint8_t>(BoardTest::RX_INPUT) &&
|
||||||
s.timeIndex < countOf(TEST_TIME_OPTIONS_MS) && s.repeatIndex < countOf(REPEAT_OPTIONS) &&
|
s.testKind <= static_cast<uint8_t>(TestKind::DRIVER) &&
|
||||||
s.dutyIndex < countOf(DUTY_OPTIONS_PCT) && s.checksum == settingsChecksum(s) &&
|
s.lightCode <= static_cast<uint8_t>(LightCode::LL) &&
|
||||||
END_FREQ_OPTIONS_HZ[s.endIndex] > START_FREQ_OPTIONS_HZ[s.startIndex];
|
(s.testKind != static_cast<uint8_t>(TestKind::DRIVER) ||
|
||||||
|
s.role == static_cast<uint8_t>(Role::SOLO)) &&
|
||||||
|
s.frequencyIndex < countOf(PWM_FREQUENCY_OPTIONS_HZ) &&
|
||||||
|
s.maxPulseIndex < countOf(MAX_PULSE_OPTIONS_NS) &&
|
||||||
|
s.minPulseIndex < countOf(MIN_PULSE_OPTIONS_NS) &&
|
||||||
|
MAX_PULSE_OPTIONS_NS[s.maxPulseIndex] >= MIN_PULSE_OPTIONS_NS[s.minPulseIndex] &&
|
||||||
|
static_cast<uint64_t>(MAX_PULSE_OPTIONS_NS[s.maxPulseIndex]) *
|
||||||
|
PWM_FREQUENCY_OPTIONS_HZ[s.frequencyIndex] < 1000000000ULL &&
|
||||||
|
s.accuracyIndex < countOf(ACCURACY_OPTIONS_PCT) &&
|
||||||
|
s.timeIndex < countOf(TEST_TIME_OPTIONS_MS) &&
|
||||||
|
s.checksum == settingsChecksum(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SettingsStore::load(Settings &s) {
|
bool SettingsStore::load(Settings &s) {
|
||||||
@@ -39,8 +55,7 @@ bool SettingsStore::save(Settings &s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TestParams SettingsStore::params(const Settings &s) const {
|
TestParams SettingsStore::params(const Settings &s) const {
|
||||||
return {START_FREQ_OPTIONS_HZ[s.startIndex], END_FREQ_OPTIONS_HZ[s.endIndex],
|
return {PWM_FREQUENCY_OPTIONS_HZ[s.frequencyIndex],
|
||||||
STEP_OPTIONS_HZ[s.stepIndex], ACCURACY_OPTIONS_PCT[s.accuracyIndex],
|
MAX_PULSE_OPTIONS_NS[s.maxPulseIndex], MIN_PULSE_OPTIONS_NS[s.minPulseIndex],
|
||||||
TEST_TIME_OPTIONS_MS[s.timeIndex], REPEAT_OPTIONS[s.repeatIndex],
|
ACCURACY_OPTIONS_PCT[s.accuracyIndex], TEST_TIME_OPTIONS_MS[s.timeIndex]};
|
||||||
DUTY_OPTIONS_PCT[s.dutyIndex]};
|
|
||||||
}
|
}
|
||||||
|
|||||||
1866
PCB/GerberManufacture/OptoTest.GBL
Normal file
1866
PCB/GerberManufacture/OptoTest.GBL
Normal file
@@ -0,0 +1,1866 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Physical_Order=3*
|
||||||
|
G04 Layer_Color=16711680*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD19R,1.2000X1.4000*%
|
||||||
|
%ADD20R,1.3000X1.5000*%
|
||||||
|
%ADD21R,1.5000X1.3000*%
|
||||||
|
%ADD22R,1.4000X1.2000*%
|
||||||
|
%ADD43C,0.8000*%
|
||||||
|
%ADD44C,1.5240*%
|
||||||
|
%ADD45C,1.7000*%
|
||||||
|
%ADD46O,2.4000X1.8000*%
|
||||||
|
%ADD47C,1.5000*%
|
||||||
|
%ADD48R,1.5000X1.5000*%
|
||||||
|
%ADD49R,1.5000X1.5000*%
|
||||||
|
%ADD50C,3.0000*%
|
||||||
|
%ADD51C,2.0000*%
|
||||||
|
%ADD52C,1.8000*%
|
||||||
|
%ADD53R,1.8000X1.8000*%
|
||||||
|
%ADD54C,1.6000*%
|
||||||
|
%ADD55R,1.6000X1.6000*%
|
||||||
|
%ADD56R,1.7000X1.7000*%
|
||||||
|
%ADD57R,1.6000X1.6000*%
|
||||||
|
%ADD58C,1.6000*%
|
||||||
|
G04:AMPARAMS|DCode=59|XSize=2.3mm|YSize=1.8mm|CornerRadius=0.225mm|HoleSize=0mm|Usage=FLASHONLY|Rotation=0.000|XOffset=0mm|YOffset=0mm|HoleType=Round|Shape=RoundedRectangle|*
|
||||||
|
%AMROUNDEDRECTD59*
|
||||||
|
21,1,2.3000,1.3500,0,0,0.0*
|
||||||
|
21,1,1.8500,1.8000,0,0,0.0*
|
||||||
|
1,1,0.4500,0.9250,-0.6750*
|
||||||
|
1,1,0.4500,-0.9250,-0.6750*
|
||||||
|
1,1,0.4500,-0.9250,0.6750*
|
||||||
|
1,1,0.4500,0.9250,0.6750*
|
||||||
|
%
|
||||||
|
%ADD59ROUNDEDRECTD59*%
|
||||||
|
G36*
|
||||||
|
X164097Y490000D02*
|
||||||
|
X167924Y480761D01*
|
||||||
|
X133581Y446419D01*
|
||||||
|
X132139Y444539D01*
|
||||||
|
X131232Y442350D01*
|
||||||
|
X130922Y440000D01*
|
||||||
|
Y403760D01*
|
||||||
|
X93581Y366419D01*
|
||||||
|
X92139Y364539D01*
|
||||||
|
X91232Y362349D01*
|
||||||
|
X90922Y360000D01*
|
||||||
|
Y320166D01*
|
||||||
|
X88190Y317602D01*
|
||||||
|
X80922Y313286D01*
|
||||||
|
X80000Y313408D01*
|
||||||
|
X76737Y312978D01*
|
||||||
|
X73696Y311719D01*
|
||||||
|
X71085Y309715D01*
|
||||||
|
X69081Y307104D01*
|
||||||
|
X67822Y304063D01*
|
||||||
|
X67392Y300800D01*
|
||||||
|
X67822Y297537D01*
|
||||||
|
X69081Y294496D01*
|
||||||
|
X71085Y290946D01*
|
||||||
|
Y285254D01*
|
||||||
|
X69081Y281704D01*
|
||||||
|
X67822Y278663D01*
|
||||||
|
X67392Y275400D01*
|
||||||
|
X67822Y272137D01*
|
||||||
|
X69001Y269289D01*
|
||||||
|
X69081Y269096D01*
|
||||||
|
X71085Y263368D01*
|
||||||
|
Y262032D01*
|
||||||
|
X69081Y256304D01*
|
||||||
|
X69001Y256110D01*
|
||||||
|
X67822Y253263D01*
|
||||||
|
X67392Y250000D01*
|
||||||
|
X67822Y246737D01*
|
||||||
|
X69001Y243890D01*
|
||||||
|
X69081Y243696D01*
|
||||||
|
X71085Y237968D01*
|
||||||
|
Y236632D01*
|
||||||
|
X69081Y230904D01*
|
||||||
|
X69001Y230711D01*
|
||||||
|
X67822Y227863D01*
|
||||||
|
X67392Y224600D01*
|
||||||
|
X67774Y221700D01*
|
||||||
|
X67803Y220779D01*
|
||||||
|
X67500Y211700D01*
|
||||||
|
X67500Y205831D01*
|
||||||
|
Y202700D01*
|
||||||
|
X80000D01*
|
||||||
|
X92500D01*
|
||||||
|
Y205831D01*
|
||||||
|
X92500Y211700D01*
|
||||||
|
X92197Y220779D01*
|
||||||
|
X92226Y221700D01*
|
||||||
|
X92608Y224600D01*
|
||||||
|
X92178Y227863D01*
|
||||||
|
X90999Y230711D01*
|
||||||
|
X90919Y230904D01*
|
||||||
|
X88915Y236632D01*
|
||||||
|
Y237968D01*
|
||||||
|
X90919Y243696D01*
|
||||||
|
X90999Y243890D01*
|
||||||
|
X99504Y246871D01*
|
||||||
|
X102289Y246922D01*
|
||||||
|
X105950Y244321D01*
|
||||||
|
X108864Y235075D01*
|
||||||
|
X107468Y233374D01*
|
||||||
|
X106075Y230768D01*
|
||||||
|
X105217Y227941D01*
|
||||||
|
X104927Y225000D01*
|
||||||
|
X105217Y222059D01*
|
||||||
|
X106075Y219232D01*
|
||||||
|
X107468Y216626D01*
|
||||||
|
X109342Y214342D01*
|
||||||
|
X111626Y212468D01*
|
||||||
|
X114232Y211075D01*
|
||||||
|
X117059Y210217D01*
|
||||||
|
X120000Y209927D01*
|
||||||
|
X122941Y210217D01*
|
||||||
|
X125768Y211075D01*
|
||||||
|
X128374Y212468D01*
|
||||||
|
X130658Y214342D01*
|
||||||
|
X132532Y216626D01*
|
||||||
|
X133925Y219232D01*
|
||||||
|
X134783Y222059D01*
|
||||||
|
X135073Y225000D01*
|
||||||
|
X134783Y227941D01*
|
||||||
|
X133925Y230768D01*
|
||||||
|
X132532Y233374D01*
|
||||||
|
X130658Y235658D01*
|
||||||
|
Y239342D01*
|
||||||
|
X132532Y241626D01*
|
||||||
|
X133925Y244232D01*
|
||||||
|
X134783Y247059D01*
|
||||||
|
X135073Y250000D01*
|
||||||
|
X134783Y252941D01*
|
||||||
|
X133925Y255768D01*
|
||||||
|
X132532Y258374D01*
|
||||||
|
X130658Y260658D01*
|
||||||
|
Y264342D01*
|
||||||
|
X132532Y266626D01*
|
||||||
|
X133925Y269232D01*
|
||||||
|
X134783Y272059D01*
|
||||||
|
X135073Y275000D01*
|
||||||
|
X134783Y277941D01*
|
||||||
|
X133925Y280768D01*
|
||||||
|
X133814Y280976D01*
|
||||||
|
X163040Y310203D01*
|
||||||
|
X171433Y304691D01*
|
||||||
|
X170289Y300921D01*
|
||||||
|
X169903Y297000D01*
|
||||||
|
X170289Y293079D01*
|
||||||
|
X171433Y289309D01*
|
||||||
|
X173290Y285835D01*
|
||||||
|
X175789Y282789D01*
|
||||||
|
X178835Y280290D01*
|
||||||
|
X182309Y278433D01*
|
||||||
|
X186079Y277289D01*
|
||||||
|
X190000Y276903D01*
|
||||||
|
X193921Y277289D01*
|
||||||
|
X197691Y278433D01*
|
||||||
|
X201165Y280290D01*
|
||||||
|
X204211Y282789D01*
|
||||||
|
X206710Y285835D01*
|
||||||
|
X208567Y289309D01*
|
||||||
|
X209711Y293079D01*
|
||||||
|
X210097Y297000D01*
|
||||||
|
X209711Y300921D01*
|
||||||
|
X208567Y304691D01*
|
||||||
|
X206710Y308165D01*
|
||||||
|
X204211Y311211D01*
|
||||||
|
X201165Y313710D01*
|
||||||
|
X197691Y315567D01*
|
||||||
|
X193921Y316711D01*
|
||||||
|
X190000Y317097D01*
|
||||||
|
X186079Y316711D01*
|
||||||
|
X182309Y315567D01*
|
||||||
|
X176798Y323960D01*
|
||||||
|
X251419Y398581D01*
|
||||||
|
X252861Y400461D01*
|
||||||
|
X253768Y402650D01*
|
||||||
|
X254078Y405000D01*
|
||||||
|
X254078Y405000D01*
|
||||||
|
Y422710D01*
|
||||||
|
X255700Y423794D01*
|
||||||
|
X265700Y418449D01*
|
||||||
|
Y416500D01*
|
||||||
|
X275700D01*
|
||||||
|
Y430000D01*
|
||||||
|
X282700D01*
|
||||||
|
Y416500D01*
|
||||||
|
X292700D01*
|
||||||
|
Y416500D01*
|
||||||
|
X302700Y416634D01*
|
||||||
|
X302990Y416596D01*
|
||||||
|
X399804Y319781D01*
|
||||||
|
X401684Y318339D01*
|
||||||
|
X403873Y317432D01*
|
||||||
|
X406223Y317122D01*
|
||||||
|
X406223Y317122D01*
|
||||||
|
X460219D01*
|
||||||
|
X464046Y307884D01*
|
||||||
|
X462081Y305919D01*
|
||||||
|
X460639Y304039D01*
|
||||||
|
X459732Y301849D01*
|
||||||
|
X459422Y299500D01*
|
||||||
|
Y295947D01*
|
||||||
|
X458384Y294083D01*
|
||||||
|
X451000Y287617D01*
|
||||||
|
X447476Y287153D01*
|
||||||
|
X444192Y285792D01*
|
||||||
|
X441372Y283628D01*
|
||||||
|
X439208Y280808D01*
|
||||||
|
X437848Y277524D01*
|
||||||
|
X437384Y274000D01*
|
||||||
|
X437474Y273312D01*
|
||||||
|
X343240Y179078D01*
|
||||||
|
X255051D01*
|
||||||
|
X254628Y179628D01*
|
||||||
|
X251808Y181792D01*
|
||||||
|
X248524Y183153D01*
|
||||||
|
X245000Y183616D01*
|
||||||
|
X241476Y183153D01*
|
||||||
|
X238192Y181792D01*
|
||||||
|
X235372Y179628D01*
|
||||||
|
X233208Y176808D01*
|
||||||
|
X231847Y173524D01*
|
||||||
|
X231383Y170000D01*
|
||||||
|
X231847Y166476D01*
|
||||||
|
X233208Y163192D01*
|
||||||
|
X235372Y160372D01*
|
||||||
|
X238192Y158208D01*
|
||||||
|
X241476Y156847D01*
|
||||||
|
X245000Y156383D01*
|
||||||
|
X248524Y156847D01*
|
||||||
|
X251808Y158208D01*
|
||||||
|
X254628Y160372D01*
|
||||||
|
X255051Y160922D01*
|
||||||
|
X347000D01*
|
||||||
|
X349350Y161232D01*
|
||||||
|
X351539Y162139D01*
|
||||||
|
X353419Y163581D01*
|
||||||
|
X449422Y259585D01*
|
||||||
|
X452330Y259219D01*
|
||||||
|
X458384Y253917D01*
|
||||||
|
X459422Y252052D01*
|
||||||
|
Y229017D01*
|
||||||
|
X458732Y227349D01*
|
||||||
|
X458422Y225000D01*
|
||||||
|
Y151500D01*
|
||||||
|
Y111983D01*
|
||||||
|
X440579Y94140D01*
|
||||||
|
X430295Y95964D01*
|
||||||
|
X427979Y103612D01*
|
||||||
|
X428256Y104044D01*
|
||||||
|
X429565Y107206D01*
|
||||||
|
X430012Y110600D01*
|
||||||
|
X429565Y113994D01*
|
||||||
|
X428256Y117156D01*
|
||||||
|
X426172Y119872D01*
|
||||||
|
X423456Y121955D01*
|
||||||
|
X420294Y123265D01*
|
||||||
|
X416900Y123712D01*
|
||||||
|
X413506Y123265D01*
|
||||||
|
X410344Y121955D01*
|
||||||
|
X407628Y119872D01*
|
||||||
|
X405751Y117425D01*
|
||||||
|
X405545Y117156D01*
|
||||||
|
X405545Y117156D01*
|
||||||
|
X404235Y113994D01*
|
||||||
|
X404096Y113873D01*
|
||||||
|
X394626Y115381D01*
|
||||||
|
X394100Y117005D01*
|
||||||
|
Y131500D01*
|
||||||
|
X374969D01*
|
||||||
|
X369100Y131500D01*
|
||||||
|
X360021Y131197D01*
|
||||||
|
X359100Y131226D01*
|
||||||
|
X356200Y131608D01*
|
||||||
|
X352937Y131178D01*
|
||||||
|
X350089Y129999D01*
|
||||||
|
X349896Y129919D01*
|
||||||
|
X344168Y127915D01*
|
||||||
|
X342832D01*
|
||||||
|
X337104Y129919D01*
|
||||||
|
X336911Y129999D01*
|
||||||
|
X334063Y131178D01*
|
||||||
|
X330800Y131608D01*
|
||||||
|
X327537Y131178D01*
|
||||||
|
X324689Y129999D01*
|
||||||
|
X324496Y129919D01*
|
||||||
|
X318768Y127915D01*
|
||||||
|
X317432D01*
|
||||||
|
X311704Y129919D01*
|
||||||
|
X311511Y129999D01*
|
||||||
|
X308663Y131178D01*
|
||||||
|
X305400Y131608D01*
|
||||||
|
X302137Y131178D01*
|
||||||
|
X299289Y129999D01*
|
||||||
|
X299096Y129919D01*
|
||||||
|
X293368Y127915D01*
|
||||||
|
X292032D01*
|
||||||
|
X286304Y129919D01*
|
||||||
|
X286110Y129999D01*
|
||||||
|
X283263Y131178D01*
|
||||||
|
X280000Y131608D01*
|
||||||
|
X276737Y131178D01*
|
||||||
|
X273890Y129999D01*
|
||||||
|
X273696Y129919D01*
|
||||||
|
X267968Y127915D01*
|
||||||
|
X266632D01*
|
||||||
|
X260904Y129919D01*
|
||||||
|
X260711Y129999D01*
|
||||||
|
X257863Y131178D01*
|
||||||
|
X254600Y131608D01*
|
||||||
|
X251337Y131178D01*
|
||||||
|
X248296Y129919D01*
|
||||||
|
X245685Y127915D01*
|
||||||
|
X243681Y125304D01*
|
||||||
|
X242422Y122263D01*
|
||||||
|
X241992Y119000D01*
|
||||||
|
X242422Y115737D01*
|
||||||
|
X243681Y112696D01*
|
||||||
|
X245685Y110085D01*
|
||||||
|
X248296Y108081D01*
|
||||||
|
X251337Y106822D01*
|
||||||
|
X254600Y106392D01*
|
||||||
|
X257863Y106822D01*
|
||||||
|
X260711Y108001D01*
|
||||||
|
X260904Y108081D01*
|
||||||
|
X266632Y110085D01*
|
||||||
|
X267968D01*
|
||||||
|
X273696Y108081D01*
|
||||||
|
X273890Y108001D01*
|
||||||
|
X276737Y106822D01*
|
||||||
|
X280000Y106392D01*
|
||||||
|
X283263Y106822D01*
|
||||||
|
X286110Y108001D01*
|
||||||
|
X286304Y108081D01*
|
||||||
|
X292032Y110085D01*
|
||||||
|
X293368D01*
|
||||||
|
X299096Y108081D01*
|
||||||
|
X299289Y108001D01*
|
||||||
|
X302137Y106822D01*
|
||||||
|
X305400Y106392D01*
|
||||||
|
X308663Y106822D01*
|
||||||
|
X311511Y108001D01*
|
||||||
|
X311704Y108081D01*
|
||||||
|
X317432Y110085D01*
|
||||||
|
X318768D01*
|
||||||
|
X324496Y108081D01*
|
||||||
|
X324689Y108001D01*
|
||||||
|
X327537Y106822D01*
|
||||||
|
X330800Y106392D01*
|
||||||
|
X334063Y106822D01*
|
||||||
|
X336911Y108001D01*
|
||||||
|
X337104Y108081D01*
|
||||||
|
X342832Y110085D01*
|
||||||
|
X344168D01*
|
||||||
|
X349896Y108081D01*
|
||||||
|
X350089Y108001D01*
|
||||||
|
X352937Y106822D01*
|
||||||
|
X356200Y106392D01*
|
||||||
|
X359100Y106774D01*
|
||||||
|
X360021Y106803D01*
|
||||||
|
X369100Y106500D01*
|
||||||
|
X374969Y106500D01*
|
||||||
|
X387162Y106500D01*
|
||||||
|
X394100Y106500D01*
|
||||||
|
X401250Y101782D01*
|
||||||
|
X400661Y93062D01*
|
||||||
|
X398781Y91619D01*
|
||||||
|
X388581Y81419D01*
|
||||||
|
X387138Y79539D01*
|
||||||
|
X386232Y77350D01*
|
||||||
|
X385922Y75000D01*
|
||||||
|
Y20000D01*
|
||||||
|
X380924Y11588D01*
|
||||||
|
X380250Y10817D01*
|
||||||
|
X379037Y10000D01*
|
||||||
|
X78018D01*
|
||||||
|
X70541Y18662D01*
|
||||||
|
X70270Y20000D01*
|
||||||
|
X70598Y25000D01*
|
||||||
|
X70459Y27122D01*
|
||||||
|
X70599Y27572D01*
|
||||||
|
X74176Y32213D01*
|
||||||
|
X76301Y34210D01*
|
||||||
|
X76500Y34316D01*
|
||||||
|
Y50000D01*
|
||||||
|
Y64055D01*
|
||||||
|
X73345Y63640D01*
|
||||||
|
X69940Y62229D01*
|
||||||
|
X67015Y59985D01*
|
||||||
|
X64164Y59185D01*
|
||||||
|
X57318Y58759D01*
|
||||||
|
X54880Y59314D01*
|
||||||
|
X52758Y61175D01*
|
||||||
|
X47799Y64489D01*
|
||||||
|
X42449Y67127D01*
|
||||||
|
X36802Y69044D01*
|
||||||
|
X30952Y70208D01*
|
||||||
|
X25000Y70598D01*
|
||||||
|
X20000Y70270D01*
|
||||||
|
X18662Y70541D01*
|
||||||
|
X10000Y78018D01*
|
||||||
|
X10000Y421982D01*
|
||||||
|
X18662Y429459D01*
|
||||||
|
X20000Y429730D01*
|
||||||
|
X25000Y429402D01*
|
||||||
|
X30952Y429793D01*
|
||||||
|
X36802Y430956D01*
|
||||||
|
X42449Y432873D01*
|
||||||
|
X47799Y435511D01*
|
||||||
|
X52758Y438825D01*
|
||||||
|
X54880Y440686D01*
|
||||||
|
X57318Y441241D01*
|
||||||
|
X64164Y440815D01*
|
||||||
|
X67015Y440015D01*
|
||||||
|
X69940Y437771D01*
|
||||||
|
X73345Y436360D01*
|
||||||
|
X77000Y435879D01*
|
||||||
|
X83000D01*
|
||||||
|
X86655Y436360D01*
|
||||||
|
X90060Y437771D01*
|
||||||
|
X92985Y440015D01*
|
||||||
|
X95229Y442940D01*
|
||||||
|
X96640Y446345D01*
|
||||||
|
X97121Y450000D01*
|
||||||
|
X96640Y453655D01*
|
||||||
|
X95229Y457060D01*
|
||||||
|
X92985Y459985D01*
|
||||||
|
X90060Y462229D01*
|
||||||
|
X86655Y463640D01*
|
||||||
|
X83000Y464121D01*
|
||||||
|
X79423D01*
|
||||||
|
X76301Y465790D01*
|
||||||
|
X74176Y467786D01*
|
||||||
|
X70599Y472428D01*
|
||||||
|
X70459Y472878D01*
|
||||||
|
X70598Y475000D01*
|
||||||
|
X70270Y480000D01*
|
||||||
|
X70541Y481338D01*
|
||||||
|
X78018Y490000D01*
|
||||||
|
X164097D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X411300Y477685D02*
|
||||||
|
Y451685D01*
|
||||||
|
X411300D01*
|
||||||
|
X411502Y441685D01*
|
||||||
|
X411188Y439300D01*
|
||||||
|
X411635Y435906D01*
|
||||||
|
X412944Y432744D01*
|
||||||
|
X415028Y429492D01*
|
||||||
|
Y423707D01*
|
||||||
|
X412944Y420456D01*
|
||||||
|
X411635Y417294D01*
|
||||||
|
X411188Y413900D01*
|
||||||
|
X411635Y410506D01*
|
||||||
|
X412944Y407344D01*
|
||||||
|
X415028Y404092D01*
|
||||||
|
Y398307D01*
|
||||||
|
X413883Y396520D01*
|
||||||
|
X403618Y394286D01*
|
||||||
|
X397078Y399210D01*
|
||||||
|
Y431000D01*
|
||||||
|
X396768Y433349D01*
|
||||||
|
X395862Y435539D01*
|
||||||
|
X394419Y437419D01*
|
||||||
|
X374419Y457419D01*
|
||||||
|
X372539Y458862D01*
|
||||||
|
X370349Y459768D01*
|
||||||
|
X368000Y460078D01*
|
||||||
|
X261000D01*
|
||||||
|
X258650Y459768D01*
|
||||||
|
X256461Y458862D01*
|
||||||
|
X254581Y457419D01*
|
||||||
|
X238581Y441419D01*
|
||||||
|
X237139Y439539D01*
|
||||||
|
X236232Y437350D01*
|
||||||
|
X235922Y435000D01*
|
||||||
|
Y411411D01*
|
||||||
|
X228717Y404247D01*
|
||||||
|
X219362Y406739D01*
|
||||||
|
X219229Y407060D01*
|
||||||
|
X216985Y409985D01*
|
||||||
|
X214060Y412229D01*
|
||||||
|
X210655Y413640D01*
|
||||||
|
X207500Y414055D01*
|
||||||
|
Y400000D01*
|
||||||
|
X204000D01*
|
||||||
|
Y396500D01*
|
||||||
|
X187340D01*
|
||||||
|
X187360Y396345D01*
|
||||||
|
X188771Y392940D01*
|
||||||
|
X191015Y390015D01*
|
||||||
|
X193940Y387771D01*
|
||||||
|
X197345Y386360D01*
|
||||||
|
X199144Y386124D01*
|
||||||
|
X201909Y381424D01*
|
||||||
|
X203041Y375879D01*
|
||||||
|
X143178Y316016D01*
|
||||||
|
X135139Y319366D01*
|
||||||
|
X133547Y320527D01*
|
||||||
|
X133153Y323524D01*
|
||||||
|
X131792Y326808D01*
|
||||||
|
X131437Y327271D01*
|
||||||
|
X129628Y330568D01*
|
||||||
|
Y336932D01*
|
||||||
|
X131437Y340229D01*
|
||||||
|
X131792Y340692D01*
|
||||||
|
X133153Y343976D01*
|
||||||
|
X133616Y347500D01*
|
||||||
|
X133153Y351024D01*
|
||||||
|
X131792Y354308D01*
|
||||||
|
X129628Y357128D01*
|
||||||
|
X126808Y359292D01*
|
||||||
|
X126429Y359449D01*
|
||||||
|
X123556Y367558D01*
|
||||||
|
X123570Y370733D01*
|
||||||
|
X146419Y393581D01*
|
||||||
|
X147861Y395461D01*
|
||||||
|
X148768Y397650D01*
|
||||||
|
X149078Y400000D01*
|
||||||
|
Y436240D01*
|
||||||
|
X191260Y478422D01*
|
||||||
|
X401606D01*
|
||||||
|
X411300Y477685D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X484344Y476097D02*
|
||||||
|
X487971Y468422D01*
|
||||||
|
X487835Y468093D01*
|
||||||
|
X487388Y464700D01*
|
||||||
|
X487835Y461306D01*
|
||||||
|
X489145Y458144D01*
|
||||||
|
X491228Y454892D01*
|
||||||
|
Y449107D01*
|
||||||
|
X489145Y445856D01*
|
||||||
|
X487835Y442693D01*
|
||||||
|
X487388Y439300D01*
|
||||||
|
X487835Y435906D01*
|
||||||
|
X489145Y432744D01*
|
||||||
|
X491228Y429492D01*
|
||||||
|
Y423707D01*
|
||||||
|
X489145Y420456D01*
|
||||||
|
X487835Y417294D01*
|
||||||
|
X487388Y413900D01*
|
||||||
|
X487835Y410506D01*
|
||||||
|
X489145Y407344D01*
|
||||||
|
X491228Y404092D01*
|
||||||
|
Y398307D01*
|
||||||
|
X489145Y395056D01*
|
||||||
|
X487835Y391894D01*
|
||||||
|
X487388Y388500D01*
|
||||||
|
X487835Y385106D01*
|
||||||
|
X489145Y381944D01*
|
||||||
|
X491228Y379228D01*
|
||||||
|
X491566Y378969D01*
|
||||||
|
X493557Y370432D01*
|
||||||
|
X493335Y366596D01*
|
||||||
|
X485817Y359078D01*
|
||||||
|
X435760D01*
|
||||||
|
X428927Y365910D01*
|
||||||
|
X428642Y368208D01*
|
||||||
|
X430774Y376812D01*
|
||||||
|
X431410Y377570D01*
|
||||||
|
X433572Y379228D01*
|
||||||
|
X435655Y381944D01*
|
||||||
|
X436921Y385000D01*
|
||||||
|
X424300D01*
|
||||||
|
Y392000D01*
|
||||||
|
X436921D01*
|
||||||
|
X435655Y395056D01*
|
||||||
|
X433572Y398307D01*
|
||||||
|
Y404092D01*
|
||||||
|
X435655Y407344D01*
|
||||||
|
X436965Y410506D01*
|
||||||
|
X437412Y413900D01*
|
||||||
|
X436965Y417294D01*
|
||||||
|
X435655Y420456D01*
|
||||||
|
X433572Y423707D01*
|
||||||
|
Y429492D01*
|
||||||
|
X435655Y432744D01*
|
||||||
|
X436965Y435906D01*
|
||||||
|
X437412Y439300D01*
|
||||||
|
X437098Y441685D01*
|
||||||
|
X437300Y451685D01*
|
||||||
|
X437300Y451685D01*
|
||||||
|
Y477685D01*
|
||||||
|
X446994Y478422D01*
|
||||||
|
X482039D01*
|
||||||
|
X484344Y476097D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X688391Y490000D02*
|
||||||
|
X689849Y480000D01*
|
||||||
|
X688841Y478646D01*
|
||||||
|
X680904Y473792D01*
|
||||||
|
X680500Y473763D01*
|
||||||
|
Y460000D01*
|
||||||
|
Y446237D01*
|
||||||
|
X680904Y446208D01*
|
||||||
|
X688841Y441354D01*
|
||||||
|
X690000Y439798D01*
|
||||||
|
Y404002D01*
|
||||||
|
X688841Y402446D01*
|
||||||
|
X680904Y397592D01*
|
||||||
|
X680500Y397562D01*
|
||||||
|
Y383800D01*
|
||||||
|
Y370037D01*
|
||||||
|
X680904Y370008D01*
|
||||||
|
X688841Y365154D01*
|
||||||
|
X690000Y363598D01*
|
||||||
|
Y347455D01*
|
||||||
|
X687030Y344417D01*
|
||||||
|
X680000Y340176D01*
|
||||||
|
X678900Y340321D01*
|
||||||
|
X675245Y339840D01*
|
||||||
|
X671840Y338429D01*
|
||||||
|
X668915Y336185D01*
|
||||||
|
X663485D01*
|
||||||
|
X660560Y338429D01*
|
||||||
|
X657155Y339840D01*
|
||||||
|
X654671Y340167D01*
|
||||||
|
X640000Y354838D01*
|
||||||
|
Y366000D01*
|
||||||
|
X623226D01*
|
||||||
|
X614800Y369800D01*
|
||||||
|
Y380300D01*
|
||||||
|
X600800D01*
|
||||||
|
Y387300D01*
|
||||||
|
X614800D01*
|
||||||
|
Y397800D01*
|
||||||
|
X614800Y397800D01*
|
||||||
|
X614750Y405700D01*
|
||||||
|
X600800D01*
|
||||||
|
Y412700D01*
|
||||||
|
X614460D01*
|
||||||
|
X614440Y412855D01*
|
||||||
|
X613029Y416260D01*
|
||||||
|
X610785Y419185D01*
|
||||||
|
Y424615D01*
|
||||||
|
X613029Y427540D01*
|
||||||
|
X614440Y430945D01*
|
||||||
|
X614921Y434600D01*
|
||||||
|
X614440Y438255D01*
|
||||||
|
X613029Y441660D01*
|
||||||
|
X610785Y444585D01*
|
||||||
|
Y450015D01*
|
||||||
|
X613029Y452940D01*
|
||||||
|
X614440Y456345D01*
|
||||||
|
X614921Y460000D01*
|
||||||
|
X614440Y463655D01*
|
||||||
|
X613029Y467060D01*
|
||||||
|
X610785Y469985D01*
|
||||||
|
X607860Y472229D01*
|
||||||
|
X604455Y473640D01*
|
||||||
|
X600800Y474121D01*
|
||||||
|
X597145Y473640D01*
|
||||||
|
X596475Y473362D01*
|
||||||
|
X589076Y480761D01*
|
||||||
|
X592903Y490000D01*
|
||||||
|
X688391D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X671840Y161571D02*
|
||||||
|
X675245Y160160D01*
|
||||||
|
X678900Y159679D01*
|
||||||
|
X680000Y159824D01*
|
||||||
|
X687030Y155583D01*
|
||||||
|
X690000Y152545D01*
|
||||||
|
Y136402D01*
|
||||||
|
X688841Y134846D01*
|
||||||
|
X680904Y129992D01*
|
||||||
|
X680500Y129963D01*
|
||||||
|
Y116200D01*
|
||||||
|
Y102437D01*
|
||||||
|
X680904Y102408D01*
|
||||||
|
X688841Y97554D01*
|
||||||
|
X690000Y95998D01*
|
||||||
|
Y60202D01*
|
||||||
|
X688841Y58646D01*
|
||||||
|
X680904Y53792D01*
|
||||||
|
X680500Y53762D01*
|
||||||
|
Y40000D01*
|
||||||
|
Y26237D01*
|
||||||
|
X680904Y26208D01*
|
||||||
|
X688841Y21354D01*
|
||||||
|
X689849Y20000D01*
|
||||||
|
X688391Y10000D01*
|
||||||
|
X590472D01*
|
||||||
|
X587271Y19010D01*
|
||||||
|
X593995Y26000D01*
|
||||||
|
X614800D01*
|
||||||
|
Y37422D01*
|
||||||
|
X618500D01*
|
||||||
|
X620849Y37732D01*
|
||||||
|
X623039Y38639D01*
|
||||||
|
X624919Y40081D01*
|
||||||
|
X625838Y41000D01*
|
||||||
|
X637000D01*
|
||||||
|
Y59000D01*
|
||||||
|
Y81000D01*
|
||||||
|
X625838D01*
|
||||||
|
X614751Y92086D01*
|
||||||
|
X614440Y94455D01*
|
||||||
|
X613029Y97860D01*
|
||||||
|
X610785Y100785D01*
|
||||||
|
Y106215D01*
|
||||||
|
X613029Y109140D01*
|
||||||
|
X614440Y112545D01*
|
||||||
|
X614921Y116200D01*
|
||||||
|
X614440Y119855D01*
|
||||||
|
X613029Y123260D01*
|
||||||
|
X610785Y126185D01*
|
||||||
|
X607860Y128429D01*
|
||||||
|
X604455Y129840D01*
|
||||||
|
X600800Y130321D01*
|
||||||
|
X597145Y129840D01*
|
||||||
|
X593740Y128429D01*
|
||||||
|
X590815Y126185D01*
|
||||||
|
X590119Y125278D01*
|
||||||
|
X555060D01*
|
||||||
|
X530251Y150087D01*
|
||||||
|
X530221Y153207D01*
|
||||||
|
X532930Y160900D01*
|
||||||
|
X542233Y163571D01*
|
||||||
|
X544840Y161571D01*
|
||||||
|
X548245Y160160D01*
|
||||||
|
X551900Y159679D01*
|
||||||
|
X555555Y160160D01*
|
||||||
|
X558960Y161571D01*
|
||||||
|
X561885Y163815D01*
|
||||||
|
X567315D01*
|
||||||
|
X570240Y161571D01*
|
||||||
|
X573645Y160160D01*
|
||||||
|
X577300Y159679D01*
|
||||||
|
X580955Y160160D01*
|
||||||
|
X584360Y161571D01*
|
||||||
|
X587285Y163815D01*
|
||||||
|
X592715D01*
|
||||||
|
X595640Y161571D01*
|
||||||
|
X599045Y160160D01*
|
||||||
|
X602700Y159679D01*
|
||||||
|
X606355Y160160D01*
|
||||||
|
X609760Y161571D01*
|
||||||
|
X612685Y163815D01*
|
||||||
|
X618115D01*
|
||||||
|
X621040Y161571D01*
|
||||||
|
X624445Y160160D01*
|
||||||
|
X628100Y159679D01*
|
||||||
|
X631755Y160160D01*
|
||||||
|
X635160Y161571D01*
|
||||||
|
X638085Y163815D01*
|
||||||
|
X643515D01*
|
||||||
|
X646440Y161571D01*
|
||||||
|
X649845Y160160D01*
|
||||||
|
X653500Y159679D01*
|
||||||
|
X657155Y160160D01*
|
||||||
|
X660560Y161571D01*
|
||||||
|
X663485Y163815D01*
|
||||||
|
X668915D01*
|
||||||
|
X671840Y161571D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X528146Y99016D02*
|
||||||
|
X528372Y97958D01*
|
||||||
|
X528270Y95509D01*
|
||||||
|
X527125Y88971D01*
|
||||||
|
X526120Y87198D01*
|
||||||
|
X525977Y87043D01*
|
||||||
|
X520581Y81647D01*
|
||||||
|
X519138Y79767D01*
|
||||||
|
X518232Y77577D01*
|
||||||
|
X518090Y76500D01*
|
||||||
|
X514000D01*
|
||||||
|
Y76500D01*
|
||||||
|
X507668Y77098D01*
|
||||||
|
X505281Y80637D01*
|
||||||
|
X505721Y81700D01*
|
||||||
|
X493100D01*
|
||||||
|
X480479D01*
|
||||||
|
X481745Y78644D01*
|
||||||
|
X477582Y69405D01*
|
||||||
|
X477173Y68978D01*
|
||||||
|
X465000D01*
|
||||||
|
X462650Y68668D01*
|
||||||
|
X461919Y68365D01*
|
||||||
|
X456073Y69816D01*
|
||||||
|
X452700Y80586D01*
|
||||||
|
X468694Y96579D01*
|
||||||
|
X480087Y94622D01*
|
||||||
|
X481698Y91837D01*
|
||||||
|
X481629Y91477D01*
|
||||||
|
X480479Y88700D01*
|
||||||
|
X493100D01*
|
||||||
|
X505721D01*
|
||||||
|
X504455Y91756D01*
|
||||||
|
X502372Y95007D01*
|
||||||
|
Y100793D01*
|
||||||
|
X504455Y104044D01*
|
||||||
|
X505765Y107206D01*
|
||||||
|
X505771Y107249D01*
|
||||||
|
X514258Y111112D01*
|
||||||
|
X515943Y111219D01*
|
||||||
|
X528146Y99016D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
%LPC*%
|
||||||
|
G36*
|
||||||
|
X83500Y414055D02*
|
||||||
|
Y403500D01*
|
||||||
|
X96660D01*
|
||||||
|
X96640Y403655D01*
|
||||||
|
X95229Y407060D01*
|
||||||
|
X92985Y409985D01*
|
||||||
|
X90060Y412229D01*
|
||||||
|
X86655Y413640D01*
|
||||||
|
X83500Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X76500Y414055D02*
|
||||||
|
X73345Y413640D01*
|
||||||
|
X69940Y412229D01*
|
||||||
|
X67015Y409985D01*
|
||||||
|
X64771Y407060D01*
|
||||||
|
X63360Y403655D01*
|
||||||
|
X63340Y403500D01*
|
||||||
|
X76500D01*
|
||||||
|
Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X96660Y396500D02*
|
||||||
|
X83500D01*
|
||||||
|
Y385945D01*
|
||||||
|
X86655Y386360D01*
|
||||||
|
X90060Y387771D01*
|
||||||
|
X92985Y390015D01*
|
||||||
|
X95229Y392940D01*
|
||||||
|
X96640Y396345D01*
|
||||||
|
X96660Y396500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X76500D02*
|
||||||
|
X63340D01*
|
||||||
|
X63360Y396345D01*
|
||||||
|
X64771Y392940D01*
|
||||||
|
X67015Y390015D01*
|
||||||
|
X69940Y387771D01*
|
||||||
|
X73345Y386360D01*
|
||||||
|
X76500Y385945D01*
|
||||||
|
Y396500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X92500Y195700D02*
|
||||||
|
X83500D01*
|
||||||
|
Y186700D01*
|
||||||
|
X92500D01*
|
||||||
|
Y195700D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X76500D02*
|
||||||
|
X67500D01*
|
||||||
|
Y186700D01*
|
||||||
|
X76500D01*
|
||||||
|
Y195700D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X190000Y223097D02*
|
||||||
|
X186079Y222711D01*
|
||||||
|
X182309Y221567D01*
|
||||||
|
X178835Y219710D01*
|
||||||
|
X175789Y217211D01*
|
||||||
|
X173290Y214165D01*
|
||||||
|
X171433Y210691D01*
|
||||||
|
X170289Y206921D01*
|
||||||
|
X169903Y203000D01*
|
||||||
|
X170289Y199079D01*
|
||||||
|
X171433Y195309D01*
|
||||||
|
X173290Y191835D01*
|
||||||
|
X175789Y188789D01*
|
||||||
|
X178835Y186290D01*
|
||||||
|
X182309Y184433D01*
|
||||||
|
X186079Y183289D01*
|
||||||
|
X190000Y182903D01*
|
||||||
|
X193921Y183289D01*
|
||||||
|
X197691Y184433D01*
|
||||||
|
X201165Y186290D01*
|
||||||
|
X204211Y188789D01*
|
||||||
|
X206710Y191835D01*
|
||||||
|
X208567Y195309D01*
|
||||||
|
X209711Y199079D01*
|
||||||
|
X210097Y203000D01*
|
||||||
|
X209711Y206921D01*
|
||||||
|
X208567Y210691D01*
|
||||||
|
X206710Y214165D01*
|
||||||
|
X204211Y217211D01*
|
||||||
|
X201165Y219710D01*
|
||||||
|
X197691Y221567D01*
|
||||||
|
X193921Y222711D01*
|
||||||
|
X190000Y223097D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X83000Y114121D02*
|
||||||
|
X77000D01*
|
||||||
|
X73345Y113640D01*
|
||||||
|
X69940Y112229D01*
|
||||||
|
X67015Y109985D01*
|
||||||
|
X64771Y107060D01*
|
||||||
|
X63360Y103655D01*
|
||||||
|
X62879Y100000D01*
|
||||||
|
X63360Y96345D01*
|
||||||
|
X64771Y92940D01*
|
||||||
|
X67015Y90015D01*
|
||||||
|
X69940Y87771D01*
|
||||||
|
X73345Y86360D01*
|
||||||
|
X77000Y85879D01*
|
||||||
|
X83000D01*
|
||||||
|
X86655Y86360D01*
|
||||||
|
X90060Y87771D01*
|
||||||
|
X92985Y90015D01*
|
||||||
|
X95229Y92940D01*
|
||||||
|
X96640Y96345D01*
|
||||||
|
X97121Y100000D01*
|
||||||
|
X96640Y103655D01*
|
||||||
|
X95229Y107060D01*
|
||||||
|
X92985Y109985D01*
|
||||||
|
X90060Y112229D01*
|
||||||
|
X86655Y113640D01*
|
||||||
|
X83000Y114121D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X340000Y75000D02*
|
||||||
|
X330000D01*
|
||||||
|
Y66000D01*
|
||||||
|
X340000D01*
|
||||||
|
Y75000D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X207500Y64055D02*
|
||||||
|
Y53500D01*
|
||||||
|
X220660D01*
|
||||||
|
X220640Y53655D01*
|
||||||
|
X219229Y57060D01*
|
||||||
|
X216985Y59985D01*
|
||||||
|
X214060Y62229D01*
|
||||||
|
X210655Y63640D01*
|
||||||
|
X207500Y64055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X83500D02*
|
||||||
|
Y53500D01*
|
||||||
|
X96660D01*
|
||||||
|
X96640Y53655D01*
|
||||||
|
X95229Y57060D01*
|
||||||
|
X92985Y59985D01*
|
||||||
|
X90060Y62229D01*
|
||||||
|
X86655Y63640D01*
|
||||||
|
X83500Y64055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X200500D02*
|
||||||
|
X197345Y63640D01*
|
||||||
|
X193940Y62229D01*
|
||||||
|
X191015Y59985D01*
|
||||||
|
X188771Y57060D01*
|
||||||
|
X187360Y53655D01*
|
||||||
|
X187340Y53500D01*
|
||||||
|
X200500D01*
|
||||||
|
Y64055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X220660Y46500D02*
|
||||||
|
X207500D01*
|
||||||
|
Y35945D01*
|
||||||
|
X210655Y36360D01*
|
||||||
|
X214060Y37771D01*
|
||||||
|
X216985Y40015D01*
|
||||||
|
X219229Y42940D01*
|
||||||
|
X220640Y46345D01*
|
||||||
|
X220660Y46500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X96660D02*
|
||||||
|
X83500D01*
|
||||||
|
Y35945D01*
|
||||||
|
X86655Y36360D01*
|
||||||
|
X90060Y37771D01*
|
||||||
|
X92985Y40015D01*
|
||||||
|
X95229Y42940D01*
|
||||||
|
X96640Y46345D01*
|
||||||
|
X96660Y46500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X200500D02*
|
||||||
|
X187340D01*
|
||||||
|
X187360Y46345D01*
|
||||||
|
X188771Y42940D01*
|
||||||
|
X191015Y40015D01*
|
||||||
|
X193940Y37771D01*
|
||||||
|
X197345Y36360D01*
|
||||||
|
X200500Y35945D01*
|
||||||
|
Y46500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X207000Y114121D02*
|
||||||
|
X201000D01*
|
||||||
|
X197345Y113640D01*
|
||||||
|
X193940Y112229D01*
|
||||||
|
X191015Y109985D01*
|
||||||
|
X188771Y107060D01*
|
||||||
|
X187360Y103655D01*
|
||||||
|
X186879Y100000D01*
|
||||||
|
X187360Y96345D01*
|
||||||
|
X188771Y92940D01*
|
||||||
|
X191015Y90015D01*
|
||||||
|
X193940Y87771D01*
|
||||||
|
X197345Y86360D01*
|
||||||
|
X201000Y85879D01*
|
||||||
|
X207000D01*
|
||||||
|
X210655Y86360D01*
|
||||||
|
X212609Y87170D01*
|
||||||
|
X216265Y85727D01*
|
||||||
|
X221499Y80874D01*
|
||||||
|
X221384Y80000D01*
|
||||||
|
X221847Y76476D01*
|
||||||
|
X223208Y73192D01*
|
||||||
|
X225372Y70372D01*
|
||||||
|
X226553Y69465D01*
|
||||||
|
X227139Y68051D01*
|
||||||
|
X228581Y66171D01*
|
||||||
|
X249671Y45081D01*
|
||||||
|
X251433Y43729D01*
|
||||||
|
X253437Y41725D01*
|
||||||
|
Y33750D01*
|
||||||
|
X253687Y31857D01*
|
||||||
|
X254417Y30094D01*
|
||||||
|
X255579Y28579D01*
|
||||||
|
X257094Y27417D01*
|
||||||
|
X258857Y26687D01*
|
||||||
|
X260750Y26437D01*
|
||||||
|
X279250D01*
|
||||||
|
X281143Y26687D01*
|
||||||
|
X282906Y27417D01*
|
||||||
|
X284421Y28579D01*
|
||||||
|
X285583Y30094D01*
|
||||||
|
X285926Y30922D01*
|
||||||
|
X295000D01*
|
||||||
|
X297349Y31232D01*
|
||||||
|
X299539Y32139D01*
|
||||||
|
X301419Y33581D01*
|
||||||
|
X302838Y35000D01*
|
||||||
|
X315000Y35000D01*
|
||||||
|
Y35000D01*
|
||||||
|
X315000D01*
|
||||||
|
Y35000D01*
|
||||||
|
X340000D01*
|
||||||
|
Y52000D01*
|
||||||
|
Y61000D01*
|
||||||
|
X327500D01*
|
||||||
|
Y63500D01*
|
||||||
|
X325000D01*
|
||||||
|
Y75000D01*
|
||||||
|
X325000D01*
|
||||||
|
X315000Y75000D01*
|
||||||
|
Y75000D01*
|
||||||
|
X315000D01*
|
||||||
|
Y75000D01*
|
||||||
|
X305000D01*
|
||||||
|
Y63500D01*
|
||||||
|
X300000D01*
|
||||||
|
Y75000D01*
|
||||||
|
X290000D01*
|
||||||
|
X284421Y81421D01*
|
||||||
|
X282906Y82583D01*
|
||||||
|
X281143Y83313D01*
|
||||||
|
X279250Y83562D01*
|
||||||
|
X272500D01*
|
||||||
|
Y69500D01*
|
||||||
|
X267500D01*
|
||||||
|
Y83562D01*
|
||||||
|
X260750D01*
|
||||||
|
X258857Y83313D01*
|
||||||
|
X258297Y83081D01*
|
||||||
|
X254986Y83226D01*
|
||||||
|
X249883Y84782D01*
|
||||||
|
X246903Y86541D01*
|
||||||
|
X246792Y86808D01*
|
||||||
|
X244628Y89628D01*
|
||||||
|
X241808Y91792D01*
|
||||||
|
X238524Y93153D01*
|
||||||
|
X235000Y93616D01*
|
||||||
|
X231476Y93153D01*
|
||||||
|
X229865Y92485D01*
|
||||||
|
X225703Y94227D01*
|
||||||
|
X220970Y98856D01*
|
||||||
|
X221121Y100000D01*
|
||||||
|
X220640Y103655D01*
|
||||||
|
X219229Y107060D01*
|
||||||
|
X216985Y109985D01*
|
||||||
|
X214060Y112229D01*
|
||||||
|
X210655Y113640D01*
|
||||||
|
X207000Y114121D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y464121D02*
|
||||||
|
X201000D01*
|
||||||
|
X197345Y463640D01*
|
||||||
|
X193940Y462229D01*
|
||||||
|
X191015Y459985D01*
|
||||||
|
X188771Y457060D01*
|
||||||
|
X187360Y453655D01*
|
||||||
|
X186879Y450000D01*
|
||||||
|
X187360Y446345D01*
|
||||||
|
X188771Y442940D01*
|
||||||
|
X191015Y440015D01*
|
||||||
|
X193940Y437771D01*
|
||||||
|
X197345Y436360D01*
|
||||||
|
X201000Y435879D01*
|
||||||
|
X207000D01*
|
||||||
|
X210655Y436360D01*
|
||||||
|
X214060Y437771D01*
|
||||||
|
X216985Y440015D01*
|
||||||
|
X219229Y442940D01*
|
||||||
|
X220640Y446345D01*
|
||||||
|
X221121Y450000D01*
|
||||||
|
X220640Y453655D01*
|
||||||
|
X219229Y457060D01*
|
||||||
|
X216985Y459985D01*
|
||||||
|
X214060Y462229D01*
|
||||||
|
X210655Y463640D01*
|
||||||
|
X207000Y464121D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X200500Y414055D02*
|
||||||
|
X197345Y413640D01*
|
||||||
|
X193940Y412229D01*
|
||||||
|
X191015Y409985D01*
|
||||||
|
X188771Y407060D01*
|
||||||
|
X187360Y403655D01*
|
||||||
|
X187340Y403500D01*
|
||||||
|
X200500D01*
|
||||||
|
Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y473660D02*
|
||||||
|
X673345Y473640D01*
|
||||||
|
X669940Y472229D01*
|
||||||
|
X667015Y469985D01*
|
||||||
|
X664771Y467060D01*
|
||||||
|
X663360Y463655D01*
|
||||||
|
X663340Y463500D01*
|
||||||
|
X673500D01*
|
||||||
|
Y473660D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y456500D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y456345D01*
|
||||||
|
X664771Y452940D01*
|
||||||
|
X667015Y450015D01*
|
||||||
|
X669940Y447771D01*
|
||||||
|
X673345Y446360D01*
|
||||||
|
X673500Y446340D01*
|
||||||
|
Y456500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y397460D02*
|
||||||
|
X673345Y397440D01*
|
||||||
|
X669940Y396029D01*
|
||||||
|
X667015Y393785D01*
|
||||||
|
X664771Y390860D01*
|
||||||
|
X663360Y387455D01*
|
||||||
|
X663340Y387300D01*
|
||||||
|
X673500D01*
|
||||||
|
Y397460D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y380300D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y380145D01*
|
||||||
|
X664771Y376740D01*
|
||||||
|
X667015Y373815D01*
|
||||||
|
X669940Y371571D01*
|
||||||
|
X673345Y370160D01*
|
||||||
|
X673500Y370140D01*
|
||||||
|
Y380300D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y129860D02*
|
||||||
|
X673345Y129840D01*
|
||||||
|
X669940Y128429D01*
|
||||||
|
X667015Y126185D01*
|
||||||
|
X664771Y123260D01*
|
||||||
|
X663360Y119855D01*
|
||||||
|
X663340Y119700D01*
|
||||||
|
X673500D01*
|
||||||
|
Y129860D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y112700D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y112545D01*
|
||||||
|
X664771Y109140D01*
|
||||||
|
X667015Y106215D01*
|
||||||
|
X669940Y103971D01*
|
||||||
|
X673345Y102560D01*
|
||||||
|
X673500Y102540D01*
|
||||||
|
Y112700D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y53660D02*
|
||||||
|
X673345Y53640D01*
|
||||||
|
X669940Y52229D01*
|
||||||
|
X667015Y49985D01*
|
||||||
|
X664771Y47060D01*
|
||||||
|
X663360Y43655D01*
|
||||||
|
X663340Y43500D01*
|
||||||
|
X673500D01*
|
||||||
|
Y53660D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y36500D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y36345D01*
|
||||||
|
X664771Y32940D01*
|
||||||
|
X667015Y30015D01*
|
||||||
|
X669940Y27771D01*
|
||||||
|
X673345Y26360D01*
|
||||||
|
X673500Y26340D01*
|
||||||
|
Y36500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
%LPD*%
|
||||||
|
D19*
|
||||||
|
X537000Y435000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X537000Y470000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X549000Y97000D02*
|
||||||
|
D03*
|
||||||
|
X567000D02*
|
||||||
|
D03*
|
||||||
|
X517000Y256000D02*
|
||||||
|
D03*
|
||||||
|
X499000D02*
|
||||||
|
D03*
|
||||||
|
X537000Y256000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X611000Y354000D02*
|
||||||
|
D03*
|
||||||
|
X629000D02*
|
||||||
|
D03*
|
||||||
|
X447500Y35000D02*
|
||||||
|
D03*
|
||||||
|
X465500D02*
|
||||||
|
D03*
|
||||||
|
D20*
|
||||||
|
X555000Y380000D02*
|
||||||
|
D03*
|
||||||
|
X572000D02*
|
||||||
|
D03*
|
||||||
|
X555000Y405000D02*
|
||||||
|
D03*
|
||||||
|
X572000D02*
|
||||||
|
D03*
|
||||||
|
X542500Y64000D02*
|
||||||
|
D03*
|
||||||
|
X525500D02*
|
||||||
|
D03*
|
||||||
|
X465000Y55000D02*
|
||||||
|
D03*
|
||||||
|
X448000D02*
|
||||||
|
D03*
|
||||||
|
D21*
|
||||||
|
X327500Y63500D02*
|
||||||
|
D03*
|
||||||
|
Y46500D02*
|
||||||
|
D03*
|
||||||
|
X302500Y63500D02*
|
||||||
|
D03*
|
||||||
|
Y46500D02*
|
||||||
|
D03*
|
||||||
|
D22*
|
||||||
|
X625000Y52000D02*
|
||||||
|
D03*
|
||||||
|
Y70000D02*
|
||||||
|
D03*
|
||||||
|
D43*
|
||||||
|
X535437Y470750D02*
|
||||||
|
X537000Y469187D01*
|
||||||
|
X546000Y94000D02*
|
||||||
|
X550000D01*
|
||||||
|
X507500Y132500D02*
|
||||||
|
X546000Y94000D01*
|
||||||
|
X500000Y255000D02*
|
||||||
|
Y285000D01*
|
||||||
|
X499000Y252000D02*
|
||||||
|
X501000Y254000D01*
|
||||||
|
X235000Y72590D02*
|
||||||
|
X256090Y51500D01*
|
||||||
|
X235000Y72590D02*
|
||||||
|
Y80000D01*
|
||||||
|
X256090Y51500D02*
|
||||||
|
X256500D01*
|
||||||
|
X267500Y40500D01*
|
||||||
|
X270000D01*
|
||||||
|
X270500Y40000D02*
|
||||||
|
X295000D01*
|
||||||
|
X270000Y40500D02*
|
||||||
|
X270500Y40000D01*
|
||||||
|
X295000D02*
|
||||||
|
X301500Y46500D01*
|
||||||
|
X302500D01*
|
||||||
|
X327500D01*
|
||||||
|
X245000Y170000D02*
|
||||||
|
X347000D01*
|
||||||
|
X451000Y274000D01*
|
||||||
|
X467500Y225000D02*
|
||||||
|
X468500Y226000D01*
|
||||||
|
X467500Y151500D02*
|
||||||
|
Y225000D01*
|
||||||
|
X468500Y226000D02*
|
||||||
|
Y299500D01*
|
||||||
|
X571000Y405000D02*
|
||||||
|
X572000Y404000D01*
|
||||||
|
X100000Y360000D02*
|
||||||
|
X140000Y400000D01*
|
||||||
|
X100000Y268130D02*
|
||||||
|
Y360000D01*
|
||||||
|
Y268130D02*
|
||||||
|
X118130Y250000D01*
|
||||||
|
X120000D01*
|
||||||
|
Y225000D02*
|
||||||
|
Y250000D01*
|
||||||
|
X593800Y460000D02*
|
||||||
|
Y463200D01*
|
||||||
|
X574999Y198000D02*
|
||||||
|
Y247999D01*
|
||||||
|
X663000Y305000D02*
|
||||||
|
X678900Y320900D01*
|
||||||
|
X618000Y305000D02*
|
||||||
|
X663000D01*
|
||||||
|
X575000Y262000D02*
|
||||||
|
X618000Y305000D01*
|
||||||
|
X575000Y248000D02*
|
||||||
|
Y262000D01*
|
||||||
|
X140000Y400000D02*
|
||||||
|
Y440000D01*
|
||||||
|
X611000Y354000D02*
|
||||||
|
Y359000D01*
|
||||||
|
X600000Y370000D02*
|
||||||
|
X611000Y359000D01*
|
||||||
|
X600000Y370000D02*
|
||||||
|
Y381000D01*
|
||||||
|
X586000Y356000D02*
|
||||||
|
X600000Y370000D01*
|
||||||
|
X554000Y356000D02*
|
||||||
|
X586000D01*
|
||||||
|
X526500Y328500D02*
|
||||||
|
X554000Y356000D01*
|
||||||
|
X569500Y487500D02*
|
||||||
|
X593800Y463200D01*
|
||||||
|
X187500Y487500D02*
|
||||||
|
X569500D01*
|
||||||
|
X499000Y386000D02*
|
||||||
|
X502000Y389000D01*
|
||||||
|
X561400Y467000D02*
|
||||||
|
X593800Y434600D01*
|
||||||
|
X557000Y467000D02*
|
||||||
|
X561400D01*
|
||||||
|
X588200Y409200D02*
|
||||||
|
X600800D01*
|
||||||
|
X584000Y405000D02*
|
||||||
|
X588200Y409200D01*
|
||||||
|
X572000Y405000D02*
|
||||||
|
X584000D01*
|
||||||
|
X542500Y63000D02*
|
||||||
|
X566000D01*
|
||||||
|
X593800Y90800D01*
|
||||||
|
X587913Y62913D02*
|
||||||
|
X591313D01*
|
||||||
|
X572500Y47500D02*
|
||||||
|
X587913Y62913D01*
|
||||||
|
X532272Y47500D02*
|
||||||
|
X572500D01*
|
||||||
|
X579800Y26000D02*
|
||||||
|
X597300Y43500D01*
|
||||||
|
X624000Y52000D02*
|
||||||
|
X625000D01*
|
||||||
|
X618500Y46500D02*
|
||||||
|
X624000Y52000D01*
|
||||||
|
X607300Y46500D02*
|
||||||
|
X618500D01*
|
||||||
|
X600800Y40000D02*
|
||||||
|
X607300Y46500D01*
|
||||||
|
X624000Y70000D02*
|
||||||
|
X625000D01*
|
||||||
|
X603200Y90800D02*
|
||||||
|
X624000Y70000D01*
|
||||||
|
X600800Y90800D02*
|
||||||
|
X603200D01*
|
||||||
|
X596287Y88313D02*
|
||||||
|
X600687D01*
|
||||||
|
X591900Y381900D02*
|
||||||
|
X592000Y382000D01*
|
||||||
|
X526500Y326200D02*
|
||||||
|
Y328500D01*
|
||||||
|
X495200Y326200D02*
|
||||||
|
X501100D01*
|
||||||
|
X577300Y331144D02*
|
||||||
|
Y331200D01*
|
||||||
|
X555000Y271000D02*
|
||||||
|
X580000Y296000D01*
|
||||||
|
X555000Y256000D02*
|
||||||
|
Y271000D01*
|
||||||
|
X611000Y354000D02*
|
||||||
|
X613000Y356000D01*
|
||||||
|
X573900Y381900D02*
|
||||||
|
X591900D01*
|
||||||
|
X572000Y380000D02*
|
||||||
|
X573900Y381900D01*
|
||||||
|
X629000Y353000D02*
|
||||||
|
Y354000D01*
|
||||||
|
Y353000D02*
|
||||||
|
X653500Y328500D01*
|
||||||
|
Y326200D02*
|
||||||
|
Y328500D01*
|
||||||
|
X527000Y388000D02*
|
||||||
|
Y425000D01*
|
||||||
|
X526577Y387000D02*
|
||||||
|
X528000D01*
|
||||||
|
X432000Y350000D02*
|
||||||
|
X489577D01*
|
||||||
|
X527000Y425000D02*
|
||||||
|
X537000Y435000D01*
|
||||||
|
X527000Y388000D02*
|
||||||
|
X528000Y387000D01*
|
||||||
|
X535617Y432383D02*
|
||||||
|
X535999Y432000D01*
|
||||||
|
X489577Y350000D02*
|
||||||
|
X526577Y387000D01*
|
||||||
|
X481500Y291500D02*
|
||||||
|
X495000Y305000D01*
|
||||||
|
X500000Y255000D02*
|
||||||
|
X501000Y254000D01*
|
||||||
|
X481500Y165823D02*
|
||||||
|
Y291500D01*
|
||||||
|
X495000Y305000D02*
|
||||||
|
X558277D01*
|
||||||
|
X468500Y299500D02*
|
||||||
|
X495200Y326200D01*
|
||||||
|
X499000Y252000D02*
|
||||||
|
X499000Y252000D01*
|
||||||
|
X543999Y188217D02*
|
||||||
|
Y231999D01*
|
||||||
|
X542500Y186718D02*
|
||||||
|
X543999Y188217D01*
|
||||||
|
X542500Y186718D02*
|
||||||
|
X551900Y177318D01*
|
||||||
|
X368000Y451000D02*
|
||||||
|
X388000Y431000D01*
|
||||||
|
X261000Y451000D02*
|
||||||
|
X368000D01*
|
||||||
|
X245000Y435000D02*
|
||||||
|
X261000Y451000D01*
|
||||||
|
X388000Y394000D02*
|
||||||
|
Y431000D01*
|
||||||
|
Y394000D02*
|
||||||
|
X432000Y350000D01*
|
||||||
|
X525000Y175000D02*
|
||||||
|
X526500Y176500D01*
|
||||||
|
X520000Y219563D02*
|
||||||
|
Y224000D01*
|
||||||
|
Y219563D02*
|
||||||
|
X526500Y213063D01*
|
||||||
|
X500499Y174401D02*
|
||||||
|
X501100Y173800D01*
|
||||||
|
X500499Y174401D02*
|
||||||
|
Y231248D01*
|
||||||
|
X515000Y245749D01*
|
||||||
|
Y254000D01*
|
||||||
|
X517000Y256000D01*
|
||||||
|
X526500Y176500D02*
|
||||||
|
Y213063D01*
|
||||||
|
X551900Y173800D02*
|
||||||
|
Y177318D01*
|
||||||
|
X537000Y256000D02*
|
||||||
|
X537000Y256000D01*
|
||||||
|
X517000Y256000D02*
|
||||||
|
X537000D01*
|
||||||
|
X497323Y150000D02*
|
||||||
|
X517500D01*
|
||||||
|
X551300Y116200D01*
|
||||||
|
X481500Y165823D02*
|
||||||
|
X497323Y150000D01*
|
||||||
|
X551300Y116200D02*
|
||||||
|
X593800D01*
|
||||||
|
X571000Y405000D02*
|
||||||
|
X572000D01*
|
||||||
|
Y380000D02*
|
||||||
|
Y404000D01*
|
||||||
|
X555000Y379000D02*
|
||||||
|
Y380000D01*
|
||||||
|
X552500Y376500D02*
|
||||||
|
X555000Y379000D01*
|
||||||
|
X548415Y376500D02*
|
||||||
|
X552500D01*
|
||||||
|
X501100Y329185D02*
|
||||||
|
X548415Y376500D01*
|
||||||
|
X501100Y326200D02*
|
||||||
|
Y329185D01*
|
||||||
|
X140000Y440000D02*
|
||||||
|
X187500Y487500D01*
|
||||||
|
X245000Y405000D02*
|
||||||
|
Y435000D01*
|
||||||
|
X120000Y280000D02*
|
||||||
|
X245000Y405000D01*
|
||||||
|
X120000Y275000D02*
|
||||||
|
Y280000D01*
|
||||||
|
X555000Y469000D02*
|
||||||
|
Y470000D01*
|
||||||
|
Y469000D02*
|
||||||
|
X557000Y467000D01*
|
||||||
|
X406223Y326200D02*
|
||||||
|
X495200D01*
|
||||||
|
X304600Y427823D02*
|
||||||
|
X406223Y326200D01*
|
||||||
|
X304600Y427823D02*
|
||||||
|
Y430000D01*
|
||||||
|
X555000Y405000D02*
|
||||||
|
Y435000D01*
|
||||||
|
X506550Y470750D02*
|
||||||
|
X535437D01*
|
||||||
|
X500500Y464700D02*
|
||||||
|
X506550Y470750D01*
|
||||||
|
X537000Y469187D02*
|
||||||
|
Y470000D01*
|
||||||
|
Y460728D02*
|
||||||
|
Y469187D01*
|
||||||
|
Y460728D02*
|
||||||
|
X553000Y444728D01*
|
||||||
|
Y437000D02*
|
||||||
|
Y444728D01*
|
||||||
|
Y437000D02*
|
||||||
|
X555000Y435000D01*
|
||||||
|
X554000Y384000D02*
|
||||||
|
Y405000D01*
|
||||||
|
Y405000D02*
|
||||||
|
X554000Y405000D01*
|
||||||
|
X554000Y405000D02*
|
||||||
|
X554000Y405000D01*
|
||||||
|
X465000Y30000D02*
|
||||||
|
Y55000D01*
|
||||||
|
X448000Y35000D02*
|
||||||
|
Y55000D01*
|
||||||
|
X467500Y108223D02*
|
||||||
|
Y151500D01*
|
||||||
|
X419077Y59800D02*
|
||||||
|
X467500Y108223D01*
|
||||||
|
X416900Y59800D02*
|
||||||
|
X419077D01*
|
||||||
|
X432900Y14900D02*
|
||||||
|
X447000Y29000D01*
|
||||||
|
X400100Y14900D02*
|
||||||
|
X432900D01*
|
||||||
|
X395000Y20000D02*
|
||||||
|
X400100Y14900D01*
|
||||||
|
X395000Y20000D02*
|
||||||
|
Y75000D01*
|
||||||
|
X405200Y85200D01*
|
||||||
|
X416900D01*
|
||||||
|
X447000Y29000D02*
|
||||||
|
Y30000D01*
|
||||||
|
X448000Y31000D01*
|
||||||
|
Y35000D01*
|
||||||
|
X465000Y59900D02*
|
||||||
|
X493000D01*
|
||||||
|
X495587Y57313D01*
|
||||||
|
X467500Y151500D02*
|
||||||
|
X486500Y132500D01*
|
||||||
|
X574999Y247999D02*
|
||||||
|
X575000Y248000D01*
|
||||||
|
X678900Y320900D02*
|
||||||
|
Y326200D01*
|
||||||
|
X504075Y57313D02*
|
||||||
|
X535387Y26000D01*
|
||||||
|
X579800D01*
|
||||||
|
X527000Y52772D02*
|
||||||
|
X532272Y47500D01*
|
||||||
|
X527000Y52772D02*
|
||||||
|
Y62500D01*
|
||||||
|
X525500Y64000D02*
|
||||||
|
X527000Y62500D01*
|
||||||
|
X495587Y57313D02*
|
||||||
|
X504075D01*
|
||||||
|
X567000Y96000D02*
|
||||||
|
Y97000D01*
|
||||||
|
X564000Y93000D02*
|
||||||
|
X567000Y96000D01*
|
||||||
|
X564000Y86272D02*
|
||||||
|
Y93000D01*
|
||||||
|
X558478Y80750D02*
|
||||||
|
X564000Y86272D01*
|
||||||
|
X532522Y80750D02*
|
||||||
|
X558478D01*
|
||||||
|
X527000Y75228D02*
|
||||||
|
X532522Y80750D01*
|
||||||
|
X527000Y65500D02*
|
||||||
|
Y75228D01*
|
||||||
|
X525500Y64000D02*
|
||||||
|
X527000Y65500D01*
|
||||||
|
X593800Y90800D02*
|
||||||
|
X596287Y88313D01*
|
||||||
|
X591313Y62913D02*
|
||||||
|
X593800Y65400D01*
|
||||||
|
X486500Y132500D02*
|
||||||
|
X507500D01*
|
||||||
|
X500500Y388500D02*
|
||||||
|
X501000Y389000D01*
|
||||||
|
X499000Y386000D02*
|
||||||
|
X499000D01*
|
||||||
|
X502000Y389000D02*
|
||||||
|
X506000D01*
|
||||||
|
X558277Y305000D02*
|
||||||
|
X577300Y324023D01*
|
||||||
|
Y326200D01*
|
||||||
|
X571000Y405000D02*
|
||||||
|
X571000Y405000D01*
|
||||||
|
X501000Y389000D02*
|
||||||
|
X502000D01*
|
||||||
|
D44*
|
||||||
|
X650000Y250000D02*
|
||||||
|
D03*
|
||||||
|
X25000Y475000D02*
|
||||||
|
D03*
|
||||||
|
Y25000D02*
|
||||||
|
D03*
|
||||||
|
D45*
|
||||||
|
X120000Y347500D02*
|
||||||
|
D03*
|
||||||
|
Y320000D02*
|
||||||
|
D03*
|
||||||
|
X355400Y430000D02*
|
||||||
|
D03*
|
||||||
|
X330000D02*
|
||||||
|
D03*
|
||||||
|
X304600D02*
|
||||||
|
D03*
|
||||||
|
X587000Y299000D02*
|
||||||
|
D03*
|
||||||
|
X235000Y80000D02*
|
||||||
|
D03*
|
||||||
|
X245000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X574999Y198000D02*
|
||||||
|
D03*
|
||||||
|
X528000Y387000D02*
|
||||||
|
D03*
|
||||||
|
X500000Y285000D02*
|
||||||
|
D03*
|
||||||
|
X543999Y231999D02*
|
||||||
|
D03*
|
||||||
|
X451000Y274000D02*
|
||||||
|
D03*
|
||||||
|
X520000Y224000D02*
|
||||||
|
D03*
|
||||||
|
D46*
|
||||||
|
X80000Y450000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y400000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y100000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y50000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
D47*
|
||||||
|
X80000Y300800D02*
|
||||||
|
D03*
|
||||||
|
Y275400D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y224600D02*
|
||||||
|
D03*
|
||||||
|
X254600Y119000D02*
|
||||||
|
D03*
|
||||||
|
X356200D02*
|
||||||
|
D03*
|
||||||
|
X330800D02*
|
||||||
|
D03*
|
||||||
|
X305400D02*
|
||||||
|
D03*
|
||||||
|
X280000D02*
|
||||||
|
D03*
|
||||||
|
D48*
|
||||||
|
X80000Y199200D02*
|
||||||
|
D03*
|
||||||
|
D49*
|
||||||
|
X381600Y119000D02*
|
||||||
|
D03*
|
||||||
|
D50*
|
||||||
|
X190000Y203000D02*
|
||||||
|
D03*
|
||||||
|
Y297000D02*
|
||||||
|
D03*
|
||||||
|
D51*
|
||||||
|
X120000Y225000D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y275000D02*
|
||||||
|
D03*
|
||||||
|
D52*
|
||||||
|
X677000Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y460000D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y434600D02*
|
||||||
|
D03*
|
||||||
|
Y409200D02*
|
||||||
|
D03*
|
||||||
|
X677000Y40000D02*
|
||||||
|
D03*
|
||||||
|
Y116200D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y90800D02*
|
||||||
|
D03*
|
||||||
|
Y65400D02*
|
||||||
|
D03*
|
||||||
|
X678900Y326200D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
X678900Y173800D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
D53*
|
||||||
|
X600800Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y40000D02*
|
||||||
|
D03*
|
||||||
|
D54*
|
||||||
|
X416900Y34400D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y110600D02*
|
||||||
|
D03*
|
||||||
|
X493100D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
D55*
|
||||||
|
Y34400D02*
|
||||||
|
D03*
|
||||||
|
D56*
|
||||||
|
X279200Y430000D02*
|
||||||
|
D03*
|
||||||
|
D57*
|
||||||
|
X424300Y464684D02*
|
||||||
|
D03*
|
||||||
|
D58*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y388500D02*
|
||||||
|
D03*
|
||||||
|
X500500D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y464700D02*
|
||||||
|
D03*
|
||||||
|
D59*
|
||||||
|
X270000Y69500D02*
|
||||||
|
D03*
|
||||||
|
Y40500D02*
|
||||||
|
D03*
|
||||||
|
M02*
|
||||||
456
PCB/GerberManufacture/OptoTest.GBO
Normal file
456
PCB/GerberManufacture/OptoTest.GBO
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=32896*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD11C,0.2540*%
|
||||||
|
%ADD12C,0.2000*%
|
||||||
|
%ADD14C,0.1000*%
|
||||||
|
%ADD61C,0.1270*%
|
||||||
|
D11*
|
||||||
|
X269843Y100196D02*
|
||||||
|
X272383Y102735D01*
|
||||||
|
X277461D01*
|
||||||
|
X280000Y100196D01*
|
||||||
|
Y90039D01*
|
||||||
|
X277461Y87500D01*
|
||||||
|
X272383D01*
|
||||||
|
X269843Y90039D01*
|
||||||
|
X264765Y87500D02*
|
||||||
|
X259687D01*
|
||||||
|
X262226D01*
|
||||||
|
Y102735D01*
|
||||||
|
X264765Y100196D01*
|
||||||
|
X679000Y347000D02*
|
||||||
|
Y362235D01*
|
||||||
|
X671383D01*
|
||||||
|
X668843Y359696D01*
|
||||||
|
Y354618D01*
|
||||||
|
X671383Y352078D01*
|
||||||
|
X679000D01*
|
||||||
|
X673922D02*
|
||||||
|
X668843Y347000D01*
|
||||||
|
X663765D02*
|
||||||
|
X658687D01*
|
||||||
|
X661226D01*
|
||||||
|
Y362235D01*
|
||||||
|
X663765Y359696D01*
|
||||||
|
X651069D02*
|
||||||
|
X648530Y362235D01*
|
||||||
|
X643452D01*
|
||||||
|
X640912Y359696D01*
|
||||||
|
Y349539D01*
|
||||||
|
X643452Y347000D01*
|
||||||
|
X648530D01*
|
||||||
|
X651069Y349539D01*
|
||||||
|
Y359696D01*
|
||||||
|
X567000Y274000D02*
|
||||||
|
Y289235D01*
|
||||||
|
X559383D01*
|
||||||
|
X556843Y286696D01*
|
||||||
|
Y281618D01*
|
||||||
|
X559383Y279078D01*
|
||||||
|
X567000D01*
|
||||||
|
X561922D02*
|
||||||
|
X556843Y274000D01*
|
||||||
|
X551765Y276539D02*
|
||||||
|
X549226Y274000D01*
|
||||||
|
X544147D01*
|
||||||
|
X541608Y276539D01*
|
||||||
|
Y286696D01*
|
||||||
|
X544147Y289235D01*
|
||||||
|
X549226D01*
|
||||||
|
X551765Y286696D01*
|
||||||
|
Y284157D01*
|
||||||
|
X549226Y281618D01*
|
||||||
|
X541608D01*
|
||||||
|
X534000Y274000D02*
|
||||||
|
Y289235D01*
|
||||||
|
X526382D01*
|
||||||
|
X523843Y286696D01*
|
||||||
|
Y281618D01*
|
||||||
|
X526382Y279078D01*
|
||||||
|
X534000D01*
|
||||||
|
X528922D02*
|
||||||
|
X523843Y274000D01*
|
||||||
|
X518765Y286696D02*
|
||||||
|
X516226Y289235D01*
|
||||||
|
X511147D01*
|
||||||
|
X508608Y286696D01*
|
||||||
|
Y284157D01*
|
||||||
|
X511147Y281618D01*
|
||||||
|
X508608Y279078D01*
|
||||||
|
Y276539D01*
|
||||||
|
X511147Y274000D01*
|
||||||
|
X516226D01*
|
||||||
|
X518765Y276539D01*
|
||||||
|
Y279078D01*
|
||||||
|
X516226Y281618D01*
|
||||||
|
X518765Y284157D01*
|
||||||
|
Y286696D01*
|
||||||
|
X516226Y281618D02*
|
||||||
|
X511147D01*
|
||||||
|
X569843Y68696D02*
|
||||||
|
X572383Y71235D01*
|
||||||
|
X577461D01*
|
||||||
|
X580000Y68696D01*
|
||||||
|
Y58539D01*
|
||||||
|
X577461Y56000D01*
|
||||||
|
X572383D01*
|
||||||
|
X569843Y58539D01*
|
||||||
|
X564765Y68696D02*
|
||||||
|
X562226Y71235D01*
|
||||||
|
X557147D01*
|
||||||
|
X554608Y68696D01*
|
||||||
|
Y66157D01*
|
||||||
|
X557147Y63618D01*
|
||||||
|
X554608Y61078D01*
|
||||||
|
Y58539D01*
|
||||||
|
X557147Y56000D01*
|
||||||
|
X562226D01*
|
||||||
|
X564765Y58539D01*
|
||||||
|
Y61078D01*
|
||||||
|
X562226Y63618D01*
|
||||||
|
X564765Y66157D01*
|
||||||
|
Y68696D01*
|
||||||
|
X562226Y63618D02*
|
||||||
|
X557147D01*
|
||||||
|
X648000Y65696D02*
|
||||||
|
X645461Y68235D01*
|
||||||
|
X640383D01*
|
||||||
|
X637843Y65696D01*
|
||||||
|
Y55539D01*
|
||||||
|
X640383Y53000D01*
|
||||||
|
X645461D01*
|
||||||
|
X648000Y55539D01*
|
||||||
|
Y65696D01*
|
||||||
|
X469000Y7500D02*
|
||||||
|
Y22735D01*
|
||||||
|
X461382D01*
|
||||||
|
X458843Y20196D01*
|
||||||
|
Y15117D01*
|
||||||
|
X461382Y12578D01*
|
||||||
|
X469000D01*
|
||||||
|
X463922D02*
|
||||||
|
X458843Y7500D01*
|
||||||
|
X443608Y22735D02*
|
||||||
|
X453765D01*
|
||||||
|
Y15117D01*
|
||||||
|
X448687D01*
|
||||||
|
X453765D01*
|
||||||
|
Y7500D01*
|
||||||
|
X456343Y80196D02*
|
||||||
|
X458882Y82735D01*
|
||||||
|
X463961D01*
|
||||||
|
X466500Y80196D01*
|
||||||
|
Y70039D01*
|
||||||
|
X463961Y67500D01*
|
||||||
|
X458882D01*
|
||||||
|
X456343Y70039D01*
|
||||||
|
X441108Y82735D02*
|
||||||
|
X451265D01*
|
||||||
|
Y75118D01*
|
||||||
|
X446187D01*
|
||||||
|
X451265D01*
|
||||||
|
Y67500D01*
|
||||||
|
X535500Y89000D02*
|
||||||
|
Y104235D01*
|
||||||
|
X527882D01*
|
||||||
|
X525343Y101696D01*
|
||||||
|
Y96618D01*
|
||||||
|
X527882Y94078D01*
|
||||||
|
X535500D01*
|
||||||
|
X530422D02*
|
||||||
|
X525343Y89000D01*
|
||||||
|
X520265Y101696D02*
|
||||||
|
X517726Y104235D01*
|
||||||
|
X512647D01*
|
||||||
|
X510108Y101696D01*
|
||||||
|
Y99157D01*
|
||||||
|
X512647Y96618D01*
|
||||||
|
X515187D01*
|
||||||
|
X512647D01*
|
||||||
|
X510108Y94078D01*
|
||||||
|
Y91539D01*
|
||||||
|
X512647Y89000D01*
|
||||||
|
X517726D01*
|
||||||
|
X520265Y91539D01*
|
||||||
|
X529843Y412696D02*
|
||||||
|
X532383Y415235D01*
|
||||||
|
X537461D01*
|
||||||
|
X540000Y412696D01*
|
||||||
|
Y402539D01*
|
||||||
|
X537461Y400000D01*
|
||||||
|
X532383D01*
|
||||||
|
X529843Y402539D01*
|
||||||
|
X514608Y415235D02*
|
||||||
|
X524765D01*
|
||||||
|
Y407617D01*
|
||||||
|
X519687Y410157D01*
|
||||||
|
X517147D01*
|
||||||
|
X514608Y407617D01*
|
||||||
|
Y402539D01*
|
||||||
|
X517147Y400000D01*
|
||||||
|
X522226D01*
|
||||||
|
X524765Y402539D01*
|
||||||
|
X529843Y387696D02*
|
||||||
|
X532383Y390235D01*
|
||||||
|
X537461D01*
|
||||||
|
X540000Y387696D01*
|
||||||
|
Y377539D01*
|
||||||
|
X537461Y375000D01*
|
||||||
|
X532383D01*
|
||||||
|
X529843Y377539D01*
|
||||||
|
X517147Y375000D02*
|
||||||
|
Y390235D01*
|
||||||
|
X524765Y382617D01*
|
||||||
|
X514608D01*
|
||||||
|
D12*
|
||||||
|
X619000Y61000D02*
|
||||||
|
X631000D01*
|
||||||
|
X546000Y429000D02*
|
||||||
|
Y441000D01*
|
||||||
|
Y464000D02*
|
||||||
|
Y476000D01*
|
||||||
|
X558000Y91000D02*
|
||||||
|
Y103000D01*
|
||||||
|
X508000Y250000D02*
|
||||||
|
Y262000D01*
|
||||||
|
X546000Y250000D02*
|
||||||
|
Y262000D01*
|
||||||
|
X620000Y348000D02*
|
||||||
|
Y360000D01*
|
||||||
|
X456500Y29000D02*
|
||||||
|
Y41000D01*
|
||||||
|
X328335Y88331D02*
|
||||||
|
X330002Y89997D01*
|
||||||
|
X333334D01*
|
||||||
|
X335000Y88331D01*
|
||||||
|
Y81666D01*
|
||||||
|
X333334Y80000D01*
|
||||||
|
X330002D01*
|
||||||
|
X328335Y81666D01*
|
||||||
|
X325003Y89997D02*
|
||||||
|
X318339D01*
|
||||||
|
Y88331D01*
|
||||||
|
X325003Y81666D01*
|
||||||
|
Y80000D01*
|
||||||
|
X303335Y88331D02*
|
||||||
|
X305002Y89997D01*
|
||||||
|
X308334D01*
|
||||||
|
X310000Y88331D01*
|
||||||
|
Y81666D01*
|
||||||
|
X308334Y80000D01*
|
||||||
|
X305002D01*
|
||||||
|
X303335Y81666D01*
|
||||||
|
X293339Y89997D02*
|
||||||
|
X296671Y88331D01*
|
||||||
|
X300003Y84998D01*
|
||||||
|
Y81666D01*
|
||||||
|
X298337Y80000D01*
|
||||||
|
X295005D01*
|
||||||
|
X293339Y81666D01*
|
||||||
|
Y83332D01*
|
||||||
|
X295005Y84998D01*
|
||||||
|
X300003D01*
|
||||||
|
X583000Y473000D02*
|
||||||
|
Y482997D01*
|
||||||
|
X578002D01*
|
||||||
|
X576335Y481331D01*
|
||||||
|
Y477998D01*
|
||||||
|
X578002Y476332D01*
|
||||||
|
X583000D01*
|
||||||
|
X579668D02*
|
||||||
|
X576335Y473000D01*
|
||||||
|
X566339D02*
|
||||||
|
X573003D01*
|
||||||
|
X566339Y479664D01*
|
||||||
|
Y481331D01*
|
||||||
|
X568005Y482997D01*
|
||||||
|
X571337D01*
|
||||||
|
X573003Y481331D01*
|
||||||
|
X580000Y443000D02*
|
||||||
|
Y452997D01*
|
||||||
|
X575002D01*
|
||||||
|
X573335Y451331D01*
|
||||||
|
Y447998D01*
|
||||||
|
X575002Y446332D01*
|
||||||
|
X580000D01*
|
||||||
|
X576668D02*
|
||||||
|
X573335Y443000D01*
|
||||||
|
X570003D02*
|
||||||
|
X566671D01*
|
||||||
|
X568337D01*
|
||||||
|
Y452997D01*
|
||||||
|
X570003Y451331D01*
|
||||||
|
D14*
|
||||||
|
X337660Y37474D02*
|
||||||
|
Y72526D01*
|
||||||
|
X330040D02*
|
||||||
|
X337660D01*
|
||||||
|
X330040Y37474D02*
|
||||||
|
X337660D01*
|
||||||
|
X317340Y72526D02*
|
||||||
|
X324960D01*
|
||||||
|
X317340Y37474D02*
|
||||||
|
X324960D01*
|
||||||
|
X317340D02*
|
||||||
|
Y72526D01*
|
||||||
|
X312660Y37474D02*
|
||||||
|
Y72526D01*
|
||||||
|
X305040D02*
|
||||||
|
X312660D01*
|
||||||
|
X305040Y37474D02*
|
||||||
|
X312660D01*
|
||||||
|
X292340Y72526D02*
|
||||||
|
X299960D01*
|
||||||
|
X292340Y37474D02*
|
||||||
|
X299960D01*
|
||||||
|
X292340D02*
|
||||||
|
Y72526D01*
|
||||||
|
X634652Y43474D02*
|
||||||
|
X634652Y57190D01*
|
||||||
|
X615348Y43474D02*
|
||||||
|
X634652D01*
|
||||||
|
X615348Y57190D02*
|
||||||
|
X615348Y43474D01*
|
||||||
|
X634652Y64810D02*
|
||||||
|
Y78526D01*
|
||||||
|
X615348D02*
|
||||||
|
X634652D01*
|
||||||
|
X615348Y64810D02*
|
||||||
|
Y78526D01*
|
||||||
|
X545974Y390160D02*
|
||||||
|
X581026D01*
|
||||||
|
X545974Y382540D02*
|
||||||
|
Y390160D01*
|
||||||
|
X581026Y382540D02*
|
||||||
|
Y390160D01*
|
||||||
|
X545974Y369840D02*
|
||||||
|
Y377460D01*
|
||||||
|
X581026Y369840D02*
|
||||||
|
Y377460D01*
|
||||||
|
X545974Y369840D02*
|
||||||
|
X581026D01*
|
||||||
|
X545974Y415160D02*
|
||||||
|
X581026D01*
|
||||||
|
X545974Y407540D02*
|
||||||
|
Y415160D01*
|
||||||
|
X581026Y407540D02*
|
||||||
|
Y415160D01*
|
||||||
|
X545974Y394840D02*
|
||||||
|
Y402460D01*
|
||||||
|
X581026Y394840D02*
|
||||||
|
Y402460D01*
|
||||||
|
X545974Y394840D02*
|
||||||
|
X581026D01*
|
||||||
|
X516474Y53840D02*
|
||||||
|
X551526D01*
|
||||||
|
Y61460D01*
|
||||||
|
X516474Y53840D02*
|
||||||
|
Y61460D01*
|
||||||
|
X551526Y66540D02*
|
||||||
|
Y74160D01*
|
||||||
|
X516474Y66540D02*
|
||||||
|
Y74160D01*
|
||||||
|
X551526D01*
|
||||||
|
X438974Y44840D02*
|
||||||
|
X474026D01*
|
||||||
|
Y52460D01*
|
||||||
|
X438974Y44840D02*
|
||||||
|
Y52460D01*
|
||||||
|
X474026Y57540D02*
|
||||||
|
Y65160D01*
|
||||||
|
X438974Y57540D02*
|
||||||
|
Y65160D01*
|
||||||
|
X474026D01*
|
||||||
|
X528474Y425348D02*
|
||||||
|
X542190Y425348D01*
|
||||||
|
X528474Y425348D02*
|
||||||
|
Y444652D01*
|
||||||
|
X542190Y444652D01*
|
||||||
|
X549810Y425348D02*
|
||||||
|
X563526D01*
|
||||||
|
Y444652D01*
|
||||||
|
X549810D02*
|
||||||
|
X563526D01*
|
||||||
|
X528474Y460348D02*
|
||||||
|
X542190Y460348D01*
|
||||||
|
X528474Y460348D02*
|
||||||
|
Y479652D01*
|
||||||
|
X542190Y479652D01*
|
||||||
|
X549810Y460348D02*
|
||||||
|
X563526D01*
|
||||||
|
Y479652D01*
|
||||||
|
X549810D02*
|
||||||
|
X563526D01*
|
||||||
|
X540474Y87348D02*
|
||||||
|
X554190Y87348D01*
|
||||||
|
X540474Y87348D02*
|
||||||
|
Y106652D01*
|
||||||
|
X554190Y106652D01*
|
||||||
|
X561810Y87348D02*
|
||||||
|
X575526D01*
|
||||||
|
Y106652D01*
|
||||||
|
X561810D02*
|
||||||
|
X575526D01*
|
||||||
|
X511810Y265652D02*
|
||||||
|
X525526Y265652D01*
|
||||||
|
Y246348D02*
|
||||||
|
Y265652D01*
|
||||||
|
X511810Y246348D02*
|
||||||
|
X525526Y246348D01*
|
||||||
|
X490474Y265652D02*
|
||||||
|
X504190D01*
|
||||||
|
X490474Y246348D02*
|
||||||
|
Y265652D01*
|
||||||
|
Y246348D02*
|
||||||
|
X504190D01*
|
||||||
|
X528474Y246348D02*
|
||||||
|
X542190Y246348D01*
|
||||||
|
X528474Y246348D02*
|
||||||
|
Y265652D01*
|
||||||
|
X542190Y265652D01*
|
||||||
|
X549810Y246348D02*
|
||||||
|
X563526D01*
|
||||||
|
Y265652D01*
|
||||||
|
X549810D02*
|
||||||
|
X563526D01*
|
||||||
|
X602474Y344348D02*
|
||||||
|
X616190Y344348D01*
|
||||||
|
X602474Y344348D02*
|
||||||
|
Y363652D01*
|
||||||
|
X616190Y363652D01*
|
||||||
|
X623810Y344348D02*
|
||||||
|
X637526D01*
|
||||||
|
Y363652D01*
|
||||||
|
X623810D02*
|
||||||
|
X637526D01*
|
||||||
|
X438974Y25348D02*
|
||||||
|
X452690Y25348D01*
|
||||||
|
X438974Y25348D02*
|
||||||
|
Y44652D01*
|
||||||
|
X452690Y44652D01*
|
||||||
|
X460310Y25348D02*
|
||||||
|
X474026D01*
|
||||||
|
Y44652D01*
|
||||||
|
X460310D02*
|
||||||
|
X474026D01*
|
||||||
|
D61*
|
||||||
|
X255000Y40000D02*
|
||||||
|
Y66000D01*
|
||||||
|
X285000Y42000D02*
|
||||||
|
X288000D01*
|
||||||
|
Y40000D02*
|
||||||
|
Y42000D01*
|
||||||
|
X285000Y40000D02*
|
||||||
|
X288000D01*
|
||||||
|
X285000Y41000D02*
|
||||||
|
X288000D01*
|
||||||
|
X285000Y40000D02*
|
||||||
|
Y66000D01*
|
||||||
|
M02*
|
||||||
89
PCB/GerberManufacture/OptoTest.GBP
Normal file
89
PCB/GerberManufacture/OptoTest.GBP
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=128*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD19R,1.2000X1.4000*%
|
||||||
|
%ADD20R,1.3000X1.5000*%
|
||||||
|
%ADD21R,1.5000X1.3000*%
|
||||||
|
%ADD22R,1.4000X1.2000*%
|
||||||
|
G04:AMPARAMS|DCode=59|XSize=2.3mm|YSize=1.8mm|CornerRadius=0.225mm|HoleSize=0mm|Usage=FLASHONLY|Rotation=0.000|XOffset=0mm|YOffset=0mm|HoleType=Round|Shape=RoundedRectangle|*
|
||||||
|
%AMROUNDEDRECTD59*
|
||||||
|
21,1,2.3000,1.3500,0,0,0.0*
|
||||||
|
21,1,1.8500,1.8000,0,0,0.0*
|
||||||
|
1,1,0.4500,0.9250,-0.6750*
|
||||||
|
1,1,0.4500,-0.9250,-0.6750*
|
||||||
|
1,1,0.4500,-0.9250,0.6750*
|
||||||
|
1,1,0.4500,0.9250,0.6750*
|
||||||
|
%
|
||||||
|
%ADD59ROUNDEDRECTD59*%
|
||||||
|
D19*
|
||||||
|
X537000Y435000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X537000Y470000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X549000Y97000D02*
|
||||||
|
D03*
|
||||||
|
X567000D02*
|
||||||
|
D03*
|
||||||
|
X517000Y256000D02*
|
||||||
|
D03*
|
||||||
|
X499000D02*
|
||||||
|
D03*
|
||||||
|
X537000Y256000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X611000Y354000D02*
|
||||||
|
D03*
|
||||||
|
X629000D02*
|
||||||
|
D03*
|
||||||
|
X447500Y35000D02*
|
||||||
|
D03*
|
||||||
|
X465500D02*
|
||||||
|
D03*
|
||||||
|
D20*
|
||||||
|
X555000Y380000D02*
|
||||||
|
D03*
|
||||||
|
X572000D02*
|
||||||
|
D03*
|
||||||
|
X555000Y405000D02*
|
||||||
|
D03*
|
||||||
|
X572000D02*
|
||||||
|
D03*
|
||||||
|
X542500Y64000D02*
|
||||||
|
D03*
|
||||||
|
X525500D02*
|
||||||
|
D03*
|
||||||
|
X465000Y55000D02*
|
||||||
|
D03*
|
||||||
|
X448000D02*
|
||||||
|
D03*
|
||||||
|
D21*
|
||||||
|
X327500Y63500D02*
|
||||||
|
D03*
|
||||||
|
Y46500D02*
|
||||||
|
D03*
|
||||||
|
X302500Y63500D02*
|
||||||
|
D03*
|
||||||
|
Y46500D02*
|
||||||
|
D03*
|
||||||
|
D22*
|
||||||
|
X625000Y52000D02*
|
||||||
|
D03*
|
||||||
|
Y70000D02*
|
||||||
|
D03*
|
||||||
|
D59*
|
||||||
|
X270000Y69500D02*
|
||||||
|
D03*
|
||||||
|
Y40500D02*
|
||||||
|
D03*
|
||||||
|
M02*
|
||||||
291
PCB/GerberManufacture/OptoTest.GBS
Normal file
291
PCB/GerberManufacture/OptoTest.GBS
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=16711935*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD24R,1.3500X1.5500*%
|
||||||
|
%ADD25R,1.4500X1.6500*%
|
||||||
|
%ADD26R,1.6500X1.4500*%
|
||||||
|
%ADD27R,1.5500X1.3500*%
|
||||||
|
%ADD28C,1.6740*%
|
||||||
|
%ADD29C,1.8500*%
|
||||||
|
%ADD30O,2.6000X2.0000*%
|
||||||
|
%ADD31C,1.6500*%
|
||||||
|
%ADD32R,1.6500X1.6500*%
|
||||||
|
%ADD33R,1.6500X1.6500*%
|
||||||
|
%ADD34C,3.1500*%
|
||||||
|
%ADD35C,2.1500*%
|
||||||
|
%ADD36C,1.9500*%
|
||||||
|
%ADD37R,1.9500X1.9500*%
|
||||||
|
%ADD38C,1.7500*%
|
||||||
|
%ADD39R,1.7500X1.7500*%
|
||||||
|
%ADD40R,1.8500X1.8500*%
|
||||||
|
%ADD41R,1.7500X1.7500*%
|
||||||
|
%ADD42C,1.7500*%
|
||||||
|
G04:AMPARAMS|DCode=60|XSize=2.45mm|YSize=1.95mm|CornerRadius=0.3mm|HoleSize=0mm|Usage=FLASHONLY|Rotation=0.000|XOffset=0mm|YOffset=0mm|HoleType=Round|Shape=RoundedRectangle|*
|
||||||
|
%AMROUNDEDRECTD60*
|
||||||
|
21,1,2.4500,1.3500,0,0,0.0*
|
||||||
|
21,1,1.8500,1.9500,0,0,0.0*
|
||||||
|
1,1,0.6000,0.9250,-0.6750*
|
||||||
|
1,1,0.6000,-0.9250,-0.6750*
|
||||||
|
1,1,0.6000,-0.9250,0.6750*
|
||||||
|
1,1,0.6000,0.9250,0.6750*
|
||||||
|
%
|
||||||
|
%ADD60ROUNDEDRECTD60*%
|
||||||
|
D24*
|
||||||
|
X537000Y435000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X537000Y470000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X549000Y97000D02*
|
||||||
|
D03*
|
||||||
|
X567000D02*
|
||||||
|
D03*
|
||||||
|
X517000Y256000D02*
|
||||||
|
D03*
|
||||||
|
X499000D02*
|
||||||
|
D03*
|
||||||
|
X537000Y256000D02*
|
||||||
|
D03*
|
||||||
|
X555000D02*
|
||||||
|
D03*
|
||||||
|
X611000Y354000D02*
|
||||||
|
D03*
|
||||||
|
X629000D02*
|
||||||
|
D03*
|
||||||
|
X447500Y35000D02*
|
||||||
|
D03*
|
||||||
|
X465500D02*
|
||||||
|
D03*
|
||||||
|
D25*
|
||||||
|
X555000Y380000D02*
|
||||||
|
D03*
|
||||||
|
X572000D02*
|
||||||
|
D03*
|
||||||
|
X555000Y405000D02*
|
||||||
|
D03*
|
||||||
|
X572000D02*
|
||||||
|
D03*
|
||||||
|
X542500Y64000D02*
|
||||||
|
D03*
|
||||||
|
X525500D02*
|
||||||
|
D03*
|
||||||
|
X465000Y55000D02*
|
||||||
|
D03*
|
||||||
|
X448000D02*
|
||||||
|
D03*
|
||||||
|
D26*
|
||||||
|
X327500Y63500D02*
|
||||||
|
D03*
|
||||||
|
Y46500D02*
|
||||||
|
D03*
|
||||||
|
X302500Y63500D02*
|
||||||
|
D03*
|
||||||
|
Y46500D02*
|
||||||
|
D03*
|
||||||
|
D27*
|
||||||
|
X625000Y52000D02*
|
||||||
|
D03*
|
||||||
|
Y70000D02*
|
||||||
|
D03*
|
||||||
|
D28*
|
||||||
|
X650000Y250000D02*
|
||||||
|
D03*
|
||||||
|
X25000Y475000D02*
|
||||||
|
D03*
|
||||||
|
Y25000D02*
|
||||||
|
D03*
|
||||||
|
D29*
|
||||||
|
X120000Y347500D02*
|
||||||
|
D03*
|
||||||
|
Y320000D02*
|
||||||
|
D03*
|
||||||
|
X355400Y430000D02*
|
||||||
|
D03*
|
||||||
|
X330000D02*
|
||||||
|
D03*
|
||||||
|
X304600D02*
|
||||||
|
D03*
|
||||||
|
X587000Y299000D02*
|
||||||
|
D03*
|
||||||
|
X235000Y80000D02*
|
||||||
|
D03*
|
||||||
|
X245000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X574999Y198000D02*
|
||||||
|
D03*
|
||||||
|
X528000Y387000D02*
|
||||||
|
D03*
|
||||||
|
X500000Y285000D02*
|
||||||
|
D03*
|
||||||
|
X543999Y231999D02*
|
||||||
|
D03*
|
||||||
|
X451000Y274000D02*
|
||||||
|
D03*
|
||||||
|
X520000Y224000D02*
|
||||||
|
D03*
|
||||||
|
D30*
|
||||||
|
X80000Y450000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y400000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y100000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y50000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
D31*
|
||||||
|
X80000Y300800D02*
|
||||||
|
D03*
|
||||||
|
Y275400D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y224600D02*
|
||||||
|
D03*
|
||||||
|
X254600Y119000D02*
|
||||||
|
D03*
|
||||||
|
X356200D02*
|
||||||
|
D03*
|
||||||
|
X330800D02*
|
||||||
|
D03*
|
||||||
|
X305400D02*
|
||||||
|
D03*
|
||||||
|
X280000D02*
|
||||||
|
D03*
|
||||||
|
D32*
|
||||||
|
X80000Y199200D02*
|
||||||
|
D03*
|
||||||
|
D33*
|
||||||
|
X381600Y119000D02*
|
||||||
|
D03*
|
||||||
|
D34*
|
||||||
|
X190000Y203000D02*
|
||||||
|
D03*
|
||||||
|
Y297000D02*
|
||||||
|
D03*
|
||||||
|
D35*
|
||||||
|
X120000Y225000D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y275000D02*
|
||||||
|
D03*
|
||||||
|
D36*
|
||||||
|
X677000Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y460000D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y434600D02*
|
||||||
|
D03*
|
||||||
|
Y409200D02*
|
||||||
|
D03*
|
||||||
|
X677000Y40000D02*
|
||||||
|
D03*
|
||||||
|
Y116200D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y90800D02*
|
||||||
|
D03*
|
||||||
|
Y65400D02*
|
||||||
|
D03*
|
||||||
|
X678900Y326200D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
X678900Y173800D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
D37*
|
||||||
|
X600800Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y40000D02*
|
||||||
|
D03*
|
||||||
|
D38*
|
||||||
|
X416900Y34400D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y110600D02*
|
||||||
|
D03*
|
||||||
|
X493100D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
D39*
|
||||||
|
Y34400D02*
|
||||||
|
D03*
|
||||||
|
D40*
|
||||||
|
X279200Y430000D02*
|
||||||
|
D03*
|
||||||
|
D41*
|
||||||
|
X424300Y464684D02*
|
||||||
|
D03*
|
||||||
|
D42*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y388500D02*
|
||||||
|
D03*
|
||||||
|
X500500D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y464700D02*
|
||||||
|
D03*
|
||||||
|
D60*
|
||||||
|
X270000Y69500D02*
|
||||||
|
D03*
|
||||||
|
Y40500D02*
|
||||||
|
D03*
|
||||||
|
M02*
|
||||||
10
PCB/GerberManufacture/OptoTest.GKO
Normal file
10
PCB/GerberManufacture/OptoTest.GKO
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=16711935*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
M02*
|
||||||
1965
PCB/GerberManufacture/OptoTest.GTL
Normal file
1965
PCB/GerberManufacture/OptoTest.GTL
Normal file
@@ -0,0 +1,1965 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Physical_Order=1*
|
||||||
|
G04 Layer_Color=255*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD18R,2.5000X2.2000*%
|
||||||
|
%ADD19R,1.2000X1.4000*%
|
||||||
|
%ADD20R,1.3000X1.5000*%
|
||||||
|
%ADD21R,1.5000X1.3000*%
|
||||||
|
%ADD22R,1.4000X1.2000*%
|
||||||
|
%ADD43C,0.8000*%
|
||||||
|
%ADD44C,1.5240*%
|
||||||
|
%ADD45C,1.7000*%
|
||||||
|
%ADD46O,2.4000X1.8000*%
|
||||||
|
%ADD47C,1.5000*%
|
||||||
|
%ADD48R,1.5000X1.5000*%
|
||||||
|
%ADD49R,1.5000X1.5000*%
|
||||||
|
%ADD50C,3.0000*%
|
||||||
|
%ADD51C,2.0000*%
|
||||||
|
%ADD52C,1.8000*%
|
||||||
|
%ADD53R,1.8000X1.8000*%
|
||||||
|
%ADD54C,1.6000*%
|
||||||
|
%ADD55R,1.6000X1.6000*%
|
||||||
|
%ADD56R,1.7000X1.7000*%
|
||||||
|
%ADD57R,1.6000X1.6000*%
|
||||||
|
%ADD58C,1.6000*%
|
||||||
|
G36*
|
||||||
|
X692500Y471011D02*
|
||||||
|
X687500Y469314D01*
|
||||||
|
X686985Y469985D01*
|
||||||
|
X684060Y472229D01*
|
||||||
|
X680655Y473640D01*
|
||||||
|
X680500Y473660D01*
|
||||||
|
Y460000D01*
|
||||||
|
Y446340D01*
|
||||||
|
X680655Y446360D01*
|
||||||
|
X684060Y447771D01*
|
||||||
|
X686985Y450015D01*
|
||||||
|
X687500Y450686D01*
|
||||||
|
X692500Y448989D01*
|
||||||
|
Y394811D01*
|
||||||
|
X687500Y393114D01*
|
||||||
|
X686985Y393785D01*
|
||||||
|
X684060Y396029D01*
|
||||||
|
X680655Y397440D01*
|
||||||
|
X680500Y397460D01*
|
||||||
|
Y383800D01*
|
||||||
|
Y370140D01*
|
||||||
|
X680655Y370160D01*
|
||||||
|
X684060Y371571D01*
|
||||||
|
X686985Y373815D01*
|
||||||
|
X687500Y374486D01*
|
||||||
|
X692500Y372789D01*
|
||||||
|
Y339432D01*
|
||||||
|
X691977Y338962D01*
|
||||||
|
X687500Y337248D01*
|
||||||
|
X685960Y338429D01*
|
||||||
|
X682555Y339840D01*
|
||||||
|
X678900Y340321D01*
|
||||||
|
X675245Y339840D01*
|
||||||
|
X671840Y338429D01*
|
||||||
|
X668915Y336185D01*
|
||||||
|
X663485D01*
|
||||||
|
X660560Y338429D01*
|
||||||
|
X657155Y339840D01*
|
||||||
|
X654671Y340167D01*
|
||||||
|
X640000Y354838D01*
|
||||||
|
Y366000D01*
|
||||||
|
X617697D01*
|
||||||
|
X614800Y369800D01*
|
||||||
|
Y380300D01*
|
||||||
|
X600800D01*
|
||||||
|
X586800D01*
|
||||||
|
Y371078D01*
|
||||||
|
X578760D01*
|
||||||
|
X556419Y393419D01*
|
||||||
|
X554539Y394861D01*
|
||||||
|
X552350Y395768D01*
|
||||||
|
X550000Y396078D01*
|
||||||
|
X538051D01*
|
||||||
|
X537628Y396628D01*
|
||||||
|
X534808Y398792D01*
|
||||||
|
X533444Y399357D01*
|
||||||
|
X532003Y404067D01*
|
||||||
|
X532131Y405116D01*
|
||||||
|
X552537Y425522D01*
|
||||||
|
X590119D01*
|
||||||
|
X590815Y424615D01*
|
||||||
|
Y419185D01*
|
||||||
|
X588571Y416260D01*
|
||||||
|
X587160Y412855D01*
|
||||||
|
X587140Y412700D01*
|
||||||
|
X600800D01*
|
||||||
|
X614460D01*
|
||||||
|
X614440Y412855D01*
|
||||||
|
X613029Y416260D01*
|
||||||
|
X610785Y419185D01*
|
||||||
|
Y424615D01*
|
||||||
|
X613029Y427540D01*
|
||||||
|
X614440Y430945D01*
|
||||||
|
X614921Y434600D01*
|
||||||
|
X614440Y438255D01*
|
||||||
|
X613029Y441660D01*
|
||||||
|
X610785Y444585D01*
|
||||||
|
Y450015D01*
|
||||||
|
X613029Y452940D01*
|
||||||
|
X614440Y456345D01*
|
||||||
|
X614921Y460000D01*
|
||||||
|
X614440Y463655D01*
|
||||||
|
X613029Y467060D01*
|
||||||
|
X610785Y469985D01*
|
||||||
|
X607860Y472229D01*
|
||||||
|
X604455Y473640D01*
|
||||||
|
X600800Y474121D01*
|
||||||
|
X597145Y473640D01*
|
||||||
|
X593740Y472229D01*
|
||||||
|
X590815Y469985D01*
|
||||||
|
X588571Y467060D01*
|
||||||
|
X587160Y463655D01*
|
||||||
|
X586679Y460000D01*
|
||||||
|
X587160Y456345D01*
|
||||||
|
X588571Y452940D01*
|
||||||
|
X590815Y450015D01*
|
||||||
|
Y448389D01*
|
||||||
|
X586191Y443678D01*
|
||||||
|
X548777D01*
|
||||||
|
X546428Y443368D01*
|
||||||
|
X544239Y442461D01*
|
||||||
|
X542359Y441019D01*
|
||||||
|
X534078Y432738D01*
|
||||||
|
X529078Y434809D01*
|
||||||
|
Y447377D01*
|
||||||
|
X528768Y449726D01*
|
||||||
|
X527861Y451916D01*
|
||||||
|
X526419Y453796D01*
|
||||||
|
X526419Y453796D01*
|
||||||
|
X513324Y466891D01*
|
||||||
|
X513165Y468093D01*
|
||||||
|
X511855Y471256D01*
|
||||||
|
X509772Y473971D01*
|
||||||
|
X507056Y476055D01*
|
||||||
|
X503894Y477365D01*
|
||||||
|
X500500Y477812D01*
|
||||||
|
X497106Y477365D01*
|
||||||
|
X493944Y476055D01*
|
||||||
|
X491228Y473971D01*
|
||||||
|
X490125Y472534D01*
|
||||||
|
X488281Y471119D01*
|
||||||
|
X459581Y442419D01*
|
||||||
|
X458139Y440539D01*
|
||||||
|
X457232Y438349D01*
|
||||||
|
X456922Y436000D01*
|
||||||
|
Y362301D01*
|
||||||
|
X457232Y359952D01*
|
||||||
|
X458139Y357763D01*
|
||||||
|
X459581Y355883D01*
|
||||||
|
X487245Y328219D01*
|
||||||
|
X486979Y326200D01*
|
||||||
|
X487460Y322545D01*
|
||||||
|
X488871Y319140D01*
|
||||||
|
X491115Y316215D01*
|
||||||
|
X494040Y313971D01*
|
||||||
|
X494807Y313653D01*
|
||||||
|
X494819Y313563D01*
|
||||||
|
X495726Y311374D01*
|
||||||
|
X497169Y309494D01*
|
||||||
|
X503458Y303204D01*
|
||||||
|
X501123Y298468D01*
|
||||||
|
X500000Y298616D01*
|
||||||
|
X496476Y298152D01*
|
||||||
|
X493192Y296792D01*
|
||||||
|
X490372Y294628D01*
|
||||||
|
X488208Y291808D01*
|
||||||
|
X486847Y288524D01*
|
||||||
|
X486504Y285917D01*
|
||||||
|
X486159Y285401D01*
|
||||||
|
X485130Y284407D01*
|
||||||
|
X481636Y282754D01*
|
||||||
|
X481601Y282768D01*
|
||||||
|
X479251Y283078D01*
|
||||||
|
X461051D01*
|
||||||
|
X460628Y283628D01*
|
||||||
|
X457808Y285792D01*
|
||||||
|
X454524Y287153D01*
|
||||||
|
X451000Y287617D01*
|
||||||
|
X447476Y287153D01*
|
||||||
|
X444192Y285792D01*
|
||||||
|
X441372Y283628D01*
|
||||||
|
X439208Y280808D01*
|
||||||
|
X437848Y277524D01*
|
||||||
|
X437735Y276673D01*
|
||||||
|
X432456Y274881D01*
|
||||||
|
X410578Y296759D01*
|
||||||
|
Y376814D01*
|
||||||
|
X413332Y378308D01*
|
||||||
|
X415578Y378806D01*
|
||||||
|
X417744Y377144D01*
|
||||||
|
X420800Y375878D01*
|
||||||
|
Y388500D01*
|
||||||
|
X424300D01*
|
||||||
|
Y392000D01*
|
||||||
|
X436921D01*
|
||||||
|
X435655Y395056D01*
|
||||||
|
X433572Y397771D01*
|
||||||
|
X433031Y398186D01*
|
||||||
|
X432878Y398493D01*
|
||||||
|
Y403907D01*
|
||||||
|
X433031Y404213D01*
|
||||||
|
X433572Y404628D01*
|
||||||
|
X435655Y407344D01*
|
||||||
|
X436965Y410506D01*
|
||||||
|
X437412Y413900D01*
|
||||||
|
X436965Y417294D01*
|
||||||
|
X435655Y420456D01*
|
||||||
|
X433572Y423172D01*
|
||||||
|
X433031Y423586D01*
|
||||||
|
X432878Y423893D01*
|
||||||
|
Y429307D01*
|
||||||
|
X433031Y429613D01*
|
||||||
|
X433572Y430028D01*
|
||||||
|
X435655Y432744D01*
|
||||||
|
X436965Y435906D01*
|
||||||
|
X437412Y439300D01*
|
||||||
|
X436965Y442693D01*
|
||||||
|
X435655Y445856D01*
|
||||||
|
X435019Y446685D01*
|
||||||
|
X437300Y451685D01*
|
||||||
|
X437300D01*
|
||||||
|
Y477685D01*
|
||||||
|
X411300D01*
|
||||||
|
Y458609D01*
|
||||||
|
X406300Y456538D01*
|
||||||
|
X391419Y471419D01*
|
||||||
|
X389539Y472862D01*
|
||||||
|
X387349Y473768D01*
|
||||||
|
X385000Y474078D01*
|
||||||
|
X225000D01*
|
||||||
|
X225000Y474078D01*
|
||||||
|
X222651Y473768D01*
|
||||||
|
X220461Y472862D01*
|
||||||
|
X218581Y471419D01*
|
||||||
|
X210759Y463596D01*
|
||||||
|
X210655Y463640D01*
|
||||||
|
X207000Y464121D01*
|
||||||
|
X201000D01*
|
||||||
|
X197345Y463640D01*
|
||||||
|
X193940Y462229D01*
|
||||||
|
X191015Y459985D01*
|
||||||
|
X188771Y457060D01*
|
||||||
|
X187360Y453655D01*
|
||||||
|
X186879Y450000D01*
|
||||||
|
X187360Y446345D01*
|
||||||
|
X188771Y442940D01*
|
||||||
|
X191015Y440015D01*
|
||||||
|
X193940Y437771D01*
|
||||||
|
X197345Y436360D01*
|
||||||
|
X201000Y435879D01*
|
||||||
|
X207000D01*
|
||||||
|
X210655Y436360D01*
|
||||||
|
X214060Y437771D01*
|
||||||
|
X216985Y440015D01*
|
||||||
|
X219229Y442940D01*
|
||||||
|
X220640Y446345D01*
|
||||||
|
X220861Y448023D01*
|
||||||
|
X228760Y455922D01*
|
||||||
|
X331552D01*
|
||||||
|
X333465Y451303D01*
|
||||||
|
X324494Y442332D01*
|
||||||
|
X323192Y441792D01*
|
||||||
|
X320372Y439628D01*
|
||||||
|
X314228D01*
|
||||||
|
X311408Y441792D01*
|
||||||
|
X308124Y443153D01*
|
||||||
|
X304600Y443616D01*
|
||||||
|
X301076Y443153D01*
|
||||||
|
X297792Y441792D01*
|
||||||
|
X297700Y441722D01*
|
||||||
|
X292700Y443500D01*
|
||||||
|
Y443500D01*
|
||||||
|
X282700D01*
|
||||||
|
Y430000D01*
|
||||||
|
Y416500D01*
|
||||||
|
X292700D01*
|
||||||
|
Y416500D01*
|
||||||
|
X297700Y418278D01*
|
||||||
|
X297792Y418208D01*
|
||||||
|
X301076Y416847D01*
|
||||||
|
X304600Y416384D01*
|
||||||
|
X308124Y416847D01*
|
||||||
|
X311408Y418208D01*
|
||||||
|
X314228Y420372D01*
|
||||||
|
X320372D01*
|
||||||
|
X323192Y418208D01*
|
||||||
|
X326476Y416847D01*
|
||||||
|
X330000Y416384D01*
|
||||||
|
X333524Y416847D01*
|
||||||
|
X336808Y418208D01*
|
||||||
|
X339628Y420372D01*
|
||||||
|
X345772D01*
|
||||||
|
X348592Y418208D01*
|
||||||
|
X351876Y416847D01*
|
||||||
|
X355400Y416384D01*
|
||||||
|
X358924Y416847D01*
|
||||||
|
X359907Y417255D01*
|
||||||
|
X365922Y411240D01*
|
||||||
|
Y276615D01*
|
||||||
|
X366232Y274266D01*
|
||||||
|
X367139Y272076D01*
|
||||||
|
X368581Y270196D01*
|
||||||
|
X418196Y220581D01*
|
||||||
|
X420076Y219139D01*
|
||||||
|
X422266Y218232D01*
|
||||||
|
X424615Y217922D01*
|
||||||
|
X424615Y217922D01*
|
||||||
|
X478449D01*
|
||||||
|
X478969Y217181D01*
|
||||||
|
X480146Y212922D01*
|
||||||
|
X479881Y212719D01*
|
||||||
|
X479881Y212719D01*
|
||||||
|
X416240Y149078D01*
|
||||||
|
X245000D01*
|
||||||
|
X242651Y148768D01*
|
||||||
|
X240461Y147861D01*
|
||||||
|
X238581Y146419D01*
|
||||||
|
X206283Y114121D01*
|
||||||
|
X201000D01*
|
||||||
|
X197345Y113640D01*
|
||||||
|
X193940Y112229D01*
|
||||||
|
X191015Y109985D01*
|
||||||
|
X188771Y107060D01*
|
||||||
|
X187360Y103655D01*
|
||||||
|
X186879Y100000D01*
|
||||||
|
X187360Y96345D01*
|
||||||
|
X188771Y92940D01*
|
||||||
|
X191015Y90015D01*
|
||||||
|
X193940Y87771D01*
|
||||||
|
X197345Y86360D01*
|
||||||
|
X201000Y85879D01*
|
||||||
|
X207000D01*
|
||||||
|
X210655Y86360D01*
|
||||||
|
X214060Y87771D01*
|
||||||
|
X216985Y90015D01*
|
||||||
|
X219229Y92940D01*
|
||||||
|
X220640Y96345D01*
|
||||||
|
X221121Y100000D01*
|
||||||
|
X220739Y102901D01*
|
||||||
|
X237131Y119293D01*
|
||||||
|
X237927Y119245D01*
|
||||||
|
X242215Y117306D01*
|
||||||
|
X242422Y115737D01*
|
||||||
|
X243681Y112696D01*
|
||||||
|
X245685Y110085D01*
|
||||||
|
X248296Y108081D01*
|
||||||
|
X251337Y106822D01*
|
||||||
|
X254600Y106392D01*
|
||||||
|
X257863Y106822D01*
|
||||||
|
X260904Y108081D01*
|
||||||
|
X263515Y110085D01*
|
||||||
|
X264318Y111131D01*
|
||||||
|
X265495Y111518D01*
|
||||||
|
X269104D01*
|
||||||
|
X270282Y111131D01*
|
||||||
|
X271085Y110085D01*
|
||||||
|
X273696Y108081D01*
|
||||||
|
X276737Y106822D01*
|
||||||
|
X280000Y106392D01*
|
||||||
|
X283263Y106822D01*
|
||||||
|
X286304Y108081D01*
|
||||||
|
X288915Y110085D01*
|
||||||
|
X289718Y111131D01*
|
||||||
|
X290896Y111518D01*
|
||||||
|
X294505D01*
|
||||||
|
X295682Y111131D01*
|
||||||
|
X296485Y110085D01*
|
||||||
|
X299096Y108081D01*
|
||||||
|
X302137Y106822D01*
|
||||||
|
X305400Y106392D01*
|
||||||
|
X308663Y106822D01*
|
||||||
|
X311704Y108081D01*
|
||||||
|
X314315Y110085D01*
|
||||||
|
X315118Y111131D01*
|
||||||
|
X316296Y111518D01*
|
||||||
|
X319904D01*
|
||||||
|
X321082Y111131D01*
|
||||||
|
X321885Y110085D01*
|
||||||
|
X324496Y108081D01*
|
||||||
|
X327537Y106822D01*
|
||||||
|
X330800Y106392D01*
|
||||||
|
X334063Y106822D01*
|
||||||
|
X337104Y108081D01*
|
||||||
|
X339715Y110085D01*
|
||||||
|
X340518Y111131D01*
|
||||||
|
X341696Y111518D01*
|
||||||
|
X345304D01*
|
||||||
|
X346482Y111131D01*
|
||||||
|
X347285Y110085D01*
|
||||||
|
X349896Y108081D01*
|
||||||
|
X352937Y106822D01*
|
||||||
|
X356200Y106392D01*
|
||||||
|
X359463Y106822D01*
|
||||||
|
X362504Y108081D01*
|
||||||
|
X364100Y109306D01*
|
||||||
|
X367569Y108225D01*
|
||||||
|
X369100Y107065D01*
|
||||||
|
Y106500D01*
|
||||||
|
X394100D01*
|
||||||
|
Y130922D01*
|
||||||
|
X420000D01*
|
||||||
|
X422350Y131232D01*
|
||||||
|
X424539Y132139D01*
|
||||||
|
X426419Y133581D01*
|
||||||
|
X460803Y167965D01*
|
||||||
|
X465422Y166052D01*
|
||||||
|
Y151000D01*
|
||||||
|
X463500D01*
|
||||||
|
Y139338D01*
|
||||||
|
X448162Y124000D01*
|
||||||
|
X437000D01*
|
||||||
|
Y102000D01*
|
||||||
|
Y96838D01*
|
||||||
|
X435640Y95478D01*
|
||||||
|
X427568D01*
|
||||||
|
X425374Y99904D01*
|
||||||
|
X425449Y100550D01*
|
||||||
|
X425631Y100913D01*
|
||||||
|
X426172Y101328D01*
|
||||||
|
X428256Y104044D01*
|
||||||
|
X429565Y107206D01*
|
||||||
|
X430012Y110600D01*
|
||||||
|
X429565Y113994D01*
|
||||||
|
X428256Y117156D01*
|
||||||
|
X426172Y119872D01*
|
||||||
|
X423456Y121955D01*
|
||||||
|
X420294Y123265D01*
|
||||||
|
X416900Y123712D01*
|
||||||
|
X413506Y123265D01*
|
||||||
|
X410344Y121955D01*
|
||||||
|
X407628Y119872D01*
|
||||||
|
X405545Y117156D01*
|
||||||
|
X404235Y113994D01*
|
||||||
|
X403788Y110600D01*
|
||||||
|
X404235Y107206D01*
|
||||||
|
X405545Y104044D01*
|
||||||
|
X407628Y101328D01*
|
||||||
|
X408169Y100913D01*
|
||||||
|
X408322Y100607D01*
|
||||||
|
Y95193D01*
|
||||||
|
X408169Y94887D01*
|
||||||
|
X407628Y94472D01*
|
||||||
|
X405545Y91756D01*
|
||||||
|
X405263Y91076D01*
|
||||||
|
X404267Y90281D01*
|
||||||
|
X400019Y88686D01*
|
||||||
|
X399206Y88703D01*
|
||||||
|
X399049Y88768D01*
|
||||||
|
X396700Y89078D01*
|
||||||
|
X245051D01*
|
||||||
|
X244628Y89628D01*
|
||||||
|
X241808Y91792D01*
|
||||||
|
X238524Y93153D01*
|
||||||
|
X235000Y93616D01*
|
||||||
|
X231476Y93153D01*
|
||||||
|
X228192Y91792D01*
|
||||||
|
X225372Y89628D01*
|
||||||
|
X223208Y86808D01*
|
||||||
|
X221847Y83524D01*
|
||||||
|
X221384Y80000D01*
|
||||||
|
X221847Y76476D01*
|
||||||
|
X223208Y73192D01*
|
||||||
|
X225372Y70372D01*
|
||||||
|
X225922Y69949D01*
|
||||||
|
Y61000D01*
|
||||||
|
X220000D01*
|
||||||
|
X220000Y61000D01*
|
||||||
|
X215160Y61385D01*
|
||||||
|
X214060Y62229D01*
|
||||||
|
X210655Y63640D01*
|
||||||
|
X207500Y64055D01*
|
||||||
|
Y50000D01*
|
||||||
|
X200500D01*
|
||||||
|
Y64055D01*
|
||||||
|
X197345Y63640D01*
|
||||||
|
X193940Y62229D01*
|
||||||
|
X191015Y59985D01*
|
||||||
|
X188771Y57060D01*
|
||||||
|
X188501Y56408D01*
|
||||||
|
X182741Y55097D01*
|
||||||
|
X72578Y165260D01*
|
||||||
|
Y186700D01*
|
||||||
|
X76500D01*
|
||||||
|
Y199200D01*
|
||||||
|
X80000D01*
|
||||||
|
Y202700D01*
|
||||||
|
X92500D01*
|
||||||
|
Y205721D01*
|
||||||
|
X97500Y207792D01*
|
||||||
|
X141500Y163792D01*
|
||||||
|
Y158000D01*
|
||||||
|
X181500D01*
|
||||||
|
Y160922D01*
|
||||||
|
X189000D01*
|
||||||
|
Y158000D01*
|
||||||
|
X215500D01*
|
||||||
|
Y170000D01*
|
||||||
|
X220500D01*
|
||||||
|
Y158000D01*
|
||||||
|
X229000D01*
|
||||||
|
Y160867D01*
|
||||||
|
X229548Y161169D01*
|
||||||
|
X234000Y162159D01*
|
||||||
|
X235372Y160372D01*
|
||||||
|
X238192Y158208D01*
|
||||||
|
X241476Y156847D01*
|
||||||
|
X245000Y156383D01*
|
||||||
|
X248524Y156847D01*
|
||||||
|
X251808Y158208D01*
|
||||||
|
X254628Y160372D01*
|
||||||
|
X256792Y163192D01*
|
||||||
|
X258153Y166476D01*
|
||||||
|
X258616Y170000D01*
|
||||||
|
X258153Y173524D01*
|
||||||
|
X256792Y176808D01*
|
||||||
|
X254628Y179628D01*
|
||||||
|
X251808Y181792D01*
|
||||||
|
X248524Y183153D01*
|
||||||
|
X245000Y183616D01*
|
||||||
|
X244312Y183526D01*
|
||||||
|
X235419Y192419D01*
|
||||||
|
X233539Y193862D01*
|
||||||
|
X231349Y194768D01*
|
||||||
|
X229000Y195078D01*
|
||||||
|
X213722D01*
|
||||||
|
X211016Y197777D01*
|
||||||
|
X209809Y200078D01*
|
||||||
|
X210097Y203000D01*
|
||||||
|
X209711Y206921D01*
|
||||||
|
X208567Y210691D01*
|
||||||
|
X206710Y214165D01*
|
||||||
|
X204211Y217211D01*
|
||||||
|
X201165Y219710D01*
|
||||||
|
X197691Y221567D01*
|
||||||
|
X193921Y222711D01*
|
||||||
|
X190000Y223097D01*
|
||||||
|
X186079Y222711D01*
|
||||||
|
X182309Y221567D01*
|
||||||
|
X178835Y219710D01*
|
||||||
|
X175789Y217211D01*
|
||||||
|
X173290Y214165D01*
|
||||||
|
X171433Y210691D01*
|
||||||
|
X170289Y206921D01*
|
||||||
|
X169903Y203000D01*
|
||||||
|
X170289Y199079D01*
|
||||||
|
X171433Y195309D01*
|
||||||
|
X173290Y191835D01*
|
||||||
|
X175789Y188789D01*
|
||||||
|
X177970Y187000D01*
|
||||||
|
X177381Y183750D01*
|
||||||
|
X176380Y182000D01*
|
||||||
|
X148968D01*
|
||||||
|
X125269Y205699D01*
|
||||||
|
X125557Y208800D01*
|
||||||
|
X126547Y211491D01*
|
||||||
|
X128374Y212468D01*
|
||||||
|
X130658Y214342D01*
|
||||||
|
X132532Y216626D01*
|
||||||
|
X133925Y219232D01*
|
||||||
|
X134783Y222059D01*
|
||||||
|
X135073Y225000D01*
|
||||||
|
X134783Y227941D01*
|
||||||
|
X133925Y230768D01*
|
||||||
|
X132532Y233374D01*
|
||||||
|
X130658Y235658D01*
|
||||||
|
Y239342D01*
|
||||||
|
X132532Y241626D01*
|
||||||
|
X133925Y244232D01*
|
||||||
|
X134783Y247059D01*
|
||||||
|
X135073Y250000D01*
|
||||||
|
X134783Y252941D01*
|
||||||
|
X133925Y255768D01*
|
||||||
|
X132532Y258374D01*
|
||||||
|
X130658Y260658D01*
|
||||||
|
Y264342D01*
|
||||||
|
X132532Y266626D01*
|
||||||
|
X133925Y269232D01*
|
||||||
|
X134783Y272059D01*
|
||||||
|
X135073Y275000D01*
|
||||||
|
X134783Y277941D01*
|
||||||
|
X133925Y280768D01*
|
||||||
|
X132532Y283374D01*
|
||||||
|
X130658Y285658D01*
|
||||||
|
X128374Y287532D01*
|
||||||
|
X125768Y288925D01*
|
||||||
|
X122941Y289783D01*
|
||||||
|
X120000Y290073D01*
|
||||||
|
X117059Y289783D01*
|
||||||
|
X114232Y288925D01*
|
||||||
|
X111626Y287532D01*
|
||||||
|
X109342Y285658D01*
|
||||||
|
X107468Y283374D01*
|
||||||
|
X106075Y280768D01*
|
||||||
|
X105217Y277941D01*
|
||||||
|
X104927Y275000D01*
|
||||||
|
X105217Y272059D01*
|
||||||
|
X106075Y269232D01*
|
||||||
|
X107468Y266626D01*
|
||||||
|
X109342Y264342D01*
|
||||||
|
Y260658D01*
|
||||||
|
X107468Y258374D01*
|
||||||
|
X106075Y255768D01*
|
||||||
|
X105217Y252941D01*
|
||||||
|
X104927Y250000D01*
|
||||||
|
X105217Y247059D01*
|
||||||
|
X106075Y244232D01*
|
||||||
|
X106532Y243377D01*
|
||||||
|
X102472Y240366D01*
|
||||||
|
X92573Y250265D01*
|
||||||
|
X92178Y253263D01*
|
||||||
|
X90919Y256304D01*
|
||||||
|
X88915Y258915D01*
|
||||||
|
X87869Y259718D01*
|
||||||
|
X87482Y260896D01*
|
||||||
|
Y264505D01*
|
||||||
|
X87869Y265682D01*
|
||||||
|
X88915Y266485D01*
|
||||||
|
X90919Y269096D01*
|
||||||
|
X92178Y272137D01*
|
||||||
|
X92608Y275400D01*
|
||||||
|
X92390Y277053D01*
|
||||||
|
X93105Y277767D01*
|
||||||
|
X93253Y277881D01*
|
||||||
|
X122022Y306650D01*
|
||||||
|
X123524Y306847D01*
|
||||||
|
X126808Y308208D01*
|
||||||
|
X129628Y310372D01*
|
||||||
|
X131792Y313192D01*
|
||||||
|
X133153Y316476D01*
|
||||||
|
X133616Y320000D01*
|
||||||
|
X133153Y323524D01*
|
||||||
|
X131792Y326808D01*
|
||||||
|
X129628Y329628D01*
|
||||||
|
X128075Y330820D01*
|
||||||
|
X127646Y332477D01*
|
||||||
|
Y335023D01*
|
||||||
|
X128075Y336680D01*
|
||||||
|
X129628Y337872D01*
|
||||||
|
X131792Y340692D01*
|
||||||
|
X133153Y343976D01*
|
||||||
|
X133616Y347500D01*
|
||||||
|
X133153Y351024D01*
|
||||||
|
X131792Y354308D01*
|
||||||
|
X129628Y357128D01*
|
||||||
|
X126808Y359292D01*
|
||||||
|
X123524Y360653D01*
|
||||||
|
X120000Y361116D01*
|
||||||
|
X116476Y360653D01*
|
||||||
|
X113192Y359292D01*
|
||||||
|
X110372Y357128D01*
|
||||||
|
X108208Y354308D01*
|
||||||
|
X106847Y351024D01*
|
||||||
|
X106383Y347500D01*
|
||||||
|
X106474Y346812D01*
|
||||||
|
X80581Y320919D01*
|
||||||
|
X79139Y319039D01*
|
||||||
|
X78232Y316849D01*
|
||||||
|
X77922Y314500D01*
|
||||||
|
Y313454D01*
|
||||||
|
X77554Y313086D01*
|
||||||
|
X76737Y312978D01*
|
||||||
|
X73696Y311719D01*
|
||||||
|
X71085Y309715D01*
|
||||||
|
X69081Y307104D01*
|
||||||
|
X67822Y304063D01*
|
||||||
|
X67392Y300800D01*
|
||||||
|
X67822Y297537D01*
|
||||||
|
X69081Y294496D01*
|
||||||
|
X71085Y291885D01*
|
||||||
|
X72131Y291082D01*
|
||||||
|
X72518Y289904D01*
|
||||||
|
Y286296D01*
|
||||||
|
X72131Y285118D01*
|
||||||
|
X71085Y284315D01*
|
||||||
|
X69081Y281704D01*
|
||||||
|
X67822Y278663D01*
|
||||||
|
X67392Y275400D01*
|
||||||
|
X67822Y272137D01*
|
||||||
|
X69081Y269096D01*
|
||||||
|
X71085Y266485D01*
|
||||||
|
X72131Y265682D01*
|
||||||
|
X72518Y264505D01*
|
||||||
|
Y260896D01*
|
||||||
|
X72131Y259718D01*
|
||||||
|
X71085Y258915D01*
|
||||||
|
X69081Y256304D01*
|
||||||
|
X67822Y253263D01*
|
||||||
|
X67392Y250000D01*
|
||||||
|
X67822Y246737D01*
|
||||||
|
X69081Y243696D01*
|
||||||
|
X71085Y241085D01*
|
||||||
|
X72131Y240282D01*
|
||||||
|
X72518Y239104D01*
|
||||||
|
Y235495D01*
|
||||||
|
X72131Y234318D01*
|
||||||
|
X71085Y233515D01*
|
||||||
|
X69081Y230904D01*
|
||||||
|
X67822Y227863D01*
|
||||||
|
X67714Y227046D01*
|
||||||
|
X64602Y223934D01*
|
||||||
|
X62738Y222504D01*
|
||||||
|
X57081Y216847D01*
|
||||||
|
X55638Y214967D01*
|
||||||
|
X54732Y212777D01*
|
||||||
|
X54422Y210428D01*
|
||||||
|
Y161500D01*
|
||||||
|
X54732Y159151D01*
|
||||||
|
X55638Y156961D01*
|
||||||
|
X57081Y155081D01*
|
||||||
|
X193581Y18581D01*
|
||||||
|
X195461Y17139D01*
|
||||||
|
X197651Y16232D01*
|
||||||
|
X200000Y15922D01*
|
||||||
|
X200000Y15922D01*
|
||||||
|
X367500D01*
|
||||||
|
X369850Y16232D01*
|
||||||
|
X372039Y17139D01*
|
||||||
|
X373919Y18581D01*
|
||||||
|
X384338Y29000D01*
|
||||||
|
X400000D01*
|
||||||
|
Y29000D01*
|
||||||
|
X405000Y29159D01*
|
||||||
|
X405545Y27844D01*
|
||||||
|
X407628Y25128D01*
|
||||||
|
X410344Y23045D01*
|
||||||
|
X413506Y21735D01*
|
||||||
|
X416900Y21288D01*
|
||||||
|
X420294Y21735D01*
|
||||||
|
X423456Y23045D01*
|
||||||
|
X426172Y25128D01*
|
||||||
|
X428256Y27844D01*
|
||||||
|
X429565Y31006D01*
|
||||||
|
X432000Y34246D01*
|
||||||
|
X432500Y34206D01*
|
||||||
|
X437000Y33000D01*
|
||||||
|
Y33000D01*
|
||||||
|
X480100D01*
|
||||||
|
Y21400D01*
|
||||||
|
X506100D01*
|
||||||
|
Y47400D01*
|
||||||
|
X506100D01*
|
||||||
|
X503808Y52400D01*
|
||||||
|
X504455Y53244D01*
|
||||||
|
X505765Y56406D01*
|
||||||
|
X506212Y59800D01*
|
||||||
|
X505765Y63194D01*
|
||||||
|
X504455Y66356D01*
|
||||||
|
X502372Y69072D01*
|
||||||
|
X501831Y69487D01*
|
||||||
|
X501678Y69793D01*
|
||||||
|
Y75207D01*
|
||||||
|
X501831Y75513D01*
|
||||||
|
X502372Y75928D01*
|
||||||
|
X504455Y78644D01*
|
||||||
|
X505721Y81700D01*
|
||||||
|
X493100D01*
|
||||||
|
X480479D01*
|
||||||
|
X481745Y78644D01*
|
||||||
|
X482239Y78000D01*
|
||||||
|
X479773Y73000D01*
|
||||||
|
X472500D01*
|
||||||
|
Y61500D01*
|
||||||
|
X467500D01*
|
||||||
|
Y73000D01*
|
||||||
|
X452000D01*
|
||||||
|
Y61500D01*
|
||||||
|
X447000D01*
|
||||||
|
Y73000D01*
|
||||||
|
X442966D01*
|
||||||
|
X441749Y77632D01*
|
||||||
|
X443939Y78539D01*
|
||||||
|
X445819Y79981D01*
|
||||||
|
X449838Y84000D01*
|
||||||
|
X461000D01*
|
||||||
|
Y102000D01*
|
||||||
|
Y111162D01*
|
||||||
|
X476838Y127000D01*
|
||||||
|
X485657D01*
|
||||||
|
X486651Y122000D01*
|
||||||
|
X486544Y121955D01*
|
||||||
|
X483828Y119872D01*
|
||||||
|
X481745Y117156D01*
|
||||||
|
X480479Y114100D01*
|
||||||
|
X493100D01*
|
||||||
|
X505721D01*
|
||||||
|
X504455Y117156D01*
|
||||||
|
X502372Y119872D01*
|
||||||
|
X499656Y121955D01*
|
||||||
|
X499548Y122000D01*
|
||||||
|
X500543Y127000D01*
|
||||||
|
X503500D01*
|
||||||
|
Y136500D01*
|
||||||
|
X492500D01*
|
||||||
|
Y139000D01*
|
||||||
|
X490000D01*
|
||||||
|
Y151000D01*
|
||||||
|
X483578D01*
|
||||||
|
Y166453D01*
|
||||||
|
X488578Y167448D01*
|
||||||
|
X488871Y166740D01*
|
||||||
|
X491115Y163815D01*
|
||||||
|
X494040Y161571D01*
|
||||||
|
X497445Y160160D01*
|
||||||
|
X501100Y159679D01*
|
||||||
|
X504755Y160160D01*
|
||||||
|
X508160Y161571D01*
|
||||||
|
X511085Y163815D01*
|
||||||
|
X516515D01*
|
||||||
|
X519440Y161571D01*
|
||||||
|
X522845Y160160D01*
|
||||||
|
X526500Y159679D01*
|
||||||
|
X530155Y160160D01*
|
||||||
|
X533560Y161571D01*
|
||||||
|
X536485Y163815D01*
|
||||||
|
X541915D01*
|
||||||
|
X544840Y161571D01*
|
||||||
|
X548245Y160160D01*
|
||||||
|
X551900Y159679D01*
|
||||||
|
X555555Y160160D01*
|
||||||
|
X558960Y161571D01*
|
||||||
|
X561885Y163815D01*
|
||||||
|
X567315D01*
|
||||||
|
X570240Y161571D01*
|
||||||
|
X573645Y160160D01*
|
||||||
|
X577300Y159679D01*
|
||||||
|
X580955Y160160D01*
|
||||||
|
X584360Y161571D01*
|
||||||
|
X587285Y163815D01*
|
||||||
|
X592715D01*
|
||||||
|
X595640Y161571D01*
|
||||||
|
X599045Y160160D01*
|
||||||
|
X602700Y159679D01*
|
||||||
|
X606355Y160160D01*
|
||||||
|
X609760Y161571D01*
|
||||||
|
X612685Y163815D01*
|
||||||
|
X618115D01*
|
||||||
|
X621040Y161571D01*
|
||||||
|
X624445Y160160D01*
|
||||||
|
X628100Y159679D01*
|
||||||
|
X631755Y160160D01*
|
||||||
|
X635160Y161571D01*
|
||||||
|
X638085Y163815D01*
|
||||||
|
X643515D01*
|
||||||
|
X646440Y161571D01*
|
||||||
|
X649845Y160160D01*
|
||||||
|
X653500Y159679D01*
|
||||||
|
X657155Y160160D01*
|
||||||
|
X660560Y161571D01*
|
||||||
|
X663485Y163815D01*
|
||||||
|
X668915D01*
|
||||||
|
X671840Y161571D01*
|
||||||
|
X675245Y160160D01*
|
||||||
|
X678900Y159679D01*
|
||||||
|
X682555Y160160D01*
|
||||||
|
X685960Y161571D01*
|
||||||
|
X687500Y162752D01*
|
||||||
|
X691977Y161038D01*
|
||||||
|
X692500Y160568D01*
|
||||||
|
Y127211D01*
|
||||||
|
X687500Y125514D01*
|
||||||
|
X686985Y126185D01*
|
||||||
|
X684060Y128429D01*
|
||||||
|
X680655Y129840D01*
|
||||||
|
X680500Y129860D01*
|
||||||
|
Y116200D01*
|
||||||
|
Y102540D01*
|
||||||
|
X680655Y102560D01*
|
||||||
|
X684060Y103971D01*
|
||||||
|
X686985Y106215D01*
|
||||||
|
X687500Y106886D01*
|
||||||
|
X692500Y105189D01*
|
||||||
|
Y51011D01*
|
||||||
|
X687500Y49314D01*
|
||||||
|
X686985Y49985D01*
|
||||||
|
X684060Y52229D01*
|
||||||
|
X680655Y53640D01*
|
||||||
|
X680500Y53660D01*
|
||||||
|
Y40000D01*
|
||||||
|
Y26340D01*
|
||||||
|
X680655Y26360D01*
|
||||||
|
X684060Y27771D01*
|
||||||
|
X686985Y30015D01*
|
||||||
|
X687500Y30686D01*
|
||||||
|
X692500Y28989D01*
|
||||||
|
Y9092D01*
|
||||||
|
X71942D01*
|
||||||
|
X71617Y9546D01*
|
||||||
|
X69222Y14092D01*
|
||||||
|
X70208Y19048D01*
|
||||||
|
X70598Y25000D01*
|
||||||
|
X70208Y30952D01*
|
||||||
|
X69927Y32364D01*
|
||||||
|
X71698Y34436D01*
|
||||||
|
X74253Y36241D01*
|
||||||
|
X76500Y35945D01*
|
||||||
|
Y50000D01*
|
||||||
|
Y64055D01*
|
||||||
|
X73345Y63640D01*
|
||||||
|
X69940Y62229D01*
|
||||||
|
X67015Y59985D01*
|
||||||
|
X64771Y57060D01*
|
||||||
|
X64541Y56504D01*
|
||||||
|
X58741Y55534D01*
|
||||||
|
X57242Y57242D01*
|
||||||
|
X52758Y61175D01*
|
||||||
|
X47799Y64489D01*
|
||||||
|
X42449Y67127D01*
|
||||||
|
X36802Y69044D01*
|
||||||
|
X30952Y70208D01*
|
||||||
|
X25000Y70598D01*
|
||||||
|
X19048Y70208D01*
|
||||||
|
X17500Y69900D01*
|
||||||
|
X12500Y74003D01*
|
||||||
|
Y425997D01*
|
||||||
|
X17500Y430100D01*
|
||||||
|
X19048Y429793D01*
|
||||||
|
X25000Y429402D01*
|
||||||
|
X30952Y429793D01*
|
||||||
|
X36802Y430956D01*
|
||||||
|
X42449Y432873D01*
|
||||||
|
X47799Y435511D01*
|
||||||
|
X52758Y438825D01*
|
||||||
|
X57242Y442758D01*
|
||||||
|
X58741Y444466D01*
|
||||||
|
X64541Y443496D01*
|
||||||
|
X64771Y442940D01*
|
||||||
|
X67015Y440015D01*
|
||||||
|
X69940Y437771D01*
|
||||||
|
X73345Y436360D01*
|
||||||
|
X77000Y435879D01*
|
||||||
|
X83000D01*
|
||||||
|
X86655Y436360D01*
|
||||||
|
X90060Y437771D01*
|
||||||
|
X92985Y440015D01*
|
||||||
|
X95229Y442940D01*
|
||||||
|
X96640Y446345D01*
|
||||||
|
X97121Y450000D01*
|
||||||
|
X96640Y453655D01*
|
||||||
|
X95229Y457060D01*
|
||||||
|
X92985Y459985D01*
|
||||||
|
X90060Y462229D01*
|
||||||
|
X86655Y463640D01*
|
||||||
|
X83000Y464121D01*
|
||||||
|
X77000D01*
|
||||||
|
X74253Y463759D01*
|
||||||
|
X71698Y465564D01*
|
||||||
|
X69927Y467635D01*
|
||||||
|
X70208Y469048D01*
|
||||||
|
X70598Y475000D01*
|
||||||
|
X70208Y480952D01*
|
||||||
|
X69583Y484092D01*
|
||||||
|
X73069Y489092D01*
|
||||||
|
X692500D01*
|
||||||
|
Y471011D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X570240Y313971D02*
|
||||||
|
X573645Y312560D01*
|
||||||
|
X574261Y312479D01*
|
||||||
|
X574930Y311651D01*
|
||||||
|
X576255Y307174D01*
|
||||||
|
X575208Y305808D01*
|
||||||
|
X573848Y302524D01*
|
||||||
|
X573844Y302500D01*
|
||||||
|
X587000D01*
|
||||||
|
Y295500D01*
|
||||||
|
X573844D01*
|
||||||
|
X573848Y295476D01*
|
||||||
|
X575208Y292192D01*
|
||||||
|
X577372Y289372D01*
|
||||||
|
X580110Y287270D01*
|
||||||
|
X580193Y287201D01*
|
||||||
|
X581263Y281352D01*
|
||||||
|
X576489Y276578D01*
|
||||||
|
X542364D01*
|
||||||
|
X517824Y276578D01*
|
||||||
|
X517640Y276793D01*
|
||||||
|
X515915Y281577D01*
|
||||||
|
X520838Y286500D01*
|
||||||
|
X534000D01*
|
||||||
|
Y299000D01*
|
||||||
|
X536500D01*
|
||||||
|
Y301500D01*
|
||||||
|
X548000D01*
|
||||||
|
Y307549D01*
|
||||||
|
X551889Y312066D01*
|
||||||
|
X552716Y312187D01*
|
||||||
|
X555555Y312560D01*
|
||||||
|
X558960Y313971D01*
|
||||||
|
X561885Y316215D01*
|
||||||
|
X567315D01*
|
||||||
|
X570240Y313971D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
%LPC*%
|
||||||
|
G36*
|
||||||
|
X673500Y473660D02*
|
||||||
|
X673345Y473640D01*
|
||||||
|
X669940Y472229D01*
|
||||||
|
X667015Y469985D01*
|
||||||
|
X664771Y467060D01*
|
||||||
|
X663360Y463655D01*
|
||||||
|
X663340Y463500D01*
|
||||||
|
X673500D01*
|
||||||
|
Y473660D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y456500D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y456345D01*
|
||||||
|
X664771Y452940D01*
|
||||||
|
X667015Y450015D01*
|
||||||
|
X669940Y447771D01*
|
||||||
|
X673345Y446360D01*
|
||||||
|
X673500Y446340D01*
|
||||||
|
Y456500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X275700Y443500D02*
|
||||||
|
X265700D01*
|
||||||
|
Y433500D01*
|
||||||
|
X275700D01*
|
||||||
|
Y443500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y426500D02*
|
||||||
|
X265700D01*
|
||||||
|
Y416500D01*
|
||||||
|
X275700D01*
|
||||||
|
Y426500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X207500Y414055D02*
|
||||||
|
Y403500D01*
|
||||||
|
X220660D01*
|
||||||
|
X220640Y403655D01*
|
||||||
|
X219229Y407060D01*
|
||||||
|
X216985Y409985D01*
|
||||||
|
X214060Y412229D01*
|
||||||
|
X210655Y413640D01*
|
||||||
|
X207500Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X83500D02*
|
||||||
|
Y403500D01*
|
||||||
|
X96660D01*
|
||||||
|
X96640Y403655D01*
|
||||||
|
X95229Y407060D01*
|
||||||
|
X92985Y409985D01*
|
||||||
|
X90060Y412229D01*
|
||||||
|
X86655Y413640D01*
|
||||||
|
X83500Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X200500Y414055D02*
|
||||||
|
X197345Y413640D01*
|
||||||
|
X193940Y412229D01*
|
||||||
|
X191015Y409985D01*
|
||||||
|
X188771Y407060D01*
|
||||||
|
X187360Y403655D01*
|
||||||
|
X187340Y403500D01*
|
||||||
|
X200500D01*
|
||||||
|
Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X76500D02*
|
||||||
|
X73345Y413640D01*
|
||||||
|
X69940Y412229D01*
|
||||||
|
X67015Y409985D01*
|
||||||
|
X64771Y407060D01*
|
||||||
|
X63360Y403655D01*
|
||||||
|
X63340Y403500D01*
|
||||||
|
X76500D01*
|
||||||
|
Y414055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y397460D02*
|
||||||
|
X673345Y397440D01*
|
||||||
|
X669940Y396029D01*
|
||||||
|
X667015Y393785D01*
|
||||||
|
X664771Y390860D01*
|
||||||
|
X663360Y387455D01*
|
||||||
|
X663340Y387300D01*
|
||||||
|
X673500D01*
|
||||||
|
Y397460D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X614460Y405700D02*
|
||||||
|
X600800D01*
|
||||||
|
X587140D01*
|
||||||
|
X587160Y405545D01*
|
||||||
|
X588298Y402800D01*
|
||||||
|
X586800Y397800D01*
|
||||||
|
X586800D01*
|
||||||
|
Y387300D01*
|
||||||
|
X600800D01*
|
||||||
|
X614800D01*
|
||||||
|
Y397800D01*
|
||||||
|
X614800Y397800D01*
|
||||||
|
X613302Y402800D01*
|
||||||
|
X614440Y405545D01*
|
||||||
|
X614460Y405700D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X220660Y396500D02*
|
||||||
|
X207500D01*
|
||||||
|
Y385945D01*
|
||||||
|
X210655Y386360D01*
|
||||||
|
X214060Y387771D01*
|
||||||
|
X216985Y390015D01*
|
||||||
|
X219229Y392940D01*
|
||||||
|
X220640Y396345D01*
|
||||||
|
X220660Y396500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X96660D02*
|
||||||
|
X83500D01*
|
||||||
|
Y385945D01*
|
||||||
|
X86655Y386360D01*
|
||||||
|
X90060Y387771D01*
|
||||||
|
X92985Y390015D01*
|
||||||
|
X95229Y392940D01*
|
||||||
|
X96640Y396345D01*
|
||||||
|
X96660Y396500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X200500D02*
|
||||||
|
X187340D01*
|
||||||
|
X187360Y396345D01*
|
||||||
|
X188771Y392940D01*
|
||||||
|
X191015Y390015D01*
|
||||||
|
X193940Y387771D01*
|
||||||
|
X197345Y386360D01*
|
||||||
|
X200500Y385945D01*
|
||||||
|
Y396500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X76500D02*
|
||||||
|
X63340D01*
|
||||||
|
X63360Y396345D01*
|
||||||
|
X64771Y392940D01*
|
||||||
|
X67015Y390015D01*
|
||||||
|
X69940Y387771D01*
|
||||||
|
X73345Y386360D01*
|
||||||
|
X76500Y385945D01*
|
||||||
|
Y396500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X436921Y385000D02*
|
||||||
|
X427800D01*
|
||||||
|
Y375878D01*
|
||||||
|
X430856Y377144D01*
|
||||||
|
X433572Y379228D01*
|
||||||
|
X435655Y381944D01*
|
||||||
|
X436921Y385000D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y380300D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y380145D01*
|
||||||
|
X664771Y376740D01*
|
||||||
|
X667015Y373815D01*
|
||||||
|
X669940Y371571D01*
|
||||||
|
X673345Y370160D01*
|
||||||
|
X673500Y370140D01*
|
||||||
|
Y380300D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X190000Y317097D02*
|
||||||
|
X186079Y316711D01*
|
||||||
|
X182309Y315567D01*
|
||||||
|
X178835Y313710D01*
|
||||||
|
X175789Y311211D01*
|
||||||
|
X173290Y308165D01*
|
||||||
|
X171433Y304691D01*
|
||||||
|
X170289Y300921D01*
|
||||||
|
X169903Y297000D01*
|
||||||
|
X170289Y293079D01*
|
||||||
|
X171433Y289309D01*
|
||||||
|
X173290Y285835D01*
|
||||||
|
X175789Y282789D01*
|
||||||
|
X178835Y280290D01*
|
||||||
|
X182309Y278433D01*
|
||||||
|
X186079Y277289D01*
|
||||||
|
X190000Y276903D01*
|
||||||
|
X193921Y277289D01*
|
||||||
|
X197691Y278433D01*
|
||||||
|
X201165Y280290D01*
|
||||||
|
X204211Y282789D01*
|
||||||
|
X206710Y285835D01*
|
||||||
|
X208567Y289309D01*
|
||||||
|
X209711Y293079D01*
|
||||||
|
X210097Y297000D01*
|
||||||
|
X209711Y300921D01*
|
||||||
|
X208567Y304691D01*
|
||||||
|
X206710Y308165D01*
|
||||||
|
X204211Y311211D01*
|
||||||
|
X201165Y313710D01*
|
||||||
|
X197691Y315567D01*
|
||||||
|
X193921Y316711D01*
|
||||||
|
X190000Y317097D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X92500Y195700D02*
|
||||||
|
X83500D01*
|
||||||
|
Y186700D01*
|
||||||
|
X92500D01*
|
||||||
|
Y195700D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X503500Y151000D02*
|
||||||
|
X495000D01*
|
||||||
|
Y141500D01*
|
||||||
|
X503500D01*
|
||||||
|
Y151000D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y129860D02*
|
||||||
|
X673345Y129840D01*
|
||||||
|
X669940Y128429D01*
|
||||||
|
X667015Y126185D01*
|
||||||
|
X664771Y123260D01*
|
||||||
|
X663360Y119855D01*
|
||||||
|
X663340Y119700D01*
|
||||||
|
X673500D01*
|
||||||
|
Y129860D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y112700D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y112545D01*
|
||||||
|
X664771Y109140D01*
|
||||||
|
X667015Y106215D01*
|
||||||
|
X669940Y103971D01*
|
||||||
|
X673345Y102560D01*
|
||||||
|
X673500Y102540D01*
|
||||||
|
Y112700D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X505721Y107100D02*
|
||||||
|
X493100D01*
|
||||||
|
X480479D01*
|
||||||
|
X481745Y104044D01*
|
||||||
|
X483828Y101328D01*
|
||||||
|
X484369Y100913D01*
|
||||||
|
X484522Y100607D01*
|
||||||
|
Y95193D01*
|
||||||
|
X484369Y94887D01*
|
||||||
|
X483828Y94472D01*
|
||||||
|
X481745Y91756D01*
|
||||||
|
X480479Y88700D01*
|
||||||
|
X493100D01*
|
||||||
|
X505721D01*
|
||||||
|
X504455Y91756D01*
|
||||||
|
X502372Y94472D01*
|
||||||
|
X501831Y94887D01*
|
||||||
|
X501678Y95193D01*
|
||||||
|
Y100607D01*
|
||||||
|
X501831Y100913D01*
|
||||||
|
X502372Y101328D01*
|
||||||
|
X504455Y104044D01*
|
||||||
|
X505721Y107100D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X83000Y114121D02*
|
||||||
|
X77000D01*
|
||||||
|
X73345Y113640D01*
|
||||||
|
X69940Y112229D01*
|
||||||
|
X67015Y109985D01*
|
||||||
|
X64771Y107060D01*
|
||||||
|
X63360Y103655D01*
|
||||||
|
X62879Y100000D01*
|
||||||
|
X63360Y96345D01*
|
||||||
|
X64771Y92940D01*
|
||||||
|
X67015Y90015D01*
|
||||||
|
X69940Y87771D01*
|
||||||
|
X73345Y86360D01*
|
||||||
|
X77000Y85879D01*
|
||||||
|
X83000D01*
|
||||||
|
X86655Y86360D01*
|
||||||
|
X90060Y87771D01*
|
||||||
|
X92985Y90015D01*
|
||||||
|
X95229Y92940D01*
|
||||||
|
X96640Y96345D01*
|
||||||
|
X97121Y100000D01*
|
||||||
|
X96640Y103655D01*
|
||||||
|
X95229Y107060D01*
|
||||||
|
X92985Y109985D01*
|
||||||
|
X90060Y112229D01*
|
||||||
|
X86655Y113640D01*
|
||||||
|
X83000Y114121D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X83500Y64055D02*
|
||||||
|
Y53500D01*
|
||||||
|
X96660D01*
|
||||||
|
X96640Y53655D01*
|
||||||
|
X95229Y57060D01*
|
||||||
|
X92985Y59985D01*
|
||||||
|
X90060Y62229D01*
|
||||||
|
X86655Y63640D01*
|
||||||
|
X83500Y64055D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y53660D02*
|
||||||
|
X673345Y53640D01*
|
||||||
|
X669940Y52229D01*
|
||||||
|
X667015Y49985D01*
|
||||||
|
X664771Y47060D01*
|
||||||
|
X663360Y43655D01*
|
||||||
|
X663340Y43500D01*
|
||||||
|
X673500D01*
|
||||||
|
Y53660D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X96660Y46500D02*
|
||||||
|
X83500D01*
|
||||||
|
Y35945D01*
|
||||||
|
X86655Y36360D01*
|
||||||
|
X90060Y37771D01*
|
||||||
|
X92985Y40015D01*
|
||||||
|
X95229Y42940D01*
|
||||||
|
X96640Y46345D01*
|
||||||
|
X96660Y46500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X673500Y36500D02*
|
||||||
|
X663340D01*
|
||||||
|
X663360Y36345D01*
|
||||||
|
X664771Y32940D01*
|
||||||
|
X667015Y30015D01*
|
||||||
|
X669940Y27771D01*
|
||||||
|
X673345Y26360D01*
|
||||||
|
X673500Y26340D01*
|
||||||
|
Y36500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X600800Y130321D02*
|
||||||
|
X597145Y129840D01*
|
||||||
|
X593740Y128429D01*
|
||||||
|
X590815Y126185D01*
|
||||||
|
X588571Y123260D01*
|
||||||
|
X587160Y119855D01*
|
||||||
|
X586679Y116200D01*
|
||||||
|
X587160Y112545D01*
|
||||||
|
X588571Y109140D01*
|
||||||
|
X590815Y106215D01*
|
||||||
|
Y100785D01*
|
||||||
|
X588571Y97860D01*
|
||||||
|
X587160Y94455D01*
|
||||||
|
X586679Y90800D01*
|
||||||
|
X587160Y87145D01*
|
||||||
|
X588571Y83740D01*
|
||||||
|
X590815Y80815D01*
|
||||||
|
Y75385D01*
|
||||||
|
X588571Y72460D01*
|
||||||
|
X587160Y69055D01*
|
||||||
|
X586679Y65400D01*
|
||||||
|
X587160Y61745D01*
|
||||||
|
X588298Y59000D01*
|
||||||
|
X586800Y54000D01*
|
||||||
|
X586800D01*
|
||||||
|
Y26000D01*
|
||||||
|
X614800D01*
|
||||||
|
Y54000D01*
|
||||||
|
X614800Y54000D01*
|
||||||
|
X613302Y59000D01*
|
||||||
|
X614440Y61745D01*
|
||||||
|
X614921Y65400D01*
|
||||||
|
X614440Y69055D01*
|
||||||
|
X613029Y72460D01*
|
||||||
|
X610785Y75385D01*
|
||||||
|
Y80815D01*
|
||||||
|
X613029Y83740D01*
|
||||||
|
X614440Y87145D01*
|
||||||
|
X614921Y90800D01*
|
||||||
|
X614440Y94455D01*
|
||||||
|
X613029Y97860D01*
|
||||||
|
X610785Y100785D01*
|
||||||
|
Y106215D01*
|
||||||
|
X613029Y109140D01*
|
||||||
|
X614440Y112545D01*
|
||||||
|
X614921Y116200D01*
|
||||||
|
X614440Y119855D01*
|
||||||
|
X613029Y123260D01*
|
||||||
|
X610785Y126185D01*
|
||||||
|
X607860Y128429D01*
|
||||||
|
X604455Y129840D01*
|
||||||
|
X600800Y130321D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
X548000Y296500D02*
|
||||||
|
X539000D01*
|
||||||
|
Y286500D01*
|
||||||
|
X548000D01*
|
||||||
|
Y296500D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
%LPD*%
|
||||||
|
D18*
|
||||||
|
X382500Y45000D02*
|
||||||
|
D03*
|
||||||
|
X237500D02*
|
||||||
|
D03*
|
||||||
|
D19*
|
||||||
|
X200000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X218000D02*
|
||||||
|
D03*
|
||||||
|
X170500D02*
|
||||||
|
D03*
|
||||||
|
X152500D02*
|
||||||
|
D03*
|
||||||
|
X474500Y139000D02*
|
||||||
|
D03*
|
||||||
|
X492500D02*
|
||||||
|
D03*
|
||||||
|
X629000Y354000D02*
|
||||||
|
D03*
|
||||||
|
X611000D02*
|
||||||
|
D03*
|
||||||
|
D20*
|
||||||
|
X536500Y299000D02*
|
||||||
|
D03*
|
||||||
|
X519500D02*
|
||||||
|
D03*
|
||||||
|
X523500Y352000D02*
|
||||||
|
D03*
|
||||||
|
X506500D02*
|
||||||
|
D03*
|
||||||
|
D21*
|
||||||
|
X449500Y44500D02*
|
||||||
|
D03*
|
||||||
|
Y61500D02*
|
||||||
|
D03*
|
||||||
|
X470000Y44500D02*
|
||||||
|
D03*
|
||||||
|
Y61500D02*
|
||||||
|
D03*
|
||||||
|
D22*
|
||||||
|
X449000Y113000D02*
|
||||||
|
D03*
|
||||||
|
Y95000D02*
|
||||||
|
D03*
|
||||||
|
D43*
|
||||||
|
X367500Y25000D02*
|
||||||
|
X385000Y42500D01*
|
||||||
|
X200000Y25000D02*
|
||||||
|
X367500D01*
|
||||||
|
X63500Y161500D02*
|
||||||
|
X200000Y25000D01*
|
||||||
|
X432884Y44500D02*
|
||||||
|
X449500D01*
|
||||||
|
X417584Y59800D02*
|
||||||
|
X432884Y44500D01*
|
||||||
|
X449500D02*
|
||||||
|
X470000D01*
|
||||||
|
X416900Y59800D02*
|
||||||
|
X417584D01*
|
||||||
|
X396700Y80000D02*
|
||||||
|
X416900Y59800D01*
|
||||||
|
X235000Y80000D02*
|
||||||
|
X396700D01*
|
||||||
|
X63500Y161500D02*
|
||||||
|
Y210428D01*
|
||||||
|
X148130Y170000D02*
|
||||||
|
X152500D01*
|
||||||
|
X101000Y217130D02*
|
||||||
|
X148130Y170000D01*
|
||||||
|
X63500Y210428D02*
|
||||||
|
X69157Y216085D01*
|
||||||
|
X69591D01*
|
||||||
|
X78106Y224600D01*
|
||||||
|
X80000D01*
|
||||||
|
X101000Y217130D02*
|
||||||
|
Y229000D01*
|
||||||
|
X235000Y50000D02*
|
||||||
|
Y80000D01*
|
||||||
|
X118278Y315743D02*
|
||||||
|
Y318278D01*
|
||||||
|
X86834Y284300D02*
|
||||||
|
X118278Y315743D01*
|
||||||
|
X86800Y284300D02*
|
||||||
|
X86834D01*
|
||||||
|
X80000Y277500D02*
|
||||||
|
X86800Y284300D01*
|
||||||
|
X80000Y275400D02*
|
||||||
|
Y277500D01*
|
||||||
|
X137500Y318278D02*
|
||||||
|
X140778Y315000D01*
|
||||||
|
X170000D01*
|
||||||
|
X118278Y318278D02*
|
||||||
|
X120000Y320000D01*
|
||||||
|
X87000Y309694D02*
|
||||||
|
Y314500D01*
|
||||||
|
X80000Y302694D02*
|
||||||
|
X87000Y309694D01*
|
||||||
|
X80000Y300800D02*
|
||||||
|
Y302694D01*
|
||||||
|
X87000Y314500D02*
|
||||||
|
X120000Y347500D01*
|
||||||
|
X200000Y177728D02*
|
||||||
|
X208272Y186000D01*
|
||||||
|
X200000Y170000D02*
|
||||||
|
Y177728D01*
|
||||||
|
X229000Y186000D02*
|
||||||
|
X245000Y170000D01*
|
||||||
|
X208272Y186000D02*
|
||||||
|
X229000D01*
|
||||||
|
X170500Y170000D02*
|
||||||
|
X200000D01*
|
||||||
|
X78661Y223261D02*
|
||||||
|
X80000Y224600D01*
|
||||||
|
X524350Y328350D02*
|
||||||
|
X525000Y329000D01*
|
||||||
|
X523500Y327500D02*
|
||||||
|
X524350Y328350D01*
|
||||||
|
X523000Y332700D02*
|
||||||
|
Y354500D01*
|
||||||
|
X80000Y250000D02*
|
||||||
|
X101000Y229000D01*
|
||||||
|
X628100Y315351D02*
|
||||||
|
Y326200D01*
|
||||||
|
X580249Y267500D02*
|
||||||
|
X628100Y315351D01*
|
||||||
|
X542364Y267500D02*
|
||||||
|
X580249D01*
|
||||||
|
X598477Y231000D02*
|
||||||
|
X653500Y175977D01*
|
||||||
|
X571249Y231000D02*
|
||||||
|
X598477D01*
|
||||||
|
X653500Y173800D02*
|
||||||
|
Y175977D01*
|
||||||
|
X628100Y173800D02*
|
||||||
|
Y175977D01*
|
||||||
|
X588577Y215500D02*
|
||||||
|
X628100Y175977D01*
|
||||||
|
X552248Y215500D02*
|
||||||
|
X588577D01*
|
||||||
|
X570299Y193300D02*
|
||||||
|
X574999Y198000D01*
|
||||||
|
X653250Y326450D02*
|
||||||
|
X653500Y326200D01*
|
||||||
|
X500500Y388500D02*
|
||||||
|
X502677D01*
|
||||||
|
X548777Y434600D01*
|
||||||
|
X593800D01*
|
||||||
|
X533728Y368500D02*
|
||||||
|
X555228Y347000D01*
|
||||||
|
X492923Y368500D02*
|
||||||
|
X533728D01*
|
||||||
|
X528000Y387000D02*
|
||||||
|
X550000D01*
|
||||||
|
X575000Y362000D01*
|
||||||
|
X591000D01*
|
||||||
|
X520000Y431223D02*
|
||||||
|
Y447377D01*
|
||||||
|
X502677Y413900D02*
|
||||||
|
X520000Y431223D01*
|
||||||
|
X653500Y326200D02*
|
||||||
|
Y328500D01*
|
||||||
|
X629000Y353000D02*
|
||||||
|
X653500Y328500D01*
|
||||||
|
X629000Y353000D02*
|
||||||
|
Y354000D01*
|
||||||
|
X599000D02*
|
||||||
|
X611000D01*
|
||||||
|
X591000Y362000D02*
|
||||||
|
X599000Y354000D01*
|
||||||
|
X555228Y347000D02*
|
||||||
|
X584077D01*
|
||||||
|
X602700Y328377D01*
|
||||||
|
Y326200D02*
|
||||||
|
Y328377D01*
|
||||||
|
X479000Y382423D02*
|
||||||
|
X492923Y368500D01*
|
||||||
|
X500000Y285000D02*
|
||||||
|
X501722Y286722D01*
|
||||||
|
X508222D01*
|
||||||
|
X519500Y298000D01*
|
||||||
|
Y299000D01*
|
||||||
|
X526500Y322682D02*
|
||||||
|
Y326200D01*
|
||||||
|
Y322682D02*
|
||||||
|
X535000Y314182D01*
|
||||||
|
Y300500D02*
|
||||||
|
Y314182D01*
|
||||||
|
Y300500D02*
|
||||||
|
X536500Y299000D01*
|
||||||
|
X503587Y315913D02*
|
||||||
|
Y323713D01*
|
||||||
|
X501100Y326200D02*
|
||||||
|
X503587Y323713D01*
|
||||||
|
Y315913D02*
|
||||||
|
X519500Y300000D01*
|
||||||
|
Y299000D02*
|
||||||
|
Y300000D01*
|
||||||
|
X440000Y254500D02*
|
||||||
|
X547749Y254500D01*
|
||||||
|
X401500Y292999D02*
|
||||||
|
X440000Y254500D01*
|
||||||
|
X547749Y254500D02*
|
||||||
|
X571249Y231000D01*
|
||||||
|
X543048Y206300D02*
|
||||||
|
X552248Y215500D01*
|
||||||
|
X486300Y206300D02*
|
||||||
|
X543048D01*
|
||||||
|
X543999Y231999D02*
|
||||||
|
Y233501D01*
|
||||||
|
X536000Y241500D02*
|
||||||
|
X543999Y233501D01*
|
||||||
|
X479251Y274000D02*
|
||||||
|
X485751Y267500D01*
|
||||||
|
X451000Y274000D02*
|
||||||
|
X479251D01*
|
||||||
|
X485751Y267500D02*
|
||||||
|
X542364Y267500D01*
|
||||||
|
X431500Y241500D02*
|
||||||
|
X512751D01*
|
||||||
|
X388500Y284500D02*
|
||||||
|
X431500Y241500D01*
|
||||||
|
X512751D02*
|
||||||
|
X512751Y241500D01*
|
||||||
|
X388500Y284500D02*
|
||||||
|
Y431500D01*
|
||||||
|
X517000Y227000D02*
|
||||||
|
X520000Y224000D01*
|
||||||
|
X424615Y227000D02*
|
||||||
|
X517000D01*
|
||||||
|
X375000Y276615D02*
|
||||||
|
X424615Y227000D01*
|
||||||
|
X512751Y241500D02*
|
||||||
|
X536000D01*
|
||||||
|
X493023Y193300D02*
|
||||||
|
X570299D01*
|
||||||
|
X474500Y174777D02*
|
||||||
|
X493023Y193300D01*
|
||||||
|
X523000Y354500D02*
|
||||||
|
X523500Y355000D01*
|
||||||
|
X524350Y328350D02*
|
||||||
|
X526500Y326200D01*
|
||||||
|
X523000Y329700D02*
|
||||||
|
X524350Y328350D01*
|
||||||
|
X225000Y465000D02*
|
||||||
|
X385000D01*
|
||||||
|
X210000Y450000D02*
|
||||||
|
X225000Y465000D01*
|
||||||
|
X204000Y450000D02*
|
||||||
|
X210000D01*
|
||||||
|
X204000Y100000D02*
|
||||||
|
X205000D01*
|
||||||
|
X245000Y140000D02*
|
||||||
|
X420000D01*
|
||||||
|
X205000Y100000D02*
|
||||||
|
X245000Y140000D01*
|
||||||
|
X401500Y292999D02*
|
||||||
|
Y448500D01*
|
||||||
|
X385000Y465000D02*
|
||||||
|
X401500Y448500D01*
|
||||||
|
X368000Y452000D02*
|
||||||
|
X388500Y431500D01*
|
||||||
|
X347000Y452000D02*
|
||||||
|
X368000D01*
|
||||||
|
X375000Y276615D02*
|
||||||
|
Y415000D01*
|
||||||
|
X360000Y430000D02*
|
||||||
|
X375000Y415000D01*
|
||||||
|
X355400Y430000D02*
|
||||||
|
X360000D01*
|
||||||
|
X330000Y435000D02*
|
||||||
|
X347000Y452000D01*
|
||||||
|
X330000Y430000D02*
|
||||||
|
Y435000D01*
|
||||||
|
X420000Y140000D02*
|
||||||
|
X486300Y206300D01*
|
||||||
|
X448000Y95000D02*
|
||||||
|
X449000D01*
|
||||||
|
X439400Y86400D02*
|
||||||
|
X448000Y95000D01*
|
||||||
|
X418100Y86400D02*
|
||||||
|
X439400D01*
|
||||||
|
X416900Y85200D02*
|
||||||
|
X418100Y86400D01*
|
||||||
|
X479000Y382423D02*
|
||||||
|
Y419977D01*
|
||||||
|
X498323Y439300D01*
|
||||||
|
X500500D01*
|
||||||
|
X506000Y328000D02*
|
||||||
|
Y351500D01*
|
||||||
|
X501100Y326200D02*
|
||||||
|
X504200D01*
|
||||||
|
X470000Y61500D02*
|
||||||
|
X472000D01*
|
||||||
|
X449500D02*
|
||||||
|
X470000D01*
|
||||||
|
X506000Y354500D02*
|
||||||
|
X506500Y355000D01*
|
||||||
|
X474500Y139000D02*
|
||||||
|
Y174777D01*
|
||||||
|
Y137500D02*
|
||||||
|
Y139000D01*
|
||||||
|
X450000Y113000D02*
|
||||||
|
X474500Y137500D01*
|
||||||
|
X449000Y113000D02*
|
||||||
|
X450000D01*
|
||||||
|
X470000Y61500D02*
|
||||||
|
Y65000D01*
|
||||||
|
X490200Y85200D02*
|
||||||
|
X493100D01*
|
||||||
|
X470000Y65000D02*
|
||||||
|
X490200Y85200D01*
|
||||||
|
X492800Y110900D02*
|
||||||
|
X493100Y110600D01*
|
||||||
|
X492800Y110900D02*
|
||||||
|
Y134700D01*
|
||||||
|
X492500Y135000D02*
|
||||||
|
X492800Y134700D01*
|
||||||
|
X500500Y464700D02*
|
||||||
|
X502677D01*
|
||||||
|
X466000Y362301D02*
|
||||||
|
X496151Y332151D01*
|
||||||
|
X466000Y436000D02*
|
||||||
|
X494700Y464700D01*
|
||||||
|
X500500D01*
|
||||||
|
X502677D02*
|
||||||
|
X520000Y447377D01*
|
||||||
|
X499600Y413000D02*
|
||||||
|
X500000D01*
|
||||||
|
X502000Y463200D02*
|
||||||
|
Y464000D01*
|
||||||
|
X498000Y414000D02*
|
||||||
|
Y415041D01*
|
||||||
|
X466000Y362301D02*
|
||||||
|
Y436000D01*
|
||||||
|
X500500Y413900D02*
|
||||||
|
X502677D01*
|
||||||
|
D44*
|
||||||
|
X650000Y250000D02*
|
||||||
|
D03*
|
||||||
|
X25000Y475000D02*
|
||||||
|
D03*
|
||||||
|
Y25000D02*
|
||||||
|
D03*
|
||||||
|
D45*
|
||||||
|
X120000Y347500D02*
|
||||||
|
D03*
|
||||||
|
Y320000D02*
|
||||||
|
D03*
|
||||||
|
X355400Y430000D02*
|
||||||
|
D03*
|
||||||
|
X330000D02*
|
||||||
|
D03*
|
||||||
|
X304600D02*
|
||||||
|
D03*
|
||||||
|
X587000Y299000D02*
|
||||||
|
D03*
|
||||||
|
X235000Y80000D02*
|
||||||
|
D03*
|
||||||
|
X245000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X574999Y198000D02*
|
||||||
|
D03*
|
||||||
|
X528000Y387000D02*
|
||||||
|
D03*
|
||||||
|
X500000Y285000D02*
|
||||||
|
D03*
|
||||||
|
X543999Y231999D02*
|
||||||
|
D03*
|
||||||
|
X451000Y274000D02*
|
||||||
|
D03*
|
||||||
|
X520000Y224000D02*
|
||||||
|
D03*
|
||||||
|
D46*
|
||||||
|
X80000Y450000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y400000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y100000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y50000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
D47*
|
||||||
|
X80000Y300800D02*
|
||||||
|
D03*
|
||||||
|
Y275400D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y224600D02*
|
||||||
|
D03*
|
||||||
|
X254600Y119000D02*
|
||||||
|
D03*
|
||||||
|
X356200D02*
|
||||||
|
D03*
|
||||||
|
X330800D02*
|
||||||
|
D03*
|
||||||
|
X305400D02*
|
||||||
|
D03*
|
||||||
|
X280000D02*
|
||||||
|
D03*
|
||||||
|
D48*
|
||||||
|
X80000Y199200D02*
|
||||||
|
D03*
|
||||||
|
D49*
|
||||||
|
X381600Y119000D02*
|
||||||
|
D03*
|
||||||
|
D50*
|
||||||
|
X190000Y203000D02*
|
||||||
|
D03*
|
||||||
|
Y297000D02*
|
||||||
|
D03*
|
||||||
|
D51*
|
||||||
|
X120000Y225000D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y275000D02*
|
||||||
|
D03*
|
||||||
|
D52*
|
||||||
|
X677000Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y460000D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y434600D02*
|
||||||
|
D03*
|
||||||
|
Y409200D02*
|
||||||
|
D03*
|
||||||
|
X677000Y40000D02*
|
||||||
|
D03*
|
||||||
|
Y116200D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y90800D02*
|
||||||
|
D03*
|
||||||
|
Y65400D02*
|
||||||
|
D03*
|
||||||
|
X678900Y326200D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
X678900Y173800D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
D53*
|
||||||
|
X600800Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y40000D02*
|
||||||
|
D03*
|
||||||
|
D54*
|
||||||
|
X416900Y34400D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y110600D02*
|
||||||
|
D03*
|
||||||
|
X493100D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
D55*
|
||||||
|
Y34400D02*
|
||||||
|
D03*
|
||||||
|
D56*
|
||||||
|
X279200Y430000D02*
|
||||||
|
D03*
|
||||||
|
D57*
|
||||||
|
X424300Y464684D02*
|
||||||
|
D03*
|
||||||
|
D58*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y388500D02*
|
||||||
|
D03*
|
||||||
|
X500500D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y464700D02*
|
||||||
|
D03*
|
||||||
|
M02*
|
||||||
1099
PCB/GerberManufacture/OptoTest.GTO
Normal file
1099
PCB/GerberManufacture/OptoTest.GTO
Normal file
@@ -0,0 +1,1099 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=65535*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD10C,0.1524*%
|
||||||
|
%ADD11C,0.2540*%
|
||||||
|
%ADD12C,0.2000*%
|
||||||
|
%ADD13C,0.1500*%
|
||||||
|
%ADD14C,0.1000*%
|
||||||
|
%ADD15C,0.1800*%
|
||||||
|
%ADD16C,0.2500*%
|
||||||
|
%ADD17C,0.1540*%
|
||||||
|
G36*
|
||||||
|
X125490Y58490D02*
|
||||||
|
Y91510D01*
|
||||||
|
X158510D01*
|
||||||
|
Y58490D01*
|
||||||
|
X125490D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
G36*
|
||||||
|
Y408490D02*
|
||||||
|
Y441510D01*
|
||||||
|
X158510D01*
|
||||||
|
Y408490D01*
|
||||||
|
X125490D01*
|
||||||
|
D02*
|
||||||
|
G37*
|
||||||
|
D10*
|
||||||
|
X202960Y475800D02*
|
||||||
|
G03*
|
||||||
|
X192800Y485960I-10160J0D01*
|
||||||
|
G01*
|
||||||
|
X154617Y375792D02*
|
||||||
|
G03*
|
||||||
|
X154929Y474127I-12617J49208D01*
|
||||||
|
G01*
|
||||||
|
X192800Y364040D02*
|
||||||
|
G03*
|
||||||
|
X202960Y374200I0J10160D01*
|
||||||
|
G01*
|
||||||
|
X154477Y386323D02*
|
||||||
|
G03*
|
||||||
|
X154477Y463677I-12477J38677D01*
|
||||||
|
G01*
|
||||||
|
X129523D02*
|
||||||
|
G03*
|
||||||
|
X129523Y386323I12477J-38677D01*
|
||||||
|
G01*
|
||||||
|
X91200Y485960D02*
|
||||||
|
G03*
|
||||||
|
X81040Y475800I0J-10160D01*
|
||||||
|
G01*
|
||||||
|
X129382Y474208D02*
|
||||||
|
G03*
|
||||||
|
X129072Y375873I12617J-49208D01*
|
||||||
|
G01*
|
||||||
|
X81040Y374200D02*
|
||||||
|
G03*
|
||||||
|
X91200Y364040I10160J0D01*
|
||||||
|
G01*
|
||||||
|
X81040Y24200D02*
|
||||||
|
G03*
|
||||||
|
X91200Y14040I10160J0D01*
|
||||||
|
G01*
|
||||||
|
X129382Y124208D02*
|
||||||
|
G03*
|
||||||
|
X129072Y25873I12617J-49208D01*
|
||||||
|
G01*
|
||||||
|
X91200Y135960D02*
|
||||||
|
G03*
|
||||||
|
X81040Y125800I0J-10160D01*
|
||||||
|
G01*
|
||||||
|
X129523Y113677D02*
|
||||||
|
G03*
|
||||||
|
X129523Y36323I12477J-38677D01*
|
||||||
|
G01*
|
||||||
|
X154477D02*
|
||||||
|
G03*
|
||||||
|
X154477Y113677I-12477J38677D01*
|
||||||
|
G01*
|
||||||
|
X192800Y14040D02*
|
||||||
|
G03*
|
||||||
|
X202960Y24200I0J10160D01*
|
||||||
|
G01*
|
||||||
|
X154617Y25792D02*
|
||||||
|
G03*
|
||||||
|
X154929Y124127I-12617J49208D01*
|
||||||
|
G01*
|
||||||
|
X202960Y125800D02*
|
||||||
|
G03*
|
||||||
|
X192800Y135960I-10160J0D01*
|
||||||
|
G01*
|
||||||
|
D11*
|
||||||
|
X411900Y477400D02*
|
||||||
|
G03*
|
||||||
|
X411900Y477400I-300J0D01*
|
||||||
|
G01*
|
||||||
|
X449700D02*
|
||||||
|
G03*
|
||||||
|
X475100Y477400I12700J0D01*
|
||||||
|
G01*
|
||||||
|
X67300Y186500D02*
|
||||||
|
X92700D01*
|
||||||
|
Y313500D01*
|
||||||
|
X67300Y186500D02*
|
||||||
|
Y313500D01*
|
||||||
|
X92700D01*
|
||||||
|
X407000Y373000D02*
|
||||||
|
Y482000D01*
|
||||||
|
Y373000D02*
|
||||||
|
X516000D01*
|
||||||
|
X407000Y482000D02*
|
||||||
|
X516000D01*
|
||||||
|
Y373000D02*
|
||||||
|
Y482000D01*
|
||||||
|
X332153Y304294D02*
|
||||||
|
X321996Y299216D01*
|
||||||
|
X332153Y294137D01*
|
||||||
|
X321996Y281441D02*
|
||||||
|
Y286520D01*
|
||||||
|
X324536Y289059D01*
|
||||||
|
X329614D01*
|
||||||
|
X332153Y286520D01*
|
||||||
|
Y281441D01*
|
||||||
|
X329614Y278902D01*
|
||||||
|
X327075D01*
|
||||||
|
Y289059D01*
|
||||||
|
X332153Y273824D02*
|
||||||
|
X321996D01*
|
||||||
|
X327075D01*
|
||||||
|
X329614Y271285D01*
|
||||||
|
X332153Y268745D01*
|
||||||
|
Y266206D01*
|
||||||
|
X321996Y258589D02*
|
||||||
|
X324536D01*
|
||||||
|
Y256050D01*
|
||||||
|
X321996D01*
|
||||||
|
Y258589D01*
|
||||||
|
Y230658D02*
|
||||||
|
Y225579D01*
|
||||||
|
Y228119D01*
|
||||||
|
X337231D01*
|
||||||
|
X334692Y230658D01*
|
||||||
|
X321996Y217962D02*
|
||||||
|
X324536D01*
|
||||||
|
Y215423D01*
|
||||||
|
X321996D01*
|
||||||
|
Y217962D01*
|
||||||
|
X334692Y205266D02*
|
||||||
|
X337231Y202727D01*
|
||||||
|
Y197649D01*
|
||||||
|
X334692Y195109D01*
|
||||||
|
X324536D01*
|
||||||
|
X321996Y197649D01*
|
||||||
|
Y202727D01*
|
||||||
|
X324536Y205266D01*
|
||||||
|
X334692D01*
|
||||||
|
X312853Y337303D02*
|
||||||
|
X297618D01*
|
||||||
|
Y344921D01*
|
||||||
|
X300158Y347460D01*
|
||||||
|
X305236D01*
|
||||||
|
X307775Y344921D01*
|
||||||
|
Y337303D01*
|
||||||
|
X297618Y332225D02*
|
||||||
|
Y327147D01*
|
||||||
|
Y329686D01*
|
||||||
|
X307775D01*
|
||||||
|
Y332225D01*
|
||||||
|
X292540Y314451D02*
|
||||||
|
Y311912D01*
|
||||||
|
X295079Y309372D01*
|
||||||
|
X307775D01*
|
||||||
|
Y316990D01*
|
||||||
|
X305236Y319529D01*
|
||||||
|
X300158D01*
|
||||||
|
X297618Y316990D01*
|
||||||
|
Y309372D01*
|
||||||
|
Y304294D02*
|
||||||
|
Y299216D01*
|
||||||
|
Y301755D01*
|
||||||
|
X307775D01*
|
||||||
|
Y304294D01*
|
||||||
|
X310314Y289059D02*
|
||||||
|
X307775D01*
|
||||||
|
Y291598D01*
|
||||||
|
Y286520D01*
|
||||||
|
Y289059D01*
|
||||||
|
X300158D01*
|
||||||
|
X297618Y286520D01*
|
||||||
|
X307775Y276363D02*
|
||||||
|
Y271285D01*
|
||||||
|
X305236Y268745D01*
|
||||||
|
X297618D01*
|
||||||
|
Y276363D01*
|
||||||
|
X300158Y278902D01*
|
||||||
|
X302697Y276363D01*
|
||||||
|
Y268745D01*
|
||||||
|
X297618Y263667D02*
|
||||||
|
Y258589D01*
|
||||||
|
Y261128D01*
|
||||||
|
X312853D01*
|
||||||
|
Y263667D01*
|
||||||
|
X297618Y250971D02*
|
||||||
|
X307775Y240814D01*
|
||||||
|
Y233197D02*
|
||||||
|
Y228119D01*
|
||||||
|
X305236Y225579D01*
|
||||||
|
X297618D01*
|
||||||
|
Y233197D01*
|
||||||
|
X300158Y235736D01*
|
||||||
|
X302697Y233197D01*
|
||||||
|
Y225579D01*
|
||||||
|
X297618Y220501D02*
|
||||||
|
X307775D01*
|
||||||
|
Y212884D01*
|
||||||
|
X305236Y210344D01*
|
||||||
|
X297618D01*
|
||||||
|
X307775Y202727D02*
|
||||||
|
Y197649D01*
|
||||||
|
X305236Y195109D01*
|
||||||
|
X297618D01*
|
||||||
|
Y202727D01*
|
||||||
|
X300158Y205266D01*
|
||||||
|
X302697Y202727D01*
|
||||||
|
Y195109D01*
|
||||||
|
X297618Y190031D02*
|
||||||
|
Y184953D01*
|
||||||
|
Y187492D01*
|
||||||
|
X312853D01*
|
||||||
|
Y190031D01*
|
||||||
|
X297618Y174796D02*
|
||||||
|
Y169718D01*
|
||||||
|
X300158Y167178D01*
|
||||||
|
X305236D01*
|
||||||
|
X307775Y169718D01*
|
||||||
|
Y174796D01*
|
||||||
|
X305236Y177335D01*
|
||||||
|
X300158D01*
|
||||||
|
X297618Y174796D01*
|
||||||
|
X292540Y157022D02*
|
||||||
|
Y154482D01*
|
||||||
|
X295079Y151943D01*
|
||||||
|
X307775D01*
|
||||||
|
Y159561D01*
|
||||||
|
X305236Y162100D01*
|
||||||
|
X300158D01*
|
||||||
|
X297618Y159561D01*
|
||||||
|
Y151943D01*
|
||||||
|
X257657Y105196D02*
|
||||||
|
X255117Y107735D01*
|
||||||
|
X250039D01*
|
||||||
|
X247500Y105196D01*
|
||||||
|
Y102657D01*
|
||||||
|
X250039Y100118D01*
|
||||||
|
X255117D01*
|
||||||
|
X257657Y97578D01*
|
||||||
|
Y95039D01*
|
||||||
|
X255117Y92500D01*
|
||||||
|
X250039D01*
|
||||||
|
X247500Y95039D01*
|
||||||
|
X262735Y107735D02*
|
||||||
|
Y92500D01*
|
||||||
|
X267813Y97578D01*
|
||||||
|
X272892Y92500D01*
|
||||||
|
Y107735D01*
|
||||||
|
X277970Y89961D02*
|
||||||
|
X288127D01*
|
||||||
|
X293205Y92500D02*
|
||||||
|
Y107735D01*
|
||||||
|
X300823D01*
|
||||||
|
X303362Y105196D01*
|
||||||
|
Y100118D01*
|
||||||
|
X300823Y97578D01*
|
||||||
|
X293205D01*
|
||||||
|
X316058Y107735D02*
|
||||||
|
X310979D01*
|
||||||
|
X308440Y105196D01*
|
||||||
|
Y95039D01*
|
||||||
|
X310979Y92500D01*
|
||||||
|
X316058D01*
|
||||||
|
X318597Y95039D01*
|
||||||
|
Y105196D01*
|
||||||
|
X316058Y107735D01*
|
||||||
|
X323675D02*
|
||||||
|
Y92500D01*
|
||||||
|
X328754Y97578D01*
|
||||||
|
X333832Y92500D01*
|
||||||
|
Y107735D01*
|
||||||
|
X349067D02*
|
||||||
|
X338910D01*
|
||||||
|
Y92500D01*
|
||||||
|
X349067D01*
|
||||||
|
X338910Y100118D02*
|
||||||
|
X343989D01*
|
||||||
|
X354146Y92500D02*
|
||||||
|
Y107735D01*
|
||||||
|
X361763D01*
|
||||||
|
X364302Y105196D01*
|
||||||
|
Y100118D01*
|
||||||
|
X361763Y97578D01*
|
||||||
|
X354146D01*
|
||||||
|
X359224D02*
|
||||||
|
X364302Y92500D01*
|
||||||
|
X45000Y260000D02*
|
||||||
|
X60235D01*
|
||||||
|
Y252383D01*
|
||||||
|
X57696Y249843D01*
|
||||||
|
X52618D01*
|
||||||
|
X50078Y252383D01*
|
||||||
|
Y260000D01*
|
||||||
|
X45000Y244765D02*
|
||||||
|
Y239687D01*
|
||||||
|
Y242226D01*
|
||||||
|
X60235D01*
|
||||||
|
X57696Y244765D01*
|
||||||
|
X560157Y303196D02*
|
||||||
|
X557617Y305735D01*
|
||||||
|
X552539D01*
|
||||||
|
X550000Y303196D01*
|
||||||
|
Y293039D01*
|
||||||
|
X552539Y290500D01*
|
||||||
|
X557617D01*
|
||||||
|
X560157Y293039D01*
|
||||||
|
X575392Y290500D02*
|
||||||
|
X565235D01*
|
||||||
|
X575392Y300657D01*
|
||||||
|
Y303196D01*
|
||||||
|
X572853Y305735D01*
|
||||||
|
X567774D01*
|
||||||
|
X565235Y303196D01*
|
||||||
|
X546157Y357196D02*
|
||||||
|
X543618Y359735D01*
|
||||||
|
X538539D01*
|
||||||
|
X536000Y357196D01*
|
||||||
|
Y347039D01*
|
||||||
|
X538539Y344500D01*
|
||||||
|
X543618D01*
|
||||||
|
X546157Y347039D01*
|
||||||
|
X551235Y357196D02*
|
||||||
|
X553774Y359735D01*
|
||||||
|
X558853D01*
|
||||||
|
X561392Y357196D01*
|
||||||
|
Y354657D01*
|
||||||
|
X558853Y352118D01*
|
||||||
|
X556313D01*
|
||||||
|
X558853D01*
|
||||||
|
X561392Y349578D01*
|
||||||
|
Y347039D01*
|
||||||
|
X558853Y344500D01*
|
||||||
|
X553774D01*
|
||||||
|
X551235Y347039D01*
|
||||||
|
X148000Y140000D02*
|
||||||
|
Y155235D01*
|
||||||
|
X155618D01*
|
||||||
|
X158157Y152696D01*
|
||||||
|
Y147618D01*
|
||||||
|
X155618Y145078D01*
|
||||||
|
X148000D01*
|
||||||
|
X153078D02*
|
||||||
|
X158157Y140000D01*
|
||||||
|
X173392Y155235D02*
|
||||||
|
X168313Y152696D01*
|
||||||
|
X163235Y147618D01*
|
||||||
|
Y142539D01*
|
||||||
|
X165774Y140000D01*
|
||||||
|
X170853D01*
|
||||||
|
X173392Y142539D01*
|
||||||
|
Y145078D01*
|
||||||
|
X170853Y147618D01*
|
||||||
|
X163235D01*
|
||||||
|
X195000Y140000D02*
|
||||||
|
Y155235D01*
|
||||||
|
X202617D01*
|
||||||
|
X205157Y152696D01*
|
||||||
|
Y147618D01*
|
||||||
|
X202617Y145078D01*
|
||||||
|
X195000D01*
|
||||||
|
X200078D02*
|
||||||
|
X205157Y140000D01*
|
||||||
|
X210235Y155235D02*
|
||||||
|
X220392D01*
|
||||||
|
Y152696D01*
|
||||||
|
X210235Y142539D01*
|
||||||
|
Y140000D01*
|
||||||
|
X641000Y347000D02*
|
||||||
|
Y362235D01*
|
||||||
|
X648617D01*
|
||||||
|
X651157Y359696D01*
|
||||||
|
Y354618D01*
|
||||||
|
X648617Y352078D01*
|
||||||
|
X641000D01*
|
||||||
|
X646078D02*
|
||||||
|
X651157Y347000D01*
|
||||||
|
X656235D02*
|
||||||
|
X661313D01*
|
||||||
|
X658774D01*
|
||||||
|
Y362235D01*
|
||||||
|
X656235Y359696D01*
|
||||||
|
X668931Y347000D02*
|
||||||
|
X674009D01*
|
||||||
|
X671470D01*
|
||||||
|
Y362235D01*
|
||||||
|
X668931Y359696D01*
|
||||||
|
X150000Y295000D02*
|
||||||
|
X165235D01*
|
||||||
|
Y287383D01*
|
||||||
|
X162696Y284843D01*
|
||||||
|
X157618D01*
|
||||||
|
X155078Y287383D01*
|
||||||
|
Y295000D01*
|
||||||
|
X165235Y272147D02*
|
||||||
|
Y277226D01*
|
||||||
|
X162696Y279765D01*
|
||||||
|
X152539D01*
|
||||||
|
X150000Y277226D01*
|
||||||
|
Y272147D01*
|
||||||
|
X152539Y269608D01*
|
||||||
|
X162696D01*
|
||||||
|
X165235Y272147D01*
|
||||||
|
Y264530D02*
|
||||||
|
Y254373D01*
|
||||||
|
Y259452D01*
|
||||||
|
X150000D01*
|
||||||
|
X157618Y249295D02*
|
||||||
|
Y239138D01*
|
||||||
|
X165235Y234060D02*
|
||||||
|
X150000D01*
|
||||||
|
X157618D01*
|
||||||
|
Y223903D01*
|
||||||
|
X165235D01*
|
||||||
|
X150000D01*
|
||||||
|
X162696Y208668D02*
|
||||||
|
X165235Y211207D01*
|
||||||
|
Y216285D01*
|
||||||
|
X162696Y218825D01*
|
||||||
|
X152539D01*
|
||||||
|
X150000Y216285D01*
|
||||||
|
Y211207D01*
|
||||||
|
X152539Y208668D01*
|
||||||
|
X157618D01*
|
||||||
|
Y213746D01*
|
||||||
|
X614235Y274843D02*
|
||||||
|
Y285000D01*
|
||||||
|
X599000D01*
|
||||||
|
Y274843D01*
|
||||||
|
X606618Y285000D02*
|
||||||
|
Y279922D01*
|
||||||
|
X611696Y259608D02*
|
||||||
|
X614235Y262147D01*
|
||||||
|
Y267226D01*
|
||||||
|
X611696Y269765D01*
|
||||||
|
X609157D01*
|
||||||
|
X606618Y267226D01*
|
||||||
|
Y262147D01*
|
||||||
|
X604078Y259608D01*
|
||||||
|
X601539D01*
|
||||||
|
X599000Y262147D01*
|
||||||
|
Y267226D01*
|
||||||
|
X601539Y269765D01*
|
||||||
|
X599000Y254530D02*
|
||||||
|
X614235D01*
|
||||||
|
Y246912D01*
|
||||||
|
X611696Y244373D01*
|
||||||
|
X606618D01*
|
||||||
|
X604078Y246912D01*
|
||||||
|
Y254530D01*
|
||||||
|
X611696Y239295D02*
|
||||||
|
X614235Y236756D01*
|
||||||
|
Y231677D01*
|
||||||
|
X611696Y229138D01*
|
||||||
|
X609157D01*
|
||||||
|
X606618Y231677D01*
|
||||||
|
Y234216D01*
|
||||||
|
Y231677D01*
|
||||||
|
X604078Y229138D01*
|
||||||
|
X601539D01*
|
||||||
|
X599000Y231677D01*
|
||||||
|
Y236756D01*
|
||||||
|
X601539Y239295D01*
|
||||||
|
X599000Y213903D02*
|
||||||
|
Y224060D01*
|
||||||
|
X609157Y213903D01*
|
||||||
|
X611696D01*
|
||||||
|
X614235Y216442D01*
|
||||||
|
Y221521D01*
|
||||||
|
X611696Y224060D01*
|
||||||
|
X526235Y105382D02*
|
||||||
|
Y110461D01*
|
||||||
|
X523696Y113000D01*
|
||||||
|
X513539D01*
|
||||||
|
X511000Y110461D01*
|
||||||
|
Y105382D01*
|
||||||
|
X513539Y102843D01*
|
||||||
|
X523696D01*
|
||||||
|
X526235Y105382D01*
|
||||||
|
X511000Y97765D02*
|
||||||
|
X526235D01*
|
||||||
|
Y90147D01*
|
||||||
|
X523696Y87608D01*
|
||||||
|
X518618D01*
|
||||||
|
X516078Y90147D01*
|
||||||
|
Y97765D01*
|
||||||
|
X511000Y82530D02*
|
||||||
|
X521157D01*
|
||||||
|
X526235Y77452D01*
|
||||||
|
X521157Y72373D01*
|
||||||
|
X511000D01*
|
||||||
|
X518618D01*
|
||||||
|
Y82530D01*
|
||||||
|
X523696Y67295D02*
|
||||||
|
X526235Y64756D01*
|
||||||
|
Y59677D01*
|
||||||
|
X523696Y57138D01*
|
||||||
|
X521157D01*
|
||||||
|
X518618Y59677D01*
|
||||||
|
Y62216D01*
|
||||||
|
Y59677D01*
|
||||||
|
X516078Y57138D01*
|
||||||
|
X513539D01*
|
||||||
|
X511000Y59677D01*
|
||||||
|
Y64756D01*
|
||||||
|
X513539Y67295D01*
|
||||||
|
X523696Y52060D02*
|
||||||
|
X526235Y49521D01*
|
||||||
|
Y44442D01*
|
||||||
|
X523696Y41903D01*
|
||||||
|
X521157D01*
|
||||||
|
X518618Y44442D01*
|
||||||
|
X516078Y41903D01*
|
||||||
|
X513539D01*
|
||||||
|
X511000Y44442D01*
|
||||||
|
Y49521D01*
|
||||||
|
X513539Y52060D01*
|
||||||
|
X516078D01*
|
||||||
|
X518618Y49521D01*
|
||||||
|
X521157Y52060D01*
|
||||||
|
X523696D01*
|
||||||
|
X518618Y49521D02*
|
||||||
|
Y44442D01*
|
||||||
|
X523696Y36825D02*
|
||||||
|
X526235Y34286D01*
|
||||||
|
Y29207D01*
|
||||||
|
X523696Y26668D01*
|
||||||
|
X513539D01*
|
||||||
|
X511000Y29207D01*
|
||||||
|
Y34286D01*
|
||||||
|
X513539Y36825D01*
|
||||||
|
X523696D01*
|
||||||
|
X435000Y132000D02*
|
||||||
|
Y147235D01*
|
||||||
|
X442617D01*
|
||||||
|
X445157Y144696D01*
|
||||||
|
Y139618D01*
|
||||||
|
X442617Y137078D01*
|
||||||
|
X435000D01*
|
||||||
|
X440078D02*
|
||||||
|
X445157Y132000D01*
|
||||||
|
X460392Y147235D02*
|
||||||
|
X450235D01*
|
||||||
|
Y139618D01*
|
||||||
|
X455313Y142157D01*
|
||||||
|
X457853D01*
|
||||||
|
X460392Y139618D01*
|
||||||
|
Y134539D01*
|
||||||
|
X457853Y132000D01*
|
||||||
|
X452774D01*
|
||||||
|
X450235Y134539D01*
|
||||||
|
X562235Y456183D02*
|
||||||
|
Y461261D01*
|
||||||
|
X559696Y463800D01*
|
||||||
|
X549539D01*
|
||||||
|
X547000Y461261D01*
|
||||||
|
Y456183D01*
|
||||||
|
X549539Y453643D01*
|
||||||
|
X559696D01*
|
||||||
|
X562235Y456183D01*
|
||||||
|
X547000Y448565D02*
|
||||||
|
X562235D01*
|
||||||
|
Y440947D01*
|
||||||
|
X559696Y438408D01*
|
||||||
|
X554618D01*
|
||||||
|
X552078Y440947D01*
|
||||||
|
Y448565D01*
|
||||||
|
X562235Y433330D02*
|
||||||
|
Y423173D01*
|
||||||
|
Y428251D01*
|
||||||
|
X547000D01*
|
||||||
|
X544461Y418095D02*
|
||||||
|
Y407938D01*
|
||||||
|
X562235Y402860D02*
|
||||||
|
Y392703D01*
|
||||||
|
Y397781D01*
|
||||||
|
X547000D01*
|
||||||
|
X562235Y387625D02*
|
||||||
|
X547000Y377468D01*
|
||||||
|
X562235D02*
|
||||||
|
X547000Y387625D01*
|
||||||
|
X470235Y455000D02*
|
||||||
|
Y444843D01*
|
||||||
|
X467696D01*
|
||||||
|
X457539Y455000D01*
|
||||||
|
X455000D01*
|
||||||
|
X470235Y429608D02*
|
||||||
|
Y439765D01*
|
||||||
|
X462617D01*
|
||||||
|
X465157Y434687D01*
|
||||||
|
Y432147D01*
|
||||||
|
X462617Y429608D01*
|
||||||
|
X457539D01*
|
||||||
|
X455000Y432147D01*
|
||||||
|
Y437226D01*
|
||||||
|
X457539Y439765D01*
|
||||||
|
X455000Y416912D02*
|
||||||
|
X470235D01*
|
||||||
|
X462617Y424530D01*
|
||||||
|
Y414373D01*
|
||||||
|
X470235Y399138D02*
|
||||||
|
Y409295D01*
|
||||||
|
X462617D01*
|
||||||
|
X465157Y404216D01*
|
||||||
|
Y401677D01*
|
||||||
|
X462617Y399138D01*
|
||||||
|
X457539D01*
|
||||||
|
X455000Y401677D01*
|
||||||
|
Y406756D01*
|
||||||
|
X457539Y409295D01*
|
||||||
|
X455000Y394060D02*
|
||||||
|
Y388981D01*
|
||||||
|
Y391521D01*
|
||||||
|
X470235D01*
|
||||||
|
X467696Y394060D01*
|
||||||
|
X562235Y112382D02*
|
||||||
|
Y117461D01*
|
||||||
|
X559696Y120000D01*
|
||||||
|
X549539D01*
|
||||||
|
X547000Y117461D01*
|
||||||
|
Y112382D01*
|
||||||
|
X549539Y109843D01*
|
||||||
|
X559696D01*
|
||||||
|
X562235Y112382D01*
|
||||||
|
X547000Y104765D02*
|
||||||
|
X562235D01*
|
||||||
|
Y97147D01*
|
||||||
|
X559696Y94608D01*
|
||||||
|
X554618D01*
|
||||||
|
X552078Y97147D01*
|
||||||
|
Y104765D01*
|
||||||
|
X562235Y89530D02*
|
||||||
|
Y79373D01*
|
||||||
|
Y84452D01*
|
||||||
|
X547000D01*
|
||||||
|
X544461Y74295D02*
|
||||||
|
Y64138D01*
|
||||||
|
X547000Y59060D02*
|
||||||
|
X562235D01*
|
||||||
|
Y51442D01*
|
||||||
|
X559696Y48903D01*
|
||||||
|
X554618D01*
|
||||||
|
X552078Y51442D01*
|
||||||
|
Y59060D01*
|
||||||
|
Y53981D02*
|
||||||
|
X547000Y48903D01*
|
||||||
|
X562235Y43825D02*
|
||||||
|
X547000Y33668D01*
|
||||||
|
X562235D02*
|
||||||
|
X547000Y43825D01*
|
||||||
|
X297617Y405235D02*
|
||||||
|
X292539D01*
|
||||||
|
X290000Y402696D01*
|
||||||
|
Y392539D01*
|
||||||
|
X292539Y390000D01*
|
||||||
|
X297617D01*
|
||||||
|
X300157Y392539D01*
|
||||||
|
Y402696D01*
|
||||||
|
X297617Y405235D01*
|
||||||
|
X305235D02*
|
||||||
|
Y390000D01*
|
||||||
|
X315392D01*
|
||||||
|
X330627Y405235D02*
|
||||||
|
X320470D01*
|
||||||
|
Y390000D01*
|
||||||
|
X330627D01*
|
||||||
|
X320470Y397617D02*
|
||||||
|
X325549D01*
|
||||||
|
X335705Y405235D02*
|
||||||
|
Y390000D01*
|
||||||
|
X343323D01*
|
||||||
|
X345862Y392539D01*
|
||||||
|
Y402696D01*
|
||||||
|
X343323Y405235D01*
|
||||||
|
X335705D01*
|
||||||
|
X57696Y162343D02*
|
||||||
|
X60235Y164883D01*
|
||||||
|
Y169961D01*
|
||||||
|
X57696Y172500D01*
|
||||||
|
X55157D01*
|
||||||
|
X52618Y169961D01*
|
||||||
|
Y164883D01*
|
||||||
|
X50078Y162343D01*
|
||||||
|
X47539D01*
|
||||||
|
X45000Y164883D01*
|
||||||
|
Y169961D01*
|
||||||
|
X47539Y172500D01*
|
||||||
|
X60235Y157265D02*
|
||||||
|
X45000D01*
|
||||||
|
X50078Y152187D01*
|
||||||
|
X45000Y147108D01*
|
||||||
|
X60235D01*
|
||||||
|
X42461Y142030D02*
|
||||||
|
Y131873D01*
|
||||||
|
X57696Y116638D02*
|
||||||
|
X60235Y119177D01*
|
||||||
|
Y124256D01*
|
||||||
|
X57696Y126795D01*
|
||||||
|
X55157D01*
|
||||||
|
X52618Y124256D01*
|
||||||
|
Y119177D01*
|
||||||
|
X50078Y116638D01*
|
||||||
|
X47539D01*
|
||||||
|
X45000Y119177D01*
|
||||||
|
Y124256D01*
|
||||||
|
X47539Y126795D01*
|
||||||
|
X60235Y111560D02*
|
||||||
|
Y101403D01*
|
||||||
|
Y106481D01*
|
||||||
|
X45000D01*
|
||||||
|
Y96325D02*
|
||||||
|
X55157D01*
|
||||||
|
X60235Y91246D01*
|
||||||
|
X55157Y86168D01*
|
||||||
|
X45000D01*
|
||||||
|
X52618D01*
|
||||||
|
Y96325D01*
|
||||||
|
X45000Y81090D02*
|
||||||
|
X60235D01*
|
||||||
|
Y73472D01*
|
||||||
|
X57696Y70933D01*
|
||||||
|
X52618D01*
|
||||||
|
X50078Y73472D01*
|
||||||
|
Y81090D01*
|
||||||
|
Y76011D02*
|
||||||
|
X45000Y70933D01*
|
||||||
|
X60235Y65855D02*
|
||||||
|
Y55698D01*
|
||||||
|
Y60776D01*
|
||||||
|
X45000D01*
|
||||||
|
X62696Y434843D02*
|
||||||
|
X65235Y437383D01*
|
||||||
|
Y442461D01*
|
||||||
|
X62696Y445000D01*
|
||||||
|
X60157D01*
|
||||||
|
X57618Y442461D01*
|
||||||
|
Y437383D01*
|
||||||
|
X55078Y434843D01*
|
||||||
|
X52539D01*
|
||||||
|
X50000Y437383D01*
|
||||||
|
Y442461D01*
|
||||||
|
X52539Y445000D01*
|
||||||
|
X65235Y429765D02*
|
||||||
|
X50000D01*
|
||||||
|
X55078Y424687D01*
|
||||||
|
X50000Y419608D01*
|
||||||
|
X65235D01*
|
||||||
|
X47461Y414530D02*
|
||||||
|
Y404373D01*
|
||||||
|
X50000Y399295D02*
|
||||||
|
X65235D01*
|
||||||
|
X60157Y394216D01*
|
||||||
|
X65235Y389138D01*
|
||||||
|
X50000D01*
|
||||||
|
X65235Y376442D02*
|
||||||
|
Y381521D01*
|
||||||
|
X62696Y384060D01*
|
||||||
|
X52539D01*
|
||||||
|
X50000Y381521D01*
|
||||||
|
Y376442D01*
|
||||||
|
X52539Y373903D01*
|
||||||
|
X62696D01*
|
||||||
|
X65235Y376442D01*
|
||||||
|
Y368825D02*
|
||||||
|
X50000D01*
|
||||||
|
Y361207D01*
|
||||||
|
X52539Y358668D01*
|
||||||
|
X62696D01*
|
||||||
|
X65235Y361207D01*
|
||||||
|
Y368825D01*
|
||||||
|
Y343433D02*
|
||||||
|
Y353590D01*
|
||||||
|
X50000D01*
|
||||||
|
Y343433D01*
|
||||||
|
X57618Y353590D02*
|
||||||
|
Y348511D01*
|
||||||
|
D12*
|
||||||
|
X466000Y20500D02*
|
||||||
|
G03*
|
||||||
|
X444000Y20500I-11000J0D01*
|
||||||
|
G01*
|
||||||
|
X310000Y18000D02*
|
||||||
|
Y72000D01*
|
||||||
|
X283000Y45000D02*
|
||||||
|
X337000D01*
|
||||||
|
X365000Y5000D02*
|
||||||
|
Y85000D01*
|
||||||
|
X255000Y5000D02*
|
||||||
|
X365000D01*
|
||||||
|
X255000D02*
|
||||||
|
Y85000D01*
|
||||||
|
X365000D01*
|
||||||
|
X125490Y408490D02*
|
||||||
|
X158510D01*
|
||||||
|
X125490Y441510D02*
|
||||||
|
X158510D01*
|
||||||
|
Y408490D02*
|
||||||
|
Y441510D01*
|
||||||
|
X125490Y408490D02*
|
||||||
|
Y441510D01*
|
||||||
|
X126760Y364040D02*
|
||||||
|
X192800D01*
|
||||||
|
X161050Y405950D02*
|
||||||
|
Y444050D01*
|
||||||
|
X126760Y364040D02*
|
||||||
|
Y370390D01*
|
||||||
|
X91200Y485960D02*
|
||||||
|
X192800D01*
|
||||||
|
X122950Y405950D02*
|
||||||
|
X161050D01*
|
||||||
|
X122950Y444050D02*
|
||||||
|
X161050D01*
|
||||||
|
X122950Y405950D02*
|
||||||
|
Y444050D01*
|
||||||
|
X106440Y370390D02*
|
||||||
|
X126760D01*
|
||||||
|
X106440Y364040D02*
|
||||||
|
Y370390D01*
|
||||||
|
X91200Y364040D02*
|
||||||
|
X106440D01*
|
||||||
|
X209000Y164000D02*
|
||||||
|
Y176000D01*
|
||||||
|
X161500Y164000D02*
|
||||||
|
Y176000D01*
|
||||||
|
X403000Y20500D02*
|
||||||
|
Y124500D01*
|
||||||
|
Y20500D02*
|
||||||
|
X507000D01*
|
||||||
|
X403000Y124500D02*
|
||||||
|
X507000D01*
|
||||||
|
Y20500D02*
|
||||||
|
Y124500D01*
|
||||||
|
X135000Y201000D02*
|
||||||
|
Y299000D01*
|
||||||
|
X244999Y201000D02*
|
||||||
|
Y299000D01*
|
||||||
|
X91200Y14040D02*
|
||||||
|
X106440D01*
|
||||||
|
Y20390D01*
|
||||||
|
X126760D01*
|
||||||
|
X122950Y55950D02*
|
||||||
|
Y94050D01*
|
||||||
|
X161050D01*
|
||||||
|
X122950Y55950D02*
|
||||||
|
X161050D01*
|
||||||
|
X91200Y135960D02*
|
||||||
|
X192800D01*
|
||||||
|
X126760Y14040D02*
|
||||||
|
Y20390D01*
|
||||||
|
X161050Y55950D02*
|
||||||
|
Y94050D01*
|
||||||
|
X126760Y14040D02*
|
||||||
|
X192800D01*
|
||||||
|
X125490Y58490D02*
|
||||||
|
Y91510D01*
|
||||||
|
X158510Y58490D02*
|
||||||
|
Y91510D01*
|
||||||
|
X125490D02*
|
||||||
|
X158510D01*
|
||||||
|
X125490Y58490D02*
|
||||||
|
X158510D01*
|
||||||
|
X443000Y104000D02*
|
||||||
|
X455000D01*
|
||||||
|
X483500Y133000D02*
|
||||||
|
Y145000D01*
|
||||||
|
X620000Y348000D02*
|
||||||
|
Y360000D01*
|
||||||
|
D13*
|
||||||
|
X130800Y285000D02*
|
||||||
|
G03*
|
||||||
|
X130800Y285000I-800J0D01*
|
||||||
|
G01*
|
||||||
|
X256200Y140000D02*
|
||||||
|
Y444000D01*
|
||||||
|
Y140000D02*
|
||||||
|
X378200D01*
|
||||||
|
X256200Y444000D02*
|
||||||
|
X378200D01*
|
||||||
|
Y140000D02*
|
||||||
|
Y444000D01*
|
||||||
|
X141497Y354635D02*
|
||||||
|
X131500D01*
|
||||||
|
Y349636D01*
|
||||||
|
X133166Y347970D01*
|
||||||
|
X139831D01*
|
||||||
|
X141497Y349636D01*
|
||||||
|
Y354635D01*
|
||||||
|
X136498Y344638D02*
|
||||||
|
Y337974D01*
|
||||||
|
X141497Y327135D02*
|
||||||
|
X131500D01*
|
||||||
|
Y322136D01*
|
||||||
|
X133166Y320470D01*
|
||||||
|
X139831D01*
|
||||||
|
X141497Y322136D01*
|
||||||
|
Y327135D01*
|
||||||
|
X136498Y317138D02*
|
||||||
|
Y310473D01*
|
||||||
|
X139831Y313806D02*
|
||||||
|
X133166D01*
|
||||||
|
D14*
|
||||||
|
X191474Y160348D02*
|
||||||
|
X205190D01*
|
||||||
|
X212810Y160348D02*
|
||||||
|
X226526Y160348D01*
|
||||||
|
X191474D02*
|
||||||
|
Y179652D01*
|
||||||
|
X205190D01*
|
||||||
|
X226526Y160348D02*
|
||||||
|
Y179652D01*
|
||||||
|
X212810Y179652D02*
|
||||||
|
X226526Y179652D01*
|
||||||
|
X165310Y160348D02*
|
||||||
|
X179026Y160348D01*
|
||||||
|
Y179652D01*
|
||||||
|
X165310Y179652D02*
|
||||||
|
X179026Y179652D01*
|
||||||
|
X143974Y160348D02*
|
||||||
|
X157690D01*
|
||||||
|
X143974Y179652D02*
|
||||||
|
X157690D01*
|
||||||
|
X143974Y160348D02*
|
||||||
|
Y179652D01*
|
||||||
|
X545526Y301540D02*
|
||||||
|
Y309160D01*
|
||||||
|
Y288840D02*
|
||||||
|
Y296460D01*
|
||||||
|
X510474Y309160D02*
|
||||||
|
X545526D01*
|
||||||
|
X510474Y301540D02*
|
||||||
|
Y309160D01*
|
||||||
|
Y288840D02*
|
||||||
|
X545526D01*
|
||||||
|
X510474D02*
|
||||||
|
Y296460D01*
|
||||||
|
X532526Y354540D02*
|
||||||
|
Y362160D01*
|
||||||
|
Y341840D02*
|
||||||
|
Y349460D01*
|
||||||
|
X497474Y362160D02*
|
||||||
|
X532526D01*
|
||||||
|
X497474Y354540D02*
|
||||||
|
Y362160D01*
|
||||||
|
Y341840D02*
|
||||||
|
X532526D01*
|
||||||
|
X497474D02*
|
||||||
|
Y349460D01*
|
||||||
|
X459660Y35474D02*
|
||||||
|
Y70526D01*
|
||||||
|
X452040Y35474D02*
|
||||||
|
X459660D01*
|
||||||
|
X452040Y70526D02*
|
||||||
|
X459660D01*
|
||||||
|
X439340Y35474D02*
|
||||||
|
X446960D01*
|
||||||
|
X439340Y70526D02*
|
||||||
|
X446960D01*
|
||||||
|
X439340Y35474D02*
|
||||||
|
Y70526D01*
|
||||||
|
X480160Y35474D02*
|
||||||
|
Y70526D01*
|
||||||
|
X472540Y35474D02*
|
||||||
|
X480160D01*
|
||||||
|
X472540Y70526D02*
|
||||||
|
X480160D01*
|
||||||
|
X459840Y35474D02*
|
||||||
|
X467460D01*
|
||||||
|
X459840Y70526D02*
|
||||||
|
X467460D01*
|
||||||
|
X459840Y35474D02*
|
||||||
|
Y70526D01*
|
||||||
|
X458652Y121526D02*
|
||||||
|
X458652Y107810D01*
|
||||||
|
X439348Y121526D02*
|
||||||
|
X458652D01*
|
||||||
|
X439348Y107810D02*
|
||||||
|
X439348Y121526D01*
|
||||||
|
X458652Y86474D02*
|
||||||
|
Y100190D01*
|
||||||
|
X439348Y86474D02*
|
||||||
|
X458652D01*
|
||||||
|
X439348D02*
|
||||||
|
Y100190D01*
|
||||||
|
X465974Y148652D02*
|
||||||
|
X479690Y148652D01*
|
||||||
|
X465974Y129348D02*
|
||||||
|
Y148652D01*
|
||||||
|
Y129348D02*
|
||||||
|
X479690Y129348D01*
|
||||||
|
X487310Y148652D02*
|
||||||
|
X501026D01*
|
||||||
|
Y129348D02*
|
||||||
|
Y148652D01*
|
||||||
|
X487310Y129348D02*
|
||||||
|
X501026D01*
|
||||||
|
X623810Y344348D02*
|
||||||
|
X637526Y344348D01*
|
||||||
|
Y363652D01*
|
||||||
|
X623810Y363652D02*
|
||||||
|
X637526Y363652D01*
|
||||||
|
X602474Y344348D02*
|
||||||
|
X616190D01*
|
||||||
|
X602474D02*
|
||||||
|
Y363652D01*
|
||||||
|
X616190D01*
|
||||||
|
D15*
|
||||||
|
X485000Y158000D02*
|
||||||
|
Y190000D01*
|
||||||
|
Y158000D02*
|
||||||
|
X694000D01*
|
||||||
|
X485000Y190000D02*
|
||||||
|
X694000D01*
|
||||||
|
X484000Y310000D02*
|
||||||
|
Y342000D01*
|
||||||
|
Y310000D02*
|
||||||
|
X694000D01*
|
||||||
|
X484000Y342000D02*
|
||||||
|
X694000D01*
|
||||||
|
Y158000D02*
|
||||||
|
Y190000D01*
|
||||||
|
Y310000D02*
|
||||||
|
Y342000D01*
|
||||||
|
D16*
|
||||||
|
X572250Y21000D02*
|
||||||
|
Y134000D01*
|
||||||
|
Y21000D02*
|
||||||
|
X696000D01*
|
||||||
|
X572250Y134000D02*
|
||||||
|
X696000D01*
|
||||||
|
Y21000D02*
|
||||||
|
Y134000D01*
|
||||||
|
X572250Y366000D02*
|
||||||
|
Y477000D01*
|
||||||
|
Y366000D02*
|
||||||
|
X696000D01*
|
||||||
|
X572250Y477000D02*
|
||||||
|
X696000D01*
|
||||||
|
Y366000D02*
|
||||||
|
Y477000D01*
|
||||||
|
D17*
|
||||||
|
X477000Y91000D02*
|
||||||
|
X461765D01*
|
||||||
|
Y98617D01*
|
||||||
|
X464304Y101157D01*
|
||||||
|
X469383D01*
|
||||||
|
X471922Y98617D01*
|
||||||
|
Y91000D01*
|
||||||
|
Y96078D02*
|
||||||
|
X477000Y101157D01*
|
||||||
|
Y113853D02*
|
||||||
|
X461765D01*
|
||||||
|
X469383Y106235D01*
|
||||||
|
Y116392D01*
|
||||||
|
X440664Y82331D02*
|
||||||
|
X438998Y83997D01*
|
||||||
|
X435666D01*
|
||||||
|
X434000Y82331D01*
|
||||||
|
Y75666D01*
|
||||||
|
X435666Y74000D01*
|
||||||
|
X438998D01*
|
||||||
|
X440664Y75666D01*
|
||||||
|
X443997Y74000D02*
|
||||||
|
X447329D01*
|
||||||
|
X445663D01*
|
||||||
|
Y83997D01*
|
||||||
|
X443997Y82331D01*
|
||||||
|
X452327D02*
|
||||||
|
X453994Y83997D01*
|
||||||
|
X457326D01*
|
||||||
|
X458992Y82331D01*
|
||||||
|
Y75666D01*
|
||||||
|
X457326Y74000D01*
|
||||||
|
X453994D01*
|
||||||
|
X452327Y75666D01*
|
||||||
|
Y82331D01*
|
||||||
|
M02*
|
||||||
60
PCB/GerberManufacture/OptoTest.GTP
Normal file
60
PCB/GerberManufacture/OptoTest.GTP
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=8421504*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD18R,2.5000X2.2000*%
|
||||||
|
%ADD19R,1.2000X1.4000*%
|
||||||
|
%ADD20R,1.3000X1.5000*%
|
||||||
|
%ADD21R,1.5000X1.3000*%
|
||||||
|
%ADD22R,1.4000X1.2000*%
|
||||||
|
D18*
|
||||||
|
X382500Y45000D02*
|
||||||
|
D03*
|
||||||
|
X237500D02*
|
||||||
|
D03*
|
||||||
|
D19*
|
||||||
|
X200000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X218000D02*
|
||||||
|
D03*
|
||||||
|
X170500D02*
|
||||||
|
D03*
|
||||||
|
X152500D02*
|
||||||
|
D03*
|
||||||
|
X474500Y139000D02*
|
||||||
|
D03*
|
||||||
|
X492500D02*
|
||||||
|
D03*
|
||||||
|
X629000Y354000D02*
|
||||||
|
D03*
|
||||||
|
X611000D02*
|
||||||
|
D03*
|
||||||
|
D20*
|
||||||
|
X536500Y299000D02*
|
||||||
|
D03*
|
||||||
|
X519500D02*
|
||||||
|
D03*
|
||||||
|
X523500Y352000D02*
|
||||||
|
D03*
|
||||||
|
X506500D02*
|
||||||
|
D03*
|
||||||
|
D21*
|
||||||
|
X449500Y44500D02*
|
||||||
|
D03*
|
||||||
|
Y61500D02*
|
||||||
|
D03*
|
||||||
|
X470000Y44500D02*
|
||||||
|
D03*
|
||||||
|
Y61500D02*
|
||||||
|
D03*
|
||||||
|
D22*
|
||||||
|
X449000Y113000D02*
|
||||||
|
D03*
|
||||||
|
Y95000D02*
|
||||||
|
D03*
|
||||||
|
M02*
|
||||||
262
PCB/GerberManufacture/OptoTest.GTS
Normal file
262
PCB/GerberManufacture/OptoTest.GTS
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
G04*
|
||||||
|
G04 #@! TF.GenerationSoftware,Altium Limited,Altium Designer,19.1.9 (167)*
|
||||||
|
G04*
|
||||||
|
G04 Layer_Color=8388736*
|
||||||
|
%FSLAX44Y44*%
|
||||||
|
%MOMM*%
|
||||||
|
G71*
|
||||||
|
G01*
|
||||||
|
G75*
|
||||||
|
%ADD23R,2.6500X2.3500*%
|
||||||
|
%ADD24R,1.3500X1.5500*%
|
||||||
|
%ADD25R,1.4500X1.6500*%
|
||||||
|
%ADD26R,1.6500X1.4500*%
|
||||||
|
%ADD27R,1.5500X1.3500*%
|
||||||
|
%ADD28C,1.6740*%
|
||||||
|
%ADD29C,1.8500*%
|
||||||
|
%ADD30O,2.6000X2.0000*%
|
||||||
|
%ADD31C,1.6500*%
|
||||||
|
%ADD32R,1.6500X1.6500*%
|
||||||
|
%ADD33R,1.6500X1.6500*%
|
||||||
|
%ADD34C,3.1500*%
|
||||||
|
%ADD35C,2.1500*%
|
||||||
|
%ADD36C,1.9500*%
|
||||||
|
%ADD37R,1.9500X1.9500*%
|
||||||
|
%ADD38C,1.7500*%
|
||||||
|
%ADD39R,1.7500X1.7500*%
|
||||||
|
%ADD40R,1.8500X1.8500*%
|
||||||
|
%ADD41R,1.7500X1.7500*%
|
||||||
|
%ADD42C,1.7500*%
|
||||||
|
D23*
|
||||||
|
X382500Y45000D02*
|
||||||
|
D03*
|
||||||
|
X237500D02*
|
||||||
|
D03*
|
||||||
|
D24*
|
||||||
|
X200000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X218000D02*
|
||||||
|
D03*
|
||||||
|
X170500D02*
|
||||||
|
D03*
|
||||||
|
X152500D02*
|
||||||
|
D03*
|
||||||
|
X474500Y139000D02*
|
||||||
|
D03*
|
||||||
|
X492500D02*
|
||||||
|
D03*
|
||||||
|
X629000Y354000D02*
|
||||||
|
D03*
|
||||||
|
X611000D02*
|
||||||
|
D03*
|
||||||
|
D25*
|
||||||
|
X536500Y299000D02*
|
||||||
|
D03*
|
||||||
|
X519500D02*
|
||||||
|
D03*
|
||||||
|
X523500Y352000D02*
|
||||||
|
D03*
|
||||||
|
X506500D02*
|
||||||
|
D03*
|
||||||
|
D26*
|
||||||
|
X449500Y44500D02*
|
||||||
|
D03*
|
||||||
|
Y61500D02*
|
||||||
|
D03*
|
||||||
|
X470000Y44500D02*
|
||||||
|
D03*
|
||||||
|
Y61500D02*
|
||||||
|
D03*
|
||||||
|
D27*
|
||||||
|
X449000Y113000D02*
|
||||||
|
D03*
|
||||||
|
Y95000D02*
|
||||||
|
D03*
|
||||||
|
D28*
|
||||||
|
X650000Y250000D02*
|
||||||
|
D03*
|
||||||
|
X25000Y475000D02*
|
||||||
|
D03*
|
||||||
|
Y25000D02*
|
||||||
|
D03*
|
||||||
|
D29*
|
||||||
|
X120000Y347500D02*
|
||||||
|
D03*
|
||||||
|
Y320000D02*
|
||||||
|
D03*
|
||||||
|
X355400Y430000D02*
|
||||||
|
D03*
|
||||||
|
X330000D02*
|
||||||
|
D03*
|
||||||
|
X304600D02*
|
||||||
|
D03*
|
||||||
|
X587000Y299000D02*
|
||||||
|
D03*
|
||||||
|
X235000Y80000D02*
|
||||||
|
D03*
|
||||||
|
X245000Y170000D02*
|
||||||
|
D03*
|
||||||
|
X574999Y198000D02*
|
||||||
|
D03*
|
||||||
|
X528000Y387000D02*
|
||||||
|
D03*
|
||||||
|
X500000Y285000D02*
|
||||||
|
D03*
|
||||||
|
X543999Y231999D02*
|
||||||
|
D03*
|
||||||
|
X451000Y274000D02*
|
||||||
|
D03*
|
||||||
|
X520000Y224000D02*
|
||||||
|
D03*
|
||||||
|
D30*
|
||||||
|
X80000Y450000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y400000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y100000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
X80000Y50000D02*
|
||||||
|
D03*
|
||||||
|
X204000D02*
|
||||||
|
D03*
|
||||||
|
D31*
|
||||||
|
X80000Y300800D02*
|
||||||
|
D03*
|
||||||
|
Y275400D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y224600D02*
|
||||||
|
D03*
|
||||||
|
X254600Y119000D02*
|
||||||
|
D03*
|
||||||
|
X356200D02*
|
||||||
|
D03*
|
||||||
|
X330800D02*
|
||||||
|
D03*
|
||||||
|
X305400D02*
|
||||||
|
D03*
|
||||||
|
X280000D02*
|
||||||
|
D03*
|
||||||
|
D32*
|
||||||
|
X80000Y199200D02*
|
||||||
|
D03*
|
||||||
|
D33*
|
||||||
|
X381600Y119000D02*
|
||||||
|
D03*
|
||||||
|
D34*
|
||||||
|
X190000Y203000D02*
|
||||||
|
D03*
|
||||||
|
Y297000D02*
|
||||||
|
D03*
|
||||||
|
D35*
|
||||||
|
X120000Y225000D02*
|
||||||
|
D03*
|
||||||
|
Y250000D02*
|
||||||
|
D03*
|
||||||
|
Y275000D02*
|
||||||
|
D03*
|
||||||
|
D36*
|
||||||
|
X677000Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y460000D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y434600D02*
|
||||||
|
D03*
|
||||||
|
Y409200D02*
|
||||||
|
D03*
|
||||||
|
X677000Y40000D02*
|
||||||
|
D03*
|
||||||
|
Y116200D02*
|
||||||
|
D03*
|
||||||
|
X600800D02*
|
||||||
|
D03*
|
||||||
|
Y90800D02*
|
||||||
|
D03*
|
||||||
|
Y65400D02*
|
||||||
|
D03*
|
||||||
|
X678900Y326200D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
X678900Y173800D02*
|
||||||
|
D03*
|
||||||
|
X653500D02*
|
||||||
|
D03*
|
||||||
|
X628100D02*
|
||||||
|
D03*
|
||||||
|
X602700D02*
|
||||||
|
D03*
|
||||||
|
X577300D02*
|
||||||
|
D03*
|
||||||
|
X551900D02*
|
||||||
|
D03*
|
||||||
|
X526500D02*
|
||||||
|
D03*
|
||||||
|
X501100D02*
|
||||||
|
D03*
|
||||||
|
D37*
|
||||||
|
X600800Y383800D02*
|
||||||
|
D03*
|
||||||
|
Y40000D02*
|
||||||
|
D03*
|
||||||
|
D38*
|
||||||
|
X416900Y34400D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y110600D02*
|
||||||
|
D03*
|
||||||
|
X493100D02*
|
||||||
|
D03*
|
||||||
|
Y85200D02*
|
||||||
|
D03*
|
||||||
|
Y59800D02*
|
||||||
|
D03*
|
||||||
|
D39*
|
||||||
|
Y34400D02*
|
||||||
|
D03*
|
||||||
|
D40*
|
||||||
|
X279200Y430000D02*
|
||||||
|
D03*
|
||||||
|
D41*
|
||||||
|
X424300Y464684D02*
|
||||||
|
D03*
|
||||||
|
D42*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y388500D02*
|
||||||
|
D03*
|
||||||
|
X500500D02*
|
||||||
|
D03*
|
||||||
|
Y413900D02*
|
||||||
|
D03*
|
||||||
|
Y439300D02*
|
||||||
|
D03*
|
||||||
|
Y464700D02*
|
||||||
|
D03*
|
||||||
|
M02*
|
||||||
108
PCB/GerberManufacture/OptoTest.TXT
Normal file
108
PCB/GerberManufacture/OptoTest.TXT
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
M48
|
||||||
|
;Layer_Color=9474304
|
||||||
|
;FILE_FORMAT=4:4
|
||||||
|
METRIC,LZ
|
||||||
|
;TYPE=PLATED
|
||||||
|
T1F00S00C0.8000
|
||||||
|
T2F00S00C0.9000
|
||||||
|
T3F00S00C1.0000
|
||||||
|
T4F00S00C1.1000
|
||||||
|
T5F00S00C1.2000
|
||||||
|
T6F00S00C2.2000
|
||||||
|
;TYPE=NON_PLATED
|
||||||
|
T7F00S00C3.1000
|
||||||
|
%
|
||||||
|
T01
|
||||||
|
X004169Y000344
|
||||||
|
Y000598
|
||||||
|
X004931
|
||||||
|
Y000344
|
||||||
|
Y000852
|
||||||
|
Y001106
|
||||||
|
X004169
|
||||||
|
Y000852
|
||||||
|
T02
|
||||||
|
X00574999Y00198
|
||||||
|
X00587Y00299
|
||||||
|
X005Y00285
|
||||||
|
X00451Y00274
|
||||||
|
X0052Y00224
|
||||||
|
X00543999Y00231999
|
||||||
|
X00528Y00387
|
||||||
|
X003816Y00119
|
||||||
|
X003562
|
||||||
|
X003308
|
||||||
|
X003054
|
||||||
|
X0028
|
||||||
|
X002546
|
||||||
|
X00235Y0008
|
||||||
|
X00245Y0017
|
||||||
|
X0008Y001992
|
||||||
|
Y002246
|
||||||
|
Y0025
|
||||||
|
Y002754
|
||||||
|
Y003008
|
||||||
|
X0012Y0032
|
||||||
|
Y003475
|
||||||
|
T03
|
||||||
|
X005773Y001738
|
||||||
|
X006027
|
||||||
|
X006281
|
||||||
|
X006535
|
||||||
|
X006789
|
||||||
|
Y003262
|
||||||
|
X006535
|
||||||
|
X006281
|
||||||
|
X006027
|
||||||
|
X005773
|
||||||
|
X005519
|
||||||
|
X005265
|
||||||
|
X005011
|
||||||
|
X005005Y003885
|
||||||
|
Y004139
|
||||||
|
Y004393
|
||||||
|
X004243
|
||||||
|
Y004139
|
||||||
|
Y003885
|
||||||
|
X003554Y0043
|
||||||
|
X0033
|
||||||
|
X003046
|
||||||
|
X002792
|
||||||
|
X005011Y001738
|
||||||
|
X005265
|
||||||
|
X005519
|
||||||
|
X0012Y00225
|
||||||
|
Y0025
|
||||||
|
Y00275
|
||||||
|
X004243Y00464684
|
||||||
|
X005005Y004647
|
||||||
|
T04
|
||||||
|
X006008Y0004
|
||||||
|
X00677
|
||||||
|
Y001162
|
||||||
|
X006008
|
||||||
|
Y000908
|
||||||
|
Y000654
|
||||||
|
Y003838
|
||||||
|
Y004092
|
||||||
|
Y004346
|
||||||
|
X00677Y003838
|
||||||
|
Y0046
|
||||||
|
X006008
|
||||||
|
T05
|
||||||
|
X0008Y0005
|
||||||
|
X00204
|
||||||
|
Y001
|
||||||
|
Y004
|
||||||
|
Y0045
|
||||||
|
X0008
|
||||||
|
Y004
|
||||||
|
Y001
|
||||||
|
T06
|
||||||
|
X0019Y00203
|
||||||
|
Y00297
|
||||||
|
T07
|
||||||
|
X00025Y00025
|
||||||
|
X0065Y0025
|
||||||
|
X00025Y00475
|
||||||
|
M30
|
||||||
BIN
PCB/GerberManufacture/OptoTest.rar
Normal file
BIN
PCB/GerberManufacture/OptoTest.rar
Normal file
Binary file not shown.
BIN
PCB/Libs/1208YD.PcbLib
Normal file
BIN
PCB/Libs/1208YD.PcbLib
Normal file
Binary file not shown.
BIN
PCB/Libs/1208YD.SchLib
Normal file
BIN
PCB/Libs/1208YD.SchLib
Normal file
Binary file not shown.
BIN
PCB/Libs/BPW34.PcbLib
Normal file
BIN
PCB/Libs/BPW34.PcbLib
Normal file
Binary file not shown.
2544
PCB/Libs/BPW34_VERTICAL_P5.08mm.step
Normal file
2544
PCB/Libs/BPW34_VERTICAL_P5.08mm.step
Normal file
@@ -0,0 +1,2544 @@
|
|||||||
|
ISO-10303-21;
|
||||||
|
HEADER;
|
||||||
|
FILE_DESCRIPTION(('Open CASCADE Model'),'2;1');
|
||||||
|
FILE_NAME('Open CASCADE Shape Model','2026-08-09T10:52:04',('Author'),(
|
||||||
|
'Open CASCADE'),'Open CASCADE STEP processor 7.9','Open CASCADE 7.9'
|
||||||
|
,'Unknown');
|
||||||
|
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
|
||||||
|
ENDSEC;
|
||||||
|
DATA;
|
||||||
|
#1 = APPLICATION_PROTOCOL_DEFINITION('international standard',
|
||||||
|
'automotive_design',2000,#2);
|
||||||
|
#2 = APPLICATION_CONTEXT(
|
||||||
|
'core data for automotive mechanical design processes');
|
||||||
|
#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10);
|
||||||
|
#4 = PRODUCT_DEFINITION_SHAPE('','',#5);
|
||||||
|
#5 = PRODUCT_DEFINITION('design','',#6,#9);
|
||||||
|
#6 = PRODUCT_DEFINITION_FORMATION('','',#7);
|
||||||
|
#7 = PRODUCT('BPW34_VERTICAL_P5.08mm','BPW34_VERTICAL_P5.08mm','',(#8));
|
||||||
|
#8 = PRODUCT_CONTEXT('',#2,'mechanical');
|
||||||
|
#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
|
||||||
|
#10 = SHAPE_REPRESENTATION('',(#11,#15,#19,#23,#27,#31),#35);
|
||||||
|
#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14);
|
||||||
|
#12 = CARTESIAN_POINT('',(0.,0.,0.));
|
||||||
|
#13 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#14 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#15 = AXIS2_PLACEMENT_3D('',#16,#17,#18);
|
||||||
|
#16 = CARTESIAN_POINT('',(0.,0.,0.));
|
||||||
|
#17 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#18 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#19 = AXIS2_PLACEMENT_3D('',#20,#21,#22);
|
||||||
|
#20 = CARTESIAN_POINT('',(0.,0.,0.));
|
||||||
|
#21 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#22 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#23 = AXIS2_PLACEMENT_3D('',#24,#25,#26);
|
||||||
|
#24 = CARTESIAN_POINT('',(0.,0.,0.));
|
||||||
|
#25 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#26 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#27 = AXIS2_PLACEMENT_3D('',#28,#29,#30);
|
||||||
|
#28 = CARTESIAN_POINT('',(0.,0.,0.));
|
||||||
|
#29 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#30 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#31 = AXIS2_PLACEMENT_3D('',#32,#33,#34);
|
||||||
|
#32 = CARTESIAN_POINT('',(0.,0.,0.));
|
||||||
|
#33 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#34 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#35 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#39)) GLOBAL_UNIT_ASSIGNED_CONTEXT(
|
||||||
|
(#36,#37,#38)) REPRESENTATION_CONTEXT('Context #1',
|
||||||
|
'3D Context with UNIT and UNCERTAINTY') );
|
||||||
|
#36 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
|
||||||
|
#37 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
|
||||||
|
#38 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
|
||||||
|
#39 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#36,
|
||||||
|
'distance_accuracy_value','confusion accuracy');
|
||||||
|
#40 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#7));
|
||||||
|
#41 = SHAPE_DEFINITION_REPRESENTATION(#42,#48);
|
||||||
|
#42 = PRODUCT_DEFINITION_SHAPE('','',#43);
|
||||||
|
#43 = PRODUCT_DEFINITION('design','',#44,#47);
|
||||||
|
#44 = PRODUCT_DEFINITION_FORMATION('','',#45);
|
||||||
|
#45 = PRODUCT('364e6857-93c7-11f1-9269-04bad62a3558',
|
||||||
|
'364e6857-93c7-11f1-9269-04bad62a3558','',(#46));
|
||||||
|
#46 = PRODUCT_CONTEXT('',#2,'mechanical');
|
||||||
|
#47 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
|
||||||
|
#48 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#49),#379);
|
||||||
|
#49 = MANIFOLD_SOLID_BREP('',#50);
|
||||||
|
#50 = CLOSED_SHELL('',(#51,#171,#271,#318,#365,#372));
|
||||||
|
#51 = ADVANCED_FACE('',(#52),#66,.F.);
|
||||||
|
#52 = FACE_BOUND('',#53,.F.);
|
||||||
|
#53 = EDGE_LOOP('',(#54,#89,#117,#145));
|
||||||
|
#54 = ORIENTED_EDGE('',*,*,#55,.F.);
|
||||||
|
#55 = EDGE_CURVE('',#56,#58,#60,.T.);
|
||||||
|
#56 = VERTEX_POINT('',#57);
|
||||||
|
#57 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#58 = VERTEX_POINT('',#59);
|
||||||
|
#59 = CARTESIAN_POINT('',(-2.79,-0.19,2.7));
|
||||||
|
#60 = SURFACE_CURVE('',#61,(#65,#77),.PCURVE_S1.);
|
||||||
|
#61 = LINE('',#62,#63);
|
||||||
|
#62 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#63 = VECTOR('',#64,1.);
|
||||||
|
#64 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#65 = PCURVE('',#66,#71);
|
||||||
|
#66 = PLANE('',#67);
|
||||||
|
#67 = AXIS2_PLACEMENT_3D('',#68,#69,#70);
|
||||||
|
#68 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#69 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#70 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#71 = DEFINITIONAL_REPRESENTATION('',(#72),#76);
|
||||||
|
#72 = LINE('',#73,#74);
|
||||||
|
#73 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#74 = VECTOR('',#75,1.);
|
||||||
|
#75 = DIRECTION('',(1.,0.));
|
||||||
|
#76 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#77 = PCURVE('',#78,#83);
|
||||||
|
#78 = PLANE('',#79);
|
||||||
|
#79 = AXIS2_PLACEMENT_3D('',#80,#81,#82);
|
||||||
|
#80 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#81 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#82 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#83 = DEFINITIONAL_REPRESENTATION('',(#84),#88);
|
||||||
|
#84 = LINE('',#85,#86);
|
||||||
|
#85 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#86 = VECTOR('',#87,1.);
|
||||||
|
#87 = DIRECTION('',(1.,0.));
|
||||||
|
#88 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#89 = ORIENTED_EDGE('',*,*,#90,.T.);
|
||||||
|
#90 = EDGE_CURVE('',#56,#91,#93,.T.);
|
||||||
|
#91 = VERTEX_POINT('',#92);
|
||||||
|
#92 = CARTESIAN_POINT('',(-2.79,0.19,-2.6));
|
||||||
|
#93 = SURFACE_CURVE('',#94,(#98,#105),.PCURVE_S1.);
|
||||||
|
#94 = LINE('',#95,#96);
|
||||||
|
#95 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#96 = VECTOR('',#97,1.);
|
||||||
|
#97 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#98 = PCURVE('',#66,#99);
|
||||||
|
#99 = DEFINITIONAL_REPRESENTATION('',(#100),#104);
|
||||||
|
#100 = LINE('',#101,#102);
|
||||||
|
#101 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#102 = VECTOR('',#103,1.);
|
||||||
|
#103 = DIRECTION('',(0.,-1.));
|
||||||
|
#104 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#105 = PCURVE('',#106,#111);
|
||||||
|
#106 = PLANE('',#107);
|
||||||
|
#107 = AXIS2_PLACEMENT_3D('',#108,#109,#110);
|
||||||
|
#108 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#109 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#110 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#111 = DEFINITIONAL_REPRESENTATION('',(#112),#116);
|
||||||
|
#112 = LINE('',#113,#114);
|
||||||
|
#113 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#114 = VECTOR('',#115,1.);
|
||||||
|
#115 = DIRECTION('',(0.,1.));
|
||||||
|
#116 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#117 = ORIENTED_EDGE('',*,*,#118,.T.);
|
||||||
|
#118 = EDGE_CURVE('',#91,#119,#121,.T.);
|
||||||
|
#119 = VERTEX_POINT('',#120);
|
||||||
|
#120 = CARTESIAN_POINT('',(-2.79,0.19,2.7));
|
||||||
|
#121 = SURFACE_CURVE('',#122,(#126,#133),.PCURVE_S1.);
|
||||||
|
#122 = LINE('',#123,#124);
|
||||||
|
#123 = CARTESIAN_POINT('',(-2.79,0.19,-2.6));
|
||||||
|
#124 = VECTOR('',#125,1.);
|
||||||
|
#125 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#126 = PCURVE('',#66,#127);
|
||||||
|
#127 = DEFINITIONAL_REPRESENTATION('',(#128),#132);
|
||||||
|
#128 = LINE('',#129,#130);
|
||||||
|
#129 = CARTESIAN_POINT('',(0.,-0.38));
|
||||||
|
#130 = VECTOR('',#131,1.);
|
||||||
|
#131 = DIRECTION('',(1.,0.));
|
||||||
|
#132 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#133 = PCURVE('',#134,#139);
|
||||||
|
#134 = PLANE('',#135);
|
||||||
|
#135 = AXIS2_PLACEMENT_3D('',#136,#137,#138);
|
||||||
|
#136 = CARTESIAN_POINT('',(-2.79,0.19,-2.6));
|
||||||
|
#137 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#138 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#139 = DEFINITIONAL_REPRESENTATION('',(#140),#144);
|
||||||
|
#140 = LINE('',#141,#142);
|
||||||
|
#141 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#142 = VECTOR('',#143,1.);
|
||||||
|
#143 = DIRECTION('',(1.,0.));
|
||||||
|
#144 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#145 = ORIENTED_EDGE('',*,*,#146,.F.);
|
||||||
|
#146 = EDGE_CURVE('',#58,#119,#147,.T.);
|
||||||
|
#147 = SURFACE_CURVE('',#148,(#152,#159),.PCURVE_S1.);
|
||||||
|
#148 = LINE('',#149,#150);
|
||||||
|
#149 = CARTESIAN_POINT('',(-2.79,-0.19,2.7));
|
||||||
|
#150 = VECTOR('',#151,1.);
|
||||||
|
#151 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#152 = PCURVE('',#66,#153);
|
||||||
|
#153 = DEFINITIONAL_REPRESENTATION('',(#154),#158);
|
||||||
|
#154 = LINE('',#155,#156);
|
||||||
|
#155 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#156 = VECTOR('',#157,1.);
|
||||||
|
#157 = DIRECTION('',(0.,-1.));
|
||||||
|
#158 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#159 = PCURVE('',#160,#165);
|
||||||
|
#160 = PLANE('',#161);
|
||||||
|
#161 = AXIS2_PLACEMENT_3D('',#162,#163,#164);
|
||||||
|
#162 = CARTESIAN_POINT('',(-2.79,-0.19,2.7));
|
||||||
|
#163 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#164 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#165 = DEFINITIONAL_REPRESENTATION('',(#166),#170);
|
||||||
|
#166 = LINE('',#167,#168);
|
||||||
|
#167 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#168 = VECTOR('',#169,1.);
|
||||||
|
#169 = DIRECTION('',(0.,1.));
|
||||||
|
#170 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#171 = ADVANCED_FACE('',(#172),#186,.T.);
|
||||||
|
#172 = FACE_BOUND('',#173,.T.);
|
||||||
|
#173 = EDGE_LOOP('',(#174,#204,#227,#250));
|
||||||
|
#174 = ORIENTED_EDGE('',*,*,#175,.F.);
|
||||||
|
#175 = EDGE_CURVE('',#176,#178,#180,.T.);
|
||||||
|
#176 = VERTEX_POINT('',#177);
|
||||||
|
#177 = CARTESIAN_POINT('',(-2.29,-0.19,-2.6));
|
||||||
|
#178 = VERTEX_POINT('',#179);
|
||||||
|
#179 = CARTESIAN_POINT('',(-2.29,-0.19,2.7));
|
||||||
|
#180 = SURFACE_CURVE('',#181,(#185,#197),.PCURVE_S1.);
|
||||||
|
#181 = LINE('',#182,#183);
|
||||||
|
#182 = CARTESIAN_POINT('',(-2.29,-0.19,-2.6));
|
||||||
|
#183 = VECTOR('',#184,1.);
|
||||||
|
#184 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#185 = PCURVE('',#186,#191);
|
||||||
|
#186 = PLANE('',#187);
|
||||||
|
#187 = AXIS2_PLACEMENT_3D('',#188,#189,#190);
|
||||||
|
#188 = CARTESIAN_POINT('',(-2.29,-0.19,-2.6));
|
||||||
|
#189 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#190 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#191 = DEFINITIONAL_REPRESENTATION('',(#192),#196);
|
||||||
|
#192 = LINE('',#193,#194);
|
||||||
|
#193 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#194 = VECTOR('',#195,1.);
|
||||||
|
#195 = DIRECTION('',(1.,0.));
|
||||||
|
#196 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#197 = PCURVE('',#78,#198);
|
||||||
|
#198 = DEFINITIONAL_REPRESENTATION('',(#199),#203);
|
||||||
|
#199 = LINE('',#200,#201);
|
||||||
|
#200 = CARTESIAN_POINT('',(0.,0.5));
|
||||||
|
#201 = VECTOR('',#202,1.);
|
||||||
|
#202 = DIRECTION('',(1.,0.));
|
||||||
|
#203 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#204 = ORIENTED_EDGE('',*,*,#205,.T.);
|
||||||
|
#205 = EDGE_CURVE('',#176,#206,#208,.T.);
|
||||||
|
#206 = VERTEX_POINT('',#207);
|
||||||
|
#207 = CARTESIAN_POINT('',(-2.29,0.19,-2.6));
|
||||||
|
#208 = SURFACE_CURVE('',#209,(#213,#220),.PCURVE_S1.);
|
||||||
|
#209 = LINE('',#210,#211);
|
||||||
|
#210 = CARTESIAN_POINT('',(-2.29,-0.19,-2.6));
|
||||||
|
#211 = VECTOR('',#212,1.);
|
||||||
|
#212 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#213 = PCURVE('',#186,#214);
|
||||||
|
#214 = DEFINITIONAL_REPRESENTATION('',(#215),#219);
|
||||||
|
#215 = LINE('',#216,#217);
|
||||||
|
#216 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#217 = VECTOR('',#218,1.);
|
||||||
|
#218 = DIRECTION('',(0.,-1.));
|
||||||
|
#219 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#220 = PCURVE('',#106,#221);
|
||||||
|
#221 = DEFINITIONAL_REPRESENTATION('',(#222),#226);
|
||||||
|
#222 = LINE('',#223,#224);
|
||||||
|
#223 = CARTESIAN_POINT('',(0.5,0.));
|
||||||
|
#224 = VECTOR('',#225,1.);
|
||||||
|
#225 = DIRECTION('',(0.,1.));
|
||||||
|
#226 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#227 = ORIENTED_EDGE('',*,*,#228,.T.);
|
||||||
|
#228 = EDGE_CURVE('',#206,#229,#231,.T.);
|
||||||
|
#229 = VERTEX_POINT('',#230);
|
||||||
|
#230 = CARTESIAN_POINT('',(-2.29,0.19,2.7));
|
||||||
|
#231 = SURFACE_CURVE('',#232,(#236,#243),.PCURVE_S1.);
|
||||||
|
#232 = LINE('',#233,#234);
|
||||||
|
#233 = CARTESIAN_POINT('',(-2.29,0.19,-2.6));
|
||||||
|
#234 = VECTOR('',#235,1.);
|
||||||
|
#235 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#236 = PCURVE('',#186,#237);
|
||||||
|
#237 = DEFINITIONAL_REPRESENTATION('',(#238),#242);
|
||||||
|
#238 = LINE('',#239,#240);
|
||||||
|
#239 = CARTESIAN_POINT('',(0.,-0.38));
|
||||||
|
#240 = VECTOR('',#241,1.);
|
||||||
|
#241 = DIRECTION('',(1.,0.));
|
||||||
|
#242 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#243 = PCURVE('',#134,#244);
|
||||||
|
#244 = DEFINITIONAL_REPRESENTATION('',(#245),#249);
|
||||||
|
#245 = LINE('',#246,#247);
|
||||||
|
#246 = CARTESIAN_POINT('',(0.,0.5));
|
||||||
|
#247 = VECTOR('',#248,1.);
|
||||||
|
#248 = DIRECTION('',(1.,0.));
|
||||||
|
#249 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#250 = ORIENTED_EDGE('',*,*,#251,.F.);
|
||||||
|
#251 = EDGE_CURVE('',#178,#229,#252,.T.);
|
||||||
|
#252 = SURFACE_CURVE('',#253,(#257,#264),.PCURVE_S1.);
|
||||||
|
#253 = LINE('',#254,#255);
|
||||||
|
#254 = CARTESIAN_POINT('',(-2.29,-0.19,2.7));
|
||||||
|
#255 = VECTOR('',#256,1.);
|
||||||
|
#256 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#257 = PCURVE('',#186,#258);
|
||||||
|
#258 = DEFINITIONAL_REPRESENTATION('',(#259),#263);
|
||||||
|
#259 = LINE('',#260,#261);
|
||||||
|
#260 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#261 = VECTOR('',#262,1.);
|
||||||
|
#262 = DIRECTION('',(0.,-1.));
|
||||||
|
#263 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#264 = PCURVE('',#160,#265);
|
||||||
|
#265 = DEFINITIONAL_REPRESENTATION('',(#266),#270);
|
||||||
|
#266 = LINE('',#267,#268);
|
||||||
|
#267 = CARTESIAN_POINT('',(0.5,0.));
|
||||||
|
#268 = VECTOR('',#269,1.);
|
||||||
|
#269 = DIRECTION('',(0.,1.));
|
||||||
|
#270 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#271 = ADVANCED_FACE('',(#272),#78,.F.);
|
||||||
|
#272 = FACE_BOUND('',#273,.F.);
|
||||||
|
#273 = EDGE_LOOP('',(#274,#295,#296,#317));
|
||||||
|
#274 = ORIENTED_EDGE('',*,*,#275,.F.);
|
||||||
|
#275 = EDGE_CURVE('',#56,#176,#276,.T.);
|
||||||
|
#276 = SURFACE_CURVE('',#277,(#281,#288),.PCURVE_S1.);
|
||||||
|
#277 = LINE('',#278,#279);
|
||||||
|
#278 = CARTESIAN_POINT('',(-2.79,-0.19,-2.6));
|
||||||
|
#279 = VECTOR('',#280,1.);
|
||||||
|
#280 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#281 = PCURVE('',#78,#282);
|
||||||
|
#282 = DEFINITIONAL_REPRESENTATION('',(#283),#287);
|
||||||
|
#283 = LINE('',#284,#285);
|
||||||
|
#284 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#285 = VECTOR('',#286,1.);
|
||||||
|
#286 = DIRECTION('',(0.,1.));
|
||||||
|
#287 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#288 = PCURVE('',#106,#289);
|
||||||
|
#289 = DEFINITIONAL_REPRESENTATION('',(#290),#294);
|
||||||
|
#290 = LINE('',#291,#292);
|
||||||
|
#291 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#292 = VECTOR('',#293,1.);
|
||||||
|
#293 = DIRECTION('',(1.,0.));
|
||||||
|
#294 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#295 = ORIENTED_EDGE('',*,*,#55,.T.);
|
||||||
|
#296 = ORIENTED_EDGE('',*,*,#297,.T.);
|
||||||
|
#297 = EDGE_CURVE('',#58,#178,#298,.T.);
|
||||||
|
#298 = SURFACE_CURVE('',#299,(#303,#310),.PCURVE_S1.);
|
||||||
|
#299 = LINE('',#300,#301);
|
||||||
|
#300 = CARTESIAN_POINT('',(-2.79,-0.19,2.7));
|
||||||
|
#301 = VECTOR('',#302,1.);
|
||||||
|
#302 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#303 = PCURVE('',#78,#304);
|
||||||
|
#304 = DEFINITIONAL_REPRESENTATION('',(#305),#309);
|
||||||
|
#305 = LINE('',#306,#307);
|
||||||
|
#306 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#307 = VECTOR('',#308,1.);
|
||||||
|
#308 = DIRECTION('',(0.,1.));
|
||||||
|
#309 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#310 = PCURVE('',#160,#311);
|
||||||
|
#311 = DEFINITIONAL_REPRESENTATION('',(#312),#316);
|
||||||
|
#312 = LINE('',#313,#314);
|
||||||
|
#313 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#314 = VECTOR('',#315,1.);
|
||||||
|
#315 = DIRECTION('',(1.,0.));
|
||||||
|
#316 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#317 = ORIENTED_EDGE('',*,*,#175,.F.);
|
||||||
|
#318 = ADVANCED_FACE('',(#319),#134,.T.);
|
||||||
|
#319 = FACE_BOUND('',#320,.T.);
|
||||||
|
#320 = EDGE_LOOP('',(#321,#342,#343,#364));
|
||||||
|
#321 = ORIENTED_EDGE('',*,*,#322,.F.);
|
||||||
|
#322 = EDGE_CURVE('',#91,#206,#323,.T.);
|
||||||
|
#323 = SURFACE_CURVE('',#324,(#328,#335),.PCURVE_S1.);
|
||||||
|
#324 = LINE('',#325,#326);
|
||||||
|
#325 = CARTESIAN_POINT('',(-2.79,0.19,-2.6));
|
||||||
|
#326 = VECTOR('',#327,1.);
|
||||||
|
#327 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#328 = PCURVE('',#134,#329);
|
||||||
|
#329 = DEFINITIONAL_REPRESENTATION('',(#330),#334);
|
||||||
|
#330 = LINE('',#331,#332);
|
||||||
|
#331 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#332 = VECTOR('',#333,1.);
|
||||||
|
#333 = DIRECTION('',(0.,1.));
|
||||||
|
#334 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#335 = PCURVE('',#106,#336);
|
||||||
|
#336 = DEFINITIONAL_REPRESENTATION('',(#337),#341);
|
||||||
|
#337 = LINE('',#338,#339);
|
||||||
|
#338 = CARTESIAN_POINT('',(0.,0.38));
|
||||||
|
#339 = VECTOR('',#340,1.);
|
||||||
|
#340 = DIRECTION('',(1.,0.));
|
||||||
|
#341 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#342 = ORIENTED_EDGE('',*,*,#118,.T.);
|
||||||
|
#343 = ORIENTED_EDGE('',*,*,#344,.T.);
|
||||||
|
#344 = EDGE_CURVE('',#119,#229,#345,.T.);
|
||||||
|
#345 = SURFACE_CURVE('',#346,(#350,#357),.PCURVE_S1.);
|
||||||
|
#346 = LINE('',#347,#348);
|
||||||
|
#347 = CARTESIAN_POINT('',(-2.79,0.19,2.7));
|
||||||
|
#348 = VECTOR('',#349,1.);
|
||||||
|
#349 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#350 = PCURVE('',#134,#351);
|
||||||
|
#351 = DEFINITIONAL_REPRESENTATION('',(#352),#356);
|
||||||
|
#352 = LINE('',#353,#354);
|
||||||
|
#353 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#354 = VECTOR('',#355,1.);
|
||||||
|
#355 = DIRECTION('',(0.,1.));
|
||||||
|
#356 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#357 = PCURVE('',#160,#358);
|
||||||
|
#358 = DEFINITIONAL_REPRESENTATION('',(#359),#363);
|
||||||
|
#359 = LINE('',#360,#361);
|
||||||
|
#360 = CARTESIAN_POINT('',(0.,0.38));
|
||||||
|
#361 = VECTOR('',#362,1.);
|
||||||
|
#362 = DIRECTION('',(1.,0.));
|
||||||
|
#363 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#364 = ORIENTED_EDGE('',*,*,#228,.F.);
|
||||||
|
#365 = ADVANCED_FACE('',(#366),#106,.F.);
|
||||||
|
#366 = FACE_BOUND('',#367,.F.);
|
||||||
|
#367 = EDGE_LOOP('',(#368,#369,#370,#371));
|
||||||
|
#368 = ORIENTED_EDGE('',*,*,#90,.F.);
|
||||||
|
#369 = ORIENTED_EDGE('',*,*,#275,.T.);
|
||||||
|
#370 = ORIENTED_EDGE('',*,*,#205,.T.);
|
||||||
|
#371 = ORIENTED_EDGE('',*,*,#322,.F.);
|
||||||
|
#372 = ADVANCED_FACE('',(#373),#160,.T.);
|
||||||
|
#373 = FACE_BOUND('',#374,.T.);
|
||||||
|
#374 = EDGE_LOOP('',(#375,#376,#377,#378));
|
||||||
|
#375 = ORIENTED_EDGE('',*,*,#146,.F.);
|
||||||
|
#376 = ORIENTED_EDGE('',*,*,#297,.T.);
|
||||||
|
#377 = ORIENTED_EDGE('',*,*,#251,.T.);
|
||||||
|
#378 = ORIENTED_EDGE('',*,*,#344,.F.);
|
||||||
|
#379 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#383)) GLOBAL_UNIT_ASSIGNED_CONTEXT
|
||||||
|
((#380,#381,#382)) REPRESENTATION_CONTEXT('Context #1',
|
||||||
|
'3D Context with UNIT and UNCERTAINTY') );
|
||||||
|
#380 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
|
||||||
|
#381 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
|
||||||
|
#382 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
|
||||||
|
#383 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#380,
|
||||||
|
'distance_accuracy_value','confusion accuracy');
|
||||||
|
#384 = CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#385,#387);
|
||||||
|
#385 = ( REPRESENTATION_RELATIONSHIP('','',#48,#10)
|
||||||
|
REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#386)
|
||||||
|
SHAPE_REPRESENTATION_RELATIONSHIP() );
|
||||||
|
#386 = ITEM_DEFINED_TRANSFORMATION('','',#11,#15);
|
||||||
|
#387 = PRODUCT_DEFINITION_SHAPE('Placement','Placement of an item',#388
|
||||||
|
);
|
||||||
|
#388 = NEXT_ASSEMBLY_USAGE_OCCURRENCE('56',
|
||||||
|
'364e6857-93c7-11f1-9269-04bad62a3558','',#5,#43,$);
|
||||||
|
#389 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#45));
|
||||||
|
#390 = SHAPE_DEFINITION_REPRESENTATION(#391,#397);
|
||||||
|
#391 = PRODUCT_DEFINITION_SHAPE('','',#392);
|
||||||
|
#392 = PRODUCT_DEFINITION('design','',#393,#396);
|
||||||
|
#393 = PRODUCT_DEFINITION_FORMATION('','',#394);
|
||||||
|
#394 = PRODUCT('364ea3ca-93c7-11f1-bdcd-04bad62a3558',
|
||||||
|
'364ea3ca-93c7-11f1-bdcd-04bad62a3558','',(#395));
|
||||||
|
#395 = PRODUCT_CONTEXT('',#2,'mechanical');
|
||||||
|
#396 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
|
||||||
|
#397 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#398),#728);
|
||||||
|
#398 = MANIFOLD_SOLID_BREP('',#399);
|
||||||
|
#399 = CLOSED_SHELL('',(#400,#520,#620,#667,#714,#721));
|
||||||
|
#400 = ADVANCED_FACE('',(#401),#415,.F.);
|
||||||
|
#401 = FACE_BOUND('',#402,.F.);
|
||||||
|
#402 = EDGE_LOOP('',(#403,#438,#466,#494));
|
||||||
|
#403 = ORIENTED_EDGE('',*,*,#404,.F.);
|
||||||
|
#404 = EDGE_CURVE('',#405,#407,#409,.T.);
|
||||||
|
#405 = VERTEX_POINT('',#406);
|
||||||
|
#406 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#407 = VERTEX_POINT('',#408);
|
||||||
|
#408 = CARTESIAN_POINT('',(2.29,-0.19,2.7));
|
||||||
|
#409 = SURFACE_CURVE('',#410,(#414,#426),.PCURVE_S1.);
|
||||||
|
#410 = LINE('',#411,#412);
|
||||||
|
#411 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#412 = VECTOR('',#413,1.);
|
||||||
|
#413 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#414 = PCURVE('',#415,#420);
|
||||||
|
#415 = PLANE('',#416);
|
||||||
|
#416 = AXIS2_PLACEMENT_3D('',#417,#418,#419);
|
||||||
|
#417 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#418 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#419 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#420 = DEFINITIONAL_REPRESENTATION('',(#421),#425);
|
||||||
|
#421 = LINE('',#422,#423);
|
||||||
|
#422 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#423 = VECTOR('',#424,1.);
|
||||||
|
#424 = DIRECTION('',(1.,0.));
|
||||||
|
#425 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#426 = PCURVE('',#427,#432);
|
||||||
|
#427 = PLANE('',#428);
|
||||||
|
#428 = AXIS2_PLACEMENT_3D('',#429,#430,#431);
|
||||||
|
#429 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#430 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#431 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#432 = DEFINITIONAL_REPRESENTATION('',(#433),#437);
|
||||||
|
#433 = LINE('',#434,#435);
|
||||||
|
#434 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#435 = VECTOR('',#436,1.);
|
||||||
|
#436 = DIRECTION('',(1.,0.));
|
||||||
|
#437 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#438 = ORIENTED_EDGE('',*,*,#439,.T.);
|
||||||
|
#439 = EDGE_CURVE('',#405,#440,#442,.T.);
|
||||||
|
#440 = VERTEX_POINT('',#441);
|
||||||
|
#441 = CARTESIAN_POINT('',(2.29,0.19,-2.6));
|
||||||
|
#442 = SURFACE_CURVE('',#443,(#447,#454),.PCURVE_S1.);
|
||||||
|
#443 = LINE('',#444,#445);
|
||||||
|
#444 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#445 = VECTOR('',#446,1.);
|
||||||
|
#446 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#447 = PCURVE('',#415,#448);
|
||||||
|
#448 = DEFINITIONAL_REPRESENTATION('',(#449),#453);
|
||||||
|
#449 = LINE('',#450,#451);
|
||||||
|
#450 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#451 = VECTOR('',#452,1.);
|
||||||
|
#452 = DIRECTION('',(0.,-1.));
|
||||||
|
#453 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#454 = PCURVE('',#455,#460);
|
||||||
|
#455 = PLANE('',#456);
|
||||||
|
#456 = AXIS2_PLACEMENT_3D('',#457,#458,#459);
|
||||||
|
#457 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#458 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#459 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#460 = DEFINITIONAL_REPRESENTATION('',(#461),#465);
|
||||||
|
#461 = LINE('',#462,#463);
|
||||||
|
#462 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#463 = VECTOR('',#464,1.);
|
||||||
|
#464 = DIRECTION('',(0.,1.));
|
||||||
|
#465 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#466 = ORIENTED_EDGE('',*,*,#467,.T.);
|
||||||
|
#467 = EDGE_CURVE('',#440,#468,#470,.T.);
|
||||||
|
#468 = VERTEX_POINT('',#469);
|
||||||
|
#469 = CARTESIAN_POINT('',(2.29,0.19,2.7));
|
||||||
|
#470 = SURFACE_CURVE('',#471,(#475,#482),.PCURVE_S1.);
|
||||||
|
#471 = LINE('',#472,#473);
|
||||||
|
#472 = CARTESIAN_POINT('',(2.29,0.19,-2.6));
|
||||||
|
#473 = VECTOR('',#474,1.);
|
||||||
|
#474 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#475 = PCURVE('',#415,#476);
|
||||||
|
#476 = DEFINITIONAL_REPRESENTATION('',(#477),#481);
|
||||||
|
#477 = LINE('',#478,#479);
|
||||||
|
#478 = CARTESIAN_POINT('',(0.,-0.38));
|
||||||
|
#479 = VECTOR('',#480,1.);
|
||||||
|
#480 = DIRECTION('',(1.,0.));
|
||||||
|
#481 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#482 = PCURVE('',#483,#488);
|
||||||
|
#483 = PLANE('',#484);
|
||||||
|
#484 = AXIS2_PLACEMENT_3D('',#485,#486,#487);
|
||||||
|
#485 = CARTESIAN_POINT('',(2.29,0.19,-2.6));
|
||||||
|
#486 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#487 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#488 = DEFINITIONAL_REPRESENTATION('',(#489),#493);
|
||||||
|
#489 = LINE('',#490,#491);
|
||||||
|
#490 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#491 = VECTOR('',#492,1.);
|
||||||
|
#492 = DIRECTION('',(1.,0.));
|
||||||
|
#493 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#494 = ORIENTED_EDGE('',*,*,#495,.F.);
|
||||||
|
#495 = EDGE_CURVE('',#407,#468,#496,.T.);
|
||||||
|
#496 = SURFACE_CURVE('',#497,(#501,#508),.PCURVE_S1.);
|
||||||
|
#497 = LINE('',#498,#499);
|
||||||
|
#498 = CARTESIAN_POINT('',(2.29,-0.19,2.7));
|
||||||
|
#499 = VECTOR('',#500,1.);
|
||||||
|
#500 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#501 = PCURVE('',#415,#502);
|
||||||
|
#502 = DEFINITIONAL_REPRESENTATION('',(#503),#507);
|
||||||
|
#503 = LINE('',#504,#505);
|
||||||
|
#504 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#505 = VECTOR('',#506,1.);
|
||||||
|
#506 = DIRECTION('',(0.,-1.));
|
||||||
|
#507 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#508 = PCURVE('',#509,#514);
|
||||||
|
#509 = PLANE('',#510);
|
||||||
|
#510 = AXIS2_PLACEMENT_3D('',#511,#512,#513);
|
||||||
|
#511 = CARTESIAN_POINT('',(2.29,-0.19,2.7));
|
||||||
|
#512 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#513 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#514 = DEFINITIONAL_REPRESENTATION('',(#515),#519);
|
||||||
|
#515 = LINE('',#516,#517);
|
||||||
|
#516 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#517 = VECTOR('',#518,1.);
|
||||||
|
#518 = DIRECTION('',(0.,1.));
|
||||||
|
#519 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#520 = ADVANCED_FACE('',(#521),#535,.T.);
|
||||||
|
#521 = FACE_BOUND('',#522,.T.);
|
||||||
|
#522 = EDGE_LOOP('',(#523,#553,#576,#599));
|
||||||
|
#523 = ORIENTED_EDGE('',*,*,#524,.F.);
|
||||||
|
#524 = EDGE_CURVE('',#525,#527,#529,.T.);
|
||||||
|
#525 = VERTEX_POINT('',#526);
|
||||||
|
#526 = CARTESIAN_POINT('',(2.79,-0.19,-2.6));
|
||||||
|
#527 = VERTEX_POINT('',#528);
|
||||||
|
#528 = CARTESIAN_POINT('',(2.79,-0.19,2.7));
|
||||||
|
#529 = SURFACE_CURVE('',#530,(#534,#546),.PCURVE_S1.);
|
||||||
|
#530 = LINE('',#531,#532);
|
||||||
|
#531 = CARTESIAN_POINT('',(2.79,-0.19,-2.6));
|
||||||
|
#532 = VECTOR('',#533,1.);
|
||||||
|
#533 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#534 = PCURVE('',#535,#540);
|
||||||
|
#535 = PLANE('',#536);
|
||||||
|
#536 = AXIS2_PLACEMENT_3D('',#537,#538,#539);
|
||||||
|
#537 = CARTESIAN_POINT('',(2.79,-0.19,-2.6));
|
||||||
|
#538 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#539 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#540 = DEFINITIONAL_REPRESENTATION('',(#541),#545);
|
||||||
|
#541 = LINE('',#542,#543);
|
||||||
|
#542 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#543 = VECTOR('',#544,1.);
|
||||||
|
#544 = DIRECTION('',(1.,0.));
|
||||||
|
#545 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#546 = PCURVE('',#427,#547);
|
||||||
|
#547 = DEFINITIONAL_REPRESENTATION('',(#548),#552);
|
||||||
|
#548 = LINE('',#549,#550);
|
||||||
|
#549 = CARTESIAN_POINT('',(0.,0.5));
|
||||||
|
#550 = VECTOR('',#551,1.);
|
||||||
|
#551 = DIRECTION('',(1.,0.));
|
||||||
|
#552 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#553 = ORIENTED_EDGE('',*,*,#554,.T.);
|
||||||
|
#554 = EDGE_CURVE('',#525,#555,#557,.T.);
|
||||||
|
#555 = VERTEX_POINT('',#556);
|
||||||
|
#556 = CARTESIAN_POINT('',(2.79,0.19,-2.6));
|
||||||
|
#557 = SURFACE_CURVE('',#558,(#562,#569),.PCURVE_S1.);
|
||||||
|
#558 = LINE('',#559,#560);
|
||||||
|
#559 = CARTESIAN_POINT('',(2.79,-0.19,-2.6));
|
||||||
|
#560 = VECTOR('',#561,1.);
|
||||||
|
#561 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#562 = PCURVE('',#535,#563);
|
||||||
|
#563 = DEFINITIONAL_REPRESENTATION('',(#564),#568);
|
||||||
|
#564 = LINE('',#565,#566);
|
||||||
|
#565 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#566 = VECTOR('',#567,1.);
|
||||||
|
#567 = DIRECTION('',(0.,-1.));
|
||||||
|
#568 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#569 = PCURVE('',#455,#570);
|
||||||
|
#570 = DEFINITIONAL_REPRESENTATION('',(#571),#575);
|
||||||
|
#571 = LINE('',#572,#573);
|
||||||
|
#572 = CARTESIAN_POINT('',(0.5,0.));
|
||||||
|
#573 = VECTOR('',#574,1.);
|
||||||
|
#574 = DIRECTION('',(0.,1.));
|
||||||
|
#575 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#576 = ORIENTED_EDGE('',*,*,#577,.T.);
|
||||||
|
#577 = EDGE_CURVE('',#555,#578,#580,.T.);
|
||||||
|
#578 = VERTEX_POINT('',#579);
|
||||||
|
#579 = CARTESIAN_POINT('',(2.79,0.19,2.7));
|
||||||
|
#580 = SURFACE_CURVE('',#581,(#585,#592),.PCURVE_S1.);
|
||||||
|
#581 = LINE('',#582,#583);
|
||||||
|
#582 = CARTESIAN_POINT('',(2.79,0.19,-2.6));
|
||||||
|
#583 = VECTOR('',#584,1.);
|
||||||
|
#584 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#585 = PCURVE('',#535,#586);
|
||||||
|
#586 = DEFINITIONAL_REPRESENTATION('',(#587),#591);
|
||||||
|
#587 = LINE('',#588,#589);
|
||||||
|
#588 = CARTESIAN_POINT('',(0.,-0.38));
|
||||||
|
#589 = VECTOR('',#590,1.);
|
||||||
|
#590 = DIRECTION('',(1.,0.));
|
||||||
|
#591 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#592 = PCURVE('',#483,#593);
|
||||||
|
#593 = DEFINITIONAL_REPRESENTATION('',(#594),#598);
|
||||||
|
#594 = LINE('',#595,#596);
|
||||||
|
#595 = CARTESIAN_POINT('',(0.,0.5));
|
||||||
|
#596 = VECTOR('',#597,1.);
|
||||||
|
#597 = DIRECTION('',(1.,0.));
|
||||||
|
#598 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#599 = ORIENTED_EDGE('',*,*,#600,.F.);
|
||||||
|
#600 = EDGE_CURVE('',#527,#578,#601,.T.);
|
||||||
|
#601 = SURFACE_CURVE('',#602,(#606,#613),.PCURVE_S1.);
|
||||||
|
#602 = LINE('',#603,#604);
|
||||||
|
#603 = CARTESIAN_POINT('',(2.79,-0.19,2.7));
|
||||||
|
#604 = VECTOR('',#605,1.);
|
||||||
|
#605 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#606 = PCURVE('',#535,#607);
|
||||||
|
#607 = DEFINITIONAL_REPRESENTATION('',(#608),#612);
|
||||||
|
#608 = LINE('',#609,#610);
|
||||||
|
#609 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#610 = VECTOR('',#611,1.);
|
||||||
|
#611 = DIRECTION('',(0.,-1.));
|
||||||
|
#612 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#613 = PCURVE('',#509,#614);
|
||||||
|
#614 = DEFINITIONAL_REPRESENTATION('',(#615),#619);
|
||||||
|
#615 = LINE('',#616,#617);
|
||||||
|
#616 = CARTESIAN_POINT('',(0.5,0.));
|
||||||
|
#617 = VECTOR('',#618,1.);
|
||||||
|
#618 = DIRECTION('',(0.,1.));
|
||||||
|
#619 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#620 = ADVANCED_FACE('',(#621),#427,.F.);
|
||||||
|
#621 = FACE_BOUND('',#622,.F.);
|
||||||
|
#622 = EDGE_LOOP('',(#623,#644,#645,#666));
|
||||||
|
#623 = ORIENTED_EDGE('',*,*,#624,.F.);
|
||||||
|
#624 = EDGE_CURVE('',#405,#525,#625,.T.);
|
||||||
|
#625 = SURFACE_CURVE('',#626,(#630,#637),.PCURVE_S1.);
|
||||||
|
#626 = LINE('',#627,#628);
|
||||||
|
#627 = CARTESIAN_POINT('',(2.29,-0.19,-2.6));
|
||||||
|
#628 = VECTOR('',#629,1.);
|
||||||
|
#629 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#630 = PCURVE('',#427,#631);
|
||||||
|
#631 = DEFINITIONAL_REPRESENTATION('',(#632),#636);
|
||||||
|
#632 = LINE('',#633,#634);
|
||||||
|
#633 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#634 = VECTOR('',#635,1.);
|
||||||
|
#635 = DIRECTION('',(0.,1.));
|
||||||
|
#636 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#637 = PCURVE('',#455,#638);
|
||||||
|
#638 = DEFINITIONAL_REPRESENTATION('',(#639),#643);
|
||||||
|
#639 = LINE('',#640,#641);
|
||||||
|
#640 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#641 = VECTOR('',#642,1.);
|
||||||
|
#642 = DIRECTION('',(1.,0.));
|
||||||
|
#643 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#644 = ORIENTED_EDGE('',*,*,#404,.T.);
|
||||||
|
#645 = ORIENTED_EDGE('',*,*,#646,.T.);
|
||||||
|
#646 = EDGE_CURVE('',#407,#527,#647,.T.);
|
||||||
|
#647 = SURFACE_CURVE('',#648,(#652,#659),.PCURVE_S1.);
|
||||||
|
#648 = LINE('',#649,#650);
|
||||||
|
#649 = CARTESIAN_POINT('',(2.29,-0.19,2.7));
|
||||||
|
#650 = VECTOR('',#651,1.);
|
||||||
|
#651 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#652 = PCURVE('',#427,#653);
|
||||||
|
#653 = DEFINITIONAL_REPRESENTATION('',(#654),#658);
|
||||||
|
#654 = LINE('',#655,#656);
|
||||||
|
#655 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#656 = VECTOR('',#657,1.);
|
||||||
|
#657 = DIRECTION('',(0.,1.));
|
||||||
|
#658 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#659 = PCURVE('',#509,#660);
|
||||||
|
#660 = DEFINITIONAL_REPRESENTATION('',(#661),#665);
|
||||||
|
#661 = LINE('',#662,#663);
|
||||||
|
#662 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#663 = VECTOR('',#664,1.);
|
||||||
|
#664 = DIRECTION('',(1.,0.));
|
||||||
|
#665 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#666 = ORIENTED_EDGE('',*,*,#524,.F.);
|
||||||
|
#667 = ADVANCED_FACE('',(#668),#483,.T.);
|
||||||
|
#668 = FACE_BOUND('',#669,.T.);
|
||||||
|
#669 = EDGE_LOOP('',(#670,#691,#692,#713));
|
||||||
|
#670 = ORIENTED_EDGE('',*,*,#671,.F.);
|
||||||
|
#671 = EDGE_CURVE('',#440,#555,#672,.T.);
|
||||||
|
#672 = SURFACE_CURVE('',#673,(#677,#684),.PCURVE_S1.);
|
||||||
|
#673 = LINE('',#674,#675);
|
||||||
|
#674 = CARTESIAN_POINT('',(2.29,0.19,-2.6));
|
||||||
|
#675 = VECTOR('',#676,1.);
|
||||||
|
#676 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#677 = PCURVE('',#483,#678);
|
||||||
|
#678 = DEFINITIONAL_REPRESENTATION('',(#679),#683);
|
||||||
|
#679 = LINE('',#680,#681);
|
||||||
|
#680 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#681 = VECTOR('',#682,1.);
|
||||||
|
#682 = DIRECTION('',(0.,1.));
|
||||||
|
#683 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#684 = PCURVE('',#455,#685);
|
||||||
|
#685 = DEFINITIONAL_REPRESENTATION('',(#686),#690);
|
||||||
|
#686 = LINE('',#687,#688);
|
||||||
|
#687 = CARTESIAN_POINT('',(0.,0.38));
|
||||||
|
#688 = VECTOR('',#689,1.);
|
||||||
|
#689 = DIRECTION('',(1.,0.));
|
||||||
|
#690 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#691 = ORIENTED_EDGE('',*,*,#467,.T.);
|
||||||
|
#692 = ORIENTED_EDGE('',*,*,#693,.T.);
|
||||||
|
#693 = EDGE_CURVE('',#468,#578,#694,.T.);
|
||||||
|
#694 = SURFACE_CURVE('',#695,(#699,#706),.PCURVE_S1.);
|
||||||
|
#695 = LINE('',#696,#697);
|
||||||
|
#696 = CARTESIAN_POINT('',(2.29,0.19,2.7));
|
||||||
|
#697 = VECTOR('',#698,1.);
|
||||||
|
#698 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#699 = PCURVE('',#483,#700);
|
||||||
|
#700 = DEFINITIONAL_REPRESENTATION('',(#701),#705);
|
||||||
|
#701 = LINE('',#702,#703);
|
||||||
|
#702 = CARTESIAN_POINT('',(5.3,0.));
|
||||||
|
#703 = VECTOR('',#704,1.);
|
||||||
|
#704 = DIRECTION('',(0.,1.));
|
||||||
|
#705 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#706 = PCURVE('',#509,#707);
|
||||||
|
#707 = DEFINITIONAL_REPRESENTATION('',(#708),#712);
|
||||||
|
#708 = LINE('',#709,#710);
|
||||||
|
#709 = CARTESIAN_POINT('',(0.,0.38));
|
||||||
|
#710 = VECTOR('',#711,1.);
|
||||||
|
#711 = DIRECTION('',(1.,0.));
|
||||||
|
#712 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#713 = ORIENTED_EDGE('',*,*,#577,.F.);
|
||||||
|
#714 = ADVANCED_FACE('',(#715),#455,.F.);
|
||||||
|
#715 = FACE_BOUND('',#716,.F.);
|
||||||
|
#716 = EDGE_LOOP('',(#717,#718,#719,#720));
|
||||||
|
#717 = ORIENTED_EDGE('',*,*,#439,.F.);
|
||||||
|
#718 = ORIENTED_EDGE('',*,*,#624,.T.);
|
||||||
|
#719 = ORIENTED_EDGE('',*,*,#554,.T.);
|
||||||
|
#720 = ORIENTED_EDGE('',*,*,#671,.F.);
|
||||||
|
#721 = ADVANCED_FACE('',(#722),#509,.T.);
|
||||||
|
#722 = FACE_BOUND('',#723,.T.);
|
||||||
|
#723 = EDGE_LOOP('',(#724,#725,#726,#727));
|
||||||
|
#724 = ORIENTED_EDGE('',*,*,#495,.F.);
|
||||||
|
#725 = ORIENTED_EDGE('',*,*,#646,.T.);
|
||||||
|
#726 = ORIENTED_EDGE('',*,*,#600,.T.);
|
||||||
|
#727 = ORIENTED_EDGE('',*,*,#693,.F.);
|
||||||
|
#728 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#732)) GLOBAL_UNIT_ASSIGNED_CONTEXT
|
||||||
|
((#729,#730,#731)) REPRESENTATION_CONTEXT('Context #1',
|
||||||
|
'3D Context with UNIT and UNCERTAINTY') );
|
||||||
|
#729 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
|
||||||
|
#730 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
|
||||||
|
#731 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
|
||||||
|
#732 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#729,
|
||||||
|
'distance_accuracy_value','confusion accuracy');
|
||||||
|
#733 = CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#734,#736);
|
||||||
|
#734 = ( REPRESENTATION_RELATIONSHIP('','',#397,#10)
|
||||||
|
REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#735)
|
||||||
|
SHAPE_REPRESENTATION_RELATIONSHIP() );
|
||||||
|
#735 = ITEM_DEFINED_TRANSFORMATION('','',#11,#19);
|
||||||
|
#736 = PRODUCT_DEFINITION_SHAPE('Placement','Placement of an item',#737
|
||||||
|
);
|
||||||
|
#737 = NEXT_ASSEMBLY_USAGE_OCCURRENCE('57',
|
||||||
|
'364ea3ca-93c7-11f1-bdcd-04bad62a3558','',#5,#392,$);
|
||||||
|
#738 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#394));
|
||||||
|
#739 = SHAPE_DEFINITION_REPRESENTATION(#740,#746);
|
||||||
|
#740 = PRODUCT_DEFINITION_SHAPE('','',#741);
|
||||||
|
#741 = PRODUCT_DEFINITION('design','',#742,#745);
|
||||||
|
#742 = PRODUCT_DEFINITION_FORMATION('','',#743);
|
||||||
|
#743 = PRODUCT('3650c6ce-93c7-11f1-9448-04bad62a3558',
|
||||||
|
'3650c6ce-93c7-11f1-9448-04bad62a3558','',(#744));
|
||||||
|
#744 = PRODUCT_CONTEXT('',#2,'mechanical');
|
||||||
|
#745 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
|
||||||
|
#746 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#747),#1413);
|
||||||
|
#747 = MANIFOLD_SOLID_BREP('',#748);
|
||||||
|
#748 = CLOSED_SHELL('',(#749,#869,#1069,#1119,#1173,#1298,#1325,#1352,
|
||||||
|
#1379,#1406));
|
||||||
|
#749 = ADVANCED_FACE('',(#750),#764,.F.);
|
||||||
|
#750 = FACE_BOUND('',#751,.F.);
|
||||||
|
#751 = EDGE_LOOP('',(#752,#787,#815,#843));
|
||||||
|
#752 = ORIENTED_EDGE('',*,*,#753,.F.);
|
||||||
|
#753 = EDGE_CURVE('',#754,#756,#758,.T.);
|
||||||
|
#754 = VERTEX_POINT('',#755);
|
||||||
|
#755 = CARTESIAN_POINT('',(-2.325,-0.75,6.45));
|
||||||
|
#756 = VERTEX_POINT('',#757);
|
||||||
|
#757 = CARTESIAN_POINT('',(-2.325,0.75,6.45));
|
||||||
|
#758 = SURFACE_CURVE('',#759,(#763,#775),.PCURVE_S1.);
|
||||||
|
#759 = LINE('',#760,#761);
|
||||||
|
#760 = CARTESIAN_POINT('',(-2.325,-1.,6.45));
|
||||||
|
#761 = VECTOR('',#762,1.);
|
||||||
|
#762 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#763 = PCURVE('',#764,#769);
|
||||||
|
#764 = PLANE('',#765);
|
||||||
|
#765 = AXIS2_PLACEMENT_3D('',#766,#767,#768);
|
||||||
|
#766 = CARTESIAN_POINT('',(-2.325,-1.,2.15));
|
||||||
|
#767 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#768 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#769 = DEFINITIONAL_REPRESENTATION('',(#770),#774);
|
||||||
|
#770 = LINE('',#771,#772);
|
||||||
|
#771 = CARTESIAN_POINT('',(4.3,0.));
|
||||||
|
#772 = VECTOR('',#773,1.);
|
||||||
|
#773 = DIRECTION('',(0.,-1.));
|
||||||
|
#774 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#775 = PCURVE('',#776,#781);
|
||||||
|
#776 = PLANE('',#777);
|
||||||
|
#777 = AXIS2_PLACEMENT_3D('',#778,#779,#780);
|
||||||
|
#778 = CARTESIAN_POINT('',(-2.325,-1.,6.45));
|
||||||
|
#779 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#780 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#781 = DEFINITIONAL_REPRESENTATION('',(#782),#786);
|
||||||
|
#782 = LINE('',#783,#784);
|
||||||
|
#783 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#784 = VECTOR('',#785,1.);
|
||||||
|
#785 = DIRECTION('',(0.,1.));
|
||||||
|
#786 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#787 = ORIENTED_EDGE('',*,*,#788,.F.);
|
||||||
|
#788 = EDGE_CURVE('',#789,#754,#791,.T.);
|
||||||
|
#789 = VERTEX_POINT('',#790);
|
||||||
|
#790 = CARTESIAN_POINT('',(-2.325,-0.75,2.15));
|
||||||
|
#791 = SURFACE_CURVE('',#792,(#796,#803),.PCURVE_S1.);
|
||||||
|
#792 = LINE('',#793,#794);
|
||||||
|
#793 = CARTESIAN_POINT('',(-2.325,-0.75,2.15));
|
||||||
|
#794 = VECTOR('',#795,1.);
|
||||||
|
#795 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#796 = PCURVE('',#764,#797);
|
||||||
|
#797 = DEFINITIONAL_REPRESENTATION('',(#798),#802);
|
||||||
|
#798 = LINE('',#799,#800);
|
||||||
|
#799 = CARTESIAN_POINT('',(0.,-0.25));
|
||||||
|
#800 = VECTOR('',#801,1.);
|
||||||
|
#801 = DIRECTION('',(1.,0.));
|
||||||
|
#802 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#803 = PCURVE('',#804,#809);
|
||||||
|
#804 = CYLINDRICAL_SURFACE('',#805,0.25);
|
||||||
|
#805 = AXIS2_PLACEMENT_3D('',#806,#807,#808);
|
||||||
|
#806 = CARTESIAN_POINT('',(-2.075,-0.75,2.15));
|
||||||
|
#807 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#808 = DIRECTION('',(-1.,-0.,0.));
|
||||||
|
#809 = DEFINITIONAL_REPRESENTATION('',(#810),#814);
|
||||||
|
#810 = LINE('',#811,#812);
|
||||||
|
#811 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#812 = VECTOR('',#813,1.);
|
||||||
|
#813 = DIRECTION('',(0.,1.));
|
||||||
|
#814 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#815 = ORIENTED_EDGE('',*,*,#816,.T.);
|
||||||
|
#816 = EDGE_CURVE('',#789,#817,#819,.T.);
|
||||||
|
#817 = VERTEX_POINT('',#818);
|
||||||
|
#818 = CARTESIAN_POINT('',(-2.325,0.75,2.15));
|
||||||
|
#819 = SURFACE_CURVE('',#820,(#824,#831),.PCURVE_S1.);
|
||||||
|
#820 = LINE('',#821,#822);
|
||||||
|
#821 = CARTESIAN_POINT('',(-2.325,-1.,2.15));
|
||||||
|
#822 = VECTOR('',#823,1.);
|
||||||
|
#823 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#824 = PCURVE('',#764,#825);
|
||||||
|
#825 = DEFINITIONAL_REPRESENTATION('',(#826),#830);
|
||||||
|
#826 = LINE('',#827,#828);
|
||||||
|
#827 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#828 = VECTOR('',#829,1.);
|
||||||
|
#829 = DIRECTION('',(0.,-1.));
|
||||||
|
#830 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#831 = PCURVE('',#832,#837);
|
||||||
|
#832 = PLANE('',#833);
|
||||||
|
#833 = AXIS2_PLACEMENT_3D('',#834,#835,#836);
|
||||||
|
#834 = CARTESIAN_POINT('',(-2.325,-1.,2.15));
|
||||||
|
#835 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#836 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#837 = DEFINITIONAL_REPRESENTATION('',(#838),#842);
|
||||||
|
#838 = LINE('',#839,#840);
|
||||||
|
#839 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#840 = VECTOR('',#841,1.);
|
||||||
|
#841 = DIRECTION('',(0.,1.));
|
||||||
|
#842 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#843 = ORIENTED_EDGE('',*,*,#844,.T.);
|
||||||
|
#844 = EDGE_CURVE('',#817,#756,#845,.T.);
|
||||||
|
#845 = SURFACE_CURVE('',#846,(#850,#857),.PCURVE_S1.);
|
||||||
|
#846 = LINE('',#847,#848);
|
||||||
|
#847 = CARTESIAN_POINT('',(-2.325,0.75,2.15));
|
||||||
|
#848 = VECTOR('',#849,1.);
|
||||||
|
#849 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#850 = PCURVE('',#764,#851);
|
||||||
|
#851 = DEFINITIONAL_REPRESENTATION('',(#852),#856);
|
||||||
|
#852 = LINE('',#853,#854);
|
||||||
|
#853 = CARTESIAN_POINT('',(0.,-1.75));
|
||||||
|
#854 = VECTOR('',#855,1.);
|
||||||
|
#855 = DIRECTION('',(1.,0.));
|
||||||
|
#856 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#857 = PCURVE('',#858,#863);
|
||||||
|
#858 = CYLINDRICAL_SURFACE('',#859,0.25);
|
||||||
|
#859 = AXIS2_PLACEMENT_3D('',#860,#861,#862);
|
||||||
|
#860 = CARTESIAN_POINT('',(-2.075,0.75,2.15));
|
||||||
|
#861 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#862 = DIRECTION('',(-1.,-0.,0.));
|
||||||
|
#863 = DEFINITIONAL_REPRESENTATION('',(#864),#868);
|
||||||
|
#864 = LINE('',#865,#866);
|
||||||
|
#865 = CARTESIAN_POINT('',(-0.,0.));
|
||||||
|
#866 = VECTOR('',#867,1.);
|
||||||
|
#867 = DIRECTION('',(-0.,1.));
|
||||||
|
#868 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#869 = ADVANCED_FACE('',(#870),#776,.T.);
|
||||||
|
#870 = FACE_BOUND('',#871,.T.);
|
||||||
|
#871 = EDGE_LOOP('',(#872,#873,#897,#925,#958,#986,#1015,#1043));
|
||||||
|
#872 = ORIENTED_EDGE('',*,*,#753,.F.);
|
||||||
|
#873 = ORIENTED_EDGE('',*,*,#874,.T.);
|
||||||
|
#874 = EDGE_CURVE('',#754,#875,#877,.T.);
|
||||||
|
#875 = VERTEX_POINT('',#876);
|
||||||
|
#876 = CARTESIAN_POINT('',(-2.075,-1.,6.45));
|
||||||
|
#877 = SURFACE_CURVE('',#878,(#883,#890),.PCURVE_S1.);
|
||||||
|
#878 = CIRCLE('',#879,0.25);
|
||||||
|
#879 = AXIS2_PLACEMENT_3D('',#880,#881,#882);
|
||||||
|
#880 = CARTESIAN_POINT('',(-2.075,-0.75,6.45));
|
||||||
|
#881 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#882 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#883 = PCURVE('',#776,#884);
|
||||||
|
#884 = DEFINITIONAL_REPRESENTATION('',(#885),#889);
|
||||||
|
#885 = CIRCLE('',#886,0.25);
|
||||||
|
#886 = AXIS2_PLACEMENT_2D('',#887,#888);
|
||||||
|
#887 = CARTESIAN_POINT('',(0.25,0.25));
|
||||||
|
#888 = DIRECTION('',(0.,-1.));
|
||||||
|
#889 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#890 = PCURVE('',#804,#891);
|
||||||
|
#891 = DEFINITIONAL_REPRESENTATION('',(#892),#896);
|
||||||
|
#892 = LINE('',#893,#894);
|
||||||
|
#893 = CARTESIAN_POINT('',(-4.712388980385,4.3));
|
||||||
|
#894 = VECTOR('',#895,1.);
|
||||||
|
#895 = DIRECTION('',(1.,0.));
|
||||||
|
#896 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#897 = ORIENTED_EDGE('',*,*,#898,.T.);
|
||||||
|
#898 = EDGE_CURVE('',#875,#899,#901,.T.);
|
||||||
|
#899 = VERTEX_POINT('',#900);
|
||||||
|
#900 = CARTESIAN_POINT('',(2.075,-1.,6.45));
|
||||||
|
#901 = SURFACE_CURVE('',#902,(#906,#913),.PCURVE_S1.);
|
||||||
|
#902 = LINE('',#903,#904);
|
||||||
|
#903 = CARTESIAN_POINT('',(-2.325,-1.,6.45));
|
||||||
|
#904 = VECTOR('',#905,1.);
|
||||||
|
#905 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#906 = PCURVE('',#776,#907);
|
||||||
|
#907 = DEFINITIONAL_REPRESENTATION('',(#908),#912);
|
||||||
|
#908 = LINE('',#909,#910);
|
||||||
|
#909 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#910 = VECTOR('',#911,1.);
|
||||||
|
#911 = DIRECTION('',(1.,0.));
|
||||||
|
#912 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#913 = PCURVE('',#914,#919);
|
||||||
|
#914 = PLANE('',#915);
|
||||||
|
#915 = AXIS2_PLACEMENT_3D('',#916,#917,#918);
|
||||||
|
#916 = CARTESIAN_POINT('',(-2.325,-1.,2.15));
|
||||||
|
#917 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#918 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#919 = DEFINITIONAL_REPRESENTATION('',(#920),#924);
|
||||||
|
#920 = LINE('',#921,#922);
|
||||||
|
#921 = CARTESIAN_POINT('',(4.3,0.));
|
||||||
|
#922 = VECTOR('',#923,1.);
|
||||||
|
#923 = DIRECTION('',(0.,1.));
|
||||||
|
#924 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#925 = ORIENTED_EDGE('',*,*,#926,.F.);
|
||||||
|
#926 = EDGE_CURVE('',#927,#899,#929,.T.);
|
||||||
|
#927 = VERTEX_POINT('',#928);
|
||||||
|
#928 = CARTESIAN_POINT('',(2.325,-0.75,6.45));
|
||||||
|
#929 = SURFACE_CURVE('',#930,(#935,#946),.PCURVE_S1.);
|
||||||
|
#930 = CIRCLE('',#931,0.25);
|
||||||
|
#931 = AXIS2_PLACEMENT_3D('',#932,#933,#934);
|
||||||
|
#932 = CARTESIAN_POINT('',(2.075,-0.75,6.45));
|
||||||
|
#933 = DIRECTION('',(-0.,-0.,-1.));
|
||||||
|
#934 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#935 = PCURVE('',#776,#936);
|
||||||
|
#936 = DEFINITIONAL_REPRESENTATION('',(#937),#945);
|
||||||
|
#937 = ( BOUNDED_CURVE() B_SPLINE_CURVE(2,(#938,#939,#940,#941,#942,#943
|
||||||
|
,#944),.UNSPECIFIED.,.T.,.F.) B_SPLINE_CURVE_WITH_KNOTS((1,2,2,2,2,1),(
|
||||||
|
-2.094395102393,0.,2.094395102393,4.188790204786,6.28318530718,
|
||||||
|
8.377580409573),.UNSPECIFIED.) CURVE() GEOMETRIC_REPRESENTATION_ITEM()
|
||||||
|
RATIONAL_B_SPLINE_CURVE((1.,0.5,1.,0.5,1.,0.5,1.)) REPRESENTATION_ITEM(
|
||||||
|
'') );
|
||||||
|
#938 = CARTESIAN_POINT('',(4.4,0.));
|
||||||
|
#939 = CARTESIAN_POINT('',(3.966987298108,0.));
|
||||||
|
#940 = CARTESIAN_POINT('',(4.183493649054,0.375));
|
||||||
|
#941 = CARTESIAN_POINT('',(4.4,0.75));
|
||||||
|
#942 = CARTESIAN_POINT('',(4.616506350946,0.375));
|
||||||
|
#943 = CARTESIAN_POINT('',(4.833012701892,3.885780586188E-16));
|
||||||
|
#944 = CARTESIAN_POINT('',(4.4,0.));
|
||||||
|
#945 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#946 = PCURVE('',#947,#952);
|
||||||
|
#947 = CYLINDRICAL_SURFACE('',#948,0.25);
|
||||||
|
#948 = AXIS2_PLACEMENT_3D('',#949,#950,#951);
|
||||||
|
#949 = CARTESIAN_POINT('',(2.075,-0.75,2.15));
|
||||||
|
#950 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#951 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#952 = DEFINITIONAL_REPRESENTATION('',(#953),#957);
|
||||||
|
#953 = LINE('',#954,#955);
|
||||||
|
#954 = CARTESIAN_POINT('',(4.712388980385,4.3));
|
||||||
|
#955 = VECTOR('',#956,1.);
|
||||||
|
#956 = DIRECTION('',(-1.,0.));
|
||||||
|
#957 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#958 = ORIENTED_EDGE('',*,*,#959,.T.);
|
||||||
|
#959 = EDGE_CURVE('',#927,#960,#962,.T.);
|
||||||
|
#960 = VERTEX_POINT('',#961);
|
||||||
|
#961 = CARTESIAN_POINT('',(2.325,0.75,6.45));
|
||||||
|
#962 = SURFACE_CURVE('',#963,(#967,#974),.PCURVE_S1.);
|
||||||
|
#963 = LINE('',#964,#965);
|
||||||
|
#964 = CARTESIAN_POINT('',(2.325,-1.,6.45));
|
||||||
|
#965 = VECTOR('',#966,1.);
|
||||||
|
#966 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#967 = PCURVE('',#776,#968);
|
||||||
|
#968 = DEFINITIONAL_REPRESENTATION('',(#969),#973);
|
||||||
|
#969 = LINE('',#970,#971);
|
||||||
|
#970 = CARTESIAN_POINT('',(4.65,0.));
|
||||||
|
#971 = VECTOR('',#972,1.);
|
||||||
|
#972 = DIRECTION('',(0.,1.));
|
||||||
|
#973 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#974 = PCURVE('',#975,#980);
|
||||||
|
#975 = PLANE('',#976);
|
||||||
|
#976 = AXIS2_PLACEMENT_3D('',#977,#978,#979);
|
||||||
|
#977 = CARTESIAN_POINT('',(2.325,-1.,2.15));
|
||||||
|
#978 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#979 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#980 = DEFINITIONAL_REPRESENTATION('',(#981),#985);
|
||||||
|
#981 = LINE('',#982,#983);
|
||||||
|
#982 = CARTESIAN_POINT('',(4.3,0.));
|
||||||
|
#983 = VECTOR('',#984,1.);
|
||||||
|
#984 = DIRECTION('',(0.,-1.));
|
||||||
|
#985 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#986 = ORIENTED_EDGE('',*,*,#987,.T.);
|
||||||
|
#987 = EDGE_CURVE('',#960,#988,#990,.T.);
|
||||||
|
#988 = VERTEX_POINT('',#989);
|
||||||
|
#989 = CARTESIAN_POINT('',(2.075,1.,6.45));
|
||||||
|
#990 = SURFACE_CURVE('',#991,(#996,#1003),.PCURVE_S1.);
|
||||||
|
#991 = CIRCLE('',#992,0.25);
|
||||||
|
#992 = AXIS2_PLACEMENT_3D('',#993,#994,#995);
|
||||||
|
#993 = CARTESIAN_POINT('',(2.075,0.75,6.45));
|
||||||
|
#994 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#995 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#996 = PCURVE('',#776,#997);
|
||||||
|
#997 = DEFINITIONAL_REPRESENTATION('',(#998),#1002);
|
||||||
|
#998 = CIRCLE('',#999,0.25);
|
||||||
|
#999 = AXIS2_PLACEMENT_2D('',#1000,#1001);
|
||||||
|
#1000 = CARTESIAN_POINT('',(4.4,1.75));
|
||||||
|
#1001 = DIRECTION('',(0.,-1.));
|
||||||
|
#1002 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1003 = PCURVE('',#1004,#1009);
|
||||||
|
#1004 = CYLINDRICAL_SURFACE('',#1005,0.25);
|
||||||
|
#1005 = AXIS2_PLACEMENT_3D('',#1006,#1007,#1008);
|
||||||
|
#1006 = CARTESIAN_POINT('',(2.075,0.75,2.15));
|
||||||
|
#1007 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1008 = DIRECTION('',(1.,0.,-0.));
|
||||||
|
#1009 = DEFINITIONAL_REPRESENTATION('',(#1010),#1014);
|
||||||
|
#1010 = LINE('',#1011,#1012);
|
||||||
|
#1011 = CARTESIAN_POINT('',(-1.570796326795,4.3));
|
||||||
|
#1012 = VECTOR('',#1013,1.);
|
||||||
|
#1013 = DIRECTION('',(1.,0.));
|
||||||
|
#1014 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1015 = ORIENTED_EDGE('',*,*,#1016,.F.);
|
||||||
|
#1016 = EDGE_CURVE('',#1017,#988,#1019,.T.);
|
||||||
|
#1017 = VERTEX_POINT('',#1018);
|
||||||
|
#1018 = CARTESIAN_POINT('',(-2.075,1.,6.45));
|
||||||
|
#1019 = SURFACE_CURVE('',#1020,(#1024,#1031),.PCURVE_S1.);
|
||||||
|
#1020 = LINE('',#1021,#1022);
|
||||||
|
#1021 = CARTESIAN_POINT('',(-2.325,1.,6.45));
|
||||||
|
#1022 = VECTOR('',#1023,1.);
|
||||||
|
#1023 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1024 = PCURVE('',#776,#1025);
|
||||||
|
#1025 = DEFINITIONAL_REPRESENTATION('',(#1026),#1030);
|
||||||
|
#1026 = LINE('',#1027,#1028);
|
||||||
|
#1027 = CARTESIAN_POINT('',(0.,2.));
|
||||||
|
#1028 = VECTOR('',#1029,1.);
|
||||||
|
#1029 = DIRECTION('',(1.,0.));
|
||||||
|
#1030 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1031 = PCURVE('',#1032,#1037);
|
||||||
|
#1032 = PLANE('',#1033);
|
||||||
|
#1033 = AXIS2_PLACEMENT_3D('',#1034,#1035,#1036);
|
||||||
|
#1034 = CARTESIAN_POINT('',(-2.325,1.,2.15));
|
||||||
|
#1035 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1036 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1037 = DEFINITIONAL_REPRESENTATION('',(#1038),#1042);
|
||||||
|
#1038 = LINE('',#1039,#1040);
|
||||||
|
#1039 = CARTESIAN_POINT('',(4.3,0.));
|
||||||
|
#1040 = VECTOR('',#1041,1.);
|
||||||
|
#1041 = DIRECTION('',(0.,1.));
|
||||||
|
#1042 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1043 = ORIENTED_EDGE('',*,*,#1044,.F.);
|
||||||
|
#1044 = EDGE_CURVE('',#756,#1017,#1045,.T.);
|
||||||
|
#1045 = SURFACE_CURVE('',#1046,(#1051,#1062),.PCURVE_S1.);
|
||||||
|
#1046 = CIRCLE('',#1047,0.25);
|
||||||
|
#1047 = AXIS2_PLACEMENT_3D('',#1048,#1049,#1050);
|
||||||
|
#1048 = CARTESIAN_POINT('',(-2.075,0.75,6.45));
|
||||||
|
#1049 = DIRECTION('',(-0.,-0.,-1.));
|
||||||
|
#1050 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#1051 = PCURVE('',#776,#1052);
|
||||||
|
#1052 = DEFINITIONAL_REPRESENTATION('',(#1053),#1061);
|
||||||
|
#1053 = ( BOUNDED_CURVE() B_SPLINE_CURVE(2,(#1054,#1055,#1056,#1057,
|
||||||
|
#1058,#1059,#1060),.UNSPECIFIED.,.T.,.F.) B_SPLINE_CURVE_WITH_KNOTS((1,2
|
||||||
|
,2,2,2,1),(-2.094395102393,0.,2.094395102393,4.188790204786,
|
||||||
|
6.28318530718,8.377580409573),.UNSPECIFIED.) CURVE()
|
||||||
|
GEOMETRIC_REPRESENTATION_ITEM() RATIONAL_B_SPLINE_CURVE((1.,0.5,1.,0.5,
|
||||||
|
1.,0.5,1.)) REPRESENTATION_ITEM('') );
|
||||||
|
#1054 = CARTESIAN_POINT('',(0.25,1.5));
|
||||||
|
#1055 = CARTESIAN_POINT('',(-0.183012701892,1.5));
|
||||||
|
#1056 = CARTESIAN_POINT('',(3.349364905389E-02,1.875));
|
||||||
|
#1057 = CARTESIAN_POINT('',(0.25,2.25));
|
||||||
|
#1058 = CARTESIAN_POINT('',(0.466506350946,1.875));
|
||||||
|
#1059 = CARTESIAN_POINT('',(0.683012701892,1.5));
|
||||||
|
#1060 = CARTESIAN_POINT('',(0.25,1.5));
|
||||||
|
#1061 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1062 = PCURVE('',#858,#1063);
|
||||||
|
#1063 = DEFINITIONAL_REPRESENTATION('',(#1064),#1068);
|
||||||
|
#1064 = LINE('',#1065,#1066);
|
||||||
|
#1065 = CARTESIAN_POINT('',(1.570796326795,4.3));
|
||||||
|
#1066 = VECTOR('',#1067,1.);
|
||||||
|
#1067 = DIRECTION('',(-1.,0.));
|
||||||
|
#1068 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1069 = ADVANCED_FACE('',(#1070),#804,.T.);
|
||||||
|
#1070 = FACE_BOUND('',#1071,.T.);
|
||||||
|
#1071 = EDGE_LOOP('',(#1072,#1096,#1117,#1118));
|
||||||
|
#1072 = ORIENTED_EDGE('',*,*,#1073,.T.);
|
||||||
|
#1073 = EDGE_CURVE('',#789,#1074,#1076,.T.);
|
||||||
|
#1074 = VERTEX_POINT('',#1075);
|
||||||
|
#1075 = CARTESIAN_POINT('',(-2.075,-1.,2.15));
|
||||||
|
#1076 = SURFACE_CURVE('',#1077,(#1082,#1089),.PCURVE_S1.);
|
||||||
|
#1077 = CIRCLE('',#1078,0.25);
|
||||||
|
#1078 = AXIS2_PLACEMENT_3D('',#1079,#1080,#1081);
|
||||||
|
#1079 = CARTESIAN_POINT('',(-2.075,-0.75,2.15));
|
||||||
|
#1080 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1081 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#1082 = PCURVE('',#804,#1083);
|
||||||
|
#1083 = DEFINITIONAL_REPRESENTATION('',(#1084),#1088);
|
||||||
|
#1084 = LINE('',#1085,#1086);
|
||||||
|
#1085 = CARTESIAN_POINT('',(-4.712388980385,0.));
|
||||||
|
#1086 = VECTOR('',#1087,1.);
|
||||||
|
#1087 = DIRECTION('',(1.,0.));
|
||||||
|
#1088 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1089 = PCURVE('',#832,#1090);
|
||||||
|
#1090 = DEFINITIONAL_REPRESENTATION('',(#1091),#1095);
|
||||||
|
#1091 = CIRCLE('',#1092,0.25);
|
||||||
|
#1092 = AXIS2_PLACEMENT_2D('',#1093,#1094);
|
||||||
|
#1093 = CARTESIAN_POINT('',(0.25,0.25));
|
||||||
|
#1094 = DIRECTION('',(0.,-1.));
|
||||||
|
#1095 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1096 = ORIENTED_EDGE('',*,*,#1097,.T.);
|
||||||
|
#1097 = EDGE_CURVE('',#1074,#875,#1098,.T.);
|
||||||
|
#1098 = SURFACE_CURVE('',#1099,(#1103,#1110),.PCURVE_S1.);
|
||||||
|
#1099 = LINE('',#1100,#1101);
|
||||||
|
#1100 = CARTESIAN_POINT('',(-2.075,-1.,2.15));
|
||||||
|
#1101 = VECTOR('',#1102,1.);
|
||||||
|
#1102 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1103 = PCURVE('',#804,#1104);
|
||||||
|
#1104 = DEFINITIONAL_REPRESENTATION('',(#1105),#1109);
|
||||||
|
#1105 = LINE('',#1106,#1107);
|
||||||
|
#1106 = CARTESIAN_POINT('',(1.570796326795,0.));
|
||||||
|
#1107 = VECTOR('',#1108,1.);
|
||||||
|
#1108 = DIRECTION('',(0.,1.));
|
||||||
|
#1109 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1110 = PCURVE('',#914,#1111);
|
||||||
|
#1111 = DEFINITIONAL_REPRESENTATION('',(#1112),#1116);
|
||||||
|
#1112 = LINE('',#1113,#1114);
|
||||||
|
#1113 = CARTESIAN_POINT('',(0.,0.25));
|
||||||
|
#1114 = VECTOR('',#1115,1.);
|
||||||
|
#1115 = DIRECTION('',(1.,0.));
|
||||||
|
#1116 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1117 = ORIENTED_EDGE('',*,*,#874,.F.);
|
||||||
|
#1118 = ORIENTED_EDGE('',*,*,#788,.F.);
|
||||||
|
#1119 = ADVANCED_FACE('',(#1120),#858,.T.);
|
||||||
|
#1120 = FACE_BOUND('',#1121,.F.);
|
||||||
|
#1121 = EDGE_LOOP('',(#1122,#1150,#1171,#1172));
|
||||||
|
#1122 = ORIENTED_EDGE('',*,*,#1123,.T.);
|
||||||
|
#1123 = EDGE_CURVE('',#817,#1124,#1126,.T.);
|
||||||
|
#1124 = VERTEX_POINT('',#1125);
|
||||||
|
#1125 = CARTESIAN_POINT('',(-2.075,1.,2.15));
|
||||||
|
#1126 = SURFACE_CURVE('',#1127,(#1132,#1139),.PCURVE_S1.);
|
||||||
|
#1127 = CIRCLE('',#1128,0.25);
|
||||||
|
#1128 = AXIS2_PLACEMENT_3D('',#1129,#1130,#1131);
|
||||||
|
#1129 = CARTESIAN_POINT('',(-2.075,0.75,2.15));
|
||||||
|
#1130 = DIRECTION('',(-0.,-0.,-1.));
|
||||||
|
#1131 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#1132 = PCURVE('',#858,#1133);
|
||||||
|
#1133 = DEFINITIONAL_REPRESENTATION('',(#1134),#1138);
|
||||||
|
#1134 = LINE('',#1135,#1136);
|
||||||
|
#1135 = CARTESIAN_POINT('',(1.570796326795,-0.));
|
||||||
|
#1136 = VECTOR('',#1137,1.);
|
||||||
|
#1137 = DIRECTION('',(-1.,0.));
|
||||||
|
#1138 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1139 = PCURVE('',#832,#1140);
|
||||||
|
#1140 = DEFINITIONAL_REPRESENTATION('',(#1141),#1149);
|
||||||
|
#1141 = ( BOUNDED_CURVE() B_SPLINE_CURVE(2,(#1142,#1143,#1144,#1145,
|
||||||
|
#1146,#1147,#1148),.UNSPECIFIED.,.T.,.F.) B_SPLINE_CURVE_WITH_KNOTS((1,2
|
||||||
|
,2,2,2,1),(-2.094395102393,0.,2.094395102393,4.188790204786,
|
||||||
|
6.28318530718,8.377580409573),.UNSPECIFIED.) CURVE()
|
||||||
|
GEOMETRIC_REPRESENTATION_ITEM() RATIONAL_B_SPLINE_CURVE((1.,0.5,1.,0.5,
|
||||||
|
1.,0.5,1.)) REPRESENTATION_ITEM('') );
|
||||||
|
#1142 = CARTESIAN_POINT('',(0.25,1.5));
|
||||||
|
#1143 = CARTESIAN_POINT('',(-0.183012701892,1.5));
|
||||||
|
#1144 = CARTESIAN_POINT('',(3.349364905389E-02,1.875));
|
||||||
|
#1145 = CARTESIAN_POINT('',(0.25,2.25));
|
||||||
|
#1146 = CARTESIAN_POINT('',(0.466506350946,1.875));
|
||||||
|
#1147 = CARTESIAN_POINT('',(0.683012701892,1.5));
|
||||||
|
#1148 = CARTESIAN_POINT('',(0.25,1.5));
|
||||||
|
#1149 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1150 = ORIENTED_EDGE('',*,*,#1151,.T.);
|
||||||
|
#1151 = EDGE_CURVE('',#1124,#1017,#1152,.T.);
|
||||||
|
#1152 = SURFACE_CURVE('',#1153,(#1157,#1164),.PCURVE_S1.);
|
||||||
|
#1153 = LINE('',#1154,#1155);
|
||||||
|
#1154 = CARTESIAN_POINT('',(-2.075,1.,2.15));
|
||||||
|
#1155 = VECTOR('',#1156,1.);
|
||||||
|
#1156 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1157 = PCURVE('',#858,#1158);
|
||||||
|
#1158 = DEFINITIONAL_REPRESENTATION('',(#1159),#1163);
|
||||||
|
#1159 = LINE('',#1160,#1161);
|
||||||
|
#1160 = CARTESIAN_POINT('',(-1.570796326795,0.));
|
||||||
|
#1161 = VECTOR('',#1162,1.);
|
||||||
|
#1162 = DIRECTION('',(-0.,1.));
|
||||||
|
#1163 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1164 = PCURVE('',#1032,#1165);
|
||||||
|
#1165 = DEFINITIONAL_REPRESENTATION('',(#1166),#1170);
|
||||||
|
#1166 = LINE('',#1167,#1168);
|
||||||
|
#1167 = CARTESIAN_POINT('',(0.,0.25));
|
||||||
|
#1168 = VECTOR('',#1169,1.);
|
||||||
|
#1169 = DIRECTION('',(1.,0.));
|
||||||
|
#1170 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1171 = ORIENTED_EDGE('',*,*,#1044,.F.);
|
||||||
|
#1172 = ORIENTED_EDGE('',*,*,#844,.F.);
|
||||||
|
#1173 = ADVANCED_FACE('',(#1174),#832,.F.);
|
||||||
|
#1174 = FACE_BOUND('',#1175,.F.);
|
||||||
|
#1175 = EDGE_LOOP('',(#1176,#1177,#1178,#1201,#1229,#1252,#1276,#1297));
|
||||||
|
#1176 = ORIENTED_EDGE('',*,*,#816,.F.);
|
||||||
|
#1177 = ORIENTED_EDGE('',*,*,#1073,.T.);
|
||||||
|
#1178 = ORIENTED_EDGE('',*,*,#1179,.T.);
|
||||||
|
#1179 = EDGE_CURVE('',#1074,#1180,#1182,.T.);
|
||||||
|
#1180 = VERTEX_POINT('',#1181);
|
||||||
|
#1181 = CARTESIAN_POINT('',(2.075,-1.,2.15));
|
||||||
|
#1182 = SURFACE_CURVE('',#1183,(#1187,#1194),.PCURVE_S1.);
|
||||||
|
#1183 = LINE('',#1184,#1185);
|
||||||
|
#1184 = CARTESIAN_POINT('',(-2.325,-1.,2.15));
|
||||||
|
#1185 = VECTOR('',#1186,1.);
|
||||||
|
#1186 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1187 = PCURVE('',#832,#1188);
|
||||||
|
#1188 = DEFINITIONAL_REPRESENTATION('',(#1189),#1193);
|
||||||
|
#1189 = LINE('',#1190,#1191);
|
||||||
|
#1190 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1191 = VECTOR('',#1192,1.);
|
||||||
|
#1192 = DIRECTION('',(1.,0.));
|
||||||
|
#1193 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1194 = PCURVE('',#914,#1195);
|
||||||
|
#1195 = DEFINITIONAL_REPRESENTATION('',(#1196),#1200);
|
||||||
|
#1196 = LINE('',#1197,#1198);
|
||||||
|
#1197 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1198 = VECTOR('',#1199,1.);
|
||||||
|
#1199 = DIRECTION('',(0.,1.));
|
||||||
|
#1200 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1201 = ORIENTED_EDGE('',*,*,#1202,.F.);
|
||||||
|
#1202 = EDGE_CURVE('',#1203,#1180,#1205,.T.);
|
||||||
|
#1203 = VERTEX_POINT('',#1204);
|
||||||
|
#1204 = CARTESIAN_POINT('',(2.325,-0.75,2.15));
|
||||||
|
#1205 = SURFACE_CURVE('',#1206,(#1211,#1222),.PCURVE_S1.);
|
||||||
|
#1206 = CIRCLE('',#1207,0.25);
|
||||||
|
#1207 = AXIS2_PLACEMENT_3D('',#1208,#1209,#1210);
|
||||||
|
#1208 = CARTESIAN_POINT('',(2.075,-0.75,2.15));
|
||||||
|
#1209 = DIRECTION('',(-0.,-0.,-1.));
|
||||||
|
#1210 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#1211 = PCURVE('',#832,#1212);
|
||||||
|
#1212 = DEFINITIONAL_REPRESENTATION('',(#1213),#1221);
|
||||||
|
#1213 = ( BOUNDED_CURVE() B_SPLINE_CURVE(2,(#1214,#1215,#1216,#1217,
|
||||||
|
#1218,#1219,#1220),.UNSPECIFIED.,.T.,.F.) B_SPLINE_CURVE_WITH_KNOTS((1,2
|
||||||
|
,2,2,2,1),(-2.094395102393,0.,2.094395102393,4.188790204786,
|
||||||
|
6.28318530718,8.377580409573),.UNSPECIFIED.) CURVE()
|
||||||
|
GEOMETRIC_REPRESENTATION_ITEM() RATIONAL_B_SPLINE_CURVE((1.,0.5,1.,0.5,
|
||||||
|
1.,0.5,1.)) REPRESENTATION_ITEM('') );
|
||||||
|
#1214 = CARTESIAN_POINT('',(4.4,0.));
|
||||||
|
#1215 = CARTESIAN_POINT('',(3.966987298108,0.));
|
||||||
|
#1216 = CARTESIAN_POINT('',(4.183493649054,0.375));
|
||||||
|
#1217 = CARTESIAN_POINT('',(4.4,0.75));
|
||||||
|
#1218 = CARTESIAN_POINT('',(4.616506350946,0.375));
|
||||||
|
#1219 = CARTESIAN_POINT('',(4.833012701892,3.885780586188E-16));
|
||||||
|
#1220 = CARTESIAN_POINT('',(4.4,0.));
|
||||||
|
#1221 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1222 = PCURVE('',#947,#1223);
|
||||||
|
#1223 = DEFINITIONAL_REPRESENTATION('',(#1224),#1228);
|
||||||
|
#1224 = LINE('',#1225,#1226);
|
||||||
|
#1225 = CARTESIAN_POINT('',(4.712388980385,-0.));
|
||||||
|
#1226 = VECTOR('',#1227,1.);
|
||||||
|
#1227 = DIRECTION('',(-1.,0.));
|
||||||
|
#1228 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1229 = ORIENTED_EDGE('',*,*,#1230,.T.);
|
||||||
|
#1230 = EDGE_CURVE('',#1203,#1231,#1233,.T.);
|
||||||
|
#1231 = VERTEX_POINT('',#1232);
|
||||||
|
#1232 = CARTESIAN_POINT('',(2.325,0.75,2.15));
|
||||||
|
#1233 = SURFACE_CURVE('',#1234,(#1238,#1245),.PCURVE_S1.);
|
||||||
|
#1234 = LINE('',#1235,#1236);
|
||||||
|
#1235 = CARTESIAN_POINT('',(2.325,-1.,2.15));
|
||||||
|
#1236 = VECTOR('',#1237,1.);
|
||||||
|
#1237 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1238 = PCURVE('',#832,#1239);
|
||||||
|
#1239 = DEFINITIONAL_REPRESENTATION('',(#1240),#1244);
|
||||||
|
#1240 = LINE('',#1241,#1242);
|
||||||
|
#1241 = CARTESIAN_POINT('',(4.65,0.));
|
||||||
|
#1242 = VECTOR('',#1243,1.);
|
||||||
|
#1243 = DIRECTION('',(0.,1.));
|
||||||
|
#1244 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1245 = PCURVE('',#975,#1246);
|
||||||
|
#1246 = DEFINITIONAL_REPRESENTATION('',(#1247),#1251);
|
||||||
|
#1247 = LINE('',#1248,#1249);
|
||||||
|
#1248 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1249 = VECTOR('',#1250,1.);
|
||||||
|
#1250 = DIRECTION('',(0.,-1.));
|
||||||
|
#1251 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1252 = ORIENTED_EDGE('',*,*,#1253,.T.);
|
||||||
|
#1253 = EDGE_CURVE('',#1231,#1254,#1256,.T.);
|
||||||
|
#1254 = VERTEX_POINT('',#1255);
|
||||||
|
#1255 = CARTESIAN_POINT('',(2.075,1.,2.15));
|
||||||
|
#1256 = SURFACE_CURVE('',#1257,(#1262,#1269),.PCURVE_S1.);
|
||||||
|
#1257 = CIRCLE('',#1258,0.25);
|
||||||
|
#1258 = AXIS2_PLACEMENT_3D('',#1259,#1260,#1261);
|
||||||
|
#1259 = CARTESIAN_POINT('',(2.075,0.75,2.15));
|
||||||
|
#1260 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1261 = DIRECTION('',(0.,-1.,0.));
|
||||||
|
#1262 = PCURVE('',#832,#1263);
|
||||||
|
#1263 = DEFINITIONAL_REPRESENTATION('',(#1264),#1268);
|
||||||
|
#1264 = CIRCLE('',#1265,0.25);
|
||||||
|
#1265 = AXIS2_PLACEMENT_2D('',#1266,#1267);
|
||||||
|
#1266 = CARTESIAN_POINT('',(4.4,1.75));
|
||||||
|
#1267 = DIRECTION('',(0.,-1.));
|
||||||
|
#1268 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1269 = PCURVE('',#1004,#1270);
|
||||||
|
#1270 = DEFINITIONAL_REPRESENTATION('',(#1271),#1275);
|
||||||
|
#1271 = LINE('',#1272,#1273);
|
||||||
|
#1272 = CARTESIAN_POINT('',(-1.570796326795,0.));
|
||||||
|
#1273 = VECTOR('',#1274,1.);
|
||||||
|
#1274 = DIRECTION('',(1.,0.));
|
||||||
|
#1275 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1276 = ORIENTED_EDGE('',*,*,#1277,.F.);
|
||||||
|
#1277 = EDGE_CURVE('',#1124,#1254,#1278,.T.);
|
||||||
|
#1278 = SURFACE_CURVE('',#1279,(#1283,#1290),.PCURVE_S1.);
|
||||||
|
#1279 = LINE('',#1280,#1281);
|
||||||
|
#1280 = CARTESIAN_POINT('',(-2.325,1.,2.15));
|
||||||
|
#1281 = VECTOR('',#1282,1.);
|
||||||
|
#1282 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1283 = PCURVE('',#832,#1284);
|
||||||
|
#1284 = DEFINITIONAL_REPRESENTATION('',(#1285),#1289);
|
||||||
|
#1285 = LINE('',#1286,#1287);
|
||||||
|
#1286 = CARTESIAN_POINT('',(0.,2.));
|
||||||
|
#1287 = VECTOR('',#1288,1.);
|
||||||
|
#1288 = DIRECTION('',(1.,0.));
|
||||||
|
#1289 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1290 = PCURVE('',#1032,#1291);
|
||||||
|
#1291 = DEFINITIONAL_REPRESENTATION('',(#1292),#1296);
|
||||||
|
#1292 = LINE('',#1293,#1294);
|
||||||
|
#1293 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1294 = VECTOR('',#1295,1.);
|
||||||
|
#1295 = DIRECTION('',(0.,1.));
|
||||||
|
#1296 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1297 = ORIENTED_EDGE('',*,*,#1123,.F.);
|
||||||
|
#1298 = ADVANCED_FACE('',(#1299),#914,.F.);
|
||||||
|
#1299 = FACE_BOUND('',#1300,.F.);
|
||||||
|
#1300 = EDGE_LOOP('',(#1301,#1302,#1303,#1304));
|
||||||
|
#1301 = ORIENTED_EDGE('',*,*,#1179,.F.);
|
||||||
|
#1302 = ORIENTED_EDGE('',*,*,#1097,.T.);
|
||||||
|
#1303 = ORIENTED_EDGE('',*,*,#898,.T.);
|
||||||
|
#1304 = ORIENTED_EDGE('',*,*,#1305,.F.);
|
||||||
|
#1305 = EDGE_CURVE('',#1180,#899,#1306,.T.);
|
||||||
|
#1306 = SURFACE_CURVE('',#1307,(#1311,#1318),.PCURVE_S1.);
|
||||||
|
#1307 = LINE('',#1308,#1309);
|
||||||
|
#1308 = CARTESIAN_POINT('',(2.075,-1.,2.15));
|
||||||
|
#1309 = VECTOR('',#1310,1.);
|
||||||
|
#1310 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1311 = PCURVE('',#914,#1312);
|
||||||
|
#1312 = DEFINITIONAL_REPRESENTATION('',(#1313),#1317);
|
||||||
|
#1313 = LINE('',#1314,#1315);
|
||||||
|
#1314 = CARTESIAN_POINT('',(0.,4.4));
|
||||||
|
#1315 = VECTOR('',#1316,1.);
|
||||||
|
#1316 = DIRECTION('',(1.,0.));
|
||||||
|
#1317 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1318 = PCURVE('',#947,#1319);
|
||||||
|
#1319 = DEFINITIONAL_REPRESENTATION('',(#1320),#1324);
|
||||||
|
#1320 = LINE('',#1321,#1322);
|
||||||
|
#1321 = CARTESIAN_POINT('',(-1.570796326795,0.));
|
||||||
|
#1322 = VECTOR('',#1323,1.);
|
||||||
|
#1323 = DIRECTION('',(-0.,1.));
|
||||||
|
#1324 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1325 = ADVANCED_FACE('',(#1326),#1032,.T.);
|
||||||
|
#1326 = FACE_BOUND('',#1327,.T.);
|
||||||
|
#1327 = EDGE_LOOP('',(#1328,#1329,#1330,#1331));
|
||||||
|
#1328 = ORIENTED_EDGE('',*,*,#1277,.F.);
|
||||||
|
#1329 = ORIENTED_EDGE('',*,*,#1151,.T.);
|
||||||
|
#1330 = ORIENTED_EDGE('',*,*,#1016,.T.);
|
||||||
|
#1331 = ORIENTED_EDGE('',*,*,#1332,.F.);
|
||||||
|
#1332 = EDGE_CURVE('',#1254,#988,#1333,.T.);
|
||||||
|
#1333 = SURFACE_CURVE('',#1334,(#1338,#1345),.PCURVE_S1.);
|
||||||
|
#1334 = LINE('',#1335,#1336);
|
||||||
|
#1335 = CARTESIAN_POINT('',(2.075,1.,2.15));
|
||||||
|
#1336 = VECTOR('',#1337,1.);
|
||||||
|
#1337 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1338 = PCURVE('',#1032,#1339);
|
||||||
|
#1339 = DEFINITIONAL_REPRESENTATION('',(#1340),#1344);
|
||||||
|
#1340 = LINE('',#1341,#1342);
|
||||||
|
#1341 = CARTESIAN_POINT('',(0.,4.4));
|
||||||
|
#1342 = VECTOR('',#1343,1.);
|
||||||
|
#1343 = DIRECTION('',(1.,0.));
|
||||||
|
#1344 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1345 = PCURVE('',#1004,#1346);
|
||||||
|
#1346 = DEFINITIONAL_REPRESENTATION('',(#1347),#1351);
|
||||||
|
#1347 = LINE('',#1348,#1349);
|
||||||
|
#1348 = CARTESIAN_POINT('',(1.570796326795,0.));
|
||||||
|
#1349 = VECTOR('',#1350,1.);
|
||||||
|
#1350 = DIRECTION('',(0.,1.));
|
||||||
|
#1351 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1352 = ADVANCED_FACE('',(#1353),#947,.T.);
|
||||||
|
#1353 = FACE_BOUND('',#1354,.F.);
|
||||||
|
#1354 = EDGE_LOOP('',(#1355,#1356,#1357,#1358));
|
||||||
|
#1355 = ORIENTED_EDGE('',*,*,#1202,.T.);
|
||||||
|
#1356 = ORIENTED_EDGE('',*,*,#1305,.T.);
|
||||||
|
#1357 = ORIENTED_EDGE('',*,*,#926,.F.);
|
||||||
|
#1358 = ORIENTED_EDGE('',*,*,#1359,.F.);
|
||||||
|
#1359 = EDGE_CURVE('',#1203,#927,#1360,.T.);
|
||||||
|
#1360 = SURFACE_CURVE('',#1361,(#1365,#1372),.PCURVE_S1.);
|
||||||
|
#1361 = LINE('',#1362,#1363);
|
||||||
|
#1362 = CARTESIAN_POINT('',(2.325,-0.75,2.15));
|
||||||
|
#1363 = VECTOR('',#1364,1.);
|
||||||
|
#1364 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1365 = PCURVE('',#947,#1366);
|
||||||
|
#1366 = DEFINITIONAL_REPRESENTATION('',(#1367),#1371);
|
||||||
|
#1367 = LINE('',#1368,#1369);
|
||||||
|
#1368 = CARTESIAN_POINT('',(-0.,0.));
|
||||||
|
#1369 = VECTOR('',#1370,1.);
|
||||||
|
#1370 = DIRECTION('',(-0.,1.));
|
||||||
|
#1371 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1372 = PCURVE('',#975,#1373);
|
||||||
|
#1373 = DEFINITIONAL_REPRESENTATION('',(#1374),#1378);
|
||||||
|
#1374 = LINE('',#1375,#1376);
|
||||||
|
#1375 = CARTESIAN_POINT('',(0.,-0.25));
|
||||||
|
#1376 = VECTOR('',#1377,1.);
|
||||||
|
#1377 = DIRECTION('',(1.,0.));
|
||||||
|
#1378 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1379 = ADVANCED_FACE('',(#1380),#1004,.T.);
|
||||||
|
#1380 = FACE_BOUND('',#1381,.T.);
|
||||||
|
#1381 = EDGE_LOOP('',(#1382,#1383,#1384,#1385));
|
||||||
|
#1382 = ORIENTED_EDGE('',*,*,#1253,.T.);
|
||||||
|
#1383 = ORIENTED_EDGE('',*,*,#1332,.T.);
|
||||||
|
#1384 = ORIENTED_EDGE('',*,*,#987,.F.);
|
||||||
|
#1385 = ORIENTED_EDGE('',*,*,#1386,.F.);
|
||||||
|
#1386 = EDGE_CURVE('',#1231,#960,#1387,.T.);
|
||||||
|
#1387 = SURFACE_CURVE('',#1388,(#1392,#1399),.PCURVE_S1.);
|
||||||
|
#1388 = LINE('',#1389,#1390);
|
||||||
|
#1389 = CARTESIAN_POINT('',(2.325,0.75,2.15));
|
||||||
|
#1390 = VECTOR('',#1391,1.);
|
||||||
|
#1391 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1392 = PCURVE('',#1004,#1393);
|
||||||
|
#1393 = DEFINITIONAL_REPRESENTATION('',(#1394),#1398);
|
||||||
|
#1394 = LINE('',#1395,#1396);
|
||||||
|
#1395 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1396 = VECTOR('',#1397,1.);
|
||||||
|
#1397 = DIRECTION('',(0.,1.));
|
||||||
|
#1398 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1399 = PCURVE('',#975,#1400);
|
||||||
|
#1400 = DEFINITIONAL_REPRESENTATION('',(#1401),#1405);
|
||||||
|
#1401 = LINE('',#1402,#1403);
|
||||||
|
#1402 = CARTESIAN_POINT('',(0.,-1.75));
|
||||||
|
#1403 = VECTOR('',#1404,1.);
|
||||||
|
#1404 = DIRECTION('',(1.,0.));
|
||||||
|
#1405 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1406 = ADVANCED_FACE('',(#1407),#975,.T.);
|
||||||
|
#1407 = FACE_BOUND('',#1408,.T.);
|
||||||
|
#1408 = EDGE_LOOP('',(#1409,#1410,#1411,#1412));
|
||||||
|
#1409 = ORIENTED_EDGE('',*,*,#959,.F.);
|
||||||
|
#1410 = ORIENTED_EDGE('',*,*,#1359,.F.);
|
||||||
|
#1411 = ORIENTED_EDGE('',*,*,#1230,.T.);
|
||||||
|
#1412 = ORIENTED_EDGE('',*,*,#1386,.T.);
|
||||||
|
#1413 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#1417))
|
||||||
|
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1414,#1415,#1416)) REPRESENTATION_CONTEXT
|
||||||
|
('Context #1','3D Context with UNIT and UNCERTAINTY') );
|
||||||
|
#1414 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
|
||||||
|
#1415 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
|
||||||
|
#1416 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
|
||||||
|
#1417 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#1414,
|
||||||
|
'distance_accuracy_value','confusion accuracy');
|
||||||
|
#1418 = CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#1419,#1421);
|
||||||
|
#1419 = ( REPRESENTATION_RELATIONSHIP('','',#746,#10)
|
||||||
|
REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#1420)
|
||||||
|
SHAPE_REPRESENTATION_RELATIONSHIP() );
|
||||||
|
#1420 = ITEM_DEFINED_TRANSFORMATION('','',#11,#23);
|
||||||
|
#1421 = PRODUCT_DEFINITION_SHAPE('Placement','Placement of an item',
|
||||||
|
#1422);
|
||||||
|
#1422 = NEXT_ASSEMBLY_USAGE_OCCURRENCE('58',
|
||||||
|
'3650c6ce-93c7-11f1-9448-04bad62a3558','',#5,#741,$);
|
||||||
|
#1423 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#743));
|
||||||
|
#1424 = SHAPE_DEFINITION_REPRESENTATION(#1425,#1431);
|
||||||
|
#1425 = PRODUCT_DEFINITION_SHAPE('','',#1426);
|
||||||
|
#1426 = PRODUCT_DEFINITION('design','',#1427,#1430);
|
||||||
|
#1427 = PRODUCT_DEFINITION_FORMATION('','',#1428);
|
||||||
|
#1428 = PRODUCT('365114ab-93c7-11f1-8c4c-04bad62a3558',
|
||||||
|
'365114ab-93c7-11f1-8c4c-04bad62a3558','',(#1429));
|
||||||
|
#1429 = PRODUCT_CONTEXT('',#2,'mechanical');
|
||||||
|
#1430 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
|
||||||
|
#1431 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#1432),#1762);
|
||||||
|
#1432 = MANIFOLD_SOLID_BREP('',#1433);
|
||||||
|
#1433 = CLOSED_SHELL('',(#1434,#1554,#1654,#1701,#1748,#1755));
|
||||||
|
#1434 = ADVANCED_FACE('',(#1435),#1449,.F.);
|
||||||
|
#1435 = FACE_BOUND('',#1436,.F.);
|
||||||
|
#1436 = EDGE_LOOP('',(#1437,#1472,#1500,#1528));
|
||||||
|
#1437 = ORIENTED_EDGE('',*,*,#1438,.F.);
|
||||||
|
#1438 = EDGE_CURVE('',#1439,#1441,#1443,.T.);
|
||||||
|
#1439 = VERTEX_POINT('',#1440);
|
||||||
|
#1440 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1441 = VERTEX_POINT('',#1442);
|
||||||
|
#1442 = CARTESIAN_POINT('',(-1.5,-0.95,5.8));
|
||||||
|
#1443 = SURFACE_CURVE('',#1444,(#1448,#1460),.PCURVE_S1.);
|
||||||
|
#1444 = LINE('',#1445,#1446);
|
||||||
|
#1445 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1446 = VECTOR('',#1447,1.);
|
||||||
|
#1447 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1448 = PCURVE('',#1449,#1454);
|
||||||
|
#1449 = PLANE('',#1450);
|
||||||
|
#1450 = AXIS2_PLACEMENT_3D('',#1451,#1452,#1453);
|
||||||
|
#1451 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1452 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1453 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1454 = DEFINITIONAL_REPRESENTATION('',(#1455),#1459);
|
||||||
|
#1455 = LINE('',#1456,#1457);
|
||||||
|
#1456 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1457 = VECTOR('',#1458,1.);
|
||||||
|
#1458 = DIRECTION('',(1.,0.));
|
||||||
|
#1459 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1460 = PCURVE('',#1461,#1466);
|
||||||
|
#1461 = PLANE('',#1462);
|
||||||
|
#1462 = AXIS2_PLACEMENT_3D('',#1463,#1464,#1465);
|
||||||
|
#1463 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1464 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1465 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1466 = DEFINITIONAL_REPRESENTATION('',(#1467),#1471);
|
||||||
|
#1467 = LINE('',#1468,#1469);
|
||||||
|
#1468 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1469 = VECTOR('',#1470,1.);
|
||||||
|
#1470 = DIRECTION('',(1.,0.));
|
||||||
|
#1471 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1472 = ORIENTED_EDGE('',*,*,#1473,.T.);
|
||||||
|
#1473 = EDGE_CURVE('',#1439,#1474,#1476,.T.);
|
||||||
|
#1474 = VERTEX_POINT('',#1475);
|
||||||
|
#1475 = CARTESIAN_POINT('',(-1.5,-0.83,2.8));
|
||||||
|
#1476 = SURFACE_CURVE('',#1477,(#1481,#1488),.PCURVE_S1.);
|
||||||
|
#1477 = LINE('',#1478,#1479);
|
||||||
|
#1478 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1479 = VECTOR('',#1480,1.);
|
||||||
|
#1480 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1481 = PCURVE('',#1449,#1482);
|
||||||
|
#1482 = DEFINITIONAL_REPRESENTATION('',(#1483),#1487);
|
||||||
|
#1483 = LINE('',#1484,#1485);
|
||||||
|
#1484 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1485 = VECTOR('',#1486,1.);
|
||||||
|
#1486 = DIRECTION('',(0.,-1.));
|
||||||
|
#1487 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1488 = PCURVE('',#1489,#1494);
|
||||||
|
#1489 = PLANE('',#1490);
|
||||||
|
#1490 = AXIS2_PLACEMENT_3D('',#1491,#1492,#1493);
|
||||||
|
#1491 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1492 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1493 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1494 = DEFINITIONAL_REPRESENTATION('',(#1495),#1499);
|
||||||
|
#1495 = LINE('',#1496,#1497);
|
||||||
|
#1496 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1497 = VECTOR('',#1498,1.);
|
||||||
|
#1498 = DIRECTION('',(0.,1.));
|
||||||
|
#1499 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1500 = ORIENTED_EDGE('',*,*,#1501,.T.);
|
||||||
|
#1501 = EDGE_CURVE('',#1474,#1502,#1504,.T.);
|
||||||
|
#1502 = VERTEX_POINT('',#1503);
|
||||||
|
#1503 = CARTESIAN_POINT('',(-1.5,-0.83,5.8));
|
||||||
|
#1504 = SURFACE_CURVE('',#1505,(#1509,#1516),.PCURVE_S1.);
|
||||||
|
#1505 = LINE('',#1506,#1507);
|
||||||
|
#1506 = CARTESIAN_POINT('',(-1.5,-0.83,2.8));
|
||||||
|
#1507 = VECTOR('',#1508,1.);
|
||||||
|
#1508 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1509 = PCURVE('',#1449,#1510);
|
||||||
|
#1510 = DEFINITIONAL_REPRESENTATION('',(#1511),#1515);
|
||||||
|
#1511 = LINE('',#1512,#1513);
|
||||||
|
#1512 = CARTESIAN_POINT('',(0.,-0.12));
|
||||||
|
#1513 = VECTOR('',#1514,1.);
|
||||||
|
#1514 = DIRECTION('',(1.,0.));
|
||||||
|
#1515 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1516 = PCURVE('',#1517,#1522);
|
||||||
|
#1517 = PLANE('',#1518);
|
||||||
|
#1518 = AXIS2_PLACEMENT_3D('',#1519,#1520,#1521);
|
||||||
|
#1519 = CARTESIAN_POINT('',(-1.5,-0.83,2.8));
|
||||||
|
#1520 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1521 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1522 = DEFINITIONAL_REPRESENTATION('',(#1523),#1527);
|
||||||
|
#1523 = LINE('',#1524,#1525);
|
||||||
|
#1524 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1525 = VECTOR('',#1526,1.);
|
||||||
|
#1526 = DIRECTION('',(1.,0.));
|
||||||
|
#1527 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1528 = ORIENTED_EDGE('',*,*,#1529,.F.);
|
||||||
|
#1529 = EDGE_CURVE('',#1441,#1502,#1530,.T.);
|
||||||
|
#1530 = SURFACE_CURVE('',#1531,(#1535,#1542),.PCURVE_S1.);
|
||||||
|
#1531 = LINE('',#1532,#1533);
|
||||||
|
#1532 = CARTESIAN_POINT('',(-1.5,-0.95,5.8));
|
||||||
|
#1533 = VECTOR('',#1534,1.);
|
||||||
|
#1534 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1535 = PCURVE('',#1449,#1536);
|
||||||
|
#1536 = DEFINITIONAL_REPRESENTATION('',(#1537),#1541);
|
||||||
|
#1537 = LINE('',#1538,#1539);
|
||||||
|
#1538 = CARTESIAN_POINT('',(3.,0.));
|
||||||
|
#1539 = VECTOR('',#1540,1.);
|
||||||
|
#1540 = DIRECTION('',(0.,-1.));
|
||||||
|
#1541 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1542 = PCURVE('',#1543,#1548);
|
||||||
|
#1543 = PLANE('',#1544);
|
||||||
|
#1544 = AXIS2_PLACEMENT_3D('',#1545,#1546,#1547);
|
||||||
|
#1545 = CARTESIAN_POINT('',(-1.5,-0.95,5.8));
|
||||||
|
#1546 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1547 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1548 = DEFINITIONAL_REPRESENTATION('',(#1549),#1553);
|
||||||
|
#1549 = LINE('',#1550,#1551);
|
||||||
|
#1550 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1551 = VECTOR('',#1552,1.);
|
||||||
|
#1552 = DIRECTION('',(0.,1.));
|
||||||
|
#1553 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1554 = ADVANCED_FACE('',(#1555),#1569,.T.);
|
||||||
|
#1555 = FACE_BOUND('',#1556,.T.);
|
||||||
|
#1556 = EDGE_LOOP('',(#1557,#1587,#1610,#1633));
|
||||||
|
#1557 = ORIENTED_EDGE('',*,*,#1558,.F.);
|
||||||
|
#1558 = EDGE_CURVE('',#1559,#1561,#1563,.T.);
|
||||||
|
#1559 = VERTEX_POINT('',#1560);
|
||||||
|
#1560 = CARTESIAN_POINT('',(1.5,-0.95,2.8));
|
||||||
|
#1561 = VERTEX_POINT('',#1562);
|
||||||
|
#1562 = CARTESIAN_POINT('',(1.5,-0.95,5.8));
|
||||||
|
#1563 = SURFACE_CURVE('',#1564,(#1568,#1580),.PCURVE_S1.);
|
||||||
|
#1564 = LINE('',#1565,#1566);
|
||||||
|
#1565 = CARTESIAN_POINT('',(1.5,-0.95,2.8));
|
||||||
|
#1566 = VECTOR('',#1567,1.);
|
||||||
|
#1567 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1568 = PCURVE('',#1569,#1574);
|
||||||
|
#1569 = PLANE('',#1570);
|
||||||
|
#1570 = AXIS2_PLACEMENT_3D('',#1571,#1572,#1573);
|
||||||
|
#1571 = CARTESIAN_POINT('',(1.5,-0.95,2.8));
|
||||||
|
#1572 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1573 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1574 = DEFINITIONAL_REPRESENTATION('',(#1575),#1579);
|
||||||
|
#1575 = LINE('',#1576,#1577);
|
||||||
|
#1576 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1577 = VECTOR('',#1578,1.);
|
||||||
|
#1578 = DIRECTION('',(1.,0.));
|
||||||
|
#1579 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1580 = PCURVE('',#1461,#1581);
|
||||||
|
#1581 = DEFINITIONAL_REPRESENTATION('',(#1582),#1586);
|
||||||
|
#1582 = LINE('',#1583,#1584);
|
||||||
|
#1583 = CARTESIAN_POINT('',(0.,3.));
|
||||||
|
#1584 = VECTOR('',#1585,1.);
|
||||||
|
#1585 = DIRECTION('',(1.,0.));
|
||||||
|
#1586 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1587 = ORIENTED_EDGE('',*,*,#1588,.T.);
|
||||||
|
#1588 = EDGE_CURVE('',#1559,#1589,#1591,.T.);
|
||||||
|
#1589 = VERTEX_POINT('',#1590);
|
||||||
|
#1590 = CARTESIAN_POINT('',(1.5,-0.83,2.8));
|
||||||
|
#1591 = SURFACE_CURVE('',#1592,(#1596,#1603),.PCURVE_S1.);
|
||||||
|
#1592 = LINE('',#1593,#1594);
|
||||||
|
#1593 = CARTESIAN_POINT('',(1.5,-0.95,2.8));
|
||||||
|
#1594 = VECTOR('',#1595,1.);
|
||||||
|
#1595 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1596 = PCURVE('',#1569,#1597);
|
||||||
|
#1597 = DEFINITIONAL_REPRESENTATION('',(#1598),#1602);
|
||||||
|
#1598 = LINE('',#1599,#1600);
|
||||||
|
#1599 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1600 = VECTOR('',#1601,1.);
|
||||||
|
#1601 = DIRECTION('',(0.,-1.));
|
||||||
|
#1602 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1603 = PCURVE('',#1489,#1604);
|
||||||
|
#1604 = DEFINITIONAL_REPRESENTATION('',(#1605),#1609);
|
||||||
|
#1605 = LINE('',#1606,#1607);
|
||||||
|
#1606 = CARTESIAN_POINT('',(3.,0.));
|
||||||
|
#1607 = VECTOR('',#1608,1.);
|
||||||
|
#1608 = DIRECTION('',(0.,1.));
|
||||||
|
#1609 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1610 = ORIENTED_EDGE('',*,*,#1611,.T.);
|
||||||
|
#1611 = EDGE_CURVE('',#1589,#1612,#1614,.T.);
|
||||||
|
#1612 = VERTEX_POINT('',#1613);
|
||||||
|
#1613 = CARTESIAN_POINT('',(1.5,-0.83,5.8));
|
||||||
|
#1614 = SURFACE_CURVE('',#1615,(#1619,#1626),.PCURVE_S1.);
|
||||||
|
#1615 = LINE('',#1616,#1617);
|
||||||
|
#1616 = CARTESIAN_POINT('',(1.5,-0.83,2.8));
|
||||||
|
#1617 = VECTOR('',#1618,1.);
|
||||||
|
#1618 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1619 = PCURVE('',#1569,#1620);
|
||||||
|
#1620 = DEFINITIONAL_REPRESENTATION('',(#1621),#1625);
|
||||||
|
#1621 = LINE('',#1622,#1623);
|
||||||
|
#1622 = CARTESIAN_POINT('',(0.,-0.12));
|
||||||
|
#1623 = VECTOR('',#1624,1.);
|
||||||
|
#1624 = DIRECTION('',(1.,0.));
|
||||||
|
#1625 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1626 = PCURVE('',#1517,#1627);
|
||||||
|
#1627 = DEFINITIONAL_REPRESENTATION('',(#1628),#1632);
|
||||||
|
#1628 = LINE('',#1629,#1630);
|
||||||
|
#1629 = CARTESIAN_POINT('',(0.,3.));
|
||||||
|
#1630 = VECTOR('',#1631,1.);
|
||||||
|
#1631 = DIRECTION('',(1.,0.));
|
||||||
|
#1632 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1633 = ORIENTED_EDGE('',*,*,#1634,.F.);
|
||||||
|
#1634 = EDGE_CURVE('',#1561,#1612,#1635,.T.);
|
||||||
|
#1635 = SURFACE_CURVE('',#1636,(#1640,#1647),.PCURVE_S1.);
|
||||||
|
#1636 = LINE('',#1637,#1638);
|
||||||
|
#1637 = CARTESIAN_POINT('',(1.5,-0.95,5.8));
|
||||||
|
#1638 = VECTOR('',#1639,1.);
|
||||||
|
#1639 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1640 = PCURVE('',#1569,#1641);
|
||||||
|
#1641 = DEFINITIONAL_REPRESENTATION('',(#1642),#1646);
|
||||||
|
#1642 = LINE('',#1643,#1644);
|
||||||
|
#1643 = CARTESIAN_POINT('',(3.,0.));
|
||||||
|
#1644 = VECTOR('',#1645,1.);
|
||||||
|
#1645 = DIRECTION('',(0.,-1.));
|
||||||
|
#1646 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1647 = PCURVE('',#1543,#1648);
|
||||||
|
#1648 = DEFINITIONAL_REPRESENTATION('',(#1649),#1653);
|
||||||
|
#1649 = LINE('',#1650,#1651);
|
||||||
|
#1650 = CARTESIAN_POINT('',(3.,0.));
|
||||||
|
#1651 = VECTOR('',#1652,1.);
|
||||||
|
#1652 = DIRECTION('',(0.,1.));
|
||||||
|
#1653 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1654 = ADVANCED_FACE('',(#1655),#1461,.F.);
|
||||||
|
#1655 = FACE_BOUND('',#1656,.F.);
|
||||||
|
#1656 = EDGE_LOOP('',(#1657,#1678,#1679,#1700));
|
||||||
|
#1657 = ORIENTED_EDGE('',*,*,#1658,.F.);
|
||||||
|
#1658 = EDGE_CURVE('',#1439,#1559,#1659,.T.);
|
||||||
|
#1659 = SURFACE_CURVE('',#1660,(#1664,#1671),.PCURVE_S1.);
|
||||||
|
#1660 = LINE('',#1661,#1662);
|
||||||
|
#1661 = CARTESIAN_POINT('',(-1.5,-0.95,2.8));
|
||||||
|
#1662 = VECTOR('',#1663,1.);
|
||||||
|
#1663 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1664 = PCURVE('',#1461,#1665);
|
||||||
|
#1665 = DEFINITIONAL_REPRESENTATION('',(#1666),#1670);
|
||||||
|
#1666 = LINE('',#1667,#1668);
|
||||||
|
#1667 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1668 = VECTOR('',#1669,1.);
|
||||||
|
#1669 = DIRECTION('',(0.,1.));
|
||||||
|
#1670 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1671 = PCURVE('',#1489,#1672);
|
||||||
|
#1672 = DEFINITIONAL_REPRESENTATION('',(#1673),#1677);
|
||||||
|
#1673 = LINE('',#1674,#1675);
|
||||||
|
#1674 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1675 = VECTOR('',#1676,1.);
|
||||||
|
#1676 = DIRECTION('',(1.,0.));
|
||||||
|
#1677 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1678 = ORIENTED_EDGE('',*,*,#1438,.T.);
|
||||||
|
#1679 = ORIENTED_EDGE('',*,*,#1680,.T.);
|
||||||
|
#1680 = EDGE_CURVE('',#1441,#1561,#1681,.T.);
|
||||||
|
#1681 = SURFACE_CURVE('',#1682,(#1686,#1693),.PCURVE_S1.);
|
||||||
|
#1682 = LINE('',#1683,#1684);
|
||||||
|
#1683 = CARTESIAN_POINT('',(-1.5,-0.95,5.8));
|
||||||
|
#1684 = VECTOR('',#1685,1.);
|
||||||
|
#1685 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1686 = PCURVE('',#1461,#1687);
|
||||||
|
#1687 = DEFINITIONAL_REPRESENTATION('',(#1688),#1692);
|
||||||
|
#1688 = LINE('',#1689,#1690);
|
||||||
|
#1689 = CARTESIAN_POINT('',(3.,0.));
|
||||||
|
#1690 = VECTOR('',#1691,1.);
|
||||||
|
#1691 = DIRECTION('',(0.,1.));
|
||||||
|
#1692 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1693 = PCURVE('',#1543,#1694);
|
||||||
|
#1694 = DEFINITIONAL_REPRESENTATION('',(#1695),#1699);
|
||||||
|
#1695 = LINE('',#1696,#1697);
|
||||||
|
#1696 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1697 = VECTOR('',#1698,1.);
|
||||||
|
#1698 = DIRECTION('',(1.,0.));
|
||||||
|
#1699 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1700 = ORIENTED_EDGE('',*,*,#1558,.F.);
|
||||||
|
#1701 = ADVANCED_FACE('',(#1702),#1517,.T.);
|
||||||
|
#1702 = FACE_BOUND('',#1703,.T.);
|
||||||
|
#1703 = EDGE_LOOP('',(#1704,#1725,#1726,#1747));
|
||||||
|
#1704 = ORIENTED_EDGE('',*,*,#1705,.F.);
|
||||||
|
#1705 = EDGE_CURVE('',#1474,#1589,#1706,.T.);
|
||||||
|
#1706 = SURFACE_CURVE('',#1707,(#1711,#1718),.PCURVE_S1.);
|
||||||
|
#1707 = LINE('',#1708,#1709);
|
||||||
|
#1708 = CARTESIAN_POINT('',(-1.5,-0.83,2.8));
|
||||||
|
#1709 = VECTOR('',#1710,1.);
|
||||||
|
#1710 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1711 = PCURVE('',#1517,#1712);
|
||||||
|
#1712 = DEFINITIONAL_REPRESENTATION('',(#1713),#1717);
|
||||||
|
#1713 = LINE('',#1714,#1715);
|
||||||
|
#1714 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1715 = VECTOR('',#1716,1.);
|
||||||
|
#1716 = DIRECTION('',(0.,1.));
|
||||||
|
#1717 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1718 = PCURVE('',#1489,#1719);
|
||||||
|
#1719 = DEFINITIONAL_REPRESENTATION('',(#1720),#1724);
|
||||||
|
#1720 = LINE('',#1721,#1722);
|
||||||
|
#1721 = CARTESIAN_POINT('',(0.,0.12));
|
||||||
|
#1722 = VECTOR('',#1723,1.);
|
||||||
|
#1723 = DIRECTION('',(1.,0.));
|
||||||
|
#1724 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1725 = ORIENTED_EDGE('',*,*,#1501,.T.);
|
||||||
|
#1726 = ORIENTED_EDGE('',*,*,#1727,.T.);
|
||||||
|
#1727 = EDGE_CURVE('',#1502,#1612,#1728,.T.);
|
||||||
|
#1728 = SURFACE_CURVE('',#1729,(#1733,#1740),.PCURVE_S1.);
|
||||||
|
#1729 = LINE('',#1730,#1731);
|
||||||
|
#1730 = CARTESIAN_POINT('',(-1.5,-0.83,5.8));
|
||||||
|
#1731 = VECTOR('',#1732,1.);
|
||||||
|
#1732 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1733 = PCURVE('',#1517,#1734);
|
||||||
|
#1734 = DEFINITIONAL_REPRESENTATION('',(#1735),#1739);
|
||||||
|
#1735 = LINE('',#1736,#1737);
|
||||||
|
#1736 = CARTESIAN_POINT('',(3.,0.));
|
||||||
|
#1737 = VECTOR('',#1738,1.);
|
||||||
|
#1738 = DIRECTION('',(0.,1.));
|
||||||
|
#1739 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1740 = PCURVE('',#1543,#1741);
|
||||||
|
#1741 = DEFINITIONAL_REPRESENTATION('',(#1742),#1746);
|
||||||
|
#1742 = LINE('',#1743,#1744);
|
||||||
|
#1743 = CARTESIAN_POINT('',(0.,0.12));
|
||||||
|
#1744 = VECTOR('',#1745,1.);
|
||||||
|
#1745 = DIRECTION('',(1.,0.));
|
||||||
|
#1746 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1747 = ORIENTED_EDGE('',*,*,#1611,.F.);
|
||||||
|
#1748 = ADVANCED_FACE('',(#1749),#1489,.F.);
|
||||||
|
#1749 = FACE_BOUND('',#1750,.F.);
|
||||||
|
#1750 = EDGE_LOOP('',(#1751,#1752,#1753,#1754));
|
||||||
|
#1751 = ORIENTED_EDGE('',*,*,#1473,.F.);
|
||||||
|
#1752 = ORIENTED_EDGE('',*,*,#1658,.T.);
|
||||||
|
#1753 = ORIENTED_EDGE('',*,*,#1588,.T.);
|
||||||
|
#1754 = ORIENTED_EDGE('',*,*,#1705,.F.);
|
||||||
|
#1755 = ADVANCED_FACE('',(#1756),#1543,.T.);
|
||||||
|
#1756 = FACE_BOUND('',#1757,.T.);
|
||||||
|
#1757 = EDGE_LOOP('',(#1758,#1759,#1760,#1761));
|
||||||
|
#1758 = ORIENTED_EDGE('',*,*,#1529,.F.);
|
||||||
|
#1759 = ORIENTED_EDGE('',*,*,#1680,.T.);
|
||||||
|
#1760 = ORIENTED_EDGE('',*,*,#1634,.T.);
|
||||||
|
#1761 = ORIENTED_EDGE('',*,*,#1727,.F.);
|
||||||
|
#1762 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#1766))
|
||||||
|
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1763,#1764,#1765)) REPRESENTATION_CONTEXT
|
||||||
|
('Context #1','3D Context with UNIT and UNCERTAINTY') );
|
||||||
|
#1763 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
|
||||||
|
#1764 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
|
||||||
|
#1765 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
|
||||||
|
#1766 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#1763,
|
||||||
|
'distance_accuracy_value','confusion accuracy');
|
||||||
|
#1767 = CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#1768,#1770);
|
||||||
|
#1768 = ( REPRESENTATION_RELATIONSHIP('','',#1431,#10)
|
||||||
|
REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#1769)
|
||||||
|
SHAPE_REPRESENTATION_RELATIONSHIP() );
|
||||||
|
#1769 = ITEM_DEFINED_TRANSFORMATION('','',#11,#27);
|
||||||
|
#1770 = PRODUCT_DEFINITION_SHAPE('Placement','Placement of an item',
|
||||||
|
#1771);
|
||||||
|
#1771 = NEXT_ASSEMBLY_USAGE_OCCURRENCE('59',
|
||||||
|
'365114ab-93c7-11f1-8c4c-04bad62a3558','',#5,#1426,$);
|
||||||
|
#1772 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#1428));
|
||||||
|
#1773 = SHAPE_DEFINITION_REPRESENTATION(#1774,#1780);
|
||||||
|
#1774 = PRODUCT_DEFINITION_SHAPE('','',#1775);
|
||||||
|
#1775 = PRODUCT_DEFINITION('design','',#1776,#1779);
|
||||||
|
#1776 = PRODUCT_DEFINITION_FORMATION('','',#1777);
|
||||||
|
#1777 = PRODUCT('36516288-93c7-11f1-ba5d-04bad62a3558',
|
||||||
|
'36516288-93c7-11f1-ba5d-04bad62a3558','',(#1778));
|
||||||
|
#1778 = PRODUCT_CONTEXT('',#2,'mechanical');
|
||||||
|
#1779 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design');
|
||||||
|
#1780 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#1781),#2111);
|
||||||
|
#1781 = MANIFOLD_SOLID_BREP('',#1782);
|
||||||
|
#1782 = CLOSED_SHELL('',(#1783,#1903,#2003,#2050,#2097,#2104));
|
||||||
|
#1783 = ADVANCED_FACE('',(#1784),#1798,.F.);
|
||||||
|
#1784 = FACE_BOUND('',#1785,.F.);
|
||||||
|
#1785 = EDGE_LOOP('',(#1786,#1821,#1849,#1877));
|
||||||
|
#1786 = ORIENTED_EDGE('',*,*,#1787,.F.);
|
||||||
|
#1787 = EDGE_CURVE('',#1788,#1790,#1792,.T.);
|
||||||
|
#1788 = VERTEX_POINT('',#1789);
|
||||||
|
#1789 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#1790 = VERTEX_POINT('',#1791);
|
||||||
|
#1791 = CARTESIAN_POINT('',(-2.27,-1.1,6.05));
|
||||||
|
#1792 = SURFACE_CURVE('',#1793,(#1797,#1809),.PCURVE_S1.);
|
||||||
|
#1793 = LINE('',#1794,#1795);
|
||||||
|
#1794 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#1795 = VECTOR('',#1796,1.);
|
||||||
|
#1796 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1797 = PCURVE('',#1798,#1803);
|
||||||
|
#1798 = PLANE('',#1799);
|
||||||
|
#1799 = AXIS2_PLACEMENT_3D('',#1800,#1801,#1802);
|
||||||
|
#1800 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#1801 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1802 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1803 = DEFINITIONAL_REPRESENTATION('',(#1804),#1808);
|
||||||
|
#1804 = LINE('',#1805,#1806);
|
||||||
|
#1805 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1806 = VECTOR('',#1807,1.);
|
||||||
|
#1807 = DIRECTION('',(1.,0.));
|
||||||
|
#1808 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1809 = PCURVE('',#1810,#1815);
|
||||||
|
#1810 = PLANE('',#1811);
|
||||||
|
#1811 = AXIS2_PLACEMENT_3D('',#1812,#1813,#1814);
|
||||||
|
#1812 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#1813 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1814 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1815 = DEFINITIONAL_REPRESENTATION('',(#1816),#1820);
|
||||||
|
#1816 = LINE('',#1817,#1818);
|
||||||
|
#1817 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1818 = VECTOR('',#1819,1.);
|
||||||
|
#1819 = DIRECTION('',(1.,0.));
|
||||||
|
#1820 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1821 = ORIENTED_EDGE('',*,*,#1822,.T.);
|
||||||
|
#1822 = EDGE_CURVE('',#1788,#1823,#1825,.T.);
|
||||||
|
#1823 = VERTEX_POINT('',#1824);
|
||||||
|
#1824 = CARTESIAN_POINT('',(-2.27,-1.02,2.5));
|
||||||
|
#1825 = SURFACE_CURVE('',#1826,(#1830,#1837),.PCURVE_S1.);
|
||||||
|
#1826 = LINE('',#1827,#1828);
|
||||||
|
#1827 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#1828 = VECTOR('',#1829,1.);
|
||||||
|
#1829 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1830 = PCURVE('',#1798,#1831);
|
||||||
|
#1831 = DEFINITIONAL_REPRESENTATION('',(#1832),#1836);
|
||||||
|
#1832 = LINE('',#1833,#1834);
|
||||||
|
#1833 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1834 = VECTOR('',#1835,1.);
|
||||||
|
#1835 = DIRECTION('',(0.,-1.));
|
||||||
|
#1836 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1837 = PCURVE('',#1838,#1843);
|
||||||
|
#1838 = PLANE('',#1839);
|
||||||
|
#1839 = AXIS2_PLACEMENT_3D('',#1840,#1841,#1842);
|
||||||
|
#1840 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#1841 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1842 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1843 = DEFINITIONAL_REPRESENTATION('',(#1844),#1848);
|
||||||
|
#1844 = LINE('',#1845,#1846);
|
||||||
|
#1845 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1846 = VECTOR('',#1847,1.);
|
||||||
|
#1847 = DIRECTION('',(0.,1.));
|
||||||
|
#1848 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1849 = ORIENTED_EDGE('',*,*,#1850,.T.);
|
||||||
|
#1850 = EDGE_CURVE('',#1823,#1851,#1853,.T.);
|
||||||
|
#1851 = VERTEX_POINT('',#1852);
|
||||||
|
#1852 = CARTESIAN_POINT('',(-2.27,-1.02,6.05));
|
||||||
|
#1853 = SURFACE_CURVE('',#1854,(#1858,#1865),.PCURVE_S1.);
|
||||||
|
#1854 = LINE('',#1855,#1856);
|
||||||
|
#1855 = CARTESIAN_POINT('',(-2.27,-1.02,2.5));
|
||||||
|
#1856 = VECTOR('',#1857,1.);
|
||||||
|
#1857 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1858 = PCURVE('',#1798,#1859);
|
||||||
|
#1859 = DEFINITIONAL_REPRESENTATION('',(#1860),#1864);
|
||||||
|
#1860 = LINE('',#1861,#1862);
|
||||||
|
#1861 = CARTESIAN_POINT('',(0.,-8.E-02));
|
||||||
|
#1862 = VECTOR('',#1863,1.);
|
||||||
|
#1863 = DIRECTION('',(1.,0.));
|
||||||
|
#1864 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1865 = PCURVE('',#1866,#1871);
|
||||||
|
#1866 = PLANE('',#1867);
|
||||||
|
#1867 = AXIS2_PLACEMENT_3D('',#1868,#1869,#1870);
|
||||||
|
#1868 = CARTESIAN_POINT('',(-2.27,-1.02,2.5));
|
||||||
|
#1869 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1870 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1871 = DEFINITIONAL_REPRESENTATION('',(#1872),#1876);
|
||||||
|
#1872 = LINE('',#1873,#1874);
|
||||||
|
#1873 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1874 = VECTOR('',#1875,1.);
|
||||||
|
#1875 = DIRECTION('',(1.,0.));
|
||||||
|
#1876 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1877 = ORIENTED_EDGE('',*,*,#1878,.F.);
|
||||||
|
#1878 = EDGE_CURVE('',#1790,#1851,#1879,.T.);
|
||||||
|
#1879 = SURFACE_CURVE('',#1880,(#1884,#1891),.PCURVE_S1.);
|
||||||
|
#1880 = LINE('',#1881,#1882);
|
||||||
|
#1881 = CARTESIAN_POINT('',(-2.27,-1.1,6.05));
|
||||||
|
#1882 = VECTOR('',#1883,1.);
|
||||||
|
#1883 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1884 = PCURVE('',#1798,#1885);
|
||||||
|
#1885 = DEFINITIONAL_REPRESENTATION('',(#1886),#1890);
|
||||||
|
#1886 = LINE('',#1887,#1888);
|
||||||
|
#1887 = CARTESIAN_POINT('',(3.55,0.));
|
||||||
|
#1888 = VECTOR('',#1889,1.);
|
||||||
|
#1889 = DIRECTION('',(0.,-1.));
|
||||||
|
#1890 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1891 = PCURVE('',#1892,#1897);
|
||||||
|
#1892 = PLANE('',#1893);
|
||||||
|
#1893 = AXIS2_PLACEMENT_3D('',#1894,#1895,#1896);
|
||||||
|
#1894 = CARTESIAN_POINT('',(-2.27,-1.1,6.05));
|
||||||
|
#1895 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1896 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1897 = DEFINITIONAL_REPRESENTATION('',(#1898),#1902);
|
||||||
|
#1898 = LINE('',#1899,#1900);
|
||||||
|
#1899 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1900 = VECTOR('',#1901,1.);
|
||||||
|
#1901 = DIRECTION('',(0.,1.));
|
||||||
|
#1902 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1903 = ADVANCED_FACE('',(#1904),#1918,.T.);
|
||||||
|
#1904 = FACE_BOUND('',#1905,.T.);
|
||||||
|
#1905 = EDGE_LOOP('',(#1906,#1936,#1959,#1982));
|
||||||
|
#1906 = ORIENTED_EDGE('',*,*,#1907,.F.);
|
||||||
|
#1907 = EDGE_CURVE('',#1908,#1910,#1912,.T.);
|
||||||
|
#1908 = VERTEX_POINT('',#1909);
|
||||||
|
#1909 = CARTESIAN_POINT('',(-2.05,-1.1,2.5));
|
||||||
|
#1910 = VERTEX_POINT('',#1911);
|
||||||
|
#1911 = CARTESIAN_POINT('',(-2.05,-1.1,6.05));
|
||||||
|
#1912 = SURFACE_CURVE('',#1913,(#1917,#1929),.PCURVE_S1.);
|
||||||
|
#1913 = LINE('',#1914,#1915);
|
||||||
|
#1914 = CARTESIAN_POINT('',(-2.05,-1.1,2.5));
|
||||||
|
#1915 = VECTOR('',#1916,1.);
|
||||||
|
#1916 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1917 = PCURVE('',#1918,#1923);
|
||||||
|
#1918 = PLANE('',#1919);
|
||||||
|
#1919 = AXIS2_PLACEMENT_3D('',#1920,#1921,#1922);
|
||||||
|
#1920 = CARTESIAN_POINT('',(-2.05,-1.1,2.5));
|
||||||
|
#1921 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#1922 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1923 = DEFINITIONAL_REPRESENTATION('',(#1924),#1928);
|
||||||
|
#1924 = LINE('',#1925,#1926);
|
||||||
|
#1925 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1926 = VECTOR('',#1927,1.);
|
||||||
|
#1927 = DIRECTION('',(1.,0.));
|
||||||
|
#1928 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1929 = PCURVE('',#1810,#1930);
|
||||||
|
#1930 = DEFINITIONAL_REPRESENTATION('',(#1931),#1935);
|
||||||
|
#1931 = LINE('',#1932,#1933);
|
||||||
|
#1932 = CARTESIAN_POINT('',(0.,0.22));
|
||||||
|
#1933 = VECTOR('',#1934,1.);
|
||||||
|
#1934 = DIRECTION('',(1.,0.));
|
||||||
|
#1935 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1936 = ORIENTED_EDGE('',*,*,#1937,.T.);
|
||||||
|
#1937 = EDGE_CURVE('',#1908,#1938,#1940,.T.);
|
||||||
|
#1938 = VERTEX_POINT('',#1939);
|
||||||
|
#1939 = CARTESIAN_POINT('',(-2.05,-1.02,2.5));
|
||||||
|
#1940 = SURFACE_CURVE('',#1941,(#1945,#1952),.PCURVE_S1.);
|
||||||
|
#1941 = LINE('',#1942,#1943);
|
||||||
|
#1942 = CARTESIAN_POINT('',(-2.05,-1.1,2.5));
|
||||||
|
#1943 = VECTOR('',#1944,1.);
|
||||||
|
#1944 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1945 = PCURVE('',#1918,#1946);
|
||||||
|
#1946 = DEFINITIONAL_REPRESENTATION('',(#1947),#1951);
|
||||||
|
#1947 = LINE('',#1948,#1949);
|
||||||
|
#1948 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#1949 = VECTOR('',#1950,1.);
|
||||||
|
#1950 = DIRECTION('',(0.,-1.));
|
||||||
|
#1951 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1952 = PCURVE('',#1838,#1953);
|
||||||
|
#1953 = DEFINITIONAL_REPRESENTATION('',(#1954),#1958);
|
||||||
|
#1954 = LINE('',#1955,#1956);
|
||||||
|
#1955 = CARTESIAN_POINT('',(0.22,0.));
|
||||||
|
#1956 = VECTOR('',#1957,1.);
|
||||||
|
#1957 = DIRECTION('',(0.,1.));
|
||||||
|
#1958 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1959 = ORIENTED_EDGE('',*,*,#1960,.T.);
|
||||||
|
#1960 = EDGE_CURVE('',#1938,#1961,#1963,.T.);
|
||||||
|
#1961 = VERTEX_POINT('',#1962);
|
||||||
|
#1962 = CARTESIAN_POINT('',(-2.05,-1.02,6.05));
|
||||||
|
#1963 = SURFACE_CURVE('',#1964,(#1968,#1975),.PCURVE_S1.);
|
||||||
|
#1964 = LINE('',#1965,#1966);
|
||||||
|
#1965 = CARTESIAN_POINT('',(-2.05,-1.02,2.5));
|
||||||
|
#1966 = VECTOR('',#1967,1.);
|
||||||
|
#1967 = DIRECTION('',(0.,0.,1.));
|
||||||
|
#1968 = PCURVE('',#1918,#1969);
|
||||||
|
#1969 = DEFINITIONAL_REPRESENTATION('',(#1970),#1974);
|
||||||
|
#1970 = LINE('',#1971,#1972);
|
||||||
|
#1971 = CARTESIAN_POINT('',(0.,-8.E-02));
|
||||||
|
#1972 = VECTOR('',#1973,1.);
|
||||||
|
#1973 = DIRECTION('',(1.,0.));
|
||||||
|
#1974 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1975 = PCURVE('',#1866,#1976);
|
||||||
|
#1976 = DEFINITIONAL_REPRESENTATION('',(#1977),#1981);
|
||||||
|
#1977 = LINE('',#1978,#1979);
|
||||||
|
#1978 = CARTESIAN_POINT('',(0.,0.22));
|
||||||
|
#1979 = VECTOR('',#1980,1.);
|
||||||
|
#1980 = DIRECTION('',(1.,0.));
|
||||||
|
#1981 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1982 = ORIENTED_EDGE('',*,*,#1983,.F.);
|
||||||
|
#1983 = EDGE_CURVE('',#1910,#1961,#1984,.T.);
|
||||||
|
#1984 = SURFACE_CURVE('',#1985,(#1989,#1996),.PCURVE_S1.);
|
||||||
|
#1985 = LINE('',#1986,#1987);
|
||||||
|
#1986 = CARTESIAN_POINT('',(-2.05,-1.1,6.05));
|
||||||
|
#1987 = VECTOR('',#1988,1.);
|
||||||
|
#1988 = DIRECTION('',(0.,1.,0.));
|
||||||
|
#1989 = PCURVE('',#1918,#1990);
|
||||||
|
#1990 = DEFINITIONAL_REPRESENTATION('',(#1991),#1995);
|
||||||
|
#1991 = LINE('',#1992,#1993);
|
||||||
|
#1992 = CARTESIAN_POINT('',(3.55,0.));
|
||||||
|
#1993 = VECTOR('',#1994,1.);
|
||||||
|
#1994 = DIRECTION('',(0.,-1.));
|
||||||
|
#1995 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#1996 = PCURVE('',#1892,#1997);
|
||||||
|
#1997 = DEFINITIONAL_REPRESENTATION('',(#1998),#2002);
|
||||||
|
#1998 = LINE('',#1999,#2000);
|
||||||
|
#1999 = CARTESIAN_POINT('',(0.22,0.));
|
||||||
|
#2000 = VECTOR('',#2001,1.);
|
||||||
|
#2001 = DIRECTION('',(0.,1.));
|
||||||
|
#2002 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2003 = ADVANCED_FACE('',(#2004),#1810,.F.);
|
||||||
|
#2004 = FACE_BOUND('',#2005,.F.);
|
||||||
|
#2005 = EDGE_LOOP('',(#2006,#2027,#2028,#2049));
|
||||||
|
#2006 = ORIENTED_EDGE('',*,*,#2007,.F.);
|
||||||
|
#2007 = EDGE_CURVE('',#1788,#1908,#2008,.T.);
|
||||||
|
#2008 = SURFACE_CURVE('',#2009,(#2013,#2020),.PCURVE_S1.);
|
||||||
|
#2009 = LINE('',#2010,#2011);
|
||||||
|
#2010 = CARTESIAN_POINT('',(-2.27,-1.1,2.5));
|
||||||
|
#2011 = VECTOR('',#2012,1.);
|
||||||
|
#2012 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#2013 = PCURVE('',#1810,#2014);
|
||||||
|
#2014 = DEFINITIONAL_REPRESENTATION('',(#2015),#2019);
|
||||||
|
#2015 = LINE('',#2016,#2017);
|
||||||
|
#2016 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#2017 = VECTOR('',#2018,1.);
|
||||||
|
#2018 = DIRECTION('',(0.,1.));
|
||||||
|
#2019 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2020 = PCURVE('',#1838,#2021);
|
||||||
|
#2021 = DEFINITIONAL_REPRESENTATION('',(#2022),#2026);
|
||||||
|
#2022 = LINE('',#2023,#2024);
|
||||||
|
#2023 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#2024 = VECTOR('',#2025,1.);
|
||||||
|
#2025 = DIRECTION('',(1.,0.));
|
||||||
|
#2026 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2027 = ORIENTED_EDGE('',*,*,#1787,.T.);
|
||||||
|
#2028 = ORIENTED_EDGE('',*,*,#2029,.T.);
|
||||||
|
#2029 = EDGE_CURVE('',#1790,#1910,#2030,.T.);
|
||||||
|
#2030 = SURFACE_CURVE('',#2031,(#2035,#2042),.PCURVE_S1.);
|
||||||
|
#2031 = LINE('',#2032,#2033);
|
||||||
|
#2032 = CARTESIAN_POINT('',(-2.27,-1.1,6.05));
|
||||||
|
#2033 = VECTOR('',#2034,1.);
|
||||||
|
#2034 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#2035 = PCURVE('',#1810,#2036);
|
||||||
|
#2036 = DEFINITIONAL_REPRESENTATION('',(#2037),#2041);
|
||||||
|
#2037 = LINE('',#2038,#2039);
|
||||||
|
#2038 = CARTESIAN_POINT('',(3.55,0.));
|
||||||
|
#2039 = VECTOR('',#2040,1.);
|
||||||
|
#2040 = DIRECTION('',(0.,1.));
|
||||||
|
#2041 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2042 = PCURVE('',#1892,#2043);
|
||||||
|
#2043 = DEFINITIONAL_REPRESENTATION('',(#2044),#2048);
|
||||||
|
#2044 = LINE('',#2045,#2046);
|
||||||
|
#2045 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#2046 = VECTOR('',#2047,1.);
|
||||||
|
#2047 = DIRECTION('',(1.,0.));
|
||||||
|
#2048 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2049 = ORIENTED_EDGE('',*,*,#1907,.F.);
|
||||||
|
#2050 = ADVANCED_FACE('',(#2051),#1866,.T.);
|
||||||
|
#2051 = FACE_BOUND('',#2052,.T.);
|
||||||
|
#2052 = EDGE_LOOP('',(#2053,#2074,#2075,#2096));
|
||||||
|
#2053 = ORIENTED_EDGE('',*,*,#2054,.F.);
|
||||||
|
#2054 = EDGE_CURVE('',#1823,#1938,#2055,.T.);
|
||||||
|
#2055 = SURFACE_CURVE('',#2056,(#2060,#2067),.PCURVE_S1.);
|
||||||
|
#2056 = LINE('',#2057,#2058);
|
||||||
|
#2057 = CARTESIAN_POINT('',(-2.27,-1.02,2.5));
|
||||||
|
#2058 = VECTOR('',#2059,1.);
|
||||||
|
#2059 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#2060 = PCURVE('',#1866,#2061);
|
||||||
|
#2061 = DEFINITIONAL_REPRESENTATION('',(#2062),#2066);
|
||||||
|
#2062 = LINE('',#2063,#2064);
|
||||||
|
#2063 = CARTESIAN_POINT('',(0.,0.));
|
||||||
|
#2064 = VECTOR('',#2065,1.);
|
||||||
|
#2065 = DIRECTION('',(0.,1.));
|
||||||
|
#2066 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2067 = PCURVE('',#1838,#2068);
|
||||||
|
#2068 = DEFINITIONAL_REPRESENTATION('',(#2069),#2073);
|
||||||
|
#2069 = LINE('',#2070,#2071);
|
||||||
|
#2070 = CARTESIAN_POINT('',(0.,8.E-02));
|
||||||
|
#2071 = VECTOR('',#2072,1.);
|
||||||
|
#2072 = DIRECTION('',(1.,0.));
|
||||||
|
#2073 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2074 = ORIENTED_EDGE('',*,*,#1850,.T.);
|
||||||
|
#2075 = ORIENTED_EDGE('',*,*,#2076,.T.);
|
||||||
|
#2076 = EDGE_CURVE('',#1851,#1961,#2077,.T.);
|
||||||
|
#2077 = SURFACE_CURVE('',#2078,(#2082,#2089),.PCURVE_S1.);
|
||||||
|
#2078 = LINE('',#2079,#2080);
|
||||||
|
#2079 = CARTESIAN_POINT('',(-2.27,-1.02,6.05));
|
||||||
|
#2080 = VECTOR('',#2081,1.);
|
||||||
|
#2081 = DIRECTION('',(1.,0.,0.));
|
||||||
|
#2082 = PCURVE('',#1866,#2083);
|
||||||
|
#2083 = DEFINITIONAL_REPRESENTATION('',(#2084),#2088);
|
||||||
|
#2084 = LINE('',#2085,#2086);
|
||||||
|
#2085 = CARTESIAN_POINT('',(3.55,0.));
|
||||||
|
#2086 = VECTOR('',#2087,1.);
|
||||||
|
#2087 = DIRECTION('',(0.,1.));
|
||||||
|
#2088 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2089 = PCURVE('',#1892,#2090);
|
||||||
|
#2090 = DEFINITIONAL_REPRESENTATION('',(#2091),#2095);
|
||||||
|
#2091 = LINE('',#2092,#2093);
|
||||||
|
#2092 = CARTESIAN_POINT('',(0.,8.E-02));
|
||||||
|
#2093 = VECTOR('',#2094,1.);
|
||||||
|
#2094 = DIRECTION('',(1.,0.));
|
||||||
|
#2095 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2)
|
||||||
|
PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE',''
|
||||||
|
) );
|
||||||
|
#2096 = ORIENTED_EDGE('',*,*,#1960,.F.);
|
||||||
|
#2097 = ADVANCED_FACE('',(#2098),#1838,.F.);
|
||||||
|
#2098 = FACE_BOUND('',#2099,.F.);
|
||||||
|
#2099 = EDGE_LOOP('',(#2100,#2101,#2102,#2103));
|
||||||
|
#2100 = ORIENTED_EDGE('',*,*,#1822,.F.);
|
||||||
|
#2101 = ORIENTED_EDGE('',*,*,#2007,.T.);
|
||||||
|
#2102 = ORIENTED_EDGE('',*,*,#1937,.T.);
|
||||||
|
#2103 = ORIENTED_EDGE('',*,*,#2054,.F.);
|
||||||
|
#2104 = ADVANCED_FACE('',(#2105),#1892,.T.);
|
||||||
|
#2105 = FACE_BOUND('',#2106,.T.);
|
||||||
|
#2106 = EDGE_LOOP('',(#2107,#2108,#2109,#2110));
|
||||||
|
#2107 = ORIENTED_EDGE('',*,*,#1878,.F.);
|
||||||
|
#2108 = ORIENTED_EDGE('',*,*,#2029,.T.);
|
||||||
|
#2109 = ORIENTED_EDGE('',*,*,#1983,.T.);
|
||||||
|
#2110 = ORIENTED_EDGE('',*,*,#2076,.F.);
|
||||||
|
#2111 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#2115))
|
||||||
|
GLOBAL_UNIT_ASSIGNED_CONTEXT((#2112,#2113,#2114)) REPRESENTATION_CONTEXT
|
||||||
|
('Context #1','3D Context with UNIT and UNCERTAINTY') );
|
||||||
|
#2112 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) );
|
||||||
|
#2113 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) );
|
||||||
|
#2114 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() );
|
||||||
|
#2115 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#2112,
|
||||||
|
'distance_accuracy_value','confusion accuracy');
|
||||||
|
#2116 = CONTEXT_DEPENDENT_SHAPE_REPRESENTATION(#2117,#2119);
|
||||||
|
#2117 = ( REPRESENTATION_RELATIONSHIP('','',#1780,#10)
|
||||||
|
REPRESENTATION_RELATIONSHIP_WITH_TRANSFORMATION(#2118)
|
||||||
|
SHAPE_REPRESENTATION_RELATIONSHIP() );
|
||||||
|
#2118 = ITEM_DEFINED_TRANSFORMATION('','',#11,#31);
|
||||||
|
#2119 = PRODUCT_DEFINITION_SHAPE('Placement','Placement of an item',
|
||||||
|
#2120);
|
||||||
|
#2120 = NEXT_ASSEMBLY_USAGE_OCCURRENCE('60',
|
||||||
|
'36516288-93c7-11f1-ba5d-04bad62a3558','',#5,#1775,$);
|
||||||
|
#2121 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#1777));
|
||||||
|
#2122 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(
|
||||||
|
#2123),#2111);
|
||||||
|
#2123 = STYLED_ITEM('color',(#2124),#1781);
|
||||||
|
#2124 = PRESENTATION_STYLE_ASSIGNMENT((#2125));
|
||||||
|
#2125 = SURFACE_STYLE_USAGE(.BOTH.,#2126);
|
||||||
|
#2126 = SURFACE_SIDE_STYLE('',(#2127));
|
||||||
|
#2127 = SURFACE_STYLE_FILL_AREA(#2128);
|
||||||
|
#2128 = FILL_AREA_STYLE('',(#2129));
|
||||||
|
#2129 = FILL_AREA_STYLE_COLOUR('',#2130);
|
||||||
|
#2130 = COLOUR_RGB('',0.250000000672,0.27999999963,0.299999996101);
|
||||||
|
#2131 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(
|
||||||
|
#2132),#1413);
|
||||||
|
#2132 = STYLED_ITEM('color',(#2133),#747);
|
||||||
|
#2133 = PRESENTATION_STYLE_ASSIGNMENT((#2134));
|
||||||
|
#2134 = SURFACE_STYLE_USAGE(.BOTH.,#2135);
|
||||||
|
#2135 = SURFACE_SIDE_STYLE('',(#2136,#2140));
|
||||||
|
#2136 = SURFACE_STYLE_FILL_AREA(#2137);
|
||||||
|
#2137 = FILL_AREA_STYLE('',(#2138));
|
||||||
|
#2138 = FILL_AREA_STYLE_COLOUR('',#2139);
|
||||||
|
#2139 = COLOUR_RGB('',0.720000003324,0.78000000177,0.800000010877);
|
||||||
|
#2140 = SURFACE_STYLE_RENDERING_WITH_PROPERTIES(.NORMAL_SHADING.,#2139,(
|
||||||
|
#2141));
|
||||||
|
#2141 = SURFACE_STYLE_TRANSPARENT(0.420000016689);
|
||||||
|
#2142 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(
|
||||||
|
#2143),#728);
|
||||||
|
#2143 = STYLED_ITEM('color',(#2144),#398);
|
||||||
|
#2144 = PRESENTATION_STYLE_ASSIGNMENT((#2145));
|
||||||
|
#2145 = SURFACE_STYLE_USAGE(.BOTH.,#2146);
|
||||||
|
#2146 = SURFACE_SIDE_STYLE('',(#2147));
|
||||||
|
#2147 = SURFACE_STYLE_FILL_AREA(#2148);
|
||||||
|
#2148 = FILL_AREA_STYLE('',(#2149));
|
||||||
|
#2149 = FILL_AREA_STYLE_COLOUR('',#2150);
|
||||||
|
#2150 = COLOUR_RGB('',0.720000003324,0.740000011925,0.760000013601);
|
||||||
|
#2151 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(
|
||||||
|
#2152),#1762);
|
||||||
|
#2152 = STYLED_ITEM('color',(#2153),#1432);
|
||||||
|
#2153 = PRESENTATION_STYLE_ASSIGNMENT((#2154));
|
||||||
|
#2154 = SURFACE_STYLE_USAGE(.BOTH.,#2155);
|
||||||
|
#2155 = SURFACE_SIDE_STYLE('',(#2156));
|
||||||
|
#2156 = SURFACE_STYLE_FILL_AREA(#2157);
|
||||||
|
#2157 = FILL_AREA_STYLE('',(#2158));
|
||||||
|
#2158 = FILL_AREA_STYLE_COLOUR('',#2159);
|
||||||
|
#2159 = COLOUR_RGB('',9.999999991362E-02,0.1599999992,0.190000001765);
|
||||||
|
#2160 = MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(
|
||||||
|
#2161),#379);
|
||||||
|
#2161 = STYLED_ITEM('color',(#2162),#49);
|
||||||
|
#2162 = PRESENTATION_STYLE_ASSIGNMENT((#2163));
|
||||||
|
#2163 = SURFACE_STYLE_USAGE(.BOTH.,#2164);
|
||||||
|
#2164 = SURFACE_SIDE_STYLE('',(#2165));
|
||||||
|
#2165 = SURFACE_STYLE_FILL_AREA(#2166);
|
||||||
|
#2166 = FILL_AREA_STYLE('',(#2167));
|
||||||
|
#2167 = FILL_AREA_STYLE_COLOUR('',#2150);
|
||||||
|
ENDSEC;
|
||||||
|
END-ISO-10303-21;
|
||||||
BIN
PCB/Libs/ESP32-C3-SuperMini.PcbLib
Normal file
BIN
PCB/Libs/ESP32-C3-SuperMini.PcbLib
Normal file
Binary file not shown.
BIN
PCB/Libs/ESP32-C3-SuperMini.SchLib
Normal file
BIN
PCB/Libs/ESP32-C3-SuperMini.SchLib
Normal file
Binary file not shown.
BIN
PCB/Libs/ESP32-S3-SuperMini.PcbLib
Normal file
BIN
PCB/Libs/ESP32-S3-SuperMini.PcbLib
Normal file
Binary file not shown.
BIN
PCB/Libs/ESP32-S3-SuperMini.SchLib
Normal file
BIN
PCB/Libs/ESP32-S3-SuperMini.SchLib
Normal file
Binary file not shown.
BIN
PCB/Libs/HFBR-1528Z_HFBR-2528Z.PcbLib
Normal file
BIN
PCB/Libs/HFBR-1528Z_HFBR-2528Z.PcbLib
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user