openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

204 lines
7.0 KiB

#include "tools/cabana/signaledit.h"
#include <QDoubleValidator>
#include <QFormLayout>
#include <QGuiApplication>
#include <QHBoxLayout>
#include <QVBoxLayout>
// SignalForm
SignalForm::SignalForm(QWidget *parent) : QWidget(parent) {
QFormLayout *form_layout = new QFormLayout(this);
name = new QLineEdit();
name->setValidator(new QRegExpValidator(QRegExp("^(\\w+)"), name));
form_layout->addRow(tr("Name"), name);
size = new QSpinBox();
size->setMinimum(1);
form_layout->addRow(tr("Size"), size);
endianness = new QComboBox();
endianness->addItems({"Little", "Big"});
form_layout->addRow(tr("Endianness"), endianness);
form_layout->addRow(tr("lsb"), lsb = new QLabel());
form_layout->addRow(tr("msb"), msb = new QLabel());
sign = new QComboBox();
sign->addItems({"Signed", "Unsigned"});
form_layout->addRow(tr("sign"), sign);
auto double_validator = new QDoubleValidator(this);
factor = new QLineEdit();
factor->setValidator(double_validator);
form_layout->addRow(tr("Factor"), factor);
offset = new QLineEdit();
offset->setValidator(double_validator);
form_layout->addRow(tr("Offset"), offset);
// TODO: parse the following parameters in opendbc
unit = new QLineEdit();
form_layout->addRow(tr("Unit"), unit);
comment = new QLineEdit();
form_layout->addRow(tr("Comment"), comment);
min_val = new QLineEdit();
min_val->setValidator(double_validator);
form_layout->addRow(tr("Minimum value"), min_val);
max_val = new QLineEdit();
max_val->setValidator(double_validator);
form_layout->addRow(tr("Maximum value"), max_val);
val_desc = new QLineEdit();
form_layout->addRow(tr("Value descriptions"), val_desc);
QObject::connect(name, &QLineEdit::textEdited, this, &SignalForm::changed);
QObject::connect(factor, &QLineEdit::textEdited, this, &SignalForm::changed);
QObject::connect(offset, &QLineEdit::textEdited, this, &SignalForm::changed);
QObject::connect(sign, SIGNAL(activated(int)), SIGNAL(changed()));
QObject::connect(endianness, SIGNAL(activated(int)), SIGNAL(changed()));
QObject::connect(size, SIGNAL(valueChanged(int)), SIGNAL(changed()));
}
// SignalEdit
SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0, 0, 0, 0);
main_layout->setSpacing(0);
// title bar
auto title_bar = new QWidget(this);
title_bar->setFixedHeight(32);
QHBoxLayout *title_layout = new QHBoxLayout(title_bar);
title_layout->setContentsMargins(0, 0, 0, 0);
title_bar->setStyleSheet("QToolButton {width:15px;height:15px;font-size:15px}");
color_label = new QLabel(this);
color_label->setFixedWidth(25);
color_label->setContentsMargins(5, 0, 0, 0);
title_layout->addWidget(color_label);
icon = new QLabel(this);
title_layout->addWidget(icon);
title = new ElidedLabel(this);
title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
title_layout->addWidget(title);
plot_btn = new QToolButton(this);
plot_btn->setText("📈");
plot_btn->setCheckable(true);
plot_btn->setAutoRaise(true);
title_layout->addWidget(plot_btn);
auto remove_btn = new QToolButton(this);
remove_btn->setAutoRaise(true);
remove_btn->setText("x");
remove_btn->setToolTip(tr("Remove signal"));
title_layout->addWidget(remove_btn);
main_layout->addWidget(title_bar);
// signal form
form = new SignalForm(this);
form->setVisible(false);
main_layout->addWidget(form);
// bottom line
QFrame *hline = new QFrame();
hline->setFrameShape(QFrame::HLine);
hline->setFrameShadow(QFrame::Sunken);
main_layout->addWidget(hline);
save_timer = new QTimer(this);
save_timer->setInterval(300);
save_timer->setSingleShot(true);
save_timer->callOnTimeout(this, &SignalEdit::saveSignal);
QObject::connect(title, &ElidedLabel::clicked, [this]() { emit showFormClicked(sig); });
QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) {
emit showChart(msg_id, sig, checked, QGuiApplication::keyboardModifiers() & Qt::ShiftModifier);
});
QObject::connect(remove_btn, &QToolButton::clicked, [this]() { emit remove(sig); });
QObject::connect(form, &SignalForm::changed, [this]() { save_timer->start(); });
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
void SignalEdit::setSignal(const QString &message_id, const Signal *signal) {
sig = signal;
updateForm(msg_id == message_id && form->isVisible());
msg_id = message_id;
color_label->setText(QString::number(form_idx + 1));
color_label->setStyleSheet(QString("color:black; background-color:%2").arg(getColor(form_idx)));
title->setText(sig->name.c_str());
show();
}
void SignalEdit::saveSignal() {
if (!sig || !form->changed_by_user) return;
Signal s = *sig;
s.name = form->name->text().toStdString();
s.size = form->size->text().toInt();
s.offset = form->offset->text().toDouble();
s.factor = form->factor->text().toDouble();
s.is_signed = form->sign->currentIndex() == 0;
bool little_endian = form->endianness->currentIndex() == 0;
if (little_endian != s.is_little_endian) {
int start = std::floor(s.start_bit / 8);
if (little_endian) {
int end = std::floor((s.start_bit - s.size + 1) / 8);
s.start_bit = start == end ? s.start_bit - s.size + 1 : bigEndianStartBitsIndex(s.start_bit);
} else {
int end = std::floor((s.start_bit + s.size - 1) / 8);
s.start_bit = start == end ? s.start_bit + s.size - 1 : bigEndianBitIndex(s.start_bit);
}
s.is_little_endian = little_endian;
}
if (s.is_little_endian) {
s.lsb = s.start_bit;
s.msb = s.start_bit + s.size - 1;
} else {
s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1);
s.msb = s.start_bit;
}
if (s != *sig)
emit save(this->sig, s);
}
void SignalEdit::setChartOpened(bool opened) {
plot_btn->setToolTip(opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened chart"));
plot_btn->setChecked(opened);
}
void SignalEdit::updateForm(bool visible) {
if (visible && sig) {
form->changed_by_user = false;
if (form->name->text() != sig->name.c_str()) {
form->name->setText(sig->name.c_str());
}
form->endianness->setCurrentIndex(sig->is_little_endian ? 0 : 1);
form->sign->setCurrentIndex(sig->is_signed ? 0 : 1);
form->factor->setText(QString::number(sig->factor));
form->offset->setText(QString::number(sig->offset));
form->msb->setText(QString::number(sig->msb));
form->lsb->setText(QString::number(sig->lsb));
form->size->setValue(sig->size);
form->changed_by_user = true;
}
form->setVisible(visible);
icon->setText(visible ? "" : "> ");
}
void SignalEdit::signalHovered(const Signal *s) {
auto color = sig == s ? "white" : "black";
color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(color).arg(getColor(form_idx)));
}
void SignalEdit::enterEvent(QEvent *event) {
emit highlight(sig);
QWidget::enterEvent(event);
}
void SignalEdit::leaveEvent(QEvent *event) {
emit highlight(nullptr);
QWidget::leaveEvent(event);
}