From 151567809ba567d811e41e44026d65b7b2d15f0a Mon Sep 17 00:00:00 2001 From: Rui Pires Date: Mon, 6 Jan 2025 22:09:54 +0000 Subject: [PATCH 1/2] Add battery property and functionality to CANBusHandler; update QML integration --- include/CANBusHandler.hpp | 9 +++++-- src/CANBusHandler.cpp | 29 +++++++++++++++++++---- src/Main.qml | 50 ++++----------------------------------- 3 files changed, 36 insertions(+), 52 deletions(-) diff --git a/include/CANBusHandler.hpp b/include/CANBusHandler.hpp index 8d79bba..b46a8a2 100644 --- a/include/CANBusHandler.hpp +++ b/include/CANBusHandler.hpp @@ -7,6 +7,7 @@ class CANBusHandler : public QObject { Q_OBJECT Q_PROPERTY(int speed READ getSpeed WRITE setSpeed NOTIFY speedChanged) + Q_PROPERTY(int battery READ getBattery WRITE setBattery NOTIFY batteryChanged) public: explicit CANBusHandler(QObject *parent = nullptr); @@ -14,16 +15,20 @@ class CANBusHandler : public QObject int getSpeed() const; void setSpeed(int speed); + int getBattery() const; + void setBattery(int battery); signals: void speedChanged(int speed); + void batteryChanged(int battery); private slots: void readFrames(); private: - int canSocket; // File descriptor for the CAN socket - int m_speed; // Member variable for the speed + int canSocket; + int m_speed; + int m_battery; }; #endif // CANBUSHANDLER_HPP diff --git a/src/CANBusHandler.cpp b/src/CANBusHandler.cpp index af28be9..fd1bac5 100644 --- a/src/CANBusHandler.cpp +++ b/src/CANBusHandler.cpp @@ -12,7 +12,8 @@ CANBusHandler::CANBusHandler(QObject *parent) : QObject(parent), canSocket(-1), - m_speed(0) + m_speed(0), + m_battery(0) { struct ifreq ifr; struct sockaddr_can addr; @@ -46,7 +47,6 @@ CANBusHandler::~CANBusHandler() { if (canSocket >= 0) { close(canSocket); // Close the CAN socket - canSocket = -1; } } @@ -63,6 +63,19 @@ void CANBusHandler::setSpeed(int speed) } } +int CANBusHandler::getBattery() const +{ + return m_battery; +} + +void CANBusHandler::setBattery(int battery) +{ + if (m_battery != battery) { + m_battery = battery; + emit batteryChanged(m_battery); + } +} + void CANBusHandler::readFrames() { struct can_frame frame; @@ -78,10 +91,16 @@ void CANBusHandler::readFrames() memcpy(&speed, frame.data, sizeof(int)); speed = ntohl(speed); - + // qDebug() << "Speed:" << speed; // Print the speed value setSpeed(speed); - } else { - qDebug() << "Received CAN frame with ID:" << frame.can_id; + } else if (frame.can_id == 0x02) { + int battery; + memcpy(&battery, frame.data, sizeof(int)); + + battery = ntohl(battery); + + // qDebug() << "Battery:" << battery; // Print the speed value + setBattery(battery); } } diff --git a/src/Main.qml b/src/Main.qml index ea5ed84..b38add3 100644 --- a/src/Main.qml +++ b/src/Main.qml @@ -11,12 +11,12 @@ ApplicationWindow { CANBusHandler { id: canBusHandler onSpeedChanged: speedGauge.requestPaint() + onBatteryChanged: batteryGauge.requestPaint() } Rectangle { anchors.fill: parent - // Background gradient Canvas { anchors.fill: parent onPaint: { @@ -59,46 +59,6 @@ ApplicationWindow { } } - Canvas { - id: roadCanvas - anchors.fill: parent - - onPaint: { - var ctx = getContext("2d"); - ctx.clearRect(0, 0, width, height); - - var centerX = width / 2; - var roadWidth = 200; - var roadHeight = height; - - // Perspective variables - var topRoadWidth = 50; // Simulated narrow top width for 3D effect - var bottomRoadWidth = roadWidth; - - // Road boundaries - var leftTop = centerX - topRoadWidth / 2; - var rightTop = centerX + topRoadWidth / 2; - var leftBottom = centerX - bottomRoadWidth / 2; - var rightBottom = centerX + bottomRoadWidth / 2; - - // Draw road edges - ctx.strokeStyle = "white"; - ctx.lineWidth = 3; - - // Left edge - ctx.beginPath(); - ctx.moveTo(leftTop, 0); - ctx.lineTo(leftBottom, roadHeight); - ctx.stroke(); - - // Right edge - ctx.beginPath(); - ctx.moveTo(rightTop, 0); - ctx.lineTo(rightBottom, roadHeight); - ctx.stroke(); - } - } - // Left Speedometer Gauge Canvas { id: speedGauge @@ -108,7 +68,7 @@ ApplicationWindow { anchors.left: parent.left anchors.leftMargin: 20 - property real angle: 0.75 * Math.PI // Initial angle for the arc + property real angle: 0.75 * Math.PI onPaint: { var ctx = getContext("2d"); @@ -189,7 +149,7 @@ ApplicationWindow { // Draw Battery Arc based on battery value var arcStartAngle = 0.75 * Math.PI; // Start at 270 degrees (left) - var arcEndAngle = arcStartAngle + (Math.PI * batteryValue / 500); // Map batteryValue to an arc from 0 to 180 degrees + var arcEndAngle = arcStartAngle + (Math.PI * canBusHandler.battery / 500); // Map batteryValue to an arc from 0 to 180 degrees var arcGradient = ctx.createLinearGradient(0, 0, width, height); arcGradient.addColorStop(0, "#ffcc00"); // Yellow arc for battery status arcGradient.addColorStop(1, "#e0b100"); @@ -203,7 +163,7 @@ ApplicationWindow { ctx.font = "36px Arial"; ctx.fillStyle = "white"; ctx.textAlign = "center"; - ctx.fillText(batteryValue + " km", width / 2, height / 2); + ctx.fillText(canBusHandler.battery + " km", width / 2, height / 2); // Label ctx.font = "18px Arial"; @@ -217,7 +177,7 @@ ApplicationWindow { target: batteryGauge property: "angle" from: batteryGauge.angle - to: 0.75 * Math.PI + (Math.PI * batteryValue / 500) + to: 0.75 * Math.PI + (Math.PI * canBusHandler.battery / 500) duration: 1000 // 1 second transition for smoother effect easing.type: Easing.InOutQuad // Smoother easing running: true From 6876fab5aa90d2bc3d39dd36ea0bb8d1d7f855f6 Mon Sep 17 00:00:00 2001 From: Rui Pires Date: Tue, 7 Jan 2025 10:13:43 +0000 Subject: [PATCH 2/2] Refactor CANBusHandler and QML integration; update clang-format path and improve formatting --- .vscode/settings.json | 2 +- include/CANBusHandler.hpp | 13 +++--- src/CANBusHandler.cpp | 38 +++++++++------- src/Main.qml | 93 ++++----------------------------------- src/main.cpp | 22 ++++----- 5 files changed, 51 insertions(+), 117 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 37cb614..f02b29a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "editor.defaultFormatter": "xaver.clang-format", "editor.formatOnSave": true }, - "clang-format.executable": "C:\\Program Files\\LLVM\\bin\\clang-format.exe", + "clang-format.executable": "/opt/homebrew/bin/clang-format", "C_Cpp.codeAnalysis.clangTidy.enabled": true, "C_Cpp.codeAnalysis.clangTidy.path": "C:\\Program Files\\LLVM\\bin\\clang-tidy.exe" } \ No newline at end of file diff --git a/include/CANBusHandler.hpp b/include/CANBusHandler.hpp index b46a8a2..0fb3df9 100644 --- a/include/CANBusHandler.hpp +++ b/include/CANBusHandler.hpp @@ -7,10 +7,11 @@ class CANBusHandler : public QObject { Q_OBJECT Q_PROPERTY(int speed READ getSpeed WRITE setSpeed NOTIFY speedChanged) - Q_PROPERTY(int battery READ getBattery WRITE setBattery NOTIFY batteryChanged) + Q_PROPERTY( + int battery READ getBattery WRITE setBattery NOTIFY batteryChanged) -public: - explicit CANBusHandler(QObject *parent = nullptr); + public: + explicit CANBusHandler(QObject* parent = nullptr); ~CANBusHandler(); int getSpeed() const; @@ -18,14 +19,14 @@ class CANBusHandler : public QObject int getBattery() const; void setBattery(int battery); -signals: + signals: void speedChanged(int speed); void batteryChanged(int battery); -private slots: + private slots: void readFrames(); -private: + private: int canSocket; int m_speed; int m_battery; diff --git a/src/CANBusHandler.cpp b/src/CANBusHandler.cpp index fd1bac5..23fb595 100644 --- a/src/CANBusHandler.cpp +++ b/src/CANBusHandler.cpp @@ -9,17 +9,15 @@ #include #include "../include/CANBusHandler.hpp" -CANBusHandler::CANBusHandler(QObject *parent) - : QObject(parent), - canSocket(-1), - m_speed(0), - m_battery(0) +CANBusHandler::CANBusHandler(QObject* parent) + : QObject(parent), canSocket(-1), m_speed(0), m_battery(0) { struct ifreq ifr; struct sockaddr_can addr; canSocket = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if (canSocket < 0) { + if (canSocket < 0) + { qWarning() << "Cannot create CAN socket!"; return; } @@ -27,9 +25,10 @@ CANBusHandler::CANBusHandler(QObject *parent) strcpy(ifr.ifr_name, "can0"); ioctl(canSocket, SIOCGIFINDEX, &ifr); - addr.can_family = AF_CAN; + addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; - if (bind(canSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (bind(canSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { qWarning() << "Cannot bind CAN socket!"; close(canSocket); return; @@ -38,15 +37,16 @@ CANBusHandler::CANBusHandler(QObject *parent) qDebug() << "CAN socket bound to can0 interface successfully."; // Set up a timer to periodically read frames - QTimer *timer = new QTimer(this); + QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [this]() { readFrames(); }); timer->start(10); // Adjust the interval as needed } CANBusHandler::~CANBusHandler() { - if (canSocket >= 0) { - close(canSocket); // Close the CAN socket + if (canSocket >= 0) + { + close(canSocket); // Close the CAN socket } } @@ -57,7 +57,8 @@ int CANBusHandler::getSpeed() const void CANBusHandler::setSpeed(int speed) { - if (m_speed != speed) { + if (m_speed != speed) + { m_speed = speed; emit speedChanged(m_speed); } @@ -70,7 +71,8 @@ int CANBusHandler::getBattery() const void CANBusHandler::setBattery(int battery) { - if (m_battery != battery) { + if (m_battery != battery) + { m_battery = battery; emit batteryChanged(m_battery); } @@ -81,12 +83,14 @@ void CANBusHandler::readFrames() struct can_frame frame; int nbytes = read(canSocket, &frame, sizeof(struct can_frame)); - if (nbytes < 0) { + if (nbytes < 0) + { qWarning() << "Error reading CAN frame!"; return; } - if (frame.can_id == 0x01) { + if (frame.can_id == 0x01) + { int speed; memcpy(&speed, frame.data, sizeof(int)); @@ -94,7 +98,9 @@ void CANBusHandler::readFrames() // qDebug() << "Speed:" << speed; // Print the speed value setSpeed(speed); - } else if (frame.can_id == 0x02) { + } + else if (frame.can_id == 0x02) + { int battery; memcpy(&battery, frame.data, sizeof(int)); diff --git a/src/Main.qml b/src/Main.qml index b38add3..e7f8c01 100644 --- a/src/Main.qml +++ b/src/Main.qml @@ -1,6 +1,6 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 -import com.example.canbus 1.0 +import canbus 1.0 ApplicationWindow { visible: true @@ -17,6 +17,7 @@ ApplicationWindow { Rectangle { anchors.fill: parent + // Background Gradient Canvas { anchors.fill: parent onPaint: { @@ -68,58 +69,20 @@ ApplicationWindow { anchors.left: parent.left anchors.leftMargin: 20 - property real angle: 0.75 * Math.PI - onPaint: { var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); - // Background gradient for the circular gauge - var bgGradient = ctx.createRadialGradient(width / 2, height / 2, 50, width / 2, height / 2, 120); - bgGradient.addColorStop(0, "#001848"); - bgGradient.addColorStop(1, "#002060"); - ctx.fillStyle = bgGradient; - ctx.beginPath(); - ctx.arc(width / 2, height / 2, 120, 0, 2 * Math.PI); - ctx.fill(); - - // Draw Speed Arc based on speed value - var arcStartAngle = 0.75 * Math.PI; // Start at 270 degrees (left) - var arcEndAngle = arcStartAngle + (Math.PI * canBusHandler.speed / 180); // Map speedValue to an arc from 0 to 180 degrees - var arcGradient = ctx.createLinearGradient(0, 0, width, height); - arcGradient.addColorStop(0, "#00ff00"); - arcGradient.addColorStop(1, "#004000"); - ctx.lineWidth = 15; - ctx.strokeStyle = arcGradient; - ctx.beginPath(); - ctx.arc(width / 2, height / 2, 100, arcStartAngle, arcEndAngle); - ctx.stroke(); - // Speed Value - ctx.font = "36px Arial"; + ctx.font = "36px sans-serif"; ctx.fillStyle = "white"; ctx.textAlign = "center"; - ctx.fillText(canBusHandler.speed + " km/h", width / 2, height / 2); + ctx.fillText(canBusHandler.speed, width / 2, height / 2); // Label - ctx.font = "18px Arial"; + ctx.font = "18px sans-serif"; ctx.fillStyle = "lightgray"; - ctx.fillText("km/h", width / 2, height / 2 + 40); - } - - // Speed angle animation with smoother transition - NumberAnimation { - id: speedAnimation - target: speedGauge - property: "angle" - from: speedGauge.angle - to: 0.75 * Math.PI + (Math.PI * canBusHandler.speed / 180) - duration: 1000 // 1 second transition for smoother effect - easing.type: Easing.InOutQuad // Smoother easing - running: true - onRunningChanged: { - speedGauge.requestPaint(); // Trigger repaint when animation is running - } + ctx.fillText("Speed", width / 2, height / 2 + 40); } } @@ -132,59 +95,21 @@ ApplicationWindow { anchors.right: parent.right anchors.rightMargin: 20 - property real angle: 0.75 * Math.PI // Initial angle for the arc - onPaint: { var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); - // Background gradient for the circular gauge - var bgGradient = ctx.createRadialGradient(width / 2, height / 2, 50, width / 2, height / 2, 120); - bgGradient.addColorStop(0, "#001848"); - bgGradient.addColorStop(1, "#002060"); - ctx.fillStyle = bgGradient; - ctx.beginPath(); - ctx.arc(width / 2, height / 2, 120, 0, 2 * Math.PI); - ctx.fill(); - - // Draw Battery Arc based on battery value - var arcStartAngle = 0.75 * Math.PI; // Start at 270 degrees (left) - var arcEndAngle = arcStartAngle + (Math.PI * canBusHandler.battery / 500); // Map batteryValue to an arc from 0 to 180 degrees - var arcGradient = ctx.createLinearGradient(0, 0, width, height); - arcGradient.addColorStop(0, "#ffcc00"); // Yellow arc for battery status - arcGradient.addColorStop(1, "#e0b100"); - ctx.lineWidth = 15; - ctx.strokeStyle = arcGradient; - ctx.beginPath(); - ctx.arc(width / 2, height / 2, 100, arcStartAngle, arcEndAngle); - ctx.stroke(); - // Battery Value - ctx.font = "36px Arial"; + ctx.font = "36px sans-serif"; ctx.fillStyle = "white"; ctx.textAlign = "center"; - ctx.fillText(canBusHandler.battery + " km", width / 2, height / 2); + ctx.fillText(canBusHandler.battery + " %", width / 2, height / 2); // Label - ctx.font = "18px Arial"; + ctx.font = "18px sans-serif"; ctx.fillStyle = "lightgray"; ctx.fillText("Battery", width / 2, height / 2 + 40); } - - // Battery angle animation with smoother transition - NumberAnimation { - id: batteryAnimation - target: batteryGauge - property: "angle" - from: batteryGauge.angle - to: 0.75 * Math.PI + (Math.PI * canBusHandler.battery / 500) - duration: 1000 // 1 second transition for smoother effect - easing.type: Easing.InOutQuad // Smoother easing - running: true - onRunningChanged: { - batteryGauge.requestPaint(); // Trigger repaint when animation is running - } - } } } } diff --git a/src/main.cpp b/src/main.cpp index bb5e44a..925258e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,29 +1,31 @@ #include #include #include -#include +#include #include #include "../include/CANBusHandler.hpp" -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { QGuiApplication app(argc, argv); - // Set up the QML engine QQmlApplicationEngine engine; - qmlRegisterType("com.example.canbus", 1, 0, "CANBusHandler"); - // Create and expose the CAN bus handler to QML + qmlRegisterType("canbus", 1, 0, "CANBusHandler"); + CANBusHandler canBusHandler; engine.rootContext()->setContextProperty("canBusHandler", &canBusHandler); // Load QML file const QUrl url(QStringLiteral("qrc:/Main.qml")); - QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, - &app, [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, Qt::QueuedConnection); + QObject::connect( + &engine, &QQmlApplicationEngine::objectCreated, &app, + [url](QObject* obj, const QUrl& objUrl) + { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, + Qt::QueuedConnection); engine.load(url); return app.exec();