34#ifndef _DCC_LOGON_HXX_
35#define _DCC_LOGON_HXX_
119template <
class Module>
154 logonSelect_.ensure_triggered();
165 if (feedback_key >= 1 << 14)
167 LOG(
INFO,
"classify %x", (
unsigned)feedback_key);
190 uintptr_t feedback_key,
bool error, uint64_t data)
override
194 LOG(
WARNING,
"Unexpected select shortinfo key: %08x",
195 (
unsigned)feedback_key);
199 if (!
module_->is_valid_loco_id(loco_id))
202 "Unexpected select shortinfo key: %08x - invalid loco id",
203 (
unsigned)feedback_key);
206 uint8_t &flags =
module_->loco_flags(loco_id);
207 LOG(
INFO,
"Select shortinfo for loco ID %d, flags %02x error %d",
208 loco_id, flags, error);
222 logonSelect_.wakeup();
235 logonSelect_.wakeup();
244 uintptr_t feedback_key,
bool error, uint64_t data)
override
248 LOG(
WARNING,
"Unexpected logon assign key: %08x",
249 (
unsigned)feedback_key);
253 if (!
module_->is_valid_loco_id(loco_id))
255 LOG(
WARNING,
"Unexpected logon assign key: %08x - invalid loco id",
256 (
unsigned)feedback_key);
259 uint8_t &flags =
module_->loco_flags(loco_id);
278 logonSelect_.wakeup();
284 LOG(
INFO,
"Assign completed for loco %d address %d", loco_id,
285 module_->assigned_address(loco_id));
294 uintptr_t feedback_key,
bool error, uint64_t data)
override
304 if (LOGLEVEL >=
INFO)
306 unsigned didh = (data >> 32) & 0xfff;
307 unsigned didl = data & 0xffffffffu;
308 LOG(
INFO,
"Decoder id %03x%08x error %d", didh, didl, error);
316 auto lid =
module_->create_or_lookup_loco(did);
317 if (!
module_->is_valid_loco_id(lid))
321 auto &flags =
module_->loco_flags(lid);
323 logonSelect_.wakeup();
425 b->data()->packet_header.rept_count = rept;
426 b->set_done(bn_.
reset(
this));
436 friend class LogonSelect;
464 bool need_wakeup =
false;
465 for (
unsigned id = 0;
id <
m()->num_locos() &&
id <
MAX_LOCO_ID;
570 b->data()->set_dcc_select_shortinfo(did);
571 b->data()->feedback_key =
588 b->data()->set_dcc_logon_assign(
590 b->data()->feedback_key =
610 } logonSelect_ {
this};
614 uint32_t((Defs::ADDRESS_LOGON << 24) | (Defs::DCC_LOGON_ENABLE << 16));
626 uint32_t((Defs::ADDRESS_LOGON << 24) | (Defs::DCC_SELECT << 16) |
627 (Defs::CMD_READ_SHORT_INFO << 12));
639 uint32_t((Defs::ADDRESS_LOGON << 24) | (Defs::DCC_LOGON_ASSIGN << 16));
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
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().
ActiveTimers * active_timers()
virtual void send(MessageType *message, unsigned priority=UINT_MAX)=0
Entry point to the flow.
Templated implementation of the HubFlow.
Collection of related state machines that pend on incoming messages.
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.
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 again()
Call the current state again via call_immediately.
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.
A timer that can schedule itself to run on an executor at specified times in the future.
@ RESTART
Restart the timer with existing period.
void start(long long period=-1)
Starts a timer.
void start_absolute(long long expiry_time_nsec)
Starts the timer with an absolute deadline.
void ensure_triggered()
Triggers the timer if it is not expired yet.
Abstract class to get callbacks for recognized feedback messages.
@ LOGON_ENABLE
Logon Enable packet.
@ SELECT_SHORTINFO
Select packet with Get Short Info command.
@ LOGON_ASSIGN
Logon Assign packet.
@ UNKNOWN
Non-254 packet or not known (not relevant) 254 packet type.
Parser for RailCom feedback that recognizes logon messages.
This class needs to be a base class for the template argument of the Logon Handler.
void assign_complete(unsigned loco_id)
Invoked when the address assignment completes for a decoder.
Flags
Flags for the logon handler module.
@ FLAG_PENDING_GET_SHORTINFO
We sent a get shortinfo command.
@ FLAG_COMPLETE
1 if we completed the address assignment.
@ FLAG_PENDING_RETRY
1 if we have asked for a re-try.
@ FLAG_NEEDS_GET_SHORTINFO
This decoder needs a get shortinfo command.
@ FLAG_ERROR_STATE
1 if we ended up in an error state for this loco.
@ FLAG_PENDING_TICK
This is a 1-bit pre-scaler on a shared 50 msec timer that controls the delay of re-tries.
@ FLAG_PENDING_ASSIGN
We sent an assign command.
@ FLAG_NEEDS_ASSIGN
This decoder needs an assign command.
uint16_t assigned_address(unsigned loco_id)
unsigned create_or_lookup_loco(uint64_t decoder_id)
Creates a new locomotive by decoder ID, or looks up an existing locomotive by decoder ID.
uint8_t & loco_flags(unsigned loco_id)
Finds the storage cell for a locomotive and returns the flag byte for it.
uint64_t loco_did(unsigned loco_id)
Retrieves the decoder unique ID.
void run_address_policy(unsigned loco_id, uint16_t desired_address)
Runs the locomotive address policy.
bool is_valid_loco_id(unsigned loco_id)
Flow that sends out addressed packets that are part of the logon sequences.
Action send_assign()
Called with a buffer allocated.
LogonHandler * parent_
Owning logon handler.
Action send_get_shortinfo()
Called with a buffer allocated.
void tick()
Called by a timer every 50 msec.
BarrierNotifiable bn_
Helper for self notification.
Action search()
Entry to the flow.
long long timeout() override
Timer callback.
unsigned cycleNextId_
Identifier of the storage that provides the next locomotive to look at.
void wakeup()
Notifies the flow that there is work to do.
Handles the automatic logon flow for DCC decoders.
long long lastLogonTime_
Timestamp of the last logon packet we sent out.
uint16_t cid_
Command station unique ID.
Action send_logon_now()
Sends a Logon Enable(now) packet.
PacketType classify_packet(uintptr_t feedback_key) override
Determines based on feedback key what the given DCC packet was.
Module * module_
Storage module.
uint8_t needShutdown_
Signals that we need to shut down the flow.
uint8_t countLogonToSend_
Tracks how many logons to send out.
void startup_logon(uint16_t cid, uint8_t session_id)
Initiates a logon sequence at startup.
static constexpr unsigned LOGON_PERIOD_MSEC
How often to send logon enable packets.
static constexpr uintptr_t LOGON_ENABLE_KEY
We send this as feedback key for logon enable packets.
void process_decoder_id(uintptr_t feedback_key, bool error, uint64_t data) override
Handles a Decoder ID feedback message.
static constexpr uintptr_t SELECT_SHORTINFO_KEY
We send this as feedback key for select/get short info packets.
Action allocate_logon_many()
Called when we have seen a conflict on a logon enable packet.
LogonHandler(Service *service, TrackIf *track, RailcomHubFlow *rcom_hub, Module *m)
Constructor.
Action allocate_logon_now()
Allocates a buffer and sends a Logon Enable(now) packet.
static constexpr bool is_logon_enable_key(uintptr_t feedback_key)
Checks if a feedback key is for logon enable.
uint8_t hasLogonEnableConflict_
1 if we got an error (presumably a conflict) in the logon enable feedback.
Action send_logon_many()
Send out the repeated logon request.
static constexpr bool is_select_shortinfo_key(uintptr_t feedback_key)
Checks if a feedback key is for select shortinfo.
uint8_t hasLogonEnableFeedback_
1 if we got any feedback packet from logon enable.
static constexpr uint64_t DECODER_ID_MASK
Mask selecting bits that belong to the decoder ID.
Action start_logon_wait()
Called when the logon now packet is released.
static constexpr bool is_logon_assign_key(uintptr_t feedback_key)
Checks if a feedback key is for logon assign.
static constexpr uintptr_t LOCO_ID_MASK
Mask selecting bits that belong to the locomotive ID.
static constexpr uintptr_t LOGON_ASSIGN_KEY
We send this as feedback key for logon assign packets.
StateFlowTimer timer_
Helper object for timing.
void process_select_shortinfo(uintptr_t feedback_key, bool error, uint64_t data) override
Handles a Select ShortInfo feedback message.
Action evaluate_logon()
Called when the logon timer expires or is cancelled due to feedback.
LogonFeedbackParser fbParser_
Helper object for parsing railcom feedback from the railcom hub.
uint8_t sessionId_
Session ID of the current session.
static constexpr unsigned MAX_LOCO_ID
Maximum allowed locomotive ID.
Action many_logon_wait()
Called after the many logon packets' buffer is freed.
void logon_send_helper(Defs::LogonEnableParam param, unsigned rept)
Helper function to send out logon enable commands.
TrackIf * trackIf_
If we need to send packets to the track, we can do it here directly.
void process_logon_assign(uintptr_t feedback_key, bool error, uint64_t data) override
Handles a Logon Assign feedback message.
LogonEnableParam
Parameters for the Logon Enable command.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int WARNING
Loglevel that is always printed, reporting a warning or a retryable error.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
long long os_get_time_monotonic(void)
Get the monotonic time since the system started.
#define MSEC_TO_NSEC(_msec)
Convert a millisecond value to a nanosecond value.