Skip to content
This repository was archived by the owner on Oct 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Remote Debug on Raspberry Pi",
"type": "cppdbg",
"request": "launch",
"program": "/Users/ruipedropires/SEA:ME/QTonRaspberryPi/HelloQt6", // Be sure that this is the path where binary is exist on host
"stopAtEntry": false,
"cwd": "/Users/ruipedropires/SEA:ME/QTonRaspberryPi", // should be host path not target
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb-multiarch", // gdb-multiacrh should be used not gdb
"miDebuggerServerAddress": "192.168.178.21:2000", // Replace with your Raspberry Pi's IP and the gdbserver port
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "", // Optional: Specify a task to run before debugging starts
"postDebugTask": "" // Optional: Specify a task to run after debugging ends
}
]
}
29 changes: 29 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build with Docker",
"type": "shell",
"command": "./helperTasks.sh build_docker_image",
"group": "build"
},
{
"label": "Copy binary from tmp container",
"type": "shell",
"command": "./helperTasks.sh create_binary_and_copy",
"group": "build"
},
{
"label": "Send binary to Rasp",
"type": "shell",
"command": "./helperTasks.sh send_binary_to_rasp",
"group": "build"
},
{
"label": "Run gdbserver on Rasp",
"type": "shell",
"command": "./helperTasks.sh run_gdb_server_on_rasp",
"group": "build"
}
]
}
74 changes: 27 additions & 47 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,47 +1,27 @@
cmake_minimum_required(VERSION 3.16)

project(Speedometer VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)

qt_standard_project_setup(REQUIRES 6.5)

qt_add_executable(appSpeedometer
./src/main.cpp
)

qt_add_qml_module(appSpeedometer
URI Speedometer
VERSION 1.0
QML_FILES
./src/Main.qml
)

# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(appSpeedometer PROPERTIES
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appSpeedometer
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)

target_link_libraries(appSpeedometer
PRIVATE
Qt6::Quick
Qt6::Core
Qt6::Gui
Qt6::Qml
Qt6::Network
)

include(GNUInstallDirs)
install(TARGETS appSpeedometer
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
cmake_minimum_required(VERSION 3.5)

project(HelloQt6 LANGUAGES CXX)
message("CMAKE_SYSROOT " ${CMAKE_SYSROOT})
message("CMAKE_LIBRARY_ARCHITECTURE " ${CMAKE_LIBRARY_ARCHITECTURE})
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 COMPONENTS Core Quick DBus SerialBus REQUIRED)

set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wl,-rpath-link, ${CMAKE_SYSROOT}/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} -L${CMAKE_SYSROOT}/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wl,-rpath-link,${CMAKE_SYSROOT}/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} -L${CMAKE_SYSROOT}/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
# Enable automatic MOC, UIC, and RCC processing
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

qt_add_resources(QT_RESOURCES ./src/resources.qrc)

add_executable(speedometer ${QT_RESOURCES}
./src/main.cpp
./src/CANBusHandler.cpp
./include/CANBusHandler.hpp
)

target_link_libraries(speedometer -lm -ldl Qt6::Core Qt6::DBus Qt6::Quick Qt6::SerialBus)

Empty file removed include/.keep
Empty file.
29 changes: 29 additions & 0 deletions include/CANBusHandler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef CANBUSHANDLER_HPP
#define CANBUSHANDLER_HPP

#include <QtCore/QObject>

class CANBusHandler : public QObject
{
Q_OBJECT
Q_PROPERTY(int speed READ getSpeed WRITE setSpeed NOTIFY speedChanged)

public:
explicit CANBusHandler(QObject *parent = nullptr);
~CANBusHandler();

int getSpeed() const;
void setSpeed(int speed);

signals:
void speedChanged(int speed);

private slots:
void readFrames();

private:
int canSocket; // File descriptor for the CAN socket
int m_speed; // Member variable for the speed
};

#endif // CANBUSHANDLER_HPP
87 changes: 87 additions & 0 deletions src/CANBusHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "../include/CANBusHandler.hpp"

CANBusHandler::CANBusHandler(QObject *parent)
: QObject(parent),
canSocket(-1),
m_speed(0)
{
struct ifreq ifr;
struct sockaddr_can addr;

canSocket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (canSocket < 0) {
qWarning() << "Cannot create CAN socket!";
return;
}

strcpy(ifr.ifr_name, "can0");
ioctl(canSocket, SIOCGIFINDEX, &ifr);

addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(canSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
qWarning() << "Cannot bind CAN socket!";
close(canSocket);
return;
}

qDebug() << "CAN socket bound to can0 interface successfully.";

// Set up a timer to periodically read frames
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
canSocket = -1;
}
}

int CANBusHandler::getSpeed() const
{
return m_speed;
}

void CANBusHandler::setSpeed(int speed)
{
if (m_speed != speed) {
m_speed = speed;
emit speedChanged(m_speed);
}
}

void CANBusHandler::readFrames()
{
struct can_frame frame;
int nbytes = read(canSocket, &frame, sizeof(struct can_frame));

if (nbytes < 0) {
qWarning() << "Error reading CAN frame!";
return;
}

if (frame.can_id == 0x01) {
int speed;
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;
}
}
46 changes: 10 additions & 36 deletions src/Main.qml
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import com.example.canbus 1.0

ApplicationWindow {
visible: true
width: 1000
height: 400
width: Screen.width
height: Screen.height
title: "Instrument Cluster with Smooth Transitions"

// Initial values declared here
property int speedValue: 0
property int batteryValue: 284
CANBusHandler {
id: canBusHandler
onSpeedChanged: speedGauge.requestPaint()
}

Rectangle {
anchors.fill: parent
Expand Down Expand Up @@ -97,8 +99,6 @@ ApplicationWindow {
}
}



// Left Speedometer Gauge
Canvas {
id: speedGauge
Expand All @@ -125,7 +125,7 @@ ApplicationWindow {

// Draw Speed Arc based on speed value
var arcStartAngle = 0.75 * Math.PI; // Start at 270 degrees (left)
var arcEndAngle = arcStartAngle + (Math.PI * speedValue / 180); // Map speedValue to an arc from 0 to 180 degrees
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");
Expand All @@ -139,7 +139,7 @@ ApplicationWindow {
ctx.font = "36px Arial";
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.fillText(speedValue + " km/h", width / 2, height / 2);
ctx.fillText(canBusHandler.speed + " km/h", width / 2, height / 2);

// Label
ctx.font = "18px Arial";
Expand All @@ -153,7 +153,7 @@ ApplicationWindow {
target: speedGauge
property: "angle"
from: speedGauge.angle
to: 0.75 * Math.PI + (Math.PI * speedValue / 180)
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
Expand Down Expand Up @@ -226,31 +226,5 @@ ApplicationWindow {
}
}
}

// Dynamic Speed Timer
Timer {
id: speedTimer
interval: 500 // 500 milliseconds for more frequent updates
repeat: true
running: true
onTriggered: {
speedValue = Math.floor(Math.random() * 180); // Simulate random speed between 0 and 180 km/h
speedAnimation.stop(); // Stop any ongoing animation
speedAnimation.start(); // Start a new animation
}
}

// Dynamic Battery Timer
Timer {
id: batteryTimer
interval: 1000 // 1 second for more frequent updates
repeat: true
running: true
onTriggered: {
batteryValue = Math.floor(Math.random() * 500); // Simulate random battery value between 0 and 500 km
batteryAnimation.stop(); // Stop any ongoing animation
batteryAnimation.start(); // Start a new animation
}
}
}
}
26 changes: 19 additions & 7 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtCore/QObject>
#include <QQmlContext>
#include <QtSerialBus/QCanBus>
#include "../include/CANBusHandler.hpp"

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

// Set up the QML engine
QQmlApplicationEngine engine;
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.loadFromModule("Speedometer", "Main");

qmlRegisterType<CANBusHandler>("com.example.canbus", 1, 0, "CANBusHandler");
// Create and expose the CAN bus handler to QML
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);
engine.load(url);

return app.exec();
}
5 changes: 5 additions & 0 deletions src/resources.qrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>Main.qml</file>
</qresource>
</RCC>
Loading