Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
IfCan.cxx
Go to the documentation of this file.
1
35#include "openlcb/IfCan.hxx"
36
37#include "utils/StlMap.hxx"
39#include "openlcb/IfImpl.hxx"
40#include "openlcb/IfCanImpl.hxx"
41#include "openlcb/CanDefs.hxx"
42#include "can_frame.h"
43
44namespace openlcb
45{
46
48
58
64{
65public:
67 : CanMessageWriteFlow(if_can)
68 {
69 }
70
71protected:
72 Action entry() override
73 {
74 return call_immediately(STATE(send_to_hardware));
75 }
76
78 {
79 return call_immediately(STATE(global_entry));
80 }
81};
82
96{
97public:
99 : CanFrameStateFlow(service)
100 {
102 this, 0, ~((1 << 30) - 1));
103 }
104
106 {
108 this, 0, ~((1 << 30) - 1));
109 }
110
112 Action entry() override
113 {
114 uint32_t id = GET_CAN_FRAME_ID_EFF(*message()->data());
115 release();
117 {
118 // Probably not an OpenLCB frame.
120 return exit();
121 }
122 NodeAlias alias = CanDefs::get_src(id);
123 // If the caller comes with alias 000, we ignore that.
124 NodeID node = alias ? if_can()->local_aliases()->lookup(alias) : 0;
125 if (!node)
126 {
127 // This is not a local alias of ours.
128 return exit();
129 }
131 {
132 // Checks for localhost stream data payloads. These are ok to see
133 // in the incoming data since they are looped back.
134 NodeAlias dst = CanDefs::get_dst(id);
135 NodeID dnode = dst ? if_can()->local_aliases()->lookup(dst) : 0;
136 if (dnode)
137 {
138 return exit();
139 }
140 }
141 if (CanDefs::is_cid_frame(id))
142 {
143 // This is a CID frame. We own the alias, let them know.
144 alias_ = alias;
145 return allocate_and_call(
146 if_can()->frame_write_flow(), STATE(send_reserved_alias));
147 }
148 /* Removes the alias from the local alias cache. If it was assigned to
149 * a node, the node will grab a new alias next time it tries to send
150 * something. If it was reserved but not used, then whoever tries to
151 * use it will realize due to the RESERVED_ALIAS_NODE_ID guard missing
152 * from the cache. We do not aggressively start looking for a new
153 * alias in place of the missing one. If we want to do that, we would
154 * have to find the entry in the list of
155 * ifCan_->alias_allocator()->reserved_alias_allocator() and put it
156 * into the empty_alias_allocator() instead to be picked up by the
157 * alias allocator flow. */
159 alias_ = alias;
160 return allocate_and_call(
161 if_can()->frame_write_flow(), STATE(send_release_alias));
162 }
163
169 {
170 auto *b = get_allocation_result(if_can()->frame_write_flow());
171 // We are sending an RID frame.
172 struct can_frame *f = b->data();
174 if_can()->frame_write_flow()->send(b);
175 return exit();
176 }
177
185 {
186 auto b = get_buffer_deleter(
187 get_allocation_result(if_can()->frame_write_flow()));
188
189 NodeID node =
190 alias_ ? if_can()->local_aliases()->lookup(NodeAlias(alias_)) : 0;
191 // Actually purge the table entry.
192 if_can()->local_aliases()->remove(alias_);
193 if (!node || CanDefs::is_reserved_alias_node_id(node))
194 {
195 // We do not have a node ID to use for alias release.
196 return exit();
197 }
198
199 // We are sending an AMR frame to release the alias.
200 struct can_frame *f = b->data();
202 f->can_dlc = 6;
203 node_id_to_data(node, f->data);
204 if_can()->frame_write_flow()->send(b.release());
205 return exit();
206 }
207
208private:
210 unsigned alias_ : 12;
211};
212
216{
217public:
218 enum
219 {
222 CAN_MASK =
224 };
225
227 : CanFrameStateFlow(service)
228 {
230 this, CAN_FILTER, CAN_MASK);
231 }
232
234 {
236 this, CAN_FILTER, CAN_MASK);
237 }
238
240 {
241 struct can_frame *f = message()->data();
242 uint32_t id = GET_CAN_FRAME_ID_EFF(*f);
244 return release_and_exit();
245 auto control_field = CanDefs::get_control_field(id);
246 NodeAlias alias = CanDefs::get_src(id);
247 if (!alias)
248 {
249 return release_and_exit();
250 }
251 NodeID node_id = 0;
252 if (f->can_dlc == 6)
253 {
254 node_id = data_to_node_id(f->data);
255 }
256 switch (control_field)
257 {
259 {
260 if (!node_id)
261 {
262 return release_and_exit();
263 }
264 NodeAlias old_alias =
265 if_can()->remote_aliases()->lookup(node_id);
266 if (old_alias == alias)
267 {
268 // No change.
269 return release_and_exit();
270 }
271 if (old_alias)
272 {
273 if_can()->remote_aliases()->remove(old_alias);
274 }
275 if_can()->remote_aliases()->add(node_id, alias);
276 return release_and_exit();
277 }
279 {
280 if (node_id)
281 {
282 NodeAlias old_alias =
283 if_can()->remote_aliases()->lookup(node_id);
284 if (old_alias && old_alias != alias)
285 {
286 if_can()->remote_aliases()->remove(old_alias);
287 }
288 }
289 if_can()->remote_aliases()->remove(alias);
290 return release_and_exit();
291 }
292 default: // ignore
293 ;
294 }
295
296 return release_and_exit();
297 }
298};
299
303{
304public:
305 enum
306 {
312 };
313
314 AMEQueryHandler(IfCan *service)
315 : CanFrameStateFlow(service)
316 {
318 this, CAN_FILTER, CAN_MASK);
319 }
320
322 {
324 this, CAN_FILTER, CAN_MASK);
325 }
326
328 {
329 struct can_frame *f = message()->data();
330 uint32_t id = GET_CAN_FRAME_ID_EFF(*f);
332 return release_and_exit();}
334 return release_and_exit();}
335 NodeID node_id = 0;
336 if (f->can_dlc == 6)
337 {
338 node_id = data_to_node_id(f->data);
339 }
340 else
341 {
342 return release_and_exit();
343 }
344 NodeAlias local_alias = if_can()->local_aliases()->lookup(node_id);
345 if (!node_id || !local_alias)
346 {
347 return release_and_exit();
348 }
349 auto* b = reinterpret_cast<Buffer<CanHubData>*>(transfer_message());
351 SET_CAN_FRAME_ID_EFF(*b->data()->mutable_frame(), id);
352 if_can()->frame_write_flow()->send(b);
353 return exit();
354 }
355};
356
361 private FlowInterface<Buffer<CanMessageData>>
362{
363public:
366 {
368 this, CAN_FILTER, CAN_MASK);
369 }
370
372 {
374 this, CAN_FILTER, CAN_MASK);
375 }
376
378
379private:
380 enum
381 {
387 };
388
389 IfCan *if_can()
390 {
391 return static_cast<IfCan *>(service());
392 }
393
402 void send(MessageType *msg, unsigned priority = UINT_MAX) override
403 {
405 struct can_frame *f = msg->data();
406 if (f->can_dlc != 0)
407 {
408 return;
409 }
410 needRerun_ = true;
411 // Drops all remote aliases from the cache to re-populate this cache
412 // from the network responses.
413 if_can()->remote_aliases()->clear();
414 if (is_terminated())
415 {
416 start_flow(STATE(rerun));
417 }
418 }
419
420 Action rerun()
421 {
422 needRerun_ = false;
423 nextIndex_ = 0;
424 return call_immediately(STATE(find_next));
425 }
426
427 Action find_next()
428 {
429 while (nextIndex_ < if_can()->local_aliases()->size())
430 {
431 NodeID n;
432 if (if_can()->local_aliases()->retrieve(nextIndex_, &n, nullptr) &&
433 ((n >> (5 * 8)) != 0))
434 {
435 return allocate_and_call(
436 if_can()->frame_write_flow(), STATE(fill_response));
437 }
438 nextIndex_++;
439 }
440 if (needRerun_)
441 {
442 return call_immediately(STATE(rerun));
443 }
444 else
445 {
446 return exit();
447 }
448 }
449
450 Action fill_response()
451 {
452 auto *b = get_allocation_result(if_can()->frame_write_flow());
453 NodeID node;
454 NodeAlias alias;
455 if (if_can()->local_aliases()->retrieve(nextIndex_, &node, &alias))
456 {
457 struct can_frame *f = b->data()->mutable_frame();
458 SET_CAN_FRAME_ID_EFF(
460 f->can_dlc = 6;
461 node_id_to_data(node, f->data);
462 b->set_done(n_.reset(this));
463 if_can()->frame_write_flow()->send(b);
464 nextIndex_++;
465 return wait_and_call(STATE(find_next));
466 }
467 else
468 {
469 // The alias disappeared in the mean time. Release.
470 b->unref();
471 return call_immediately(STATE(find_next));
472 }
473 }
474
477 bool needRerun_ = false;
479 unsigned nextIndex_;
482};
483
489{
490public:
491 enum
492 {
501 };
502
504 : CanFrameStateFlow(service)
505 {
507 this, CAN_FILTER, CAN_MASK);
508 }
509
511 {
513 this, CAN_FILTER, CAN_MASK);
514 }
515
518 {
519 struct can_frame *f = message()->data();
520 id_ = GET_CAN_FRAME_ID_EFF(*f);
521 if (f->can_dlc)
522 {
523 buf_.assign((const char *)(&f->data[0]), f->can_dlc);
524 }
525 else
526 {
527 buf_.clear();
528 }
529 release();
530 // Get the dispatch flow.
531 return allocate_and_call(if_can()->dispatcher(), STATE(send_to_if));
532 }
533
534 Action send_to_if()
535 {
536 auto *b = get_allocation_result(if_can()->dispatcher());
537 GenMessage *m = b->data();
538 m->mti = static_cast<Defs::MTI>(
540 m->payload = buf_;
541 m->dst = {0, 0};
542 m->dstNode = nullptr;
544 // This will be zero if the alias is not known.
545 m->src.id =
546 m->src.alias ? if_can()->remote_aliases()->lookup(m->src.alias) : 0;
547 if (!m->src.id && m->src.alias)
548 {
549 m->src.id = if_can()->local_aliases()->lookup(m->src.alias);
550 }
551 if_can()->dispatcher()->send(b, b->data()->priority());
552 return exit();
553 }
554
555private:
557 uint32_t id_;
559 string buf_;
560};
561
567{
568public:
569 enum
570 {
580 };
581
583 : CanFrameStateFlow(service)
584 {
586 this, CAN_FILTER, CAN_MASK);
587 }
588
590 {
592 this, CAN_FILTER, CAN_MASK);
593 }
594
596 Action entry() override
597 {
598 struct can_frame *f = message()->data();
599 id_ = GET_CAN_FRAME_ID_EFF(*f);
600 // Do we have enough payload for the destination address?
601 if (f->can_dlc < 2)
602 {
603 LOG(WARNING, "Incoming can frame addressed message without payload."
604 " can ID %08x data length %d",
605 (unsigned)id_, f->can_dlc);
606 // Drop the frame.
607 return release_and_exit();
608 }
609 // Gets the destination address and checks if it is our node.
610 dstHandle_.alias = (((unsigned)f->data[0] & 0xf) << 8) | f->data[1];
611 dstHandle_.id = if_can()->local_aliases()->lookup(dstHandle_.alias);
612 if (!dstHandle_.id) // Not destined for us.
613 {
614 LOG(VERBOSE, "Dropping addressed message not for local destination."
615 "id %08x Alias %03x",
616 (unsigned)id_, dstHandle_.alias);
617 // Drop the frame.
618 return release_and_exit();
619 }
620 // Checks the continuation bits.
621 if (f->data[0] & (CanDefs::NOT_FIRST_FRAME | CanDefs::NOT_LAST_FRAME))
622 {
623 uint64_t buffer_key = dstHandle_.alias;
624 buffer_key <<= 12;
625 buffer_key |= CanDefs::get_src(id_);
626 buffer_key <<= 12;
627 buffer_key |= CanDefs::get_mti(id_);
630 Payload *mapped_buffer = &pendingBuffers_[buffer_key];
631 if ((f->data[0] & CanDefs::NOT_FIRST_FRAME) == 0)
632 {
633 // First frame. Make sure the pending buffer is empty.
634 if (!mapped_buffer->empty())
635 {
636 LOG(WARNING, "Received multi-frame message when a previous "
637 "multi-frame message has not been flushed "
638 "yet. frame ID=%08x, fddd=%02x%02x",
639 (unsigned)id_, f->data[0], f->data[1]);
640 }
641 mapped_buffer->clear();
642 }
643 if (f->can_dlc > 2)
644 {
645 mapped_buffer->append(
646 (const char *)(f->data + 2), f->can_dlc - 2);
647 }
648 if (f->data[0] & CanDefs::NOT_LAST_FRAME)
649 {
650 // We are done for now
651 return release_and_exit();
652 }
653 else
654 {
655 // Frame complete.
656 mapped_buffer->swap(buf_);
657 pendingBuffers_.erase(buffer_key);
658 }
659 }
660 else
661 {
662 // Saves the payload.
663 if (f->can_dlc > 2)
664 {
665 buf_.assign((const char *)(f->data + 2), f->can_dlc - 2);
666 }
667 else
668 {
669 buf_.clear();
670 }
671 }
674 release();
675 return allocate_and_call(if_can()->dispatcher(), STATE(send_to_if));
676 }
677
678 Action send_to_if()
679 {
680 auto *b = get_allocation_result(if_can()->dispatcher());
681 GenMessage *m = b->data();
682 m->mti = static_cast<Defs::MTI>(
684 m->payload.swap(buf_);
685 m->dst = dstHandle_;
686 // This might be NULL if dst is a proxied node in a router.
687 m->dstNode = if_can()->lookup_local_node(dstHandle_.id);
688 m->src.alias = id_ & CanDefs::SRC_MASK;
689 // This will be zero if the alias is not known.
690 m->src.id =
691 m->src.alias ? if_can()->remote_aliases()->lookup(m->src.alias) : 0;
692 if (!m->src.id && m->src.alias)
693 {
694 m->src.id = if_can()->local_aliases()->lookup(m->src.alias);
695 }
696 if_can()->dispatcher()->send(b, b->data()->priority());
697 return exit();
698 }
699
700private:
701 uint32_t id_;
702 string buf_;
703 NodeHandle dstHandle_;
706};
707
709 int local_alias_cache_size, int remote_alias_cache_size,
710 int local_nodes_count)
711 : If(executor, local_nodes_count)
712 , CanIf(this, device)
713 , localAliases_(0, local_alias_cache_size)
714 , remoteAliases_(0, remote_alias_cache_size)
715{
716 auto *gflow = new GlobalCanMessageWriteFlow(this);
717 globalWriteFlow_ = gflow;
718 add_owned_flow(gflow);
719
728 /*pipe_member_.reset(new CanReadFlow(device, this, executor));
729 for (int i = 0; i < hw_write_flow_count; ++i)
730 {
731 CanFrameWriteFlow *f = new CanWriteFlow(this, executor);
732 write_allocator_.Release(f);
733 owned_flows_.push_back(std::unique_ptr<ControlFlow>(f));
734 }
735 for (int i = 0; i < global_can_write_flow_count; ++i)
736 {
737 owned_flows_.push_back(
738 std::unique_ptr<Executable>(new GlobalCanMessageWriteFlow(this)));
739 }*/
740}
741
742IfCan::~IfCan()
743{
744}
745
747{
748 ownedFlows_.push_back(std::unique_ptr<Executable>(e));
749}
750
755
757{
758 if (!source->is_initialized())
759 {
760 LOG_ERROR("Tried to send global AME from not initialized node.");
761 return;
762 }
763 NodeAlias send_alias = local_aliases()->lookup(source->node_id());
764 if (!send_alias)
765 {
766 LOG_ERROR("Tried to send global AME without a local alias.");
767 return;
768 }
769 {
770 auto *b = frame_write_flow()->alloc();
771 CanDefs::control_init(*b->data(), send_alias, CanDefs::AME_FRAME, 0);
772 // Sends it out
774 }
775 {
776 // Sends another to the local node, but not using the local alias.
777 auto *b = frame_dispatcher()->alloc();
778 CanDefs::control_init(*b->data(), 0, CanDefs::AME_FRAME, 0);
780 }
781}
782
792
794 remove_local_node_from_map(node);
795 auto alias = localAliases_.lookup(node->node_id());
796 if (alias) {
797 // The node had a local alias.
798 localAliases_.remove(alias);
800 // Sends AMR & returns alias to pool.
801 aliasAllocator_->return_alias(node->node_id(), alias);
802 }
803}
804
805
807{
808 if (!h->id && !h->alias)
809 return;
810 if (!h->id)
811 {
812 h->id = local_aliases()->lookup(h->alias);
813 }
814 if (!h->id)
815 {
816 h->id = remote_aliases()->lookup(h->alias);
817 }
818 if (!h->alias)
819 {
820 h->alias = local_aliases()->lookup(h->id);
821 }
822 if (!h->alias)
823 {
824 h->alias = remote_aliases()->lookup(h->id);
825 }
826}
827
829{
830 canonicalize_handle(&expected);
831 canonicalize_handle(&actual);
832 if (expected.id && actual.id)
833 {
834 return expected.id == actual.id;
835 }
836 if (expected.alias && actual.alias)
837 {
838 return expected.alias == actual.alias;
839 }
840 // Cannot reconcile.
841 LOG(VERBOSE, "Cannot reconcile expected and actual NodeHandles for "
842 "equality testing.");
843 return false;
844}
845
847{
848 if (!h.id)
849 {
850 h.id = local_aliases()->lookup(h.alias);
851 }
852 return lookup_local_node(h.id);
853}
854
856{
857 if (!aliasAllocator_)
858 {
859 return 0;
860 }
861 return aliasAllocator_->if_node_id();
862}
863
864} // namespace openlcb
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
std::unique_ptr< Buffer< T >, BufferDelete< T > > AutoReleaseBuffer
This class will automatically unref a Buffer when going out of scope.
Definition Buffer.hxx:256
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
Definition StateFlow.hxx:61
A BarrierNotifiable allows to create a number of child Notifiable and wait for all of them to finish.
BarrierNotifiable * reset(Notifiable *done)
Resets the barrier. Returns &*this. Asserts that is_done().
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
Interface class for CANbus-based protocols.
Definition CanIf.hxx:185
FrameDispatchFlow * frame_dispatcher()
Definition CanIf.hxx:208
OutgoingFrameHandler * frame_write_flow()
Definition CanIf.hxx:214
void register_handler(HandlerType *handler, ID id, ID mask)
Adds a new handler to this dispatcher.
void unregister_handler(HandlerType *handler, ID id, ID mask)
Removes a specific instance of a handler from this dispatcher.
An object that can be scheduled on an executor to run.
This class implements an execution of tasks pulled off an input queue.
Definition Executor.hxx:64
Abstract class for message recipients.
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
MessageType * alloc()
Synchronously allocates a message buffer from the pool of this flow.
Base class for state machines.
Service * service()
Return a pointer to the service I am bound to.
bool is_terminated()
Action allocate_and_call(FlowInterface< Buffer< T > > *target_flow, Callback c, Pool *pool=nullptr)
Allocates a buffer from a pool and proceed to the next state when allocation is successful.
StateFlowBase()
Default constructor.
Action exit()
Terminate current StateFlow activity.
void start_flow(Callback c)
Resets the flow to the specified state and starts it.
Buffer< T > * get_allocation_result(FlowInterface< Buffer< T > > *target_flow)
Takes the result of the asynchronous allocation.
Action call_immediately(Callback c)
Imediately call the next state upon return.
Action wait_and_call(Callback c)
Wait for resource to become available before proceeding to next state.
Though at the surface, this may seem like an unnecessary abstraction of std::map, it has the purpose ...
Definition StlMap.hxx:50
size_t erase(Key key)
Remove an element from the tree.
Definition StlMap.hxx:102
void release() OVERRIDE
Unrefs the current buffer.
Base::Action Action
Allows using Action without having StateFlowBase:: prefix in front of it.
void send(MessageType *msg, unsigned priority=UINT_MAX) OVERRIDE
Sends a message to the state flow for processing.
MessageType * transfer_message()
Releases ownership of the current message.
MessageType * message()
This class listens for Alias Mapping Enquiry frames with no destination node ID (aka global alias enq...
Definition IfCan.cxx:362
unsigned nextIndex_
Which alias entry index we take next.
Definition IfCan.cxx:479
BarrierNotifiable n_
Helper object to wait for frame to be sent.
Definition IfCan.cxx:481
void send(MessageType *msg, unsigned priority=UINT_MAX) override
Sends a message to the state flow for processing.
Definition IfCan.cxx:402
bool needRerun_
This boolean will be set to true when a full re-run of all sent frames is necessary.
Definition IfCan.cxx:477
This class listens for alias mapping enquiry frames targeted for local nodes, and replies with AMD fr...
Definition IfCan.cxx:303
Action entry() OVERRIDE
Entry into the StateFlow activity.
Definition IfCan.cxx:327
The addressed write flow is responsible for sending addressed messages to the CANbus.
This state flow is responsible for reserving node ID aliases.
void remove(NodeAlias alias)
Remove an alias from an alias cache.
NodeAlias lookup(NodeID id)
Lookup a node's alias based on its Node ID.
void clear()
Reinitializes the entire map.
void add(NodeID id, NodeAlias alias)
Add an alias to an alias cache.
This class listens for incoming CAN messages, and if it sees a local alias conflict,...
Definition IfCan.cxx:96
unsigned alias_
Alias being checked.
Definition IfCan.cxx:210
Action send_release_alias()
Sends an AMR (alias mapping release) frame with the alias alias_ and the local node ID that we have f...
Definition IfCan.cxx:184
Action entry() override
Handler callback for incoming messages.
Definition IfCan.cxx:112
Action send_reserved_alias()
Sends an RID with the alias alias_.
Definition IfCan.cxx:168
Base class for incoming CAN frame handlers.
Definition IfCan.hxx:164
Implements the write-side conversion logic from generic messages to CAN frames.
Definition IfCanImpl.hxx:51
Action send_to_hardware() override
This function will be called (on the main executor) to initiate sending this message to the hardware.
Definition IfCanImpl.hxx:68
This class listens for incoming CAN frames of regular addressed OpenLCB messages destined for local n...
Definition IfCan.cxx:567
Action entry() override
Handler entry for incoming messages.
Definition IfCan.cxx:596
StlMap< uint32_t, Payload > pendingBuffers_
Reassembly buffers for multi-frame messages.
Definition IfCan.cxx:705
This class listens for incoming CAN frames of regular unaddressed global OpenLCB messages,...
Definition IfCan.cxx:489
string buf_
Payload for the MTI message.
Definition IfCan.cxx:559
uint32_t id_
CAN frame ID, saved from the incoming frame.
Definition IfCan.cxx:557
Action entry() OVERRIDE
Handler entry for incoming messages.
Definition IfCan.cxx:517
This write flow inherits all the business logic from the parent, just maintains a separate allocation...
Definition IfCan.cxx:64
Action send_finished() override
Virtual method called after the send is completed, i.e., all the frames are generated and sent to the...
Definition IfCan.cxx:77
Action entry() override
Entry into the StateFlow activity.
Definition IfCan.cxx:72
Implementation of the OpenLCB interface abstraction for the CAN-bus interface standard.
Definition IfCan.hxx:65
std::vector< std::unique_ptr< Executable > > ownedFlows_
Various implementation control flows that this interface owns.
Definition IfCan.hxx:154
void add_addressed_message_support()
Adds support to this interface for addressed NMRAnet messages (both sending and receiving).
Definition IfCan.cxx:783
Node * lookup_local_node_handle(NodeHandle handle) override
Looks up a node ID in the local nodes' registry.
Definition IfCan.cxx:846
void send_global_alias_enquiry(Node *source)
Sends a global alias enquiry packet.
Definition IfCan.cxx:756
void set_alias_allocator(AliasAllocator *a)
Sets the alias allocator for this If. Takes ownership of pointer.
Definition IfCan.cxx:751
AliasCache localAliases_
Aliases we know are owned by local (virtual or proxied) nodes.
Definition IfCan.hxx:146
NodeID get_default_node_id() override
Definition IfCan.cxx:855
bool matching_node(NodeHandle expected, NodeHandle actual) override
Definition IfCan.cxx:828
IfCan(ExecutorBase *executor, CanHubFlow *device, int local_alias_cache_size, int remote_alias_cache_size, int local_nodes_count)
Creates a CAN interface.
Definition IfCan.cxx:708
std::unique_ptr< AliasAllocator > aliasAllocator_
Owns the alias allocator module.
Definition IfCan.hxx:157
AliasCache * local_aliases()
Definition IfCan.hxx:96
void delete_local_node(Node *node) override
Removes a local node from this interface.
Definition IfCan.cxx:793
AliasCache * remote_aliases()
Definition IfCan.hxx:103
void add_owned_flow(Executable *e) override
Transfers ownership of a module to the interface.
Definition IfCan.cxx:746
void canonicalize_handle(NodeHandle *h) override
Canonicalizes the node handle: fills in id and/or alias from the maps the interface holds internally.
Definition IfCan.cxx:806
Abstract class representing an OpenLCB Interface.
Definition If.hxx:185
MessageDispatchFlow * dispatcher()
Definition If.hxx:224
MessageHandler * addressedWriteFlow_
Allocator containing the addressed write flows.
Definition If.hxx:371
Node * lookup_local_node(NodeID id)
Looks up a node ID in the local nodes' registry.
Definition If.hxx:263
MessageHandler * globalWriteFlow_
Allocator containing the global write flows.
Definition If.hxx:369
Base class for NMRAnet nodes conforming to the asynchronous interface.
Definition Node.hxx:52
virtual bool is_initialized()=0
This class listens for alias mapping frames and updates the remote alias cache with the incoming info...
Definition IfCan.cxx:216
Action entry() OVERRIDE
Entry into the StateFlow activity.
Definition IfCan.cxx:239
Message handler that is registered as a fallback handler in the interface's message dispatcher.
Definition IfImpl.hxx:280
This handler handles VerifyNodeId messages (both addressed and global) on the interface level.
Definition IfImpl.hxx:140
Action global_entry()
Global write flows should return to this state AFTER sending the message to the hardware.
Definition IfImpl.cxx:67
#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 LOG_ERROR(message...)
Shorthand for LOG(LEVEL_ERROR, message...). See LOG.
Definition logging.h:124
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
void node_id_to_data(NodeID id, void *data)
Convenience function to render a 48-bit NMRAnet node ID into an existing buffer.
Definition If.cxx:52
NodeID data_to_node_id(const void *d)
Converts 6 bytes of big-endian data to a node ID.
Definition If.cxx:59
uint64_t NodeID
48-bit NMRAnet Node ID type
size_t g_alias_use_conflicts
Counts the number of alias conflicts that we see for aliases that we already reserved.
Definition IfCan.cxx:47
string Payload
Container that carries the data bytes in an NMRAnet message.
uint16_t NodeAlias
Alias to a 48-bit NMRAnet Node ID type.
long long ADDRESSED_MESSAGE_LOOKUP_TIMEOUT_NSEC
Specifies how long to wait for a response to an alias mapping enquiry message when trying to send an ...
Definition IfCan.cxx:57
#define SEC_TO_NSEC(_sec)
Convert a second value to a nanosecond value.
Definition os.h:286
static const uint32_t CAN_EXT_FRAME_MASK
Mask to OR onto a can mask to tell the dispatcher to only consider extended can frames.
Definition CanIf.hxx:69
static const uint32_t CAN_EXT_FRAME_FILTER
Filter to OR onto a can ID to tell the dispatcher to only consider extended can frames.
Definition CanIf.hxx:66
static bool is_cid_frame(uint32_t can_id)
Tests if the incoming frame is a CID frame.
Definition CanDefs.hxx:208
static NodeID get_reserved_alias_node_id(NodeAlias alias)
Computes a reserved alias node ID for the local alias cache map.
Definition CanDefs.hxx:389
@ NMRANET_MSG
normal NMRAnet message
Definition CanDefs.hxx:112
@ CONTROL_MSG
CAN control frame message.
Definition CanDefs.hxx:111
static ControlField get_control_field(uint32_t can_id)
Get the control field of a can control frame.
Definition CanDefs.hxx:334
static void control_init(struct can_frame &frame, NodeAlias src, uint16_t field, int sequence)
Initialize a control frame CAN ID and set DLC to 0.
Definition CanDefs.hxx:379
static NodeAlias get_dst(uint32_t can_id)
Get the destination field value of the CAN ID.
Definition CanDefs.hxx:172
static FrameType get_frame_type(uint32_t can_id)
Get the frame type field value of the CAN ID.
Definition CanDefs.hxx:190
static uint32_t set_control_fields(NodeAlias src, uint16_t field, int sequence)
Initialize a control frame CAN ID and set DLC to 0.
Definition CanDefs.hxx:365
static CanMTI get_mti(uint32_t can_id)
Get the MTI field value of the CAN ID.
Definition CanDefs.hxx:163
@ AMD_FRAME
Alias Map Definition frame.
Definition CanDefs.hxx:127
@ AME_FRAME
Alias Mapping Enquiry.
Definition CanDefs.hxx:128
@ RID_FRAME
Reserve ID Frame.
Definition CanDefs.hxx:126
@ AMR_FRAME
Alias Map Reset.
Definition CanDefs.hxx:129
static Priority get_priority(uint32_t can_id)
Get the priority field value of the CAN ID.
Definition CanDefs.hxx:199
static bool is_reserved_alias_node_id(NodeID id)
Tests if a node ID is a reserved alias Node ID.
Definition CanDefs.hxx:397
@ GLOBAL_ADDRESSED
most CAN frame types fall in this category
Definition CanDefs.hxx:100
@ NORMAL_PRIORITY
normal priority CAN message
Definition CanDefs.hxx:121
static NodeAlias get_src(uint32_t can_id)
Get the source field value of the CAN ID.
Definition CanDefs.hxx:154
static bool is_stream_frame(uint32_t can_id)
Tests if the incoming frame is a stream data send frame.
Definition CanDefs.hxx:217
@ FRAME_TYPE_MASK
mask for frame type field of CAN ID
Definition CanDefs.hxx:66
@ SRC_MASK
mask for source field of CAN ID
Definition CanDefs.hxx:62
@ FRAME_TYPE_SHIFT
shift for frame type field of CAN ID
Definition CanDefs.hxx:75
@ CONTROL_FIELD_MASK
control field data mask
Definition CanDefs.hxx:80
@ MTI_MASK
mask for MTI field of CAN ID
Definition CanDefs.hxx:63
@ CONTROL_FIELD_SHIFT
control field data shift
Definition CanDefs.hxx:87
@ CAN_FRAME_TYPE_SHIFT
shift for can frame type field of CAN ID
Definition CanDefs.hxx:74
@ CAN_FRAME_TYPE_MASK
mask for can frame type field of CAN ID
Definition CanDefs.hxx:65
@ PRIORITY_SHIFT
shift for priority field of CAN ID
Definition CanDefs.hxx:76
@ PRIORITY_MASK
mask for priority field of CAN ID
Definition CanDefs.hxx:67
@ MTI_SHIFT
shift for MTI field of CAN ID
Definition CanDefs.hxx:72
MTI
Known Message type indicators.
@ MTI_ADDRESS_MASK
Address present mask.
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
Container of both a NodeID and NodeAlias.
NodeID id
48-bit NMRAnet Node ID
NodeAlias alias
alias to NMRAnet Node ID