Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
WriteHelper.hxx
Go to the documentation of this file.
1
35#ifndef _OPENLCB_WRITEHELPER_HXX_
36#define _OPENLCB_WRITEHELPER_HXX_
37
38#include <string>
39
40#include "nmranet_config.h"
41
42#include "openlcb/If.hxx"
43#include "openlcb/Node.hxx"
44
45namespace openlcb
46{
47
51class WriteHelper : public Executable
52{
53public:
54 typedef Node *node_type;
55 typedef string payload_type;
56
57 static NodeHandle global()
58 {
59 return {0, 0};
60 }
61
63 : waitForLocalLoopback_(0)
64 {
65 }
66
67 const payload_type &last_payload()
68 {
69 return buffer_;
70 }
71
72 void clear_last_payload()
73 {
74 buffer_.clear();
75 }
76
77 void set_wait_for_local_loopback(bool wait = true)
78 {
79 waitForLocalLoopback_ = (wait ? 1 : 0);
80 }
81
91 void WriteAsync(Node *node, Defs::MTI mti, NodeHandle dst,
92 const payload_type &buffer, Notifiable *done)
93 {
94 if (done)
95 {
96 done_.reset(done);
97 }
98 else
99 {
100 // We don't support synchronous sending anymore.
101 HASSERT(0);
102 }
103 if (!node ||
105 {
106 done_.notify();
107 return;
108 }
109 node_ = node;
110 mti_ = mti;
111 dst_ = dst;
112 buffer_ = buffer;
113 if (dst == global())
114 {
115 node->iface()->global_message_write_flow()->alloc_async(this);
116 }
117 else
118 {
120 this);
121 }
122 }
123
124private:
125 // Callback from the allocator.
126 void alloc_result(QMember *entry) override
127 {
128 /* NOTE(balazs.racz): We could choose not to pass on the done_
129 * callback. That will allow the current write flow to be released
130 * earlier for reuse, but breaks the assumption that done means that
131 * the current packet is enqueued on the physical layer. */
132 if (dst_ == global())
133 {
134 auto *f = node_->iface()->global_message_write_flow();
135 Buffer<GenMessage> *b = f->cast_alloc(entry);
136 b->data()->reset(mti_, node_->node_id(), buffer_);
137 if (waitForLocalLoopback_)
138 {
139 b->data()->set_flag_dst(
141 }
142 b->set_done(&done_);
143 f->send(b, b->data()->priority());
144 }
145 else
146 {
147 auto *f = node_->iface()->addressed_message_write_flow();
148 auto *b = f->cast_alloc(entry);
149 b->data()->reset(mti_, node_->node_id(), dst_, buffer_);
150 if (waitForLocalLoopback_)
151 {
152 b->data()->set_flag_dst(
154 }
155 b->set_done(&done_);
156 f->send(b, b->data()->priority());
157 }
158 }
159
160 void run() override
161 {
162 HASSERT(0);
163 }
164
165 unsigned waitForLocalLoopback_ : 1;
166 NodeHandle dst_;
167 Defs::MTI mti_;
168 Node *node_;
169 payload_type buffer_;
170 BarrierNotifiable done_;
171};
172
173}; /* namespace openlcb */
174
175#endif // _OPENLCB_WRITEHELPER_HXX_
A BarrierNotifiable allows to create a number of child Notifiable and wait for all of them to finish.
void notify() override
Implementation of the barrier semantics.
BarrierNotifiable * reset(Notifiable *done)
Resets the barrier. Returns &*this. Asserts that is_done().
void set_done(BarrierNotifiable *done)
Specifies that a given BarrierNotifiable must be called when the Buffer is deallocated (unreffed to z...
Definition Buffer.hxx:97
Base class for all QMember types that hold data in an expandable format.
Definition Buffer.hxx:195
T * data()
get a pointer to the start of the data.
Definition Buffer.hxx:215
An object that can be scheduled on an executor to run.
static MessageType * cast_alloc(QMember *entry)
Down casts and initializes an asynchronous allocation result to the appropriate flow's buffer type.
void alloc_async(Executable *target)
Asynchronously allocates a message buffer from the pool of this flow.
An object that can schedule itself on an executor to run.
Essentially a "next" pointer container.
Definition QMember.hxx:42
MessageHandler * global_message_write_flow()
Definition If.hxx:200
MessageHandler * addressed_message_write_flow()
Definition If.hxx:210
Base class for NMRAnet nodes conforming to the asynchronous interface.
Definition Node.hxx:52
virtual bool is_initialized()=0
A statically allocated buffer for sending one message to the OpenLCB bus.
void run() override
Entry point.
void WriteAsync(Node *node, Defs::MTI mti, NodeHandle dst, const payload_type &buffer, Notifiable *done)
Originates an NMRAnet message from a particular node.
void alloc_result(QMember *entry) override
Return the result of an alloc_async() from a memory Pool.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
MTI
Known Message type indicators.
@ MTI_INITIALIZATION_COMPLETE
initialization complete
@ WAIT_FOR_LOCAL_LOOPBACK
Specifies that the stack should wait for the local loopback processing before invoking the done notif...
Definition If.hxx:159
Container of both a NodeID and NodeAlias.