Skip to content

Commit

Permalink
Makes TrainNode pure abstract. (#430)
Browse files Browse the repository at this point in the history
* Makes the TrainNode object pure abstract with very little implementation.
Creates DefaultTrainNode in the class hierarchy to own most of the
existing implementation.

* fix whitespace.

* refactor consist storage implementation from TrainNode into a separate intermediate class.
  • Loading branch information
balazsracz authored Sep 11, 2020
1 parent 9d88c35 commit 368a0c4
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 62 deletions.
24 changes: 17 additions & 7 deletions src/openlcb/TractionTrain.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
namespace openlcb
{

TrainNode::TrainNode(TrainService *service, TrainImpl *train)
DefaultTrainNode::DefaultTrainNode(TrainService *service, TrainImpl *train)
: service_(service)
, train_(train)
, isInitialized_(0)
Expand All @@ -52,14 +52,24 @@ TrainNode::TrainNode(TrainService *service, TrainImpl *train)

TrainNode::~TrainNode()
{
while (!consistSlaves_.empty()) {
}

TrainNodeWithConsist::~TrainNodeWithConsist()
{
while (!consistSlaves_.empty())
{
delete consistSlaves_.pop_front();
}
}

DefaultTrainNode::~DefaultTrainNode()
{
}

TrainNodeForProxy::TrainNodeForProxy(TrainService *service, TrainImpl *train)
: TrainNode(service, train) {
service_->register_train(this);
: DefaultTrainNode(service, train)
{
service->register_train(this);
}

TrainNodeForProxy::~TrainNodeForProxy()
Expand All @@ -71,10 +81,10 @@ TrainNodeForProxy::~TrainNodeForProxy()

TrainNodeWithId::TrainNodeWithId(
TrainService *service, TrainImpl *train, NodeID node_id)
: TrainNode(service, train)
: DefaultTrainNode(service, train)
, nodeId_(node_id)
{
service_->register_train(this);
service->register_train(this);
}

TrainNodeWithId::~TrainNodeWithId()
Expand All @@ -90,7 +100,7 @@ NodeID TrainNodeForProxy::node_id()
train_->legacy_address_type(), train_->legacy_address());
}

If *TrainNode::iface()
If *DefaultTrainNode::iface()
{
return service_->iface();
}
Expand Down
175 changes: 120 additions & 55 deletions src/openlcb/TractionTrain.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,6 @@ namespace openlcb

class TrainService;

/// Linked list entry for all registered consist clients for a given train
/// node.
struct ConsistEntry : public QMember {
ConsistEntry(NodeID s, uint8_t flags) : payload((s << 8) | flags) {}
NodeID get_slave() const {
return payload >> 8;
}
uint8_t get_flags() const {
return payload & 0xff;
}
void set_flags(uint8_t new_flags) {
payload ^= (payload & 0xff);
payload |= new_flags;
}
private:
uint64_t payload;
};

/// Virtual node class for an OpenLCB train protocol node.
///
/// Usage:
Expand All @@ -77,39 +59,17 @@ private:
class TrainNode : public Node
{
public:
TrainNode(TrainService *service, TrainImpl *train);
~TrainNode();

If *iface() OVERRIDE;
bool is_initialized() OVERRIDE
{
return isInitialized_;
}
void set_initialized() OVERRIDE
{
isInitialized_ = 1;
}
/// @return the train implementation object for issuing control commands to
/// this train.
virtual TrainImpl *train() = 0;

// Used for restarting the stack.
void clear_initialized() OVERRIDE
{
isInitialized_ = 0;
}
/// @return the last stored controller node.
virtual NodeHandle get_controller() = 0;

TrainImpl *train()
{
return train_;
}

NodeHandle get_controller()
{
return controllerNodeId_;
}

void set_controller(NodeHandle id)
{
controllerNodeId_ = id;
}
/// @param id the controller node of this train.
virtual void set_controller(NodeHandle id) = 0;

// Thread-safety information
//
Expand All @@ -124,9 +84,71 @@ public:
// before any consist change requests would reach the front of the queue
// for the traction flow.

/// Adds a node ID to the consist targets. @return false if the node was
/// already in the target list, true if it was newly added.
/// @param tgt the destination of the consist link
/// @param flags consisting flags from the Traction protocol.
virtual bool add_consist(NodeID tgt, uint8_t flags) = 0;

/// Removes a node ID from the consist targets. @return true if the target
/// was removed, false if the target was not on the list.
/// @param tgt destination of consist link to remove.
virtual bool remove_consist(NodeID tgt) = 0;

/// Fetch a given consist link.
/// @return The target of a given consist link, or NodeID(0) if there are
/// fewer than id consist targets.
/// @param id zero-based index of consist links.
/// @param flags retrieved consist link's flags go here.
virtual NodeID query_consist(int id, uint8_t* flags) = 0;

/// @return the number of slaves in this consist.
virtual int query_consist_length() = 0;
};

/// Linked list entry for all registered consist clients for a given train
/// node.
struct ConsistEntry : public QMember
{
/// Creates a new consist entry storage.
/// @param s the stored node ID
/// @param flags the stored flag byte
ConsistEntry(NodeID s, uint8_t flags)
: payload((s << 8) | flags)
{
}
/// @return the stored Node ID.
NodeID get_slave() const
{
return payload >> 8;
}
/// @return the stored flags byte.
uint8_t get_flags() const
{
return payload & 0xff;
}
/// Overrides the stored flags.
/// @param new_flags the new value of the flags byte.
void set_flags(uint8_t new_flags)
{
payload ^= (payload & 0xff);
payload |= new_flags;
}

private:
/// Data contents.
uint64_t payload;
};

/// Intermediate class which is still abstract, but adds implementation for the
/// consist management functions.
class TrainNodeWithConsist : public TrainNode {
public:
~TrainNodeWithConsist();

/** Adds a node ID to the consist targets. @return false if the node was
* already in the target list, true if it was newly added. */
virtual bool add_consist(NodeID tgt, uint8_t flags)
bool add_consist(NodeID tgt, uint8_t flags) override
{
if (!tgt)
{
Expand All @@ -151,7 +173,7 @@ public:

/** Removes a node ID from the consist targets. @return true if the target
* was removed, false if the target was not on the list. */
virtual bool remove_consist(NodeID tgt)
bool remove_consist(NodeID tgt) override
{
for (auto it = consistSlaves_.begin(); it != consistSlaves_.end(); ++it)
{
Expand All @@ -168,7 +190,7 @@ public:

/** Returns the consist target with offset id, or NodeID(0) if there are
* fewer than id consist targets. id is zero-based. */
NodeID query_consist(int id, uint8_t* flags)
NodeID query_consist(int id, uint8_t* flags) override
{
int k = 0;
for (auto it = consistSlaves_.begin();
Expand All @@ -184,7 +206,7 @@ public:
}

/** Returns the number of slaves in this consist. */
int query_consist_length()
int query_consist_length() override
{
int ret = 0;
for (auto it = consistSlaves_.begin(); it != consistSlaves_.end();
Expand All @@ -194,21 +216,63 @@ public:
return ret;
}

TypedQueue<ConsistEntry> consistSlaves_;
};

/// Default implementation of a train node.
class DefaultTrainNode : public TrainNodeWithConsist
{
public:
DefaultTrainNode(TrainService *service, TrainImpl *impl);
~DefaultTrainNode();

NodeHandle get_controller() override
{
return controllerNodeId_;
}

void set_controller(NodeHandle id) override
{
controllerNodeId_ = id;
}

If *iface() override;
bool is_initialized() override
{
return isInitialized_;
}
void set_initialized() override
{
isInitialized_ = 1;
}
// Used for restarting the stack.
void clear_initialized() override
{
isInitialized_ = 0;
}

TrainImpl *train() override
{
return train_;
}

protected:
/// Pointer to the traction service.
TrainService *service_;
/// Pointer to the train implementation object.
TrainImpl *train_;

private:
/// Node is initialized bit for startup transient.
unsigned isInitialized_ : 1;

/// Controller node that is assigned to run this train. 0 if none.
NodeHandle controllerNodeId_;
TypedQueue<ConsistEntry> consistSlaves_;
};


/// Train node class with a an OpenLCB Node ID from the DCC pool. Used for command stations.
class TrainNodeForProxy : public TrainNode {
class TrainNodeForProxy : public DefaultTrainNode
{
public:
/// Constructor.
/// @param service the traction service object that will own this node.
Expand All @@ -226,7 +290,8 @@ public:

/// Train node class with a fixed OpenLCB Node ID. This is useful for native
/// train nodes that are not dynamically generated by a command station.
class TrainNodeWithId : public TrainNode {
class TrainNodeWithId : public DefaultTrainNode
{
public:
/// Constructor.
/// @param service the traction service object that will own this node.
Expand Down

0 comments on commit 368a0c4

Please sign in to comment.