diff --git a/src/RobotNode/.run/Dixon-Attach.run.xml b/src/RobotNode/.run/Dixon-Attach.run.xml new file mode 100644 index 0000000..af036a6 --- /dev/null +++ b/src/RobotNode/.run/Dixon-Attach.run.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/RobotNode/CardioCenter/Heart.cpp b/src/RobotNode/CardioCenter/Heart.cpp index b0c2bba..7881654 100644 --- a/src/RobotNode/CardioCenter/Heart.cpp +++ b/src/RobotNode/CardioCenter/Heart.cpp @@ -1,6 +1,8 @@ #include "Heart.h" #include +#include "../DixonNodeState.h" + namespace cardio { Heart::Heart(const char* chipName, const unsigned int lineOffset) @@ -13,6 +15,10 @@ namespace cardio void Heart::beat() { + if (const auto nodeStatus = DixonNodeState::instance().getNodeStatus(); + nodeStatus == NodeStatus::Stopped || nodeStatus == NodeStatus::Stopping) + return; + const auto now = std::chrono::steady_clock::now(); if (const auto elapsed = std::chrono::duration_cast (now - _lastBeat); elapsed.count() >= 500) @@ -32,11 +38,13 @@ namespace cardio 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); + const auto settings = gpiod::line_settings() // Force it to a known state immediately on acquisition + .set_output_value(gpiod::line::value::INACTIVE) + .set_direction(gpiod::line::direction::OUTPUT); return chip.prepare_request() - .add_line_settings(lineOffset, settings) - .do_request(); + .set_consumer("dixon-robot") + .add_line_settings(lineOffset, settings) + .do_request(); } } diff --git a/src/RobotNode/DixonBrain.cpp b/src/RobotNode/DixonBrain.cpp index 0047d32..e05226f 100644 --- a/src/RobotNode/DixonBrain.cpp +++ b/src/RobotNode/DixonBrain.cpp @@ -18,10 +18,10 @@ DixonBrain::~DixonBrain() void DixonBrain::start() { - if (state_.isBrainRunning()) + if (state_.getNodeStatus() != NodeStatus::Stopped) return; - state_.setBrainRunning(true); + state_.setNodeStatus(NodeStatus::Running); loopThread_ = std::thread(&DixonBrain::runLoop, this); @@ -30,22 +30,25 @@ void DixonBrain::start() void DixonBrain::stop() { - if (!state_.isBrainRunning()) + if (state_.getNodeStatus() == NodeStatus::Stopped) return; - state_.setBrainRunning(false); + state_.setNodeStatus(NodeStatus::Stopping); + if (loopThread_.joinable()) loopThread_.join(); heart_.stop(); + state_.setNodeStatus(NodeStatus::Stopped); + std::cout << "DixonBrain stopped\n"; } void DixonBrain::runLoop() { - while (state_.isBrainRunning()) + while (state_.getNodeStatus() != NodeStatus::Stopped) { heart_.beat(); // TODO: main control logic diff --git a/src/RobotNode/DixonNodeState.cpp b/src/RobotNode/DixonNodeState.cpp index 1b50986..4741a7b 100644 --- a/src/RobotNode/DixonNodeState.cpp +++ b/src/RobotNode/DixonNodeState.cpp @@ -16,12 +16,12 @@ bool DixonNodeState::isConnected() const return connected_; } -void DixonNodeState::setBrainRunning(bool value) +void DixonNodeState::setNodeStatus(NodeStatus value) { - brainRunning_ = value; + node_status_ = value; } -bool DixonNodeState::isBrainRunning() const +NodeStatus DixonNodeState::getNodeStatus() const { - return brainRunning_; -} \ No newline at end of file + return node_status_; +} diff --git a/src/RobotNode/DixonNodeState.h b/src/RobotNode/DixonNodeState.h index c64f598..a686810 100644 --- a/src/RobotNode/DixonNodeState.h +++ b/src/RobotNode/DixonNodeState.h @@ -1,16 +1,24 @@ #pragma once #include + +enum class NodeStatus : int { + Starting, + Running, + Stopping, + Stopped +}; + class DixonNodeState { public: static DixonNodeState& instance(); void setConnected(bool value); - bool isConnected() const; + [[nodiscard]] bool isConnected() const; - void setBrainRunning(bool value); - bool isBrainRunning() const; + void setNodeStatus(NodeStatus value); + [[nodiscard]] NodeStatus getNodeStatus() const; DixonNodeState(const DixonNodeState&) = delete; DixonNodeState& operator=(const DixonNodeState&) = delete; @@ -22,5 +30,5 @@ private: ~DixonNodeState() = default; std::atomic connected_ = false; - std::atomic brainRunning_ = false; + std::atomic node_status_ = NodeStatus::Stopped; }; \ No newline at end of file diff --git a/src/RobotNode/main.cpp b/src/RobotNode/main.cpp index 094eefa..68c1e69 100644 --- a/src/RobotNode/main.cpp +++ b/src/RobotNode/main.cpp @@ -1,25 +1,51 @@ +#include #include #include "DixonBrain.h" -#include "DixonNodeState.h" #include "Version.h" // The generated header + + +void signal_handler(int signal) { + if (signal == SIGINT || signal == SIGTERM) { + std::cout << "\nShutdown signal received (" << signal << ")." << std::endl; + + // Use your atomic flag to tell the brain to stop looping + DixonNodeState::instance().setNodeStatus(NodeStatus::Stopping); + } +} + + int main() { // The "Splash Screen" std::cout << "Starting Dixon v" << DIXON_VERSION << "...\n"; + std::signal(SIGINT, signal_handler); + std::signal(SIGTERM, signal_handler); + // Create the brain controller DixonBrain brain; // Start the brain's control loop brain.start(); - std::cout << "Dixon is running. Press Enter to stop...\n"; - std::cin.get(); + std::cout << "Dixon is alive...\n"; + auto count = 1; + while (DixonNodeState::instance().getNodeStatus() == NodeStatus::Running) + { + + count++; + if (count>10) + { + count = 0; + std::cout << "Dixon state is " << static_cast( DixonNodeState::instance().getNodeStatus()) << "\n"; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + } // Stop the brain cleanly brain.stop(); - - std::cout << "Dixon shut down.\n"; + std::cout << "Dixon has left the building...\n"; return 0; } \ No newline at end of file diff --git a/src/RobotNode/version.txt b/src/RobotNode/version.txt index 492b167..3f11ef6 100644 --- a/src/RobotNode/version.txt +++ b/src/RobotNode/version.txt @@ -1 +1 @@ -1.0.12 \ No newline at end of file +1.0.27 \ No newline at end of file