Feature/source plugins #1
No files matched your search
@@ -137,7 +137,8 @@ whether the handshake may answer status 2 ("code ignored"; one reference accepts
|
|||||||
source accepts it); the first frame id; and the maximum frame size. Two further things
|
source accepts it); the first frame id; and the maximum frame size. Two further things
|
||||||
are worth a look on a board even though the mock's header does not flag them: the calibration memory layout and
|
are worth a look on a board even though the mock's header does not flag them: the calibration memory layout and
|
||||||
its coefficient type, and the status word's bits, in particular whether the "scan running" bit stays set while the
|
its coefficient type, and the status word's bits, in particular whether the "scan running" bit stays set while the
|
||||||
board waits for a trigger (the source restarts a scan that reads as stopped when auto-restart is on). The DIFF input
|
board waits for a trigger (with auto-restart on, the source restarts a scan that reads as stopped only when no
|
||||||
|
trigger is configured, so as not to reset the wait for the edge; this is unverified on hardware). The DIFF input
|
||||||
numbering (channel + 8) and the filler byte after scan start are agreed by both references. The scan overrun count
|
numbering (channel + 8) and the filler byte after scan start are agreed by both references. The scan overrun count
|
||||||
is approximate: the board does not say how many scans it dropped, so the frame after a restart reports one lost.
|
is approximate: the board does not say how many scans it dropped, so the frame after a restart reports one lost.
|
||||||
Errors (no device, a rejected connection code, a timeout, the scan socket closing) are written to stderr as
|
Errors (no device, a rejected connection code, a timeout, the scan socket closing) are written to stderr as
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ What feeds `Acquisition` is a `DataSource`, one of the registered *kinds*.
|
|||||||
`e1608_source` is the `DataSource`; `e1608_kind` and `e1608_panels` are the UI. A change to the wire
|
`e1608_source` is the `DataSource`; `e1608_kind` and `e1608_panels` are the UI. A change to the wire
|
||||||
never reaches the UI files.
|
never reaches the UI files.
|
||||||
- The E-1608 source runs **everything inside `poll()`** on the producer thread: posted commands, the
|
- The E-1608 source runs **everything inside `poll()`** on the producer thread: posted commands, the
|
||||||
connect state machine (Down, Scanning, Halted), the scan read, the 500 ms status check, the digital
|
connect state machine (Down, Scanning, Halted), the scan read, the 500 ms status check (its not-running restart is skipped when a hardware trigger is configured), the digital
|
||||||
input/counter poll and the 20 ms waveform tick. There is no second thread. A connect attempt (discovery,
|
input/counter poll and the 20 ms waveform tick. There is no second thread. A connect attempt (discovery,
|
||||||
handshake, calibration read, scan start) can block `poll()` for as long as the command timeout allows each
|
handshake, calibration read, scan start) can block `poll()` for as long as the command timeout allows each
|
||||||
step; that delays only the command queue. Every exception is caught inside `poll()`: an escape would end
|
step; that delays only the command queue. Every exception is caught inside `poll()`: an escape would end
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ void E1608Source::open(SourceSink& sink) {
|
|||||||
|
|
||||||
void E1608Source::close() {
|
void E1608Source::close() {
|
||||||
if (state_ == State::Scanning) dev_.scan_stop();
|
if (state_ == State::Scanning) dev_.scan_stop();
|
||||||
|
scan_started_ = false;
|
||||||
link_.close();
|
link_.close();
|
||||||
connected_.store(false, std::memory_order_relaxed);
|
connected_.store(false, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
@@ -212,6 +213,15 @@ void E1608Source::note(const std::string& msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void E1608Source::fail(const std::string& msg, bool fatal) {
|
void E1608Source::fail(const std::string& msg, bool fatal) {
|
||||||
|
if (scan_started_) {
|
||||||
|
// The scan may have started before a later connect step failed: tell the board to stop, so it
|
||||||
|
// is not left scanning with nobody reading. Best effort; it must never throw out of here.
|
||||||
|
try {
|
||||||
|
dev_.scan_stop();
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
scan_started_ = false;
|
||||||
|
}
|
||||||
link_.close();
|
link_.close();
|
||||||
const bool was_up = connected_.exchange(false, std::memory_order_relaxed);
|
const bool was_up = connected_.exchange(false, std::memory_order_relaxed);
|
||||||
note(msg);
|
note(msg);
|
||||||
@@ -283,6 +293,7 @@ void E1608Source::connect_and_start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
link_.connect(host, cfg_.port, cfg_.code, cfg_.timeout_ms);
|
link_.connect(host, cfg_.port, cfg_.code, cfg_.timeout_ms);
|
||||||
|
scan_started_ = false;
|
||||||
cal_ = Calibration{};
|
cal_ = Calibration{};
|
||||||
if (cfg_.calibrate && !dev_.read_calibration(cal_))
|
if (cfg_.calibrate && !dev_.read_calibration(cal_))
|
||||||
note("calibration memory refused; using nominal values");
|
note("calibration memory refused; using nominal values");
|
||||||
@@ -419,13 +430,16 @@ void E1608Source::check_status() {
|
|||||||
sink_->on_event(SourceEvent::Error, "scan overrun; restarting");
|
sink_->on_event(SourceEvent::Error, "scan overrun; restarting");
|
||||||
restart_scan();
|
restart_scan();
|
||||||
pending_lost_ = 1;
|
pending_lost_ = 1;
|
||||||
} else if (!(st & 2) && cfg_.auto_restart) {
|
} else if (!(st & 2) && cfg_.auto_restart && cfg_.trigger == Trigger::None) {
|
||||||
|
// With a hardware trigger the board may report "not running" while it waits for the edge;
|
||||||
|
// restarting then would reset the wait forever, so only the overrun bit restarts the scan.
|
||||||
restart_scan();
|
restart_scan();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void E1608Source::restart_scan() {
|
void E1608Source::restart_scan() {
|
||||||
dev_.scan_stop();
|
dev_.scan_stop();
|
||||||
|
scan_started_ = false;
|
||||||
pending_.clear();
|
pending_.clear();
|
||||||
for (auto& r : ready_) r.clear();
|
for (auto& r : ready_) r.clear();
|
||||||
start_scan();
|
start_scan();
|
||||||
@@ -437,6 +451,7 @@ void E1608Source::start_scan() {
|
|||||||
throw LinkError(LinkError::Kind::Command, "the aggregate rate exceeds 250 kS/s");
|
throw LinkError(LinkError::Kind::Command, "the aggregate rate exceeds 250 kS/s");
|
||||||
try {
|
try {
|
||||||
dev_.scan_start(queue_, cfg_.aggregate(), cfg_.ext_clock, cfg_.trigger);
|
dev_.scan_start(queue_, cfg_.aggregate(), cfg_.ext_clock, cfg_.trigger);
|
||||||
|
scan_started_ = true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// The board may have accepted the start (0x11) before a later step failed (the filler byte):
|
// The board may have accepted the start (0x11) before a later step failed (the filler byte):
|
||||||
// tell it to stop, so it is not left scanning with nobody reading.
|
// tell it to stop, so it is not left scanning with nobody reading.
|
||||||
@@ -444,6 +459,7 @@ void E1608Source::start_scan() {
|
|||||||
dev_.scan_stop();
|
dev_.scan_stop();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
scan_started_ = false;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ class E1608Source final : public DataSource {
|
|||||||
E1608Settings cfg_;
|
E1608Settings cfg_;
|
||||||
SourceSink* sink_ = nullptr;
|
SourceSink* sink_ = nullptr;
|
||||||
State state_ = State::Down;
|
State state_ = State::Down;
|
||||||
|
bool scan_started_ = false; ///< a scan start succeeded and no stop has followed
|
||||||
Link link_;
|
Link link_;
|
||||||
Device dev_{link_};
|
Device dev_{link_};
|
||||||
Calibration cal_;
|
Calibration cal_;
|
||||||
|
|||||||
+3
-1
@@ -327,7 +327,9 @@ class Board:
|
|||||||
self.first_conn = time.monotonic()
|
self.first_conn = time.monotonic()
|
||||||
close_quietly(old)
|
close_quietly(old)
|
||||||
if first and self.args.drop_after > 0:
|
if first and self.args.drop_after > 0:
|
||||||
threading.Timer(self.args.drop_after, self.drop).start()
|
timer = threading.Timer(self.args.drop_after, self.drop)
|
||||||
|
timer.daemon = True
|
||||||
|
timer.start()
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
b = conn.recv(1)
|
b = conn.recv(1)
|
||||||
|
|||||||
Reference in new issue
Block a user