77 result_ = OPERATION_PENDING;
86 DIE(
"Canceling datagram send operation is not yet implemented.");
121 c; c = c->LinkedObject<DatagramClientImpl>::link_next())
124 if (!c->sendPending_)
continue;
125 if (c->src_.id !=
src_.
id)
continue;
126 if (!
iface()->matching_node(c->dst_,
dst_))
131 c->waitingClients_.push_front(
this);
148 b->set_done(
nullptr);
156 STATE(timeout_waiting_for_dg_response));
163 MASK_1 = ~(MTI_1a ^ MTI_1b),
167 MASK_2 = ~(MTI_2a ^ MTI_2b),
173 void register_handlers()
189 result_ |= PERMANENT_ERROR | DST_NOT_FOUND;
190 unregister_response_handler();
194 Action timeout_waiting_for_dg_response()
197 "CanDatagramWriteFlow: No datagram response arrived from "
198 "destination %012" PRIx64
".",
201 unregister_response_handler();
202 result_ |= PERMANENT_ERROR | TIMEOUT;
206 void unregister_response_handler()
214 DatagramClientImpl *c =
217 HASSERT(c->waitingClients_.empty());
223 Action datagram_finalize()
226 HASSERT(result_ & OPERATION_PENDING);
227 result_ &= ~OPERATION_PENDING;
267 if (message->
payload.size() != 6)
274 if (
iface()->matching_node(
dst_, rebooted))
277 result_ |= DST_REBOOT;
296 uint16_t error_code = 0;
297 uint8_t payload_length = 0;
298 const uint8_t *payload =
nullptr;
302 reinterpret_cast<const uint8_t *
>(message->
payload.data());
303 payload_length = message->
payload.size();
305 if (payload_length >= 2)
307 error_code = (((uint16_t)payload[0]) << 8) | payload[1];
310 switch (message->
mti)
315 if (payload_length >= 4)
317 uint16_t return_mti = payload[2];
319 return_mti |= payload[3];
332 result_ |= error_code;
334 if (!(result_ & (PERMANENT_ERROR | RESEND_OK)))
336 result_ |= PERMANENT_ERROR;
344 result_ &= ~(0xff << RESPONSE_FLAGS_SHIFT);
345 result_ |= payload[0] << RESPONSE_FLAGS_SHIFT;
347 result_ |= OPERATION_SUCCESS;
363 unregister_response_handler();
373 LOG(
VERBOSE,
"restarting at datagram finalize");
420 unsigned hasResponse_ : 1;
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
See OSMutexLock in os/OS.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 * new_child()
Call this for each child task.
Base class for all QMember types that hold data in an expandable format.
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 add(Executable *action, unsigned priority=UINT_MAX)=0
Send a message to this Executor's queue.
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
Using this class as a base class will cause the given class to have all its instances linked up in a ...
ExecutorBase * executor()
Return type for a state flow callback.
Use this timer class to deliver the timeout notification to a stateflow.
Base class for state machines.
Service * service()
Return a pointer to the service I am bound to.
void start_flow(Callback c)
Resets the flow to the specified state and starts it.
Action wait()
Wait for an asynchronous call.
void reset_flow(Callback c)
Resets the flow to the specified state.
Action call_immediately(Callback c)
Imediately call the next state upon return.
Action set_terminated()
Sets the flow to terminated state.
Action sleep_and_call(::Timer *timer, long long timeout_nsec, Callback c)
Suspends execution of this control flow for a specified time.
void trigger()
This will wakeup the timer prematurely, immediately.
A simple, fast, type-safe single-linked queue class with non-virtual methods.
T * pop_front()
Removes the entry at the front of the queue.
This object is registered to receive response messages at the interface level.
void send(message_type *buffer, unsigned priority=UINT_MAX) OVERRIDE
Entry point to the flow.
Datagram client implementation for CANbus-based datagram protocol.
Action timeout_looking_for_dst()
unsigned isSleeping_
1 when we are in the sleep call waiting for the datagram Ack or Reject message.
MessageHandler * sendFlow_
Addressed datagram send flow from the interface. Externally owned.
BarrierNotifiable * done_
This notifiable is saved from the datagram buffer.
DatagramClientImpl(If *iface, MessageHandler *send_flow)
Constructor.
void notify() override
Overrides the default notify implementation to make sure we obey the priority values.
void cancel() OVERRIDE
Requests cancelling the datagram send operation.
Action do_send()
Hands off the datagram to the send flow.
TypedQueue< Executable > waitingClients_
List of other datagram clients that are trying to send to the same target node.
unsigned sendPending_
1 when we have the handlers registered.
StateFlowTimer timer_
Helper object for sleep.
void set_priority(unsigned p)
Sets the stateflow priority.
ReplyListener listener_
Instance of the listener object.
NodeHandle dst_
Destination of the datagram we are currently sending.
Action start_send()
Entry point to the flow processing.
void write_datagram(Buffer< GenMessage > *b, unsigned priority) OVERRIDE
Triggers sending a datagram.
void reset_message(Buffer< GenMessage > *b, unsigned priority)
Equivalent to enqueuing a new datagram to send.
void handle_response(GenMessage *message)
Callback when a matching response comes in on the bus.
static constexpr unsigned MAX_PRIORITY
Constant used to clamp the incoming priority value to something that first in priority_ bit field.
Buffer< GenMessage > * message_
Datagram message we are trying to send now. We own it.
unsigned priority_
Priority in the executor.
void stop_waiting_for_response()
To be called from the handler.
NodeHandle src_
Source of the datagram we are currently sending.
Action acquire_srcdst_lock()
Ensures that there is no other datagram client with the same src:dst pair.
Use this class to send datagrams.
Abstract class representing an OpenLCB Interface.
virtual void canonicalize_handle(NodeHandle *h)
Canonicalizes the node handle: fills in id and/or alias from the maps the interface holds internally.
MessageDispatchFlow * dispatcher()
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#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.
#define DIE(MSG)
Unconditionally terminates the current process with a message.
long long DATAGRAM_RESPONSE_TIMEOUT_NSEC
Defines how long the datagram client flow should wait for the datagram ack/nack response message.
NodeID buffer_to_node_id(const string &buf)
Converts a 6-byte-long buffer to a node ID.
@ MTI_DATAGRAM_REJECTED
datagram rejected by receiver
@ MTI_EXACT
match mask for a single MTI
@ MTI_DATAGRAM_OK
datagram received okay
@ MTI_INITIALIZATION_COMPLETE
initialization complete
@ 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...
NodeHandle dst
Destination node.
NodeHandle src
Source node.
Defs::MTI mti
OpenLCB MTI of the incoming message.
string payload
Data content in the message body.
Container of both a NodeID and NodeAlias.
NodeID id
48-bit NMRAnet Node ID