Merge remote-tracking branch 'upstream/master' into zstd-uploader

pull/32736/head
Shane Smiskol 1 year ago
commit 17ea583274
  1. 2
      .github/workflows/docs.yaml
  2. 3
      .github/workflows/selfdrive_tests.yaml
  3. 56
      README.md
  4. 4
      SConstruct
  5. 3
      docs/mkdocs.yml
  6. 6
      pyproject.toml
  7. 2
      selfdrive/car/hyundai/fingerprints.py
  8. 2
      selfdrive/test/test_onroad.py
  9. 34
      system/camerad/cameras/camera_common.cc
  10. 9
      system/camerad/cameras/camera_common.h
  11. 99
      system/camerad/cameras/camera_qcom2.cc
  12. 119
      system/camerad/cameras/camera_qcom2.h
  13. 22
      system/micd.py
  14. 9
      tools/mac_setup.sh
  15. 193
      tools/op.sh
  16. 67
      tools/setup.sh
  17. 5
      tools/ubuntu_setup.sh
  18. 115
      uv.lock

@ -29,7 +29,7 @@ jobs:
- name: Build docs - name: Build docs
run: | run: |
# TODO: can we install just the "docs" dependency group without the normal deps? # TODO: can we install just the "docs" dependency group without the normal deps?
pip install mkdocs mkdocs-terminal pip install mkdocs==1.4.3 mkdocs-terminal mkdocs-plugin-commonmark
cd docs cd docs
mkdocs build mkdocs build

@ -96,7 +96,7 @@ jobs:
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
build_mac: build_mac:
name: build macos name: build macOS
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -106,7 +106,6 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: ./tools/mac_setup.sh run: ./tools/mac_setup.sh
env: env:
SKIP_PROMPT: 1
# package install has DeprecationWarnings # package install has DeprecationWarnings
PYTHONWARNINGS: default PYTHONWARNINGS: default
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV - run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV

@ -1,9 +1,32 @@
[![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/8762862/f09e6d29-db2d-4179-80c2-51e8d92bdb5c)](https://comma.ai/shop/comma-3x) <div align="center" style="text-align: center;">
What is openpilot? <h1>openpilot</h1>
------
<p>
<b>openpilot is an operating system for robotics.</b>
<br>
Currently, it upgrades the driver assistance system in 275+ supported cars.
</p>
<h3>
<a href="https://docs.comma.ai">Read the docs</a>
<span> · </span>
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
<span> · </span>
<a href="https://discord.comma.ai">Community</a>
<span> · </span>
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
</h3>
Quick start: `curl -fsSL openpilot.comma.ai | bash`
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md). ![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![X Follow](https://img.shields.io/twitter/follow/comma_ai)](https://x.com/comma_ai)
[![Discord](https://img.shields.io/discord/469524606043160576)](https://discord.comma.ai)
</div>
<table> <table>
<tr> <tr>
@ -49,18 +72,6 @@ Safety and Testing
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile). * panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes. * We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
User Data and comma Account
------
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
Licensing Licensing
------ ------
@ -72,9 +83,14 @@ Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and i
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS. YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.** NO WARRANTY EXPRESSED OR IMPLIED.**
--- User Data and comma Account
------
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img> By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg) openpilot is open source software: the user is free to disable data collection if they wish to do so.
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.

@ -169,7 +169,6 @@ if arch != "Darwin":
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"] ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
# Enable swaglog include in submodules # Enable swaglog include in submodules
cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""'] cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
ccflags_option = GetOption('ccflags') ccflags_option = GetOption('ccflags')
@ -205,7 +204,6 @@ env = Environment(
"#third_party/json11", "#third_party/json11",
"#third_party/linux/include", "#third_party/linux/include",
"#third_party/snpe/include", "#third_party/snpe/include",
"#third_party/qrcode",
"#third_party", "#third_party",
"#cereal", "#cereal",
"#msgq", "#msgq",
@ -314,7 +312,7 @@ try:
except SCons.Errors.UserError: except SCons.Errors.UserError:
qt_env.Tool('qt') qt_env.Tool('qt')
qt_env['CPPPATH'] += qt_dirs# + ["#selfdrive/ui/qt/"] qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
qt_flags = [ qt_flags = [
"-D_REENTRANT", "-D_REENTRANT",
"-DQT_NO_DEBUG", "-DQT_NO_DEBUG",

@ -5,6 +5,9 @@ site_url: https://docs.comma.ai
strict: true strict: true
plugins:
- commonmark
theme: theme:
name: terminal name: terminal
features: features:

@ -67,8 +67,9 @@ dependencies = [
[project.optional-dependencies] [project.optional-dependencies]
docs = [ docs = [
"Jinja2", "Jinja2",
"mkdocs", "mkdocs==1.4.3", # needed for mkdocs-plugin-commonmark
"mkdocs-terminal", "mkdocs-terminal",
"mkdocs-plugin-commonmark",
] ]
testing = [ testing = [
@ -110,6 +111,7 @@ dev = [
#pprofile = "*" #pprofile = "*"
"pyautogui", "pyautogui",
"pyopencl; platform_machine != 'aarch64'", # broken on arm64 "pyopencl; platform_machine != 'aarch64'", # broken on arm64
"pytools < 2024.1.11; platform_machine != 'aarch64'", # pyopencl use a broken version
"pywinctl", "pywinctl",
"pyprof2calltree", "pyprof2calltree",
"rerun-sdk", "rerun-sdk",
@ -240,6 +242,7 @@ exclude = [
"third_party", "third_party",
] ]
lint.flake8-implicit-str-concat.allow-multiline = false lint.flake8-implicit-str-concat.allow-multiline = false
[tool.ruff.lint.flake8-tidy-imports.banned-api] [tool.ruff.lint.flake8-tidy-imports.banned-api]
"selfdrive".msg = "Use openpilot.selfdrive" "selfdrive".msg = "Use openpilot.selfdrive"
"common".msg = "Use openpilot.common" "common".msg = "Use openpilot.common"
@ -251,5 +254,6 @@ lint.flake8-implicit-str-concat.allow-multiline=false
[tool.coverage.run] [tool.coverage.run]
concurrency = ["multiprocessing", "thread"] concurrency = ["multiprocessing", "thread"]
[tool.ruff.format] [tool.ruff.format]
quote-style = "preserve" quote-style = "preserve"

@ -765,9 +765,11 @@ FW_VERSIONS = {
], ],
(Ecu.abs, 0x7d1, None): [ (Ecu.abs, 0x7d1, None): [
b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080', b'\xf1\x00JF ESC \x0f 16 \x16\x06\x17 58920-D5080',
b'\xf1\x00JF ESC \t 17 \x16\x06# 58920-D4180',
], ],
(Ecu.fwdCamera, 0x7c4, None): [ (Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JFWGN LDWS AT USA LHD 1.00 1.02 95895-D4100 G21', b'\xf1\x00JFWGN LDWS AT USA LHD 1.00 1.02 95895-D4100 G21',
b'\xf1\x00JFWGN LKAS AT EUR LHD 1.00 1.01 95895-D4100 G20',
], ],
}, },
CAR.KIA_OPTIMA_G4_FL: { CAR.KIA_OPTIMA_G4_FL: {

@ -56,7 +56,7 @@ PROCS = {
"system.logmessaged": 0.2, "system.logmessaged": 0.2,
"system.tombstoned": 0, "system.tombstoned": 0,
"logcatd": 0, "logcatd": 0,
"system.micd": 6.0, "system.micd": 5.0,
"system.timed": 0, "system.timed": 0,
"selfdrive.pandad.pandad": 0, "selfdrive.pandad.pandad": 0,
"system.statsd": 0.4, "system.statsd": 0.4,

@ -244,7 +244,7 @@ static kj::Array<capnp::byte> yuv420_to_jpeg(const CameraBuf *b, int thumbnail_w
return dat; return dat;
} }
static void publish_thumbnail(PubMaster *pm, const CameraBuf *b) { void publish_thumbnail(PubMaster *pm, const CameraBuf *b) {
auto thumbnail = yuv420_to_jpeg(b, b->rgb_width / 4, b->rgb_height / 4); auto thumbnail = yuv420_to_jpeg(b, b->rgb_width / 4, b->rgb_height / 4);
if (thumbnail.size() == 0) return; if (thumbnail.size() == 0) return;
@ -284,36 +284,6 @@ float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_sk
return lum_med / 256.0; return lum_med / 256.0;
} }
void *processing_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback) {
const char *thread_name = nullptr;
if (cs == &cameras->road_cam) {
thread_name = "RoadCamera";
} else if (cs == &cameras->driver_cam) {
thread_name = "DriverCamera";
} else {
thread_name = "WideRoadCamera";
}
util::set_thread_name(thread_name);
uint32_t cnt = 0;
while (!do_exit) {
if (!cs->buf.acquire()) continue;
callback(cameras, cs, cnt);
if (cs == &(cameras->road_cam) && cameras->pm && cnt % 100 == 3) {
// this takes 10ms???
publish_thumbnail(cameras->pm, &(cs->buf));
}
++cnt;
}
return NULL;
}
std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback) {
return std::thread(processing_thread, cameras, cs, callback);
}
void camerad_thread() { void camerad_thread() {
cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT); cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT);
#ifdef QCOM2 #ifdef QCOM2
@ -324,7 +294,7 @@ void camerad_thread() {
#endif #endif
{ {
MultiCameraState cameras = {}; MultiCameraState cameras;
VisionIpcServer vipc_server("camerad", device_id, context); VisionIpcServer vipc_server("camerad", device_id, context);
cameras_open(&cameras); cameras_open(&cameras);

@ -2,7 +2,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <memory> #include <memory>
#include <thread>
#include "cereal/messaging/messaging.h" #include "cereal/messaging/messaging.h"
#include "msgq/visionipc/visionipc_server.h" #include "msgq/visionipc/visionipc_server.h"
@ -18,9 +17,6 @@ enum CameraType {
}; };
// for debugging // for debugging
const bool env_disable_road = getenv("DISABLE_ROAD") != NULL;
const bool env_disable_wide_road = getenv("DISABLE_WIDE_ROAD") != NULL;
const bool env_disable_driver = getenv("DISABLE_DRIVER") != NULL;
const bool env_debug_frames = getenv("DEBUG_FRAMES") != NULL; const bool env_debug_frames = getenv("DEBUG_FRAMES") != NULL;
const bool env_log_raw_frames = getenv("LOG_RAW_FRAMES") != NULL; const bool env_log_raw_frames = getenv("LOG_RAW_FRAMES") != NULL;
const bool env_ctrl_exp_from_params = getenv("CTRL_EXP_FROM_PARAMS") != NULL; const bool env_ctrl_exp_from_params = getenv("CTRL_EXP_FROM_PARAMS") != NULL;
@ -72,13 +68,10 @@ public:
void queue(size_t buf_idx); void queue(size_t buf_idx);
}; };
typedef void (*process_thread_cb)(MultiCameraState *s, CameraState *c, int cnt);
void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &frame_data, CameraState *c); void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &frame_data, CameraState *c);
kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b); kj::Array<uint8_t> get_raw_frame_image(const CameraBuf *b);
float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_skip); float set_exposure_target(const CameraBuf *b, Rect ae_xywh, int x_skip, int y_skip);
std::thread start_process_thread(MultiCameraState *cameras, CameraState *cs, process_thread_cb callback); void publish_thumbnail(PubMaster *pm, const CameraBuf *b);
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);
void cameras_open(MultiCameraState *s); void cameras_open(MultiCameraState *s);
void cameras_run(MultiCameraState *s); void cameras_run(MultiCameraState *s);

@ -26,6 +26,16 @@ const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py
extern ExitHandler do_exit; extern ExitHandler do_exit;
CameraState::CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config)
: multi_cam_state(multi_camera_state),
camera_num(config.camera_num),
stream_type(config.stream_type),
focal_len(config.focal_len),
publish_name(config.publish_name),
init_camera_state(config.init_camera_state),
enabled(config.enabled) {
}
int CameraState::clear_req_queue() { int CameraState::clear_req_queue() {
struct cam_req_mgr_flush_info req_mgr_flush_request = {0}; struct cam_req_mgr_flush_info req_mgr_flush_request = {0};
req_mgr_flush_request.session_hdl = session_handle; req_mgr_flush_request.session_hdl = session_handle;
@ -425,48 +435,38 @@ void CameraState::set_exposure_rect() {
} }
void CameraState::sensor_set_parameters() { void CameraState::sensor_set_parameters() {
target_grey_fraction = 0.3;
dc_gain_enabled = false;
dc_gain_weight = ci->dc_gain_min_weight; dc_gain_weight = ci->dc_gain_min_weight;
gain_idx = ci->analog_gain_rec_idx; gain_idx = ci->analog_gain_rec_idx;
exposure_time = 5;
cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (ci->dc_gain_factor-1) / ci->dc_gain_max_weight) * ci->sensor_analog_gains[gain_idx] * exposure_time; cur_ev[0] = cur_ev[1] = cur_ev[2] = (1 + dc_gain_weight * (ci->dc_gain_factor-1) / ci->dc_gain_max_weight) * ci->sensor_analog_gains[gain_idx] * exposure_time;
} }
void CameraState::camera_map_bufs(MultiCameraState *s) { void CameraState::camera_map_bufs() {
for (int i = 0; i < FRAME_BUF_COUNT; i++) { for (int i = 0; i < FRAME_BUF_COUNT; i++) {
// configure ISP to put the image in place // configure ISP to put the image in place
struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0}; struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0};
mem_mgr_map_cmd.mmu_hdls[0] = s->device_iommu; mem_mgr_map_cmd.mmu_hdls[0] = multi_cam_state->device_iommu;
mem_mgr_map_cmd.num_hdl = 1; mem_mgr_map_cmd.num_hdl = 1;
mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd; mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd;
int ret = do_cam_control(s->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd)); int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret); LOGD("map buf req: (fd: %d) 0x%x %d", buf.camera_bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
buf_handle[i] = mem_mgr_map_cmd.out.buf_handle; buf_handle[i] = mem_mgr_map_cmd.out.buf_handle;
} }
enqueue_req_multi(1, FRAME_BUF_COUNT, 0); enqueue_req_multi(1, FRAME_BUF_COUNT, 0);
} }
void CameraState::camera_init(MultiCameraState *s, VisionIpcServer * v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len) { void CameraState::camera_init(VisionIpcServer * v, cl_device_id device_id, cl_context ctx) {
if (!enabled) return; if (!enabled) return;
LOGD("camera init %d", camera_num); LOGD("camera init %d", camera_num);
request_id_last = 0; buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, stream_type);
skipped = true; camera_map_bufs();
buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, yuv_type);
camera_map_bufs(s);
fl_pix = focal_len / ci->pixel_size_mm; fl_pix = focal_len / ci->pixel_size_mm;
set_exposure_rect(); set_exposure_rect();
} }
void CameraState::camera_open(MultiCameraState *multi_cam_state_, int camera_num_, bool enabled_) { void CameraState::camera_open() {
multi_cam_state = multi_cam_state_;
camera_num = camera_num_;
enabled = enabled_;
if (!enabled) return; if (!enabled) return;
if (!openSensor()) { if (!openSensor()) {
@ -660,9 +660,9 @@ void CameraState::linkDevices() {
} }
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, device_id, ctx, VISION_STREAM_DRIVER, DRIVER_FL_MM); s->driver_cam.camera_init(v, device_id, ctx);
s->road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_ROAD, ROAD_FL_MM); s->road_cam.camera_init(v, device_id, ctx);
s->wide_road_cam.camera_init(s, v, device_id, ctx, VISION_STREAM_WIDE_ROAD, WIDE_FL_MM); s->wide_road_cam.camera_init(v, device_id, ctx);
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"}); s->pm = new PubMaster({"roadCameraState", "driverCameraState", "wideRoadCameraState", "thumbnail"});
} }
@ -706,11 +706,11 @@ void cameras_open(MultiCameraState *s) {
ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub)); ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub));
LOGD("req mgr subscribe: %d", ret); LOGD("req mgr subscribe: %d", ret);
s->driver_cam.camera_open(s, 2, !env_disable_driver); s->driver_cam.camera_open();
LOGD("driver camera opened"); LOGD("driver camera opened");
s->road_cam.camera_open(s, 1, !env_disable_road); s->road_cam.camera_open();
LOGD("road camera opened"); LOGD("road camera opened");
s->wide_road_cam.camera_open(s, 0, !env_disable_wide_road); s->wide_road_cam.camera_open();
LOGD("wide road camera opened"); LOGD("wide road camera opened");
} }
@ -943,41 +943,50 @@ void CameraState::set_camera_exposure(float grey_frac) {
sensors_i2c(exp_reg_array.data(), exp_reg_array.size(), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, ci->data_word); sensors_i2c(exp_reg_array.data(), exp_reg_array.size(), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, ci->data_word);
} }
static void process_driver_camera(MultiCameraState *s, CameraState *c, int cnt) { void CameraState::run() {
c->set_camera_exposure(set_exposure_target(&c->buf, c->ae_xywh, 2, 4)); util::set_thread_name(publish_name);
for (uint32_t cnt = 0; !do_exit; ++cnt) {
// Acquire the buffer; continue if acquisition fails
if (!buf.acquire()) continue;
MessageBuilder msg; MessageBuilder msg;
auto framed = msg.initEvent().initDriverCameraState(); auto framed = (msg.initEvent().*init_camera_state)();
fill_frame_data(framed, c->buf.cur_frame_data, c); fill_frame_data(framed, buf.cur_frame_data, this);
c->ci->processRegisters(c, framed); // Log raw frames for road camera
s->pm->send("driverCameraState", msg); if (env_log_raw_frames && stream_type == VISION_STREAM_ROAD && cnt % 100 == 5) { // no overlap with qlog decimation
framed.setImage(get_raw_frame_image(&buf));
}
// Log frame id for road and wide road cameras
if (stream_type != VISION_STREAM_DRIVER) {
LOGT(buf.cur_frame_data.frame_id, "%s: Image set", publish_name);
} }
void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) { // Process camera registers and set camera exposure
const CameraBuf *b = &c->buf; ci->processRegisters(this, framed);
set_camera_exposure(set_exposure_target(&buf, ae_xywh, 2, stream_type != VISION_STREAM_DRIVER ? 2 : 4));
MessageBuilder msg; // Send the message
auto framed = c == &s->road_cam ? msg.initEvent().initRoadCameraState() : msg.initEvent().initWideRoadCameraState(); multi_cam_state->pm->send(publish_name, msg);
fill_frame_data(framed, b->cur_frame_data, c); if (stream_type == VISION_STREAM_ROAD && cnt % 100 == 3) {
if (env_log_raw_frames && c == &s->road_cam && cnt % 100 == 5) { // no overlap with qlog decimation publish_thumbnail(multi_cam_state->pm, &buf); // this takes 10ms???
framed.setImage(get_raw_frame_image(b)); }
}
} }
LOGT(c->buf.cur_frame_data.frame_id, "%s: Image set", c == &s->road_cam ? "RoadCamera" : "WideRoadCamera");
c->ci->processRegisters(c, framed);
s->pm->send(c == &s->road_cam ? "roadCameraState" : "wideRoadCameraState", msg);
const int skip = 2; MultiCameraState::MultiCameraState()
c->set_camera_exposure(set_exposure_target(b, c->ae_xywh, skip, skip)); : driver_cam(this, DRIVER_CAMERA_CONFIG),
road_cam(this, ROAD_CAMERA_CONFIG),
wide_road_cam(this, WIDE_ROAD_CAMERA_CONFIG) {
} }
void cameras_run(MultiCameraState *s) { void cameras_run(MultiCameraState *s) {
LOG("-- Starting threads"); LOG("-- Starting threads");
std::vector<std::thread> threads; std::vector<std::thread> threads;
if (s->driver_cam.enabled) threads.push_back(start_process_thread(s, &s->driver_cam, process_driver_camera)); if (s->driver_cam.enabled) threads.emplace_back(&CameraState::run, &s->driver_cam);
if (s->road_cam.enabled) threads.push_back(start_process_thread(s, &s->road_cam, process_road_camera)); if (s->road_cam.enabled) threads.emplace_back(&CameraState::run, &s->road_cam);
if (s->wide_road_cam.enabled) threads.push_back(start_process_thread(s, &s->wide_road_cam, process_road_camera)); if (s->wide_road_cam.enabled) threads.emplace_back(&CameraState::run, &s->wide_road_cam);
// start devices // start devices
LOG("-- Starting devices"); LOG("-- Starting devices");

@ -11,67 +11,105 @@
#define FRAME_BUF_COUNT 4 #define FRAME_BUF_COUNT 4
#define ROAD_FL_MM 8.0f struct CameraConfig {
#define WIDE_FL_MM 1.71f int camera_num;
#define DRIVER_FL_MM 1.71f VisionStreamType stream_type;
float focal_len; // millimeters
const char *publish_name;
cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)();
bool enabled;
};
const CameraConfig WIDE_ROAD_CAMERA_CONFIG = {
.camera_num = 0,
.stream_type = VISION_STREAM_WIDE_ROAD,
.focal_len = 1.71,
.publish_name = "wideRoadCameraState",
.init_camera_state = &cereal::Event::Builder::initWideRoadCameraState,
.enabled = !getenv("DISABLE_WIDE_ROAD"),
};
const CameraConfig ROAD_CAMERA_CONFIG = {
.camera_num = 1,
.stream_type = VISION_STREAM_ROAD,
.focal_len = 8.0,
.publish_name = "roadCameraState",
.init_camera_state = &cereal::Event::Builder::initRoadCameraState,
.enabled = !getenv("DISABLE_ROAD"),
};
const CameraConfig DRIVER_CAMERA_CONFIG = {
.camera_num = 2,
.stream_type = VISION_STREAM_DRIVER,
.focal_len = 1.71,
.publish_name = "driverCameraState",
.init_camera_state = &cereal::Event::Builder::initDriverCameraState,
.enabled = !getenv("DISABLE_DRIVER"),
};
class CameraState { class CameraState {
public: public:
MultiCameraState *multi_cam_state; MultiCameraState *multi_cam_state = nullptr;
std::unique_ptr<const SensorInfo> ci; std::unique_ptr<const SensorInfo> ci;
bool enabled; bool enabled = true;
VisionStreamType stream_type;
const char *publish_name = nullptr;
cereal::FrameData::Builder (cereal::Event::Builder::*init_camera_state)() = nullptr;
float focal_len = 0;
std::mutex exp_lock; std::mutex exp_lock;
int exposure_time; int exposure_time = 5;
bool dc_gain_enabled; bool dc_gain_enabled = false;
int dc_gain_weight; int dc_gain_weight = 0;
int gain_idx; int gain_idx = 0;
float analog_gain_frac; float analog_gain_frac = 0;
float cur_ev[3]; float cur_ev[3] = {};
float best_ev_score; float best_ev_score = 0;
int new_exp_g; int new_exp_g = 0;
int new_exp_t; int new_exp_t = 0;
Rect ae_xywh; Rect ae_xywh = {};
float measured_grey_fraction; float measured_grey_fraction = 0;
float target_grey_fraction; float target_grey_fraction = 0.3;
unique_fd sensor_fd; unique_fd sensor_fd;
unique_fd csiphy_fd; unique_fd csiphy_fd;
int camera_num; int camera_num = 0;
float fl_pix; float fl_pix = 0;
CameraState(MultiCameraState *multi_camera_state, const CameraConfig &config);
void handle_camera_event(void *evdat); void handle_camera_event(void *evdat);
void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain); void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain);
void set_camera_exposure(float grey_frac); void set_camera_exposure(float grey_frac);
void sensors_start(); void sensors_start();
void camera_open(MultiCameraState *multi_cam_state, int camera_num, bool enabled); void camera_open();
void set_exposure_rect(); void set_exposure_rect();
void sensor_set_parameters(); void sensor_set_parameters();
void camera_map_bufs(MultiCameraState *s); void camera_map_bufs();
void camera_init(MultiCameraState *s, VisionIpcServer *v, cl_device_id device_id, cl_context ctx, VisionStreamType yuv_type, float focal_len); void camera_init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx);
void camera_close(); void camera_close();
void run();
int32_t session_handle; int32_t session_handle = -1;
int32_t sensor_dev_handle; int32_t sensor_dev_handle = -1;
int32_t isp_dev_handle; int32_t isp_dev_handle = -1;
int32_t csiphy_dev_handle; int32_t csiphy_dev_handle = -1;
int32_t link_handle; int32_t link_handle = -1;
int buf0_handle; int buf0_handle = 0;
int buf_handle[FRAME_BUF_COUNT]; int buf_handle[FRAME_BUF_COUNT] = {};
int sync_objs[FRAME_BUF_COUNT]; int sync_objs[FRAME_BUF_COUNT] = {};
int request_ids[FRAME_BUF_COUNT]; int request_ids[FRAME_BUF_COUNT] = {};
int request_id_last; int request_id_last = 0;
int frame_id_last; int frame_id_last = 0;
int idx_offset; int idx_offset = 0;
bool skipped; bool skipped = true;
CameraBuf buf; CameraBuf buf;
MemoryManager mm; MemoryManager mm;
@ -95,16 +133,19 @@ private:
Params params; Params params;
}; };
typedef struct MultiCameraState { class MultiCameraState {
public:
MultiCameraState();
unique_fd video0_fd; unique_fd video0_fd;
unique_fd cam_sync_fd; unique_fd cam_sync_fd;
unique_fd isp_fd; unique_fd isp_fd;
int device_iommu; int device_iommu = -1;
int cdm_iommu; int cdm_iommu = -1;
CameraState road_cam; CameraState road_cam;
CameraState wide_road_cam; CameraState wide_road_cam;
CameraState driver_cam; CameraState driver_cam;
PubMaster *pm; PubMaster *pm;
} MultiCameraState; };

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import numpy as np import numpy as np
from functools import cache
from cereal import messaging from cereal import messaging
from openpilot.common.realtime import Ratekeeper from openpilot.common.realtime import Ratekeeper
@ -10,7 +11,16 @@ RATE = 10
FFT_SAMPLES = 4096 FFT_SAMPLES = 4096
REFERENCE_SPL = 2e-5 # newtons/m^2 REFERENCE_SPL = 2e-5 # newtons/m^2
SAMPLE_RATE = 44100 SAMPLE_RATE = 44100
SAMPLE_BUFFER = 4096 # (approx 100ms) SAMPLE_BUFFER = 4096 # approx 100ms
@cache
def get_a_weighting_filter():
# Calculate the A-weighting filter
# https://en.wikipedia.org/wiki/A-weighting
freqs = np.fft.fftfreq(FFT_SAMPLES, d=1 / SAMPLE_RATE)
A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2)))
return A / np.max(A)
def calculate_spl(measurements): def calculate_spl(measurements):
@ -27,16 +37,8 @@ def apply_a_weighting(measurements: np.ndarray) -> np.ndarray:
# Generate a Hanning window of the same length as the audio measurements # Generate a Hanning window of the same length as the audio measurements
measurements_windowed = measurements * np.hanning(len(measurements)) measurements_windowed = measurements * np.hanning(len(measurements))
# Calculate the frequency axis for the signal
freqs = np.fft.fftfreq(measurements_windowed.size, d=1 / SAMPLE_RATE)
# Calculate the A-weighting filter
# https://en.wikipedia.org/wiki/A-weighting
A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2)))
A /= np.max(A) # Normalize the filter
# Apply the A-weighting filter to the signal # Apply the A-weighting filter to the signal
return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * A)) return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * get_a_weighting_filter()))
class Mic: class Mic:

@ -2,19 +2,12 @@
set -e set -e
if [ -z "$SKIP_PROMPT" ]; then
echo "--------------- macOS support ---------------" echo "--------------- macOS support ---------------"
echo "Running openpilot natively on macOS is not officially supported." echo "Running openpilot natively on macOS is still a work-in-progress."
echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues." echo "It might build, some parts of it might work, but it's not fully tested, so there might be some issues."
echo echo
echo "Check out devcontainers for a seamless experience (see tools/README.md)." echo "Check out devcontainers for a seamless experience (see tools/README.md)."
echo "-------------------------------------------------" echo "-------------------------------------------------"
echo -n "Are you sure you want to continue? [y/N] "
read -r response
if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
exit 1
fi
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
ROOT="$(cd $DIR/../ && pwd)" ROOT="$(cd $DIR/../ && pwd)"

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
@ -14,64 +14,66 @@ function op_first_install() {
if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then if [ "$(uname)" == "Darwin" ] && [ $SHELL == "/bin/bash" ]; then
RC_FILE="$HOME/.bash_profile" RC_FILE="$HOME/.bash_profile"
fi fi
op_run_command printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE printf "\nalias op='source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" >> $RC_FILE
echo -e " ↳ [${GREEN}${NC}] op installed successfully. Open a new shell to use it.\n" echo -e " ↳ [${GREEN}${NC}] op installed successfully. Open a new shell to use it.\n"
) )
} }
function op_run_command() {
CMD="$@"
echo -e "${BOLD}Running:${NC} $CMD"
if [[ -z "$DRY" ]]; then
eval "$CMD"
fi
}
# be default, assume openpilot dir is in current directory # be default, assume openpilot dir is in current directory
OPENPILOT_ROOT=$(pwd) OPENPILOT_ROOT=$(pwd)
function op_check_openpilot_dir() { function op_check_openpilot_dir() {
echo "Checking for openpilot directory..."
while [[ "$OPENPILOT_ROOT" != '/' ]]; while [[ "$OPENPILOT_ROOT" != '/' ]];
do do
if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then if find "$OPENPILOT_ROOT/launch_openpilot.sh" -maxdepth 1 -mindepth 1 &> /dev/null; then
echo -e " ↳ [${GREEN}${NC}] openpilot found.\n"
return 0 return 0
fi fi
OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)" OPENPILOT_ROOT="$(readlink -f "$OPENPILOT_ROOT/"..)"
done done
echo "openpilot directory not found! Make sure that you are inside openpilot" echo -e " ↳ [${RED}${NC}] openpilot directory not found! Make sure that you are"
echo "directory or specify one with the --dir option!" echo " inside the openpilot directory or specify one with the"
echo " --dir option!"
return 1 return 1
} }
function op_run_command() {
CMD="$@"
echo -e "${BOLD}Running:${NC} $CMD"
if [[ -z "$DRY" ]]; then
$CMD
fi
}
function op_check_git() { function op_check_git() {
(set -e (set -e
cd $OPENPILOT_ROOT
echo "Checking for git..." echo "Checking for git..."
if ! command -v "git" > /dev/null 2>&1; then if ! command -v "git" > /dev/null 2>&1; then
echo -e " ↳ [${RED}${NC}] git not found on your system!" echo -e " ↳ [${RED}${NC}] git not found on your system!\n"
return 1 return 1
else else
echo -e " ↳ [${GREEN}${NC}] git found on your system.\n" echo -e " ↳ [${GREEN}${NC}] git found.\n"
fi fi
echo "Checking for git lfs files..." echo "Checking for git lfs files..."
if [[ $(file -b $(git lfs ls-files -n | grep "\.so" | head -n 1)) == "ASCII text" ]]; then if [[ $(file -b $OPENPILOT_ROOT/selfdrive/modeld/models/supercombo.onnx) == "ASCII text" ]]; then
echo -e " ↳ [${RED}${NC}] git lfs files not found! Run git lfs pull" echo -e " ↳ [${RED}${NC}] git lfs files not found! Run 'git lfs pull'\n"
return 1 return 1
else else
echo -e " ↳ [${GREEN}${NC}] git lfs files found on your system.\n" echo -e " ↳ [${GREEN}${NC}] git lfs files found.\n"
fi fi
echo "Checking for git submodules..." echo "Checking for git submodules..."
if $(git submodule foreach --quiet --recursive 'return 1' 2&> /dev/null); then for name in body msgq_repo opendbc panda rednose_repo tinygrad_repo; do
echo -e " ↳ [${RED}${NC}] git submodules not found! Run 'git submodule update --init --recursive'" if [[ -z $(ls $OPENPILOT_ROOT/$name) ]]; then
echo -e " ↳ [${RED}${NC}] git submodule $name not found! Run 'git submodule update --init --recursive'\n"
return 1 return 1
else
echo -e " ↳ [${GREEN}${NC}] git submodules found on your system.\n"
fi fi
done
echo -e " ↳ [${GREEN}${NC}] git submodules found.\n"
) )
} }
@ -89,19 +91,19 @@ function op_check_os() {
echo -e " ↳ [${GREEN}${NC}] Ubuntu $VERSION_CODENAME detected.\n" echo -e " ↳ [${GREEN}${NC}] Ubuntu $VERSION_CODENAME detected.\n"
;; ;;
* ) * )
echo -e " ↳ [${RED}${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!" echo -e " ↳ [${RED}${NC}] Incompatible Ubuntu version $VERSION_CODENAME detected!\n"
return 1 return 1
;; ;;
esac esac
else else
echo -e " ↳ [${RED}${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!" echo -e " ↳ [${RED}${NC}] No /etc/os-release on your system. Make sure you're running on Ubuntu, or similar!\n"
return 1 return 1
fi fi
elif [[ "$OSTYPE" == "darwin"* ]]; then elif [[ "$OSTYPE" == "darwin"* ]]; then
echo -e " ↳ [${GREEN}${NC}] macos detected.\n" echo -e " ↳ [${GREEN}${NC}] macos detected.\n"
else else
echo -e " ↳ [${RED}${NC}] OS type $OSTYPE not supported!" echo -e " ↳ [${RED}${NC}] OS type $OSTYPE not supported!\n"
return 1 return 1
fi fi
@ -112,78 +114,109 @@ function op_check_python() {
(set -e (set -e
echo "Checking for compatible python version..." echo "Checking for compatible python version..."
export REQUIRED_PYTHON_VERSION=$(grep "requires-python" pyproject.toml | cut -d= -f3- | tr -d '"' | tr -d ' ') REQUIRED_PYTHON_VERSION=$(grep "requires-python" $OPENPILOT_ROOT/pyproject.toml)
if ! command -v "python3" > /dev/null 2>&1; then INSTALLED_PYTHON_VERSION=$(python3 --version 2> /dev/null || true)
echo -e " ↳ [${RED}${NC}] python3 not found on your system. You need python version at least $REQUIRED_PYTHON_VERSION to continue!"
if [[ -z $INSTALLED_PYTHON_VERSION ]]; then
echo -e " ↳ [${RED}${NC}] python3 not found on your system. You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n"
return 1 return 1
elif [[ $(echo $INSTALLED_PYTHON_VERSION | tr -d -c '[0-9]') -ge $(($(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9]') * 10)) ]]; then
echo -e " ↳ [${GREEN}${NC}] $INSTALLED_PYTHON_VERSION detected.\n"
else else
if $(python3 -c "import sys; quit(not sys.version_info >= tuple(map(int, \"$REQUIRED_PYTHON_VERSION\".split('.'))))"); then echo -e " ↳ [${RED}${NC}] You need python version at least $(echo $REQUIRED_PYTHON_VERSION | tr -d -c '[0-9.]') to continue!\n"
echo -e " ↳ [${GREEN}${NC}] $(python3 --version) detected.\n"
else
echo -e " ↳ [${RED}${NC}] You need python version at least $REQUIRED_PYTHON_VERSION to continue!"
return 1 return 1
fi fi
fi
) )
} }
# this must be run in the same shell as the user calling "op" function op_check_venv() {
function op_venv() { echo "Checking for venv..."
op_check_openpilot_dir || return 1 if source $OPENPILOT_ROOT/.venv/bin/activate; then
op_run_command source $OPENPILOT_ROOT/.venv/bin/activate || (echo -e "\nCan't activate venv. Have you ran 'op install' ?" && return 1) echo -e " ↳ [${GREEN}${NC}] venv detected.\n"
else
echo -e " ↳ [${RED}${NC}] Can't activate venv in $OPENPILOT_ROOT. Assuming global env!\n"
fi
} }
function op_check() { function op_before_cmd() {
(set -e if [[ ! -z "$NO_VERIFY" ]]; then
return 0
fi
op_check_openpilot_dir op_check_openpilot_dir
cd $OPENPILOT_ROOT cd $OPENPILOT_ROOT
op_check_git op_check_git
op_check_os op_check_os
op_check_venv
op_check_python op_check_python
echo -e "-----------------------------\n"
)
} }
function op_run() { function op_install() {
(set -e (set -e
op_venv op_check_openpilot_dir
cd $OPENPILOT_ROOT cd $OPENPILOT_ROOT
op_check_os
op_check_python
echo "Installing dependencies..."
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
op_run_command $OPENPILOT_ROOT/tools/ubuntu_setup.sh
elif [[ "$OSTYPE" == "darwin"* ]]; then
op_run_command $OPENPILOT_ROOT/tools/mac_setup.sh
fi
echo -e " ↳ [${GREEN}${NC}] Dependencies installed successfully.\n"
echo "Getting git submodules..."
op_run_command git submodule update --init --recursive
echo -e " ↳ [${GREEN}${NC}] Submodules installed successfully.\n"
echo "Pulling git lfs files..."
op_run_command git lfs pull
echo -e " ↳ [${GREEN}${NC}] Files pulled successfully.\n"
op_run_command $OPENPILOT_ROOT/launch_openpilot.sh op_check
) )
} }
function op_install() { function op_venv() {
( set -e ( set -e
op_check_openpilot_dir op_before_cmd
cd $OPENPILOT_ROOT
op_check_os )
op_check_python
if [[ "$OSTYPE" == "linux-gnu"* ]]; then if [[ "$?" -eq 0 ]]; then
$OPENPILOT_ROOT/tools/ubuntu_setup.sh # this must be run in the same shell as the user calling "op"
elif [[ "$OSTYPE" == "darwin"* ]]; then op_check_openpilot_dir > /dev/null
$OPENPILOT_ROOT/tools/mac_setup.sh op_run_command source $OPENPILOT_ROOT/.venv/bin/activate
fi fi
}
git submodule update --init --recursive function op_check() {
git lfs pull (set -e
op_before_cmd
) )
} }
function op_build() { function op_run() {
(set -e (set -e
op_venv op_before_cmd
cd $OPENPILOT_ROOT op_run_command $OPENPILOT_ROOT/launch_openpilot.sh $@
)
}
function op_build() {
(set -e
op_before_cmd
op_run_command scons $@ op_run_command scons $@
) )
@ -192,9 +225,7 @@ function op_build() {
function op_juggle() { function op_juggle() {
(set -e (set -e
op_venv op_before_cmd
cd $OPENPILOT_ROOT
op_run_command $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@ op_run_command $OPENPILOT_ROOT/tools/plotjuggler/juggle.py $@
) )
@ -203,9 +234,7 @@ function op_juggle() {
function op_linter() { function op_linter() {
(set -e (set -e
op_venv op_before_cmd
cd $OPENPILOT_ROOT
op_run_command pre-commit run --all $@ op_run_command pre-commit run --all $@
) )
@ -213,14 +242,32 @@ function op_linter() {
function op_replay() { function op_replay() {
(set -e (set -e
op_check_openpilot_dir
cd $OPENPILOT_ROOT
op_before_cmd
op_run_command $OPENPILOT_ROOT/tools/replay/replay $@ op_run_command $OPENPILOT_ROOT/tools/replay/replay $@
) )
} }
function op_cabana() {
(set -e
op_before_cmd
op_run_command $OPENPILOT_ROOT/tools/cabana/cabana $@
)
}
function op_sim() {
(set -e
op_before_cmd
op_run_command exec $OPENPILOT_ROOT/tools/sim/run_bridge.py &
op_run_command exec $OPENPILOT_ROOT/tools/sim/launch_openpilot.sh
)
}
function op_default() { function op_default() {
echo "An openpilot helper" echo "An openpilot helper"
echo "" echo ""
@ -242,8 +289,10 @@ function op_default() {
echo -e " ${BOLD}install${NC} Install requirements to use openpilot" echo -e " ${BOLD}install${NC} Install requirements to use openpilot"
echo -e " ${BOLD}build${NC} Build openpilot" echo -e " ${BOLD}build${NC} Build openpilot"
echo -e " ${BOLD}run${NC} Run openpilot" echo -e " ${BOLD}run${NC} Run openpilot"
echo -e " ${BOLD}sim${NC} Run openpilot in a simulator"
echo -e " ${BOLD}juggle${NC} Run Plotjuggler" echo -e " ${BOLD}juggle${NC} Run Plotjuggler"
echo -e " ${BOLD}replay${NC} Run replay" echo -e " ${BOLD}replay${NC} Run replay"
echo -e " ${BOLD}cabana${NC} Run cabana"
echo -e " ${BOLD}linter${NC} Run all the pre-commit checks" echo -e " ${BOLD}linter${NC} Run all the pre-commit checks"
echo -e " ${BOLD}help${NC} Show this message" echo -e " ${BOLD}help${NC} Show this message"
echo -e " ${BOLD}--install${NC} Install this tool system wide" echo -e " ${BOLD}--install${NC} Install this tool system wide"
@ -253,6 +302,8 @@ function op_default() {
echo " Specify the openpilot directory you want to use" echo " Specify the openpilot directory you want to use"
echo -e " ${BOLD}--dry${NC}" echo -e " ${BOLD}--dry${NC}"
echo " Don't actually run anything, just print what would be" echo " Don't actually run anything, just print what would be"
echo -e " ${BOLD}-n, --no-verify${NC}"
echo " Don't run checks before running a command"
echo "" echo ""
echo -e "${BOLD}${UNDERLINE}Examples:${NC}" echo -e "${BOLD}${UNDERLINE}Examples:${NC}"
echo " op --dir /tmp/openpilot check" echo " op --dir /tmp/openpilot check"
@ -273,6 +324,7 @@ function _op() {
case $1 in case $1 in
-d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;;
--dry ) shift 1; DRY="1" ;; --dry ) shift 1; DRY="1" ;;
-n | --no-verify ) shift 1; NO_VERIFY="1" ;;
esac esac
# parse Commands # parse Commands
@ -283,8 +335,10 @@ function _op() {
build ) shift 1; op_build "$@" ;; build ) shift 1; op_build "$@" ;;
run ) shift 1; op_run "$@" ;; run ) shift 1; op_run "$@" ;;
juggle ) shift 1; op_juggle "$@" ;; juggle ) shift 1; op_juggle "$@" ;;
cabana ) shift 1; op_cabana "$@" ;;
linter ) shift 1; op_linter "$@" ;; linter ) shift 1; op_linter "$@" ;;
replay ) shift 1; op_replay "$@" ;; replay ) shift 1; op_replay "$@" ;;
sim ) shift 1; op_sim "$@" ;;
--install ) shift 1; op_first_install "$@" ;; --install ) shift 1; op_first_install "$@" ;;
* ) op_default "$@" ;; * ) op_default "$@" ;;
esac esac
@ -309,5 +363,10 @@ unset -f op_default
unset -f op_run_command unset -f op_run_command
unset -f op_linter unset -f op_linter
unset -f op_replay unset -f op_replay
unset -f op_cabana
unset -f op_check_venv
unset -f op_before_cmd
unset -f op_sim
unset DRY unset DRY
unset OPENPILOT_ROOT unset OPENPILOT_ROOT
unset NO_VERIFY

@ -1,32 +1,59 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
if [ ! -f launch_openpilot.sh ]; then if [ -z "$OPENPILOT_ROOT" ]; then
if [ ! -d openpilot ]; then # default to current directory for installation
git clone --single-branch --recurse-submodules https://github.com/commaai/openpilot.git OPENPILOT_ROOT="$(pwd)/openpilot"
fi fi
cd openpilot
function check_dir() {
echo "Checking for installation directory..."
if [ -d "$OPENPILOT_ROOT" ]; then
echo -e " ↳ [${RED}${NC}] can't install openpilot in $OPENPILOT_ROOT !"
return 1
fi fi
if [[ "$OSTYPE" == "darwin"* ]]; then echo -e " ↳ [${GREEN}${NC}] Successfully chosen $OPENPILOT_ROOT as installation directory\n"
tools/mac_setup.sh }
function check_git() {
echo "Checking for git..."
if ! command -v "git" > /dev/null 2>&1; then
echo -e " ↳ [${RED}${NC}] git not found on your system, can't continue!"
return 1
else else
tools/ubuntu_setup.sh echo -e " ↳ [${GREEN}${NC}] git found.\n"
fi
}
function git_clone() {
echo "Cloning openpilot..."
if $(git clone --depth=1 https://github.com/commaai/openpilot.git "$OPENPILOT_ROOT"); then
if [[ -f $OPENPILOT_ROOT/launch_openpilot.sh ]]; then
echo -e " ↳ [${GREEN}${NC}] Successfully cloned openpilot.\n"
return 0
fi
fi fi
git lfs pull echo -e " ↳ [${RED}${NC}] failed to clone openpilot!"
return 1
}
function install_with_op() {
cd $OPENPILOT_ROOT
$OPENPILOT_ROOT/tools/op.sh --install
$OPENPILOT_ROOT/tools/op.sh install
source .venv/bin/activate # make op usable right now
alias op="source $OPENPILOT_ROOT/tools/op.sh \"\$@\""
}
echo "Building openpilot" check_dir && check_git && git_clone && install_with_op
scons -u -j$(nproc)
echo unset OPENPILOT_ROOT
echo "---- OPENPILOT BUILDING DONE ----" unset RED
echo "To push changes to your fork, run the following commands:" unset GREEN
echo "git remote remove origin" unset NC
echo "git remote add origin git@github.com:<YOUR_USERNAME>/openpilot.git"
echo "git fetch"
echo "git commit -m \"first commit\""
echo "git push"

@ -8,8 +8,3 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
$DIR/install_ubuntu_dependencies.sh $DIR/install_ubuntu_dependencies.sh
$DIR/install_python_dependencies.sh $DIR/install_python_dependencies.sh
echo
echo "---- OPENPILOT SETUP DONE ----"
echo "Open a new shell or configure your active shell env by running:"
echo "source ~/.bashrc"

@ -863,14 +863,14 @@ wheels = [
[[distribution]] [[distribution]]
name = "importlib-metadata" name = "importlib-metadata"
version = "8.0.0" version = "8.2.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "zipp" }, { name = "zipp" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/20/ff/bd28f70283b9cca0cbf0c2a6082acbecd822d1962ae7b2a904861b9965f8/importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812", size = 52667 } sdist = { url = "https://files.pythonhosted.org/packages/f6/a1/db39a513aa99ab3442010a994eef1cb977a436aded53042e69bee6959f74/importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d", size = 53907 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/ef/38766b2edb096260d9b1b6ad35adaa0bce3b0567abb452b21eb074af88c4/importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f", size = 24769 }, { url = "https://files.pythonhosted.org/packages/82/47/bb25ec04985d0693da478797c3d8c1092b140f3a53ccb984fbbd38affa5b/importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369", size = 25920 },
] ]
[[distribution]] [[distribution]]
@ -1059,11 +1059,11 @@ wheels = [
[[distribution]] [[distribution]]
name = "markdown" name = "markdown"
version = "3.6" version = "3.3.7"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/22/02/4785861427848cc11e452cc62bb541006a1087cf04a1de83aedd5530b948/Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224", size = 354715 } sdist = { url = "https://files.pythonhosted.org/packages/d6/58/79df20de6e67a83f0d0bbfe6c19bb82adf68cdf362885257eb01099f930a/Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", size = 324130 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f", size = 105381 }, { url = "https://files.pythonhosted.org/packages/f3/df/ca72f352e15b6f8ce32b74af029f1189abffb906f7c137501ffe69c98a65/Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621", size = 97778 },
] ]
[[distribution]] [[distribution]]
@ -1196,9 +1196,18 @@ dependencies = [
{ name = "yapf" }, { name = "yapf" },
] ]
[[distribution]]
name = "mistletoe"
version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/11/96/ea46a376a7c4cd56955ecdfff0ea68de43996a4e6d1aee4599729453bd11/mistletoe-1.4.0.tar.gz", hash = "sha256:1630f906e5e4bbe66fdeb4d29d277e2ea515d642bb18a9b49b136361a9818c9d", size = 107203 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/0f/b5e545f0c7962be90366af3418989b12cf441d9da1e5d89d88f2f3e5cf8f/mistletoe-1.4.0-py3-none-any.whl", hash = "sha256:44a477803861de1237ba22e375c6b617690a31d2902b47279d1f8f7ed498a794", size = 51304 },
]
[[distribution]] [[distribution]]
name = "mkdocs" name = "mkdocs"
version = "1.6.0" version = "1.4.3"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "click" }, { name = "click" },
@ -1206,32 +1215,29 @@ dependencies = [
{ name = "ghp-import" }, { name = "ghp-import" },
{ name = "jinja2" }, { name = "jinja2" },
{ name = "markdown" }, { name = "markdown" },
{ name = "markupsafe" },
{ name = "mergedeep" }, { name = "mergedeep" },
{ name = "mkdocs-get-deps" },
{ name = "packaging" }, { name = "packaging" },
{ name = "pathspec" },
{ name = "pyyaml" }, { name = "pyyaml" },
{ name = "pyyaml-env-tag" }, { name = "pyyaml-env-tag" },
{ name = "watchdog" }, { name = "watchdog" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/cc/6b/26b33cc8ad54e8bc0345cddc061c2c5c23e364de0ecd97969df23f95a673/mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512", size = 3888392 } sdist = { url = "https://files.pythonhosted.org/packages/b0/ef/49b4427e5eec761b77a3c3c421d3fd63010e2798b7401dc0fa2b875ef6b5/mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57", size = 3624951 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/b8/c0/930dcf5a3e96b9c8e7ad15502603fc61d495479699e2d2c381e3d37294d1/mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7", size = 3862264 }, { url = "https://files.pythonhosted.org/packages/42/7a/5ed794942ace9d00bb77a8036c64c999cda6ebaab57e9b8a6ec1aa5fc900/mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd", size = 3654464 },
] ]
[[distribution]] [[distribution]]
name = "mkdocs-get-deps" name = "mkdocs-plugin-commonmark"
version = "0.2.0" version = "0.0.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "mergedeep" }, { name = "markdown" },
{ name = "platformdirs" }, { name = "mistletoe" },
{ name = "pyyaml" }, { name = "mkdocs" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } sdist = { url = "https://files.pythonhosted.org/packages/fa/a1/4aaa744deec61d75dbe3c67c18f6e4c1fa7699bc2661b6eff5f891e83023/mkdocs-plugin-commonmark-0.0.4.tar.gz", hash = "sha256:9034507af26646e95188a130782dd07d65c86507fddd3b47ea340c02683e85e7", size = 10805 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, { url = "https://files.pythonhosted.org/packages/f9/4a/4333ef1eb57ff130c7715ba0847dbdae471d153d94507004c92c591cb3c5/mkdocs_plugin_commonmark-0.0.4-py3-none-any.whl", hash = "sha256:70a33394d86a04ec97877ca1b2dff6181de3ec01ef4c7add178fa45b327da535", size = 12532 },
] ]
[[distribution]] [[distribution]]
@ -1585,6 +1591,7 @@ dev = [
{ name = "pyopencl", marker = "platform_machine != 'aarch64'" }, { name = "pyopencl", marker = "platform_machine != 'aarch64'" },
{ name = "pyprof2calltree" }, { name = "pyprof2calltree" },
{ name = "pyqt5", marker = "platform_machine == 'x86_64'" }, { name = "pyqt5", marker = "platform_machine == 'x86_64'" },
{ name = "pytools", marker = "platform_machine != 'aarch64'" },
{ name = "pywinctl" }, { name = "pywinctl" },
{ name = "rerun-sdk" }, { name = "rerun-sdk" },
{ name = "tabulate" }, { name = "tabulate" },
@ -1594,6 +1601,7 @@ dev = [
docs = [ docs = [
{ name = "jinja2" }, { name = "jinja2" },
{ name = "mkdocs" }, { name = "mkdocs" },
{ name = "mkdocs-plugin-commonmark" },
{ name = "mkdocs-terminal" }, { name = "mkdocs-terminal" },
] ]
testing = [ testing = [
@ -1705,15 +1713,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354 }, { url = "https://files.pythonhosted.org/packages/31/13/fe468c8c7400a8eca204e6e160a29bf7dcd45a76e20f1c030f3eaa690d93/parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9", size = 26354 },
] ]
[[distribution]]
name = "pathspec"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
]
[[distribution]] [[distribution]]
name = "pillow" name = "pillow"
version = "10.4.0" version = "10.4.0"
@ -2042,15 +2041,15 @@ wheels = [
[[distribution]] [[distribution]]
name = "pymdown-extensions" name = "pymdown-extensions"
version = "10.8.1" version = "10.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "markdown" }, { name = "markdown" },
{ name = "pyyaml" }, { name = "pyyaml" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/09/11/0a1da270c1011194a6efee7ec1ac07d8b75a9706eed4a80675403f6a9d70/pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940", size = 812097 } sdist = { url = "https://files.pythonhosted.org/packages/85/71/5f48080bde77b07ca1eba6d7cb5c5598ac6c8f2a399846159b3c8b45e171/pymdown_extensions-10.4.tar.gz", hash = "sha256:bc46f11749ecd4d6b71cf62396104b4a200bad3498cb0f5dad1b8502fe461a35", size = 785151 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/c6/d7/e19f9bee2729a8d65b9bf822bb69ac364bf782bac8d761c62b4252769ae0/pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb", size = 250833 }, { url = "https://files.pythonhosted.org/packages/98/2d/2929de81618c7213176899dd6372d6ec9c8f24337841dd74634fb69864ae/pymdown_extensions-10.4-py3-none-any.whl", hash = "sha256:cfc28d6a09d19448bcbf8eee3ce098c7d17ff99f7bd3069db4819af181212037", size = 240838 },
] ]
[[distribution]] [[distribution]]
@ -4705,7 +4704,7 @@ wheels = [
[[distribution]] [[distribution]]
name = "pytest" name = "pytest"
version = "8.3.1" version = "8.3.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" }, { name = "colorama", marker = "sys_platform == 'win32'" },
@ -4713,9 +4712,9 @@ dependencies = [
{ name = "packaging" }, { name = "packaging" },
{ name = "pluggy" }, { name = "pluggy" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/bc/7f/a6f79e033aa8318b6dfe2173fa6409ee75dafccf409d90884bf921433d88/pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6", size = 1438997 } sdist = { url = "https://files.pythonhosted.org/packages/b4/8c/9862305bdcd6020bc7b45b1b5e7397a6caf1a33d3025b9a003b39075ffb2/pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce", size = 1439314 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/77/ccea391104f576a6e54a54334fc26d29c28aa0ec85714c781fbd2c34ac86/pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c", size = 341628 }, { url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802 },
] ]
[[distribution]] [[distribution]]
@ -5049,27 +5048,27 @@ wheels = [
[[distribution]] [[distribution]]
name = "ruff" name = "ruff"
version = "0.5.4" version = "0.5.5"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8e/1a/5955fa22ab088c1f4d8458b4cbc158c6db72143361e8d46e179c48576aab/ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed", size = 2424702 } sdist = { url = "https://files.pythonhosted.org/packages/95/15/3945cfecfd3de874633d2466327ebb01eabf4f61f962a0dd4bf5ce2dc997/ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a", size = 2434890 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/34/2235ecce6794345f42ad334d1b14384c70b202f77509e5678b68a640fe78/ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf", size = 9499774 }, { url = "https://files.pythonhosted.org/packages/2c/4d/f9e5e37369b22d74588fe496e82d2aa2fff508f0c05b34c38374194f5a8e/ruff-0.5.5-py3-none-linux_armv6l.whl", hash = "sha256:605d589ec35d1da9213a9d4d7e7a9c761d90bba78fc8790d1c5e65026c1b9eaf", size = 9505926 },
{ url = "https://files.pythonhosted.org/packages/11/23/ffe51028ba274223191d3f96b059108cf7690eb93985a7fdb077c3d1191b/ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be", size = 8550240 }, { url = "https://files.pythonhosted.org/packages/b3/48/ee53a87351dd03472cf1cb8073019a53a7282e4295e7ae62d7f5ae24202a/ruff-0.5.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00817603822a3e42b80f7c3298c8269e09f889ee94640cd1fc7f9329788d7bf8", size = 8585187 },
{ url = "https://files.pythonhosted.org/packages/28/75/843aa3d10a39ab60fbd63f65c825f647907a9732ac27e24d3f94dd2db618/ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059", size = 8160520 }, { url = "https://files.pythonhosted.org/packages/a2/ec/2c0bd5ec0965672bb2957abf6e44d93c2c7aab2ceb4251ea77eb9234ffd3/ruff-0.5.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:187a60f555e9f865a2ff2c6984b9afeffa7158ba6e1eab56cb830404c942b0f3", size = 8175846 },
{ url = "https://files.pythonhosted.org/packages/19/88/3d0f5244905088cc2fd136fae8ce81f46d145e2449051313c462032d144d/ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19", size = 9911606 }, { url = "https://files.pythonhosted.org/packages/8d/d7/e476f96c013d59af08b7b155f2beee03e7595915718573c724a01681bea8/ruff-0.5.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe26fc46fa8c6e0ae3f47ddccfbb136253c831c3289bba044befe68f467bfb16", size = 9948714 },
{ url = "https://files.pythonhosted.org/packages/1f/ff/6546020836408351e7558dedacc6e5ca7f652f76a9d05ac4882c787d45b1/ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793", size = 9286353 }, { url = "https://files.pythonhosted.org/packages/dd/da/00269f4905b5ceab77f64ec9ed2e8f848ccba68884b66b2423c9f8962878/ruff-0.5.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad25dd9c5faac95c8e9efb13e15803cd8bbf7f4600645a60ffe17c73f60779b", size = 9299822 },
{ url = "https://files.pythonhosted.org/packages/b6/bf/51e0c5f12a9bf3c7596cf7f45e1b102f8b49f1da39943e03739890bbf6a4/ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278", size = 10082929 }, { url = "https://files.pythonhosted.org/packages/c3/ce/8784906480809b5b43cfbb346bddcc3b9e8716fd73927e4d70fb5260c18e/ruff-0.5.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f70737c157d7edf749bcb952d13854e8f745cec695a01bdc6e29c29c288fc36e", size = 10100197 },
{ url = "https://files.pythonhosted.org/packages/b5/0e/a44cb6edb629788de892fc7bb8ac8b47059df94d7ec9c4e52e04bab5be95/ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7", size = 10832586 }, { url = "https://files.pythonhosted.org/packages/42/a4/4f4796e6b440ed42ec8486e19fe9b9489d94f13c2debf49e68ed58af5d0b/ruff-0.5.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfd7de17cef6ab559e9f5ab859f0d3296393bc78f69030967ca4d87a541b97a0", size = 10813891 },
{ url = "https://files.pythonhosted.org/packages/97/ca/e3810f701ae472e5fe3180d56fe6fcc92ea94c7490097a0f731f5602f26f/ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60", size = 10421967 }, { url = "https://files.pythonhosted.org/packages/a0/a4/9a0084212e0b2810beadd993f1b36f156438465a4d4193fd5bb2ab833892/ruff-0.5.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09b43e02f76ac0145f86a08e045e2ea452066f7ba064fd6b0cdccb486f7c3e7", size = 10439725 },
{ url = "https://files.pythonhosted.org/packages/01/47/a62df6ccd6e5d019271df203ea6564f2022c49f85c0bf6ada708cd7b4a5e/ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1", size = 11371031 }, { url = "https://files.pythonhosted.org/packages/8e/f7/4480e739af49f66f04edf2b1dd7ac6fa5e55639491e47267dbfa70d62488/ruff-0.5.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0b856cb19c60cd40198be5d8d4b556228e3dcd545b4f423d1ad812bfdca5884", size = 11358405 },
{ url = "https://files.pythonhosted.org/packages/a1/02/64f24893eea23c447460e6509e9dd0ae18d7a797f67fee1bafed964ebbae/ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516", size = 10103164 }, { url = "https://files.pythonhosted.org/packages/0e/fd/7a6e01b8098c3375ce694427956a8192c708941051cebd279b988304a753/ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091", size = 10130793 },
{ url = "https://files.pythonhosted.org/packages/ca/78/683b6c6976fcc33e4a03a0e234e0b9f9b8682f807a661225c829b248de82/ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc", size = 9920056 }, { url = "https://files.pythonhosted.org/packages/2f/4a/ba83ca67da7e81a8a191da36f3f6a350243210518c78c2e809fb25cac6c4/ruff-0.5.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ac9dc814e510436e30d0ba535f435a7f3dc97f895f844f5b3f347ec8c228a523", size = 9910666 },
{ url = "https://files.pythonhosted.org/packages/78/3a/6c67c5d670aae2a51a11713aff819d729ed92cb0b1d962b8df27e4657650/ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f", size = 9361286 }, { url = "https://files.pythonhosted.org/packages/3f/6d/c982a93907559fa5cb62fd68c74b21662a4f088a09ad27f813244c7379c1/ruff-0.5.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:af9bdf6c389b5add40d89b201425b531e0a5cceb3cfdcc69f04d3d531c6be74f", size = 9365153 },
{ url = "https://files.pythonhosted.org/packages/0d/f5/da3a0e2fd0bcbdb3d2ff579ef9cb3ca2af71b9bee97fa917c9a9e0500b67/ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7", size = 9720829 }, { url = "https://files.pythonhosted.org/packages/be/a6/b3dbdb4505086d80ab8202c8592ad90a811fc328dc4a5966e065cda12dcc/ruff-0.5.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d40a8533ed545390ef8315b8e25c4bb85739b90bd0f3fe1280a29ae364cc55d8", size = 9736802 },
{ url = "https://files.pythonhosted.org/packages/4a/56/5062119a5c9e06d98cd6406bfc1eab7616a7c67494a4d05b6052d99dd147/ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff", size = 10143530 }, { url = "https://files.pythonhosted.org/packages/4d/ba/b850fa0925ce59bc0bce412d18a9633a92126f23153f970437a51be711f0/ruff-0.5.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cab904683bf9e2ecbbe9ff235bfe056f0eba754d0168ad5407832928d579e7ab", size = 10198368 },
{ url = "https://files.pythonhosted.org/packages/e6/76/16f8f1c8d0cba6c96ab6f292146fc0acb6dd633a989f524d3b3ef1ee8364/ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e", size = 7794271 }, { url = "https://files.pythonhosted.org/packages/56/db/a9162178c90cada13f4c9bed9860947a1c5a79d7ecadd27250c67681dc81/ruff-0.5.5-py3-none-win32.whl", hash = "sha256:696f18463b47a94575db635ebb4c178188645636f05e934fdf361b74edf1bb2d", size = 7798506 },
{ url = "https://files.pythonhosted.org/packages/82/35/d6c3c83fb8817328db73c15b1836ccb0c3ce56b72d0d01d98b3a452bec58/ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4", size = 8579021 }, { url = "https://files.pythonhosted.org/packages/c9/5b/13288039ea8190c121b70f1a11be2c4830cb3ebb57dc91d91fc5d3c65fc6/ruff-0.5.5-py3-none-win_amd64.whl", hash = "sha256:50f36d77f52d4c9c2f1361ccbfbd09099a1b2ea5d2b2222c586ab08885cf3445", size = 8611739 },
{ url = "https://files.pythonhosted.org/packages/3c/ef/3e732c0152280775f728ab99691c718ee9a4ae79bf5af1dd9258f7fe7fef/ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7", size = 8034239 }, { url = "https://files.pythonhosted.org/packages/ba/b3/525847f73ab956053b130ec9f5d1ea078d94282b1d5eda90c09b8a81a935/ruff-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3191317d967af701f1b73a31ed5788795936e423b7acce82a2b63e26eb3e89d6", size = 8039120 },
] ]
[[distribution]] [[distribution]]
@ -5124,15 +5123,15 @@ wheels = [
[[distribution]] [[distribution]]
name = "sentry-sdk" name = "sentry-sdk"
version = "2.10.0" version = "2.11.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "certifi" }, { name = "certifi" },
{ name = "urllib3" }, { name = "urllib3" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/34/d8/ec3e43d4ce31e4f4cb6adb7210950362d71ce87a96c89934c4ac94f7110f/sentry_sdk-2.10.0.tar.gz", hash = "sha256:545fcc6e36c335faa6d6cda84669b6e17025f31efbf3b2211ec14efe008b75d1", size = 273996 } sdist = { url = "https://files.pythonhosted.org/packages/6d/b3/39e4cd04b75a1ada788342d0d30a781cf65b5e43da806d5bf2bad4846ea3/sentry_sdk-2.11.0.tar.gz", hash = "sha256:4ca16e9f5c7c6bc2fb2d5c956219f4926b148e511fffdbbde711dc94f1e0468f", size = 276242 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/4f/9e/9298785949269c8930e1fd3707b960da6e1a95a2442b747b8f8cca4578cb/sentry_sdk-2.10.0-py2.py3-none-any.whl", hash = "sha256:87b3d413c87d8e7f816cc9334bff255a83d8b577db2b22042651c30c19c09190", size = 302064 }, { url = "https://files.pythonhosted.org/packages/bc/3c/a8ab3309d22c1d7142f811882e7d45449696f87c6e4e723b1433b6069b84/sentry_sdk-2.11.0-py2.py3-none-any.whl", hash = "sha256:d964710e2dbe015d9dc4ff0ad16225d68c3b36936b742a6fe0504565b760a3b7", size = 303581 },
] ]
[[distribution]] [[distribution]]

Loading…
Cancel
Save