diff --git a/core_network_setup/free5gc/free5gc/config/amfcfg.yaml b/core_network_setup/free5gc/free5gc/config/amfcfg.yaml index 085c49b..4c4f5ee 100644 --- a/core_network_setup/free5gc/free5gc/config/amfcfg.yaml +++ b/core_network_setup/free5gc/free5gc/config/amfcfg.yaml @@ -70,7 +70,7 @@ configuration: emcN3: 0 # Emergency service support indicator for Non-3GPP access (uinteger, range: 0~1) mcsi: 0 # MCS indicator (uinteger, range: 0~1) t3502Value: 720 # timer value (seconds) at UE side - t3512Value: 3600 # timer value (seconds) at UE side + t3512Value: 10 # timer value (seconds) at UE side non3gppDeregTimerValue: 3240 # timer value (seconds) at UE side # retransmission timer for paging message t3513: diff --git a/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so b/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so old mode 100644 new mode 100755 index 60e0362..6fdf3f8 Binary files a/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so and b/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so differ diff --git a/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so b/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so old mode 100644 new mode 100755 index 2ef93d1..b344462 Binary files a/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so and b/demo/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so differ diff --git a/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so b/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so old mode 100644 new mode 100755 index 60e0362..6fdf3f8 Binary files a/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so and b/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libUePowerPlugin.so differ diff --git a/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so b/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so old mode 100644 new mode 100755 index 2ef93d1..b344462 Binary files a/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so and b/demo_containerized/images/simulation/gazebo_launch/src/ign_turtlebot/gui_plugins/libgNBPowerPlugin.so differ diff --git a/phine-plugins/src/phine_plugins/src/UePowerPlugin.cc b/phine-plugins/src/phine_plugins/src/UePowerPlugin.cc index 4856c7f..734c628 100644 --- a/phine-plugins/src/phine_plugins/src/UePowerPlugin.cc +++ b/phine-plugins/src/phine_plugins/src/UePowerPlugin.cc @@ -13,34 +13,50 @@ See the License for the specific language governing permissions and limitations under the License.*/ #include "UePowerPlugin.hh" +#include +#include #include #include #include #include +#include +#include #include +#include IGNITION_ADD_PLUGIN(phine_plugins::UePowerPlugin, ignition::gui::Plugin) using namespace phine_plugins; -UePowerPlugin::UePowerPlugin() { - ignmsg << "[UePowerPlugin] constructor called" << std::endl; +// Helper function to ask Docker for data without freezing Gazebo +static void triggerDockerCheck(const std::string &name) { + std::string file_path = "/tmp/ue_" + name + "_pids.txt"; + std::string tmp_path = file_path + ".tmp"; + // Redirects Docker output to a temporary file, then instantly swaps it. The + // '&' ensures 0 freezing. + std::string cmd = "docker exec " + name + + " ps -eo pid,stat,args --no-headers 2>/dev/null > " + + tmp_path + " && mv " + tmp_path + " " + file_path + " &"; + system(cmd.c_str()); +} +UePowerPlugin::UePowerPlugin() { const char *ue_name_env = std::getenv("UE_NAME_FOR_BUTTON"); if (ue_name_env != nullptr) { this->container_name = QString::fromStdString(std::string(ue_name_env)); } - ignmsg << "[UePowerPlugin] UE container: " - << this->container_name.toStdString() << std::endl; + status_timer = new QTimer(this); + status_timer->setInterval(2000); + connect(status_timer, &QTimer::timeout, this, + &UePowerPlugin::checkAndUpdateStatus); } UePowerPlugin::~UePowerPlugin() {} void UePowerPlugin::LoadConfig(const tinyxml2::XMLElement *_pluginElem) { - if (this->title.empty()) { + if (this->title.empty()) this->title = "UE Power Control"; - } if (_pluginElem != nullptr) { auto *name_elem = _pluginElem->FirstChildElement("container_name"); @@ -52,11 +68,15 @@ void UePowerPlugin::LoadConfig(const tinyxml2::XMLElement *_pluginElem) { if (ip_elem != nullptr && ip_elem->GetText() != nullptr) { gnb_ip = QString::fromStdString(ip_elem->GetText()); } + + auto *freq_elem = _pluginElem->FirstChildElement("carrier_freq"); + if (freq_elem != nullptr && freq_elem->GetText() != nullptr) { + carrier_freq = QString::fromStdString(freq_elem->GetText()); + } } } QString UePowerPlugin::getContainerName() const { return container_name; } - void UePowerPlugin::setContainerName(const QString &name) { if (container_name != name) { container_name = name; @@ -65,7 +85,6 @@ void UePowerPlugin::setContainerName(const QString &name) { } QString UePowerPlugin::getGnbIp() const { return gnb_ip; } - void UePowerPlugin::setGnbIp(const QString &ip) { if (gnb_ip != ip) { gnb_ip = ip; @@ -73,14 +92,20 @@ void UePowerPlugin::setGnbIp(const QString &ip) { } } -bool UePowerPlugin::isProcessRunning() const { return process_running; } +QString UePowerPlugin::getCarrierFreq() const { return carrier_freq; } +void UePowerPlugin::setCarrierFreq(const QString &freq) { + if (carrier_freq != freq) { + carrier_freq = freq; + emit carrierFreqChanged(); + } +} +bool UePowerPlugin::isProcessRunning() const { return process_running; } bool UePowerPlugin::isConnected() const { return connected; } bool UePowerPlugin::isValidContainerName(const std::string &name) { - if (name.empty() || name.size() > 128) { + if (name.empty() || name.size() > 128) return false; - } static const std::regex valid_name(R"(^[a-zA-Z0-9][a-zA-Z0-9_.\-]*$)"); return std::regex_match(name, valid_name); } @@ -89,82 +114,165 @@ bool UePowerPlugin::isValidIpAddress(const std::string &ip) { static const std::regex ip_regex( R"(^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$)"); std::smatch match; - if (!std::regex_match(ip, match, ip_regex)) { + if (!std::regex_match(ip, match, ip_regex)) return false; - } for (int i = 1; i <= 4; ++i) { int octet = std::stoi(match[i].str()); - if (octet < 0 || octet > 255) { + if (octet < 0 || octet > 255) return false; - } } return true; } -bool UePowerPlugin::checkProcessRunning() { - std::string name = container_name.toStdString(); - if (!isValidContainerName(name)) { +bool UePowerPlugin::isValidFrequency(const std::string &freq) { + if (freq.empty() || freq.size() < 8 || freq.size() > 12) return false; + for (char c : freq) { + if (!std::isdigit(c)) + return false; + } + return true; +} + +std::vector UePowerPlugin::getProcessPids() const { + std::vector pids; + std::string name = container_name.toStdString(); + + if (!isValidContainerName(name)) + return pids; + + // Reads the file locally. This is instantaneous and immune to Docker + // lock-ups. + std::string file_path = "/tmp/ue_" + name + "_pids.txt"; + std::ifstream file(file_path); + if (file.is_open()) { + std::string line; + while (std::getline(file, line)) { + std::istringstream iss(line); + std::string pid_str, stat; + + if (iss >> pid_str >> stat) { + try { + int pid = std::stoi(pid_str); + if (line.find("nr-uesoftmodem") != std::string::npos && + stat.front() != 'Z') { + pids.push_back(pid); + } + } catch (...) { + } + } + } } - std::string cmd = - "docker exec " + name + " pgrep nr-uesoftmodem > /dev/null 2>&1"; - int ret = system(cmd.c_str()); - return (ret == 0); + return pids; } std::string UePowerPlugin::buildStartCommand() const { std::string name = container_name.toStdString(); std::string ip = gnb_ip.toStdString(); + std::string freq = carrier_freq.toStdString(); return "docker exec " + name + " /bin/bash -c" " '/opt/oai-nr-ue/bin/nr-uesoftmodem" " -O /opt/oai-nr-ue/etc/nr-ue.yaml" " -E --rfsim -r 106 --numerology 1" - " -C 3319680000" - " --rfsimulator.serveraddr " + - ip + " &'"; + " -C " + + freq + " --rfsimulator.serveraddr " + ip + " > /dev/null 2>&1 &'"; +} + +void UePowerPlugin::checkAndUpdateStatus() { + if (!connected) + return; + + std::string name = container_name.toStdString(); + + if (skip_checks_count > 0) { + skip_checks_count--; + triggerDockerCheck(name); // Keep background updates going + return; + } + + std::vector live_pids = getProcessPids(); + bool is_actually_running = !live_pids.empty(); + + if (is_actually_running) { + failed_checks = 0; + ignmsg << "[UePowerPlugin] Polling: PROCESS FOUND (" << live_pids.size() + << " PIDs)" << std::endl; + + if (!process_running) { + process_running = true; + emit processRunningChanged(); + } + } else { + failed_checks++; + ignmsg << "[UePowerPlugin] Polling: PROCESS NOT FOUND (Strike " + << failed_checks << "/2)" << std::endl; + + if (failed_checks >= 2 && process_running) { + process_running = false; + emit processRunningChanged(); + } + } + + // Ping Docker to gather data for the *next* cycle + triggerDockerCheck(name); } void UePowerPlugin::toggleProcess() { std::string name = container_name.toStdString(); if (!isValidContainerName(name)) { - ignerr << "[UePowerPlugin] Invalid container name: " << name - << std::endl; + ignerr << "[UePowerPlugin] Invalid container name." << std::endl; return; } - // First click: check actual state, then become connected + // --- 1. FIRST CLICK --- if (!connected) { - process_running = checkProcessRunning(); + ignmsg << "[UePowerPlugin] === INITIALIZING CONNECTION ===" + << std::endl; connected = true; + + triggerDockerCheck( + name); // Fire the very first check to build the text file + status_timer->start(); emit connectedChanged(); - emit processRunningChanged(); - ignmsg << "[UePowerPlugin] Connected to " << name << " — process is " - << (process_running ? "running" : "stopped") << std::endl; return; } - // Subsequent clicks: toggle without checking + // --- 2. SUBSEQUENT CLICKS --- + skip_checks_count = + 3; // Block UI from flickering for 6 seconds while processes boot/die + if (process_running) { - std::string cmd = "docker exec " + name + " pkill nr-uesoftmodem 2>&1"; - ignmsg << "[UePowerPlugin] Running: " << cmd << std::endl; - int ret = system(cmd.c_str()); - ignmsg << "[UePowerPlugin] Kill exit=" << ret << std::endl; + ignmsg << "[UePowerPlugin] TURN OFF Clicked. Executing KILL..." + << std::endl; + std::vector current_live_pids = getProcessPids(); + for (int pid : current_live_pids) { + std::string cmd = "docker exec " + name + " kill -9 " + + std::to_string(pid) + " > /dev/null 2>&1 &"; + system(cmd.c_str()); + } + + // Immediately delete the text file so the timer doesn't read ghost + // processes + system(("rm -f /tmp/ue_" + name + "_pids.txt").c_str()); + process_running = false; emit processRunningChanged(); } else { + ignmsg << "[UePowerPlugin] TURN ON Clicked. Executing START..." + << std::endl; std::string ip = gnb_ip.toStdString(); - if (!isValidIpAddress(ip)) { - ignerr << "[UePowerPlugin] Invalid gNB IP address: " << ip - << std::endl; + std::string freq = carrier_freq.toStdString(); + if (!isValidIpAddress(ip) || !isValidFrequency(freq)) return; - } - std::string cmd = buildStartCommand(); - ignmsg << "[UePowerPlugin] Running: " << cmd << std::endl; - int ret = system(cmd.c_str()); - ignmsg << "[UePowerPlugin] Start exit=" << ret << std::endl; + + // Ensure the host doesn't freeze waiting for Docker to parse the + // command + std::string cmd = buildStartCommand() + " > /dev/null 2>&1 &"; + system(cmd.c_str()); + process_running = true; emit processRunningChanged(); } -} +} \ No newline at end of file diff --git a/phine-plugins/src/phine_plugins/src/UePowerPlugin.hh b/phine-plugins/src/phine_plugins/src/UePowerPlugin.hh index b0a5cc3..4f3bb35 100644 --- a/phine-plugins/src/phine_plugins/src/UePowerPlugin.hh +++ b/phine-plugins/src/phine_plugins/src/UePowerPlugin.hh @@ -16,8 +16,11 @@ limitations under the License.*/ #define UE_POWER_PLUGIN_HH_ #include +#include +#include #include #include +#include namespace phine_plugins { @@ -27,6 +30,8 @@ class UePowerPlugin : public ignition::gui::Plugin { Q_PROPERTY(QString containerName READ getContainerName WRITE setContainerName NOTIFY containerNameChanged) Q_PROPERTY(QString gnbIp READ getGnbIp WRITE setGnbIp NOTIFY gnbIpChanged) + Q_PROPERTY(QString carrierFreq READ getCarrierFreq WRITE setCarrierFreq + NOTIFY carrierFreqChanged) Q_PROPERTY( bool processRunning READ isProcessRunning NOTIFY processRunningChanged) Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged) @@ -40,30 +45,43 @@ class UePowerPlugin : public ignition::gui::Plugin { void setContainerName(const QString &name); QString getGnbIp() const; void setGnbIp(const QString &ip); + QString getCarrierFreq() const; + void setCarrierFreq(const QString &freq); bool isProcessRunning() const; bool isConnected() const; public slots: void toggleProcess(); + void checkAndUpdateStatus(); signals: void containerNameChanged(); void gnbIpChanged(); + void carrierFreqChanged(); void processRunningChanged(); void connectedChanged(); private: bool checkProcessRunning(); + std::vector getProcessPids() const; std::string buildStartCommand() const; static bool isValidContainerName(const std::string &name); static bool isValidIpAddress(const std::string &ip); + static bool isValidFrequency(const std::string &freq); QString container_name{"ue_turtlebot"}; QString gnb_ip{"192.168.70.160"}; + QString carrier_freq{"3619200000"}; bool process_running{false}; bool connected{false}; + QTimer *status_timer{nullptr}; + std::vector tracked_pids; + + // Anti-Flicker trackers + int skip_checks_count{0}; + int failed_checks{0}; }; } // namespace phine_plugins -#endif // UE_POWER_PLUGIN_HH_ +#endif // UE_POWER_PLUGIN_HH_ \ No newline at end of file diff --git a/phine-plugins/src/phine_plugins/src/UePowerPlugin.qml b/phine-plugins/src/phine_plugins/src/UePowerPlugin.qml index 13647fa..d3f8edf 100644 --- a/phine-plugins/src/phine_plugins/src/UePowerPlugin.qml +++ b/phine-plugins/src/phine_plugins/src/UePowerPlugin.qml @@ -6,7 +6,7 @@ Rectangle { id: uePower color: "#2b2b2b" Layout.minimumWidth: 400 - Layout.minimumHeight: 270 + Layout.minimumHeight: 320 Layout.fillWidth: true anchors.fill: parent @@ -82,6 +82,32 @@ Rectangle { } } + // Carrier Frequency Input + RowLayout { + spacing: 8 + Label { + text: "Carrier Freq:" + color: "#cccccc" + font.pixelSize: 13 + Layout.preferredWidth: 80 + } + TextField { + id: carrierFreqField + text: UePowerPlugin.carrierFreq + placeholderText: "e.g. 3619200000" + Layout.fillWidth: true + onTextChanged: UePowerPlugin.carrierFreq = text + enabled: !UePowerPlugin.connected + font.pixelSize: 13 + background: Rectangle { + color: carrierFreqField.enabled ? "#3c3c3c" : "#2a2a2a" + border.color: "#666666" + radius: 3 + } + color: "#ffffff" + } + } + Rectangle { Layout.fillWidth: true height: 1 diff --git a/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.cc b/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.cc index ea37688..d0d66cb 100644 --- a/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.cc +++ b/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.cc @@ -13,18 +13,40 @@ See the License for the specific language governing permissions and limitations under the License.*/ #include "gNBPowerPlugin.hh" +#include +#include #include #include #include #include +#include +#include #include +#include IGNITION_ADD_PLUGIN(phine_plugins::gNBPowerPlugin, ignition::gui::Plugin) using namespace phine_plugins; +// Helper function to ask Docker for data without freezing Gazebo +static void triggerDockerCheck(const std::string &name) { + std::string file_path = "/tmp/gnb_" + name + "_pids.txt"; + std::string tmp_path = file_path + ".tmp"; + // Redirects Docker output to a temporary file, then instantly swaps it. The + // '&' ensures 0 freezing. + std::string cmd = "docker exec " + name + + " ps -eo pid,stat,args --no-headers 2>/dev/null > " + + tmp_path + " && mv " + tmp_path + " " + file_path + " &"; + system(cmd.c_str()); +} + gNBPowerPlugin::gNBPowerPlugin() { ignmsg << "[gNBPowerPlugin] constructor called" << std::endl; + + status_timer = new QTimer(this); + status_timer->setInterval(2000); // 2 seconds + connect(status_timer, &QTimer::timeout, this, + &gNBPowerPlugin::checkAndUpdateStatus); } gNBPowerPlugin::~gNBPowerPlugin() {} @@ -43,7 +65,6 @@ void gNBPowerPlugin::LoadConfig(const tinyxml2::XMLElement *_pluginElem) { } QString gNBPowerPlugin::getContainerName() const { return container_name; } - void gNBPowerPlugin::setContainerName(const QString &name) { if (container_name != name) { container_name = name; @@ -52,71 +73,149 @@ void gNBPowerPlugin::setContainerName(const QString &name) { } bool gNBPowerPlugin::isProcessRunning() const { return process_running; } - bool gNBPowerPlugin::isConnected() const { return connected; } bool gNBPowerPlugin::isValidContainerName(const std::string &name) { - if (name.empty() || name.size() > 128) { + if (name.empty() || name.size() > 128) return false; - } static const std::regex valid_name(R"(^[a-zA-Z0-9][a-zA-Z0-9_.\-]*$)"); return std::regex_match(name, valid_name); } -bool gNBPowerPlugin::checkProcessRunning() { +std::vector gNBPowerPlugin::getProcessPids() const { + std::vector pids; std::string name = container_name.toStdString(); - if (!isValidContainerName(name)) { - return false; + + if (!isValidContainerName(name)) + return pids; + + // Reads the file locally. This is instantaneous and immune to Docker + // lock-ups. + std::string file_path = "/tmp/gnb_" + name + "_pids.txt"; + std::ifstream file(file_path); + if (file.is_open()) { + std::string line; + while (std::getline(file, line)) { + std::istringstream iss(line); + std::string pid_str, stat; + + if (iss >> pid_str >> stat) { + try { + int pid = std::stoi(pid_str); + // Search specifically for nr-softmodem + if (line.find("nr-softmodem") != std::string::npos && + stat.front() != 'Z') { + pids.push_back(pid); + } + } catch (...) { + } + } + } } - std::string cmd = - "docker exec " + name + " pgrep nr-softmodem > /dev/null 2>&1"; - int ret = system(cmd.c_str()); - return (ret == 0); + return pids; } std::string gNBPowerPlugin::buildStartCommand() const { std::string name = container_name.toStdString(); + return "docker exec " + name + " /bin/bash -c" " '/opt/oai-gnb/bin/nr-softmodem" " -O /opt/oai-gnb/etc/gnb.yaml" " -E --rfsim" - " --log_config.global_log_options level,nocolor,time &'"; + " --log_config.global_log_options level,nocolor,time > /dev/null " + "2>&1 &'"; +} + +void gNBPowerPlugin::checkAndUpdateStatus() { + if (!connected) + return; + + std::string name = container_name.toStdString(); + + if (skip_checks_count > 0) { + skip_checks_count--; + triggerDockerCheck(name); // Keep background updates going + return; + } + + std::vector live_pids = getProcessPids(); + bool is_actually_running = !live_pids.empty(); + + if (is_actually_running) { + failed_checks = 0; + ignmsg << "[gNBPowerPlugin] Polling: PROCESS FOUND (" + << live_pids.size() << " PIDs)" << std::endl; + + if (!process_running) { + process_running = true; + emit processRunningChanged(); + } + } else { + failed_checks++; + ignmsg << "[gNBPowerPlugin] Polling: PROCESS NOT FOUND (Strike " + << failed_checks << "/2)" << std::endl; + + if (failed_checks >= 2 && process_running) { + process_running = false; + emit processRunningChanged(); + } + } + + // Ping Docker to gather data for the *next* cycle + triggerDockerCheck(name); } void gNBPowerPlugin::toggleProcess() { std::string name = container_name.toStdString(); if (!isValidContainerName(name)) { - ignerr << "[gNBPowerPlugin] Invalid container name: " << name - << std::endl; + ignerr << "[gNBPowerPlugin] Invalid container name." << std::endl; return; } - // First click: check actual state, then become connected + // --- 1. FIRST CLICK --- if (!connected) { - process_running = checkProcessRunning(); + ignmsg << "[gNBPowerPlugin] === INITIALIZING CONNECTION ===" + << std::endl; connected = true; + + triggerDockerCheck( + name); // Fire the very first check to build the text file + status_timer->start(); emit connectedChanged(); - emit processRunningChanged(); - ignmsg << "[gNBPowerPlugin] Connected to " << name << " — process is " - << (process_running ? "running" : "stopped") << std::endl; return; } - // Subsequent clicks: toggle without checking + // --- 2. SUBSEQUENT CLICKS --- + skip_checks_count = + 3; // Block UI from flickering for 6 seconds while processes boot/die + if (process_running) { - std::string cmd = "docker exec " + name + " pkill nr-softmodem 2>&1"; - ignmsg << "[gNBPowerPlugin] Running: " << cmd << std::endl; - int ret = system(cmd.c_str()); - ignmsg << "[gNBPowerPlugin] Kill exit=" << ret << std::endl; + ignmsg << "[gNBPowerPlugin] TURN OFF Clicked. Executing KILL..." + << std::endl; + std::vector current_live_pids = getProcessPids(); + for (int pid : current_live_pids) { + std::string cmd = "docker exec " + name + " kill -9 " + + std::to_string(pid) + " > /dev/null 2>&1 &"; + system(cmd.c_str()); + } + + // Immediately delete the text file so the timer doesn't read ghost + // processes + system(("rm -f /tmp/gnb_" + name + "_pids.txt").c_str()); + process_running = false; emit processRunningChanged(); } else { - std::string cmd = buildStartCommand(); - ignmsg << "[gNBPowerPlugin] Running: " << cmd << std::endl; - int ret = system(cmd.c_str()); - ignmsg << "[gNBPowerPlugin] Start exit=" << ret << std::endl; + ignmsg << "[gNBPowerPlugin] TURN ON Clicked. Executing START..." + << std::endl; + + // Ensure the host doesn't freeze waiting for Docker to parse the + // command + std::string cmd = buildStartCommand() + " > /dev/null 2>&1 &"; + system(cmd.c_str()); + process_running = true; emit processRunningChanged(); } -} +} \ No newline at end of file diff --git a/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.hh b/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.hh index b256bab..7e7da6b 100644 --- a/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.hh +++ b/phine-plugins/src/phine_plugins/src/gNBPowerPlugin.hh @@ -16,8 +16,10 @@ limitations under the License.*/ #define GNB_POWER_PLUGIN_HH_ #include +#include #include #include +#include namespace phine_plugins { @@ -42,6 +44,7 @@ class gNBPowerPlugin : public ignition::gui::Plugin { public slots: void toggleProcess(); + void checkAndUpdateStatus(); signals: void containerNameChanged(); @@ -49,15 +52,20 @@ class gNBPowerPlugin : public ignition::gui::Plugin { void connectedChanged(); private: - bool checkProcessRunning(); + std::vector getProcessPids() const; std::string buildStartCommand() const; static bool isValidContainerName(const std::string &name); QString container_name{"oai-gNB1"}; bool process_running{false}; bool connected{false}; + QTimer *status_timer{nullptr}; + + // Anti-Flicker trackers required by the compiler + int skip_checks_count{0}; + int failed_checks{0}; }; } // namespace phine_plugins -#endif // GNB_POWER_PLUGIN_HH_ +#endif // GNB_POWER_PLUGIN_HH_ \ No newline at end of file