Skip to content
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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.5
0.4.6
13 changes: 10 additions & 3 deletions src/driver/GenericCanSetupPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,10 @@ void GenericCanSetupPage::fillSamplePointsForBitrate(CanInterface *intf, unsigne
void GenericCanSetupPage::fillFdBitrate(CanInterface *intf, unsigned selectedBitrate)
{
QList<uint32_t> fdBitrates;
unsigned currentArbBitrate = ui->cbBitrate->currentData().toUInt();

for (CanTiming t : intf->getAvailableBitrates()) {
if (1) {
//if (t.getBitrate() == selectedBitrate) {
if (t.getBitrate() == currentArbBitrate) {
if (t.isCanFD() && !fdBitrates.contains(t.getBitrateFD())) {
fdBitrates.append(t.getBitrateFD());
}
Expand All @@ -272,7 +273,13 @@ void GenericCanSetupPage::fillFdBitrate(CanInterface *intf, unsigned selectedBit
for (uint32_t fd_br : fdBitrates) {
ui->cbBitrateFD->addItem(QString::number(fd_br), fd_br);
}
ui->cbBitrateFD->setCurrentText(QString::number(selectedBitrate));

int idx = ui->cbBitrateFD->findData(selectedBitrate);
if (idx >= 0) {
ui->cbBitrateFD->setCurrentIndex(idx);
} else if (ui->cbBitrateFD->count() > 0) {
ui->cbBitrateFD->setCurrentIndex(0);
}
}

void GenericCanSetupPage::fillSamplePointsForFdBitrate(CanInterface *intf, unsigned selectedBitrate, unsigned selectedSamplePoint)
Expand Down
77 changes: 58 additions & 19 deletions src/driver/SocketCanDriver/SocketCanInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ QList<CanTiming> SocketCanInterface::getAvailableBitrates()
}
}

// Add CAN FD Data Bitrates if supported
if (supportsCanFD()) {
QList<unsigned> fdBitrates({500000, 1000000, 2000000, 4000000, 5000000, 8000000});
foreach (unsigned br, bitrates) {
foreach (unsigned fdbr, fdBitrates) {
// For simplicity, we add FD variants of common arbitration bitrates
retval << CanTiming(i++, br, fdbr, 800, 800);
}
}
}

return retval;
}

Expand Down Expand Up @@ -148,28 +159,52 @@ void SocketCanInterface::applyConfig(const MeasurementInterface &mi)
return;
}

log_info(QString("calling canifconfig to reconfigure interface %1").arg(getName()));
QStringList sl = buildCanIfConfigArgs(mi);
sl.prepend("canifconfig");
log_info(sl.join(" "));
QString cmd;
QStringList args;

QProcess canIfConfig;
canIfConfig.start("canifconfig", buildCanIfConfigArgs(mi));
if (!canIfConfig.waitForFinished()) {
log_error(QString("timeout waiting for canifconfig"));
return;
// Use ip link if CAN FD is requested, as it's the standard way now
if (mi.isCanFD()) {
log_info(QString("calling ip link to reconfigure interface %1 (CAN FD)").arg(getName()));

// First bring interface down
QProcess::execute("ip", {"link", "set", getName(), "down"});

cmd = "ip";
args << "link" << "set" << getName() << "up" << "type" << "can";
args << "bitrate" << QString::number(mi.bitrate());
args << "sample-point" << QString::number((float)mi.samplePoint()/1000.0, 'f', 3);
args << "dbitrate" << QString::number(mi.fdBitrate());
args << "dsample-point" << QString::number((float)mi.fdSamplePoint()/1000.0, 'f', 3);
args << "fd" << "on";

if (mi.doAutoRestart()) {
args << "restart-ms" << QString::number(mi.autoRestartMs());
}

} else {
log_info(QString("calling canifconfig to reconfigure interface %1").arg(getName()));
cmd = "canifconfig";
args = buildCanIfConfigArgs(mi);
}

if (canIfConfig.exitStatus()!=QProcess::NormalExit) {
log_error(QString("canifconfig crashed"));
log_info(cmd + " " + args.join(" "));

QProcess proc;
proc.start(cmd, args);
if (!proc.waitForFinished()) {
log_error(QString("timeout waiting for %1").arg(cmd));
return;
}

if (canIfConfig.exitCode() != 0) {
log_error(QString("canifconfig failed: ") + QString(canIfConfig.readAllStandardError()).trimmed());
if (proc.exitStatus()!=QProcess::NormalExit) {
log_error(QString("%1 crashed").arg(cmd));
return;
}

if (proc.exitCode() != 0) {
log_error(QString("%1 failed: ").arg(cmd) + QString(proc.readAllStandardError()).trimmed());
return;
}
}

#if (LIBNL_CURRENT<=216)
Expand Down Expand Up @@ -482,7 +517,7 @@ void SocketCanInterface::sendMessage(const CanMessage &msg) {

bool SocketCanInterface::readMessage(QList<CanMessage> &msglist, unsigned int timeout_ms) {

struct can_frame frame;
struct canfd_frame frame;
struct timespec ts_rcv;
struct timeval tv_rcv;
struct timeval timeout;
Expand All @@ -498,8 +533,8 @@ bool SocketCanInterface::readMessage(QList<CanMessage> &msglist, unsigned int ti

int rv = select(_fd+1, &fdset, NULL, NULL, &timeout);
if (rv > 0) {

if (::read(_fd, &frame, sizeof(struct can_frame)) < 0) {
int nbytes = ::read(_fd, &frame, sizeof(struct canfd_frame));
if (nbytes < 0) {
return false;
}

Expand All @@ -521,15 +556,19 @@ bool SocketCanInterface::readMessage(QList<CanMessage> &msglist, unsigned int ti
msg.setTimestamp(tv_rcv.tv_sec, tv_rcv.tv_usec);
}

msg.setId(frame.can_id);
msg.setId(frame.can_id & CAN_EFF_MASK);
msg.setExtended((frame.can_id & CAN_EFF_FLAG)!=0);
msg.setRTR((frame.can_id & CAN_RTR_FLAG)!=0);
msg.setErrorFrame((frame.can_id & CAN_ERR_FLAG)!=0);
msg.setInterfaceId(getId());

uint8_t len = frame.can_dlc;
if (len > 8) { len = 8; }
bool isFD = (nbytes == CANFD_MTU);
msg.setFD(isFD);
if (isFD) {
msg.setBRS((frame.flags & CANFD_BRS) != 0);
}

uint8_t len = frame.len;
msg.setLength(len);
for (int i=0; i<len; i++) {
msg.setByte(i, frame.data[i]);
Expand Down
92 changes: 88 additions & 4 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ MainWindow::MainWindow(QWidget *parent) :

QLabel* versionLabel = new QLabel(this);
versionLabel->setText(QString("v%1").arg(CANGAROO_VERSION_STR));
versionLabel->setStyleSheet("padding-right: 15px; color: #000000; font-weight: bold; font-size: 11px;");
versionLabel->setStyleSheet("padding-right: 15px; font-weight: bold; font-size: 11px;");
statusBar()->addPermanentWidget(versionLabel);

QIcon icon(":/assets/cangaroo.png");
Expand Down Expand Up @@ -113,6 +113,29 @@ MainWindow::MainWindow(QWidget *parent) :

_showSetupDialog_first = false;

// Theme Toggle Button in top-left (actually after spacer, so top-right)
_btnThemeToggle = new QPushButton(this);
_btnThemeToggle->setFixedSize(32, 32);
_btnThemeToggle->setCursor(Qt::PointingHandCursor);
_btnThemeToggle->setToolTip(tr("Toggle Dark/Light Mode"));
_btnThemeToggle->setFlat(true);
_btnThemeToggle->setStyleSheet(
"QPushButton {"
" font-size: 18px;"
" border-radius: 16px;"
" background: transparent;"
"}"
"QPushButton:hover {"
" background: rgba(0, 0, 0, 0.1);"
"}"
);

ui->horizontalLayoutControls->addWidget(_btnThemeToggle);
connect(_btnThemeToggle, &QPushButton::clicked, this, &MainWindow::onThemeToggleClicked);

// Default to Light
setTheme("light");

setStyleSheet(
"QMainWindow::separator {"
" background: transparent;"
Expand Down Expand Up @@ -210,10 +233,7 @@ Backend &MainWindow::backend()
QMainWindow *MainWindow::createTab(QString title)
{
QMainWindow *mm = new QMainWindow(this);
QPalette pal(palette());
pal.setColor(QPalette::Window, QColor(0xeb, 0xeb, 0xeb));
mm->setAutoFillBackground(true);
mm->setPalette(pal);
ui->mainTabs->addTab(mm, title);
return mm;
}
Expand Down Expand Up @@ -798,3 +818,67 @@ void MainWindow::on_actionGenerator_View_triggered()
addTxGeneratorWidget();
}

void MainWindow::onThemeToggleClicked()
{
if (_currentTheme == "light") {
setTheme("dark");
} else {
setTheme("light");
}
}

void MainWindow::setTheme(const QString &theme)
{
_currentTheme = theme;

if (theme == "light") {
qApp->setPalette(style()->standardPalette());
qApp->setStyleSheet("");
if (_btnThemeToggle) {
_btnThemeToggle->setText("🌙");
_btnThemeToggle->setStyleSheet(
"QPushButton {"
" font-size: 18px;"
" border-radius: 16px;"
" background: transparent;"
"}"
"QPushButton:hover {"
" background: rgba(0, 0, 0, 0.1);"
"}"
);
}
} else if (theme == "dark") {
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, QColor(53, 53, 53));
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, QColor(25, 25, 25));
darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, QColor(53, 53, 53));
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::BrightText, Qt::red);
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(darkPalette);
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");

if (_btnThemeToggle) {
_btnThemeToggle->setText("☀️");
_btnThemeToggle->setStyleSheet(
"QPushButton {"
" font-size: 18px;"
" border-radius: 16px;"
" background: transparent;"
" color: white;"
"}"
"QPushButton:hover {"
" background: rgba(255, 255, 255, 0.1);"
"}"
);
}
}
}

8 changes: 8 additions & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <QMainWindow>
#include <QList>
#include <core/Backend.h>
#include <QPushButton>

QT_BEGIN_NAMESPACE
class QAction;
Expand All @@ -50,6 +51,8 @@ class MainWindow : public QMainWindow
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

void setTheme(const QString &theme);

protected:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;

Expand Down Expand Up @@ -81,6 +84,11 @@ private slots:
void on_actionCan_Status_View_triggered();
void on_actionGenerator_View_triggered();
void on_actionReport_Issue_triggered();
void onThemeToggleClicked();

private:
QString _currentTheme;
QPushButton *_btnThemeToggle;

private:
Ui::MainWindow *ui;
Expand Down
2 changes: 1 addition & 1 deletion src/version.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef VERSION_H
#define VERSION_H
#define CANGAROO_VERSION_STR "0.4.5"
#define CANGAROO_VERSION_STR "0.4.6"
#endif // VERSION_H
12 changes: 8 additions & 4 deletions src/window/GraphWindow/GaugeVisualization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ void GaugeWidget::paintEvent(QPaintEvent *)
painter.scale(side / 200.0, side / 200.0);

// Draw background ring (Ghost Bar)
painter.setPen(QPen(QColor(240, 240, 240), 18, Qt::SolidLine, Qt::RoundCap));
QColor ghostColor = palette().color(QPalette::WindowText);
ghostColor.setAlpha(30);
painter.setPen(QPen(ghostColor, 18, Qt::SolidLine, Qt::RoundCap));
painter.drawArc(-85, -85, 170, 170, -30 * 16, 240 * 16);

// Active Radial Bar (The colored arc)
Expand All @@ -57,7 +59,7 @@ void GaugeWidget::paintEvent(QPaintEvent *)
painter.drawArc(-85, -85, 170, 170, 210 * 16 - span, span);

// Text: Value (Primary Readout, Centered)
painter.setPen(QColor(33, 37, 41)); // High contrast dark gray
painter.setPen(palette().color(QPalette::WindowText));
QFont font = painter.font();
font.setPixelSize(40);
font.setBold(true);
Expand All @@ -68,14 +70,16 @@ void GaugeWidget::paintEvent(QPaintEvent *)
font.setPixelSize(16);
font.setBold(false);
painter.setFont(font);
painter.setPen(QColor(108, 117, 125));
QColor unitColor = palette().color(QPalette::WindowText);
unitColor.setAlpha(160);
painter.setPen(unitColor);
painter.drawText(QRect(-70, 15, 140, 20), Qt::AlignCenter, _unit);

// Text: Name (Bottom Center)
font.setPixelSize(13);
font.setBold(true);
painter.setFont(font);
painter.setPen(Qt::black);
painter.setPen(palette().color(QPalette::WindowText));
painter.drawText(QRect(-100, 75, 200, 25), Qt::AlignCenter, _name);
}

Expand Down
7 changes: 4 additions & 3 deletions src/window/GraphWindow/ScatterVisualization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,20 @@ ScatterVisualization::ScatterVisualization(QWidget *parent, Backend &backend)

// Create cursor line
_cursorLine = new QGraphicsLineItem(_chart);
QPen cursorPen(Qt::gray, 1, Qt::DashLine);
QPen cursorPen(palette().color(QPalette::WindowText), 1, Qt::DashLine);
_cursorLine->setPen(cursorPen);
_cursorLine->setZValue(1000);
_cursorLine->hide();

// Create Tooltip Box
_tooltipBox = new QGraphicsRectItem(_chart);
_tooltipBox->setBrush(QBrush(Qt::white));
_tooltipBox->setPen(QPen(Qt::lightGray, 1));
_tooltipBox->setBrush(QBrush(palette().color(QPalette::ToolTipBase)));
_tooltipBox->setPen(QPen(palette().color(QPalette::ToolTipText), 1));
_tooltipBox->setZValue(2000);
_tooltipBox->hide();

_tooltipText = new QGraphicsTextItem(_tooltipBox);
_tooltipText->setDefaultTextColor(palette().color(QPalette::ToolTipText));
_tooltipText->setTextInteractionFlags(Qt::NoTextInteraction);
_tooltipText->setZValue(2001);

Expand Down
Loading