mirror of
https://github.com/BotChain-Robots/dev-tools.git
synced 2026-07-08 15:07:22 +02:00
149 lines
5.7 KiB
C++
149 lines
5.7 KiB
C++
#include "tabs/InformationTab.h"
|
|
#include <ftxui/dom/elements.hpp>
|
|
#include <format>
|
|
|
|
InformationTab::InformationTab(std::shared_ptr<RobotController> robot_controller, uint8_t device_id)
|
|
: robot_controller_(robot_controller), device_id_(device_id) {
|
|
}
|
|
|
|
Component InformationTab::createComponent() {
|
|
return Renderer([=, this] {
|
|
// Try to get the module data
|
|
auto module_opt = robot_controller_->getModule(device_id_);
|
|
|
|
Elements content = {
|
|
text("Device Information") | bold | hcenter,
|
|
separator()
|
|
};
|
|
|
|
if (!module_opt.has_value()) {
|
|
content.push_back(text("Module not found or unavailable") | color(Color::Red) | hcenter);
|
|
return vbox(content);
|
|
}
|
|
|
|
auto module_weak = module_opt.value();
|
|
if (module_weak.expired()) {
|
|
content.push_back(text("Module reference expired") | color(Color::Red) | hcenter);
|
|
return vbox(content);
|
|
}
|
|
|
|
auto module = module_weak.lock();
|
|
if (!module) {
|
|
content.push_back(text("Failed to access module") | color(Color::Red) | hcenter);
|
|
return vbox(content);
|
|
}
|
|
|
|
// Get real module data
|
|
uint8_t device_id = module->get_device_id();
|
|
ModuleType module_type = module->get_type();
|
|
Messaging::ConnectionType connection_type = module->get_connection_type();
|
|
uint8_t leader = module->get_leader();
|
|
auto last_updated = module->get_last_updated_time();
|
|
auto neighbours = module->get_neighbours();
|
|
|
|
// Create information display with real data
|
|
Elements info_elements = {
|
|
hbox({text("Device ID: ") | bold, text(std::to_string(static_cast<int>(device_id)))}),
|
|
hbox({text("Module Type: ") | bold, text(getModuleTypeString(module_type))}),
|
|
hbox({text("Connection Type: ") | bold, text(getConnectionTypeString(connection_type))}),
|
|
hbox({text("Leader ID: ") | bold, text(std::to_string(static_cast<int>(leader)))}),
|
|
hbox({text("Last Updated: ") | bold, text(formatTimeSince(last_updated))}),
|
|
separator(),
|
|
text("Neighbours:") | bold
|
|
};
|
|
|
|
// Add neighbour information
|
|
if (neighbours.empty()) {
|
|
info_elements.push_back(text("• No neighbours detected") | dim);
|
|
} else {
|
|
for (const auto& neighbour : neighbours) {
|
|
info_elements.push_back(
|
|
text(std::format("• Device ID: {} (Orientation: {})",
|
|
static_cast<int>(neighbour.device_id),
|
|
static_cast<int>(neighbour.orientation))) | dim
|
|
);
|
|
}
|
|
}
|
|
|
|
info_elements.push_back(separator());
|
|
|
|
// Try to get sensor values (these may throw or return defaults if not implemented)
|
|
try {
|
|
double position = module->get_position();
|
|
std::string text_value = module->get_text();
|
|
|
|
info_elements.push_back(text("Sensor Values:") | bold);
|
|
if (position != 0.0) { // Assume 0.0 means no position data
|
|
info_elements.push_back(
|
|
text(std::format("• Position: {:.2f}", position)) | dim
|
|
);
|
|
}
|
|
if (!text_value.empty()) {
|
|
info_elements.push_back(
|
|
text(std::format("• Text: {}", text_value)) | dim
|
|
);
|
|
}
|
|
if (position == 0.0 && text_value.empty()) {
|
|
info_elements.push_back(text("• No sensor data available") | dim);
|
|
}
|
|
} catch (...) {
|
|
info_elements.push_back(text("• Sensor data unavailable") | dim);
|
|
}
|
|
|
|
content.insert(content.end(), info_elements.begin(), info_elements.end());
|
|
|
|
return vbox(content) | flex;
|
|
});
|
|
}
|
|
|
|
std::string InformationTab::getModuleTypeString(ModuleType type) {
|
|
// Provide meaningful names for common module types
|
|
int type_value = static_cast<int>(type);
|
|
switch (type_value) {
|
|
case 0: return "MMMF Splitter";
|
|
case 1: return "Arm Servo";
|
|
case 2: return "DC Motor";
|
|
case 3: return "Power";
|
|
case 4: return "Pivot Servo";
|
|
case 5: return "Display";
|
|
case 6: return "Gripper";
|
|
case 7: return "Speaker";
|
|
case 8: return "IMU";
|
|
case 9: return "Distance Sensor";
|
|
case 10: return "MMMM Splitter";
|
|
case 11: return "MMF Triangle Splitter";
|
|
case 12: return "MMM Triangle Splitter";
|
|
default: return std::format("Module Type {}", type_value);
|
|
}
|
|
}
|
|
|
|
std::string InformationTab::getConnectionTypeString(Messaging::ConnectionType type) {
|
|
// Provide meaningful names for common connection types
|
|
int type_value = static_cast<int>(type);
|
|
switch (type_value) {
|
|
case 0: return "Wi-Fi";
|
|
case 1: return "Wired Hop";
|
|
default: return std::format("Connection Type {}", type_value);
|
|
}
|
|
}
|
|
|
|
std::string InformationTab::formatTimeSince(const std::chrono::time_point<std::chrono::system_clock>& time_point) {
|
|
auto now = std::chrono::system_clock::now();
|
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - time_point);
|
|
|
|
auto seconds = duration.count();
|
|
|
|
if (seconds < 60) {
|
|
return std::format("{} seconds ago", seconds);
|
|
} else if (seconds < 3600) {
|
|
auto minutes = seconds / 60;
|
|
return std::format("{} minute{} ago", minutes, minutes == 1 ? "" : "s");
|
|
} else if (seconds < 86400) {
|
|
auto hours = seconds / 3600;
|
|
return std::format("{} hour{} ago", hours, hours == 1 ? "" : "s");
|
|
} else {
|
|
auto days = seconds / 86400;
|
|
return std::format("{} day{} ago", days, days == 1 ? "" : "s");
|
|
}
|
|
}
|