Line data Source code
1 : /*! 2 : * @file DisplayManager.cpp 3 : * @brief Implementation of the DisplayManager class for handling the display of 4 : * the cluster. 5 : * @version 0.1 6 : * @date 2025-01-31 7 : * @author FĂ©lix LE BIHAN (@Fle-bihh) 8 : * @author Tiago Pereira (@t-pereira06) 9 : * @author Ricardo Melo (@reomelo) 10 : * @author Michel Batista (@MicchelFAB) 11 : * @details This file contains the implementation of the DisplayManager class, 12 : * which is responsible for handling the display of the cluster. 13 : * @note This class is used to manage the display of the cluster. 14 : * @warning Ensure that the display labels are properly initialized in the UI 15 : * form. 16 : * @see DisplayManager.hpp 17 : * @copyright Copyright (c) 2025 18 : */ 19 : 20 : #include "DisplayManager.hpp" 21 : #include <QDebug> 22 : #include <QPushButton> 23 : 24 : /*! 25 : * @brief Construct a new DisplayManager object. 26 : * @param ui The UI form for the cluster. 27 : * @param parent The parent QObject. 28 : * @details This constructor initializes the DisplayManager object with the 29 : * specified UI form. 30 : */ 31 16 : DisplayManager::DisplayManager(Ui::CarManager *ui, QObject *parent) 32 16 : : QObject(parent), m_ui(ui) { 33 : // Ensure the labels are initialized 34 16 : if (!m_ui->speedLabel || !m_ui->timeLabel || 35 16 : !m_ui->temperatureLabel || !m_ui->batteryLabel) { 36 0 : qDebug() << "Error: Labels not initialized in the UI form!"; 37 0 : return; 38 : } 39 : 40 16 : m_ui->speedLimit50Label->hide(); 41 16 : m_ui->speedLimit80Label->hide(); 42 : 43 : // Set initial values for the labels 44 16 : m_ui->speedLabel->setText("0"); 45 16 : m_ui->timeLabel->setText("--:--:--"); 46 16 : m_ui->temperatureLabel->setText("N/A"); 47 16 : m_ui->batteryLabel->setText("--%"); 48 16 : m_ui->speedMetricsLabel->setText("KM/H"); 49 : 50 16 : setupWifiDropdown(); 51 : 52 : // Directly connect button clicks to signals 53 16 : connect(m_ui->toggleDrivingModeButton, &QPushButton::clicked, this, 54 : &DisplayManager::drivingModeToggled); 55 16 : connect(m_ui->toggleMetricsButton, &QPushButton::clicked, this, 56 : &DisplayManager::clusterMetricsToggled); 57 : 58 16 : m_speed50Timer = new QTimer(this); 59 16 : m_speed50Timer->setSingleShot(true); 60 16 : connect(m_speed50Timer, &QTimer::timeout, m_ui->speedLimit50Label, &QWidget::hide); 61 : 62 16 : m_speed80Timer = new QTimer(this); 63 16 : m_speed80Timer->setSingleShot(true); 64 16 : connect(m_speed80Timer, &QTimer::timeout, m_ui->speedLimit80Label, &QWidget::hide); 65 : } 66 : 67 : /*! 68 : * @brief Updates the CAN bus data on the display. 69 : * @details This function updates the speed and RPM labels based on the CAN bus 70 : * data. 71 : * @param speed The current speed of the car. 72 : * @param rpm The current RPM of the car. 73 : */ 74 1 : void DisplayManager::updateCanBusData(float speed, int rpm) { 75 1 : m_ui->speedLabel->setText(QString::number(static_cast<int>(speed))); 76 1 : } 77 : 78 : /*! 79 : * @brief Updates the engine data on the display. 80 : * @details This function updates the direction label and blinker visibility 81 : * based on the engine data. 82 : * @param direction The current direction of the car. 83 : * @param steeringAngle The current steering angle of the car. 84 : */ 85 2 : void DisplayManager::updateEngineData(CarDirection direction, 86 : int steeringAngle) { 87 : //QString directionText; 88 2 : switch (direction) { 89 1 : case CarDirection::Drive: 90 : //directionText = "D"; 91 1 : m_ui->directionParkLabel->setStyleSheet("color: white; background: transparent;"); 92 1 : m_ui->directionReverseLabel->setStyleSheet("color: white; background: transparent;"); 93 1 : m_ui->directionNeutralLabel->setStyleSheet("color: white; background: transparent;"); 94 1 : m_ui->directionDriveLabel->setStyleSheet("color: green; background: transparent;"); 95 : 96 1 : m_ui->directionParkLabel->update(); 97 1 : m_ui->directionReverseLabel->update(); 98 1 : m_ui->directionNeutralLabel->update(); 99 1 : m_ui->directionDriveLabel->update(); 100 1 : break; 101 1 : case CarDirection::Reverse: 102 : //directionText = "R"; 103 1 : m_ui->directionParkLabel->setStyleSheet("color: white; background: transparent;"); 104 1 : m_ui->directionReverseLabel->setStyleSheet("color: lightgreen; background: transparent;"); 105 1 : m_ui->directionNeutralLabel->setStyleSheet("color: white; background: transparent;"); 106 1 : m_ui->directionDriveLabel->setStyleSheet("color: white; background: transparent;"); 107 : 108 1 : m_ui->directionParkLabel->update(); 109 1 : m_ui->directionReverseLabel->update(); 110 1 : m_ui->directionNeutralLabel->update(); 111 1 : m_ui->directionDriveLabel->update(); 112 1 : break; 113 : } 114 2 : } 115 : 116 : /*! 117 : * @brief Updates the system time on the display. 118 : * @details This function updates the date, time, and weekday labels based on 119 : * the current system time. 120 : * @param currentMonth The current month. 121 : * @param currentTime The current time. 122 : * @param currentDay The current day of the week. 123 : */ 124 1 : void DisplayManager::updateSystemTime(const QString ¤tMonth, 125 : const QString ¤tTime, 126 : const QString ¤tDay) { 127 1 : m_ui->dateLabel->setText(currentMonth + " " + currentDay); 128 1 : m_ui->timeLabel->setText(currentTime); 129 1 : } 130 : 131 1 : QString DisplayManager::getWifiSSID() { 132 : // Linux: read active SSID using shell command 133 2 : QProcess proc; 134 1 : proc.start("iwgetid -r"); // Gets current SSID 135 1 : proc.waitForFinished(); 136 3 : QString output = proc.readAllStandardOutput().trimmed(); 137 2 : return output.isEmpty() ? "Not connected" : output; 138 : } 139 : 140 1 : QString DisplayManager::getLocalIPAddress() { 141 2 : const QList<QHostAddress> &addresses = QNetworkInterface::allAddresses(); 142 3 : for (const QHostAddress &address : addresses) { 143 3 : if (address.protocol() == QAbstractSocket::IPv4Protocol && !address.isLoopback()) 144 1 : return address.toString(); 145 : } 146 0 : return "No IP"; 147 : } 148 : 149 16 : void DisplayManager::setupWifiDropdown() { 150 16 : connect(m_ui->wifiToggleButton, &QToolButton::clicked, this, [=]() { 151 0 : QMenu* wifiMenu = new QMenu(m_ui->wifiToggleButton); 152 : 153 : // Fetch current data 154 0 : QString ssidText = getWifiSSID(); 155 0 : QString ipText = getLocalIPAddress(); 156 : 157 0 : wifiMenu->addAction("Connected to: " + ssidText); 158 0 : wifiMenu->addAction("IP Address: " + ipText); 159 : 160 0 : wifiMenu->setStyleSheet( 161 : "QMenu {" 162 : " background-color: rgba(30, 30, 30, 0.9);" 163 : " color: white;" 164 : " border: 1px solid rgba(255, 255, 255, 0.2);" 165 : " border-radius: 6px;" 166 : " padding: 6px;" 167 : " }" 168 : ); 169 : 170 0 : QPoint pos = m_ui->wifiToggleButton->mapToGlobal(QPoint(0, m_ui->wifiToggleButton->height())); 171 0 : wifiMenu->exec(pos); 172 0 : }); 173 16 : } 174 : 175 : /*! 176 : * @brief Updates the temperature on the display. 177 : * @details This function updates the temperature label based on the current 178 : * temperature. 179 : * @param temperature The current temperature. 180 : */ 181 1 : void DisplayManager::updateTemperature(const QString &temperature) { 182 1 : m_ui->temperatureLabel->setText(temperature); 183 1 : } 184 : 185 : /*! 186 : * @brief Updates the battery percentage on the display. 187 : * @details This function updates the battery percentage label and low battery 188 : * warning based on the current battery percentage. 189 : * @param batteryPercentage The current battery percentage. 190 : */ 191 1 : void DisplayManager::updateBatteryPercentage(float batteryPercentage) { 192 1 : m_ui->batteryLabel->setText(QString::number(static_cast<int>(batteryPercentage)) + "%"); 193 1 : } 194 : 195 : /*! 196 : * @brief Updates the mileage on the display. 197 : * @details This function updates the mileage label based on the current 198 : * mileage. 199 : * @param mileage The current mileage. 200 : */ 201 1 : void DisplayManager::updateMileage(double mileage) { 202 1 : m_ui->mileageLabel->setText(QString::number(static_cast<int>(mileage)) + 203 : " m"); 204 1 : } 205 : 206 : /*! 207 : * @brief Updates the driving mode on the display. 208 : * @details This function updates the driving mode label based on the current 209 : * driving mode. 210 : * @param newMode The new driving mode. 211 : */ 212 2 : void DisplayManager::updateDrivingMode(DrivingMode newMode) { 213 4 : QString modeText; 214 2 : switch (newMode) { 215 1 : case DrivingMode::Manual: 216 1 : modeText = "Manual"; 217 1 : m_ui->laneKeepingAssistLabel->show(); 218 1 : m_ui->laneDepartureWarningLabel->show(); 219 : // Stop blinking if active 220 1 : if (m_blinkTimer) { 221 0 : m_blinkTimer->stop(); 222 0 : m_blinkTimer->deleteLater(); 223 0 : m_blinkTimer = nullptr; 224 : } 225 1 : break; 226 1 : case DrivingMode::Automatic: 227 1 : modeText = "Automatic"; 228 1 : m_ui->laneKeepingAssistLabel->hide(); 229 1 : if (!m_blinkTimer) { 230 1 : m_blinkTimer = new QTimer(this); 231 1 : connect(m_blinkTimer, &QTimer::timeout, this, [=]() { 232 0 : bool currentlyVisible = m_ui->laneDepartureWarningLabel->isVisible(); 233 0 : m_ui->laneDepartureWarningLabel->setVisible(!currentlyVisible); 234 0 : }); 235 1 : m_blinkTimer->start(150); // Blink every 150ms 236 : } 237 1 : break; 238 : } 239 2 : m_ui->drivingModeLabel->setText(modeText); 240 2 : } 241 : 242 : /*! 243 : * @brief Updates the cluster theme on the display. 244 : * @details This function updates the cluster theme label based on the current 245 : * cluster theme. 246 : * @param newTheme The new cluster theme. 247 : */ 248 2 : void DisplayManager::updateClusterTheme(ClusterTheme newTheme) { 249 4 : QString themeText; 250 2 : switch (newTheme) { 251 1 : case ClusterTheme::Dark: 252 1 : themeText = "Dark"; 253 1 : break; 254 1 : case ClusterTheme::Light: 255 1 : themeText = "Light"; 256 1 : break; 257 : } 258 2 : } 259 : 260 : /*! 261 : * @brief Updates the cluster metrics on the display. 262 : * @details This function updates the cluster metrics label and speed metrics 263 : * label based on the current cluster metrics. 264 : * @param newMetrics The new cluster metrics. 265 : */ 266 2 : void DisplayManager::updateClusterMetrics(ClusterMetrics newMetrics) { 267 2 : QString metricsText; 268 2 : switch (newMetrics) { 269 1 : case ClusterMetrics::Kilometers: 270 1 : metricsText = "km/h"; 271 1 : break; 272 1 : case ClusterMetrics::Miles: 273 1 : metricsText = "mph"; 274 1 : break; 275 : } 276 2 : m_ui->speedMetricsLabel->setText(metricsText.toUpper()); 277 2 : } 278 : 279 2 : void DisplayManager::updateSpeedLimitLabels(int speed) { 280 2 : if (speed == 50) { 281 1 : m_ui->speedLimit80Label->hide(); 282 1 : m_ui->speedLimit50Label->show(); 283 1 : m_speed50Timer->start(3000); 284 1 : } else if (speed == 80) { 285 1 : m_ui->speedLimit50Label->hide(); 286 1 : m_ui->speedLimit80Label->show(); 287 1 : m_speed80Timer->start(3000); 288 : } 289 2 : } 290 : 291 1 : void DisplayManager::displayInferenceImage(const QImage &image) { 292 1 : if (!m_ui->inferenceLabel) 293 0 : return; 294 : 295 2 : QPixmap original = QPixmap::fromImage(image); 296 2 : QPixmap rounded(original.size()); 297 1 : rounded.fill(Qt::transparent); 298 : 299 2 : QPainter painter(&rounded); 300 1 : painter.setRenderHint(QPainter::Antialiasing, true); 301 : 302 2 : QPainterPath path; 303 1 : path.addRoundedRect(original.rect(), 34, 34); 304 1 : painter.setClipPath(path); 305 1 : painter.drawPixmap(0, 0, original); 306 : 307 1 : m_ui->inferenceLabel->setPixmap(rounded); 308 : }