35#ifndef _OPENLCB_TRACTIONTHROTTLE_HXX_
36#define _OPENLCB_TRACTIONTHROTTLE_HXX_
70 using Command = TractionThrottleInput::Command;
78 ERROR_UNASSIGNED = 0x4000000,
79 ERROR_ASSIGNED = 0x4010000,
85 TractionDefs::speed_set_payload(speed));
111 void set_fn(uint32_t address, uint16_t value)
override
114 TractionDefs::fn_set_payload(address, value));
118 uint16_t
get_fn(uint32_t address)
override
130 auto fnstate =
get_fn(fn);
157 return dcc::TrainAddressType::DCC_SHORT_ADDRESS;
205 switch (
message()->data()->cmd)
207 case Command::CMD_SET_DST:
216 case Command::CMD_ASSIGN_TRAIN:
228 case Command::CMD_RELEASE_TRAIN:
239 case Command::CMD_LOAD_STATE:
247 case Command::CMD_CONSIST_ADD:
259 case Command::CMD_CONSIST_DEL:
271 case Command::CMD_CONSIST_QRY:
280 LOG_ERROR(
"Unknown traction throttle command %d received.",
286 Action release_train()
293 bool found_other_throttle =
false;
298 p && !found_other_throttle;
299 p = p->LinkedObject<TractionThrottle>::link_next())
306 if (p->node_ != node_)
317 if (!p->listenConsist_)
322 found_other_throttle =
true;
325 if (!found_other_throttle)
329 TractionDefs::RESP_CONSIST_CONFIG, &timer_);
331 TractionDefs::consist_del_payload(node_->node_id()));
336 "skipping unregister consist because of another throttle.");
343 Action release_listener_response()
354 Action release_step_2()
359 if (input()->cmd == Command::CMD_ASSIGN_TRAIN)
370 Action assign_train()
374 NodeHandle(dst_), TractionDefs::RESP_CONTROLLER_CONFIG, &timer_);
379 Action assign_response()
389 if (payload.size() < 3)
393 if (payload[1] != TractionDefs::CTRLRESP_ASSIGN_CONTROLLER)
408 NodeHandle(dst_), TractionDefs::RESP_CONSIST_CONFIG, &timer_);
411 TractionDefs::CNSTFLAGS_HIDE | TractionDefs::CNSTFLAGS_LINKF0 |
412 TractionDefs::CNSTFLAGS_LINKFN));
419 Action assign_consist_response()
481 if (msg->
data()->dstNode != node_)
495 case TractionDefs::RESP_QUERY_SPEED:
511 case TractionDefs::RESP_QUERY_FN:
525 case TractionDefs::RESP_TRACTION_MGMT:
527 if (p.size() >= 2 && p[1] == TractionDefs::MGMTRESP_HEARTBEAT)
539 NodeHandle(dst_), TractionDefs::RESP_CONSIST_CONFIG, &timer_);
541 TractionDefs::consist_add_payload(input()->dst, input()->flags));
548 NodeHandle(dst_), TractionDefs::RESP_CONSIST_CONFIG, &timer_);
553 Action consist_add_response()
563 if (payload.size() < 9)
567 if (
message()->data()->cmd == Command::CMD_CONSIST_ADD)
569 if (payload[1] != TractionDefs::CNSTRESP_ATTACH_NODE)
575 else if (
message()->data()->cmd == Command::CMD_CONSIST_DEL)
577 if (payload[1] != TractionDefs::CNSTRESP_DETACH_NODE)
586 uint16_t e = payload[8];
596 NodeHandle(dst_), TractionDefs::RESP_CONSIST_CONFIG, &timer_);
597 if (input()->replyCause == 0xff)
604 TractionDefs::consist_qry_payload(input()->consistIndex));
610 Action consist_qry_response()
620 if (payload.size() < 3)
624 if (payload[1] != TractionDefs::CNSTRESP_QUERY_NODES)
630 if (payload.size() >= 11) {
632 input()->
flags = payload[4];
636 input()->
flags = 0xff;
649 if (msg->
data()->dstNode != node_)
671 case TractionDefs::REQ_SET_SPEED:
686 case TractionDefs::REQ_EMERGENCY_STOP:
695 case TractionDefs::REQ_SET_FN:
725 std::function<void()> f = std::bind(
752 p = p->LinkedObject<TractionThrottle>::link_next();
763 if (p->node_ != node_)
789 }
while (p !=
nullptr);
812 b->data()->reset(Defs::MTI_TRACTION_CONTROL_COMMAND, node_->node_id(),
825 void clear_listening()
838 void clear_assigned()
855 TractionThrottleInput *input()
864 return static_cast<If *
>(
service());
867 MessageHandler::GenericHandler speedReplyHandler_{
869 MessageHandler::GenericHandler listenReplyHandler_{
874 StateFlowTimer timer_{
this};
BufferPtr< T > get_buffer_deleter(Buffer< T > *b)
Helper function to create a BufferPtr of an appropriate type without having to explicitly specify the...
AutoReleaseBuffer< T > BufferPtr
Smart pointer for buffers.
std::unique_ptr< Buffer< T >, BufferDelete< T > > AutoReleaseBuffer
This class will automatically unref a Buffer when going out of scope.
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
See OSMutexLock in os/OS.hxx.
Base class for all QMember types that hold data in an expandable format.
T * data()
get a pointer to the start of the data.
Action return_ok()
Terminates the flow and returns the request buffer to the caller with an error code of OK (zero).
Action return_with_error(int error)
Terminates the flow and returns the request buffer to the caller with an specific error code.
A notifiable class that calls a particular function object once when it is invoked,...
void register_handler(HandlerType *handler, ID id, ID mask)
Adds a new handler to this dispatcher.
void unregister_handler_all(HandlerType *handler)
Removes all instances of a handler from 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.
MessageType * alloc()
Synchronously allocates a message buffer from the pool of this 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.
Service * service()
Return a pointer to the service I am bound to.
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.
Action call_immediately(Callback c)
Imediately call the next state upon return.
MessageDispatchFlow * dispatcher()
MessageHandler * addressed_message_write_flow()
Base class for NMRAnet nodes conforming to the asynchronous interface.
This class helps waiting for traction responses.
void wait_for_response(NodeHandle target_node, uint8_t expected_type, ::Timer *trigger)
Starts waiting for a traction control reply from a given node with the first byte 'expected_type'.
void wait_timeout()
Call this if the timeout has expired.
Buffer< GenMessage > * response()
Caller must unref this buffer when done with it.
@ FN_NOT_KNOWN
Returned from get_fn() when we don't have a cahced value for a function.
Interface for a single throttle for running a train node.
void query_fn(uint32_t address) override
Sends out a function query command.
SpeedType get_speed() override
dcc::TrainAddressType legacy_address_type() override
std::map< uint32_t, uint16_t > lastKnownFn_
Cache: all known function values.
TractionThrottle(Node *node)
void send_traction_message_with_loopback(Payload payload)
Allocates (synchronously) an outgoing openlcb buffer with traction request MTI and the given payload ...
void listen_reply_process(const Payload &p)
Business logic for interpreting a proxied traction command payload.
bool estopActive_
keep track if E-Stop is active
bool assigned_
True if the assign controller has returned positive.
void set_throttle_listener(std::function< void(int fn)> update_callback) override
Sets up a callback for listening for remote throttle updates.
SpeedType lastSetSpeed_
Cache: Velocity value that we last commanded to the train.
Action entry() override
Entry into the StateFlow activity.
openlcb::NodeID target_node() override
unsigned pendingQueries_
How many speed/fn query requests I have sent off to the train node that have not yet seen a reply.
void set_speed(SpeedType speed) override
Sets the speed of the locomotive.
uint32_t legacy_address() override
void speed_reply(Buffer< GenMessage > *msg)
Invoked for TRACTION_CONTROL_REPLY messages coming in via the dispatcher.
TractionResponseHandler handler_
Helper class for stateful query/return flows.
bool pending_reply_arrived()
Notifies that a pending query during load has gotten a reply.
void loopback_traction_message(Buffer< GenMessage > *b)
Performs loopback processing of an outgoing traction message.
bool listenConsist_
True if we also have a consist link with the assigned loco.
void set_emergencystop() override
Sets the train to emergency stop.
void toggle_fn(uint32_t fn) override
Flips a function on<>off.
void set_fn(uint32_t address, uint16_t value) override
Sets the value of a function.
BufferPtr< GenMessage > send_traction_message_helper(Payload payload)
Allocates (synchronously) an outgoing openlcb buffer with traction request MTI and the given payload ...
@ TIMEOUT_NSEC
Timeout for assign controller request.
@ MAX_FN_QUERY
Upon a load state request, how far do we go into the function list?
uint16_t get_fn(uint32_t address) override
void listen_reply(Buffer< GenMessage > *msg)
Invoked for TRACTION_CONTROL_COMMAND messages coming in via the dispatcher.
bool is_train_assigned() override
Determine if a train is currently assigned to this trottle.
bool get_emergencystop() override
Get the current E-Stop state.
std::function< void(int fn)> updateCallback_
Function to call when a different controller updates the train.
openlcb::Node * throttle_node() override
void send_traction_message(Payload payload)
Allocates (synchronously) an outgoing openlcb buffer with traction request MTI and the given payload ...
This class provides a mechanism for working with velocity in different forms.
void set_mph(float mph)
Sets the speed value from a given mph value.
TrainAddressType
Which address type this legacy train node uses.
#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.
#define LOG_ERROR(message...)
Shorthand for LOG(LEVEL_ERROR, message...). See LOG.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
NodeID data_to_node_id(const void *d)
Converts 6 bytes of big-endian data to a node ID.
uint64_t NodeID
48-bit NMRAnet Node ID type
string Payload
Container that carries the data bytes in an NMRAnet message.
#define MSEC_TO_NSEC(_msec)
Convert a millisecond value to a nanosecond value.
#define SEC_TO_NSEC(_sec)
Convert a second value to a nanosecond value.
@ MTI_EXACT
match mask for a single MTI
Container of both a NodeID and NodeAlias.
static bool fn_get_parse(const Payload &p, uint16_t *value, unsigned *address)
Parses the response payload of a GET_FN packet.
static Payload noop_payload()
Generates a Noop message, to be sent from the throttle to the train node.
static bool speed_get_parse_last(const Payload &p, Velocity *v, bool *is_estop=nullptr)
Parses the response payload of a GET_SPEED packet.
@ REQ_MASK
Mask to apply to the command byte of the requests.