Merge remote-tracking branch 'upstream/master' into big-test-models

pull/29291/head
Shane Smiskol 3 years ago
commit 9fc84f5844
  1. 2
      opendbc
  2. 2
      panda
  3. 3
      selfdrive/boardd/boardd.cc
  4. 3
      selfdrive/boardd/panda.cc
  5. 4
      selfdrive/car/gm/carstate.py
  6. 2
      selfdrive/controls/controlsd.py
  7. 3
      selfdrive/controls/lib/events.py
  8. 2
      selfdrive/debug/test_fw_query_on_routes.py
  9. 2
      selfdrive/modeld/models/supercombo.onnx
  10. 2
      selfdrive/test/process_replay/model_replay_ref_commit
  11. 2
      selfdrive/test/process_replay/ref_commit
  12. 1
      selfdrive/test/setup_device_ci.sh
  13. 9
      selfdrive/thermald/power_monitoring.py
  14. 63
      selfdrive/thermald/tests/test_power_monitoring.py
  15. 3
      selfdrive/thermald/thermald.py
  16. 29
      tools/cabana/binaryview.cc
  17. 4
      tools/cabana/binaryview.h
  18. 2
      tools/cabana/cabana.cc
  19. 4
      tools/cabana/chartswidget.cc
  20. 1
      tools/cabana/chartswidget.h
  21. 3
      tools/cabana/detailwidget.cc
  22. 17
      tools/cabana/historylog.cc
  23. 1
      tools/cabana/historylog.h
  24. 8
      tools/cabana/settings.cc
  25. 2
      tools/cabana/settings.h
  26. 2
      tools/cabana/signaledit.cc

@ -1 +1 @@
Subproject commit 296f190000a2e71408e207ba21a2257cc853ec15
Subproject commit 871e054d9a94629d92c22fe89cae71af5b0d3823

@ -1 +1 @@
Subproject commit 2e90b6f308dc09bf1734f6cb5cc990cb8149486d
Subproject commit c075050d5df70570cfadd8c0d7507f25fe67d247

@ -528,9 +528,6 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) {
cnt++;
sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update?
// Other pandas don't have fan/IR to control
if (panda->hw_type != cereal::PandaState::PandaType::UNO && panda->hw_type != cereal::PandaState::PandaType::DOS) continue;
if (sm.updated("deviceState") && !no_fan_control) {
// Fan speed
uint16_t fan_speed = sm["deviceState"].getDeviceState().getFanSpeedPercentDesired();

@ -24,7 +24,8 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) {
(hw_type != cereal::PandaState::PandaType::GREY_PANDA));
has_rtc = (hw_type == cereal::PandaState::PandaType::UNO) ||
(hw_type == cereal::PandaState::PandaType::DOS);
(hw_type == cereal::PandaState::PandaType::DOS) ||
(hw_type == cereal::PandaState::PandaType::TRES);
return;
}

@ -100,6 +100,9 @@ class CarState(CarStateBase):
if self.CP.networkLocation == NetworkLocation.fwdCamera:
ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS
ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
# openpilot controls nonAdaptive when not pcmCruise
if self.CP.pcmCruise:
ret.cruiseState.nonAdaptive = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCruiseState"] not in (2, 3)
return ret
@ -112,6 +115,7 @@ class CarState(CarStateBase):
("AEBCmdActive", "AEBCmd"),
("RollingCounter", "ASCMLKASteeringCmd"),
("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"),
("ACCCruiseState", "ASCMActiveCruiseControlStatus"),
]
checks += [
("AEBCmd", 10),

@ -275,7 +275,7 @@ class Controls:
# self.events.add(EventName.highCpuUsage)
# Alert if fan isn't spinning for 5 seconds
if self.sm['peripheralState'].pandaType == PandaType.dos:
if self.sm['peripheralState'].pandaType != log.PandaState.PandaType.unknown:
if self.sm['peripheralState'].fanSpeedRpm == 0 and self.sm['deviceState'].fanSpeedPercentDesired > 50:
if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 5.0:
self.events.add(EventName.fanMalfunction)

@ -250,10 +250,9 @@ def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messag
def no_gps_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
gps_integrated = sm['peripheralState'].pandaType in (log.PandaState.PandaType.uno, log.PandaState.PandaType.dos)
return Alert(
"Poor GPS reception",
"Hardware malfunctioning if sky is visible" if gps_integrated else "Check GPS antenna placement",
"Hardware malfunctioning if sky is visible",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=300.)

@ -68,7 +68,7 @@ if __name__ == "__main__":
CP = None
for msg in lr:
if msg.which() == "pandaStates":
if msg.pandaStates[0].pandaType not in ('uno', 'blackPanda', 'dos'):
if msg.pandaStates[0].pandaType in ('unknown', 'whitePanda', 'greyPanda', 'pedal'):
print("wrong panda type")
break

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c73998c9f428380dd2282b451de6011469b717498ae83578cbf7aa95948910f7
oid sha256:db746e3753de84367595fedd089c2bd41b06bd401ea28e085663533d0e63d74b
size 45962473

@ -1 +1 @@
ca02aa240e629920ad88a6510213cb0a153af92b
30efb4238327d723e17a3bda7e7c19c18f8a3b18

@ -1 +1 @@
959e63af52d9efdb62156cab4b773f88b154fd75
ff508a46616a1a3d66e8d1154d123ffd11025003

@ -29,6 +29,7 @@ sudo abctl --set_success
# patch sshd config
sudo mount -o rw,remount /
echo tici-$(cat /proc/cmdline | sed -e 's/^.*androidboot.serialno=//' -e 's/ .*$//') | sudo tee /etc/hostname
sudo sed -i "s,/data/params/d/GithubSshKeys,/usr/comma/setup_keys," /etc/ssh/sshd_config
sudo systemctl daemon-reload
sudo systemctl restart ssh

@ -1,7 +1,6 @@
import threading
from typing import Optional
from cereal import log
from common.params import Params, put_nonblocking
from common.realtime import sec_since_boot
from system.hardware import HARDWARE
@ -39,12 +38,12 @@ class PowerMonitoring:
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh))
# Calculation tick
def calculate(self, peripheralState, ignition):
def calculate(self, voltage: Optional[int], ignition: bool):
try:
now = sec_since_boot()
# If peripheralState is None, we're probably not in a car, so we don't care
if peripheralState is None or peripheralState.pandaType == log.PandaState.PandaType.unknown:
if voltage is None:
with self.integration_lock:
self.last_measurement_time = None
self.next_pulsed_measurement_time = None
@ -52,8 +51,8 @@ class PowerMonitoring:
return
# Low-pass battery voltage
self.car_voltage_instant_mV = peripheralState.voltage
self.car_voltage_mV = ((peripheralState.voltage * CAR_VOLTAGE_LOW_PASS_K) + (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K)))
self.car_voltage_instant_mV = voltage
self.car_voltage_mV = ((voltage * CAR_VOLTAGE_LOW_PASS_K) + (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K)))
statlog.gauge("car_voltage", self.car_voltage_mV / 1e3)
# Cap the car battery power and save it in a param every 10-ish seconds

@ -1,10 +1,7 @@
#!/usr/bin/env python3
import unittest
from unittest.mock import patch
from parameterized import parameterized
from cereal import log
import cereal.messaging as messaging
from common.params import Params
params = Params()
@ -21,7 +18,8 @@ with patch("common.realtime.sec_since_boot", new=mock_sec_since_boot):
CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING
TEST_DURATION_S = 50
ALL_PANDA_TYPES = [(log.PandaState.PandaType.dos,)]
GOOD_VOLTAGE = 12 * 1e3
VOLTAGE_BELOW_PAUSE_CHARGING = (VBATT_PAUSE_CHARGING - 1) * 1e3
def pm_patch(name, value, constant=False):
if constant:
@ -34,12 +32,6 @@ class TestPowerMonitoring(unittest.TestCase):
params.remove("CarBatteryCapacity")
params.remove("DisablePowerDown")
def mock_peripheralState(self, hw_type, car_voltage=12):
ps = messaging.new_message('peripheralState').peripheralState
ps.pandaType = hw_type
ps.voltage = car_voltage * 1e3
return ps
# Test to see that it doesn't do anything when pandaState is None
def test_pandaState_present(self):
pm = PowerMonitoring()
@ -49,75 +41,68 @@ class TestPowerMonitoring(unittest.TestCase):
self.assertEqual(pm.get_car_battery_capacity(), (CAR_BATTERY_CAPACITY_uWh / 10))
# Test to see that it doesn't integrate offroad when ignition is True
@parameterized.expand(ALL_PANDA_TYPES)
def test_offroad_ignition(self, hw_type):
def test_offroad_ignition(self):
pm = PowerMonitoring()
for _ in range(10):
pm.calculate(self.mock_peripheralState(hw_type), True)
pm.calculate(GOOD_VOLTAGE, True)
self.assertEqual(pm.get_power_used(), 0)
# Test to see that it integrates with discharging battery
@parameterized.expand(ALL_PANDA_TYPES)
def test_offroad_integration_discharging(self, hw_type):
def test_offroad_integration_discharging(self):
POWER_DRAW = 4
with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
pm = PowerMonitoring()
for _ in range(TEST_DURATION_S + 1):
pm.calculate(self.mock_peripheralState(hw_type), False)
pm.calculate(GOOD_VOLTAGE, False)
expected_power_usage = ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6)
self.assertLess(abs(pm.get_power_used() - expected_power_usage), 10)
# Test to check positive integration of car_battery_capacity
@parameterized.expand(ALL_PANDA_TYPES)
def test_car_battery_integration_onroad(self, hw_type):
def test_car_battery_integration_onroad(self):
POWER_DRAW = 4
with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = 0
for _ in range(TEST_DURATION_S + 1):
pm.calculate(self.mock_peripheralState(hw_type), True)
pm.calculate(GOOD_VOLTAGE, True)
expected_capacity = ((TEST_DURATION_S/3600) * CAR_CHARGING_RATE_W * 1e6)
self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10)
# Test to check positive integration upper limit
@parameterized.expand(ALL_PANDA_TYPES)
def test_car_battery_integration_upper_limit(self, hw_type):
def test_car_battery_integration_upper_limit(self):
POWER_DRAW = 4
with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - 1000
for _ in range(TEST_DURATION_S + 1):
pm.calculate(self.mock_peripheralState(hw_type), True)
pm.calculate(GOOD_VOLTAGE, True)
estimated_capacity = CAR_BATTERY_CAPACITY_uWh + (CAR_CHARGING_RATE_W / 3600 * 1e6)
self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10)
# Test to check negative integration of car_battery_capacity
@parameterized.expand(ALL_PANDA_TYPES)
def test_car_battery_integration_offroad(self, hw_type):
def test_car_battery_integration_offroad(self):
POWER_DRAW = 4
with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh
for _ in range(TEST_DURATION_S + 1):
pm.calculate(self.mock_peripheralState(hw_type), False)
pm.calculate(GOOD_VOLTAGE, False)
expected_capacity = CAR_BATTERY_CAPACITY_uWh - ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6)
self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10)
# Test to check negative integration lower limit
@parameterized.expand(ALL_PANDA_TYPES)
def test_car_battery_integration_lower_limit(self, hw_type):
def test_car_battery_integration_lower_limit(self):
POWER_DRAW = 4
with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = 1000
for _ in range(TEST_DURATION_S + 1):
pm.calculate(self.mock_peripheralState(hw_type), False)
pm.calculate(GOOD_VOLTAGE, False)
estimated_capacity = 0 - ((1/3600) * POWER_DRAW * 1e6)
self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10)
# Test to check policy of stopping charging after MAX_TIME_OFFROAD_S
@parameterized.expand(ALL_PANDA_TYPES)
def test_max_time_offroad(self, hw_type):
def test_max_time_offroad(self):
MOCKED_MAX_OFFROAD_TIME = 3600
POWER_DRAW = 0 # To stop shutting down for other reasons
with pm_patch("MAX_TIME_OFFROAD_S", MOCKED_MAX_OFFROAD_TIME, constant=True), pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
@ -125,25 +110,22 @@ class TestPowerMonitoring(unittest.TestCase):
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh
start_time = ssb
ignition = False
peripheralState = self.mock_peripheralState(hw_type)
while ssb <= start_time + MOCKED_MAX_OFFROAD_TIME:
pm.calculate(peripheralState, ignition)
pm.calculate(GOOD_VOLTAGE, ignition)
if (ssb - start_time) % 1000 == 0 and ssb < start_time + MOCKED_MAX_OFFROAD_TIME:
self.assertFalse(pm.should_shutdown(ignition, True, start_time, False))
self.assertTrue(pm.should_shutdown(ignition, True, start_time, False))
# Test to check policy of stopping charging when the car voltage is too low
@parameterized.expand(ALL_PANDA_TYPES)
def test_car_voltage(self, hw_type):
def test_car_voltage(self):
POWER_DRAW = 0 # To stop shutting down for other reasons
TEST_TIME = 100
with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh
ignition = False
peripheralState = self.mock_peripheralState(hw_type, car_voltage=(VBATT_PAUSE_CHARGING - 1))
for i in range(TEST_TIME):
pm.calculate(peripheralState, ignition)
pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition)
if i % 10 == 0:
self.assertEqual(pm.should_shutdown(ignition, True, ssb, True), (pm.car_voltage_mV < VBATT_PAUSE_CHARGING*1e3))
self.assertTrue(pm.should_shutdown(ignition, True, ssb, True))
@ -157,9 +139,8 @@ class TestPowerMonitoring(unittest.TestCase):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh
ignition = False
peripheralState = self.mock_peripheralState(log.PandaState.PandaType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1))
for i in range(TEST_TIME):
pm.calculate(peripheralState, ignition)
pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition)
if i % 10 == 0:
self.assertFalse(pm.should_shutdown(ignition, True, ssb, False))
self.assertFalse(pm.should_shutdown(ignition, True, ssb, False))
@ -172,9 +153,8 @@ class TestPowerMonitoring(unittest.TestCase):
pm = PowerMonitoring()
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh
ignition = True
peripheralState = self.mock_peripheralState(log.PandaState.PandaType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1))
for i in range(TEST_TIME):
pm.calculate(peripheralState, ignition)
pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition)
if i % 10 == 0:
self.assertFalse(pm.should_shutdown(ignition, True, ssb, False))
self.assertFalse(pm.should_shutdown(ignition, True, ssb, False))
@ -188,9 +168,8 @@ class TestPowerMonitoring(unittest.TestCase):
pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh
ignition = False
peripheralState = self.mock_peripheralState(log.PandaState.PandaType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1))
for i in range(TEST_TIME):
pm.calculate(peripheralState, ignition)
pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition)
if i % 10 == 0:
self.assertFalse(pm.should_shutdown(ignition, False, ssb, False))
self.assertFalse(pm.should_shutdown(ignition, False, ssb, False))

@ -347,7 +347,8 @@ def thermald_thread(end_event, hw_queue):
off_ts = sec_since_boot()
# Offroad power monitoring
power_monitor.calculate(peripheralState, onroad_conditions["ignition"])
voltage = None if peripheralState.pandaType == log.PandaState.PandaType.unknown else peripheralState.voltage
power_monitor.calculate(voltage, onroad_conditions["ignition"])
msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used()
msg.deviceState.carBatteryCapacityUwh = max(0, power_monitor.get_car_battery_capacity())
current_power_draw = HARDWARE.get_current_power_draw()

@ -1,6 +1,5 @@
#include "tools/cabana/binaryview.h"
#include <QApplication>
#include <QFontDatabase>
#include <QHeaderView>
#include <QMouseEvent>
@ -74,14 +73,18 @@ void BinaryView::mousePressEvent(QMouseEvent *event) {
event->accept();
}
void BinaryView::mouseMoveEvent(QMouseEvent *event) {
if (auto index = indexAt(event->pos()); index.isValid()) {
void BinaryView::highlightPosition(const QPoint &pos) {
if (auto index = indexAt(viewport()->mapFromGlobal(pos)); index.isValid()) {
auto item = (BinaryViewModel::Item *)index.internalPointer();
const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back();
highlight(sig);
sig ? QToolTip::showText(event->globalPos(), sig->name.c_str(), this, rect())
sig ? QToolTip::showText(pos, sig->name.c_str(), this, rect())
: QToolTip::hideText();
}
}
void BinaryView::mouseMoveEvent(QMouseEvent *event) {
highlightPosition(event->globalPos());
QTableView::mouseMoveEvent(event);
}
@ -116,6 +119,7 @@ void BinaryView::setMessage(const QString &message_id) {
anchor_index = QModelIndex();
resize_sig = nullptr;
hovered_sig = nullptr;
highlightPosition(QCursor::pos());
updateState();
}
@ -232,19 +236,18 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
BinaryView *bin_view = (BinaryView *)parent();
painter->save();
// background
if (option.state & QStyle::State_Selected) {
if (index.column() == 8) {
painter->setFont(hex_font);
} else if (option.state & QStyle::State_Selected) {
painter->fillRect(option.rect, selection_color);
} else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) {
painter->setPen(QApplication::style()->standardPalette().color(QPalette::BrightText));
} else if (!item->sigs.isEmpty() && (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig))) {
painter->fillRect(option.rect, item->bg_color);
painter->setPen(item->sigs.contains(bin_view->hovered_sig)
? QApplication::style()->standardPalette().color(QPalette::BrightText)
: Qt::black);
}
// text
if (index.column() == 8) { // hex column
painter->setFont(hex_font);
} else if (option.state & QStyle::State_Selected || (!bin_view->resize_sig && item->sigs.contains(bin_view->hovered_sig))) {
painter->setPen(Qt::white);
}
painter->drawText(option.rect, Qt::AlignCenter, item->val);
if (item->is_msb || item->is_lsb) {
painter->setFont(small_font);

@ -1,5 +1,6 @@
#pragma once
#include <QApplication>
#include <QList>
#include <QSet>
#include <QStyledItemDelegate>
@ -41,7 +42,7 @@ public:
}
struct Item {
QColor bg_color = QColor(Qt::white);
QColor bg_color = QApplication::style()->standardPalette().color(QPalette::Base);
bool is_msb = false;
bool is_lsb = false;
QString val = "0";
@ -79,6 +80,7 @@ private:
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void leaveEvent(QEvent *event) override;
void highlightPosition(const QPoint &pt);
QModelIndex anchor_index;
BinaryViewModel *model;

@ -1,6 +1,5 @@
#include <QApplication>
#include <QCommandLineParser>
#include <QStyleFactory>
#include "selfdrive/ui/qt/util.h"
#include "tools/cabana/mainwin.h"
@ -8,7 +7,6 @@
int main(int argc, char *argv[]) {
initApp(argc, argv);
QApplication app(argc, argv);
app.setStyle(QStyleFactory::create("Fusion"));
QCommandLineParser cmd_parser;
cmd_parser.addHelpOption();

@ -40,6 +40,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
main_layout->addWidget(charts_scroll);
use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value();
QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll);
QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged);
QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState);
@ -125,6 +127,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo
ChartView *chart = merge && charts.size() > 0 ? charts.back() : nullptr;
if (!chart) {
chart = new ChartView(this);
chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight);
chart->setEventsRange(display_range);
auto range = is_zoomed ? zoomed_range : display_range;
chart->setDisplayRange(range.first, range.second);
@ -288,7 +291,6 @@ void ChartView::updateTitle() {
void ChartView::updateFromSettings() {
setFixedHeight(settings.chart_height);
chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark);
}
void ChartView::setEventsRange(const std::pair<double, double> &range) {

@ -112,4 +112,5 @@ private:
std::pair<double, double> event_range;
std::pair<double, double> display_range;
std::pair<double, double> zoomed_range;
bool use_dark_theme = false;
};

@ -25,7 +25,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
// tabbar
tabbar = new QTabBar(this);
tabbar->setTabsClosable(true);
tabbar->setDrawBase(false);
tabbar->setUsesScrollButtons(true);
tabbar->setAutoHide(true);
tabbar->setContextMenuPolicy(Qt::CustomContextMenu);
@ -57,7 +56,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget);
warning_hlayout->setContentsMargins(0, 0, 0, 0);
QLabel *warning_icon = new QLabel(this);
warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning));
warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning).scaledToWidth(24, Qt::SmoothTransformation));
warning_hlayout->addWidget(warning_icon, 0, Qt::AlignTop);
warning_label = new QLabel(this);
warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft);

@ -1,6 +1,7 @@
#include "tools/cabana/historylog.h"
#include <QFontDatabase>
#include <QPainter>
// HistoryLogModel
@ -44,6 +45,8 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i
return has_signal ? QString::fromStdString(get_signal(dbc_msg, section - 1).name).replace('_', ' ') : "Data";
} else if (role == Qt::BackgroundRole && section > 0 && has_signal) {
return QBrush(QColor(getColor(section - 1)));
} else if (role == Qt::ForegroundRole && section > 0 && has_signal) {
return QBrush(Qt::black);
}
}
return {};
@ -73,7 +76,18 @@ void HistoryLogModel::updateState() {
QSize HeaderView::sectionSizeFromContents(int logicalIndex) const {
const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString();
const QRect rect = fontMetrics().boundingRect(QRect(0, 0, sectionSize(logicalIndex), 1000), defaultAlignment(), text);
return rect.size() + QSize{10, 5};
return rect.size() + QSize{10, 6};
}
void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const {
auto bg_role = model()->headerData(logicalIndex, Qt::Horizontal, Qt::BackgroundRole);
if (bg_role.isValid()) {
QPen pen(model()->headerData(logicalIndex, Qt::Horizontal, Qt::ForegroundRole).value<QBrush>(), 1);
painter->setPen(pen);
painter->fillRect(rect, bg_role.value<QBrush>());
}
QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString();
painter->drawText(rect.adjusted(5, 3, 5, 3), defaultAlignment(), text);
}
// HistoryLog
@ -88,7 +102,6 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) {
verticalHeader()->setVisible(false);
setFrameShape(QFrame::NoFrame);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }");
}
int HistoryLog::sizeHintForColumn(int column) const {

@ -10,6 +10,7 @@ class HeaderView : public QHeaderView {
public:
HeaderView(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {}
QSize sectionSizeFromContents(int logicalIndex) const override;
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
};
class HistoryLogModel : public QAbstractTableModel {

@ -18,7 +18,6 @@ void Settings::save() {
s.setValue("log_size", can_msg_log_size);
s.setValue("cached_segment", cached_segment_limit);
s.setValue("chart_height", chart_height);
s.setValue("chart_theme", chart_theme);
s.setValue("max_chart_x_range", max_chart_x_range);
s.setValue("last_dir", last_dir);
s.setValue("splitter_state", splitter_state);
@ -30,7 +29,6 @@ void Settings::load() {
can_msg_log_size = s.value("log_size", 50).toInt();
cached_segment_limit = s.value("cached_segment", 3).toInt();
chart_height = s.value("chart_height", 200).toInt();
chart_theme = s.value("chart_theme", 0).toInt();
max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt();
last_dir = s.value("last_dir", QDir::homePath()).toString();
splitter_state = s.value("splitter_state").toByteArray();
@ -72,11 +70,6 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) {
chart_height->setValue(settings.chart_height);
form_layout->addRow(tr("Chart height"), chart_height);
chart_theme = new QComboBox();
chart_theme->addItems({"Light", "Dark"});
chart_theme->setCurrentIndex(settings.chart_theme == 1 ? 1 : 0);
form_layout->addRow(tr("Chart theme"), chart_theme);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
form_layout->addRow(buttonBox);
@ -90,7 +83,6 @@ void SettingsDlg::save() {
settings.can_msg_log_size = log_size->value();
settings.cached_segment_limit = cached_segment->value();
settings.chart_height = chart_height->value();
settings.chart_theme = chart_theme->currentIndex();
settings.max_chart_x_range = max_chart_x_range->value() * 60;
settings.save();
accept();

@ -17,7 +17,6 @@ public:
int can_msg_log_size = 50;
int cached_segment_limit = 3;
int chart_height = 200;
int chart_theme = 0;
int max_chart_x_range = 3 * 60; // 3 minutes
QString last_dir;
QByteArray splitter_state;
@ -36,7 +35,6 @@ public:
QSpinBox *log_size ;
QSpinBox *cached_segment;
QSpinBox *chart_height;
QComboBox *chart_theme;
QSpinBox *max_chart_x_range;
};

@ -137,7 +137,7 @@ void SignalEdit::setSignal(const QString &message_id, const Signal *signal) {
updateForm(msg_id == message_id && form->isVisible());
msg_id = message_id;
color_label->setText(QString::number(form_idx + 1));
color_label->setStyleSheet(QString("background-color:%1").arg(getColor(form_idx)));
color_label->setStyleSheet(QString("color:black; background-color:%2").arg(getColor(form_idx)));
title->setText(sig->name.c_str());
show();
}

Loading…
Cancel
Save