|
dxd - dynax driver framework 3.0.2
cross platform open source driver development framework
|
one isochronous endpoint as a stream: the ring, the cycle of slots the session rotates through and the thread that ticks them. The data path itself is dx::usb::isoc::pipeline, shared with the kernel driver; this class supplies its platform part - a slot's request over its buffer, the completions in submission order, the direction's data event and the timestamp clock. An asynchronous sink keeps its sync endpoint's requests here too (isoc.sync), an implicit feedback source reads its rate off its own delivered lines. More...
#include <dx_usb_stream_pipe.h>
Classes | |
| struct | cache |
| what the tick reads instead of asking a promoted: the derived transaction sizes, the encoder stages and the in slot's sentinel - none of them may block or lock More... | |
| struct | isoc |
| what this pipe's session needs beside its own requests: the feedback ring of lines per frame, and an explicit feedback endpoint's own slots More... | |
Public Types | |
| typedef struct device_t::desc::stream | desc |
| typedef device<> | device_t |
| typedef device<> | device_t |
| typedef event<user> | event_t |
| enum | type |
Public Member Functions | |
| pipe& | abort() |
| stream& | attach(void **[2], const std::vector<bool> &, direction::direction, const dx::stream::format &) |
| the pin passes its own direction: a stream shared by two pins carries none of its own | |
| catch(const std::out_of_range& exception) | |
| os_result | charge() noexcept |
| streaming session prologue: selects the alternate setting, (re-)creates the isoc buffer, then the pipeline's own - run by the thread owning the session (group pipes: the group's thread), whose ticks then submit; logs a failure as it starts and its recovery once | |
| bool | claim(direction::direction direction) |
| taken while there is none | |
| pipe& | clear(bool force= false) |
| void | conclude() noexcept override |
| conclude notification: object will be removed. If you overwrite conclude() you also need to overwrite destructor and check if its needed to be called from there. Called only through try_conclude() - never call this directly from outside the class hierarchy. | |
| pipe& | drain(std::chrono::milliseconds timeout= std::chrono::milliseconds(250)) noexcept |
| waits for already-submitted requests to complete on their own, without cancelling them | |
| float | encoder(dx::stream::encoder::index::type typetype, unsigned int index) const override |
| bool | encoder(dx::stream::encoder::index::type typetype, unsigned int index, float value) override |
| void | exception(const class exception& exception, bool filtered= false) const noexcept override |
| void | exception(const dx::exception& exception, bool filtered= false) const noexcept override |
| notification exception handler | |
| void | flush() |
| uint64_t | frame(int64_t* timestamp= nullptr) |
| current bus frame number; timestamp: dx::timestamp() of the readout | |
| void | free() noexcept override |
| overrides may release further alloc()-acquired resources (request buffers, isoc pools, shared-memory attachments) alongside circular; called only from alloc()'s own self-cleanup or the destructor - never from halt()/stop(), so everything alloc() acquires stays live for the object's full lifetime | |
| void | initialize() override |
| void | launch() override |
| pipe& | max_frame_size(uint32_t frame_size) |
| operator dx::circular*() const noexcept | |
| dx::circular* | operator ->() const noexcept |
| pipe& | operator <<(const data_t& data) |
| synchronous USB write request | |
| pipe& | operator >>(data_t& data) |
| synchronous USB read request | |
| bool | outstanding() const noexcept |
| pipe(device_t& device, const decltype(super::id)& id, const super::desc& descdesc) | |
| creates this->circular streaming backing store and frame buffers | |
| bool | poll(usb::isoc::result& result) noexcept |
| pulls the oldest completed request's result | |
| pipe& | read(void* data, size_t& size) |
| synchronous USB read request | |
| virtual pipe& | receive(void* data, size_t size) |
| asynchronous USB read request | |
| virtual os_result | status() noexcept |
| os_result | status() const noexcept |
| virtual bool | submit(dx::stream::encoder::index::type, unsigned int, uint8_t) |
| submit encoder stage to device return true if successfully submitted; if false is returned the encode state machine will not update the stage value (i.e. if the stage can't be submitted during streaming pause), given the chance to submit the stage at start(). | |
| pipe& | submit(const request<data_t>& request) const |
| standard request to pipe | |
| pipe& | transfer(bool in, void* data, size_t& size) |
| a synchronous transfer: asynchronous underneath, past timeout the pipe aborted and the transfer failed as timed out - IOKit completes every request, an aborted one included | |
| virtual pipe& | transmit(const void* data, size_t& size) |
| asynchronous USB write request | |
| bool | try_conclude() noexcept |
| atomically conclude()s if currently launched; returns whether this call did it | |
| bool | try_conclude() noexcept |
| atomically conclude()s if currently launched; returns whether this call did it | |
| bool | try_launch() |
| atomically launch()es if not already launched; returns whether this call did it. A launch() that throws is concluded before the exception leaves: the object never claims a launch it did not finish | |
| bool | try_launch() |
| atomically launch()es if not already launched; returns whether this call did it. A launch() that throws is concluded before the exception leaves: the object never claims a launch it did not finish | |
| pipe& | write(const void* data, size_t size) |
| synchronous USB write request | |
| ~pipe() override | |
Static Public Member Functions | |
| static unsigned int | micro_frames(const device_t& device, uint8_t bInterval) |
| an endpoint's requests per frame: its interval at high speed, one below | |
Public Attributes | |
| bool | anchored |
| origin is set: by the tick that first finds the ring ticking, reset by the run hook | |
| const usb::endpoint::attributes& | attributes |
| std::deque<union audio::descriptor::endpoint> | audio |
| uint8_t | bRefresh |
| audio class endpoint: 2^bRefresh frames between two feedback values | |
| uint8_t | bSynchAddress |
| audio class endpoint: the isoc sync endpoint pacing this one, 0: none | |
| dx::stream::channel::control* | control |
| kernel streaming: the driver's buffer switch bookkeeping, set by attach() | |
| event_t | data [direction::directions] |
| event signalising data arrival(in) or draining(out) | |
| dx::promoted<dx::stream::format> | format |
| the container this stream's ring runs: class and width its participants agreed on | |
| const decltype(desc::target.idx()) | id |
| interface& | interface |
| uint32_t | latency |
| std::atomic<bool> | launched |
| std::atomic<bool> | launched |
| int64_t | origin |
| the ring's index at the device's sample zero: a ticking group keeps every ring's cycle from its device time and this | |
| decltype(device_t::samplerate)& | samplerate |
| promoted<uint32_t> | start |
| promoted<uint32_t> | start |
| promoted<bool> | started |
| promoted<bool> | started |
| bool | ticking |
| the tick's own view of this stream's session: set by the run hook once the ring stands, cleared by the halt hook before the session ends - a plain flag, the tick must never block on a promoted's transition | |
| std::chrono::milliseconds | timeout |
| volatile int64_t | transport |
| std::mutex | writer |
| the ring's client writers one at a time: a stream's pins write one ring, each on its own port | |
Static Public Attributes | |
| static constexpr auto | max |
Protected Member Functions | |
| void | alloc(size_t= 0, bool free= true) override |
| void | isoc_buffer_create() |
| (re-)creates the buffered isoc pipe's tick-staging buffer via isoc.buffer.create(); safe to call again per start/stop cycle since cache.buffered keeps this->circular on its own, separate, construction-time allocation (super::alloc() below). | |
| void | pump_in() noexcept |
| data driven streaming in | |
| void | pump_out() noexcept |
| data driven streaming out | |
| void | received(os_result status, size_t size) override |
| async read callback | |
| void | transmitted(os_result status, size_t size) override |
| async write callback | |
| virtual size_t | vendor(uint8_t *, size_t size, bool) |
| a vendor transaction's wire bytes past its fill (out; data false: an idle transaction) and ahead of its take (in): returns the bytes the ring takes | |
Protected Attributes | |
| struct dx::usb::platform::pipe:: { ... } | address |
| struct dx::usb::stream::pipe:: { ... } | async |
| struct dx::usb::stream::pipe::cache | cache |
| listener<dx::listen<std::function<void(const uint32_t &)>>> | cadence_listener{this->samplerate.listen, {[this](const uint32_t& samplerate){pipeline.rate(samplerate);}}} |
| the tick reads the cache, never the promoted: the rate's derivations are the pipeline's, rederived on every commit | |
| dx::circular* | circular |
| allocated once by initialize()/alloc(); released only by free() | |
| usb::isoc::result | completed [max] |
| isoc completions in callback order, filled by the runloop, drained by poll() | |
| device<>& | device |
| device<>& | device |
| std::function<void()> | flush_hook |
| std::function<void()> | flush_hook |
| std::function<void()> | halt_hook |
| std::function<void()> | halt_hook |
| uint8_t | idx |
| struct dx::usb::stream::pipe::isoc | isoc |
| listener<dx::listen<std::function<void(const uint32_t &)>>> | lead_listener{this->device[*this].transport::safety_offset[this->target.direction].listen, {[this](const uint32_t& ticks){pipeline.cache.lead= ticks;}}} |
| a lead set mid-session moves the tick's slots along | |
| std::function<void()> | run_hook |
| std::function<void()> | run_hook |
| volatile unsigned int | rx |
| struct dx::usb::stream::pipe:: { ... } | sync |
| volatile unsigned int | tx |
| struct dx::usb::platform::pipe:: { ... } | winusb |
Friends | |
| class | isoc::pipeline<pipe, circular_t> |
| struct | isoc::session<usb::stream::group<device_t>> |
| class | pause |
| class | usb::stream::group<device_t> |
one isochronous endpoint as a stream: the ring, the cycle of slots the session rotates through and the thread that ticks them. The data path itself is dx::usb::isoc::pipeline, shared with the kernel driver; this class supplies its platform part - a slot's request over its buffer, the completions in submission order, the direction's data event and the timestamp clock. An asynchronous sink keeps its sync endpoint's requests here too (isoc.sync), an implicit feedback source reads its rate off its own delivered lines.
|
inherited |
|
inherited |
|
inherited |
|
inherited |
|
stronginherited |
|
inline |
creates this->circular streaming backing store and frame buffers
stream::stream's ring reset, composed with usb::platform::pipe's completion-thread launch
stream::stream's group decrement, composed with usb::platform::pipe's join-outstanding-requests wait
|
inlineoverride |
|
inlineinherited |
|
inlineoverrideprotectedvirtual |
generates isoc cycle metrics from sample rate,
requests buffers to fit at least 3x max iosize with isoc cycle size granularity
update max frame size
Reimplemented from dx::stream::stream< device_t, dx::circular, usb::pipe< device_t > >.
|
inlineinherited |
the pin passes its own direction: a stream shared by two pins carries none of its own
|
inlineinherited |
|
inlinenoexcept |
streaming session prologue: selects the alternate setting, (re-)creates the isoc buffer, then the pipeline's own - run by the thread owning the session (group pipes: the group's thread), whose ticks then submit; logs a failure as it starts and its recovery once
|
inlineinherited |
taken while there is none
|
inlineinherited |
|
inlineoverridevirtualnoexceptinherited |
conclude notification: object will be removed. If you overwrite conclude() you also need to overwrite destructor and check if its needed to be called from there. Called only through try_conclude() - never call this directly from outside the class hierarchy.
Reimplemented from dx::stream::control< stream::object< device_t > >.
|
inlinenoexceptinherited |
waits for already-submitted requests to complete on their own, without cancelling them
|
inlineoverride |
|
inlineoverridevirtual |
Reimplemented from dx::stream::stream< device_t, dx::circular, usb::pipe< device_t > >.
|
inlineoverridenoexceptinherited |
|
inlineoverridevirtualnoexcept |
notification exception handler
Reimplemented from dx::stream::object< _device_t >.
|
inlineinherited |
|
inlineinherited |
current bus frame number; timestamp: dx::timestamp() of the readout
|
inlineoverridevirtualnoexcept |
overrides may release further alloc()-acquired resources (request buffers, isoc pools, shared-memory attachments) alongside circular; called only from alloc()'s own self-cleanup or the destructor - never from halt()/stop(), so everything alloc() acquires stays live for the object's full lifetime
Reimplemented from dx::stream::stream< device_t, dx::circular, usb::pipe< device_t > >.
|
inlineoverridevirtual |
Reimplemented from dx::stream::stream< device_t, dx::circular, usb::pipe< device_t > >.
|
inlineprotected |
(re-)creates the buffered isoc pipe's tick-staging buffer via isoc.buffer.create(); safe to call again per start/stop cycle since cache.buffered keeps this->circular on its own, separate, construction-time allocation (super::alloc() below).
|
inlineoverridevirtualinherited |
Reimplemented from dx::object.
|
inlineinherited |
|
inlinestaticinherited |
an endpoint's requests per frame: its interval at high speed, one below
|
inlinenoexceptinherited |
|
inlinenoexceptinherited |
|
inlineinherited |
synchronous USB write request
|
inlineinherited |
synchronous USB read request
|
inlinenoexceptinherited |
asynchronous requests in flight
|
inlinenoexceptinherited |
pulls the oldest completed request's result
|
inlineprotectednoexcept |
data driven streaming in
postponed
|
inlineprotectednoexcept |
data driven streaming out
|
inlineinherited |
synchronous USB read request
|
inlinevirtualinherited |
asynchronous USB read request
|
inlineoverrideprotectedvirtual |
async read callback
generates timestamp
Reimplemented from dx::usb::platform::pipe< device_t, interface >.
|
inlinevirtualnoexceptinherited |
|
inlinenoexceptinherited |
|
inlinevirtualinherited |
submit encoder stage to device return true if successfully submitted; if false is returned the encode state machine will not update the stage value (i.e. if the stage can't be submitted during streaming pause), given the chance to submit the stage at start().
|
inlineinherited |
standard request to pipe
|
inlineinherited |
a synchronous transfer: asynchronous underneath, past timeout the pipe aborted and the transfer failed as timed out - IOKit completes every request, an aborted one included
|
inlinevirtualinherited |
asynchronous USB write request
|
inlineoverrideprotectedvirtual |
async write callback
generates timestamp
Reimplemented from dx::usb::platform::pipe< device_t, interface >.
|
inlinenoexceptinherited |
atomically conclude()s if currently launched; returns whether this call did it
|
inlinenoexceptinherited |
atomically conclude()s if currently launched; returns whether this call did it
|
inlineinherited |
|
inlineinherited |
|
inlineprotectedvirtual |
a vendor transaction's wire bytes past its fill (out; data false: an idle transaction) and ahead of its take (in): returns the bytes the ring takes
|
inlineinherited |
synchronous USB write request
|
friend |
|
friend |
|
friend |
|
friend |
| struct { ... } dx::usb::platform::pipe<device<>, interface>::address |
|
inherited |
origin is set: by the tick that first finds the ring ticking, reset by the run hook
| struct { ... } dx::usb::stream::pipe<device_t, circular_t, stream_t>::async |
|
inherited |
|
inherited |
|
inherited |
audio class endpoint: 2^bRefresh frames between two feedback values
|
inherited |
audio class endpoint: the isoc sync endpoint pacing this one, 0: none
|
protected |
|
protected |
the tick reads the cache, never the promoted: the rate's derivations are the pipeline's, rederived on every commit
|
protectedinherited |
allocated once by initialize()/alloc(); released only by free()
|
protectedinherited |
isoc completions in callback order, filled by the runloop, drained by poll()
|
inherited |
kernel streaming: the driver's buffer switch bookkeeping, set by attach()
|
inherited |
event signalising data arrival(in) or draining(out)
|
protectedinherited |
|
protectedinherited |
|
protectedinherited |
|
protectedinherited |
|
inherited |
the container this stream's ring runs: class and width its participants agreed on
A bus that negotiates it installs its own server; without one the request stands, unless the stream's configuration states its format: that one runs whatever is asked. The seed is the desc's own pin format, so a stream that nobody contradicts runs what it was declared with.
|
protectedinherited |
|
protectedinherited |
|
inherited |
|
protectedinherited |
|
inherited |
|
protected |
|
inherited |
|
inherited |
|
inherited |
|
protected |
a lead set mid-session moves the tick's slots along
|
staticconstexprinherited |
|
inherited |
the ring's index at the device's sample zero: a ticking group keeps every ring's cycle from its device time and this
|
protectedinherited |
|
protectedinherited |
|
protectedinherited |
|
inherited |
|
inherited |
|
inherited |
|
inherited |
|
inherited |
| struct { ... } dx::usb::stream::pipe<device_t, circular_t, stream_t>::sync |
|
inherited |
the tick's own view of this stream's session: set by the run hook once the ring stands, cleared by the halt hook before the session ends - a plain flag, the tick must never block on a promoted's transition
|
inherited |
a synchronous transfer's bound, 0: none
|
inherited |
the ring's one transport while a participant holds it, of the direction the desc declares: none again at its release and at the session's halt
|
protectedinherited |
| struct { ... } dx::usb::platform::pipe<device<>, interface>::winusb |
|
inherited |
the ring's client writers one at a time: a stream's pins write one ring, each on its own port