35#ifndef _OPENLCB_IFCANIMPL_HXX_
36#define _OPENLCB_IFCANIMPL_HXX_
73 if (
nmsg()->payload.size())
93 return src_alias_lookup_done();
106 HASSERT(if_can()->alias_allocator());
108 nmsg()->src.id,
this);
114 LOG(
INFO,
"Allocating new alias %03X for node %012" PRIx64, alias,
119 return allocate_and_call(if_can()->frame_write_flow(),
120 STATE(send_amd_frame));
125 auto *b = get_allocation_result(if_can()->frame_write_flow());
126 struct can_frame *f = b->data()->mutable_frame();
129 uint64_t rd = htobe64(
nmsg()->src.id);
130 memcpy(f->data,
reinterpret_cast<uint8_t *
>(&rd) + 2, 6);
133 return src_alias_lookup_done();
136 Action src_alias_lookup_done()
138 return call_immediately(
STATE(get_can_frame_buffer));
142 Action get_can_frame_buffer()
144 return allocate_and_call(if_can()->frame_write_flow(),
145 STATE(fill_can_frame_buffer));
149 virtual Action fill_can_frame_buffer()
151 auto *b = get_allocation_result(if_can()->frame_write_flow());
152 b->set_done(
message()->new_child());
153 struct can_frame *f = b->data()->mutable_frame();
169 SET_CAN_FRAME_ID_EFF(*f, can_id);
172 bool need_more_frames =
false;
187 f->data[0] |= CanDefs::NOT_FIRST_FRAME;
189 const char *b = data.data();
195 need_more_frames =
true;
196 f->data[0] |= CanDefs::NOT_LAST_FRAME;
200 f->can_dlc = 2 + len;
208 memcpy(f->data, data.data(), data.size());
209 f->can_dlc = data.size();
213 if (need_more_frames)
215 return call_immediately(
STATE(get_can_frame_buffer));
250 if (
nmsg()->payload.size())
264 LOG(
INFO,
"AddressedWriteFlow: Could not resolve destination "
265 "address %012" PRIx64
266 " to an alias on the bus. Dropping packet.",
290 LOG(
INFO,
"AddressedWriteFlow: Caller supplied outdated alias. "
291 "Node id %012" PRIx64
", Result from cache %03x, "
292 "alias from caller %03x.",
305 return call_immediately(
STATE(find_remote_alias));
309 Action find_remote_alias()
311 aliasListener_.RegisterLocalHandler();
317 return allocate_and_call(if_can()->frame_write_flow(),
318 STATE(send_ame_frame));
322 return call_immediately(
STATE(send_verify_nodeid_global));
327 auto *b = get_allocation_result(if_can()->frame_write_flow());
328 struct can_frame *f = b->data();
331 uint64_t rd = htobe64(
nmsg()->dst.id);
332 memcpy(f->data,
reinterpret_cast<uint8_t *
>(&rd) + 2, 6);
338 STATE(send_verify_nodeid_global));
341 Action send_verify_nodeid_global()
345 return call_immediately(
STATE(remote_alias_found));
347 return allocate_and_call(if_can()->global_message_write_flow(),
348 STATE(fill_verify_nodeid_global));
351 Action fill_verify_nodeid_global()
353 auto *b = get_allocation_result(if_can()->global_message_write_flow());
359 STATE(wait_looking_for_dst));
362 Action wait_looking_for_dst()
366 return call_immediately(
STATE(remote_alias_found));
368 LOG(
INFO,
"AddressedWriteFlow: Could not resolve destination "
369 "address %012" PRIx64
" to an alias on the bus. Dropping packet.",
371 aliasListener_.UnregisterLocalHandler();
382 Action remote_alias_found()
409 IfCan* if_can() {
return parent_->if_can(); }
412 void RegisterLocalHandler()
415 this, CAN_FILTER1, CAN_MASK1);
417 this, CAN_FILTER2, CAN_MASK2);
419 this, CAN_FILTER3, CAN_MASK3);
424 void UnregisterLocalHandler()
427 this, CAN_FILTER1, CAN_MASK1);
429 this, CAN_FILTER2, CAN_MASK2);
431 this, CAN_FILTER3, CAN_MASK3);
437 struct can_frame *f =
message->data();
438 uint32_t
id = GET_CAN_FRAME_ID_EFF(*f);
445 uint64_t nodeid_be = htobe64(parent_->
nmsg()->
dst.
id);
446 uint8_t *nodeid_start =
reinterpret_cast<uint8_t *
>(&nodeid_be) + 2;
447 if (memcmp(nodeid_start, f->data, 6))
457 LOG_ERROR(
"Incoming alias definition message with zero alias. "
463 UnregisterLocalHandler();
465 parent_->timer_.trigger();
471 } aliasListener_{
this};
473 friend class AliasDefListener;
475 StateFlowTimer timer_;
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
Base class for all QMember types that hold data in an expandable format.
FrameDispatchFlow * frame_dispatcher()
OutgoingFrameHandler * frame_write_flow()
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.
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
Base::Action Action
Allows using Action without having StateFlowBase:: prefix in front of it.
This helper class listend for incoming CAN frames looking for alias mapping definitions.
void send(Buffer< CanMessageData > *message, unsigned priority) OVERRIDE
Handler callback for incoming messages.
The addressed write flow is responsible for sending addressed messages to the CANbus.
Action send_to_hardware() override
This function will be called (on the main executor) to initiate sending this message to the hardware.
Action entry() override
Entry point of message handling flow.
virtual Action timeout_looking_for_dst()
NodeAlias get_allocated_alias(NodeID destination_id, Executable *done)
Allocates an alias from the reserved but unused aliases list.
NodeAlias lookup(NodeID id)
Lookup a node's alias based on its Node ID.
void add(NodeID id, NodeAlias alias)
Add an alias to an alias cache.
Implements the write-side conversion logic from generic messages to CAN frames.
uint8_t dataOffset_
for continuation frames: which offset in the Buffer should we start the payload at.
Action send_to_hardware() override
This function will be called (on the main executor) to initiate sending this message to the hardware.
Action find_local_alias()
Performs the local alias lookup and branches depending on whether we found a local alias or not.
NodeAlias dstAlias_
Destination node alias.
Action allocate_new_alias()
NodeAlias srcAlias_
Source node alias.
Implementation of the OpenLCB interface abstraction for the CAN-bus interface standard.
AliasCache * local_aliases()
AliasAllocator * alias_allocator()
AliasCache * remote_aliases()
MessageHandler * global_message_write_flow()
Node * lookup_local_node(NodeID id)
Looks up a node ID in the local nodes' registry.
Base class for NMRAnet nodes conforming to the asynchronous interface.
Implementation of the hardware-independent parts of the write flows.
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...
virtual Action send_finished()
Virtual method called after the send is completed, i.e., all the frames are generated and sent to the...
GenMessage * nmsg()
Implementations shall call this function when they are done with sending the packet.
Action addressed_entry()
Addressed write flows should call this state BEFORE sending to the hardware.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#define LOG_ERROR(message...)
Shorthand for LOG(LEVEL_ERROR, message...). See LOG.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
string node_id_to_buffer(NodeID id)
Convenience function to render a 48-bit NMRAnet node ID into a new buffer.
uint64_t NodeID
48-bit NMRAnet Node ID type
static const NodeAlias NOT_RESPONDING
Guard value put into the the internal node alias maps when a node ID could not be translated to a val...
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 ...
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.
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.
@ NMRANET_MSG
normal NMRAnet message
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.
@ AMD_FRAME
Alias Map Definition frame.
@ AME_FRAME
Alias Mapping Enquiry.
@ GLOBAL_ADDRESSED
most CAN frame types fall in this category
@ NORMAL_PRIORITY
normal priority CAN message
@ SRC_MASK
mask for source field of CAN ID
static void set_fields(uint32_t *can_id, NodeAlias src, Defs::MTI mti, CanFrameType can_type, FrameType type, Priority priority)
Set all the CAN ID fields.
@ MTI_VERIFY_NODE_ID_GLOBAL
verify a Node ID globally
@ MTI_RESERVED_MASK
reserved mask
@ MTI_SPECIAL_MASK
special mask
@ MTI_DATAGRAM_MASK
stream or datagram mask
static bool get_mti_address(MTI mti)
Get the MTI address present value field.
NodeHandle dst
Destination node.
Node * dstNode
If the destination node is local, this value is non-NULL.
string payload
Data content in the message body.
Container of both a NodeID and NodeAlias.
NodeID id
48-bit NMRAnet Node ID
NodeAlias alias
alias to NMRAnet Node ID