Merge remote-tracking branch 'upstream/master' into random-test-segs

pull/30653/head
Shane Smiskol 1 year ago
commit d393bfdcf8
  1. 5
      Jenkinsfile
  2. 2
      cereal
  3. 5
      selfdrive/athena/athenad.py
  4. 25
      selfdrive/athena/tests/test_athenad_ping.py
  5. 15
      selfdrive/ui/soundd.py
  6. 9
      system/camerad/cameras/camera_common.cc
  7. 3
      system/camerad/cameras/camera_common.h
  8. 46
      system/camerad/cameras/camera_qcom2.cc
  9. 5
      system/camerad/cameras/camera_qcom2.h
  10. 1
      system/camerad/sensors/ar0231.cc
  11. 1
      system/camerad/sensors/ox03c10.cc
  12. 1
      system/camerad/sensors/sensor.h
  13. 19
      system/micd.py
  14. 2
      teleoprtc_repo
  15. 4
      tools/cabana/dbc/dbc.h
  16. 9
      tools/cabana/dbc/dbcfile.cc
  17. 6
      tools/cabana/dbc/dbcfile.h
  18. 25
      tools/cabana/dbc/dbcmanager.cc
  19. 7
      tools/cabana/dbc/dbcmanager.h
  20. 26
      tools/cabana/mainwin.cc
  21. 1
      tools/cabana/mainwin.h
  22. 4
      tools/cabana/tests/test_cabana.cc
  23. 1
      tools/cabana/util.cc
  24. 2
      tools/sim/lib/camerad.py
  25. 8
      tools/sim/lib/simulated_sensors.py

5
Jenkinsfile vendored

@ -234,9 +234,8 @@ node {
'car tests': { 'car tests': {
pcStage("car tests") { pcStage("car tests") {
sh label: "build", script: "selfdrive/manager/build.py" sh label: "build", script: "selfdrive/manager/build.py"
sh label: "test_models.py", script: "INTERNAL_SEG_CNT=250 INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt FILEREADER_CACHE=1 \ sh label: "run car tests", script: "cd selfdrive/car/tests && MAX_EXAMPLES=100 INTERNAL_SEG_CNT=250 FILEREADER_CACHE=1 \
pytest selfdrive/car/tests/test_models.py" INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt pytest test_models.py test_car_interfaces.py"
sh label: "test_car_interfaces.py", script: "MAX_EXAMPLES=100 pytest selfdrive/car/tests/test_car_interfaces.py"
} }
}, },

@ -1 +1 @@
Subproject commit 4fb8352484c4ef074bee775975c0d1d1e8f57a78 Subproject commit a3a6e4969e58875f7cdfc9e6cc6b1af3ee2392b5

@ -41,9 +41,6 @@ from openpilot.system.version import get_commit, get_origin, get_short_branch, g
from openpilot.system.hardware.hw import Paths from openpilot.system.hardware.hw import Paths
# TODO: use socket constant when mypy recognizes this as a valid attribute
TCP_USER_TIMEOUT = 18
ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai') ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai')
HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4")) HANDLER_THREADS = int(os.getenv('HANDLER_THREADS', "4"))
LOCAL_PORT_WHITELIST = {8022} LOCAL_PORT_WHITELIST = {8022}
@ -760,7 +757,7 @@ def ws_manage(ws: WebSocket, end_event: threading.Event) -> None:
if onroad != onroad_prev: if onroad != onroad_prev:
onroad_prev = onroad onroad_prev = onroad
sock.setsockopt(socket.IPPROTO_TCP, TCP_USER_TIMEOUT, 16000 if onroad else 0) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT, 16000 if onroad else 0)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7 if onroad else 30) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7 if onroad else 30)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 7 if onroad else 10) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 7 if onroad else 10)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 2 if onroad else 3) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 2 if onroad else 3)

@ -3,8 +3,8 @@ import subprocess
import threading import threading
import time import time
import unittest import unittest
from typing import Callable, cast, Optional from typing import cast, Optional
from unittest.mock import MagicMock from unittest import mock
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.timeout import Timeout from openpilot.common.timeout import Timeout
@ -27,8 +27,6 @@ class TestAthenadPing(unittest.TestCase):
athenad: threading.Thread athenad: threading.Thread
exit_event: threading.Event exit_event: threading.Event
_create_connection: Callable
def _get_ping_time(self) -> Optional[str]: def _get_ping_time(self) -> Optional[str]:
return cast(Optional[str], self.params.get("LastAthenaPingTime", encoding="utf-8")) return cast(Optional[str], self.params.get("LastAthenaPingTime", encoding="utf-8"))
@ -38,15 +36,9 @@ class TestAthenadPing(unittest.TestCase):
def _received_ping(self) -> bool: def _received_ping(self) -> bool:
return self._get_ping_time() is not None return self._get_ping_time() is not None
@classmethod
def setUpClass(cls) -> None:
cls._create_connection = athenad.create_connection
athenad.create_connection = MagicMock(wraps=cls._create_connection)
@classmethod @classmethod
def tearDownClass(cls) -> None: def tearDownClass(cls) -> None:
wifi_radio(True) wifi_radio(True)
athenad.create_connection = cls._create_connection
def setUp(self) -> None: def setUp(self) -> None:
self.params = Params() self.params = Params()
@ -58,19 +50,18 @@ class TestAthenadPing(unittest.TestCase):
self.exit_event = threading.Event() self.exit_event = threading.Event()
self.athenad = threading.Thread(target=athenad.main, args=(self.exit_event,)) self.athenad = threading.Thread(target=athenad.main, args=(self.exit_event,))
athenad.create_connection.reset_mock()
def tearDown(self) -> None: def tearDown(self) -> None:
if self.athenad.is_alive(): if self.athenad.is_alive():
self.exit_event.set() self.exit_event.set()
self.athenad.join() self.athenad.join()
def assertTimeout(self, reconnect_time: float) -> None: @mock.patch('openpilot.selfdrive.athena.athenad.create_connection', autospec=True)
def assertTimeout(self, reconnect_time: float, mock_create_connection: mock.MagicMock) -> None:
self.athenad.start() self.athenad.start()
time.sleep(1) time.sleep(1)
athenad.create_connection.assert_called_once() mock_create_connection.assert_called_once()
athenad.create_connection.reset_mock() mock_create_connection.reset_mock()
# check normal behaviour # check normal behaviour
with self.subTest("Wi-Fi: receives ping"), Timeout(70, "no ping received"): with self.subTest("Wi-Fi: receives ping"), Timeout(70, "no ping received"):
@ -78,7 +69,7 @@ class TestAthenadPing(unittest.TestCase):
time.sleep(0.1) time.sleep(0.1)
print("ping received") print("ping received")
athenad.create_connection.assert_not_called() mock_create_connection.assert_not_called()
# websocket should attempt reconnect after short time # websocket should attempt reconnect after short time
with self.subTest("LTE: attempt reconnect"): with self.subTest("LTE: attempt reconnect"):
@ -86,7 +77,7 @@ class TestAthenadPing(unittest.TestCase):
print("waiting for reconnect attempt") print("waiting for reconnect attempt")
start_time = time.monotonic() start_time = time.monotonic()
with Timeout(reconnect_time, "no reconnect attempt"): with Timeout(reconnect_time, "no reconnect attempt"):
while not athenad.create_connection.called: while not mock_create_connection.called:
time.sleep(0.1) time.sleep(0.1)
print(f"reconnect attempt after {time.monotonic() - start_time:.2f}s") print(f"reconnect attempt after {time.monotonic() - start_time:.2f}s")

@ -10,9 +10,9 @@ from openpilot.common.basedir import BASEDIR
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.system import micd from openpilot.system import micd
from openpilot.system.hardware import TICI
from openpilot.common.realtime import Ratekeeper from openpilot.common.realtime import Ratekeeper
from openpilot.system.hardware import PC
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
SAMPLE_RATE = 48000 SAMPLE_RATE = 48000
@ -130,16 +130,13 @@ class Soundd:
# sounddevice must be imported after forking processes # sounddevice must be imported after forking processes
import sounddevice as sd import sounddevice as sd
rk = Ratekeeper(20) if TICI:
micd.wait_for_devices(sd) # wait for alsa to be initialized on device
sm = messaging.SubMaster(['controlsState', 'microphone']) with sd.OutputStream(channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream:
rk = Ratekeeper(20)
sm = messaging.SubMaster(['controlsState', 'microphone'])
if PC:
device = None
else:
device = "sdm845-tavil-snd-card: - (hw:0,0)"
with sd.OutputStream(device=device, channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream:
cloudlog.info(f"soundd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}") cloudlog.info(f"soundd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}")
while True: while True:
sm.update(0) sm.update(0)

@ -36,7 +36,7 @@ public:
"-DIS_OX=%d -DCAM_NUM=%d%s", "-DIS_OX=%d -DCAM_NUM=%d%s",
ci->frame_width, ci->frame_height, ci->frame_stride, ci->frame_offset, ci->frame_width, ci->frame_height, ci->frame_stride, ci->frame_offset,
b->rgb_width, b->rgb_height, b->rgb_stride, buf_width, uv_offset, b->rgb_width, b->rgb_height, b->rgb_stride, buf_width, uv_offset,
s->camera_id==CAMERA_ID_OX03C10 ? 1 : 0, s->camera_num, s->camera_num==1 ? " -DVIGNETTING" : ""); ci->image_sensor == cereal::FrameData::ImageSensor::OX03C10, s->camera_num, s->camera_num==1 ? " -DVIGNETTING" : "");
const char *cl_file = "cameras/real_debayer.cl"; const char *cl_file = "cameras/real_debayer.cl";
cl_program prg_debayer = cl_program_from_file(context, device_id, cl_file, args); cl_program prg_debayer = cl_program_from_file(context, device_id, cl_file, args);
krnl_ = CL_CHECK_ERR(clCreateKernel(prg_debayer, "debayer10", &err)); krnl_ = CL_CHECK_ERR(clCreateKernel(prg_debayer, "debayer10", &err));
@ -154,12 +154,7 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr
const float ev = c->cur_ev[frame_data.frame_id % 3]; const float ev = c->cur_ev[frame_data.frame_id % 3];
const float perc = util::map_val(ev, c->ci->min_ev, c->ci->max_ev, 0.0f, 100.0f); const float perc = util::map_val(ev, c->ci->min_ev, c->ci->max_ev, 0.0f, 100.0f);
framed.setExposureValPercent(perc); framed.setExposureValPercent(perc);
framed.setSensor(c->ci->image_sensor);
if (c->camera_id == CAMERA_ID_AR0231) {
framed.setSensor(cereal::FrameData::ImageSensor::AR0231);
} else if (c->camera_id == CAMERA_ID_OX03C10) {
framed.setSensor(cereal::FrameData::ImageSensor::OX03C10);
}
} }
kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b) { kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b) {

@ -14,9 +14,6 @@
#include "common/swaglog.h" #include "common/swaglog.h"
#include "system/hardware/hw.h" #include "system/hardware/hw.h"
#define CAMERA_ID_AR0231 0
#define CAMERA_ID_OX03C10 1
const int YUV_BUFFER_COUNT = 20; const int YUV_BUFFER_COUNT = 20;
enum CameraType { enum CameraType {

@ -106,8 +106,6 @@ static cam_cmd_power *power_set_wait(cam_cmd_power *power, int16_t delay_ms) {
} }
int CameraState::sensors_init() { int CameraState::sensors_init() {
create_sensor();
uint32_t cam_packet_handle = 0; uint32_t cam_packet_handle = 0;
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2; int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2;
auto pkt = mm.alloc<struct cam_packet>(size, &cam_packet_handle); auto pkt = mm.alloc<struct cam_packet>(size, &cam_packet_handle);
@ -403,15 +401,7 @@ void CameraState::enqueue_req_multi(int start, int n, bool dp) {
// ******************* camera ******************* // ******************* camera *******************
void CameraState::create_sensor() { void CameraState::sensor_set_parameters() {
if (camera_id == CAMERA_ID_AR0231) {
ci = std::make_unique<AR0231>();
} else if (camera_id == CAMERA_ID_OX03C10) {
ci = std::make_unique<OX03C10>();
} else {
assert(false);
}
target_grey_fraction = 0.3; target_grey_fraction = 0.3;
dc_gain_enabled = false; dc_gain_enabled = false;
@ -436,9 +426,8 @@ void CameraState::camera_map_bufs(MultiCameraState *s) {
enqueue_req_multi(1, FRAME_BUF_COUNT, 0); enqueue_req_multi(1, FRAME_BUF_COUNT, 0);
} }
void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, int camera_id_, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type) { void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type) {
if (!enabled) return; if (!enabled) return;
camera_id = camera_id_;
LOGD("camera init %d", camera_num); LOGD("camera init %d", camera_num);
request_id_last = 0; request_id_last = 0;
@ -462,22 +451,25 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num
// init memorymanager for this camera // init memorymanager for this camera
mm.init(multi_cam_state->video0_fd); mm.init(multi_cam_state->video0_fd);
// probe the sensor
LOGD("-- Probing sensor %d", camera_num); LOGD("-- Probing sensor %d", camera_num);
camera_id = CAMERA_ID_AR0231;
ret = sensors_init(); auto init_sensor_lambda = [this](SensorInfo *sensor) {
if (ret != 0) { ci.reset(sensor);
// TODO: use build flag instead? int ret = sensors_init();
LOGD("AR0231 init failed, trying OX03C10"); if (ret == 0) {
camera_id = CAMERA_ID_OX03C10; sensor_set_parameters();
ret = sensors_init(); }
} return ret == 0;
LOGD("-- Probing sensor %d done with %d", camera_num, ret); };
if (ret != 0) {
// Try different sensors one by one until it success.
if (!init_sensor_lambda(new AR0231) &&
!init_sensor_lambda(new OX03C10)) {
LOGE("** sensor %d FAILED bringup, disabling", camera_num); LOGE("** sensor %d FAILED bringup, disabling", camera_num);
enabled = false; enabled = false;
return; return;
} }
LOGD("-- Probing sensor %d success", camera_num);
// create session // create session
struct cam_req_mgr_session_info session_info = {}; struct cam_req_mgr_session_info session_info = {};
@ -626,9 +618,9 @@ void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num
} }
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) { void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) {
s->driver_cam.camera_init(s, v, s->driver_cam.camera_id, 20, device_id, ctx, VISION_STREAM_DRIVER); s->driver_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_DRIVER);
s->road_cam.camera_init(s, v, s->road_cam.camera_id, 20, device_id, ctx, VISION_STREAM_ROAD); s->road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_ROAD);
s->wide_road_cam.camera_init(s, v, s->wide_road_cam.camera_id, 20, device_id, ctx, VISION_STREAM_WIDE_ROAD); s->wide_road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_WIDE_ROAD);
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"}); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"});
} }

@ -48,9 +48,9 @@ public:
void sensors_start(); void sensors_start();
void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled); void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled);
void create_sensor(); void sensor_set_parameters();
void camera_map_bufs(MultiCameraState *s); void camera_map_bufs(MultiCameraState *s);
void camera_init(MultiCameraState *s, VisionIpcServer *v, int camera_id, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type); void camera_init(MultiCameraState *s, VisionIpcServer *v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type);
void camera_close(); void camera_close();
int32_t session_handle; int32_t session_handle;
@ -68,7 +68,6 @@ public:
int frame_id_last; int frame_id_last;
int idx_offset; int idx_offset;
bool skipped; bool skipped;
int camera_id;
CameraBuf buf; CameraBuf buf;
MemoryManager mm; MemoryManager mm;

@ -77,6 +77,7 @@ float ar0231_parse_temp_sensor(uint16_t calib1, uint16_t calib2, uint16_t data_r
} // namespace } // namespace
AR0231::AR0231() { AR0231::AR0231() {
image_sensor = cereal::FrameData::ImageSensor::AR0231;
data_word = true; data_word = true;
frame_width = FRAME_WIDTH; frame_width = FRAME_WIDTH;
frame_height = FRAME_HEIGHT; frame_height = FRAME_HEIGHT;

@ -22,6 +22,7 @@ const uint32_t VS_TIME_MAX_OX03C10 = 34; // vs < 35
} // namespace } // namespace
OX03C10::OX03C10() { OX03C10::OX03C10() {
image_sensor = cereal::FrameData::ImageSensor::OX03C10;
data_word = false; data_word = false;
frame_width = FRAME_WIDTH; frame_width = FRAME_WIDTH;
frame_height = FRAME_HEIGHT; frame_height = FRAME_HEIGHT;

@ -23,6 +23,7 @@ public:
virtual int getSlaveAddress(int port) const { assert(0); } virtual int getSlaveAddress(int port) const { assert(0); }
virtual void processRegisters(CameraState *c, cereal::FrameData::Builder &framed) const {} virtual void processRegisters(CameraState *c, cereal::FrameData::Builder &framed) const {}
cereal::FrameData::ImageSensor image_sensor = cereal::FrameData::ImageSensor::UNKNOWN;
uint32_t frame_width, frame_height; uint32_t frame_width, frame_height;
uint32_t frame_stride; uint32_t frame_stride;
uint32_t frame_offset = 0; uint32_t frame_offset = 0;

@ -3,7 +3,9 @@ import numpy as np
from cereal import messaging from cereal import messaging
from openpilot.common.realtime import Ratekeeper from openpilot.common.realtime import Ratekeeper
from openpilot.common.retry import retry
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.system.hardware import TICI
RATE = 10 RATE = 10
FFT_SAMPLES = 4096 FFT_SAMPLES = 4096
@ -11,6 +13,18 @@ REFERENCE_SPL = 2e-5 # newtons/m^2
SAMPLE_RATE = 44100 SAMPLE_RATE = 44100
@retry(attempts=7, delay=3)
def wait_for_devices(sd):
# reload sounddevice to reinitialize portaudio
sd._terminate()
sd._initialize()
devices = sd.query_devices()
cloudlog.info(f"sounddevice available devices: {list(devices)}")
assert len(devices) > 0
def calculate_spl(measurements): def calculate_spl(measurements):
# https://www.engineeringtoolbox.com/sound-pressure-d_711.html # https://www.engineeringtoolbox.com/sound-pressure-d_711.html
sound_pressure = np.sqrt(np.mean(measurements ** 2)) # RMS of amplitudes sound_pressure = np.sqrt(np.mean(measurements ** 2)) # RMS of amplitudes
@ -81,7 +95,10 @@ class Mic:
# sounddevice must be imported after forking processes # sounddevice must be imported after forking processes
import sounddevice as sd import sounddevice as sd
with sd.InputStream(channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream: if TICI:
wait_for_devices(sd) # wait for alsa to be initialized on device
with sd.InputStream(channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream:
cloudlog.info(f"micd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}") cloudlog.info(f"micd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}")
while True: while True:
self.update() self.update()

@ -1 +1 @@
Subproject commit 8ec477868591eed9a6136a44f16428bc0468b4e9 Subproject commit 4df237c512622d3914a73f4fc15a3fc89b7f5a97

@ -1,12 +1,10 @@
#pragma once #pragma once
#include <limits> #include <limits>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <QColor> #include <QColor>
#include <QList>
#include <QMetaType> #include <QMetaType>
#include <QString> #include <QString>
@ -47,7 +45,7 @@ struct std::hash<MessageId> {
std::size_t operator()(const MessageId &k) const noexcept { return qHash(k); } std::size_t operator()(const MessageId &k) const noexcept { return qHash(k); }
}; };
typedef QList<std::pair<double, QString>> ValueDescription; typedef std::vector<std::pair<double, QString>> ValueDescription;
namespace cabana { namespace cabana {

@ -52,8 +52,7 @@ void DBCFile::cleanupAutoSaveFile() {
bool DBCFile::writeContents(const QString &fn) { bool DBCFile::writeContents(const QString &fn) {
QFile file(fn); QFile file(fn);
if (file.open(QIODevice::WriteOnly)) { if (file.open(QIODevice::WriteOnly)) {
file.write(generateDBC().toUtf8()); return file.write(generateDBC().toUtf8()) >= 0;
return true;
} }
return false; return false;
} }
@ -77,10 +76,6 @@ cabana::Msg *DBCFile::msg(const QString &name) {
return it != msgs.end() ? &(it->second) : nullptr; return it != msgs.end() ? &(it->second) : nullptr;
} }
int DBCFile::signalCount() {
return std::accumulate(msgs.cbegin(), msgs.cend(), 0, [](int &n, const auto &m) { return n + m.second.sigs.size(); });
}
void DBCFile::parse(const QString &content) { void DBCFile::parse(const QString &content) {
static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))");
static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))");
@ -226,7 +221,7 @@ QString DBCFile::generateDBC() {
if (!sig->comment.isEmpty()) { if (!sig->comment.isEmpty()) {
signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig->name).arg(sig->comment); signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig->name).arg(sig->comment);
} }
if (!sig->val_desc.isEmpty()) { if (!sig->val_desc.empty()) {
QStringList text; QStringList text;
for (auto &[val, desc] : sig->val_desc) { for (auto &[val, desc] : sig->val_desc) {
text << QString("%1 \"%2\"").arg(val).arg(desc); text << QString("%1 \"%2\"").arg(val).arg(desc);

@ -27,10 +27,8 @@ public:
cabana::Msg *msg(const QString &name); cabana::Msg *msg(const QString &name);
inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); } inline cabana::Msg *msg(const MessageId &id) { return msg(id.address); }
int signalCount(); inline QString name() const { return name_.isEmpty() ? "untitled" : name_; }
inline int msgCount() { return msgs.size(); } inline bool isEmpty() const { return msgs.empty() && name_.isEmpty(); }
inline QString name() { return name_.isEmpty() ? "untitled" : name_; }
inline bool isEmpty() { return (signalCount() == 0) && name_.isEmpty(); }
QString filename; QString filename;

@ -106,12 +106,6 @@ QString DBCManager::newSignalName(const MessageId &id) {
return m ? m->newSignalName() : ""; return m ? m->newSignalName() : "";
} }
const std::vector<uint8_t> &DBCManager::mask(const MessageId &id) {
static std::vector<uint8_t> empty_mask;
auto m = msg(id);
return m ? m->mask : empty_mask;
}
const std::map<uint32_t, cabana::Msg> &DBCManager::getMessages(uint8_t source) { const std::map<uint32_t, cabana::Msg> &DBCManager::getMessages(uint8_t source) {
static std::map<uint32_t, cabana::Msg> empty_msgs; static std::map<uint32_t, cabana::Msg> empty_msgs;
auto dbc_file = findDBCFile(source); auto dbc_file = findDBCFile(source);
@ -143,25 +137,6 @@ QStringList DBCManager::signalNames() {
return ret; return ret;
} }
int DBCManager::signalCount(const MessageId &id) {
auto m = msg(id);
return m ? m->sigs.size() : 0;
}
int DBCManager::signalCount() {
auto files = allDBCFiles();
return std::accumulate(files.cbegin(), files.cend(), 0, [](int &n, auto &f) { return n + f->signalCount(); });
}
int DBCManager::msgCount() {
auto files = allDBCFiles();
return std::accumulate(files.cbegin(), files.cend(), 0, [](int &n, auto &f) { return n + f->msgCount(); });
}
int DBCManager::dbcCount() {
return allDBCFiles().size();
}
int DBCManager::nonEmptyDBCCount() { int DBCManager::nonEmptyDBCCount() {
auto files = allDBCFiles(); auto files = allDBCFiles();
return std::count_if(files.cbegin(), files.cend(), [](auto &f) { return !f->isEmpty(); }); return std::count_if(files.cbegin(), files.cend(), [](auto &f) { return !f->isEmpty(); });

@ -4,7 +4,6 @@
#include <memory> #include <memory>
#include <map> #include <map>
#include <set> #include <set>
#include <vector>
#include "tools/cabana/dbc/dbcfile.h" #include "tools/cabana/dbc/dbcfile.h"
@ -34,17 +33,13 @@ public:
QString newMsgName(const MessageId &id); QString newMsgName(const MessageId &id);
QString newSignalName(const MessageId &id); QString newSignalName(const MessageId &id);
const std::vector<uint8_t>& mask(const MessageId &id);
const std::map<uint32_t, cabana::Msg> &getMessages(uint8_t source); const std::map<uint32_t, cabana::Msg> &getMessages(uint8_t source);
cabana::Msg *msg(const MessageId &id); cabana::Msg *msg(const MessageId &id);
cabana::Msg* msg(uint8_t source, const QString &name); cabana::Msg* msg(uint8_t source, const QString &name);
QStringList signalNames(); QStringList signalNames();
int signalCount(const MessageId &id); inline int dbcCount() { return allDBCFiles().size(); }
int signalCount();
int msgCount();
int dbcCount();
int nonEmptyDBCCount(); int nonEmptyDBCCount();
const SourceSet sources(const DBCFile *dbc_file) const; const SourceSet sources(const DBCFile *dbc_file) const;

@ -46,7 +46,6 @@ MainWindow::MainWindow() : QMainWindow() {
static auto static_main_win = this; static auto static_main_win = this;
qRegisterMetaType<uint64_t>("uint64_t"); qRegisterMetaType<uint64_t>("uint64_t");
qRegisterMetaType<SourceSet>("SourceSet"); qRegisterMetaType<SourceSet>("SourceSet");
qRegisterMetaType<ReplyMsgType>("ReplyMsgType");
installDownloadProgressHandler([](uint64_t cur, uint64_t total, bool success) { installDownloadProgressHandler([](uint64_t cur, uint64_t total, bool success) {
emit static_main_win->updateProgressBar(cur, total, success); emit static_main_win->updateProgressBar(cur, total, success);
}); });
@ -54,9 +53,7 @@ MainWindow::MainWindow() : QMainWindow() {
if (type == QtDebugMsg) std::cout << msg.toStdString() << std::endl; if (type == QtDebugMsg) std::cout << msg.toStdString() << std::endl;
emit static_main_win->showMessage(msg, 2000); emit static_main_win->showMessage(msg, 2000);
}); });
installMessageHandler([](ReplyMsgType type, const std::string msg) { installMessageHandler([](ReplyMsgType type, const std::string msg) { qInfo() << msg.c_str(); });
qInfo() << QString::fromStdString(msg);
});
setStyleSheet(QString(R"(QMainWindow::separator { setStyleSheet(QString(R"(QMainWindow::separator {
width: %1px; /* when vertical */ width: %1px; /* when vertical */
@ -329,7 +326,7 @@ void MainWindow::loadFromClipboard(SourceSet s, bool close_all) {
QString dbc_str = QGuiApplication::clipboard()->text(); QString dbc_str = QGuiApplication::clipboard()->text();
QString error; QString error;
bool ret = dbc()->open(s, "", dbc_str, &error); bool ret = dbc()->open(s, "", dbc_str, &error);
if (ret && dbc()->msgCount() > 0) { if (ret && dbc()->nonEmptyDBCCount() > 0) {
QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!"));
} else { } else {
QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC from clipboard"), tr("Make sure that you paste the text with correct format.")); QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC from clipboard"), tr("Make sure that you paste the text with correct format."));
@ -356,7 +353,7 @@ void MainWindow::streamStarted() {
video_splitter->setSizes({1, 1}); video_splitter->setSizes({1, 1});
} }
// Don't overwrite already loaded DBC // Don't overwrite already loaded DBC
if (!dbc()->msgCount()) { if (!dbc()->nonEmptyDBCCount()) {
newFile(); newFile();
} }
@ -371,7 +368,7 @@ void MainWindow::eventsMerged() {
.arg(can->routeName()) .arg(can->routeName())
.arg(car_fingerprint.isEmpty() ? tr("Unknown Car") : car_fingerprint)); .arg(car_fingerprint.isEmpty() ? tr("Unknown Car") : car_fingerprint));
// Don't overwrite already loaded DBC // Don't overwrite already loaded DBC
if (!dbc()->msgCount() && !car_fingerprint.isEmpty()) { if (!dbc()->nonEmptyDBCCount() && !car_fingerprint.isEmpty()) {
auto dbc_name = fingerprint_to_dbc[car_fingerprint]; auto dbc_name = fingerprint_to_dbc[car_fingerprint];
if (dbc_name != QJsonValue::Undefined) { if (dbc_name != QJsonValue::Undefined) {
// Prevent dialog that load autosaved file from blocking replay->start(). // Prevent dialog that load autosaved file from blocking replay->start().
@ -529,7 +526,6 @@ void MainWindow::updateRecentFiles(const QString &fn) {
void MainWindow::updateRecentFileActions() { void MainWindow::updateRecentFileActions() {
int num_recent_files = std::min<int>(settings.recent_files.size(), MAX_RECENT_FILES); int num_recent_files = std::min<int>(settings.recent_files.size(), MAX_RECENT_FILES);
for (int i = 0; i < num_recent_files; ++i) { for (int i = 0; i < num_recent_files; ++i) {
QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(settings.recent_files[i]).fileName()); QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(settings.recent_files[i]).fileName());
recent_files_acts[i]->setText(text); recent_files_acts[i]->setText(text);
@ -543,15 +539,11 @@ void MainWindow::updateRecentFileActions() {
} }
void MainWindow::remindSaveChanges() { void MainWindow::remindSaveChanges() {
bool discard_changes = false; while (!UndoStack::instance()->isClean()) {
while (!UndoStack::instance()->isClean() && !discard_changes) {
QString text = tr("You have unsaved changes. Press ok to save them, cancel to discard."); QString text = tr("You have unsaved changes. Press ok to save them, cancel to discard.");
int ret = (QMessageBox::question(this, tr("Unsaved Changes"), text, QMessageBox::Ok | QMessageBox::Cancel)); int ret = QMessageBox::question(this, tr("Unsaved Changes"), text, QMessageBox::Ok | QMessageBox::Cancel);
if (ret == QMessageBox::Ok) { if (ret != QMessageBox::Ok) break;
save(); save();
} else {
discard_changes = true;
}
} }
UndoStack::instance()->clear(); UndoStack::instance()->clear();
} }
@ -660,7 +652,7 @@ HelpOverlay::HelpOverlay(MainWindow *parent) : QWidget(parent) {
void HelpOverlay::paintEvent(QPaintEvent *event) { void HelpOverlay::paintEvent(QPaintEvent *event) {
QPainter painter(this); QPainter painter(this);
painter.fillRect(rect(), QColor(0, 0, 0, 50)); painter.fillRect(rect(), QColor(0, 0, 0, 50));
MainWindow *parent = (MainWindow *)parentWidget(); auto parent = parentWidget();
drawHelpForWidget(painter, parent->findChild<MessagesWidget *>()); drawHelpForWidget(painter, parent->findChild<MessagesWidget *>());
drawHelpForWidget(painter, parent->findChild<BinaryView *>()); drawHelpForWidget(painter, parent->findChild<BinaryView *>());
drawHelpForWidget(painter, parent->findChild<SignalView *>()); drawHelpForWidget(painter, parent->findChild<SignalView *>());

@ -101,7 +101,6 @@ protected:
int prev_undostack_index = 0; int prev_undostack_index = 0;
int prev_undostack_count = 0; int prev_undostack_count = 0;
QByteArray default_state; QByteArray default_state;
friend class OnlineHelp;
}; };
class HelpOverlay : public QWidget { class HelpOverlay : public QWidget {

@ -3,9 +3,7 @@
#include <QDir> #include <QDir>
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include "tools/replay/logreader.h"
#include "tools/cabana/dbc/dbcmanager.h" #include "tools/cabana/dbc/dbcmanager.h"
#include "tools/cabana/streams/abstractstream.h"
const std::string TEST_RLOG_URL = "https://commadataci.blob.core.windows.net/openpilotci/0c94aa1e1296d7c6/2021-05-05--19-48-37/0/rlog.bz2"; const std::string TEST_RLOG_URL = "https://commadataci.blob.core.windows.net/openpilotci/0c94aa1e1296d7c6/2021-05-05--19-48-37/0/rlog.bz2";
@ -14,7 +12,7 @@ TEST_CASE("DBCFile::generateDBC") {
DBCFile dbc_origin(fn); DBCFile dbc_origin(fn);
DBCFile dbc_from_generated("", dbc_origin.generateDBC()); DBCFile dbc_from_generated("", dbc_origin.generateDBC());
REQUIRE(dbc_origin.msgCount() == dbc_from_generated.msgCount()); REQUIRE(dbc_origin.getMessages().size() == dbc_from_generated.getMessages().size());
auto &msgs = dbc_origin.getMessages(); auto &msgs = dbc_origin.getMessages();
auto &new_msgs = dbc_from_generated.getMessages(); auto &new_msgs = dbc_from_generated.getMessages();
for (auto &[id, m] : msgs) { for (auto &[id, m] : msgs) {

@ -12,7 +12,6 @@
#include <QDateTime> #include <QDateTime>
#include <QFontDatabase> #include <QFontDatabase>
#include <QLocale> #include <QLocale>
#include <QPainter>
#include <QPixmapCache> #include <QPixmapCache>
#include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/util.h"

@ -59,7 +59,7 @@ class Camerad:
eof = int(frame_id * 0.05 * 1e9) eof = int(frame_id * 0.05 * 1e9)
self.vipc_server.send(yuv_type, yuv, frame_id, eof, eof) self.vipc_server.send(yuv_type, yuv, frame_id, eof, eof)
dat = messaging.new_message(pub_type) dat = messaging.new_message(pub_type, valid=True)
msg = { msg = {
"frameId": frame_id, "frameId": frame_id,
"transform": [1.0, 0.0, 0.0, "transform": [1.0, 0.0, 0.0,

@ -23,7 +23,7 @@ class SimulatedSensors:
def send_imu_message(self, simulator_state: 'SimulatorState'): def send_imu_message(self, simulator_state: 'SimulatorState'):
for _ in range(5): for _ in range(5):
dat = messaging.new_message('accelerometer') dat = messaging.new_message('accelerometer', valid=True)
dat.accelerometer.sensor = 4 dat.accelerometer.sensor = 4
dat.accelerometer.type = 0x10 dat.accelerometer.type = 0x10
dat.accelerometer.timestamp = dat.logMonoTime # TODO: use the IMU timestamp dat.accelerometer.timestamp = dat.logMonoTime # TODO: use the IMU timestamp
@ -32,7 +32,7 @@ class SimulatedSensors:
self.pm.send('accelerometer', dat) self.pm.send('accelerometer', dat)
# copied these numbers from locationd # copied these numbers from locationd
dat = messaging.new_message('gyroscope') dat = messaging.new_message('gyroscope', valid=True)
dat.gyroscope.sensor = 5 dat.gyroscope.sensor = 5
dat.gyroscope.type = 0x10 dat.gyroscope.type = 0x10
dat.gyroscope.timestamp = dat.logMonoTime # TODO: use the IMU timestamp dat.gyroscope.timestamp = dat.logMonoTime # TODO: use the IMU timestamp
@ -53,7 +53,7 @@ class SimulatedSensors:
] ]
for _ in range(10): for _ in range(10):
dat = messaging.new_message('gpsLocationExternal') dat = messaging.new_message('gpsLocationExternal', valid=True)
dat.gpsLocationExternal = { dat.gpsLocationExternal = {
"unixTimestampMillis": int(time.time() * 1000), "unixTimestampMillis": int(time.time() * 1000),
"flags": 1, # valid fix "flags": 1, # valid fix
@ -94,7 +94,7 @@ class SimulatedSensors:
self.pm.send('driverStateV2', dat) self.pm.send('driverStateV2', dat)
# dmonitoringd output # dmonitoringd output
dat = messaging.new_message('driverMonitoringState') dat = messaging.new_message('driverMonitoringState', valid=True)
dat.driverMonitoringState = { dat.driverMonitoringState = {
"faceDetected": True, "faceDetected": True,
"isDistracted": False, "isDistracted": False,

Loading…
Cancel
Save