Adds heartbeat functionality using GPIO
Introduces a heartbeat mechanism to the robot node using GPIO. This allows for external monitoring of the node's active state. The heartbeat is implemented using a GPIO pin that toggles at a regular interval, indicating that the system is running. Updates CMakeLists to link the project with gpiod libraries staged locally. Adds .gitignore entries for local dependencies and PC build directories.
This commit is contained in:
parent
6a8f4f364b
commit
957f789faa
6 changed files with 62 additions and 39 deletions
8
src/RobotNode/.gitignore
vendored
8
src/RobotNode/.gitignore
vendored
|
|
@ -38,4 +38,10 @@
|
|||
*.app
|
||||
|
||||
# debug information files
|
||||
*.dwo
|
||||
*.dwo
|
||||
|
||||
# Local dependencies
|
||||
extern/
|
||||
|
||||
# PC-side build directories
|
||||
cmake-build-*/
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
# Sets the minimum CMake version required to handle modern C++ features
|
||||
cmake_minimum_required(VERSION 3.10) # Version 4.1 doesn't exist yet (standard is 3.x)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Defines the project name
|
||||
project(Dixon)
|
||||
|
|
@ -7,14 +6,9 @@ project(Dixon)
|
|||
# Forces the compiler to use C++20 features
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Load the PkgConfig tool to find libraries automatically
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# Search for libgpiod v2.x C++ bindings
|
||||
pkg_check_modules(GPIOD REQUIRED libgpiodcxx)
|
||||
|
||||
# Define the executable and its source files
|
||||
add_executable(Dixon main.cpp
|
||||
add_executable(Dixon
|
||||
main.cpp
|
||||
DixonNodeState.cpp
|
||||
DixonNodeState.h
|
||||
DixonBrain.cpp
|
||||
|
|
@ -22,8 +16,14 @@ add_executable(Dixon main.cpp
|
|||
CardioCenter/Heart.cpp
|
||||
CardioCenter/Heart.h)
|
||||
|
||||
# Add the Include directories found by PkgConfig (where the .hpp files live)
|
||||
target_include_directories(Dixon PRIVATE ${GPIOD_INCLUDE_DIRS})
|
||||
# Header Path: Use the local v2.1 headers staged in the project
|
||||
target_include_directories(Dixon PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/extern/libgpiod/include")
|
||||
|
||||
# Link the specific libraries found by PkgConfig
|
||||
target_link_libraries(Dixon PRIVATE ${GPIOD_LIBRARIES})
|
||||
|
||||
# Link the gpiod libraries
|
||||
target_link_libraries(Dixon PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/extern/libgpiod/aarch64/libgpiodcxx.so.2"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/extern/libgpiod/aarch64/libgpiod.so.3")
|
||||
|
||||
# Tell the linker: "Trust me, the Pi has the rest of the C++ and C libraries"
|
||||
target_link_options(Dixon PRIVATE "-Wl,--allow-shlib-undefined")
|
||||
|
|
@ -3,33 +3,40 @@
|
|||
|
||||
namespace cardio
|
||||
{
|
||||
Heart::Heart(const char* chipName, unsigned int lineOffset)
|
||||
: _isOn(false),
|
||||
_request(setup_request(chipName, lineOffset))
|
||||
Heart::Heart(const char* chipName, unsigned int lineOffset)
|
||||
: chip_(std::string("/dev/") + chipName),
|
||||
isOn_(false),
|
||||
_lastBeat(std::chrono::steady_clock::now()),
|
||||
request_(get_line_request(chip_, lineOffset))
|
||||
{
|
||||
}
|
||||
|
||||
void Heart::beat()
|
||||
{
|
||||
_isOn = !_isOn;
|
||||
auto val = _isOn ? gpiod::line::value::ACTIVE : gpiod::line::value::INACTIVE;
|
||||
|
||||
_request.set_value(HEART_LINE_INDEX, val);
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>
|
||||
(now - _lastBeat); elapsed.count() >= 500)
|
||||
{
|
||||
isOn_ = !isOn_;
|
||||
const auto val = isOn_ ? gpiod::line::value::ACTIVE : gpiod::line::value::INACTIVE;
|
||||
request_.set_value(DEFAULT_HEART_PIN, val);
|
||||
_lastBeat = now;
|
||||
}
|
||||
}
|
||||
|
||||
gpiod::line_request Heart::setup_request(const char* chipName, const unsigned int lineOffset)
|
||||
{
|
||||
std::string chipPath = std::string("/dev/") + chipName;
|
||||
gpiod::chip chip(chipPath);
|
||||
void Heart::stop()
|
||||
{
|
||||
isOn_ = false;
|
||||
request_.set_value(DEFAULT_HEART_PIN, gpiod::line::value::INACTIVE);
|
||||
}
|
||||
|
||||
auto settings = gpiod::line_settings()
|
||||
.set_direction(gpiod::line::direction::OUTPUT);
|
||||
gpiod::line_request Heart::get_line_request(gpiod::chip& chip, const unsigned int lineOffset)
|
||||
{
|
||||
const auto settings = gpiod::line_settings()
|
||||
.set_direction(gpiod::line::direction::OUTPUT);
|
||||
|
||||
auto line_cfg = gpiod::line_config();
|
||||
line_cfg.add_line_settings(lineOffset, settings);
|
||||
|
||||
return chip.prepare_request()
|
||||
.set_line_config(line_cfg)
|
||||
.do_request();
|
||||
}
|
||||
}
|
||||
return chip.prepare_request()
|
||||
.add_line_settings(lineOffset, settings)
|
||||
.do_request();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <gpiod.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace cardio
|
||||
{
|
||||
|
|
@ -9,13 +10,16 @@ namespace cardio
|
|||
public:
|
||||
explicit Heart(const char* chipName = GPIO_CHIP_NAME, unsigned int lineOffset = DEFAULT_HEART_PIN);
|
||||
void beat();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
static gpiod::line_request get_line_request(gpiod::chip&, unsigned int lineOffset);
|
||||
static constexpr auto GPIO_CHIP_NAME = "gpiochip0";
|
||||
static constexpr unsigned int DEFAULT_HEART_PIN = 17;
|
||||
static constexpr unsigned int HEART_LINE_INDEX = 0;
|
||||
static gpiod::line_request setup_request(const char* chipName, unsigned int lineOffset);
|
||||
bool _isOn;
|
||||
gpiod::line_request _request;
|
||||
std::chrono::steady_clock::time_point _lastBeat;
|
||||
gpiod::chip chip_;
|
||||
bool isOn_;
|
||||
gpiod::line_request request_;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
#include <thread>
|
||||
|
||||
DixonBrain::DixonBrain()
|
||||
: state_(DixonNodeState::instance())
|
||||
: heart_(),
|
||||
state_(DixonNodeState::instance())
|
||||
{
|
||||
std::cout << "DixonBrain initialised\n";
|
||||
}
|
||||
|
|
@ -37,6 +38,8 @@ void DixonBrain::stop()
|
|||
if (loopThread_.joinable())
|
||||
loopThread_.join();
|
||||
|
||||
heart_.stop();
|
||||
|
||||
std::cout << "DixonBrain stopped\n";
|
||||
}
|
||||
|
||||
|
|
@ -44,6 +47,7 @@ void DixonBrain::runLoop()
|
|||
{
|
||||
while (state_.isBrainRunning())
|
||||
{
|
||||
heart_.beat();
|
||||
// TODO: main control logic
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "DixonNodeState.h"
|
||||
#include "CardioCenter/Heart.h"
|
||||
#include <thread>
|
||||
|
||||
class DixonBrain
|
||||
|
|
@ -14,6 +15,7 @@ public:
|
|||
private:
|
||||
void runLoop();
|
||||
|
||||
cardio::Heart heart_;
|
||||
DixonNodeState& state_;
|
||||
std::thread loopThread_;
|
||||
};
|
||||
Loading…
Reference in a new issue