Skip to content

Commit

Permalink
Adds activity LED support. (#438)
Browse files Browse the repository at this point in the history
* Adds activity LED support.

Adds a hook into the openlcb interface that calls a user supplied function
whenever a message is transmitted to the network.
Adds a simple implementaiton for this hook that flashes an LED when there
is bus activity originated from this node.

* Adds comments and parametrizes the period of activity LED.
  • Loading branch information
balazsracz authored Sep 29, 2020
1 parent ad4c454 commit 1721b05
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 1 deletion.
21 changes: 20 additions & 1 deletion src/openlcb/If.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,20 @@ public:
MessageHandler *global_message_write_flow()
{
HASSERT(globalWriteFlow_);
if (txHook_)
{
txHook_();
}
return globalWriteFlow_;
}
/** @return Flow to send addressed messages to the NMRAnet bus. */
MessageHandler *addressed_message_write_flow()
{
HASSERT(addressedWriteFlow_);
if (txHook_)
{
txHook_();
}
return addressedWriteFlow_;
}

Expand Down Expand Up @@ -399,7 +407,15 @@ public:
* the interface holds internally. Noop for TCP interface. Must be called
* on the interface executor. */
virtual void canonicalize_handle(NodeHandle *h) {}


/// Sets a transmit hook. This function will be called once for every
/// OpenLCB message transmitted. Used for implementing activity LEDs.
/// @param hook function to call for each transmit message.
void set_tx_hook(std::function<void()> hook)
{
txHook_ = std::move(hook);
}

protected:
void remove_local_node_from_map(Node *node) {
auto it = localNodes_.find(node->node_id());
Expand All @@ -416,6 +432,9 @@ private:
/// Flow responsible for routing incoming messages to handlers.
MessageDispatchFlow dispatcher_;

/// This function is pinged every time a message is transmitted.
std::function<void()> txHook_;

typedef Map<NodeID, Node *> VNodeMap;

/// Local virtual nodes registered on this interface.
Expand Down
12 changes: 12 additions & 0 deletions src/openlcb/SimpleStack.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "openlcb/SimpleNodeInfo.hxx"
#include "openlcb/TractionTrain.hxx"
#include "openlcb/TrainInterface.hxx"
#include "utils/ActivityLed.hxx"
#include "utils/GcTcpHub.hxx"
#include "utils/GridConnectHub.hxx"
#include "utils/HubDevice.hxx"
Expand Down Expand Up @@ -153,6 +154,17 @@ public:
return &configUpdateFlow_;
}

/// Adds an activiy LED which will be flashed every time a message is sent
/// from this node to the network.
/// @param gpio LED that will be flashed on for each packet.
/// @param period defines in nanosecond the time to spend between updates.
void set_tx_activity_led(
const Gpio *led, long long period = MSEC_TO_NSEC(33))
{
auto *al = new ActivityLed(iface(), led, period);
iface()->set_tx_hook(std::bind(&ActivityLed::activity, al));
}

/// Reinitializes the node. Useful to call after the connection has flapped
/// (gone down and up).
void restart_stack();
Expand Down
88 changes: 88 additions & 0 deletions src/utils/ActivityLed.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/** \copyright
* Copyright (c) 2020, Balazs Racz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \file ActivityLed.hxx
*
* State flow that controls an activity LED based on triggers of events.
*
* @author Balazs Racz
* @date 26 Sep 2020
*/

#ifndef _UTILS_ACTIVITYLED_HXX_
#define _UTILS_ACTIVITYLED_HXX_

#include "executor/StateFlow.hxx"
#include "os/Gpio.hxx"

/// Operates an LED to visually display some activity. When the activity()
/// function is called at least once within a period, we turn the LED on for
/// the next period, if no call was made, the LED turns off for the next
/// period.
class ActivityLed : private ::Timer
{
public:
/// Constructor.
/// @param service defines which executor this timer should be running on.
/// @param pin the LED of the output. Will be high for activity, low for
/// inactivity. Use InvertedGPIO if needed.
/// @param period defines in nanosecond the time to spend between updates.
ActivityLed(
Service *service, const Gpio *pin, long long period = MSEC_TO_NSEC(33))
: ::Timer(service->executor()->active_timers())
, gpio_(pin)
{
start(period);
}

/// Call this function when activity happens.
void activity()
{
triggerCount_++;
}

private:
long long timeout() override
{
if (triggerCount_)
{
gpio_->write(true);
triggerCount_ = 0;
}
else
{
gpio_->write(false);
}
return RESTART;
}

/// Output pin to blink for activity.
const Gpio *gpio_;
/// How many triggers happened since the last run of the timer.
unsigned triggerCount_ {0};
};

#endif // _UTILS_ACTIVITYLED_HXX_

0 comments on commit 1721b05

Please sign in to comment.