mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 00:53:45 +08:00
Camera
Coordinate finite camera leases with manager-owned processes and reject frames that predate a request. Preserve the native frame timestamp contract across camera variants.
This commit is contained in:
@@ -4,5 +4,5 @@ libs = [common, messaging, visionipc]
|
||||
|
||||
if arch != "Darwin":
|
||||
camera_obj = env.Object(['cameras/camera_qcom2.cc', 'cameras/camera_common.cc', 'cameras/spectra.cc',
|
||||
'cameras/cdm.cc', 'sensors/ox03c10.cc', 'sensors/os04c10.cc'])
|
||||
'cameras/cdm.cc', 'sensors/ar0231.cc', 'sensors/ox03c10.cc', 'sensors/os04c10.cc'])
|
||||
env.Program('camerad', ['main.cc', camera_obj], LIBS=libs)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -20,6 +20,10 @@
|
||||
#include "system/camerad/cameras/bps_blobs.h"
|
||||
|
||||
|
||||
static bool uses_legacy_bps_config(const SensorInfo *sensor) {
|
||||
return sensor->image_sensor == cereal::FrameData::ImageSensor::AR0231;
|
||||
}
|
||||
|
||||
// ************** low level camera helpers ****************
|
||||
|
||||
int do_cam_control(int fd, int op_code, void *handle, int size) {
|
||||
@@ -465,9 +469,10 @@ void SpectraCamera::config_bps(int idx, int request_id) {
|
||||
* BPS = Bayer Processing Segment
|
||||
*/
|
||||
|
||||
bool needs_downscale = sensor->out_scale > 1;
|
||||
const bool legacy_bps = uses_legacy_bps_config(sensor.get());
|
||||
bool needs_downscale = !legacy_bps && sensor->out_scale > 1;
|
||||
int num_io_cfgs = needs_downscale ? 3 : 2;
|
||||
int num_patches = needs_downscale ? 14 : 12;
|
||||
int num_patches = legacy_bps ? 9 : (needs_downscale ? 14 : 12);
|
||||
int size = sizeof(struct cam_packet) + sizeof(struct cam_cmd_buf_desc)*2 + sizeof(struct cam_buf_io_cfg)*num_io_cfgs;
|
||||
size += sizeof(struct cam_patch_desc)*num_patches;
|
||||
|
||||
@@ -547,15 +552,21 @@ void SpectraCamera::config_bps(int idx, int request_id) {
|
||||
int cdm_len = 0;
|
||||
|
||||
if (bps_lin_reg.size() == 0) {
|
||||
// set first knee pt to do BLC
|
||||
uint32_t new_knee[8];
|
||||
new_knee[0] = sensor->black_level << (14 - sensor->bits_per_pixel);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
uint32_t pts = sensor->linearization_pts[i / 2];
|
||||
new_knee[i + 1] = (i % 2 == 0) ? (pts >> 16) : (pts & 0xffff);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bps_lin_reg.push_back((new_knee[2*i + 1] << 16) | new_knee[2*i]);
|
||||
if (legacy_bps) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bps_lin_reg.push_back((sensor->linearization_pts[i] << 16) | (sensor->linearization_pts[i] >> 16));
|
||||
}
|
||||
} else {
|
||||
// set first knee pt to do BLC
|
||||
uint32_t new_knee[8];
|
||||
new_knee[0] = sensor->black_level << (14 - sensor->bits_per_pixel);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
uint32_t pts = sensor->linearization_pts[i / 2];
|
||||
new_knee[i + 1] = (i % 2 == 0) ? (pts >> 16) : (pts & 0xffff);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bps_lin_reg.push_back((new_knee[2*i + 1] << 16) | new_knee[2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,16 +595,20 @@ void SpectraCamera::config_bps(int idx, int request_id) {
|
||||
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x1888, bps_lin_reg);
|
||||
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x1898, bps_lin_reg);
|
||||
uint64_t addr;
|
||||
cdm_len += write_dmi((unsigned char *)bps_cdm_program_array.ptr + cdm_len, &addr, sensor->linearization_lut.size()*sizeof(uint32_t), 0x1808, 1, CAM_CDM_CMD_DMI);
|
||||
patches.push_back(addr - (uint64_t)bps_cdm_program_array.ptr);
|
||||
if (!legacy_bps) {
|
||||
cdm_len += write_dmi((unsigned char *)bps_cdm_program_array.ptr + cdm_len, &addr, sensor->linearization_lut.size()*sizeof(uint32_t), 0x1808, 1, CAM_CDM_CMD_DMI);
|
||||
patches.push_back(addr - (uint64_t)bps_cdm_program_array.ptr);
|
||||
}
|
||||
|
||||
// color correction
|
||||
cdm_len += write_cont((unsigned char *)bps_cdm_program_array.ptr + cdm_len, 0x2e68, bps_ccm_reg);
|
||||
|
||||
// gamma
|
||||
for (uint8_t ch = 1; ch <= 3; ch++) {
|
||||
cdm_len += write_dmi((unsigned char *)bps_cdm_program_array.ptr + cdm_len, &addr, sensor->gamma_lut_rgb.size()*sizeof(uint32_t), 0x3208, ch, CAM_CDM_CMD_DMI);
|
||||
patches.push_back(addr - (uint64_t)bps_cdm_program_array.ptr);
|
||||
if (!legacy_bps) {
|
||||
for (uint8_t ch = 1; ch <= 3; ch++) {
|
||||
cdm_len += write_dmi((unsigned char *)bps_cdm_program_array.ptr + cdm_len, &addr, sensor->gamma_lut_rgb.size()*sizeof(uint32_t), 0x3208, ch, CAM_CDM_CMD_DMI);
|
||||
patches.push_back(addr - (uint64_t)bps_cdm_program_array.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
cdm_len += build_common_ife_bps((unsigned char *)bps_cdm_program_array.ptr + cdm_len, cc, sensor.get(), patches, false);
|
||||
@@ -609,7 +624,7 @@ void SpectraCamera::config_bps(int idx, int request_id) {
|
||||
tmp.header = CAM_ICP_CMD_GENERIC_BLOB_CLK;
|
||||
tmp.header |= (sizeof(cam_icp_clk_bw_request)) << 8;
|
||||
tmp.clk.budget_ns = 0x1fca058;
|
||||
tmp.clk.frame_cycles = 20000000; // force max BPS clock (600 MHz)
|
||||
tmp.clk.frame_cycles = legacy_bps ? 2329024 : 20000000; // modern BPS keeps its 600 MHz clock
|
||||
tmp.clk.rt_flag = 0x0;
|
||||
tmp.clk.uncompressed_bw = 0x38512180;
|
||||
tmp.clk.compressed_bw = 0x38512180;
|
||||
@@ -705,7 +720,7 @@ void SpectraCamera::config_bps(int idx, int request_id) {
|
||||
|
||||
// *** patches ***
|
||||
{
|
||||
assert(patches.size() == 0 || patches.size() == 4);
|
||||
assert(legacy_bps ? patches.empty() : (patches.size() == 0 || patches.size() == 4));
|
||||
pkt->patch_offset = sizeof(struct cam_cmd_buf_desc)*pkt->num_cmd_buf + sizeof(struct cam_buf_io_cfg)*pkt->num_io_configs;
|
||||
|
||||
if (patches.size() > 0) {
|
||||
@@ -1047,7 +1062,8 @@ bool SpectraCamera::openSensor() {
|
||||
|
||||
// Figure out which sensor we have
|
||||
if (!init_sensor_lambda(new OS04C10) &&
|
||||
!init_sensor_lambda(new OX03C10)) {
|
||||
!init_sensor_lambda(new OX03C10) &&
|
||||
!init_sensor_lambda(new AR0231)) {
|
||||
LOGE("** sensor %d FAILED bringup, disabling", cc.camera_num);
|
||||
enabled = false;
|
||||
return false;
|
||||
@@ -1166,6 +1182,7 @@ void SpectraCamera::configICP() {
|
||||
*/
|
||||
|
||||
int cfg_handle;
|
||||
const bool legacy_bps = uses_legacy_bps_config(sensor.get());
|
||||
|
||||
uint32_t cfg_size = sizeof(bps_cfg[0]) / sizeof(bps_cfg[0][0]);
|
||||
void *cfg = alloc_w_mmu_hdl(m->video0_fd, cfg_size, (uint32_t*)&cfg_handle, 0x1,
|
||||
@@ -1212,20 +1229,23 @@ void SpectraCamera::configICP() {
|
||||
bps_cdm_program_array.init(m, 0x1000, 0x20, true, m->icp_device_iommu);
|
||||
|
||||
// striping lib output
|
||||
uint32_t striping_size = sizeof(bps_striping_output[0]) / sizeof(bps_striping_output[0][0]);
|
||||
uint32_t striping_size = legacy_bps ? 0x9a0 : sizeof(bps_striping_output[0]) / sizeof(bps_striping_output[0][0]);
|
||||
bps_striping.init(m, striping_size, 0x20, true, m->icp_device_iommu);
|
||||
memcpy(bps_striping.ptr, bps_striping_output[sensor->num()], striping_size);
|
||||
|
||||
// used internally by the BPS, we just allocate it.
|
||||
// size comes from the BPSStripingLib
|
||||
bps_cdm_striping_bl.init(m, 0xcfe0, 0x20, true, m->icp_device_iommu);
|
||||
bps_cdm_striping_bl.init(m, legacy_bps ? 0xa100 : 0xcfe0, 0x20, true, m->icp_device_iommu);
|
||||
|
||||
if (sensor->out_scale > 1) {
|
||||
if (!legacy_bps && sensor->out_scale > 1) {
|
||||
uint32_t full_stride, full_y_h, full_uv_h, full_yuv_size;
|
||||
std::tie(full_stride, full_y_h, full_uv_h, full_yuv_size) = get_nv12_info(sensor->frame_width, sensor->frame_height);
|
||||
bps_fullres_dummy.init(m, full_yuv_size, 0x1000, true, m->icp_device_iommu);
|
||||
}
|
||||
|
||||
// Legacy BPS tables contain the complete processing configuration.
|
||||
if (legacy_bps) return;
|
||||
|
||||
// LUTs
|
||||
assert(sensor->linearization_lut.size() == 36);
|
||||
bps_linearization_lut.init(m, sensor->linearization_lut.size()*sizeof(uint32_t), 0x20, true, m->icp_device_iommu);
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
#include "system/camerad/sensors/sensor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const size_t AR0231_REGISTERS_HEIGHT = 2;
|
||||
// TODO: this extra height is universal and doesn't apply per camera
|
||||
const size_t AR0231_STATS_HEIGHT = 2 + 8;
|
||||
|
||||
const float sensor_analog_gains_AR0231[] = {
|
||||
1.0 / 8.0, 2.0 / 8.0, 2.0 / 7.0, 3.0 / 7.0, // 0, 1, 2, 3
|
||||
3.0 / 6.0, 4.0 / 6.0, 4.0 / 5.0, 5.0 / 5.0, // 4, 5, 6, 7
|
||||
5.0 / 4.0, 6.0 / 4.0, 6.0 / 3.0, 7.0 / 3.0, // 8, 9, 10, 11
|
||||
7.0 / 2.0, 8.0 / 2.0, 8.0 / 1.0}; // 12, 13, 14, 15 = bypass
|
||||
|
||||
} // namespace
|
||||
|
||||
AR0231::AR0231() {
|
||||
image_sensor = cereal::FrameData::ImageSensor::AR0231;
|
||||
bayer_pattern = CAM_ISP_PATTERN_BAYER_GRGRGR;
|
||||
pixel_size_mm = 0.003;
|
||||
data_word = true;
|
||||
frame_width = 1928;
|
||||
frame_height = 1208;
|
||||
frame_stride = (frame_width * 12 / 8) + 4;
|
||||
extra_height = AR0231_REGISTERS_HEIGHT + AR0231_STATS_HEIGHT;
|
||||
|
||||
registers_offset = 0;
|
||||
frame_offset = AR0231_REGISTERS_HEIGHT;
|
||||
stats_offset = AR0231_REGISTERS_HEIGHT + frame_height;
|
||||
|
||||
start_reg_array.assign(std::begin(start_reg_array_ar0231), std::end(start_reg_array_ar0231));
|
||||
init_reg_array.assign(std::begin(init_array_ar0231), std::end(init_array_ar0231));
|
||||
probe_reg_addr = 0x3000;
|
||||
probe_expected_data = 0x354;
|
||||
bits_per_pixel = 12;
|
||||
mipi_format = CAM_FORMAT_MIPI_RAW_12;
|
||||
frame_data_type = 0x12; // Changing stats to 0x2C doesn't work, so change pixels to 0x12 instead
|
||||
mclk_frequency = 19200000; //Hz
|
||||
|
||||
readout_time_ns = 22850000;
|
||||
|
||||
dc_gain_factor = 2.5;
|
||||
dc_gain_min_weight = 0;
|
||||
dc_gain_max_weight = 1;
|
||||
dc_gain_on_grey = 0.2;
|
||||
dc_gain_off_grey = 0.3;
|
||||
exposure_time_min = 2; // with HDR, fastest ss
|
||||
exposure_time_max = 0x0855; // with HDR, slowest ss, 40ms
|
||||
analog_gain_min_idx = 0x1; // 0.25x
|
||||
analog_gain_rec_idx = 0x6; // 0.8x
|
||||
analog_gain_max_idx = 0xD; // 4.0x
|
||||
analog_gain_cost_delta = 0;
|
||||
analog_gain_cost_low = 0.1;
|
||||
analog_gain_cost_high = 5.0;
|
||||
for (int i = 0; i <= analog_gain_max_idx; i++) {
|
||||
sensor_analog_gains[i] = sensor_analog_gains_AR0231[i];
|
||||
}
|
||||
min_ev = exposure_time_min * sensor_analog_gains[analog_gain_min_idx];
|
||||
max_ev = exposure_time_max * dc_gain_factor * sensor_analog_gains[analog_gain_max_idx];
|
||||
target_grey_factor = 1.0;
|
||||
|
||||
black_level = 168;
|
||||
color_correct_matrix = {
|
||||
0x000000af, 0x00000ff9, 0x00000fd8,
|
||||
0x00000fbc, 0x000000bb, 0x00000009,
|
||||
0x00000fb6, 0x00000fe0, 0x000000ea,
|
||||
};
|
||||
for (int i = 0; i < 65; i++) {
|
||||
float fx = i / 64.0;
|
||||
const float gamma_k = 0.75;
|
||||
const float gamma_b = 0.125;
|
||||
const float mp = 0.01; // ideally midpoint should be adaptive
|
||||
const float rk = 9 - 100*mp;
|
||||
// poly approximation for s curve
|
||||
fx = (fx > mp) ?
|
||||
((rk * (fx-mp) * (1-(gamma_k*mp+gamma_b)) * (1+1/(rk*(1-mp))) / (1+rk*(fx-mp))) + gamma_k*mp + gamma_b) :
|
||||
((rk * (fx-mp) * (gamma_k*mp+gamma_b) * (1+1/(rk*mp)) / (1-rk*(fx-mp))) + gamma_k*mp + gamma_b);
|
||||
gamma_lut_rgb.push_back((uint32_t)(fx*1023.0 + 0.5));
|
||||
}
|
||||
prepare_gamma_lut();
|
||||
linearization_lut = {
|
||||
0x02000000, 0x02000000, 0x02000000, 0x02000000,
|
||||
0x020007ff, 0x020007ff, 0x020007ff, 0x020007ff,
|
||||
0x02000bff, 0x02000bff, 0x02000bff, 0x02000bff,
|
||||
0x020017ff, 0x020017ff, 0x020017ff, 0x020017ff,
|
||||
0x02001bff, 0x02001bff, 0x02001bff, 0x02001bff,
|
||||
0x020023ff, 0x020023ff, 0x020023ff, 0x020023ff,
|
||||
0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
};
|
||||
linearization_pts = {0x07ff0bff, 0x17ff1bff, 0x23ff3fff, 0x3fff3fff};
|
||||
vignetting_lut = {
|
||||
0x00eaa755, 0x00cf2679, 0x00bc05e0, 0x00acc566, 0x00a1450a, 0x009984cc, 0x0095a4ad, 0x009584ac, 0x009944ca, 0x00a0c506, 0x00ac0560, 0x00bb25d9, 0x00ce2671, 0x00e90748, 0x01112889, 0x014a2a51, 0x01984cc2,
|
||||
0x00db06d8, 0x00c30618, 0x00afe57f, 0x00a0a505, 0x009524a9, 0x008d646b, 0x0089844c, 0x0089644b, 0x008d2469, 0x0094a4a5, 0x009fe4ff, 0x00af0578, 0x00c20610, 0x00d986cc, 0x00fda7ed, 0x01320990, 0x017aebd7,
|
||||
0x00d1868c, 0x00baa5d5, 0x00a7853c, 0x009844c2, 0x008cc466, 0x0085a42d, 0x0083641b, 0x0083641b, 0x0085842c, 0x008c4462, 0x0097a4bd, 0x00a6c536, 0x00b9a5cd, 0x00d06683, 0x00f1678b, 0x01226913, 0x0167ab3d,
|
||||
0x00cd0668, 0x00b625b1, 0x00a30518, 0x0093c49e, 0x00884442, 0x00830418, 0x0080e407, 0x0080c406, 0x0082e417, 0x0087c43e, 0x00932499, 0x00a22511, 0x00b525a9, 0x00cbe65f, 0x00eb0758, 0x011a68d3, 0x015daaed,
|
||||
0x00cc4662, 0x00b565ab, 0x00a24512, 0x00930498, 0x0087843c, 0x0082a415, 0x00806403, 0x00806403, 0x00828414, 0x00870438, 0x00926493, 0x00a1850c, 0x00b465a3, 0x00cb2659, 0x00ea2751, 0x011928c9, 0x015c2ae1,
|
||||
0x00cf667b, 0x00b885c4, 0x00a5652b, 0x009624b1, 0x008aa455, 0x00846423, 0x00822411, 0x00822411, 0x00844422, 0x008a2451, 0x009564ab, 0x00a48524, 0x00b785bc, 0x00ce4672, 0x00ee6773, 0x011e88f4, 0x0162eb17,
|
||||
0x00d6c6b6, 0x00bf65fb, 0x00ac4562, 0x009d04e8, 0x0091848c, 0x0089c44e, 0x00862431, 0x00860430, 0x0089844c, 0x00910488, 0x009c64e3, 0x00ab655b, 0x00be65f3, 0x00d566ab, 0x00f847c2, 0x012b2959, 0x01726b93,
|
||||
0x00e3e71f, 0x00ca0650, 0x00b705b8, 0x00a7a53d, 0x009c24e1, 0x009484a4, 0x00908484, 0x00908484, 0x009424a1, 0x009bc4de, 0x00a70538, 0x00b625b1, 0x00c90648, 0x00e26713, 0x0108e847, 0x013fe9ff, 0x018bcc5e,
|
||||
0x00f807c0, 0x00d966cb, 0x00c5862c, 0x00b625b1, 0x00aaa555, 0x00a30518, 0x009f04f8, 0x009f04f8, 0x00a2a515, 0x00aa2551, 0x00b585ac, 0x00c4a625, 0x00d846c2, 0x00f647b2, 0x0121a90d, 0x015e4af2, 0x01b8cdc6,
|
||||
0x011548aa, 0x00f1678b, 0x00d886c4, 0x00c86643, 0x00bce5e7, 0x00b545aa, 0x00b1658b, 0x00b1458a, 0x00b505a8, 0x00bc85e4, 0x00c7c63e, 0x00d786bc, 0x00efe77f, 0x0113489a, 0x0144ea27, 0x01888c44, 0x01fdcfee,
|
||||
0x013e49f2, 0x0113e89f, 0x00f5a7ad, 0x00e0c706, 0x00d30698, 0x00cb665b, 0x00c7663b, 0x00c7663b, 0x00cb0658, 0x00d2a695, 0x00dfe6ff, 0x00f467a3, 0x01122891, 0x013be9df, 0x01750ba8, 0x01cfae7d, 0x025912c8,
|
||||
0x01766bb3, 0x01446a23, 0x011fc8fe, 0x0105e82f, 0x00f467a3, 0x00e9874c, 0x00e46723, 0x00e44722, 0x00e92749, 0x00f3a79d, 0x0104c826, 0x011e48f2, 0x01424a12, 0x01738b9c, 0x01bf6dfb, 0x023611b0, 0x02ced676,
|
||||
0x01cf8e7c, 0x01866c33, 0x015aaad5, 0x013ae9d7, 0x01250928, 0x011768bb, 0x0110a885, 0x01108884, 0x0116e8b7, 0x01242921, 0x0139a9cd, 0x0158eac7, 0x01840c20, 0x01cb0e58, 0x0233719b, 0x02b9d5ce, 0x03645b22,
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<i2c_random_wr_payload> AR0231::getExposureRegisters(int exposure_time, int new_exp_g, bool dc_gain_enabled) const {
|
||||
uint16_t analog_gain_reg = 0xFF00 | (new_exp_g << 4) | new_exp_g;
|
||||
return {
|
||||
{0x3366, analog_gain_reg},
|
||||
{0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)},
|
||||
{0x3012, (uint16_t)exposure_time},
|
||||
};
|
||||
}
|
||||
|
||||
int AR0231::getSlaveAddress(int port) const {
|
||||
assert(port >= 0 && port <= 2);
|
||||
return (int[]){0x20, 0x30, 0x20}[port];
|
||||
}
|
||||
|
||||
float AR0231::getExposureScore(float desired_ev, int exp_t, int exp_g_idx, float exp_gain, int gain_idx) const {
|
||||
// Cost of ev diff
|
||||
float score = std::abs(desired_ev - (exp_t * exp_gain)) * 10;
|
||||
// Cost of absolute gain
|
||||
float m = exp_g_idx > analog_gain_rec_idx ? analog_gain_cost_high : analog_gain_cost_low;
|
||||
score += std::abs(exp_g_idx - (int)analog_gain_rec_idx) * m;
|
||||
// Cost of changing gain
|
||||
score += std::abs(exp_g_idx - gain_idx) * (score + 1.0) / 10.0;
|
||||
return score;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
const struct i2c_random_wr_payload start_reg_array_ar0231[] = {{0x301A, 0x91C}};
|
||||
const struct i2c_random_wr_payload stop_reg_array_ar0231[] = {{0x301A, 0x918}};
|
||||
|
||||
const struct i2c_random_wr_payload init_array_ar0231[] = {
|
||||
{0x301A, 0x0018}, // RESET_REGISTER
|
||||
|
||||
// **NOTE**: if this is changed, readout_time_ns must be updated in the Sensor config
|
||||
|
||||
// CLOCK Settings
|
||||
// input clock is 19.2 / 2 * 0x37 = 528 MHz
|
||||
// pixclk is 528 / 6 = 88 MHz
|
||||
// full roll time is 1000/(PIXCLK/(LINE_LENGTH_PCK*FRAME_LENGTH_LINES)) = 39.99 ms
|
||||
// img roll time is 1000/(PIXCLK/(LINE_LENGTH_PCK*Y_OUTPUT_CONTROL)) = 22.85 ms
|
||||
{0x302A, 0x0006}, // VT_PIX_CLK_DIV
|
||||
{0x302C, 0x0001}, // VT_SYS_CLK_DIV
|
||||
{0x302E, 0x0002}, // PRE_PLL_CLK_DIV
|
||||
{0x3030, 0x0037}, // PLL_MULTIPLIER
|
||||
{0x3036, 0x000C}, // OP_PIX_CLK_DIV
|
||||
{0x3038, 0x0001}, // OP_SYS_CLK_DIV
|
||||
|
||||
// FORMAT
|
||||
{0x3040, 0xC000}, // READ_MODE
|
||||
{0x3004, 0x0000}, // X_ADDR_START_
|
||||
{0x3008, 0x0787}, // X_ADDR_END_
|
||||
{0x3002, 0x0000}, // Y_ADDR_START_
|
||||
{0x3006, 0x04B7}, // Y_ADDR_END_
|
||||
{0x3032, 0x0000}, // SCALING_MODE
|
||||
{0x30A2, 0x0001}, // X_ODD_INC_
|
||||
{0x30A6, 0x0001}, // Y_ODD_INC_
|
||||
{0x3402, 0x0788}, // X_OUTPUT_CONTROL
|
||||
{0x3404, 0x04B8}, // Y_OUTPUT_CONTROL
|
||||
{0x3064, 0x1982}, // SMIA_TEST
|
||||
{0x30BA, 0x11F2}, // DIGITAL_CTRL
|
||||
|
||||
// Enable external trigger and disable GPIO outputs
|
||||
{0x30CE, 0x0120}, // SLAVE_SH_SYNC_MODE | FRAME_START_MODE
|
||||
{0x340A, 0xE0}, // GPIO3_INPUT_DISABLE | GPIO2_INPUT_DISABLE | GPIO1_INPUT_DISABLE
|
||||
{0x340C, 0x802}, // GPIO_HIDRV_EN | GPIO0_ISEL=2
|
||||
|
||||
// Readout timing
|
||||
{0x300C, 0x0672}, // LINE_LENGTH_PCK (valid for 3-exposure HDR)
|
||||
{0x300A, 0x0855}, // FRAME_LENGTH_LINES
|
||||
{0x3042, 0x0000}, // EXTRA_DELAY
|
||||
|
||||
// Readout Settings
|
||||
{0x31AE, 0x0204}, // SERIAL_FORMAT, 4-lane MIPI
|
||||
{0x31AC, 0x0C0C}, // DATA_FORMAT_BITS, 12 -> 12
|
||||
{0x3342, 0x1212}, // MIPI_F1_PDT_EDT
|
||||
{0x3346, 0x1212}, // MIPI_F2_PDT_EDT
|
||||
{0x334A, 0x1212}, // MIPI_F3_PDT_EDT
|
||||
{0x334E, 0x1212}, // MIPI_F4_PDT_EDT
|
||||
{0x3344, 0x0011}, // MIPI_F1_VDT_VC
|
||||
{0x3348, 0x0111}, // MIPI_F2_VDT_VC
|
||||
{0x334C, 0x0211}, // MIPI_F3_VDT_VC
|
||||
{0x3350, 0x0311}, // MIPI_F4_VDT_VC
|
||||
{0x31B0, 0x0053}, // FRAME_PREAMBLE
|
||||
{0x31B2, 0x003B}, // LINE_PREAMBLE
|
||||
{0x301A, 0x001C}, // RESET_REGISTER
|
||||
|
||||
// Noise Corrections
|
||||
{0x3092, 0x0C24}, // ROW_NOISE_CONTROL
|
||||
{0x337A, 0x0C80}, // DBLC_SCALE0
|
||||
{0x3370, 0x03B1}, // DBLC
|
||||
{0x3044, 0x0400}, // DARK_CONTROL
|
||||
|
||||
// Enable temperature sensor
|
||||
{0x30B4, 0x0007}, // TEMPSENS0_CTRL_REG
|
||||
{0x30B8, 0x0007}, // TEMPSENS1_CTRL_REG
|
||||
|
||||
// Enable dead pixel correction using
|
||||
// the 1D line correction scheme
|
||||
{0x31E0, 0x0003},
|
||||
|
||||
// HDR Settings
|
||||
{0x3082, 0x0004}, // OPERATION_MODE_CTRL
|
||||
{0x3238, 0x0444}, // EXPOSURE_RATIO
|
||||
|
||||
{0x1008, 0x0361}, // FINE_INTEGRATION_TIME_MIN
|
||||
{0x100C, 0x0589}, // FINE_INTEGRATION_TIME2_MIN
|
||||
{0x100E, 0x07B1}, // FINE_INTEGRATION_TIME3_MIN
|
||||
{0x1010, 0x0139}, // FINE_INTEGRATION_TIME4_MIN
|
||||
|
||||
// TODO: do these have to be lower than LINE_LENGTH_PCK?
|
||||
{0x3014, 0x08CB}, // FINE_INTEGRATION_TIME_
|
||||
{0x321E, 0x0894}, // FINE_INTEGRATION_TIME2
|
||||
|
||||
{0x31D0, 0x0000}, // COMPANDING, no good in 10 bit?
|
||||
{0x33DA, 0x0000}, // COMPANDING
|
||||
{0x318E, 0x0200}, // PRE_HDR_GAIN_EN
|
||||
|
||||
// DLO Settings
|
||||
{0x3100, 0x4000}, // DLO_CONTROL0
|
||||
{0x3280, 0x0CCC}, // T1 G1
|
||||
{0x3282, 0x0CCC}, // T1 R
|
||||
{0x3284, 0x0CCC}, // T1 B
|
||||
{0x3286, 0x0CCC}, // T1 G2
|
||||
{0x3288, 0x0FA0}, // T2 G1
|
||||
{0x328A, 0x0FA0}, // T2 R
|
||||
{0x328C, 0x0FA0}, // T2 B
|
||||
{0x328E, 0x0FA0}, // T2 G2
|
||||
|
||||
// Initial Gains
|
||||
{0x3022, 0x0001}, // GROUPED_PARAMETER_HOLD_
|
||||
{0x3366, 0xFF77}, // ANALOG_GAIN (1x)
|
||||
|
||||
{0x3060, 0x3333}, // ANALOG_COLOR_GAIN
|
||||
|
||||
{0x3362, 0x0000}, // DC GAIN
|
||||
|
||||
{0x305A, 0x00F8}, // red gain
|
||||
{0x3058, 0x0122}, // blue gain
|
||||
{0x3056, 0x009A}, // g1 gain
|
||||
{0x305C, 0x009A}, // g2 gain
|
||||
|
||||
{0x3022, 0x0000}, // GROUPED_PARAMETER_HOLD_
|
||||
|
||||
// Initial Integration Time
|
||||
{0x3012, 0x0005},
|
||||
};
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "media/cam_sensor.h"
|
||||
|
||||
#include "openpilot/cereal/gen/cpp/log.capnp.h"
|
||||
#include "system/camerad/sensors/ar0231_registers.h"
|
||||
#include "system/camerad/sensors/ox03c10_registers.h"
|
||||
#include "system/camerad/sensors/os04c10_registers.h"
|
||||
|
||||
@@ -87,6 +88,17 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
class AR0231 : public SensorInfo {
|
||||
public:
|
||||
AR0231();
|
||||
std::vector<i2c_random_wr_payload> getExposureRegisters(int exposure_time, int new_exp_g, bool dc_gain_enabled) const override;
|
||||
float getExposureScore(float desired_ev, int exp_t, int exp_g_idx, float exp_gain, int gain_idx) const override;
|
||||
int getSlaveAddress(int port) const override;
|
||||
|
||||
private:
|
||||
mutable std::map<uint16_t, std::pair<int, int>> ar0231_register_lut;
|
||||
};
|
||||
|
||||
class OX03C10 : public SensorInfo {
|
||||
public:
|
||||
OX03C10();
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
"""Legacy sensor exposure and BPS configuration without camera hardware."""
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
CAMERA = ROOT / 'openpilot/system/camerad'
|
||||
|
||||
|
||||
def function(text, name):
|
||||
start = text.index('{', text.index(name))
|
||||
depth = 0
|
||||
for end in range(start, len(text)):
|
||||
depth += (text[end] == '{') - (text[end] == '}')
|
||||
if depth == 0:
|
||||
return text[start:end + 1]
|
||||
raise AssertionError(name)
|
||||
|
||||
|
||||
class TestAR0231(unittest.TestCase):
|
||||
def test_build_and_probe_preserve_modern_priority(self):
|
||||
source = (CAMERA / 'cameras/spectra.cc').read_text()
|
||||
probe = function(source, 'bool SpectraCamera::openSensor()')
|
||||
self.assertEqual(re.findall(r'init_sensor_lambda\(new (\w+)\)', probe), ['OS04C10', 'OX03C10', 'AR0231'])
|
||||
self.assertIn("'sensors/ar0231.cc'", (CAMERA / 'SConscript').read_text())
|
||||
for row in ('bps_cfg', 'bps_striping_output', 'bps_settings'):
|
||||
text = (CAMERA / 'cameras/bps_blobs.h').read_text()
|
||||
rows = re.findall(r'\{([^{}]*)\}', function(text, row))
|
||||
self.assertEqual(len(rows), 4)
|
||||
self.assertEqual(len(re.findall(r'0x[0-9a-fA-F]+', rows[1])), {'bps_cfg':768, 'bps_striping_output':2464, 'bps_settings':684}[row])
|
||||
|
||||
def test_actual_sensor_exposure_and_bps_contract(self):
|
||||
compiler = shutil.which('clang++') or shutil.which('g++')
|
||||
if compiler is None:
|
||||
self.skipTest('C++ compiler unavailable')
|
||||
source = (CAMERA / 'cameras/spectra.cc').read_text()
|
||||
bps = function(source, 'void SpectraCamera::config_bps(')
|
||||
icp = function(source, 'void SpectraCamera::configICP()')
|
||||
downscale = re.search(r'bool needs_downscale = ([^;]+);', bps)[1]
|
||||
patches = re.search(r'int num_patches = ([^;]+);', bps)[1]
|
||||
cycles = re.search(r'tmp.clk.frame_cycles = ([^;]+);', bps)[1]
|
||||
striping = re.search(r'uint32_t striping_size = ([^;]+);', icp)[1]
|
||||
striping_bl = re.search(r'bps_cdm_striping_bl.init\(m, ([^,]+),', icp)[1]
|
||||
legacy = function(source, 'static bool uses_legacy_bps_config')
|
||||
knees = function(bps, 'if (legacy_bps)')
|
||||
probe = function(source, 'bool SpectraCamera::openSensor()')
|
||||
condition = re.search(r'if \((!init_sensor_lambda\(new OS04C10\).*?)\) \{', probe, re.S)[1]
|
||||
for name, identity in (('OS04C10', 3), ('OX03C10', 2), ('AR0231', 1)):
|
||||
condition = condition.replace('new ' + name, str(identity))
|
||||
with tempfile.TemporaryDirectory(prefix='camera-sensor-contract-') as directory:
|
||||
root = Path(directory)
|
||||
for path, text in {
|
||||
'media/cam_isp.h': '#pragma once\n#define CAM_ISP_PATTERN_BAYER_GRGRGR 0\n#define CAM_FORMAT_MIPI_RAW_12 12\n',
|
||||
'media/cam_sensor.h': '#pragma once\n#include <cstdint>\nstruct i2c_random_wr_payload {uint32_t reg_addr; uint32_t reg_data;};\n',
|
||||
'openpilot/cereal/gen/cpp/log.capnp.h': ('#pragma once\nnamespace cereal {struct FrameData ' +
|
||||
'{enum class ImageSensor {UNKNOWN, AR0231, OX03C10, OS04C10};};}\n'),
|
||||
}.items():
|
||||
target = root / path
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text(text)
|
||||
test = root / 'sensor.cc'
|
||||
test.write_text('''#include <cassert>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include "system/camerad/sensors/sensor.h"
|
||||
#include "system/camerad/cameras/bps_blobs.h"
|
||||
static bool uses_legacy_bps_config(const SensorInfo *sensor) ''' + legacy + '''
|
||||
int main() {
|
||||
AR0231 ar;
|
||||
assert(ar.frame_width == 1928 && ar.frame_height == 1208 && ar.frame_stride == 2896);
|
||||
assert(ar.extra_height == 12 && ar.frame_offset == 2 && ar.stats_offset == 1210);
|
||||
assert(ar.probe_reg_addr == 0x3000 && ar.probe_expected_data == 0x354);
|
||||
assert(ar.mclk_frequency == 19200000 && ar.readout_time_ns == 22850000);
|
||||
for (int port=0; port<3; ++port) assert(ar.getSlaveAddress(port) == (port==1 ? 0x30 : 0x20));
|
||||
for (int gain=1; gain<=13; ++gain) for (int exposure : {2, 32, 2133}) for (bool dc : {false,true}) {
|
||||
auto values = ar.getExposureRegisters(exposure, gain, dc);
|
||||
assert(values.size() == 3);
|
||||
assert(values[0].reg_addr == 0x3366 && values[0].reg_data == (0xff00U | (gain << 4) | gain));
|
||||
assert(values[1].reg_addr == 0x3362 && values[1].reg_data == unsigned(dc));
|
||||
assert(values[2].reg_addr == 0x3012 && values[2].reg_data == unsigned(exposure));
|
||||
}
|
||||
assert(ar.getExposureScore(10,10,6,1,6)==0);
|
||||
assert(std::abs(ar.getExposureScore(10,10,7,1,6)-5.6f)<0.00001f);
|
||||
assert(std::abs(ar.getExposureScore(10,10,5,1,6)-0.21f)<0.00001f);
|
||||
assert(ar.getExposureScore(12,10,6,1,6)==20);
|
||||
assert(ar.linearization_lut.size()==36 && ar.gamma_lut_rgb.size()==64 && ar.vignetting_lut.size()==221);
|
||||
{
|
||||
auto sensor=std::make_unique<AR0231>();
|
||||
std::vector<uint32_t> bps_lin_reg;
|
||||
''' + knees + '''
|
||||
assert((bps_lin_reg == std::vector<uint32_t>{0x0bff07ff,0x1bff17ff,0x3fff23ff,0x3fff3fff}));
|
||||
}
|
||||
for (int success : {0,1,2,3}) {
|
||||
std::vector<int> called;
|
||||
auto init_sensor_lambda=[&](int identity) {called.push_back(identity); return identity==success;};
|
||||
bool failed=''' + condition + ''';
|
||||
assert(failed == (success==0));
|
||||
assert((called == (success==3 ? std::vector<int>{3} : success==2 ? std::vector<int>{3,2} : std::vector<int>{3,2,1})));
|
||||
}
|
||||
for (auto identity : {cereal::FrameData::ImageSensor::AR0231, cereal::FrameData::ImageSensor::OX03C10, cereal::FrameData::ImageSensor::OS04C10}) {
|
||||
for (int scale : {1,2}) {
|
||||
auto sensor = std::make_unique<SensorInfo>(); sensor->image_sensor=identity; sensor->out_scale=scale;
|
||||
bool legacy_bps=uses_legacy_bps_config(sensor.get());
|
||||
bool needs_downscale=''' + downscale + ''';
|
||||
int num_patches=''' + patches + ''';
|
||||
int frame_cycles=''' + cycles + ''';
|
||||
unsigned striping_size=''' + striping + ''';
|
||||
unsigned striping_bl=''' + striping_bl + ''';
|
||||
assert(needs_downscale == (!legacy_bps && scale>1));
|
||||
assert(num_patches == (legacy_bps ? 9 : scale>1 ? 14 : 12));
|
||||
assert(frame_cycles == (legacy_bps ? 2329024 : 20000000));
|
||||
assert(striping_size == (legacy_bps ? 2464 : 3160));
|
||||
assert(striping_bl == (legacy_bps ? 41216 : 53216));
|
||||
}
|
||||
}
|
||||
}
|
||||
''')
|
||||
artifact = root / 'sensor-test'
|
||||
result = subprocess.run([compiler, '-std=gnu++17', '-I', str(root), '-I', str(ROOT / 'openpilot'),
|
||||
str(CAMERA / 'sensors/ar0231.cc'), str(test), '-o', str(artifact)],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False)
|
||||
self.assertEqual(result.returncode, 0, result.stdout)
|
||||
subprocess.run([str(artifact)], check=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user