Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
IfImpl.hxx
Go to the documentation of this file.
1
36#ifndef _OPENLCB_IFIMPL_HXX_
37#define _OPENLCB_IFIMPL_HXX_
38
39#include "openlcb/If.hxx"
40
41namespace openlcb
42{
43
45class WriteFlowBase : public StateFlow<Buffer<GenMessage>, QList<4>>
46{
47public:
50 {
51 }
52
53protected:
60 virtual Action send_to_hardware() = 0;
61
66 virtual Action send_to_local_node();
67
72 {
73 return release_and_exit();
74 }
75
78 {
79 return static_cast<If *>(service());
80 }
81
85 // void cleanup();
86
89 {
90 return message()->data();
91 }
92
93protected:
94 /* /// Entry point for external callers.
95 virtual void WriteAddressedMessage(Defs::MTI mti, NodeID src, NodeHandle
96 dst,
97 Buffer* data, Notifiable* done)
98 {
99 HASSERT(IsNotStarted());
100 Restart(done);
101 mti_ = mti;
102 src_ = src;
103 dst_ = dst;
104 dstNode_ = nullptr;
105 data_ = data;
106 StartFlowAt(STATE(maybe_send_to_local_node));
107 }
108
110 virtual void WriteGlobalMessage(Defs::MTI mti, NodeID src, Buffer* data,
111 Notifiable* done)
112 {
113 HASSERT(IsNotStarted());
114 Restart(done);
115 mti_ = mti;
116 src_ = src;
117 dst_.id = 0;
118 dst_.alias = 0;
119 dstNode_ = nullptr;
120 data_ = data;
121 StartFlowAt(STATE(send_to_local_nodes));
122 }
123 */
124
134};
135
140{
141public:
143 {
144 iface()->dispatcher()->register_handler(
149 }
150
152 {
153 iface()->dispatcher()->unregister_handler(
158 }
159
161 Action entry() override
162 {
163 GenMessage *m = message()->data();
164 if (m->dst.id)
165 {
166 // Addressed message.
167 srcNode_ = m->dstNode;
168 it_ = iface()->localNodes_.end();
169 }
170 else if (!m->payload.empty() && m->payload.size() == 6)
171 {
172 // Global message with a node id included
174 srcNode_ = iface()->lookup_local_node(id);
175 if (!srcNode_)
176 {
177 // Someone looking for a node that's not on this interface.
178 return release_and_exit();
179 }
180#ifndef SIMPLE_NODE_ONLY
181 it_ = iface()->localNodes_.end();
182#endif
183 }
184 else
185 {
186// Global message. Everyone should respond.
187#ifdef SIMPLE_NODE_ONLY
188 // We assume there can be only one local node.
189 If::VNodeMap::Iterator it = iface()->localNodes_.begin();
190 if (it == iface()->localNodes_.end())
191 {
192 // No local nodes.
193 return release_and_exit();
194 }
195 srcNode_ = it->second;
196 ++it;
197 HASSERT(it == iface()->localNodes_.end());
198#else
199 // We need to do an iteration over all local nodes.
200 it_ = iface()->localNodes_.begin();
201 if (it_ == iface()->localNodes_.end())
202 {
203 // No local nodes.
204 return release_and_exit();
205 }
206 srcNode_ = it_->second;
207 ++it_;
208#endif // not simple node.
209 }
210 if (srcNode_)
211 {
212 release();
213 return allocate_and_call(iface()->global_message_write_flow(),
215 }
216 LOG(WARNING, "node pointer not found.");
217 return release_and_exit();
218 }
219
220#ifdef SIMPLE_NODE_ONLY
222 {
223 auto *b =
224 get_allocation_result(iface()->global_message_write_flow());
225 GenMessage *m = b->data();
226 NodeID id = srcNode_->node_id();
228 iface()->global_message_write_flow()->send(b);
229 return exit();
230 }
231#else
233 {
234 auto *b =
235 get_allocation_result(iface()->global_message_write_flow());
236 GenMessage *m = b->data();
237 // This is called on the main executor of the interface, this we are
238 // allowed to access the local nodes cache.
239 NodeID id = srcNode_->node_id();
240 LOG(VERBOSE, "Sending verified reply from node %012" PRIx64, id);
242 iface()->global_message_write_flow()->send(b);
243
248 if (it_ != iface()->localNodes_.end())
249 {
250 srcNode_ = it_->second;
251 ++it_;
252 return allocate_and_call(iface()->global_message_write_flow(),
254 }
255 else
256 {
257 return exit();
258 }
259 }
260#endif // not simple node
261
262private:
263 Node *srcNode_;
264
265#ifndef SIMPLE_NODE_ONLY
266 If::VNodeMap::Iterator it_;
267#endif
268};
269
280{
281public:
283 : IncomingMessageStateFlow(service)
284 {
285 iface()->dispatcher()->register_fallback_handler(this);
286 }
287
289 Action entry() override
290 {
291 if (!message()->data()->dstNode)
292 {
293 // Destination is not a local node.
294 return release_and_exit();
295 }
296 auto mti = message()->data()->mti;
299 // We don't generate an OIR for an incoming error report, as this
300 // generally would cause an infinite bouncing of error reports back
301 // and forth between two OpenMRN nodes.
302 return release_and_exit();
303 }
304 return allocate_and_call(
305 iface()->addressed_message_write_flow(), STATE(fill_oir));
306 }
307
312 {
313 auto rb = get_buffer_deleter(
314 get_allocation_result(iface()->addressed_message_write_flow()));
315 GenMessage *inm = message()->data();
316 GenMessage *outm = rb->data();
318 inm->dstNode->node_id(), inm->src,
319 error_payload(Defs::ERROR_UNIMPLEMENTED, inm->mti));
320 iface()->addressed_message_write_flow()->send(rb.release());
321 return release_and_exit();
322 }
323};
324
325} // namespace openlcb
326
327#endif // _OPENLCB_IFIMPL_HXX_
BufferPtr< T > get_buffer_deleter(Buffer< T > *b)
Helper function to create a BufferPtr of an appropriate type without having to explicitly specify the...
Definition Buffer.hxx:272
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
Definition StateFlow.hxx:61
void register_handler(HandlerType *handler, ID id, ID mask)
Adds a new handler to this dispatcher.
void register_fallback_handler(HandlerType *handler)
Sets one handler to receive all messages that no other handler has matched.
void unregister_handler(HandlerType *handler, ID id, ID mask)
Removes a specific instance of a handler from this dispatcher.
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
A list of queues.
Definition Queue.hxx:466
State flow with a given typed input queue.
void release() OVERRIDE
Unrefs the current buffer.
Base::Action Action
Allows using Action without having StateFlowBase:: prefix in front of it.
MessageType * message()
Abstract class representing an OpenLCB Interface.
Definition If.hxx:185
VNodeMap localNodes_
Local virtual nodes registered on this interface.
Definition If.hxx:383
MessageHandler * global_message_write_flow()
Definition If.hxx:200
MessageDispatchFlow * dispatcher()
Definition If.hxx:224
Node * lookup_local_node(NodeID id)
Looks up a node ID in the local nodes' registry.
Definition If.hxx:263
MessageHandler * addressed_message_write_flow()
Definition If.hxx:210
Base class for incoming message handler flows.
Definition If.hxx:400
Base class for NMRAnet nodes conforming to the asynchronous interface.
Definition Node.hxx:52
Message handler that is registered as a fallback handler in the interface's message dispatcher.
Definition IfImpl.hxx:280
Action fill_oir()
Called after the message buffer allocation is complete.
Definition IfImpl.hxx:311
Action entry() override
Handler callback for incoming messages.
Definition IfImpl.hxx:289
This handler handles VerifyNodeId messages (both addressed and global) on the interface level.
Definition IfImpl.hxx:140
Action entry() override
Handler callback for incoming messages.
Definition IfImpl.hxx:161
Implementation of the hardware-independent parts of the write flows.
Definition IfImpl.hxx:46
virtual Action send_to_local_node()
This state is called when an addressed message's destination is a node that is local to this interfac...
Definition IfImpl.cxx:54
Action global_entry()
Global write flows should return to this state AFTER sending the message to the hardware.
Definition IfImpl.cxx:67
virtual Action send_finished()
Virtual method called after the send is completed, i.e., all the frames are generated and sent to the...
Definition IfImpl.hxx:71
GenMessage * nmsg()
Implementations shall call this function when they are done with sending the packet.
Definition IfImpl.hxx:88
Action addressed_entry()
Addressed write flows should call this state BEFORE sending to the hardware.
Definition IfImpl.cxx:41
virtual Action send_to_hardware()=0
This function will be called (on the main executor) to initiate sending this message to the hardware.
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
Definition logging.h:59
static const int WARNING
Loglevel that is always printed, reporting a warning or a retryable error.
Definition logging.h:55
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
string node_id_to_buffer(NodeID id)
Convenience function to render a 48-bit NMRAnet node ID into a new buffer.
Definition If.cxx:45
uint64_t NodeID
48-bit NMRAnet Node ID type
NodeID buffer_to_node_id(const string &buf)
Converts a 6-byte-long buffer to a node ID.
Definition If.cxx:66
Payload error_payload(uint16_t error_code, Defs::MTI incoming_mti)
Generates the payload for an OIR or TDE message.
Definition If.cxx:135
@ MTI_VERIFY_NODE_ID_ADDRESSED
verify a Node ID
@ MTI_VERIFY_NODE_ID_GLOBAL
verify a Node ID globally
@ MTI_VERIFIED_NODE_ID_NUMBER
respond to a verify Node ID request
@ MTI_OPTIONAL_INTERACTION_REJECTED
rejected request
@ MTI_TERMINATE_DUE_TO_ERROR
terminate due to some error
This class is used in the dispatching of incoming or outgoing NMRAnet messages to the message handler...
Definition If.hxx:72
NodeHandle dst
Destination node.
Definition If.hxx:106
Node * dstNode
If the destination node is local, this value is non-NULL.
Definition If.hxx:110
NodeHandle src
Source node.
Definition If.hxx:104
Defs::MTI mti
OpenLCB MTI of the incoming message.
Definition If.hxx:108
string payload
Data content in the message body.
Definition If.hxx:113
NodeID id
48-bit NMRAnet Node ID